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 "spdk_internal/sock.h" 40 41 #include "sock/sock.c" 42 #include "sock/posix/posix.c" 43 44 #define UT_IP "test_ip" 45 #define UT_PORT 1234 46 47 bool g_read_data_called; 48 ssize_t g_bytes_read; 49 char g_buf[256]; 50 struct spdk_sock *g_server_sock_read; 51 int g_ut_accept_count; 52 struct spdk_ut_sock *g_ut_listen_sock; 53 struct spdk_ut_sock *g_ut_client_sock; 54 55 struct spdk_ut_sock { 56 struct spdk_sock base; 57 struct spdk_ut_sock *peer; 58 size_t bytes_avail; 59 char buf[256]; 60 }; 61 62 struct spdk_ut_sock_group_impl { 63 struct spdk_sock_group_impl base; 64 struct spdk_ut_sock *sock; 65 }; 66 67 #define __ut_sock(sock) (struct spdk_ut_sock *)sock 68 #define __ut_group(group) (struct spdk_ut_sock_group_impl *)group 69 70 static int 71 spdk_ut_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport, 72 char *caddr, int clen, uint16_t *cport) 73 { 74 return 0; 75 } 76 77 static struct spdk_sock * 78 spdk_ut_sock_listen(const char *ip, int port) 79 { 80 struct spdk_ut_sock *sock; 81 82 if (strcmp(ip, UT_IP) || port != UT_PORT) { 83 return NULL; 84 } 85 86 CU_ASSERT(g_ut_listen_sock == NULL); 87 88 sock = calloc(1, sizeof(*sock)); 89 SPDK_CU_ASSERT_FATAL(sock != NULL); 90 g_ut_listen_sock = sock; 91 92 return &sock->base; 93 } 94 95 static struct spdk_sock * 96 spdk_ut_sock_connect(const char *ip, int port) 97 { 98 struct spdk_ut_sock *sock; 99 100 if (strcmp(ip, UT_IP) || port != UT_PORT) { 101 return NULL; 102 } 103 104 sock = calloc(1, sizeof(*sock)); 105 SPDK_CU_ASSERT_FATAL(sock != NULL); 106 g_ut_accept_count++; 107 CU_ASSERT(g_ut_client_sock == NULL); 108 g_ut_client_sock = sock; 109 110 return &sock->base; 111 } 112 113 static struct spdk_sock * 114 spdk_ut_sock_accept(struct spdk_sock *_sock) 115 { 116 struct spdk_ut_sock *sock = __ut_sock(_sock); 117 struct spdk_ut_sock *new_sock; 118 119 CU_ASSERT(sock == g_ut_listen_sock); 120 121 if (g_ut_accept_count == 0) { 122 errno = EAGAIN; 123 return NULL; 124 } 125 126 g_ut_accept_count--; 127 new_sock = calloc(1, sizeof(*sock)); 128 if (new_sock == NULL) { 129 SPDK_ERRLOG("sock allocation failed\n"); 130 return NULL; 131 } 132 133 SPDK_CU_ASSERT_FATAL(g_ut_client_sock != NULL); 134 g_ut_client_sock->peer = new_sock; 135 new_sock->peer = g_ut_client_sock; 136 137 return &new_sock->base; 138 } 139 140 static int 141 spdk_ut_sock_close(struct spdk_sock *_sock) 142 { 143 struct spdk_ut_sock *sock = __ut_sock(_sock); 144 145 if (sock == g_ut_listen_sock) { 146 g_ut_listen_sock = NULL; 147 } 148 if (sock == g_ut_client_sock) { 149 g_ut_client_sock = NULL; 150 } 151 152 if (sock->peer != NULL) { 153 sock->peer->peer = NULL; 154 } 155 156 free(_sock); 157 158 return 0; 159 } 160 161 static ssize_t 162 spdk_ut_sock_recv(struct spdk_sock *_sock, void *buf, size_t len) 163 { 164 struct spdk_ut_sock *sock = __ut_sock(_sock); 165 char tmp[256]; 166 167 len = spdk_min(len, sock->bytes_avail); 168 169 if (len == 0) { 170 errno = EAGAIN; 171 return -1; 172 } 173 174 memcpy(buf, sock->buf, len); 175 memcpy(tmp, &sock->buf[len], sock->bytes_avail - len); 176 memcpy(sock->buf, tmp, sock->bytes_avail - len); 177 sock->bytes_avail -= len; 178 179 return len; 180 } 181 182 static ssize_t 183 spdk_ut_sock_readv(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) 184 { 185 struct spdk_ut_sock *sock = __ut_sock(_sock); 186 size_t len; 187 char tmp[256]; 188 189 /* Test implementation only supports single iov for now. */ 190 CU_ASSERT(iovcnt == 1); 191 192 len = spdk_min(iov[0].iov_len, sock->bytes_avail); 193 194 if (len == 0) { 195 errno = EAGAIN; 196 return -1; 197 } 198 199 memcpy(iov[0].iov_base, sock->buf, len); 200 memcpy(tmp, &sock->buf[len], sock->bytes_avail - len); 201 memcpy(sock->buf, tmp, sock->bytes_avail - len); 202 sock->bytes_avail -= len; 203 204 return len; 205 } 206 207 static ssize_t 208 spdk_ut_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt) 209 { 210 struct spdk_ut_sock *sock = __ut_sock(_sock); 211 struct spdk_ut_sock *peer; 212 213 SPDK_CU_ASSERT_FATAL(sock->peer != NULL); 214 peer = sock->peer; 215 216 /* Test implementation only supports single iov for now. */ 217 CU_ASSERT(iovcnt == 1); 218 219 memcpy(&peer->buf[peer->bytes_avail], iov[0].iov_base, iov[0].iov_len); 220 peer->bytes_avail += iov[0].iov_len; 221 222 return iov[0].iov_len; 223 } 224 225 static int 226 spdk_ut_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes) 227 { 228 return 0; 229 } 230 231 static int 232 spdk_ut_sock_set_recvbuf(struct spdk_sock *_sock, int sz) 233 { 234 return 0; 235 } 236 237 static int 238 spdk_ut_sock_set_sendbuf(struct spdk_sock *_sock, int sz) 239 { 240 return 0; 241 } 242 243 static bool 244 spdk_ut_sock_is_ipv6(struct spdk_sock *_sock) 245 { 246 return false; 247 } 248 249 static bool 250 spdk_ut_sock_is_ipv4(struct spdk_sock *_sock) 251 { 252 return true; 253 } 254 255 static bool 256 spdk_ut_sock_is_connected(struct spdk_sock *_sock) 257 { 258 struct spdk_ut_sock *sock = __ut_sock(_sock); 259 260 return (sock->peer != NULL); 261 } 262 263 static int 264 spdk_ut_sock_get_placement_id(struct spdk_sock *_sock, int *placement_id) 265 { 266 return -1; 267 } 268 269 static int 270 spdk_ut_sock_set_priority(struct spdk_sock *_sock, int priority) 271 { 272 return 0; 273 } 274 275 static struct spdk_sock_group_impl * 276 spdk_ut_sock_group_impl_create(void) 277 { 278 struct spdk_ut_sock_group_impl *group_impl; 279 280 group_impl = calloc(1, sizeof(*group_impl)); 281 SPDK_CU_ASSERT_FATAL(group_impl != NULL); 282 283 return &group_impl->base; 284 } 285 286 static int 287 spdk_ut_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) 288 { 289 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 290 struct spdk_ut_sock *sock = __ut_sock(_sock); 291 292 group->sock = sock; 293 294 return 0; 295 } 296 297 static int 298 spdk_ut_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) 299 { 300 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 301 struct spdk_ut_sock *sock = __ut_sock(_sock); 302 303 CU_ASSERT(group->sock == sock); 304 group->sock = NULL; 305 306 return 0; 307 } 308 309 static int 310 spdk_ut_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events, 311 struct spdk_sock **socks) 312 { 313 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 314 315 if (group->sock != NULL && group->sock->bytes_avail > 0) { 316 socks[0] = &group->sock->base; 317 return 1; 318 } 319 320 return 0; 321 } 322 323 static int 324 spdk_ut_sock_group_impl_close(struct spdk_sock_group_impl *_group) 325 { 326 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 327 328 CU_ASSERT(group->sock == NULL); 329 free(_group); 330 331 return 0; 332 } 333 334 static struct spdk_net_impl g_ut_net_impl = { 335 .name = "ut", 336 .getaddr = spdk_ut_sock_getaddr, 337 .connect = spdk_ut_sock_connect, 338 .listen = spdk_ut_sock_listen, 339 .accept = spdk_ut_sock_accept, 340 .close = spdk_ut_sock_close, 341 .recv = spdk_ut_sock_recv, 342 .readv = spdk_ut_sock_readv, 343 .writev = spdk_ut_sock_writev, 344 .set_recvlowat = spdk_ut_sock_set_recvlowat, 345 .set_recvbuf = spdk_ut_sock_set_recvbuf, 346 .set_sendbuf = spdk_ut_sock_set_sendbuf, 347 .set_priority = spdk_ut_sock_set_priority, 348 .is_ipv6 = spdk_ut_sock_is_ipv6, 349 .is_ipv4 = spdk_ut_sock_is_ipv4, 350 .is_connected = spdk_ut_sock_is_connected, 351 .get_placement_id = spdk_ut_sock_get_placement_id, 352 .group_impl_create = spdk_ut_sock_group_impl_create, 353 .group_impl_add_sock = spdk_ut_sock_group_impl_add_sock, 354 .group_impl_remove_sock = spdk_ut_sock_group_impl_remove_sock, 355 .group_impl_poll = spdk_ut_sock_group_impl_poll, 356 .group_impl_close = spdk_ut_sock_group_impl_close, 357 }; 358 359 SPDK_NET_IMPL_REGISTER(ut, &g_ut_net_impl, DEFAULT_SOCK_PRIORITY + 2); 360 361 static void 362 _sock(const char *ip, int port, char *impl_name) 363 { 364 struct spdk_sock *listen_sock; 365 struct spdk_sock *server_sock; 366 struct spdk_sock *client_sock; 367 char *test_string = "abcdef"; 368 char buffer[64]; 369 ssize_t bytes_read, bytes_written; 370 struct iovec iov; 371 int rc; 372 373 listen_sock = spdk_sock_listen(ip, port, impl_name); 374 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 375 376 server_sock = spdk_sock_accept(listen_sock); 377 CU_ASSERT(server_sock == NULL); 378 CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK); 379 380 client_sock = spdk_sock_connect(ip, port, impl_name); 381 SPDK_CU_ASSERT_FATAL(client_sock != NULL); 382 383 /* 384 * Delay a bit here before checking if server socket is 385 * ready. 386 */ 387 usleep(1000); 388 389 server_sock = spdk_sock_accept(listen_sock); 390 SPDK_CU_ASSERT_FATAL(server_sock != NULL); 391 CU_ASSERT(spdk_sock_is_connected(client_sock) == true); 392 CU_ASSERT(spdk_sock_is_connected(server_sock) == true); 393 394 /* Test spdk_sock_recv */ 395 iov.iov_base = test_string; 396 iov.iov_len = 7; 397 bytes_written = spdk_sock_writev(client_sock, &iov, 1); 398 CU_ASSERT(bytes_written == 7); 399 400 usleep(1000); 401 402 bytes_read = spdk_sock_recv(server_sock, buffer, 2); 403 CU_ASSERT(bytes_read == 2); 404 405 usleep(1000); 406 407 bytes_read += spdk_sock_recv(server_sock, buffer + 2, 5); 408 CU_ASSERT(bytes_read == 7); 409 410 CU_ASSERT(strncmp(test_string, buffer, 7) == 0); 411 412 /* Test spdk_sock_readv */ 413 iov.iov_base = test_string; 414 iov.iov_len = 7; 415 bytes_written = spdk_sock_writev(client_sock, &iov, 1); 416 CU_ASSERT(bytes_written == 7); 417 418 usleep(1000); 419 420 iov.iov_base = buffer; 421 iov.iov_len = 2; 422 bytes_read = spdk_sock_readv(server_sock, &iov, 1); 423 CU_ASSERT(bytes_read == 2); 424 425 usleep(1000); 426 427 iov.iov_base = buffer + 2; 428 iov.iov_len = 5; 429 bytes_read += spdk_sock_readv(server_sock, &iov, 1); 430 CU_ASSERT(bytes_read == 7); 431 432 usleep(1000); 433 434 CU_ASSERT(strncmp(test_string, buffer, 7) == 0); 435 436 rc = spdk_sock_close(&client_sock); 437 CU_ASSERT(client_sock == NULL); 438 CU_ASSERT(rc == 0); 439 440 #if defined(__FreeBSD__) 441 /* On FreeBSD, it takes a small amount of time for a close to propagate to the 442 * other side, even in loopback. Introduce a small sleep. */ 443 sleep(1); 444 #endif 445 CU_ASSERT(spdk_sock_is_connected(server_sock) == false); 446 447 rc = spdk_sock_close(&server_sock); 448 CU_ASSERT(server_sock == NULL); 449 CU_ASSERT(rc == 0); 450 451 rc = spdk_sock_close(&listen_sock); 452 CU_ASSERT(listen_sock == NULL); 453 CU_ASSERT(rc == 0); 454 } 455 456 static void 457 posix_sock(void) 458 { 459 _sock("127.0.0.1", UT_PORT, "posix"); 460 } 461 462 static void 463 ut_sock(void) 464 { 465 _sock(UT_IP, UT_PORT, "ut"); 466 } 467 468 static void 469 read_data(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock) 470 { 471 struct spdk_sock *server_sock = cb_arg; 472 473 CU_ASSERT(server_sock == sock); 474 475 g_read_data_called = true; 476 g_bytes_read += spdk_sock_recv(server_sock, g_buf + g_bytes_read, sizeof(g_buf) - g_bytes_read); 477 } 478 479 static void 480 _sock_group(const char *ip, int port, char *impl_name) 481 { 482 struct spdk_sock_group *group; 483 struct spdk_sock *listen_sock; 484 struct spdk_sock *server_sock; 485 struct spdk_sock *client_sock; 486 char *test_string = "abcdef"; 487 ssize_t bytes_written; 488 struct iovec iov; 489 int rc; 490 491 listen_sock = spdk_sock_listen(ip, port, impl_name); 492 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 493 494 server_sock = spdk_sock_accept(listen_sock); 495 CU_ASSERT(server_sock == NULL); 496 CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK); 497 498 client_sock = spdk_sock_connect(ip, port, impl_name); 499 SPDK_CU_ASSERT_FATAL(client_sock != NULL); 500 501 usleep(1000); 502 503 server_sock = spdk_sock_accept(listen_sock); 504 SPDK_CU_ASSERT_FATAL(server_sock != NULL); 505 506 group = spdk_sock_group_create(NULL); 507 SPDK_CU_ASSERT_FATAL(group != NULL); 508 509 /* pass null cb_fn */ 510 rc = spdk_sock_group_add_sock(group, server_sock, NULL, NULL); 511 CU_ASSERT(rc == -1); 512 CU_ASSERT(errno == EINVAL); 513 514 rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock); 515 CU_ASSERT(rc == 0); 516 517 /* try adding sock a second time */ 518 rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock); 519 CU_ASSERT(rc == -1); 520 CU_ASSERT(errno == EBUSY); 521 522 g_read_data_called = false; 523 g_bytes_read = 0; 524 rc = spdk_sock_group_poll(group); 525 526 CU_ASSERT(rc == 0); 527 CU_ASSERT(g_read_data_called == false); 528 529 iov.iov_base = test_string; 530 iov.iov_len = 7; 531 bytes_written = spdk_sock_writev(client_sock, &iov, 1); 532 CU_ASSERT(bytes_written == 7); 533 534 usleep(1000); 535 536 g_read_data_called = false; 537 g_bytes_read = 0; 538 rc = spdk_sock_group_poll(group); 539 540 CU_ASSERT(rc == 1); 541 CU_ASSERT(g_read_data_called == true); 542 CU_ASSERT(g_bytes_read == 7); 543 544 CU_ASSERT(strncmp(test_string, g_buf, 7) == 0); 545 546 rc = spdk_sock_close(&client_sock); 547 CU_ASSERT(client_sock == NULL); 548 CU_ASSERT(rc == 0); 549 550 /* Try to close sock_group while it still has sockets. */ 551 rc = spdk_sock_group_close(&group); 552 CU_ASSERT(rc == -1); 553 CU_ASSERT(errno == EBUSY); 554 555 /* Try to close sock while it is still part of a sock_group. */ 556 rc = spdk_sock_close(&server_sock); 557 CU_ASSERT(rc == -1); 558 CU_ASSERT(errno == EBUSY); 559 560 rc = spdk_sock_group_remove_sock(group, server_sock); 561 CU_ASSERT(rc == 0); 562 563 rc = spdk_sock_group_close(&group); 564 CU_ASSERT(group == NULL); 565 CU_ASSERT(rc == 0); 566 567 rc = spdk_sock_close(&server_sock); 568 CU_ASSERT(server_sock == NULL); 569 CU_ASSERT(rc == 0); 570 571 rc = spdk_sock_close(&listen_sock); 572 CU_ASSERT(listen_sock == NULL); 573 CU_ASSERT(rc == 0); 574 } 575 576 static void 577 posix_sock_group(void) 578 { 579 _sock_group("127.0.0.1", UT_PORT, "posix"); 580 } 581 582 static void 583 ut_sock_group(void) 584 { 585 _sock_group(UT_IP, UT_PORT, "ut"); 586 } 587 588 static void 589 read_data_fairness(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock) 590 { 591 struct spdk_sock *server_sock = cb_arg; 592 ssize_t bytes_read; 593 char buf[1]; 594 595 CU_ASSERT(g_server_sock_read == NULL); 596 CU_ASSERT(server_sock == sock); 597 598 g_server_sock_read = server_sock; 599 bytes_read = spdk_sock_recv(server_sock, buf, 1); 600 CU_ASSERT(bytes_read == 1); 601 } 602 603 static void 604 posix_sock_group_fairness(void) 605 { 606 struct spdk_sock_group *group; 607 struct spdk_sock *listen_sock; 608 struct spdk_sock *server_sock[3]; 609 struct spdk_sock *client_sock[3]; 610 char test_char = 'a'; 611 ssize_t bytes_written; 612 struct iovec iov; 613 int i, rc; 614 615 listen_sock = spdk_sock_listen("127.0.0.1", UT_PORT, "posix"); 616 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 617 618 group = spdk_sock_group_create(NULL); 619 SPDK_CU_ASSERT_FATAL(group != NULL); 620 621 for (i = 0; i < 3; i++) { 622 client_sock[i] = spdk_sock_connect("127.0.0.1", UT_PORT, "posix"); 623 SPDK_CU_ASSERT_FATAL(client_sock[i] != NULL); 624 625 usleep(1000); 626 627 server_sock[i] = spdk_sock_accept(listen_sock); 628 SPDK_CU_ASSERT_FATAL(server_sock[i] != NULL); 629 630 rc = spdk_sock_group_add_sock(group, server_sock[i], 631 read_data_fairness, server_sock[i]); 632 CU_ASSERT(rc == 0); 633 } 634 635 iov.iov_base = &test_char; 636 iov.iov_len = 1; 637 638 for (i = 0; i < 3; i++) { 639 bytes_written = spdk_sock_writev(client_sock[i], &iov, 1); 640 CU_ASSERT(bytes_written == 1); 641 } 642 643 usleep(1000); 644 645 /* 646 * Poll for just one event - this should be server sock 0, since that 647 * is the peer of the first client sock that we wrote to. 648 */ 649 g_server_sock_read = NULL; 650 rc = spdk_sock_group_poll_count(group, 1); 651 CU_ASSERT(rc == 1); 652 CU_ASSERT(g_server_sock_read == server_sock[0]); 653 654 /* 655 * Now write another byte to client sock 0. We want to ensure that 656 * the sock group does not unfairly process the event for this sock 657 * before the socks that were written to earlier. 658 */ 659 bytes_written = spdk_sock_writev(client_sock[0], &iov, 1); 660 CU_ASSERT(bytes_written == 1); 661 662 usleep(1000); 663 664 g_server_sock_read = NULL; 665 rc = spdk_sock_group_poll_count(group, 1); 666 CU_ASSERT(rc == 1); 667 CU_ASSERT(g_server_sock_read == server_sock[1]); 668 669 g_server_sock_read = NULL; 670 rc = spdk_sock_group_poll_count(group, 1); 671 CU_ASSERT(rc == 1); 672 CU_ASSERT(g_server_sock_read == server_sock[2]); 673 674 g_server_sock_read = NULL; 675 rc = spdk_sock_group_poll_count(group, 1); 676 CU_ASSERT(rc == 1); 677 CU_ASSERT(g_server_sock_read == server_sock[0]); 678 679 for (i = 0; i < 3; i++) { 680 rc = spdk_sock_group_remove_sock(group, server_sock[i]); 681 CU_ASSERT(rc == 0); 682 683 rc = spdk_sock_close(&client_sock[i]); 684 CU_ASSERT(client_sock[i] == NULL); 685 CU_ASSERT(rc == 0); 686 687 rc = spdk_sock_close(&server_sock[i]); 688 CU_ASSERT(server_sock[i] == NULL); 689 CU_ASSERT(rc == 0); 690 } 691 692 rc = spdk_sock_group_close(&group); 693 CU_ASSERT(group == NULL); 694 CU_ASSERT(rc == 0); 695 696 rc = spdk_sock_close(&listen_sock); 697 CU_ASSERT(listen_sock == NULL); 698 CU_ASSERT(rc == 0); 699 } 700 701 struct close_ctx { 702 struct spdk_sock_group *group; 703 struct spdk_sock *sock; 704 bool called; 705 }; 706 707 static void 708 _first_close_cb(void *cb_arg, int err) 709 { 710 struct close_ctx *ctx = cb_arg; 711 int rc; 712 713 ctx->called = true; 714 715 /* Always close the socket here */ 716 rc = spdk_sock_group_remove_sock(ctx->group, ctx->sock); 717 CU_ASSERT(rc == 0); 718 spdk_sock_close(&ctx->sock); 719 720 CU_ASSERT(err == 0); 721 } 722 723 static void 724 _second_close_cb(void *cb_arg, int err) 725 { 726 *(bool *)cb_arg = true; 727 CU_ASSERT(err == -ECANCELED); 728 } 729 730 static void 731 _sock_close(const char *ip, int port, char *impl_name) 732 { 733 struct spdk_sock_group *group; 734 struct spdk_sock *listen_sock; 735 struct spdk_sock *server_sock; 736 struct spdk_sock *client_sock; 737 uint8_t data_buf[64]; 738 struct spdk_sock_request *req1, *req2; 739 struct close_ctx ctx = {}; 740 bool cb_arg2 = false; 741 int rc; 742 743 listen_sock = spdk_sock_listen(ip, port, impl_name); 744 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 745 746 client_sock = spdk_sock_connect(ip, port, impl_name); 747 SPDK_CU_ASSERT_FATAL(client_sock != NULL); 748 749 usleep(1000); 750 751 server_sock = spdk_sock_accept(listen_sock); 752 SPDK_CU_ASSERT_FATAL(server_sock != NULL); 753 754 group = spdk_sock_group_create(NULL); 755 SPDK_CU_ASSERT_FATAL(group != NULL); 756 757 rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock); 758 CU_ASSERT(rc == 0); 759 760 /* Submit multiple async writevs on the server sock */ 761 762 req1 = calloc(1, sizeof(struct spdk_sock_request) + sizeof(struct iovec)); 763 SPDK_CU_ASSERT_FATAL(req1 != NULL); 764 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = data_buf; 765 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64; 766 ctx.group = group; 767 ctx.sock = server_sock; 768 ctx.called = false; 769 req1->iovcnt = 1; 770 req1->cb_fn = _first_close_cb; 771 req1->cb_arg = &ctx; 772 spdk_sock_writev_async(server_sock, req1); 773 CU_ASSERT(ctx.called == false); 774 775 req2 = calloc(1, sizeof(struct spdk_sock_request) + sizeof(struct iovec)); 776 SPDK_CU_ASSERT_FATAL(req2 != NULL); 777 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = data_buf; 778 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 64; 779 req2->iovcnt = 1; 780 req2->cb_fn = _second_close_cb; 781 req2->cb_arg = &cb_arg2; 782 spdk_sock_writev_async(server_sock, req2); 783 CU_ASSERT(cb_arg2 == false); 784 785 /* Poll the socket so the writev_async's send. The first one's 786 * callback will close the socket. */ 787 spdk_sock_group_poll(group); 788 if (ctx.called == false) { 789 /* Sometimes the zerocopy completion isn't posted immediately. Delay slightly 790 * and poll one more time. */ 791 usleep(1000); 792 spdk_sock_group_poll(group); 793 } 794 CU_ASSERT(ctx.called == true); 795 CU_ASSERT(cb_arg2 == true); 796 797 rc = spdk_sock_group_close(&group); 798 CU_ASSERT(group == NULL); 799 CU_ASSERT(rc == 0); 800 801 rc = spdk_sock_close(&client_sock); 802 CU_ASSERT(client_sock == NULL); 803 CU_ASSERT(rc == 0); 804 805 rc = spdk_sock_close(&listen_sock); 806 CU_ASSERT(listen_sock == NULL); 807 CU_ASSERT(rc == 0); 808 809 free(req1); 810 free(req2); 811 } 812 813 static void 814 posix_sock_close(void) 815 { 816 _sock_close("127.0.0.1", UT_PORT, "posix"); 817 } 818 819 int 820 main(int argc, char **argv) 821 { 822 CU_pSuite suite = NULL; 823 unsigned int num_failures; 824 825 if (CU_initialize_registry() != CUE_SUCCESS) { 826 return CU_get_error(); 827 } 828 829 suite = CU_add_suite("sock", NULL, NULL); 830 if (suite == NULL) { 831 CU_cleanup_registry(); 832 return CU_get_error(); 833 } 834 835 if ( 836 CU_add_test(suite, "posix_sock", posix_sock) == NULL || 837 CU_add_test(suite, "ut_sock", ut_sock) == NULL || 838 CU_add_test(suite, "posix_sock_group", posix_sock_group) == NULL || 839 CU_add_test(suite, "ut_sock_group", ut_sock_group) == NULL || 840 CU_add_test(suite, "posix_sock_group_fairness", posix_sock_group_fairness) == NULL || 841 CU_add_test(suite, "posix_sock_close", posix_sock_close) == NULL) { 842 CU_cleanup_registry(); 843 return CU_get_error(); 844 } 845 846 CU_basic_set_mode(CU_BRM_VERBOSE); 847 848 CU_basic_run_tests(); 849 850 num_failures = CU_get_number_of_failures(); 851 CU_cleanup_registry(); 852 853 return num_failures; 854 } 855