xref: /spdk/test/unit/lib/sock/sock.c/sock_ut.c (revision 0098e636761237b77c12c30c2408263a5d2260cc)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation. All rights reserved.
3  *   Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
4  *   Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5  */
6 
7 #include "spdk/stdinc.h"
8 #include "spdk/util.h"
9 
10 #include "spdk_cunit.h"
11 
12 #include "spdk_internal/sock.h"
13 
14 #include "sock/sock.c"
15 #include "sock/posix/posix.c"
16 
17 #include "spdk_internal/mock.h"
18 #include "common/lib/test_env.c"
19 
20 #include "unit/lib/json_mock.c"
21 
22 #define UT_IP	"test_ip"
23 #define UT_PORT	1234
24 
25 bool g_read_data_called;
26 ssize_t g_bytes_read;
27 char g_buf[256];
28 struct spdk_sock *g_server_sock_read;
29 int g_ut_accept_count;
30 struct spdk_ut_sock *g_ut_listen_sock;
31 struct spdk_ut_sock *g_ut_client_sock;
32 
33 struct spdk_ut_sock {
34 	struct spdk_sock	base;
35 	struct spdk_ut_sock	*peer;
36 	size_t			bytes_avail;
37 	char			buf[256];
38 };
39 
40 struct spdk_ut_sock_group_impl {
41 	struct spdk_sock_group_impl	base;
42 	struct spdk_ut_sock		*sock;
43 };
44 
45 #define __ut_sock(sock) (struct spdk_ut_sock *)sock
46 #define __ut_group(group) (struct spdk_ut_sock_group_impl *)group
47 
48 static int
49 spdk_ut_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport,
50 		     char *caddr, int clen, uint16_t *cport)
51 {
52 	return 0;
53 }
54 
55 static struct spdk_sock *
56 spdk_ut_sock_listen(const char *ip, int port, struct spdk_sock_opts *opts)
57 {
58 	struct spdk_ut_sock *sock;
59 
60 	if (strcmp(ip, UT_IP) || port != UT_PORT) {
61 		return NULL;
62 	}
63 
64 	CU_ASSERT(g_ut_listen_sock == NULL);
65 
66 	sock = calloc(1, sizeof(*sock));
67 	SPDK_CU_ASSERT_FATAL(sock != NULL);
68 	g_ut_listen_sock = sock;
69 
70 	return &sock->base;
71 }
72 
73 static struct spdk_sock *
74 spdk_ut_sock_connect(const char *ip, int port, struct spdk_sock_opts *opts)
75 {
76 	struct spdk_ut_sock *sock;
77 
78 	if (strcmp(ip, UT_IP) || port != UT_PORT) {
79 		return NULL;
80 	}
81 
82 	sock = calloc(1, sizeof(*sock));
83 	SPDK_CU_ASSERT_FATAL(sock != NULL);
84 	g_ut_accept_count++;
85 	CU_ASSERT(g_ut_client_sock == NULL);
86 	g_ut_client_sock = sock;
87 
88 	return &sock->base;
89 }
90 
91 static struct spdk_sock *
92 spdk_ut_sock_accept(struct spdk_sock *_sock)
93 {
94 	struct spdk_ut_sock *sock = __ut_sock(_sock);
95 	struct spdk_ut_sock *new_sock;
96 
97 	CU_ASSERT(sock == g_ut_listen_sock);
98 
99 	if (g_ut_accept_count == 0) {
100 		errno = EAGAIN;
101 		return NULL;
102 	}
103 
104 	g_ut_accept_count--;
105 	new_sock = calloc(1, sizeof(*sock));
106 	if (new_sock == NULL) {
107 		SPDK_ERRLOG("sock allocation failed\n");
108 		return NULL;
109 	}
110 
111 	SPDK_CU_ASSERT_FATAL(g_ut_client_sock != NULL);
112 	g_ut_client_sock->peer = new_sock;
113 	new_sock->peer = g_ut_client_sock;
114 
115 	return &new_sock->base;
116 }
117 
118 static int
119 spdk_ut_sock_close(struct spdk_sock *_sock)
120 {
121 	struct spdk_ut_sock *sock = __ut_sock(_sock);
122 
123 	if (sock == g_ut_listen_sock) {
124 		g_ut_listen_sock = NULL;
125 	}
126 	if (sock == g_ut_client_sock) {
127 		g_ut_client_sock = NULL;
128 	}
129 
130 	if (sock->peer != NULL) {
131 		sock->peer->peer = NULL;
132 	}
133 
134 	free(_sock);
135 
136 	return 0;
137 }
138 
139 static ssize_t
140 spdk_ut_sock_recv(struct spdk_sock *_sock, void *buf, size_t len)
141 {
142 	struct spdk_ut_sock *sock = __ut_sock(_sock);
143 	char tmp[256];
144 
145 	len = spdk_min(len, sock->bytes_avail);
146 
147 	if (len == 0) {
148 		errno = EAGAIN;
149 		return -1;
150 	}
151 
152 	memcpy(buf, sock->buf, len);
153 	memcpy(tmp, &sock->buf[len], sock->bytes_avail - len);
154 	memcpy(sock->buf, tmp, sock->bytes_avail - len);
155 	sock->bytes_avail -= len;
156 
157 	return len;
158 }
159 
160 static ssize_t
161 spdk_ut_sock_readv(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
162 {
163 	struct spdk_ut_sock *sock = __ut_sock(_sock);
164 	size_t len;
165 	char tmp[256];
166 
167 	/* Test implementation only supports single iov for now. */
168 	CU_ASSERT(iovcnt == 1);
169 
170 	len = spdk_min(iov[0].iov_len, sock->bytes_avail);
171 
172 	if (len == 0) {
173 		errno = EAGAIN;
174 		return -1;
175 	}
176 
177 	memcpy(iov[0].iov_base, sock->buf, len);
178 	memcpy(tmp, &sock->buf[len], sock->bytes_avail - len);
179 	memcpy(sock->buf, tmp, sock->bytes_avail - len);
180 	sock->bytes_avail -= len;
181 
182 	return len;
183 }
184 
185 static ssize_t
186 spdk_ut_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
187 {
188 	struct spdk_ut_sock *sock = __ut_sock(_sock);
189 	struct spdk_ut_sock *peer;
190 
191 	SPDK_CU_ASSERT_FATAL(sock->peer != NULL);
192 	peer = sock->peer;
193 
194 	/* Test implementation only supports single iov for now. */
195 	CU_ASSERT(iovcnt == 1);
196 
197 	memcpy(&peer->buf[peer->bytes_avail], iov[0].iov_base, iov[0].iov_len);
198 	peer->bytes_avail += iov[0].iov_len;
199 
200 	return iov[0].iov_len;
201 }
202 
203 static int
204 spdk_ut_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes)
205 {
206 	return 0;
207 }
208 
209 static int
210 spdk_ut_sock_set_recvbuf(struct spdk_sock *_sock, int sz)
211 {
212 	return 0;
213 }
214 
215 static int
216 spdk_ut_sock_set_sendbuf(struct spdk_sock *_sock, int sz)
217 {
218 	return 0;
219 }
220 
221 static bool
222 spdk_ut_sock_is_ipv6(struct spdk_sock *_sock)
223 {
224 	return false;
225 }
226 
227 static bool
228 spdk_ut_sock_is_ipv4(struct spdk_sock *_sock)
229 {
230 	return true;
231 }
232 
233 static bool
234 spdk_ut_sock_is_connected(struct spdk_sock *_sock)
235 {
236 	struct spdk_ut_sock *sock = __ut_sock(_sock);
237 
238 	return (sock->peer != NULL);
239 }
240 
241 static struct spdk_sock_group_impl *
242 spdk_ut_sock_group_impl_get_optimal(struct spdk_sock *_sock, struct spdk_sock_group_impl *hint)
243 {
244 	return NULL;
245 }
246 
247 static struct spdk_sock_group_impl *
248 spdk_ut_sock_group_impl_create(void)
249 {
250 	struct spdk_ut_sock_group_impl *group_impl;
251 
252 	group_impl = calloc(1, sizeof(*group_impl));
253 	SPDK_CU_ASSERT_FATAL(group_impl != NULL);
254 
255 	return &group_impl->base;
256 }
257 
258 static int
259 spdk_ut_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
260 {
261 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
262 	struct spdk_ut_sock *sock = __ut_sock(_sock);
263 
264 	group->sock = sock;
265 
266 	return 0;
267 }
268 
269 static int
270 spdk_ut_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
271 {
272 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
273 	struct spdk_ut_sock *sock = __ut_sock(_sock);
274 
275 	CU_ASSERT(group->sock == sock);
276 	group->sock = NULL;
277 
278 	return 0;
279 }
280 
281 static int
282 spdk_ut_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events,
283 			     struct spdk_sock **socks)
284 {
285 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
286 
287 	if (group->sock != NULL && group->sock->bytes_avail > 0) {
288 		socks[0] = &group->sock->base;
289 		return 1;
290 	}
291 
292 	return 0;
293 }
294 
295 static int
296 spdk_ut_sock_group_impl_close(struct spdk_sock_group_impl *_group)
297 {
298 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
299 
300 	CU_ASSERT(group->sock == NULL);
301 	free(_group);
302 
303 	return 0;
304 }
305 
306 static struct spdk_net_impl g_ut_net_impl = {
307 	.name		= "ut",
308 	.getaddr	= spdk_ut_sock_getaddr,
309 	.connect	= spdk_ut_sock_connect,
310 	.listen		= spdk_ut_sock_listen,
311 	.accept		= spdk_ut_sock_accept,
312 	.close		= spdk_ut_sock_close,
313 	.recv		= spdk_ut_sock_recv,
314 	.readv		= spdk_ut_sock_readv,
315 	.writev		= spdk_ut_sock_writev,
316 	.set_recvlowat	= spdk_ut_sock_set_recvlowat,
317 	.set_recvbuf	= spdk_ut_sock_set_recvbuf,
318 	.set_sendbuf	= spdk_ut_sock_set_sendbuf,
319 	.is_ipv6	= spdk_ut_sock_is_ipv6,
320 	.is_ipv4	= spdk_ut_sock_is_ipv4,
321 	.is_connected	= spdk_ut_sock_is_connected,
322 	.group_impl_get_optimal	= spdk_ut_sock_group_impl_get_optimal,
323 	.group_impl_create	= spdk_ut_sock_group_impl_create,
324 	.group_impl_add_sock	= spdk_ut_sock_group_impl_add_sock,
325 	.group_impl_remove_sock = spdk_ut_sock_group_impl_remove_sock,
326 	.group_impl_poll	= spdk_ut_sock_group_impl_poll,
327 	.group_impl_close	= spdk_ut_sock_group_impl_close,
328 };
329 
330 SPDK_NET_IMPL_REGISTER(ut, &g_ut_net_impl, DEFAULT_SOCK_PRIORITY + 2);
331 
332 static void
333 _sock(const char *ip, int port, char *impl_name)
334 {
335 	struct spdk_sock *listen_sock;
336 	struct spdk_sock *server_sock;
337 	struct spdk_sock *client_sock;
338 	char *test_string = "abcdef";
339 	char buffer[64];
340 	ssize_t bytes_read, bytes_written;
341 	struct iovec iov;
342 	int rc;
343 
344 	listen_sock = spdk_sock_listen(ip, port, impl_name);
345 	SPDK_CU_ASSERT_FATAL(listen_sock != NULL);
346 
347 	server_sock = spdk_sock_accept(listen_sock);
348 	CU_ASSERT(server_sock == NULL);
349 	CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK);
350 
351 	client_sock = spdk_sock_connect(ip, port, impl_name);
352 	SPDK_CU_ASSERT_FATAL(client_sock != NULL);
353 
354 	/*
355 	 * Delay a bit here before checking if server socket is
356 	 *  ready.
357 	 */
358 	usleep(1000);
359 
360 	server_sock = spdk_sock_accept(listen_sock);
361 	SPDK_CU_ASSERT_FATAL(server_sock != NULL);
362 	CU_ASSERT(spdk_sock_is_connected(client_sock) == true);
363 	CU_ASSERT(spdk_sock_is_connected(server_sock) == true);
364 
365 	/* Test spdk_sock_recv */
366 	iov.iov_base = test_string;
367 	iov.iov_len = 7;
368 	bytes_written = spdk_sock_writev(client_sock, &iov, 1);
369 	CU_ASSERT(bytes_written == 7);
370 
371 	usleep(1000);
372 
373 	bytes_read = spdk_sock_recv(server_sock, buffer, 2);
374 	CU_ASSERT(bytes_read == 2);
375 
376 	usleep(1000);
377 
378 	bytes_read += spdk_sock_recv(server_sock, buffer + 2, 5);
379 	CU_ASSERT(bytes_read == 7);
380 
381 	CU_ASSERT(strncmp(test_string, buffer, 7) == 0);
382 
383 	/* Test spdk_sock_readv */
384 	iov.iov_base = test_string;
385 	iov.iov_len = 7;
386 	bytes_written = spdk_sock_writev(client_sock, &iov, 1);
387 	CU_ASSERT(bytes_written == 7);
388 
389 	usleep(1000);
390 
391 	iov.iov_base = buffer;
392 	iov.iov_len = 2;
393 	bytes_read = spdk_sock_readv(server_sock, &iov, 1);
394 	CU_ASSERT(bytes_read == 2);
395 
396 	usleep(1000);
397 
398 	iov.iov_base = buffer + 2;
399 	iov.iov_len = 5;
400 	bytes_read += spdk_sock_readv(server_sock, &iov, 1);
401 	CU_ASSERT(bytes_read == 7);
402 
403 	usleep(1000);
404 
405 	CU_ASSERT(strncmp(test_string, buffer, 7) == 0);
406 
407 	rc = spdk_sock_close(&client_sock);
408 	CU_ASSERT(client_sock == NULL);
409 	CU_ASSERT(rc == 0);
410 
411 #if defined(__FreeBSD__)
412 	/* On FreeBSD, it takes a small amount of time for a close to propagate to the
413 	 * other side, even in loopback. Introduce a small sleep. */
414 	sleep(1);
415 #endif
416 	CU_ASSERT(spdk_sock_is_connected(server_sock) == false);
417 
418 	rc = spdk_sock_close(&server_sock);
419 	CU_ASSERT(server_sock == NULL);
420 	CU_ASSERT(rc == 0);
421 
422 	rc = spdk_sock_close(&listen_sock);
423 	CU_ASSERT(listen_sock == NULL);
424 	CU_ASSERT(rc == 0);
425 }
426 
427 static void
428 posix_sock(void)
429 {
430 	_sock("127.0.0.1", UT_PORT, "posix");
431 }
432 
433 static void
434 ut_sock(void)
435 {
436 	_sock(UT_IP, UT_PORT, "ut");
437 }
438 
439 static void
440 read_data(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock)
441 {
442 	struct spdk_sock *server_sock = cb_arg;
443 
444 	CU_ASSERT(server_sock == sock);
445 
446 	g_read_data_called = true;
447 	g_bytes_read += spdk_sock_recv(server_sock, g_buf + g_bytes_read, sizeof(g_buf) - g_bytes_read);
448 }
449 
450 static void
451 _sock_group(const char *ip, int port, char *impl_name)
452 {
453 	struct spdk_sock_group *group;
454 	struct spdk_sock *listen_sock;
455 	struct spdk_sock *server_sock;
456 	struct spdk_sock *client_sock;
457 	char *test_string = "abcdef";
458 	ssize_t bytes_written;
459 	struct iovec iov;
460 	int rc;
461 
462 	listen_sock = spdk_sock_listen(ip, port, impl_name);
463 	SPDK_CU_ASSERT_FATAL(listen_sock != NULL);
464 
465 	server_sock = spdk_sock_accept(listen_sock);
466 	CU_ASSERT(server_sock == NULL);
467 	CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK);
468 
469 	client_sock = spdk_sock_connect(ip, port, impl_name);
470 	SPDK_CU_ASSERT_FATAL(client_sock != NULL);
471 
472 	usleep(1000);
473 
474 	server_sock = spdk_sock_accept(listen_sock);
475 	SPDK_CU_ASSERT_FATAL(server_sock != NULL);
476 
477 	group = spdk_sock_group_create(NULL);
478 	SPDK_CU_ASSERT_FATAL(group != NULL);
479 
480 	/* pass null cb_fn */
481 	rc = spdk_sock_group_add_sock(group, server_sock, NULL, NULL);
482 	CU_ASSERT(rc == -1);
483 	CU_ASSERT(errno == EINVAL);
484 
485 	rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock);
486 	CU_ASSERT(rc == 0);
487 
488 	/* try adding sock a second time */
489 	rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock);
490 	CU_ASSERT(rc == -1);
491 	CU_ASSERT(errno == EINVAL);
492 
493 	g_read_data_called = false;
494 	g_bytes_read = 0;
495 	rc = spdk_sock_group_poll(group);
496 
497 	CU_ASSERT(rc == 0);
498 	CU_ASSERT(g_read_data_called == false);
499 
500 	iov.iov_base = test_string;
501 	iov.iov_len = 7;
502 	bytes_written = spdk_sock_writev(client_sock, &iov, 1);
503 	CU_ASSERT(bytes_written == 7);
504 
505 	usleep(1000);
506 
507 	g_read_data_called = false;
508 	g_bytes_read = 0;
509 	rc = spdk_sock_group_poll(group);
510 
511 	CU_ASSERT(rc == 1);
512 	CU_ASSERT(g_read_data_called == true);
513 	CU_ASSERT(g_bytes_read == 7);
514 
515 	CU_ASSERT(strncmp(test_string, g_buf, 7) == 0);
516 
517 	rc = spdk_sock_close(&client_sock);
518 	CU_ASSERT(client_sock == NULL);
519 	CU_ASSERT(rc == 0);
520 
521 	/* Try to close sock_group while it still has sockets. */
522 	rc = spdk_sock_group_close(&group);
523 	CU_ASSERT(rc == -1);
524 	CU_ASSERT(errno == EBUSY);
525 
526 	/* Try to close sock while it is still part of a sock_group. */
527 	rc = spdk_sock_close(&server_sock);
528 	CU_ASSERT(rc == -1);
529 	CU_ASSERT(errno == EBUSY);
530 
531 	rc = spdk_sock_group_remove_sock(group, server_sock);
532 	CU_ASSERT(rc == 0);
533 
534 	rc = spdk_sock_group_close(&group);
535 	CU_ASSERT(group == NULL);
536 	CU_ASSERT(rc == 0);
537 
538 	rc = spdk_sock_close(&server_sock);
539 	CU_ASSERT(server_sock == NULL);
540 	CU_ASSERT(rc == 0);
541 
542 	rc = spdk_sock_close(&listen_sock);
543 	CU_ASSERT(listen_sock == NULL);
544 	CU_ASSERT(rc == 0);
545 }
546 
547 static void
548 posix_sock_group(void)
549 {
550 	_sock_group("127.0.0.1", UT_PORT, "posix");
551 }
552 
553 static void
554 ut_sock_group(void)
555 {
556 	_sock_group(UT_IP, UT_PORT, "ut");
557 }
558 
559 static void
560 read_data_fairness(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock)
561 {
562 	struct spdk_sock *server_sock = cb_arg;
563 	ssize_t bytes_read;
564 	char buf[1];
565 
566 	CU_ASSERT(g_server_sock_read == NULL);
567 	CU_ASSERT(server_sock == sock);
568 
569 	g_server_sock_read = server_sock;
570 	bytes_read = spdk_sock_recv(server_sock, buf, 1);
571 	CU_ASSERT(bytes_read == 1);
572 }
573 
574 static void
575 posix_sock_group_fairness(void)
576 {
577 	struct spdk_sock_group *group;
578 	struct spdk_sock *listen_sock;
579 	struct spdk_sock *server_sock[3];
580 	struct spdk_sock *client_sock[3];
581 	char test_char = 'a';
582 	ssize_t bytes_written;
583 	struct iovec iov;
584 	int i, rc;
585 
586 	listen_sock = spdk_sock_listen("127.0.0.1", UT_PORT, "posix");
587 	SPDK_CU_ASSERT_FATAL(listen_sock != NULL);
588 
589 	group = spdk_sock_group_create(NULL);
590 	SPDK_CU_ASSERT_FATAL(group != NULL);
591 
592 	for (i = 0; i < 3; i++) {
593 		client_sock[i] = spdk_sock_connect("127.0.0.1", UT_PORT, "posix");
594 		SPDK_CU_ASSERT_FATAL(client_sock[i] != NULL);
595 
596 		usleep(1000);
597 
598 		server_sock[i] = spdk_sock_accept(listen_sock);
599 		SPDK_CU_ASSERT_FATAL(server_sock[i] != NULL);
600 
601 		rc = spdk_sock_group_add_sock(group, server_sock[i],
602 					      read_data_fairness, server_sock[i]);
603 		CU_ASSERT(rc == 0);
604 	}
605 
606 	iov.iov_base = &test_char;
607 	iov.iov_len = 1;
608 
609 	for (i = 0; i < 3; i++) {
610 		bytes_written = spdk_sock_writev(client_sock[i], &iov, 1);
611 		CU_ASSERT(bytes_written == 1);
612 	}
613 
614 	usleep(1000);
615 
616 	/*
617 	 * Poll for just one event - this should be server sock 0, since that
618 	 *  is the peer of the first client sock that we wrote to.
619 	 */
620 	g_server_sock_read = NULL;
621 	rc = spdk_sock_group_poll_count(group, 1);
622 	CU_ASSERT(rc == 1);
623 	CU_ASSERT(g_server_sock_read == server_sock[0]);
624 
625 	/*
626 	 * Now write another byte to client sock 0.  We want to ensure that
627 	 *  the sock group does not unfairly process the event for this sock
628 	 *  before the socks that were written to earlier.
629 	 */
630 	bytes_written = spdk_sock_writev(client_sock[0], &iov, 1);
631 	CU_ASSERT(bytes_written == 1);
632 
633 	usleep(1000);
634 
635 	g_server_sock_read = NULL;
636 	rc = spdk_sock_group_poll_count(group, 1);
637 	CU_ASSERT(rc == 1);
638 	CU_ASSERT(g_server_sock_read == server_sock[1]);
639 
640 	g_server_sock_read = NULL;
641 	rc = spdk_sock_group_poll_count(group, 1);
642 	CU_ASSERT(rc == 1);
643 	CU_ASSERT(g_server_sock_read == server_sock[2]);
644 
645 	g_server_sock_read = NULL;
646 	rc = spdk_sock_group_poll_count(group, 1);
647 	CU_ASSERT(rc == 1);
648 	CU_ASSERT(g_server_sock_read == server_sock[0]);
649 
650 	for (i = 0; i < 3; i++) {
651 		rc = spdk_sock_group_remove_sock(group, server_sock[i]);
652 		CU_ASSERT(rc == 0);
653 
654 		rc = spdk_sock_close(&client_sock[i]);
655 		CU_ASSERT(client_sock[i] == NULL);
656 		CU_ASSERT(rc == 0);
657 
658 		rc = spdk_sock_close(&server_sock[i]);
659 		CU_ASSERT(server_sock[i] == NULL);
660 		CU_ASSERT(rc == 0);
661 	}
662 
663 	rc = spdk_sock_group_close(&group);
664 	CU_ASSERT(group == NULL);
665 	CU_ASSERT(rc == 0);
666 
667 	rc = spdk_sock_close(&listen_sock);
668 	CU_ASSERT(listen_sock == NULL);
669 	CU_ASSERT(rc == 0);
670 }
671 
672 struct close_ctx {
673 	struct spdk_sock_group *group;
674 	struct spdk_sock *sock;
675 	bool called;
676 };
677 
678 static void
679 _first_close_cb(void *cb_arg, int err)
680 {
681 	struct close_ctx *ctx = cb_arg;
682 	int rc;
683 
684 	ctx->called = true;
685 
686 	/* Always close the socket here */
687 	rc = spdk_sock_group_remove_sock(ctx->group, ctx->sock);
688 	CU_ASSERT(rc == 0);
689 	spdk_sock_close(&ctx->sock);
690 
691 	CU_ASSERT(err == 0);
692 }
693 
694 static void
695 _second_close_cb(void *cb_arg, int err)
696 {
697 	*(bool *)cb_arg = true;
698 	CU_ASSERT(err == -ECANCELED);
699 }
700 
701 static void
702 _sock_close(const char *ip, int port, char *impl_name)
703 {
704 	struct spdk_sock_group *group;
705 	struct spdk_sock *listen_sock;
706 	struct spdk_sock *server_sock;
707 	struct spdk_sock *client_sock;
708 	uint8_t data_buf[64] = {};
709 	struct spdk_sock_request *req1, *req2;
710 	struct close_ctx ctx = {};
711 	bool cb_arg2 = false;
712 	int rc;
713 
714 	listen_sock = spdk_sock_listen(ip, port, impl_name);
715 	SPDK_CU_ASSERT_FATAL(listen_sock != NULL);
716 
717 	client_sock = spdk_sock_connect(ip, port, impl_name);
718 	SPDK_CU_ASSERT_FATAL(client_sock != NULL);
719 
720 	usleep(1000);
721 
722 	server_sock = spdk_sock_accept(listen_sock);
723 	SPDK_CU_ASSERT_FATAL(server_sock != NULL);
724 
725 	group = spdk_sock_group_create(NULL);
726 	SPDK_CU_ASSERT_FATAL(group != NULL);
727 
728 	rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock);
729 	CU_ASSERT(rc == 0);
730 
731 	/* Submit multiple async writevs on the server sock */
732 
733 	req1 = calloc(1, sizeof(struct spdk_sock_request) + sizeof(struct iovec));
734 	SPDK_CU_ASSERT_FATAL(req1 != NULL);
735 	SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = data_buf;
736 	SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64;
737 	ctx.group = group;
738 	ctx.sock = server_sock;
739 	ctx.called = false;
740 	req1->iovcnt = 1;
741 	req1->cb_fn = _first_close_cb;
742 	req1->cb_arg = &ctx;
743 	spdk_sock_writev_async(server_sock, req1);
744 	CU_ASSERT(ctx.called == false);
745 
746 	req2 = calloc(1, sizeof(struct spdk_sock_request) + sizeof(struct iovec));
747 	SPDK_CU_ASSERT_FATAL(req2 != NULL);
748 	SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = data_buf;
749 	SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 64;
750 	req2->iovcnt = 1;
751 	req2->cb_fn = _second_close_cb;
752 	req2->cb_arg = &cb_arg2;
753 	spdk_sock_writev_async(server_sock, req2);
754 	CU_ASSERT(cb_arg2 == false);
755 
756 	/* Poll the socket so the writev_async's send. The first one's
757 	 * callback will close the socket. */
758 	spdk_sock_group_poll(group);
759 	if (ctx.called == false) {
760 		/* Sometimes the zerocopy completion isn't posted immediately. Delay slightly
761 		* and poll one more time. */
762 		usleep(1000);
763 		spdk_sock_group_poll(group);
764 	}
765 	CU_ASSERT(ctx.called == true);
766 	CU_ASSERT(cb_arg2 == true);
767 
768 	rc = spdk_sock_group_close(&group);
769 	CU_ASSERT(group == NULL);
770 	CU_ASSERT(rc == 0);
771 
772 	rc = spdk_sock_close(&client_sock);
773 	CU_ASSERT(client_sock == NULL);
774 	CU_ASSERT(rc == 0);
775 
776 	rc = spdk_sock_close(&listen_sock);
777 	CU_ASSERT(listen_sock == NULL);
778 	CU_ASSERT(rc == 0);
779 
780 	free(req1);
781 	free(req2);
782 }
783 
784 static void
785 _posix_sock_close(void)
786 {
787 	_sock_close("127.0.0.1", UT_PORT, "posix");
788 }
789 
790 static void
791 sock_get_default_opts(void)
792 {
793 	struct spdk_sock_opts opts;
794 
795 	/* opts_size is 0 */
796 	opts.opts_size = 0;
797 	opts.priority = 3;
798 	spdk_sock_get_default_opts(&opts);
799 	CU_ASSERT(opts.priority == 3);
800 	CU_ASSERT(opts.opts_size == 0);
801 
802 	/* opts_size is less than sizeof(opts) */
803 	opts.opts_size = 4;
804 	opts.priority = 3;
805 	spdk_sock_get_default_opts(&opts);
806 	CU_ASSERT(opts.priority == 3);
807 	CU_ASSERT(opts.opts_size == 4);
808 
809 	/* opts_size is equal to sizeof(opts) */
810 	opts.opts_size = sizeof(opts);
811 	opts.priority = 3;
812 	spdk_sock_get_default_opts(&opts);
813 	CU_ASSERT(opts.priority == SPDK_SOCK_DEFAULT_PRIORITY);
814 	CU_ASSERT(opts.opts_size == sizeof(opts));
815 
816 	/* opts_size is larger then sizeof(opts) */
817 	opts.opts_size = sizeof(opts) + 1;
818 	opts.priority = 3;
819 	spdk_sock_get_default_opts(&opts);
820 	CU_ASSERT(opts.priority == SPDK_SOCK_DEFAULT_PRIORITY);
821 	CU_ASSERT(opts.opts_size == (sizeof(opts) + 1));
822 }
823 
824 static void
825 ut_sock_impl_get_set_opts(void)
826 {
827 	int rc;
828 	size_t len = 0;
829 	/* Use any pointer value for opts. It is never dereferenced in this test */
830 	struct spdk_sock_impl_opts *opts = (struct spdk_sock_impl_opts *)0x123456789;
831 
832 	rc = spdk_sock_impl_get_opts("ut", NULL, &len);
833 	CU_ASSERT(rc == -1);
834 	CU_ASSERT(errno == EINVAL);
835 	rc = spdk_sock_impl_get_opts("ut", opts, NULL);
836 	CU_ASSERT(rc == -1);
837 	CU_ASSERT(errno == EINVAL);
838 	rc = spdk_sock_impl_get_opts("ut", opts, &len);
839 	CU_ASSERT(rc == -1);
840 	CU_ASSERT(errno == ENOTSUP);
841 
842 	rc = spdk_sock_impl_set_opts("ut", NULL, len);
843 	CU_ASSERT(rc == -1);
844 	CU_ASSERT(errno == EINVAL);
845 	rc = spdk_sock_impl_set_opts("ut", opts, len);
846 	CU_ASSERT(rc == -1);
847 	CU_ASSERT(errno == ENOTSUP);
848 }
849 
850 static void
851 posix_sock_impl_get_set_opts(void)
852 {
853 	int rc;
854 	size_t len = 0;
855 	struct spdk_sock_impl_opts opts = {};
856 	struct spdk_sock_impl_opts long_opts[2];
857 
858 	rc = spdk_sock_impl_get_opts("posix", NULL, &len);
859 	CU_ASSERT(rc == -1);
860 	CU_ASSERT(errno == EINVAL);
861 	rc = spdk_sock_impl_get_opts("posix", &opts, NULL);
862 	CU_ASSERT(rc == -1);
863 	CU_ASSERT(errno == EINVAL);
864 
865 	/* Check default opts */
866 	len = sizeof(opts);
867 	rc = spdk_sock_impl_get_opts("posix", &opts, &len);
868 	CU_ASSERT(rc == 0);
869 	CU_ASSERT(len == sizeof(opts));
870 	CU_ASSERT(opts.recv_buf_size == MIN_SO_RCVBUF_SIZE);
871 	CU_ASSERT(opts.send_buf_size == MIN_SO_SNDBUF_SIZE);
872 
873 	/* Try to request more opts */
874 	len = sizeof(long_opts);
875 	rc = spdk_sock_impl_get_opts("posix", long_opts, &len);
876 	CU_ASSERT(rc == 0);
877 	CU_ASSERT(len == sizeof(opts));
878 
879 	/* Try to request zero opts */
880 	len = 0;
881 	rc = spdk_sock_impl_get_opts("posix", &opts, &len);
882 	CU_ASSERT(rc == 0);
883 	CU_ASSERT(len == 0);
884 
885 	rc = spdk_sock_impl_set_opts("posix", NULL, len);
886 	CU_ASSERT(rc == -1);
887 	CU_ASSERT(errno == EINVAL);
888 
889 	opts.recv_buf_size = 16;
890 	opts.send_buf_size = 4;
891 	rc = spdk_sock_impl_set_opts("posix", &opts, sizeof(opts));
892 	CU_ASSERT(rc == 0);
893 	len = sizeof(opts);
894 	memset(&opts, 0, sizeof(opts));
895 	rc = spdk_sock_impl_get_opts("posix", &opts, &len);
896 	CU_ASSERT(rc == 0);
897 	CU_ASSERT(opts.recv_buf_size == 16);
898 	CU_ASSERT(opts.send_buf_size == 4);
899 
900 	/* Try to set more opts */
901 	long_opts[0].recv_buf_size = 4;
902 	long_opts[0].send_buf_size = 6;
903 	long_opts[1].recv_buf_size = 0;
904 	long_opts[1].send_buf_size = 0;
905 	rc = spdk_sock_impl_set_opts("posix", long_opts, sizeof(long_opts));
906 	CU_ASSERT(rc == 0);
907 
908 	/* Try to set less opts. Opts in the end should be untouched */
909 	opts.recv_buf_size = 5;
910 	opts.send_buf_size = 10;
911 	rc = spdk_sock_impl_set_opts("posix", &opts, sizeof(opts.recv_buf_size));
912 	CU_ASSERT(rc == 0);
913 	len = sizeof(opts);
914 	memset(&opts, 0, sizeof(opts));
915 	rc = spdk_sock_impl_get_opts("posix", &opts, &len);
916 	CU_ASSERT(rc == 0);
917 	CU_ASSERT(opts.recv_buf_size == 5);
918 	CU_ASSERT(opts.send_buf_size == 6);
919 
920 	/* Try to set partial option. It should not be changed */
921 	opts.recv_buf_size = 1000;
922 	rc = spdk_sock_impl_set_opts("posix", &opts, 1);
923 	CU_ASSERT(rc == 0);
924 	len = sizeof(opts);
925 	memset(&opts, 0, sizeof(opts));
926 	rc = spdk_sock_impl_get_opts("posix", &opts, &len);
927 	CU_ASSERT(rc == 0);
928 	CU_ASSERT(opts.recv_buf_size == 5);
929 }
930 
931 static void
932 ut_sock_map(void)
933 {
934 	struct spdk_sock_map map = {
935 		.entries = STAILQ_HEAD_INITIALIZER(map.entries),
936 		.mtx = PTHREAD_MUTEX_INITIALIZER
937 	};
938 	struct spdk_sock_group_impl *group_1, *group_2, *test_group;
939 	int rc;
940 	int test_id;
941 
942 	group_1 = spdk_ut_sock_group_impl_create();
943 	group_2 = spdk_ut_sock_group_impl_create();
944 
945 	/* Test 1
946 	 * Sanity check when sock_map is empty */
947 	test_id = spdk_sock_map_find_free(&map);
948 	CU_ASSERT(test_id == -1);
949 
950 	test_group = NULL;
951 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
952 	CU_ASSERT(rc == -EINVAL);
953 	CU_ASSERT(test_group == NULL);
954 
955 	/* Test 2
956 	 * Insert single entry */
957 	rc = spdk_sock_map_insert(&map, 1, group_1);
958 	CU_ASSERT(rc == 0);
959 
960 	test_group = NULL;
961 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
962 	CU_ASSERT(rc == 0);
963 	CU_ASSERT(test_group == group_1);
964 
965 	/* There is single entry allocated, but it is not free */
966 	test_id = spdk_sock_map_find_free(&map);
967 	CU_ASSERT(test_id == -1);
968 
969 	/* Free the entry and verify */
970 	spdk_sock_map_release(&map, 1);
971 	test_id = spdk_sock_map_find_free(&map);
972 	CU_ASSERT(test_id == 1);
973 
974 	spdk_sock_map_cleanup(&map);
975 
976 	/* Test 3
977 	 * Insert sock_group into placement_id multiple times */
978 	rc = spdk_sock_map_insert(&map, 1, group_1);
979 	CU_ASSERT(rc == 0);
980 	CU_ASSERT(STAILQ_FIRST(&map.entries)->ref == 1);
981 	rc = spdk_sock_map_insert(&map, 1, group_1);
982 	CU_ASSERT(rc == 0);
983 	CU_ASSERT(STAILQ_FIRST(&map.entries)->ref == 2);
984 
985 	/* Release entry once and see that it still exists. */
986 	spdk_sock_map_release(&map, 1);
987 	test_group = NULL;
988 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
989 	CU_ASSERT(rc == 0);
990 	CU_ASSERT(test_group == group_1);
991 
992 	/* Release entry second and final time. */
993 	spdk_sock_map_release(&map, 1);
994 	test_group = NULL;
995 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
996 	CU_ASSERT(rc == -EINVAL);
997 	CU_ASSERT(test_group == NULL);
998 
999 	spdk_sock_map_cleanup(&map);
1000 
1001 	/* Test 4
1002 	 * Test multiple entries */
1003 	rc = spdk_sock_map_insert(&map, 1, group_1);
1004 	CU_ASSERT(rc == 0);
1005 
1006 	test_group = NULL;
1007 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
1008 	CU_ASSERT(rc == 0);
1009 	CU_ASSERT(test_group == group_1);
1010 
1011 	rc = spdk_sock_map_insert(&map, 2, group_2);
1012 	CU_ASSERT(rc == 0);
1013 
1014 	test_group = NULL;
1015 	rc = spdk_sock_map_lookup(&map, 2, &test_group, NULL);
1016 	CU_ASSERT(rc == 0);
1017 	CU_ASSERT(test_group == group_2);
1018 
1019 	spdk_sock_map_cleanup(&map);
1020 
1021 	/* Test 5
1022 	 * Attempt inserting multiple entries into single placement_id */
1023 	rc = spdk_sock_map_insert(&map, 1, group_1);
1024 	CU_ASSERT(rc == 0);
1025 
1026 	test_group = NULL;
1027 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
1028 	CU_ASSERT(rc == 0);
1029 	CU_ASSERT(test_group == group_1);
1030 
1031 	rc = spdk_sock_map_insert(&map, 1, group_2);
1032 	CU_ASSERT(rc == -EINVAL);
1033 
1034 	test_group = NULL;
1035 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
1036 	CU_ASSERT(rc == 0);
1037 	CU_ASSERT(test_group == group_1);
1038 
1039 	spdk_sock_map_cleanup(&map);
1040 
1041 	/* Test 6
1042 	 * Insert single entry without a sock_group */
1043 	rc = spdk_sock_map_insert(&map, 1, NULL);
1044 	CU_ASSERT(rc == 0);
1045 
1046 	test_group = NULL;
1047 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
1048 	CU_ASSERT(rc == -EINVAL);
1049 	CU_ASSERT(test_group == NULL);
1050 
1051 	test_id = spdk_sock_map_find_free(&map);
1052 	CU_ASSERT(test_id == 1);
1053 
1054 	rc = spdk_sock_map_insert(&map, test_id, group_1);
1055 	CU_ASSERT(rc == 0);
1056 
1057 	test_group = NULL;
1058 	rc = spdk_sock_map_lookup(&map, test_id, &test_group, NULL);
1059 	CU_ASSERT(rc == 0);
1060 	CU_ASSERT(test_group == group_1);
1061 
1062 	spdk_sock_map_cleanup(&map);
1063 
1064 	/* Test 6
1065 	 * Use hint sock_group for for placement_id */
1066 	test_group = NULL;
1067 	rc = spdk_sock_map_lookup(&map, 1, &test_group, group_1);
1068 	CU_ASSERT(rc == 0);
1069 	CU_ASSERT(test_group == NULL);
1070 
1071 	test_group = NULL;
1072 	rc = spdk_sock_map_lookup(&map, 1, &test_group, NULL);
1073 	CU_ASSERT(rc == 0);
1074 	CU_ASSERT(test_group == group_1);
1075 
1076 	test_id = spdk_sock_map_find_free(&map);
1077 	CU_ASSERT(test_id == -1);
1078 
1079 	rc = spdk_sock_map_insert(&map, 1, group_2);
1080 	CU_ASSERT(rc == -EINVAL);
1081 
1082 	rc = spdk_sock_map_insert(&map, 1, group_1);
1083 	CU_ASSERT(rc == 0);
1084 
1085 	spdk_sock_map_cleanup(&map);
1086 
1087 	spdk_ut_sock_group_impl_close(group_2);
1088 	spdk_ut_sock_group_impl_close(group_1);
1089 }
1090 
1091 int
1092 main(int argc, char **argv)
1093 {
1094 	CU_pSuite	suite = NULL;
1095 	unsigned int	num_failures;
1096 
1097 	CU_set_error_action(CUEA_ABORT);
1098 	CU_initialize_registry();
1099 
1100 	suite = CU_add_suite("sock", NULL, NULL);
1101 
1102 	CU_ADD_TEST(suite, posix_sock);
1103 	CU_ADD_TEST(suite, ut_sock);
1104 	CU_ADD_TEST(suite, posix_sock_group);
1105 	CU_ADD_TEST(suite, ut_sock_group);
1106 	CU_ADD_TEST(suite, posix_sock_group_fairness);
1107 	CU_ADD_TEST(suite, _posix_sock_close);
1108 	CU_ADD_TEST(suite, sock_get_default_opts);
1109 	CU_ADD_TEST(suite, ut_sock_impl_get_set_opts);
1110 	CU_ADD_TEST(suite, posix_sock_impl_get_set_opts);
1111 	CU_ADD_TEST(suite, ut_sock_map);
1112 
1113 	CU_basic_set_mode(CU_BRM_VERBOSE);
1114 
1115 	CU_basic_run_tests();
1116 
1117 	num_failures = CU_get_number_of_failures();
1118 	CU_cleanup_registry();
1119 
1120 	return num_failures;
1121 }
1122