xref: /spdk/test/unit/lib/sock/sock.c/sock_ut.c (revision 9889ab2dc80e40dae92dcef361d53dcba722043d)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 #include "spdk/util.h"
36 
37 #include "spdk_cunit.h"
38 
39 #include "sock/sock.c"
40 #include "sock/posix/posix.c"
41 
42 #define UT_IP	"test_ip"
43 #define UT_PORT	1234
44 
45 bool g_read_data_called;
46 ssize_t g_bytes_read;
47 char g_buf[256];
48 struct spdk_sock *g_server_sock_read;
49 int g_ut_accept_count;
50 struct spdk_ut_sock *g_ut_listen_sock;
51 struct spdk_ut_sock *g_ut_client_sock;
52 
53 struct spdk_ut_sock {
54 	struct spdk_sock	base;
55 	struct spdk_ut_sock	*peer;
56 	size_t			bytes_avail;
57 	char			buf[256];
58 };
59 
60 struct spdk_ut_sock_group_impl {
61 	struct spdk_sock_group_impl	base;
62 	struct spdk_ut_sock		*sock;
63 };
64 
65 #define __ut_sock(sock) (struct spdk_ut_sock *)sock
66 #define __ut_group(group) (struct spdk_ut_sock_group_impl *)group
67 
68 static int
69 spdk_ut_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport,
70 		     char *caddr, int clen, uint16_t *cport)
71 {
72 	return 0;
73 }
74 
75 static struct spdk_sock *
76 spdk_ut_sock_listen(const char *ip, int port)
77 {
78 	struct spdk_ut_sock *sock;
79 
80 	if (strcmp(ip, UT_IP) || port != UT_PORT) {
81 		return NULL;
82 	}
83 
84 	CU_ASSERT(g_ut_listen_sock == NULL);
85 
86 	sock = calloc(1, sizeof(*sock));
87 	SPDK_CU_ASSERT_FATAL(sock != NULL);
88 	g_ut_listen_sock = sock;
89 
90 	return &sock->base;
91 }
92 
93 static struct spdk_sock *
94 spdk_ut_sock_connect(const char *ip, int port)
95 {
96 	struct spdk_ut_sock *sock;
97 
98 	if (strcmp(ip, UT_IP) || port != UT_PORT) {
99 		return NULL;
100 	}
101 
102 	sock = calloc(1, sizeof(*sock));
103 	SPDK_CU_ASSERT_FATAL(sock != NULL);
104 	g_ut_accept_count++;
105 	CU_ASSERT(g_ut_client_sock == NULL);
106 	g_ut_client_sock = sock;
107 
108 	return &sock->base;
109 }
110 
111 static struct spdk_sock *
112 spdk_ut_sock_accept(struct spdk_sock *_sock)
113 {
114 	struct spdk_ut_sock *sock = __ut_sock(_sock);
115 	struct spdk_ut_sock *new_sock;
116 
117 	CU_ASSERT(sock == g_ut_listen_sock);
118 
119 	if (g_ut_accept_count == 0) {
120 		errno = EAGAIN;
121 		return NULL;
122 	}
123 
124 	g_ut_accept_count--;
125 	new_sock = calloc(1, sizeof(*sock));
126 	if (new_sock == NULL) {
127 		SPDK_ERRLOG("sock allocation failed\n");
128 		return NULL;
129 	}
130 
131 	SPDK_CU_ASSERT_FATAL(g_ut_client_sock != NULL);
132 	g_ut_client_sock->peer = new_sock;
133 	new_sock->peer = g_ut_client_sock;
134 
135 	return &new_sock->base;
136 }
137 
138 static int
139 spdk_ut_sock_close(struct spdk_sock *_sock)
140 {
141 	struct spdk_ut_sock *sock = __ut_sock(_sock);
142 
143 	if (sock == g_ut_listen_sock) {
144 		g_ut_listen_sock = NULL;
145 	}
146 	if (sock == g_ut_client_sock) {
147 		g_ut_client_sock = NULL;
148 	}
149 
150 	if (sock->peer != NULL) {
151 		sock->peer->peer = NULL;
152 	}
153 
154 	free(_sock);
155 
156 	return 0;
157 }
158 
159 static ssize_t
160 spdk_ut_sock_recv(struct spdk_sock *_sock, void *buf, size_t len)
161 {
162 	struct spdk_ut_sock *sock = __ut_sock(_sock);
163 	char tmp[256];
164 
165 	len = spdk_min(len, sock->bytes_avail);
166 
167 	if (len == 0) {
168 		errno = EAGAIN;
169 		return -1;
170 	}
171 
172 	memcpy(buf, sock->buf, len);
173 	memcpy(tmp, &sock->buf[len], sock->bytes_avail - len);
174 	memcpy(sock->buf, tmp, sock->bytes_avail - len);
175 	sock->bytes_avail -= len;
176 
177 	return len;
178 }
179 
180 static ssize_t
181 spdk_ut_sock_readv(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
182 {
183 	struct spdk_ut_sock *sock = __ut_sock(_sock);
184 	size_t len;
185 	char tmp[256];
186 
187 	/* Test implementation only supports single iov for now. */
188 	CU_ASSERT(iovcnt == 1);
189 
190 	len = spdk_min(iov[0].iov_len, sock->bytes_avail);
191 
192 	if (len == 0) {
193 		errno = EAGAIN;
194 		return -1;
195 	}
196 
197 	memcpy(iov[0].iov_base, sock->buf, len);
198 	memcpy(tmp, &sock->buf[len], sock->bytes_avail - len);
199 	memcpy(sock->buf, tmp, sock->bytes_avail - len);
200 	sock->bytes_avail -= len;
201 
202 	return len;
203 }
204 
205 static ssize_t
206 spdk_ut_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
207 {
208 	struct spdk_ut_sock *sock = __ut_sock(_sock);
209 	struct spdk_ut_sock *peer;
210 
211 	SPDK_CU_ASSERT_FATAL(sock->peer != NULL);
212 	peer = sock->peer;
213 
214 	/* Test implementation only supports single iov for now. */
215 	CU_ASSERT(iovcnt == 1);
216 
217 	memcpy(&peer->buf[peer->bytes_avail], iov[0].iov_base, iov[0].iov_len);
218 	peer->bytes_avail += iov[0].iov_len;
219 
220 	return iov[0].iov_len;
221 }
222 
223 static int
224 spdk_ut_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes)
225 {
226 	return 0;
227 }
228 
229 static int
230 spdk_ut_sock_set_recvbuf(struct spdk_sock *_sock, int sz)
231 {
232 	return 0;
233 }
234 
235 static int
236 spdk_ut_sock_set_sendbuf(struct spdk_sock *_sock, int sz)
237 {
238 	return 0;
239 }
240 
241 static bool
242 spdk_ut_sock_is_ipv6(struct spdk_sock *_sock)
243 {
244 	return false;
245 }
246 
247 static bool
248 spdk_ut_sock_is_ipv4(struct spdk_sock *_sock)
249 {
250 	return true;
251 }
252 
253 static bool
254 spdk_ut_sock_is_connected(struct spdk_sock *_sock)
255 {
256 	struct spdk_ut_sock *sock = __ut_sock(_sock);
257 
258 	return (sock->peer != NULL);
259 }
260 
261 static int
262 spdk_ut_sock_get_placement_id(struct spdk_sock *_sock, int *placement_id)
263 {
264 	return -1;
265 }
266 
267 static int
268 spdk_ut_sock_set_priority(struct spdk_sock *_sock, int priority)
269 {
270 	return 0;
271 }
272 
273 static struct spdk_sock_group_impl *
274 spdk_ut_sock_group_impl_create(void)
275 {
276 	struct spdk_ut_sock_group_impl *group_impl;
277 
278 	group_impl = calloc(1, sizeof(*group_impl));
279 	SPDK_CU_ASSERT_FATAL(group_impl != NULL);
280 
281 	return &group_impl->base;
282 }
283 
284 static int
285 spdk_ut_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
286 {
287 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
288 	struct spdk_ut_sock *sock = __ut_sock(_sock);
289 
290 	group->sock = sock;
291 
292 	return 0;
293 }
294 
295 static int
296 spdk_ut_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
297 {
298 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
299 	struct spdk_ut_sock *sock = __ut_sock(_sock);
300 
301 	CU_ASSERT(group->sock == sock);
302 	group->sock = NULL;
303 
304 	return 0;
305 }
306 
307 static int
308 spdk_ut_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events,
309 			     struct spdk_sock **socks)
310 {
311 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
312 
313 	if (group->sock != NULL && group->sock->bytes_avail > 0) {
314 		socks[0] = &group->sock->base;
315 		return 1;
316 	}
317 
318 	return 0;
319 }
320 
321 static int
322 spdk_ut_sock_group_impl_close(struct spdk_sock_group_impl *_group)
323 {
324 	struct spdk_ut_sock_group_impl *group = __ut_group(_group);
325 
326 	CU_ASSERT(group->sock == NULL);
327 	free(_group);
328 
329 	return 0;
330 }
331 
332 static struct spdk_net_impl g_ut_net_impl = {
333 	.name		= "ut",
334 	.getaddr	= spdk_ut_sock_getaddr,
335 	.connect	= spdk_ut_sock_connect,
336 	.listen		= spdk_ut_sock_listen,
337 	.accept		= spdk_ut_sock_accept,
338 	.close		= spdk_ut_sock_close,
339 	.recv		= spdk_ut_sock_recv,
340 	.readv		= spdk_ut_sock_readv,
341 	.writev		= spdk_ut_sock_writev,
342 	.set_recvlowat	= spdk_ut_sock_set_recvlowat,
343 	.set_recvbuf	= spdk_ut_sock_set_recvbuf,
344 	.set_sendbuf	= spdk_ut_sock_set_sendbuf,
345 	.set_priority	= spdk_ut_sock_set_priority,
346 	.is_ipv6	= spdk_ut_sock_is_ipv6,
347 	.is_ipv4	= spdk_ut_sock_is_ipv4,
348 	.is_connected	= spdk_ut_sock_is_connected,
349 	.get_placement_id	= spdk_ut_sock_get_placement_id,
350 	.group_impl_create	= spdk_ut_sock_group_impl_create,
351 	.group_impl_add_sock	= spdk_ut_sock_group_impl_add_sock,
352 	.group_impl_remove_sock = spdk_ut_sock_group_impl_remove_sock,
353 	.group_impl_poll	= spdk_ut_sock_group_impl_poll,
354 	.group_impl_close	= spdk_ut_sock_group_impl_close,
355 };
356 
357 SPDK_NET_IMPL_REGISTER(ut, &g_ut_net_impl);
358 
359 static void
360 _sock(const char *ip, int port)
361 {
362 	struct spdk_sock *listen_sock;
363 	struct spdk_sock *server_sock;
364 	struct spdk_sock *client_sock;
365 	char *test_string = "abcdef";
366 	char buffer[64];
367 	ssize_t bytes_read, bytes_written;
368 	struct iovec iov;
369 	int rc;
370 
371 	listen_sock = spdk_sock_listen(ip, port);
372 	SPDK_CU_ASSERT_FATAL(listen_sock != NULL);
373 
374 	server_sock = spdk_sock_accept(listen_sock);
375 	CU_ASSERT(server_sock == NULL);
376 	CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK);
377 
378 	client_sock = spdk_sock_connect(ip, port);
379 	SPDK_CU_ASSERT_FATAL(client_sock != NULL);
380 
381 	/*
382 	 * Delay a bit here before checking if server socket is
383 	 *  ready.
384 	 */
385 	usleep(1000);
386 
387 	server_sock = spdk_sock_accept(listen_sock);
388 	SPDK_CU_ASSERT_FATAL(server_sock != NULL);
389 	CU_ASSERT(spdk_sock_is_connected(client_sock) == true);
390 	CU_ASSERT(spdk_sock_is_connected(server_sock) == true);
391 
392 	/* Test spdk_sock_recv */
393 	iov.iov_base = test_string;
394 	iov.iov_len = 7;
395 	bytes_written = spdk_sock_writev(client_sock, &iov, 1);
396 	CU_ASSERT(bytes_written == 7);
397 
398 	usleep(1000);
399 
400 	bytes_read = spdk_sock_recv(server_sock, buffer, 2);
401 	CU_ASSERT(bytes_read == 2);
402 
403 	usleep(1000);
404 
405 	bytes_read += spdk_sock_recv(server_sock, buffer + 2, 5);
406 	CU_ASSERT(bytes_read == 7);
407 
408 	CU_ASSERT(strncmp(test_string, buffer, 7) == 0);
409 
410 	/* Test spdk_sock_readv */
411 	iov.iov_base = test_string;
412 	iov.iov_len = 7;
413 	bytes_written = spdk_sock_writev(client_sock, &iov, 1);
414 	CU_ASSERT(bytes_written == 7);
415 
416 	usleep(1000);
417 
418 	iov.iov_base = buffer;
419 	iov.iov_len = 2;
420 	bytes_read = spdk_sock_readv(server_sock, &iov, 1);
421 	CU_ASSERT(bytes_read == 2);
422 
423 	usleep(1000);
424 
425 	iov.iov_base = buffer + 2;
426 	iov.iov_len = 5;
427 	bytes_read += spdk_sock_readv(server_sock, &iov, 1);
428 	CU_ASSERT(bytes_read == 7);
429 
430 	usleep(1000);
431 
432 	CU_ASSERT(strncmp(test_string, buffer, 7) == 0);
433 
434 	rc = spdk_sock_close(&client_sock);
435 	CU_ASSERT(client_sock == NULL);
436 	CU_ASSERT(rc == 0);
437 
438 	/* On FreeBSD, it takes a small amount of time for a close to propagate to the
439 	 * other side, even in loopback. Introduce a small sleep. */
440 	sleep(1);
441 	CU_ASSERT(spdk_sock_is_connected(server_sock) == false);
442 
443 	rc = spdk_sock_close(&server_sock);
444 	CU_ASSERT(server_sock == NULL);
445 	CU_ASSERT(rc == 0);
446 
447 	rc = spdk_sock_close(&listen_sock);
448 	CU_ASSERT(listen_sock == NULL);
449 	CU_ASSERT(rc == 0);
450 }
451 
452 static void
453 posix_sock(void)
454 {
455 	_sock("127.0.0.1", UT_PORT);
456 }
457 
458 static void
459 ut_sock(void)
460 {
461 	_sock(UT_IP, UT_PORT);
462 }
463 
464 static void
465 read_data(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock)
466 {
467 	struct spdk_sock *server_sock = cb_arg;
468 
469 	CU_ASSERT(server_sock == sock);
470 
471 	g_read_data_called = true;
472 	g_bytes_read += spdk_sock_recv(server_sock, g_buf + g_bytes_read, sizeof(g_buf) - g_bytes_read);
473 }
474 
475 static void
476 _sock_group(const char *ip, int port)
477 {
478 	struct spdk_sock_group *group;
479 	struct spdk_sock *listen_sock;
480 	struct spdk_sock *server_sock;
481 	struct spdk_sock *client_sock;
482 	char *test_string = "abcdef";
483 	ssize_t bytes_written;
484 	struct iovec iov;
485 	int rc;
486 
487 	listen_sock = spdk_sock_listen(ip, port);
488 	SPDK_CU_ASSERT_FATAL(listen_sock != NULL);
489 
490 	server_sock = spdk_sock_accept(listen_sock);
491 	CU_ASSERT(server_sock == NULL);
492 	CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK);
493 
494 	client_sock = spdk_sock_connect(ip, port);
495 	SPDK_CU_ASSERT_FATAL(client_sock != NULL);
496 
497 	usleep(1000);
498 
499 	server_sock = spdk_sock_accept(listen_sock);
500 	SPDK_CU_ASSERT_FATAL(server_sock != NULL);
501 
502 	group = spdk_sock_group_create(NULL);
503 	SPDK_CU_ASSERT_FATAL(group != NULL);
504 
505 	/* pass null cb_fn */
506 	rc = spdk_sock_group_add_sock(group, server_sock, NULL, NULL);
507 	CU_ASSERT(rc == -1);
508 	CU_ASSERT(errno == EINVAL);
509 
510 	rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock);
511 	CU_ASSERT(rc == 0);
512 
513 	/* try adding sock a second time */
514 	rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock);
515 	CU_ASSERT(rc == -1);
516 	CU_ASSERT(errno == EBUSY);
517 
518 	g_read_data_called = false;
519 	g_bytes_read = 0;
520 	rc = spdk_sock_group_poll(group);
521 
522 	CU_ASSERT(rc == 0);
523 	CU_ASSERT(g_read_data_called == false);
524 
525 	iov.iov_base = test_string;
526 	iov.iov_len = 7;
527 	bytes_written = spdk_sock_writev(client_sock, &iov, 1);
528 	CU_ASSERT(bytes_written == 7);
529 
530 	usleep(1000);
531 
532 	g_read_data_called = false;
533 	g_bytes_read = 0;
534 	rc = spdk_sock_group_poll(group);
535 
536 	CU_ASSERT(rc == 1);
537 	CU_ASSERT(g_read_data_called == true);
538 	CU_ASSERT(g_bytes_read == 7);
539 
540 	CU_ASSERT(strncmp(test_string, g_buf, 7) == 0);
541 
542 	rc = spdk_sock_close(&client_sock);
543 	CU_ASSERT(client_sock == NULL);
544 	CU_ASSERT(rc == 0);
545 
546 	/* Try to close sock_group while it still has sockets. */
547 	rc = spdk_sock_group_close(&group);
548 	CU_ASSERT(rc == -1);
549 	CU_ASSERT(errno == EBUSY);
550 
551 	/* Try to close sock while it is still part of a sock_group. */
552 	rc = spdk_sock_close(&server_sock);
553 	CU_ASSERT(rc == -1);
554 	CU_ASSERT(errno == EBUSY);
555 
556 	rc = spdk_sock_group_remove_sock(group, server_sock);
557 	CU_ASSERT(rc == 0);
558 
559 	rc = spdk_sock_group_close(&group);
560 	CU_ASSERT(group == NULL);
561 	CU_ASSERT(rc == 0);
562 
563 	rc = spdk_sock_close(&server_sock);
564 	CU_ASSERT(server_sock == NULL);
565 	CU_ASSERT(rc == 0);
566 
567 	rc = spdk_sock_close(&listen_sock);
568 	CU_ASSERT(listen_sock == NULL);
569 	CU_ASSERT(rc == 0);
570 }
571 
572 static void
573 posix_sock_group(void)
574 {
575 	_sock_group("127.0.0.1", UT_PORT);
576 }
577 
578 static void
579 ut_sock_group(void)
580 {
581 	_sock_group(UT_IP, UT_PORT);
582 }
583 
584 static void
585 read_data_fairness(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock)
586 {
587 	struct spdk_sock *server_sock = cb_arg;
588 	ssize_t bytes_read;
589 	char buf[1];
590 
591 	CU_ASSERT(g_server_sock_read == NULL);
592 	CU_ASSERT(server_sock == sock);
593 
594 	g_server_sock_read = server_sock;
595 	bytes_read = spdk_sock_recv(server_sock, buf, 1);
596 	CU_ASSERT(bytes_read == 1);
597 }
598 
599 static void
600 posix_sock_group_fairness(void)
601 {
602 	struct spdk_sock_group *group;
603 	struct spdk_sock *listen_sock;
604 	struct spdk_sock *server_sock[3];
605 	struct spdk_sock *client_sock[3];
606 	char test_char = 'a';
607 	ssize_t bytes_written;
608 	struct iovec iov;
609 	int i, rc;
610 
611 	listen_sock = spdk_sock_listen("127.0.0.1", UT_PORT);
612 	SPDK_CU_ASSERT_FATAL(listen_sock != NULL);
613 
614 	group = spdk_sock_group_create(NULL);
615 	SPDK_CU_ASSERT_FATAL(group != NULL);
616 
617 	for (i = 0; i < 3; i++) {
618 		client_sock[i] = spdk_sock_connect("127.0.0.1", UT_PORT);
619 		SPDK_CU_ASSERT_FATAL(client_sock[i] != NULL);
620 
621 		usleep(1000);
622 
623 		server_sock[i] = spdk_sock_accept(listen_sock);
624 		SPDK_CU_ASSERT_FATAL(server_sock[i] != NULL);
625 
626 		rc = spdk_sock_group_add_sock(group, server_sock[i],
627 					      read_data_fairness, server_sock[i]);
628 		CU_ASSERT(rc == 0);
629 	}
630 
631 	iov.iov_base = &test_char;
632 	iov.iov_len = 1;
633 
634 	for (i = 0; i < 3; i++) {
635 		bytes_written = spdk_sock_writev(client_sock[i], &iov, 1);
636 		CU_ASSERT(bytes_written == 1);
637 	}
638 
639 	usleep(1000);
640 
641 	/*
642 	 * Poll for just one event - this should be server sock 0, since that
643 	 *  is the peer of the first client sock that we wrote to.
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 	/*
651 	 * Now write another byte to client sock 0.  We want to ensure that
652 	 *  the sock group does not unfairly process the event for this sock
653 	 *  before the socks that were written to earlier.
654 	 */
655 	bytes_written = spdk_sock_writev(client_sock[0], &iov, 1);
656 	CU_ASSERT(bytes_written == 1);
657 
658 	usleep(1000);
659 
660 	g_server_sock_read = NULL;
661 	rc = spdk_sock_group_poll_count(group, 1);
662 	CU_ASSERT(rc == 1);
663 	CU_ASSERT(g_server_sock_read == server_sock[1]);
664 
665 	g_server_sock_read = NULL;
666 	rc = spdk_sock_group_poll_count(group, 1);
667 	CU_ASSERT(rc == 1);
668 	CU_ASSERT(g_server_sock_read == server_sock[2]);
669 
670 	g_server_sock_read = NULL;
671 	rc = spdk_sock_group_poll_count(group, 1);
672 	CU_ASSERT(rc == 1);
673 	CU_ASSERT(g_server_sock_read == server_sock[0]);
674 
675 	for (i = 0; i < 3; i++) {
676 		rc = spdk_sock_group_remove_sock(group, server_sock[i]);
677 		CU_ASSERT(rc == 0);
678 
679 		rc = spdk_sock_close(&client_sock[i]);
680 		CU_ASSERT(client_sock[i] == NULL);
681 		CU_ASSERT(rc == 0);
682 
683 		rc = spdk_sock_close(&server_sock[i]);
684 		CU_ASSERT(server_sock[i] == NULL);
685 		CU_ASSERT(rc == 0);
686 	}
687 
688 	rc = spdk_sock_group_close(&group);
689 	CU_ASSERT(group == NULL);
690 	CU_ASSERT(rc == 0);
691 
692 	rc = spdk_sock_close(&listen_sock);
693 	CU_ASSERT(listen_sock == NULL);
694 	CU_ASSERT(rc == 0);
695 }
696 
697 int
698 main(int argc, char **argv)
699 {
700 	CU_pSuite	suite = NULL;
701 	unsigned int	num_failures;
702 
703 	if (CU_initialize_registry() != CUE_SUCCESS) {
704 		return CU_get_error();
705 	}
706 
707 	suite = CU_add_suite("sock", NULL, NULL);
708 	if (suite == NULL) {
709 		CU_cleanup_registry();
710 		return CU_get_error();
711 	}
712 
713 	if (
714 		CU_add_test(suite, "posix_sock", posix_sock) == NULL ||
715 		CU_add_test(suite, "ut_sock", ut_sock) == NULL ||
716 		CU_add_test(suite, "posix_sock_group", posix_sock_group) == NULL ||
717 		CU_add_test(suite, "ut_sock_group", ut_sock_group) == NULL ||
718 		CU_add_test(suite, "posix_sock_group_fairness", posix_sock_group_fairness) == NULL) {
719 		CU_cleanup_registry();
720 		return CU_get_error();
721 	}
722 
723 	CU_basic_set_mode(CU_BRM_VERBOSE);
724 
725 	CU_basic_run_tests();
726 
727 	num_failures = CU_get_number_of_failures();
728 	CU_cleanup_registry();
729 
730 	return num_failures;
731 }
732