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, struct spdk_sock_opts *opts) 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, struct spdk_sock_opts *opts) 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 struct spdk_sock_group_impl * 270 spdk_ut_sock_group_impl_create(void) 271 { 272 struct spdk_ut_sock_group_impl *group_impl; 273 274 group_impl = calloc(1, sizeof(*group_impl)); 275 SPDK_CU_ASSERT_FATAL(group_impl != NULL); 276 277 return &group_impl->base; 278 } 279 280 static int 281 spdk_ut_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) 282 { 283 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 284 struct spdk_ut_sock *sock = __ut_sock(_sock); 285 286 group->sock = sock; 287 288 return 0; 289 } 290 291 static int 292 spdk_ut_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock) 293 { 294 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 295 struct spdk_ut_sock *sock = __ut_sock(_sock); 296 297 CU_ASSERT(group->sock == sock); 298 group->sock = NULL; 299 300 return 0; 301 } 302 303 static int 304 spdk_ut_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events, 305 struct spdk_sock **socks) 306 { 307 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 308 309 if (group->sock != NULL && group->sock->bytes_avail > 0) { 310 socks[0] = &group->sock->base; 311 return 1; 312 } 313 314 return 0; 315 } 316 317 static int 318 spdk_ut_sock_group_impl_close(struct spdk_sock_group_impl *_group) 319 { 320 struct spdk_ut_sock_group_impl *group = __ut_group(_group); 321 322 CU_ASSERT(group->sock == NULL); 323 free(_group); 324 325 return 0; 326 } 327 328 static struct spdk_net_impl g_ut_net_impl = { 329 .name = "ut", 330 .getaddr = spdk_ut_sock_getaddr, 331 .connect = spdk_ut_sock_connect, 332 .listen = spdk_ut_sock_listen, 333 .accept = spdk_ut_sock_accept, 334 .close = spdk_ut_sock_close, 335 .recv = spdk_ut_sock_recv, 336 .readv = spdk_ut_sock_readv, 337 .writev = spdk_ut_sock_writev, 338 .set_recvlowat = spdk_ut_sock_set_recvlowat, 339 .set_recvbuf = spdk_ut_sock_set_recvbuf, 340 .set_sendbuf = spdk_ut_sock_set_sendbuf, 341 .is_ipv6 = spdk_ut_sock_is_ipv6, 342 .is_ipv4 = spdk_ut_sock_is_ipv4, 343 .is_connected = spdk_ut_sock_is_connected, 344 .get_placement_id = spdk_ut_sock_get_placement_id, 345 .group_impl_create = spdk_ut_sock_group_impl_create, 346 .group_impl_add_sock = spdk_ut_sock_group_impl_add_sock, 347 .group_impl_remove_sock = spdk_ut_sock_group_impl_remove_sock, 348 .group_impl_poll = spdk_ut_sock_group_impl_poll, 349 .group_impl_close = spdk_ut_sock_group_impl_close, 350 }; 351 352 SPDK_NET_IMPL_REGISTER(ut, &g_ut_net_impl, DEFAULT_SOCK_PRIORITY + 2); 353 354 static void 355 _sock(const char *ip, int port, char *impl_name) 356 { 357 struct spdk_sock *listen_sock; 358 struct spdk_sock *server_sock; 359 struct spdk_sock *client_sock; 360 char *test_string = "abcdef"; 361 char buffer[64]; 362 ssize_t bytes_read, bytes_written; 363 struct iovec iov; 364 int rc; 365 366 listen_sock = spdk_sock_listen(ip, port, impl_name); 367 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 368 369 server_sock = spdk_sock_accept(listen_sock); 370 CU_ASSERT(server_sock == NULL); 371 CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK); 372 373 client_sock = spdk_sock_connect(ip, port, impl_name); 374 SPDK_CU_ASSERT_FATAL(client_sock != NULL); 375 376 /* 377 * Delay a bit here before checking if server socket is 378 * ready. 379 */ 380 usleep(1000); 381 382 server_sock = spdk_sock_accept(listen_sock); 383 SPDK_CU_ASSERT_FATAL(server_sock != NULL); 384 CU_ASSERT(spdk_sock_is_connected(client_sock) == true); 385 CU_ASSERT(spdk_sock_is_connected(server_sock) == true); 386 387 /* Test spdk_sock_recv */ 388 iov.iov_base = test_string; 389 iov.iov_len = 7; 390 bytes_written = spdk_sock_writev(client_sock, &iov, 1); 391 CU_ASSERT(bytes_written == 7); 392 393 usleep(1000); 394 395 bytes_read = spdk_sock_recv(server_sock, buffer, 2); 396 CU_ASSERT(bytes_read == 2); 397 398 usleep(1000); 399 400 bytes_read += spdk_sock_recv(server_sock, buffer + 2, 5); 401 CU_ASSERT(bytes_read == 7); 402 403 CU_ASSERT(strncmp(test_string, buffer, 7) == 0); 404 405 /* Test spdk_sock_readv */ 406 iov.iov_base = test_string; 407 iov.iov_len = 7; 408 bytes_written = spdk_sock_writev(client_sock, &iov, 1); 409 CU_ASSERT(bytes_written == 7); 410 411 usleep(1000); 412 413 iov.iov_base = buffer; 414 iov.iov_len = 2; 415 bytes_read = spdk_sock_readv(server_sock, &iov, 1); 416 CU_ASSERT(bytes_read == 2); 417 418 usleep(1000); 419 420 iov.iov_base = buffer + 2; 421 iov.iov_len = 5; 422 bytes_read += spdk_sock_readv(server_sock, &iov, 1); 423 CU_ASSERT(bytes_read == 7); 424 425 usleep(1000); 426 427 CU_ASSERT(strncmp(test_string, buffer, 7) == 0); 428 429 rc = spdk_sock_close(&client_sock); 430 CU_ASSERT(client_sock == NULL); 431 CU_ASSERT(rc == 0); 432 433 #if defined(__FreeBSD__) 434 /* On FreeBSD, it takes a small amount of time for a close to propagate to the 435 * other side, even in loopback. Introduce a small sleep. */ 436 sleep(1); 437 #endif 438 CU_ASSERT(spdk_sock_is_connected(server_sock) == false); 439 440 rc = spdk_sock_close(&server_sock); 441 CU_ASSERT(server_sock == NULL); 442 CU_ASSERT(rc == 0); 443 444 rc = spdk_sock_close(&listen_sock); 445 CU_ASSERT(listen_sock == NULL); 446 CU_ASSERT(rc == 0); 447 } 448 449 static void 450 posix_sock(void) 451 { 452 _sock("127.0.0.1", UT_PORT, "posix"); 453 } 454 455 static void 456 ut_sock(void) 457 { 458 _sock(UT_IP, UT_PORT, "ut"); 459 } 460 461 static void 462 read_data(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock) 463 { 464 struct spdk_sock *server_sock = cb_arg; 465 466 CU_ASSERT(server_sock == sock); 467 468 g_read_data_called = true; 469 g_bytes_read += spdk_sock_recv(server_sock, g_buf + g_bytes_read, sizeof(g_buf) - g_bytes_read); 470 } 471 472 static void 473 _sock_group(const char *ip, int port, char *impl_name) 474 { 475 struct spdk_sock_group *group; 476 struct spdk_sock *listen_sock; 477 struct spdk_sock *server_sock; 478 struct spdk_sock *client_sock; 479 char *test_string = "abcdef"; 480 ssize_t bytes_written; 481 struct iovec iov; 482 int rc; 483 484 listen_sock = spdk_sock_listen(ip, port, impl_name); 485 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 486 487 server_sock = spdk_sock_accept(listen_sock); 488 CU_ASSERT(server_sock == NULL); 489 CU_ASSERT(errno == EAGAIN || errno == EWOULDBLOCK); 490 491 client_sock = spdk_sock_connect(ip, port, impl_name); 492 SPDK_CU_ASSERT_FATAL(client_sock != NULL); 493 494 usleep(1000); 495 496 server_sock = spdk_sock_accept(listen_sock); 497 SPDK_CU_ASSERT_FATAL(server_sock != NULL); 498 499 group = spdk_sock_group_create(NULL); 500 SPDK_CU_ASSERT_FATAL(group != NULL); 501 502 /* pass null cb_fn */ 503 rc = spdk_sock_group_add_sock(group, server_sock, NULL, NULL); 504 CU_ASSERT(rc == -1); 505 CU_ASSERT(errno == EINVAL); 506 507 rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock); 508 CU_ASSERT(rc == 0); 509 510 /* try adding sock a second time */ 511 rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock); 512 CU_ASSERT(rc == -1); 513 CU_ASSERT(errno == EBUSY); 514 515 g_read_data_called = false; 516 g_bytes_read = 0; 517 rc = spdk_sock_group_poll(group); 518 519 CU_ASSERT(rc == 0); 520 CU_ASSERT(g_read_data_called == false); 521 522 iov.iov_base = test_string; 523 iov.iov_len = 7; 524 bytes_written = spdk_sock_writev(client_sock, &iov, 1); 525 CU_ASSERT(bytes_written == 7); 526 527 usleep(1000); 528 529 g_read_data_called = false; 530 g_bytes_read = 0; 531 rc = spdk_sock_group_poll(group); 532 533 CU_ASSERT(rc == 1); 534 CU_ASSERT(g_read_data_called == true); 535 CU_ASSERT(g_bytes_read == 7); 536 537 CU_ASSERT(strncmp(test_string, g_buf, 7) == 0); 538 539 rc = spdk_sock_close(&client_sock); 540 CU_ASSERT(client_sock == NULL); 541 CU_ASSERT(rc == 0); 542 543 /* Try to close sock_group while it still has sockets. */ 544 rc = spdk_sock_group_close(&group); 545 CU_ASSERT(rc == -1); 546 CU_ASSERT(errno == EBUSY); 547 548 /* Try to close sock while it is still part of a sock_group. */ 549 rc = spdk_sock_close(&server_sock); 550 CU_ASSERT(rc == -1); 551 CU_ASSERT(errno == EBUSY); 552 553 rc = spdk_sock_group_remove_sock(group, server_sock); 554 CU_ASSERT(rc == 0); 555 556 rc = spdk_sock_group_close(&group); 557 CU_ASSERT(group == NULL); 558 CU_ASSERT(rc == 0); 559 560 rc = spdk_sock_close(&server_sock); 561 CU_ASSERT(server_sock == NULL); 562 CU_ASSERT(rc == 0); 563 564 rc = spdk_sock_close(&listen_sock); 565 CU_ASSERT(listen_sock == NULL); 566 CU_ASSERT(rc == 0); 567 } 568 569 static void 570 posix_sock_group(void) 571 { 572 _sock_group("127.0.0.1", UT_PORT, "posix"); 573 } 574 575 static void 576 ut_sock_group(void) 577 { 578 _sock_group(UT_IP, UT_PORT, "ut"); 579 } 580 581 static void 582 read_data_fairness(void *cb_arg, struct spdk_sock_group *group, struct spdk_sock *sock) 583 { 584 struct spdk_sock *server_sock = cb_arg; 585 ssize_t bytes_read; 586 char buf[1]; 587 588 CU_ASSERT(g_server_sock_read == NULL); 589 CU_ASSERT(server_sock == sock); 590 591 g_server_sock_read = server_sock; 592 bytes_read = spdk_sock_recv(server_sock, buf, 1); 593 CU_ASSERT(bytes_read == 1); 594 } 595 596 static void 597 posix_sock_group_fairness(void) 598 { 599 struct spdk_sock_group *group; 600 struct spdk_sock *listen_sock; 601 struct spdk_sock *server_sock[3]; 602 struct spdk_sock *client_sock[3]; 603 char test_char = 'a'; 604 ssize_t bytes_written; 605 struct iovec iov; 606 int i, rc; 607 608 listen_sock = spdk_sock_listen("127.0.0.1", UT_PORT, "posix"); 609 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 610 611 group = spdk_sock_group_create(NULL); 612 SPDK_CU_ASSERT_FATAL(group != NULL); 613 614 for (i = 0; i < 3; i++) { 615 client_sock[i] = spdk_sock_connect("127.0.0.1", UT_PORT, "posix"); 616 SPDK_CU_ASSERT_FATAL(client_sock[i] != NULL); 617 618 usleep(1000); 619 620 server_sock[i] = spdk_sock_accept(listen_sock); 621 SPDK_CU_ASSERT_FATAL(server_sock[i] != NULL); 622 623 rc = spdk_sock_group_add_sock(group, server_sock[i], 624 read_data_fairness, server_sock[i]); 625 CU_ASSERT(rc == 0); 626 } 627 628 iov.iov_base = &test_char; 629 iov.iov_len = 1; 630 631 for (i = 0; i < 3; i++) { 632 bytes_written = spdk_sock_writev(client_sock[i], &iov, 1); 633 CU_ASSERT(bytes_written == 1); 634 } 635 636 usleep(1000); 637 638 /* 639 * Poll for just one event - this should be server sock 0, since that 640 * is the peer of the first client sock that we wrote to. 641 */ 642 g_server_sock_read = NULL; 643 rc = spdk_sock_group_poll_count(group, 1); 644 CU_ASSERT(rc == 1); 645 CU_ASSERT(g_server_sock_read == server_sock[0]); 646 647 /* 648 * Now write another byte to client sock 0. We want to ensure that 649 * the sock group does not unfairly process the event for this sock 650 * before the socks that were written to earlier. 651 */ 652 bytes_written = spdk_sock_writev(client_sock[0], &iov, 1); 653 CU_ASSERT(bytes_written == 1); 654 655 usleep(1000); 656 657 g_server_sock_read = NULL; 658 rc = spdk_sock_group_poll_count(group, 1); 659 CU_ASSERT(rc == 1); 660 CU_ASSERT(g_server_sock_read == server_sock[1]); 661 662 g_server_sock_read = NULL; 663 rc = spdk_sock_group_poll_count(group, 1); 664 CU_ASSERT(rc == 1); 665 CU_ASSERT(g_server_sock_read == server_sock[2]); 666 667 g_server_sock_read = NULL; 668 rc = spdk_sock_group_poll_count(group, 1); 669 CU_ASSERT(rc == 1); 670 CU_ASSERT(g_server_sock_read == server_sock[0]); 671 672 for (i = 0; i < 3; i++) { 673 rc = spdk_sock_group_remove_sock(group, server_sock[i]); 674 CU_ASSERT(rc == 0); 675 676 rc = spdk_sock_close(&client_sock[i]); 677 CU_ASSERT(client_sock[i] == NULL); 678 CU_ASSERT(rc == 0); 679 680 rc = spdk_sock_close(&server_sock[i]); 681 CU_ASSERT(server_sock[i] == NULL); 682 CU_ASSERT(rc == 0); 683 } 684 685 rc = spdk_sock_group_close(&group); 686 CU_ASSERT(group == NULL); 687 CU_ASSERT(rc == 0); 688 689 rc = spdk_sock_close(&listen_sock); 690 CU_ASSERT(listen_sock == NULL); 691 CU_ASSERT(rc == 0); 692 } 693 694 struct close_ctx { 695 struct spdk_sock_group *group; 696 struct spdk_sock *sock; 697 bool called; 698 }; 699 700 static void 701 _first_close_cb(void *cb_arg, int err) 702 { 703 struct close_ctx *ctx = cb_arg; 704 int rc; 705 706 ctx->called = true; 707 708 /* Always close the socket here */ 709 rc = spdk_sock_group_remove_sock(ctx->group, ctx->sock); 710 CU_ASSERT(rc == 0); 711 spdk_sock_close(&ctx->sock); 712 713 CU_ASSERT(err == 0); 714 } 715 716 static void 717 _second_close_cb(void *cb_arg, int err) 718 { 719 *(bool *)cb_arg = true; 720 CU_ASSERT(err == -ECANCELED); 721 } 722 723 static void 724 _sock_close(const char *ip, int port, char *impl_name) 725 { 726 struct spdk_sock_group *group; 727 struct spdk_sock *listen_sock; 728 struct spdk_sock *server_sock; 729 struct spdk_sock *client_sock; 730 uint8_t data_buf[64] = {}; 731 struct spdk_sock_request *req1, *req2; 732 struct close_ctx ctx = {}; 733 bool cb_arg2 = false; 734 int rc; 735 736 listen_sock = spdk_sock_listen(ip, port, impl_name); 737 SPDK_CU_ASSERT_FATAL(listen_sock != NULL); 738 739 client_sock = spdk_sock_connect(ip, port, impl_name); 740 SPDK_CU_ASSERT_FATAL(client_sock != NULL); 741 742 usleep(1000); 743 744 server_sock = spdk_sock_accept(listen_sock); 745 SPDK_CU_ASSERT_FATAL(server_sock != NULL); 746 747 group = spdk_sock_group_create(NULL); 748 SPDK_CU_ASSERT_FATAL(group != NULL); 749 750 rc = spdk_sock_group_add_sock(group, server_sock, read_data, server_sock); 751 CU_ASSERT(rc == 0); 752 753 /* Submit multiple async writevs on the server sock */ 754 755 req1 = calloc(1, sizeof(struct spdk_sock_request) + sizeof(struct iovec)); 756 SPDK_CU_ASSERT_FATAL(req1 != NULL); 757 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = data_buf; 758 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64; 759 ctx.group = group; 760 ctx.sock = server_sock; 761 ctx.called = false; 762 req1->iovcnt = 1; 763 req1->cb_fn = _first_close_cb; 764 req1->cb_arg = &ctx; 765 spdk_sock_writev_async(server_sock, req1); 766 CU_ASSERT(ctx.called == false); 767 768 req2 = calloc(1, sizeof(struct spdk_sock_request) + sizeof(struct iovec)); 769 SPDK_CU_ASSERT_FATAL(req2 != NULL); 770 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = data_buf; 771 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 64; 772 req2->iovcnt = 1; 773 req2->cb_fn = _second_close_cb; 774 req2->cb_arg = &cb_arg2; 775 spdk_sock_writev_async(server_sock, req2); 776 CU_ASSERT(cb_arg2 == false); 777 778 /* Poll the socket so the writev_async's send. The first one's 779 * callback will close the socket. */ 780 spdk_sock_group_poll(group); 781 if (ctx.called == false) { 782 /* Sometimes the zerocopy completion isn't posted immediately. Delay slightly 783 * and poll one more time. */ 784 usleep(1000); 785 spdk_sock_group_poll(group); 786 } 787 CU_ASSERT(ctx.called == true); 788 CU_ASSERT(cb_arg2 == true); 789 790 rc = spdk_sock_group_close(&group); 791 CU_ASSERT(group == NULL); 792 CU_ASSERT(rc == 0); 793 794 rc = spdk_sock_close(&client_sock); 795 CU_ASSERT(client_sock == NULL); 796 CU_ASSERT(rc == 0); 797 798 rc = spdk_sock_close(&listen_sock); 799 CU_ASSERT(listen_sock == NULL); 800 CU_ASSERT(rc == 0); 801 802 free(req1); 803 free(req2); 804 } 805 806 static void 807 _posix_sock_close(void) 808 { 809 _sock_close("127.0.0.1", UT_PORT, "posix"); 810 } 811 812 static void 813 sock_get_default_opts(void) 814 { 815 struct spdk_sock_opts opts; 816 817 /* opts_size is 0 */ 818 opts.opts_size = 0; 819 opts.priority = 3; 820 spdk_sock_get_default_opts(&opts); 821 CU_ASSERT(opts.priority == 3); 822 CU_ASSERT(opts.opts_size == 0); 823 824 /* opts_size is less than sizeof(opts) */ 825 opts.opts_size = 4; 826 opts.priority = 3; 827 spdk_sock_get_default_opts(&opts); 828 CU_ASSERT(opts.priority == 3); 829 CU_ASSERT(opts.opts_size == 4); 830 831 /* opts_size is equal to sizeof(opts) */ 832 opts.opts_size = sizeof(opts); 833 opts.priority = 3; 834 spdk_sock_get_default_opts(&opts); 835 CU_ASSERT(opts.priority == SPDK_SOCK_DEFAULT_PRIORITY); 836 CU_ASSERT(opts.opts_size == sizeof(opts)); 837 838 /* opts_size is larger then sizeof(opts) */ 839 opts.opts_size = sizeof(opts) + 1; 840 opts.priority = 3; 841 spdk_sock_get_default_opts(&opts); 842 CU_ASSERT(opts.priority == SPDK_SOCK_DEFAULT_PRIORITY); 843 CU_ASSERT(opts.opts_size == (sizeof(opts) + 1)); 844 } 845 846 int 847 main(int argc, char **argv) 848 { 849 CU_pSuite suite = NULL; 850 unsigned int num_failures; 851 852 CU_set_error_action(CUEA_ABORT); 853 CU_initialize_registry(); 854 855 suite = CU_add_suite("sock", NULL, NULL); 856 857 CU_ADD_TEST(suite, posix_sock); 858 CU_ADD_TEST(suite, ut_sock); 859 CU_ADD_TEST(suite, posix_sock_group); 860 CU_ADD_TEST(suite, ut_sock_group); 861 CU_ADD_TEST(suite, posix_sock_group_fairness); 862 CU_ADD_TEST(suite, _posix_sock_close); 863 CU_ADD_TEST(suite, sock_get_default_opts); 864 865 CU_basic_set_mode(CU_BRM_VERBOSE); 866 867 CU_basic_run_tests(); 868 869 num_failures = CU_get_number_of_failures(); 870 CU_cleanup_registry(); 871 872 return num_failures; 873 } 874