1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 5 #include <errno.h> 6 #include <limits.h> 7 #include <fcntl.h> 8 #include <string.h> 9 #include <stdbool.h> 10 #include <stdint.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <strings.h> 14 #include <signal.h> 15 #include <unistd.h> 16 17 #include <sys/poll.h> 18 #include <sys/sendfile.h> 19 #include <sys/stat.h> 20 #include <sys/socket.h> 21 #include <sys/types.h> 22 #include <sys/mman.h> 23 24 #include <netdb.h> 25 #include <netinet/in.h> 26 27 #include <linux/tcp.h> 28 29 extern int optind; 30 31 #ifndef IPPROTO_MPTCP 32 #define IPPROTO_MPTCP 262 33 #endif 34 #ifndef TCP_ULP 35 #define TCP_ULP 31 36 #endif 37 38 static int poll_timeout = 10 * 1000; 39 static bool listen_mode; 40 static bool quit; 41 42 enum cfg_mode { 43 CFG_MODE_POLL, 44 CFG_MODE_MMAP, 45 CFG_MODE_SENDFILE, 46 }; 47 48 static enum cfg_mode cfg_mode = CFG_MODE_POLL; 49 static const char *cfg_host; 50 static const char *cfg_port = "12000"; 51 static int cfg_sock_proto = IPPROTO_MPTCP; 52 static bool tcpulp_audit; 53 static int pf = AF_INET; 54 static int cfg_sndbuf; 55 static int cfg_rcvbuf; 56 static bool cfg_join; 57 static bool cfg_remove; 58 static unsigned int cfg_do_w; 59 static int cfg_wait; 60 61 static void die_usage(void) 62 { 63 fprintf(stderr, "Usage: mptcp_connect [-6] [-u] [-s MPTCP|TCP] [-p port] [-m mode]" 64 "[-l] [-w sec] connect_address\n"); 65 fprintf(stderr, "\t-6 use ipv6\n"); 66 fprintf(stderr, "\t-t num -- set poll timeout to num\n"); 67 fprintf(stderr, "\t-S num -- set SO_SNDBUF to num\n"); 68 fprintf(stderr, "\t-R num -- set SO_RCVBUF to num\n"); 69 fprintf(stderr, "\t-p num -- use port num\n"); 70 fprintf(stderr, "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n"); 71 fprintf(stderr, "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n"); 72 fprintf(stderr, "\t-u -- check mptcp ulp\n"); 73 fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n"); 74 exit(1); 75 } 76 77 static void handle_signal(int nr) 78 { 79 quit = true; 80 } 81 82 static const char *getxinfo_strerr(int err) 83 { 84 if (err == EAI_SYSTEM) 85 return strerror(errno); 86 87 return gai_strerror(err); 88 } 89 90 static void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen, 91 char *host, socklen_t hostlen, 92 char *serv, socklen_t servlen) 93 { 94 int flags = NI_NUMERICHOST | NI_NUMERICSERV; 95 int err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, 96 flags); 97 98 if (err) { 99 const char *errstr = getxinfo_strerr(err); 100 101 fprintf(stderr, "Fatal: getnameinfo: %s\n", errstr); 102 exit(1); 103 } 104 } 105 106 static void xgetaddrinfo(const char *node, const char *service, 107 const struct addrinfo *hints, 108 struct addrinfo **res) 109 { 110 int err = getaddrinfo(node, service, hints, res); 111 112 if (err) { 113 const char *errstr = getxinfo_strerr(err); 114 115 fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", 116 node ? node : "", service ? service : "", errstr); 117 exit(1); 118 } 119 } 120 121 static void set_rcvbuf(int fd, unsigned int size) 122 { 123 int err; 124 125 err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 126 if (err) { 127 perror("set SO_RCVBUF"); 128 exit(1); 129 } 130 } 131 132 static void set_sndbuf(int fd, unsigned int size) 133 { 134 int err; 135 136 err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); 137 if (err) { 138 perror("set SO_SNDBUF"); 139 exit(1); 140 } 141 } 142 143 static int sock_listen_mptcp(const char * const listenaddr, 144 const char * const port) 145 { 146 int sock; 147 struct addrinfo hints = { 148 .ai_protocol = IPPROTO_TCP, 149 .ai_socktype = SOCK_STREAM, 150 .ai_flags = AI_PASSIVE | AI_NUMERICHOST 151 }; 152 153 hints.ai_family = pf; 154 155 struct addrinfo *a, *addr; 156 int one = 1; 157 158 xgetaddrinfo(listenaddr, port, &hints, &addr); 159 hints.ai_family = pf; 160 161 for (a = addr; a; a = a->ai_next) { 162 sock = socket(a->ai_family, a->ai_socktype, cfg_sock_proto); 163 if (sock < 0) 164 continue; 165 166 if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, 167 sizeof(one))) 168 perror("setsockopt"); 169 170 if (bind(sock, a->ai_addr, a->ai_addrlen) == 0) 171 break; /* success */ 172 173 perror("bind"); 174 close(sock); 175 sock = -1; 176 } 177 178 freeaddrinfo(addr); 179 180 if (sock < 0) { 181 fprintf(stderr, "Could not create listen socket\n"); 182 return sock; 183 } 184 185 if (listen(sock, 20)) { 186 perror("listen"); 187 close(sock); 188 return -1; 189 } 190 191 return sock; 192 } 193 194 static bool sock_test_tcpulp(const char * const remoteaddr, 195 const char * const port) 196 { 197 struct addrinfo hints = { 198 .ai_protocol = IPPROTO_TCP, 199 .ai_socktype = SOCK_STREAM, 200 }; 201 struct addrinfo *a, *addr; 202 int sock = -1, ret = 0; 203 bool test_pass = false; 204 205 hints.ai_family = AF_INET; 206 207 xgetaddrinfo(remoteaddr, port, &hints, &addr); 208 for (a = addr; a; a = a->ai_next) { 209 sock = socket(a->ai_family, a->ai_socktype, IPPROTO_TCP); 210 if (sock < 0) { 211 perror("socket"); 212 continue; 213 } 214 ret = setsockopt(sock, IPPROTO_TCP, TCP_ULP, "mptcp", 215 sizeof("mptcp")); 216 if (ret == -1 && errno == EOPNOTSUPP) 217 test_pass = true; 218 close(sock); 219 220 if (test_pass) 221 break; 222 if (!ret) 223 fprintf(stderr, 224 "setsockopt(TCP_ULP) returned 0\n"); 225 else 226 perror("setsockopt(TCP_ULP)"); 227 } 228 return test_pass; 229 } 230 231 static int sock_connect_mptcp(const char * const remoteaddr, 232 const char * const port, int proto) 233 { 234 struct addrinfo hints = { 235 .ai_protocol = IPPROTO_TCP, 236 .ai_socktype = SOCK_STREAM, 237 }; 238 struct addrinfo *a, *addr; 239 int sock = -1; 240 241 hints.ai_family = pf; 242 243 xgetaddrinfo(remoteaddr, port, &hints, &addr); 244 for (a = addr; a; a = a->ai_next) { 245 sock = socket(a->ai_family, a->ai_socktype, proto); 246 if (sock < 0) { 247 perror("socket"); 248 continue; 249 } 250 251 if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) 252 break; /* success */ 253 254 perror("connect()"); 255 close(sock); 256 sock = -1; 257 } 258 259 freeaddrinfo(addr); 260 return sock; 261 } 262 263 static size_t do_rnd_write(const int fd, char *buf, const size_t len) 264 { 265 static bool first = true; 266 unsigned int do_w; 267 ssize_t bw; 268 269 do_w = rand() & 0xffff; 270 if (do_w == 0 || do_w > len) 271 do_w = len; 272 273 if (cfg_join && first && do_w > 100) 274 do_w = 100; 275 276 if (cfg_remove && do_w > cfg_do_w) 277 do_w = cfg_do_w; 278 279 bw = write(fd, buf, do_w); 280 if (bw < 0) 281 perror("write"); 282 283 /* let the join handshake complete, before going on */ 284 if (cfg_join && first) { 285 usleep(200000); 286 first = false; 287 } 288 289 if (cfg_remove) 290 usleep(200000); 291 292 return bw; 293 } 294 295 static size_t do_write(const int fd, char *buf, const size_t len) 296 { 297 size_t offset = 0; 298 299 while (offset < len) { 300 size_t written; 301 ssize_t bw; 302 303 bw = write(fd, buf + offset, len - offset); 304 if (bw < 0) { 305 perror("write"); 306 return 0; 307 } 308 309 written = (size_t)bw; 310 offset += written; 311 } 312 313 return offset; 314 } 315 316 static ssize_t do_rnd_read(const int fd, char *buf, const size_t len) 317 { 318 size_t cap = rand(); 319 320 cap &= 0xffff; 321 322 if (cap == 0) 323 cap = 1; 324 else if (cap > len) 325 cap = len; 326 327 return read(fd, buf, cap); 328 } 329 330 static void set_nonblock(int fd) 331 { 332 int flags = fcntl(fd, F_GETFL); 333 334 if (flags == -1) 335 return; 336 337 fcntl(fd, F_SETFL, flags | O_NONBLOCK); 338 } 339 340 static int copyfd_io_poll(int infd, int peerfd, int outfd) 341 { 342 struct pollfd fds = { 343 .fd = peerfd, 344 .events = POLLIN | POLLOUT, 345 }; 346 unsigned int woff = 0, wlen = 0; 347 char wbuf[8192]; 348 349 set_nonblock(peerfd); 350 351 for (;;) { 352 char rbuf[8192]; 353 ssize_t len; 354 355 if (fds.events == 0) 356 break; 357 358 switch (poll(&fds, 1, poll_timeout)) { 359 case -1: 360 if (errno == EINTR) 361 continue; 362 perror("poll"); 363 return 1; 364 case 0: 365 fprintf(stderr, "%s: poll timed out (events: " 366 "POLLIN %u, POLLOUT %u)\n", __func__, 367 fds.events & POLLIN, fds.events & POLLOUT); 368 return 2; 369 } 370 371 if (fds.revents & POLLIN) { 372 len = do_rnd_read(peerfd, rbuf, sizeof(rbuf)); 373 if (len == 0) { 374 /* no more data to receive: 375 * peer has closed its write side 376 */ 377 fds.events &= ~POLLIN; 378 379 if ((fds.events & POLLOUT) == 0) 380 /* and nothing more to send */ 381 break; 382 383 /* Else, still have data to transmit */ 384 } else if (len < 0) { 385 perror("read"); 386 return 3; 387 } 388 389 do_write(outfd, rbuf, len); 390 } 391 392 if (fds.revents & POLLOUT) { 393 if (wlen == 0) { 394 woff = 0; 395 wlen = read(infd, wbuf, sizeof(wbuf)); 396 } 397 398 if (wlen > 0) { 399 ssize_t bw; 400 401 bw = do_rnd_write(peerfd, wbuf + woff, wlen); 402 if (bw < 0) 403 return 111; 404 405 woff += bw; 406 wlen -= bw; 407 } else if (wlen == 0) { 408 /* We have no more data to send. */ 409 fds.events &= ~POLLOUT; 410 411 if ((fds.events & POLLIN) == 0) 412 /* ... and peer also closed already */ 413 break; 414 415 /* ... but we still receive. 416 * Close our write side, ev. give some time 417 * for address notification and/or checking 418 * the current status 419 */ 420 if (cfg_wait) 421 usleep(cfg_wait); 422 shutdown(peerfd, SHUT_WR); 423 } else { 424 if (errno == EINTR) 425 continue; 426 perror("read"); 427 return 4; 428 } 429 } 430 431 if (fds.revents & (POLLERR | POLLNVAL)) { 432 fprintf(stderr, "Unexpected revents: " 433 "POLLERR/POLLNVAL(%x)\n", fds.revents); 434 return 5; 435 } 436 } 437 438 /* leave some time for late join/announce */ 439 if (cfg_join || cfg_remove) 440 usleep(cfg_wait); 441 442 close(peerfd); 443 return 0; 444 } 445 446 static int do_recvfile(int infd, int outfd) 447 { 448 ssize_t r; 449 450 do { 451 char buf[16384]; 452 453 r = do_rnd_read(infd, buf, sizeof(buf)); 454 if (r > 0) { 455 if (write(outfd, buf, r) != r) 456 break; 457 } else if (r < 0) { 458 perror("read"); 459 } 460 } while (r > 0); 461 462 return (int)r; 463 } 464 465 static int do_mmap(int infd, int outfd, unsigned int size) 466 { 467 char *inbuf = mmap(NULL, size, PROT_READ, MAP_SHARED, infd, 0); 468 ssize_t ret = 0, off = 0; 469 size_t rem; 470 471 if (inbuf == MAP_FAILED) { 472 perror("mmap"); 473 return 1; 474 } 475 476 rem = size; 477 478 while (rem > 0) { 479 ret = write(outfd, inbuf + off, rem); 480 481 if (ret < 0) { 482 perror("write"); 483 break; 484 } 485 486 off += ret; 487 rem -= ret; 488 } 489 490 munmap(inbuf, size); 491 return rem; 492 } 493 494 static int get_infd_size(int fd) 495 { 496 struct stat sb; 497 ssize_t count; 498 int err; 499 500 err = fstat(fd, &sb); 501 if (err < 0) { 502 perror("fstat"); 503 return -1; 504 } 505 506 if ((sb.st_mode & S_IFMT) != S_IFREG) { 507 fprintf(stderr, "%s: stdin is not a regular file\n", __func__); 508 return -2; 509 } 510 511 count = sb.st_size; 512 if (count > INT_MAX) { 513 fprintf(stderr, "File too large: %zu\n", count); 514 return -3; 515 } 516 517 return (int)count; 518 } 519 520 static int do_sendfile(int infd, int outfd, unsigned int count) 521 { 522 while (count > 0) { 523 ssize_t r; 524 525 r = sendfile(outfd, infd, NULL, count); 526 if (r < 0) { 527 perror("sendfile"); 528 return 3; 529 } 530 531 count -= r; 532 } 533 534 return 0; 535 } 536 537 static int copyfd_io_mmap(int infd, int peerfd, int outfd, 538 unsigned int size) 539 { 540 int err; 541 542 if (listen_mode) { 543 err = do_recvfile(peerfd, outfd); 544 if (err) 545 return err; 546 547 err = do_mmap(infd, peerfd, size); 548 } else { 549 err = do_mmap(infd, peerfd, size); 550 if (err) 551 return err; 552 553 shutdown(peerfd, SHUT_WR); 554 555 err = do_recvfile(peerfd, outfd); 556 } 557 558 return err; 559 } 560 561 static int copyfd_io_sendfile(int infd, int peerfd, int outfd, 562 unsigned int size) 563 { 564 int err; 565 566 if (listen_mode) { 567 err = do_recvfile(peerfd, outfd); 568 if (err) 569 return err; 570 571 err = do_sendfile(infd, peerfd, size); 572 } else { 573 err = do_sendfile(infd, peerfd, size); 574 if (err) 575 return err; 576 err = do_recvfile(peerfd, outfd); 577 } 578 579 return err; 580 } 581 582 static int copyfd_io(int infd, int peerfd, int outfd) 583 { 584 int file_size; 585 586 switch (cfg_mode) { 587 case CFG_MODE_POLL: 588 return copyfd_io_poll(infd, peerfd, outfd); 589 case CFG_MODE_MMAP: 590 file_size = get_infd_size(infd); 591 if (file_size < 0) 592 return file_size; 593 return copyfd_io_mmap(infd, peerfd, outfd, file_size); 594 case CFG_MODE_SENDFILE: 595 file_size = get_infd_size(infd); 596 if (file_size < 0) 597 return file_size; 598 return copyfd_io_sendfile(infd, peerfd, outfd, file_size); 599 } 600 601 fprintf(stderr, "Invalid mode %d\n", cfg_mode); 602 603 die_usage(); 604 return 1; 605 } 606 607 static void check_sockaddr(int pf, struct sockaddr_storage *ss, 608 socklen_t salen) 609 { 610 struct sockaddr_in6 *sin6; 611 struct sockaddr_in *sin; 612 socklen_t wanted_size = 0; 613 614 switch (pf) { 615 case AF_INET: 616 wanted_size = sizeof(*sin); 617 sin = (void *)ss; 618 if (!sin->sin_port) 619 fprintf(stderr, "accept: something wrong: ip connection from port 0"); 620 break; 621 case AF_INET6: 622 wanted_size = sizeof(*sin6); 623 sin6 = (void *)ss; 624 if (!sin6->sin6_port) 625 fprintf(stderr, "accept: something wrong: ipv6 connection from port 0"); 626 break; 627 default: 628 fprintf(stderr, "accept: Unknown pf %d, salen %u\n", pf, salen); 629 return; 630 } 631 632 if (salen != wanted_size) 633 fprintf(stderr, "accept: size mismatch, got %d expected %d\n", 634 (int)salen, wanted_size); 635 636 if (ss->ss_family != pf) 637 fprintf(stderr, "accept: pf mismatch, expect %d, ss_family is %d\n", 638 (int)ss->ss_family, pf); 639 } 640 641 static void check_getpeername(int fd, struct sockaddr_storage *ss, socklen_t salen) 642 { 643 struct sockaddr_storage peerss; 644 socklen_t peersalen = sizeof(peerss); 645 646 if (getpeername(fd, (struct sockaddr *)&peerss, &peersalen) < 0) { 647 perror("getpeername"); 648 return; 649 } 650 651 if (peersalen != salen) { 652 fprintf(stderr, "%s: %d vs %d\n", __func__, peersalen, salen); 653 return; 654 } 655 656 if (memcmp(ss, &peerss, peersalen)) { 657 char a[INET6_ADDRSTRLEN]; 658 char b[INET6_ADDRSTRLEN]; 659 char c[INET6_ADDRSTRLEN]; 660 char d[INET6_ADDRSTRLEN]; 661 662 xgetnameinfo((struct sockaddr *)ss, salen, 663 a, sizeof(a), b, sizeof(b)); 664 665 xgetnameinfo((struct sockaddr *)&peerss, peersalen, 666 c, sizeof(c), d, sizeof(d)); 667 668 fprintf(stderr, "%s: memcmp failure: accept %s vs peername %s, %s vs %s salen %d vs %d\n", 669 __func__, a, c, b, d, peersalen, salen); 670 } 671 } 672 673 static void check_getpeername_connect(int fd) 674 { 675 struct sockaddr_storage ss; 676 socklen_t salen = sizeof(ss); 677 char a[INET6_ADDRSTRLEN]; 678 char b[INET6_ADDRSTRLEN]; 679 680 if (getpeername(fd, (struct sockaddr *)&ss, &salen) < 0) { 681 perror("getpeername"); 682 return; 683 } 684 685 xgetnameinfo((struct sockaddr *)&ss, salen, 686 a, sizeof(a), b, sizeof(b)); 687 688 if (strcmp(cfg_host, a) || strcmp(cfg_port, b)) 689 fprintf(stderr, "%s: %s vs %s, %s vs %s\n", __func__, 690 cfg_host, a, cfg_port, b); 691 } 692 693 static void maybe_close(int fd) 694 { 695 unsigned int r = rand(); 696 697 if (!(cfg_join || cfg_remove) && (r & 1)) 698 close(fd); 699 } 700 701 int main_loop_s(int listensock) 702 { 703 struct sockaddr_storage ss; 704 struct pollfd polls; 705 socklen_t salen; 706 int remotesock; 707 708 polls.fd = listensock; 709 polls.events = POLLIN; 710 711 switch (poll(&polls, 1, poll_timeout)) { 712 case -1: 713 perror("poll"); 714 return 1; 715 case 0: 716 fprintf(stderr, "%s: timed out\n", __func__); 717 close(listensock); 718 return 2; 719 } 720 721 salen = sizeof(ss); 722 remotesock = accept(listensock, (struct sockaddr *)&ss, &salen); 723 if (remotesock >= 0) { 724 maybe_close(listensock); 725 check_sockaddr(pf, &ss, salen); 726 check_getpeername(remotesock, &ss, salen); 727 728 return copyfd_io(0, remotesock, 1); 729 } 730 731 perror("accept"); 732 733 return 1; 734 } 735 736 static void init_rng(void) 737 { 738 int fd = open("/dev/urandom", O_RDONLY); 739 unsigned int foo; 740 741 if (fd > 0) { 742 int ret = read(fd, &foo, sizeof(foo)); 743 744 if (ret < 0) 745 srand(fd + foo); 746 close(fd); 747 } 748 749 srand(foo); 750 } 751 752 int main_loop(void) 753 { 754 int fd; 755 756 /* listener is ready. */ 757 fd = sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto); 758 if (fd < 0) 759 return 2; 760 761 check_getpeername_connect(fd); 762 763 if (cfg_rcvbuf) 764 set_rcvbuf(fd, cfg_rcvbuf); 765 if (cfg_sndbuf) 766 set_sndbuf(fd, cfg_sndbuf); 767 768 return copyfd_io(0, fd, 1); 769 } 770 771 int parse_proto(const char *proto) 772 { 773 if (!strcasecmp(proto, "MPTCP")) 774 return IPPROTO_MPTCP; 775 if (!strcasecmp(proto, "TCP")) 776 return IPPROTO_TCP; 777 778 fprintf(stderr, "Unknown protocol: %s\n.", proto); 779 die_usage(); 780 781 /* silence compiler warning */ 782 return 0; 783 } 784 785 int parse_mode(const char *mode) 786 { 787 if (!strcasecmp(mode, "poll")) 788 return CFG_MODE_POLL; 789 if (!strcasecmp(mode, "mmap")) 790 return CFG_MODE_MMAP; 791 if (!strcasecmp(mode, "sendfile")) 792 return CFG_MODE_SENDFILE; 793 794 fprintf(stderr, "Unknown test mode: %s\n", mode); 795 fprintf(stderr, "Supported modes are:\n"); 796 fprintf(stderr, "\t\t\"poll\" - interleaved read/write using poll()\n"); 797 fprintf(stderr, "\t\t\"mmap\" - send entire input file (mmap+write), then read response (-l will read input first)\n"); 798 fprintf(stderr, "\t\t\"sendfile\" - send entire input file (sendfile), then read response (-l will read input first)\n"); 799 800 die_usage(); 801 802 /* silence compiler warning */ 803 return 0; 804 } 805 806 static int parse_int(const char *size) 807 { 808 unsigned long s; 809 810 errno = 0; 811 812 s = strtoul(size, NULL, 0); 813 814 if (errno) { 815 fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 816 size, strerror(errno)); 817 die_usage(); 818 } 819 820 if (s > INT_MAX) { 821 fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 822 size, strerror(ERANGE)); 823 die_usage(); 824 } 825 826 return (int)s; 827 } 828 829 static void parse_opts(int argc, char **argv) 830 { 831 int c; 832 833 while ((c = getopt(argc, argv, "6jr:lp:s:hut:m:S:R:w:")) != -1) { 834 switch (c) { 835 case 'j': 836 cfg_join = true; 837 cfg_mode = CFG_MODE_POLL; 838 cfg_wait = 400000; 839 break; 840 case 'r': 841 cfg_remove = true; 842 cfg_mode = CFG_MODE_POLL; 843 cfg_wait = 400000; 844 cfg_do_w = atoi(optarg); 845 if (cfg_do_w <= 0) 846 cfg_do_w = 50; 847 break; 848 case 'l': 849 listen_mode = true; 850 break; 851 case 'p': 852 cfg_port = optarg; 853 break; 854 case 's': 855 cfg_sock_proto = parse_proto(optarg); 856 break; 857 case 'h': 858 die_usage(); 859 break; 860 case 'u': 861 tcpulp_audit = true; 862 break; 863 case '6': 864 pf = AF_INET6; 865 break; 866 case 't': 867 poll_timeout = atoi(optarg) * 1000; 868 if (poll_timeout <= 0) 869 poll_timeout = -1; 870 break; 871 case 'm': 872 cfg_mode = parse_mode(optarg); 873 break; 874 case 'S': 875 cfg_sndbuf = parse_int(optarg); 876 break; 877 case 'R': 878 cfg_rcvbuf = parse_int(optarg); 879 break; 880 case 'w': 881 cfg_wait = atoi(optarg)*1000000; 882 break; 883 } 884 } 885 886 if (optind + 1 != argc) 887 die_usage(); 888 cfg_host = argv[optind]; 889 890 if (strchr(cfg_host, ':')) 891 pf = AF_INET6; 892 } 893 894 int main(int argc, char *argv[]) 895 { 896 init_rng(); 897 898 signal(SIGUSR1, handle_signal); 899 parse_opts(argc, argv); 900 901 if (tcpulp_audit) 902 return sock_test_tcpulp(cfg_host, cfg_port) ? 0 : 1; 903 904 if (listen_mode) { 905 int fd = sock_listen_mptcp(cfg_host, cfg_port); 906 907 if (fd < 0) 908 return 1; 909 910 if (cfg_rcvbuf) 911 set_rcvbuf(fd, cfg_rcvbuf); 912 if (cfg_sndbuf) 913 set_sndbuf(fd, cfg_sndbuf); 914 915 return main_loop_s(fd); 916 } 917 918 return main_loop(); 919 } 920