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