1048d19d4SFlorian Westphal // SPDX-License-Identifier: GPL-2.0 2048d19d4SFlorian Westphal 3048d19d4SFlorian Westphal #define _GNU_SOURCE 4048d19d4SFlorian Westphal 5048d19d4SFlorian Westphal #include <errno.h> 6048d19d4SFlorian Westphal #include <limits.h> 7048d19d4SFlorian Westphal #include <fcntl.h> 8048d19d4SFlorian Westphal #include <string.h> 95e6af0a7SFlorian Westphal #include <stdarg.h> 10048d19d4SFlorian Westphal #include <stdbool.h> 11048d19d4SFlorian Westphal #include <stdint.h> 12048d19d4SFlorian Westphal #include <stdio.h> 13048d19d4SFlorian Westphal #include <stdlib.h> 14048d19d4SFlorian Westphal #include <strings.h> 15df62f2ecSPaolo Abeni #include <signal.h> 16048d19d4SFlorian Westphal #include <unistd.h> 17b6ab64b0SPaolo Abeni #include <time.h> 18048d19d4SFlorian Westphal 19048d19d4SFlorian Westphal #include <sys/poll.h> 20048d19d4SFlorian Westphal #include <sys/sendfile.h> 21048d19d4SFlorian Westphal #include <sys/stat.h> 22048d19d4SFlorian Westphal #include <sys/socket.h> 23048d19d4SFlorian Westphal #include <sys/types.h> 24048d19d4SFlorian Westphal #include <sys/mman.h> 25048d19d4SFlorian Westphal 26048d19d4SFlorian Westphal #include <netdb.h> 27048d19d4SFlorian Westphal #include <netinet/in.h> 28048d19d4SFlorian Westphal 29048d19d4SFlorian Westphal #include <linux/tcp.h> 305e6af0a7SFlorian Westphal #include <linux/time_types.h> 31048d19d4SFlorian Westphal 32048d19d4SFlorian Westphal extern int optind; 33048d19d4SFlorian Westphal 34048d19d4SFlorian Westphal #ifndef IPPROTO_MPTCP 35048d19d4SFlorian Westphal #define IPPROTO_MPTCP 262 36048d19d4SFlorian Westphal #endif 37048d19d4SFlorian Westphal #ifndef TCP_ULP 38048d19d4SFlorian Westphal #define TCP_ULP 31 39048d19d4SFlorian Westphal #endif 40048d19d4SFlorian Westphal 418a4b910dSFlorian Westphal static int poll_timeout = 10 * 1000; 42048d19d4SFlorian Westphal static bool listen_mode; 43df62f2ecSPaolo Abeni static bool quit; 44048d19d4SFlorian Westphal 45048d19d4SFlorian Westphal enum cfg_mode { 46048d19d4SFlorian Westphal CFG_MODE_POLL, 47048d19d4SFlorian Westphal CFG_MODE_MMAP, 48048d19d4SFlorian Westphal CFG_MODE_SENDFILE, 49048d19d4SFlorian Westphal }; 50048d19d4SFlorian Westphal 51df8aee6dSYonglong Li enum cfg_peek { 52df8aee6dSYonglong Li CFG_NONE_PEEK, 53df8aee6dSYonglong Li CFG_WITH_PEEK, 54df8aee6dSYonglong Li CFG_AFTER_PEEK, 55df8aee6dSYonglong Li }; 56df8aee6dSYonglong Li 57048d19d4SFlorian Westphal static enum cfg_mode cfg_mode = CFG_MODE_POLL; 58df8aee6dSYonglong Li static enum cfg_peek cfg_peek = CFG_NONE_PEEK; 59048d19d4SFlorian Westphal static const char *cfg_host; 60048d19d4SFlorian Westphal static const char *cfg_port = "12000"; 61048d19d4SFlorian Westphal static int cfg_sock_proto = IPPROTO_MPTCP; 62048d19d4SFlorian Westphal static int pf = AF_INET; 63048d19d4SFlorian Westphal static int cfg_sndbuf; 648a4b910dSFlorian Westphal static int cfg_rcvbuf; 65b08fbf24SPaolo Abeni static bool cfg_join; 6613153324SGeliang Tang static bool cfg_remove; 67b6ab64b0SPaolo Abeni static unsigned int cfg_time; 682e580a63SGeliang Tang static unsigned int cfg_do_w; 69df62f2ecSPaolo Abeni static int cfg_wait; 70dc65fe82SFlorian Westphal static uint32_t cfg_mark; 71048d19d4SFlorian Westphal 725e6af0a7SFlorian Westphal struct cfg_cmsg_types { 735e6af0a7SFlorian Westphal unsigned int cmsg_enabled:1; 745e6af0a7SFlorian Westphal unsigned int timestampns:1; 755cbd886cSFlorian Westphal unsigned int tcp_inq:1; 765e6af0a7SFlorian Westphal }; 775e6af0a7SFlorian Westphal 785fb62e9cSFlorian Westphal struct cfg_sockopt_types { 795fb62e9cSFlorian Westphal unsigned int transparent:1; 805fb62e9cSFlorian Westphal }; 815fb62e9cSFlorian Westphal 825cbd886cSFlorian Westphal struct tcp_inq_state { 835cbd886cSFlorian Westphal unsigned int last; 845cbd886cSFlorian Westphal bool expect_eof; 855cbd886cSFlorian Westphal }; 865cbd886cSFlorian Westphal 875cbd886cSFlorian Westphal static struct tcp_inq_state tcp_inq; 885cbd886cSFlorian Westphal 895e6af0a7SFlorian Westphal static struct cfg_cmsg_types cfg_cmsg_types; 905fb62e9cSFlorian Westphal static struct cfg_sockopt_types cfg_sockopt_types; 915e6af0a7SFlorian Westphal 92048d19d4SFlorian Westphal static void die_usage(void) 93048d19d4SFlorian Westphal { 948a4b910dSFlorian Westphal fprintf(stderr, "Usage: mptcp_connect [-6] [-u] [-s MPTCP|TCP] [-p port] [-m mode]" 95b6ab64b0SPaolo Abeni "[-l] [-w sec] [-t num] [-T num] connect_address\n"); 968a4b910dSFlorian Westphal fprintf(stderr, "\t-6 use ipv6\n"); 978a4b910dSFlorian Westphal fprintf(stderr, "\t-t num -- set poll timeout to num\n"); 98b6ab64b0SPaolo Abeni fprintf(stderr, "\t-T num -- set expected runtime to num ms\n"); 998a4b910dSFlorian Westphal fprintf(stderr, "\t-S num -- set SO_SNDBUF to num\n"); 1008a4b910dSFlorian Westphal fprintf(stderr, "\t-R num -- set SO_RCVBUF to num\n"); 1018a4b910dSFlorian Westphal fprintf(stderr, "\t-p num -- use port num\n"); 102c6f4c2b0SDavide Caratti fprintf(stderr, "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n"); 103c6f4c2b0SDavide Caratti fprintf(stderr, "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n"); 104dc65fe82SFlorian Westphal fprintf(stderr, "\t-M mark -- set socket packet mark\n"); 105df62f2ecSPaolo Abeni fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n"); 1065e6af0a7SFlorian Westphal fprintf(stderr, "\t-c cmsg -- test cmsg type <cmsg>\n"); 1075fb62e9cSFlorian Westphal fprintf(stderr, "\t-o option -- test sockopt <option>\n"); 108df8aee6dSYonglong Li fprintf(stderr, 109df8aee6dSYonglong Li "\t-P [saveWithPeek|saveAfterPeek] -- save data with/after MSG_PEEK form tcp socket\n"); 110048d19d4SFlorian Westphal exit(1); 111048d19d4SFlorian Westphal } 112048d19d4SFlorian Westphal 1135e6af0a7SFlorian Westphal static void xerror(const char *fmt, ...) 1145e6af0a7SFlorian Westphal { 1155e6af0a7SFlorian Westphal va_list ap; 1165e6af0a7SFlorian Westphal 1175e6af0a7SFlorian Westphal va_start(ap, fmt); 1185e6af0a7SFlorian Westphal vfprintf(stderr, fmt, ap); 1195e6af0a7SFlorian Westphal va_end(ap); 1205e6af0a7SFlorian Westphal exit(1); 1215e6af0a7SFlorian Westphal } 1225e6af0a7SFlorian Westphal 123df62f2ecSPaolo Abeni static void handle_signal(int nr) 124df62f2ecSPaolo Abeni { 125df62f2ecSPaolo Abeni quit = true; 126df62f2ecSPaolo Abeni } 127df62f2ecSPaolo Abeni 128048d19d4SFlorian Westphal static const char *getxinfo_strerr(int err) 129048d19d4SFlorian Westphal { 130048d19d4SFlorian Westphal if (err == EAI_SYSTEM) 131048d19d4SFlorian Westphal return strerror(errno); 132048d19d4SFlorian Westphal 133048d19d4SFlorian Westphal return gai_strerror(err); 134048d19d4SFlorian Westphal } 135048d19d4SFlorian Westphal 136048d19d4SFlorian Westphal static void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen, 137048d19d4SFlorian Westphal char *host, socklen_t hostlen, 138048d19d4SFlorian Westphal char *serv, socklen_t servlen) 139048d19d4SFlorian Westphal { 140048d19d4SFlorian Westphal int flags = NI_NUMERICHOST | NI_NUMERICSERV; 141048d19d4SFlorian Westphal int err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, 142048d19d4SFlorian Westphal flags); 143048d19d4SFlorian Westphal 144048d19d4SFlorian Westphal if (err) { 145048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 146048d19d4SFlorian Westphal 147048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getnameinfo: %s\n", errstr); 148048d19d4SFlorian Westphal exit(1); 149048d19d4SFlorian Westphal } 150048d19d4SFlorian Westphal } 151048d19d4SFlorian Westphal 152048d19d4SFlorian Westphal static void xgetaddrinfo(const char *node, const char *service, 153048d19d4SFlorian Westphal const struct addrinfo *hints, 154048d19d4SFlorian Westphal struct addrinfo **res) 155048d19d4SFlorian Westphal { 156048d19d4SFlorian Westphal int err = getaddrinfo(node, service, hints, res); 157048d19d4SFlorian Westphal 158048d19d4SFlorian Westphal if (err) { 159048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 160048d19d4SFlorian Westphal 161048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", 162048d19d4SFlorian Westphal node ? node : "", service ? service : "", errstr); 163048d19d4SFlorian Westphal exit(1); 164048d19d4SFlorian Westphal } 165048d19d4SFlorian Westphal } 166048d19d4SFlorian Westphal 1678a4b910dSFlorian Westphal static void set_rcvbuf(int fd, unsigned int size) 1688a4b910dSFlorian Westphal { 1698a4b910dSFlorian Westphal int err; 1708a4b910dSFlorian Westphal 1718a4b910dSFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 1728a4b910dSFlorian Westphal if (err) { 1738a4b910dSFlorian Westphal perror("set SO_RCVBUF"); 1748a4b910dSFlorian Westphal exit(1); 1758a4b910dSFlorian Westphal } 1768a4b910dSFlorian Westphal } 1778a4b910dSFlorian Westphal 178048d19d4SFlorian Westphal static void set_sndbuf(int fd, unsigned int size) 179048d19d4SFlorian Westphal { 180048d19d4SFlorian Westphal int err; 181048d19d4SFlorian Westphal 182048d19d4SFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); 183048d19d4SFlorian Westphal if (err) { 184048d19d4SFlorian Westphal perror("set SO_SNDBUF"); 185048d19d4SFlorian Westphal exit(1); 186048d19d4SFlorian Westphal } 187048d19d4SFlorian Westphal } 188048d19d4SFlorian Westphal 189dc65fe82SFlorian Westphal static void set_mark(int fd, uint32_t mark) 190dc65fe82SFlorian Westphal { 191dc65fe82SFlorian Westphal int err; 192dc65fe82SFlorian Westphal 193dc65fe82SFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); 194dc65fe82SFlorian Westphal if (err) { 195dc65fe82SFlorian Westphal perror("set SO_MARK"); 196dc65fe82SFlorian Westphal exit(1); 197dc65fe82SFlorian Westphal } 198dc65fe82SFlorian Westphal } 199dc65fe82SFlorian Westphal 2005fb62e9cSFlorian Westphal static void set_transparent(int fd, int pf) 2015fb62e9cSFlorian Westphal { 2025fb62e9cSFlorian Westphal int one = 1; 2035fb62e9cSFlorian Westphal 2045fb62e9cSFlorian Westphal switch (pf) { 2055fb62e9cSFlorian Westphal case AF_INET: 2065fb62e9cSFlorian Westphal if (-1 == setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one))) 2075fb62e9cSFlorian Westphal perror("IP_TRANSPARENT"); 2085fb62e9cSFlorian Westphal break; 2095fb62e9cSFlorian Westphal case AF_INET6: 2105fb62e9cSFlorian Westphal if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, &one, sizeof(one))) 2115fb62e9cSFlorian Westphal perror("IPV6_TRANSPARENT"); 2125fb62e9cSFlorian Westphal break; 2135fb62e9cSFlorian Westphal } 2145fb62e9cSFlorian Westphal } 2155fb62e9cSFlorian Westphal 216*f730b65cSFlorian Westphal static int do_ulp_so(int sock, const char *name) 217*f730b65cSFlorian Westphal { 218*f730b65cSFlorian Westphal return setsockopt(sock, IPPROTO_TCP, TCP_ULP, name, strlen(name)); 219*f730b65cSFlorian Westphal } 220*f730b65cSFlorian Westphal 221*f730b65cSFlorian Westphal #define X(m) xerror("%s:%u: %s: failed for proto %d at line %u", __FILE__, __LINE__, (m), proto, line) 222*f730b65cSFlorian Westphal static void sock_test_tcpulp(int sock, int proto, unsigned int line) 223*f730b65cSFlorian Westphal { 224*f730b65cSFlorian Westphal socklen_t buflen = 8; 225*f730b65cSFlorian Westphal char buf[8] = ""; 226*f730b65cSFlorian Westphal int ret = getsockopt(sock, IPPROTO_TCP, TCP_ULP, buf, &buflen); 227*f730b65cSFlorian Westphal 228*f730b65cSFlorian Westphal if (ret != 0) 229*f730b65cSFlorian Westphal X("getsockopt"); 230*f730b65cSFlorian Westphal 231*f730b65cSFlorian Westphal if (buflen > 0) { 232*f730b65cSFlorian Westphal if (strcmp(buf, "mptcp") != 0) 233*f730b65cSFlorian Westphal xerror("unexpected ULP '%s' for proto %d at line %u", buf, proto, line); 234*f730b65cSFlorian Westphal ret = do_ulp_so(sock, "tls"); 235*f730b65cSFlorian Westphal if (ret == 0) 236*f730b65cSFlorian Westphal X("setsockopt"); 237*f730b65cSFlorian Westphal } else if (proto == IPPROTO_MPTCP) { 238*f730b65cSFlorian Westphal ret = do_ulp_so(sock, "tls"); 239*f730b65cSFlorian Westphal if (ret != -1) 240*f730b65cSFlorian Westphal X("setsockopt"); 241*f730b65cSFlorian Westphal } 242*f730b65cSFlorian Westphal 243*f730b65cSFlorian Westphal ret = do_ulp_so(sock, "mptcp"); 244*f730b65cSFlorian Westphal if (ret != -1) 245*f730b65cSFlorian Westphal X("setsockopt"); 246*f730b65cSFlorian Westphal 247*f730b65cSFlorian Westphal #undef X 248*f730b65cSFlorian Westphal } 249*f730b65cSFlorian Westphal 250*f730b65cSFlorian Westphal #define SOCK_TEST_TCPULP(s, p) sock_test_tcpulp((s), (p), __LINE__) 251*f730b65cSFlorian Westphal 252048d19d4SFlorian Westphal static int sock_listen_mptcp(const char * const listenaddr, 253048d19d4SFlorian Westphal const char * const port) 254048d19d4SFlorian Westphal { 255048d19d4SFlorian Westphal int sock; 256048d19d4SFlorian Westphal struct addrinfo hints = { 257048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 258048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 259048d19d4SFlorian Westphal .ai_flags = AI_PASSIVE | AI_NUMERICHOST 260048d19d4SFlorian Westphal }; 261048d19d4SFlorian Westphal 262048d19d4SFlorian Westphal hints.ai_family = pf; 263048d19d4SFlorian Westphal 264048d19d4SFlorian Westphal struct addrinfo *a, *addr; 265048d19d4SFlorian Westphal int one = 1; 266048d19d4SFlorian Westphal 267048d19d4SFlorian Westphal xgetaddrinfo(listenaddr, port, &hints, &addr); 268048d19d4SFlorian Westphal hints.ai_family = pf; 269048d19d4SFlorian Westphal 270048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 271048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, cfg_sock_proto); 272048d19d4SFlorian Westphal if (sock < 0) 273048d19d4SFlorian Westphal continue; 274048d19d4SFlorian Westphal 275*f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 276*f730b65cSFlorian Westphal 277048d19d4SFlorian Westphal if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, 278048d19d4SFlorian Westphal sizeof(one))) 279048d19d4SFlorian Westphal perror("setsockopt"); 280048d19d4SFlorian Westphal 2815fb62e9cSFlorian Westphal if (cfg_sockopt_types.transparent) 2825fb62e9cSFlorian Westphal set_transparent(sock, pf); 2835fb62e9cSFlorian Westphal 284048d19d4SFlorian Westphal if (bind(sock, a->ai_addr, a->ai_addrlen) == 0) 285048d19d4SFlorian Westphal break; /* success */ 286048d19d4SFlorian Westphal 287048d19d4SFlorian Westphal perror("bind"); 288048d19d4SFlorian Westphal close(sock); 289048d19d4SFlorian Westphal sock = -1; 290048d19d4SFlorian Westphal } 291048d19d4SFlorian Westphal 292048d19d4SFlorian Westphal freeaddrinfo(addr); 293048d19d4SFlorian Westphal 294048d19d4SFlorian Westphal if (sock < 0) { 295048d19d4SFlorian Westphal fprintf(stderr, "Could not create listen socket\n"); 296048d19d4SFlorian Westphal return sock; 297048d19d4SFlorian Westphal } 298048d19d4SFlorian Westphal 299*f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 300*f730b65cSFlorian Westphal 301048d19d4SFlorian Westphal if (listen(sock, 20)) { 302048d19d4SFlorian Westphal perror("listen"); 303048d19d4SFlorian Westphal close(sock); 304048d19d4SFlorian Westphal return -1; 305048d19d4SFlorian Westphal } 306048d19d4SFlorian Westphal 307*f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 308*f730b65cSFlorian Westphal 309048d19d4SFlorian Westphal return sock; 310048d19d4SFlorian Westphal } 311048d19d4SFlorian Westphal 312048d19d4SFlorian Westphal static int sock_connect_mptcp(const char * const remoteaddr, 313048d19d4SFlorian Westphal const char * const port, int proto) 314048d19d4SFlorian Westphal { 315048d19d4SFlorian Westphal struct addrinfo hints = { 316048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 317048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 318048d19d4SFlorian Westphal }; 319048d19d4SFlorian Westphal struct addrinfo *a, *addr; 320048d19d4SFlorian Westphal int sock = -1; 321048d19d4SFlorian Westphal 322048d19d4SFlorian Westphal hints.ai_family = pf; 323048d19d4SFlorian Westphal 324048d19d4SFlorian Westphal xgetaddrinfo(remoteaddr, port, &hints, &addr); 325048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 326048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, proto); 327048d19d4SFlorian Westphal if (sock < 0) { 328048d19d4SFlorian Westphal perror("socket"); 329048d19d4SFlorian Westphal continue; 330048d19d4SFlorian Westphal } 331048d19d4SFlorian Westphal 332*f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, proto); 333*f730b65cSFlorian Westphal 334dc65fe82SFlorian Westphal if (cfg_mark) 335dc65fe82SFlorian Westphal set_mark(sock, cfg_mark); 336dc65fe82SFlorian Westphal 337048d19d4SFlorian Westphal if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) 338048d19d4SFlorian Westphal break; /* success */ 339048d19d4SFlorian Westphal 340048d19d4SFlorian Westphal perror("connect()"); 341048d19d4SFlorian Westphal close(sock); 342048d19d4SFlorian Westphal sock = -1; 343048d19d4SFlorian Westphal } 344048d19d4SFlorian Westphal 345048d19d4SFlorian Westphal freeaddrinfo(addr); 346*f730b65cSFlorian Westphal if (sock != -1) 347*f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, proto); 348048d19d4SFlorian Westphal return sock; 349048d19d4SFlorian Westphal } 350048d19d4SFlorian Westphal 351048d19d4SFlorian Westphal static size_t do_rnd_write(const int fd, char *buf, const size_t len) 352048d19d4SFlorian Westphal { 353b08fbf24SPaolo Abeni static bool first = true; 354048d19d4SFlorian Westphal unsigned int do_w; 355048d19d4SFlorian Westphal ssize_t bw; 356048d19d4SFlorian Westphal 357048d19d4SFlorian Westphal do_w = rand() & 0xffff; 358048d19d4SFlorian Westphal if (do_w == 0 || do_w > len) 359048d19d4SFlorian Westphal do_w = len; 360048d19d4SFlorian Westphal 361b08fbf24SPaolo Abeni if (cfg_join && first && do_w > 100) 362b08fbf24SPaolo Abeni do_w = 100; 363b08fbf24SPaolo Abeni 3642e580a63SGeliang Tang if (cfg_remove && do_w > cfg_do_w) 3652e580a63SGeliang Tang do_w = cfg_do_w; 36613153324SGeliang Tang 367048d19d4SFlorian Westphal bw = write(fd, buf, do_w); 368048d19d4SFlorian Westphal if (bw < 0) 369048d19d4SFlorian Westphal perror("write"); 370048d19d4SFlorian Westphal 371b08fbf24SPaolo Abeni /* let the join handshake complete, before going on */ 372b08fbf24SPaolo Abeni if (cfg_join && first) { 373b08fbf24SPaolo Abeni usleep(200000); 374b08fbf24SPaolo Abeni first = false; 375b08fbf24SPaolo Abeni } 376b08fbf24SPaolo Abeni 37713153324SGeliang Tang if (cfg_remove) 37813153324SGeliang Tang usleep(200000); 37913153324SGeliang Tang 380048d19d4SFlorian Westphal return bw; 381048d19d4SFlorian Westphal } 382048d19d4SFlorian Westphal 383048d19d4SFlorian Westphal static size_t do_write(const int fd, char *buf, const size_t len) 384048d19d4SFlorian Westphal { 385048d19d4SFlorian Westphal size_t offset = 0; 386048d19d4SFlorian Westphal 387048d19d4SFlorian Westphal while (offset < len) { 388048d19d4SFlorian Westphal size_t written; 389048d19d4SFlorian Westphal ssize_t bw; 390048d19d4SFlorian Westphal 391048d19d4SFlorian Westphal bw = write(fd, buf + offset, len - offset); 392048d19d4SFlorian Westphal if (bw < 0) { 393048d19d4SFlorian Westphal perror("write"); 394048d19d4SFlorian Westphal return 0; 395048d19d4SFlorian Westphal } 396048d19d4SFlorian Westphal 397048d19d4SFlorian Westphal written = (size_t)bw; 398048d19d4SFlorian Westphal offset += written; 399048d19d4SFlorian Westphal } 400048d19d4SFlorian Westphal 401048d19d4SFlorian Westphal return offset; 402048d19d4SFlorian Westphal } 403048d19d4SFlorian Westphal 4045e6af0a7SFlorian Westphal static void process_cmsg(struct msghdr *msgh) 4055e6af0a7SFlorian Westphal { 4065e6af0a7SFlorian Westphal struct __kernel_timespec ts; 4075cbd886cSFlorian Westphal bool inq_found = false; 4085e6af0a7SFlorian Westphal bool ts_found = false; 4095cbd886cSFlorian Westphal unsigned int inq = 0; 4105e6af0a7SFlorian Westphal struct cmsghdr *cmsg; 4115e6af0a7SFlorian Westphal 4125e6af0a7SFlorian Westphal for (cmsg = CMSG_FIRSTHDR(msgh); cmsg ; cmsg = CMSG_NXTHDR(msgh, cmsg)) { 4135e6af0a7SFlorian Westphal if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPNS_NEW) { 4145e6af0a7SFlorian Westphal memcpy(&ts, CMSG_DATA(cmsg), sizeof(ts)); 4155e6af0a7SFlorian Westphal ts_found = true; 4165e6af0a7SFlorian Westphal continue; 4175e6af0a7SFlorian Westphal } 4185cbd886cSFlorian Westphal if (cmsg->cmsg_level == IPPROTO_TCP && cmsg->cmsg_type == TCP_CM_INQ) { 4195cbd886cSFlorian Westphal memcpy(&inq, CMSG_DATA(cmsg), sizeof(inq)); 4205cbd886cSFlorian Westphal inq_found = true; 4215cbd886cSFlorian Westphal continue; 4225cbd886cSFlorian Westphal } 4235cbd886cSFlorian Westphal 4245e6af0a7SFlorian Westphal } 4255e6af0a7SFlorian Westphal 4265e6af0a7SFlorian Westphal if (cfg_cmsg_types.timestampns) { 4275e6af0a7SFlorian Westphal if (!ts_found) 4285e6af0a7SFlorian Westphal xerror("TIMESTAMPNS not present\n"); 4295e6af0a7SFlorian Westphal } 4305cbd886cSFlorian Westphal 4315cbd886cSFlorian Westphal if (cfg_cmsg_types.tcp_inq) { 4325cbd886cSFlorian Westphal if (!inq_found) 4335cbd886cSFlorian Westphal xerror("TCP_INQ not present\n"); 4345cbd886cSFlorian Westphal 4355cbd886cSFlorian Westphal if (inq > 1024) 4365cbd886cSFlorian Westphal xerror("tcp_inq %u is larger than one kbyte\n", inq); 4375cbd886cSFlorian Westphal tcp_inq.last = inq; 4385cbd886cSFlorian Westphal } 4395e6af0a7SFlorian Westphal } 4405e6af0a7SFlorian Westphal 4415e6af0a7SFlorian Westphal static ssize_t do_recvmsg_cmsg(const int fd, char *buf, const size_t len) 4425e6af0a7SFlorian Westphal { 4435e6af0a7SFlorian Westphal char msg_buf[8192]; 4445e6af0a7SFlorian Westphal struct iovec iov = { 4455e6af0a7SFlorian Westphal .iov_base = buf, 4465e6af0a7SFlorian Westphal .iov_len = len, 4475e6af0a7SFlorian Westphal }; 4485e6af0a7SFlorian Westphal struct msghdr msg = { 4495e6af0a7SFlorian Westphal .msg_iov = &iov, 4505e6af0a7SFlorian Westphal .msg_iovlen = 1, 4515e6af0a7SFlorian Westphal .msg_control = msg_buf, 4525e6af0a7SFlorian Westphal .msg_controllen = sizeof(msg_buf), 4535e6af0a7SFlorian Westphal }; 4545e6af0a7SFlorian Westphal int flags = 0; 4555cbd886cSFlorian Westphal unsigned int last_hint = tcp_inq.last; 4565e6af0a7SFlorian Westphal int ret = recvmsg(fd, &msg, flags); 4575e6af0a7SFlorian Westphal 4585cbd886cSFlorian Westphal if (ret <= 0) { 4595cbd886cSFlorian Westphal if (ret == 0 && tcp_inq.expect_eof) 4605e6af0a7SFlorian Westphal return ret; 4615e6af0a7SFlorian Westphal 4625cbd886cSFlorian Westphal if (ret == 0 && cfg_cmsg_types.tcp_inq) 4635cbd886cSFlorian Westphal if (last_hint != 1 && last_hint != 0) 4645cbd886cSFlorian Westphal xerror("EOF but last tcp_inq hint was %u\n", last_hint); 4655cbd886cSFlorian Westphal 4665cbd886cSFlorian Westphal return ret; 4675cbd886cSFlorian Westphal } 4685cbd886cSFlorian Westphal 4695cbd886cSFlorian Westphal if (tcp_inq.expect_eof) 4705cbd886cSFlorian Westphal xerror("expected EOF, last_hint %u, now %u\n", 4715cbd886cSFlorian Westphal last_hint, tcp_inq.last); 4725cbd886cSFlorian Westphal 4735e6af0a7SFlorian Westphal if (msg.msg_controllen && !cfg_cmsg_types.cmsg_enabled) 4745e6af0a7SFlorian Westphal xerror("got %lu bytes of cmsg data, expected 0\n", 4755e6af0a7SFlorian Westphal (unsigned long)msg.msg_controllen); 4765e6af0a7SFlorian Westphal 4775e6af0a7SFlorian Westphal if (msg.msg_controllen == 0 && cfg_cmsg_types.cmsg_enabled) 4785e6af0a7SFlorian Westphal xerror("%s\n", "got no cmsg data"); 4795e6af0a7SFlorian Westphal 4805e6af0a7SFlorian Westphal if (msg.msg_controllen) 4815e6af0a7SFlorian Westphal process_cmsg(&msg); 4825e6af0a7SFlorian Westphal 4835cbd886cSFlorian Westphal if (cfg_cmsg_types.tcp_inq) { 4845cbd886cSFlorian Westphal if ((size_t)ret < len && last_hint > (unsigned int)ret) { 4855cbd886cSFlorian Westphal if (ret + 1 != (int)last_hint) { 4865cbd886cSFlorian Westphal int next = read(fd, msg_buf, sizeof(msg_buf)); 4875cbd886cSFlorian Westphal 4885cbd886cSFlorian Westphal xerror("read %u of %u, last_hint was %u tcp_inq hint now %u next_read returned %d/%m\n", 4895cbd886cSFlorian Westphal ret, (unsigned int)len, last_hint, tcp_inq.last, next); 4905cbd886cSFlorian Westphal } else { 4915cbd886cSFlorian Westphal tcp_inq.expect_eof = true; 4925cbd886cSFlorian Westphal } 4935cbd886cSFlorian Westphal } 4945cbd886cSFlorian Westphal } 4955cbd886cSFlorian Westphal 4965e6af0a7SFlorian Westphal return ret; 4975e6af0a7SFlorian Westphal } 4985e6af0a7SFlorian Westphal 499048d19d4SFlorian Westphal static ssize_t do_rnd_read(const int fd, char *buf, const size_t len) 500048d19d4SFlorian Westphal { 501df8aee6dSYonglong Li int ret = 0; 502df8aee6dSYonglong Li char tmp[16384]; 503048d19d4SFlorian Westphal size_t cap = rand(); 504048d19d4SFlorian Westphal 505048d19d4SFlorian Westphal cap &= 0xffff; 506048d19d4SFlorian Westphal 507048d19d4SFlorian Westphal if (cap == 0) 508048d19d4SFlorian Westphal cap = 1; 509048d19d4SFlorian Westphal else if (cap > len) 510048d19d4SFlorian Westphal cap = len; 511048d19d4SFlorian Westphal 512df8aee6dSYonglong Li if (cfg_peek == CFG_WITH_PEEK) { 513df8aee6dSYonglong Li ret = recv(fd, buf, cap, MSG_PEEK); 514df8aee6dSYonglong Li ret = (ret < 0) ? ret : read(fd, tmp, ret); 515df8aee6dSYonglong Li } else if (cfg_peek == CFG_AFTER_PEEK) { 516df8aee6dSYonglong Li ret = recv(fd, buf, cap, MSG_PEEK); 517df8aee6dSYonglong Li ret = (ret < 0) ? ret : read(fd, buf, cap); 5185e6af0a7SFlorian Westphal } else if (cfg_cmsg_types.cmsg_enabled) { 5195e6af0a7SFlorian Westphal ret = do_recvmsg_cmsg(fd, buf, cap); 520df8aee6dSYonglong Li } else { 521df8aee6dSYonglong Li ret = read(fd, buf, cap); 522df8aee6dSYonglong Li } 523df8aee6dSYonglong Li 524df8aee6dSYonglong Li return ret; 525048d19d4SFlorian Westphal } 526048d19d4SFlorian Westphal 527048d19d4SFlorian Westphal static void set_nonblock(int fd) 528048d19d4SFlorian Westphal { 529048d19d4SFlorian Westphal int flags = fcntl(fd, F_GETFL); 530048d19d4SFlorian Westphal 531048d19d4SFlorian Westphal if (flags == -1) 532048d19d4SFlorian Westphal return; 533048d19d4SFlorian Westphal 534048d19d4SFlorian Westphal fcntl(fd, F_SETFL, flags | O_NONBLOCK); 535048d19d4SFlorian Westphal } 536048d19d4SFlorian Westphal 537b6ab64b0SPaolo Abeni static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after_out) 538048d19d4SFlorian Westphal { 539048d19d4SFlorian Westphal struct pollfd fds = { 540048d19d4SFlorian Westphal .fd = peerfd, 541048d19d4SFlorian Westphal .events = POLLIN | POLLOUT, 542048d19d4SFlorian Westphal }; 543048d19d4SFlorian Westphal unsigned int woff = 0, wlen = 0; 544048d19d4SFlorian Westphal char wbuf[8192]; 545048d19d4SFlorian Westphal 546048d19d4SFlorian Westphal set_nonblock(peerfd); 547048d19d4SFlorian Westphal 548048d19d4SFlorian Westphal for (;;) { 549048d19d4SFlorian Westphal char rbuf[8192]; 550048d19d4SFlorian Westphal ssize_t len; 551048d19d4SFlorian Westphal 552048d19d4SFlorian Westphal if (fds.events == 0) 553048d19d4SFlorian Westphal break; 554048d19d4SFlorian Westphal 555048d19d4SFlorian Westphal switch (poll(&fds, 1, poll_timeout)) { 556048d19d4SFlorian Westphal case -1: 557048d19d4SFlorian Westphal if (errno == EINTR) 558048d19d4SFlorian Westphal continue; 559048d19d4SFlorian Westphal perror("poll"); 560048d19d4SFlorian Westphal return 1; 561048d19d4SFlorian Westphal case 0: 562048d19d4SFlorian Westphal fprintf(stderr, "%s: poll timed out (events: " 563048d19d4SFlorian Westphal "POLLIN %u, POLLOUT %u)\n", __func__, 564048d19d4SFlorian Westphal fds.events & POLLIN, fds.events & POLLOUT); 565048d19d4SFlorian Westphal return 2; 566048d19d4SFlorian Westphal } 567048d19d4SFlorian Westphal 568048d19d4SFlorian Westphal if (fds.revents & POLLIN) { 569048d19d4SFlorian Westphal len = do_rnd_read(peerfd, rbuf, sizeof(rbuf)); 570048d19d4SFlorian Westphal if (len == 0) { 571048d19d4SFlorian Westphal /* no more data to receive: 572048d19d4SFlorian Westphal * peer has closed its write side 573048d19d4SFlorian Westphal */ 574048d19d4SFlorian Westphal fds.events &= ~POLLIN; 575048d19d4SFlorian Westphal 576b6ab64b0SPaolo Abeni if ((fds.events & POLLOUT) == 0) { 577b6ab64b0SPaolo Abeni *in_closed_after_out = true; 578048d19d4SFlorian Westphal /* and nothing more to send */ 579048d19d4SFlorian Westphal break; 580b6ab64b0SPaolo Abeni } 581048d19d4SFlorian Westphal 582048d19d4SFlorian Westphal /* Else, still have data to transmit */ 583048d19d4SFlorian Westphal } else if (len < 0) { 584048d19d4SFlorian Westphal perror("read"); 585048d19d4SFlorian Westphal return 3; 586048d19d4SFlorian Westphal } 587048d19d4SFlorian Westphal 588048d19d4SFlorian Westphal do_write(outfd, rbuf, len); 589048d19d4SFlorian Westphal } 590048d19d4SFlorian Westphal 591048d19d4SFlorian Westphal if (fds.revents & POLLOUT) { 592048d19d4SFlorian Westphal if (wlen == 0) { 593048d19d4SFlorian Westphal woff = 0; 594048d19d4SFlorian Westphal wlen = read(infd, wbuf, sizeof(wbuf)); 595048d19d4SFlorian Westphal } 596048d19d4SFlorian Westphal 597048d19d4SFlorian Westphal if (wlen > 0) { 598048d19d4SFlorian Westphal ssize_t bw; 599048d19d4SFlorian Westphal 600048d19d4SFlorian Westphal bw = do_rnd_write(peerfd, wbuf + woff, wlen); 601048d19d4SFlorian Westphal if (bw < 0) 602048d19d4SFlorian Westphal return 111; 603048d19d4SFlorian Westphal 604048d19d4SFlorian Westphal woff += bw; 605048d19d4SFlorian Westphal wlen -= bw; 606048d19d4SFlorian Westphal } else if (wlen == 0) { 607048d19d4SFlorian Westphal /* We have no more data to send. */ 608048d19d4SFlorian Westphal fds.events &= ~POLLOUT; 609048d19d4SFlorian Westphal 610048d19d4SFlorian Westphal if ((fds.events & POLLIN) == 0) 611048d19d4SFlorian Westphal /* ... and peer also closed already */ 612048d19d4SFlorian Westphal break; 613048d19d4SFlorian Westphal 614048d19d4SFlorian Westphal /* ... but we still receive. 615b08fbf24SPaolo Abeni * Close our write side, ev. give some time 6166bdb6211SPaolo Abeni * for address notification and/or checking 6176bdb6211SPaolo Abeni * the current status 618048d19d4SFlorian Westphal */ 6196bdb6211SPaolo Abeni if (cfg_wait) 6206bdb6211SPaolo Abeni usleep(cfg_wait); 621048d19d4SFlorian Westphal shutdown(peerfd, SHUT_WR); 622048d19d4SFlorian Westphal } else { 623048d19d4SFlorian Westphal if (errno == EINTR) 624048d19d4SFlorian Westphal continue; 625048d19d4SFlorian Westphal perror("read"); 626048d19d4SFlorian Westphal return 4; 627048d19d4SFlorian Westphal } 628048d19d4SFlorian Westphal } 629048d19d4SFlorian Westphal 630048d19d4SFlorian Westphal if (fds.revents & (POLLERR | POLLNVAL)) { 631048d19d4SFlorian Westphal fprintf(stderr, "Unexpected revents: " 632048d19d4SFlorian Westphal "POLLERR/POLLNVAL(%x)\n", fds.revents); 633048d19d4SFlorian Westphal return 5; 634048d19d4SFlorian Westphal } 635048d19d4SFlorian Westphal } 636048d19d4SFlorian Westphal 637b08fbf24SPaolo Abeni /* leave some time for late join/announce */ 638b6ab64b0SPaolo Abeni if (cfg_remove) 639df62f2ecSPaolo Abeni usleep(cfg_wait); 640b08fbf24SPaolo Abeni 641048d19d4SFlorian Westphal close(peerfd); 642048d19d4SFlorian Westphal return 0; 643048d19d4SFlorian Westphal } 644048d19d4SFlorian Westphal 645048d19d4SFlorian Westphal static int do_recvfile(int infd, int outfd) 646048d19d4SFlorian Westphal { 647048d19d4SFlorian Westphal ssize_t r; 648048d19d4SFlorian Westphal 649048d19d4SFlorian Westphal do { 650048d19d4SFlorian Westphal char buf[16384]; 651048d19d4SFlorian Westphal 652048d19d4SFlorian Westphal r = do_rnd_read(infd, buf, sizeof(buf)); 653048d19d4SFlorian Westphal if (r > 0) { 654048d19d4SFlorian Westphal if (write(outfd, buf, r) != r) 655048d19d4SFlorian Westphal break; 656048d19d4SFlorian Westphal } else if (r < 0) { 657048d19d4SFlorian Westphal perror("read"); 658048d19d4SFlorian Westphal } 659048d19d4SFlorian Westphal } while (r > 0); 660048d19d4SFlorian Westphal 661048d19d4SFlorian Westphal return (int)r; 662048d19d4SFlorian Westphal } 663048d19d4SFlorian Westphal 664048d19d4SFlorian Westphal static int do_mmap(int infd, int outfd, unsigned int size) 665048d19d4SFlorian Westphal { 666048d19d4SFlorian Westphal char *inbuf = mmap(NULL, size, PROT_READ, MAP_SHARED, infd, 0); 667048d19d4SFlorian Westphal ssize_t ret = 0, off = 0; 668048d19d4SFlorian Westphal size_t rem; 669048d19d4SFlorian Westphal 670048d19d4SFlorian Westphal if (inbuf == MAP_FAILED) { 671048d19d4SFlorian Westphal perror("mmap"); 672048d19d4SFlorian Westphal return 1; 673048d19d4SFlorian Westphal } 674048d19d4SFlorian Westphal 675048d19d4SFlorian Westphal rem = size; 676048d19d4SFlorian Westphal 677048d19d4SFlorian Westphal while (rem > 0) { 678048d19d4SFlorian Westphal ret = write(outfd, inbuf + off, rem); 679048d19d4SFlorian Westphal 680048d19d4SFlorian Westphal if (ret < 0) { 681048d19d4SFlorian Westphal perror("write"); 682048d19d4SFlorian Westphal break; 683048d19d4SFlorian Westphal } 684048d19d4SFlorian Westphal 685048d19d4SFlorian Westphal off += ret; 686048d19d4SFlorian Westphal rem -= ret; 687048d19d4SFlorian Westphal } 688048d19d4SFlorian Westphal 689048d19d4SFlorian Westphal munmap(inbuf, size); 690048d19d4SFlorian Westphal return rem; 691048d19d4SFlorian Westphal } 692048d19d4SFlorian Westphal 693048d19d4SFlorian Westphal static int get_infd_size(int fd) 694048d19d4SFlorian Westphal { 695048d19d4SFlorian Westphal struct stat sb; 696048d19d4SFlorian Westphal ssize_t count; 697048d19d4SFlorian Westphal int err; 698048d19d4SFlorian Westphal 699048d19d4SFlorian Westphal err = fstat(fd, &sb); 700048d19d4SFlorian Westphal if (err < 0) { 701048d19d4SFlorian Westphal perror("fstat"); 702048d19d4SFlorian Westphal return -1; 703048d19d4SFlorian Westphal } 704048d19d4SFlorian Westphal 705048d19d4SFlorian Westphal if ((sb.st_mode & S_IFMT) != S_IFREG) { 706048d19d4SFlorian Westphal fprintf(stderr, "%s: stdin is not a regular file\n", __func__); 707048d19d4SFlorian Westphal return -2; 708048d19d4SFlorian Westphal } 709048d19d4SFlorian Westphal 710048d19d4SFlorian Westphal count = sb.st_size; 711048d19d4SFlorian Westphal if (count > INT_MAX) { 712048d19d4SFlorian Westphal fprintf(stderr, "File too large: %zu\n", count); 713048d19d4SFlorian Westphal return -3; 714048d19d4SFlorian Westphal } 715048d19d4SFlorian Westphal 716048d19d4SFlorian Westphal return (int)count; 717048d19d4SFlorian Westphal } 718048d19d4SFlorian Westphal 719048d19d4SFlorian Westphal static int do_sendfile(int infd, int outfd, unsigned int count) 720048d19d4SFlorian Westphal { 721048d19d4SFlorian Westphal while (count > 0) { 722048d19d4SFlorian Westphal ssize_t r; 723048d19d4SFlorian Westphal 724048d19d4SFlorian Westphal r = sendfile(outfd, infd, NULL, count); 725048d19d4SFlorian Westphal if (r < 0) { 726048d19d4SFlorian Westphal perror("sendfile"); 727048d19d4SFlorian Westphal return 3; 728048d19d4SFlorian Westphal } 729048d19d4SFlorian Westphal 730048d19d4SFlorian Westphal count -= r; 731048d19d4SFlorian Westphal } 732048d19d4SFlorian Westphal 733048d19d4SFlorian Westphal return 0; 734048d19d4SFlorian Westphal } 735048d19d4SFlorian Westphal 736048d19d4SFlorian Westphal static int copyfd_io_mmap(int infd, int peerfd, int outfd, 737b6ab64b0SPaolo Abeni unsigned int size, bool *in_closed_after_out) 738048d19d4SFlorian Westphal { 739048d19d4SFlorian Westphal int err; 740048d19d4SFlorian Westphal 741048d19d4SFlorian Westphal if (listen_mode) { 742048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 743048d19d4SFlorian Westphal if (err) 744048d19d4SFlorian Westphal return err; 745048d19d4SFlorian Westphal 746048d19d4SFlorian Westphal err = do_mmap(infd, peerfd, size); 747048d19d4SFlorian Westphal } else { 748048d19d4SFlorian Westphal err = do_mmap(infd, peerfd, size); 749048d19d4SFlorian Westphal if (err) 750048d19d4SFlorian Westphal return err; 751048d19d4SFlorian Westphal 752048d19d4SFlorian Westphal shutdown(peerfd, SHUT_WR); 753048d19d4SFlorian Westphal 754048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 755b6ab64b0SPaolo Abeni *in_closed_after_out = true; 756048d19d4SFlorian Westphal } 757048d19d4SFlorian Westphal 758048d19d4SFlorian Westphal return err; 759048d19d4SFlorian Westphal } 760048d19d4SFlorian Westphal 761048d19d4SFlorian Westphal static int copyfd_io_sendfile(int infd, int peerfd, int outfd, 762b6ab64b0SPaolo Abeni unsigned int size, bool *in_closed_after_out) 763048d19d4SFlorian Westphal { 764048d19d4SFlorian Westphal int err; 765048d19d4SFlorian Westphal 766048d19d4SFlorian Westphal if (listen_mode) { 767048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 768048d19d4SFlorian Westphal if (err) 769048d19d4SFlorian Westphal return err; 770048d19d4SFlorian Westphal 771048d19d4SFlorian Westphal err = do_sendfile(infd, peerfd, size); 772048d19d4SFlorian Westphal } else { 773048d19d4SFlorian Westphal err = do_sendfile(infd, peerfd, size); 774048d19d4SFlorian Westphal if (err) 775048d19d4SFlorian Westphal return err; 776048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 777b6ab64b0SPaolo Abeni *in_closed_after_out = true; 778048d19d4SFlorian Westphal } 779048d19d4SFlorian Westphal 780048d19d4SFlorian Westphal return err; 781048d19d4SFlorian Westphal } 782048d19d4SFlorian Westphal 783048d19d4SFlorian Westphal static int copyfd_io(int infd, int peerfd, int outfd) 784048d19d4SFlorian Westphal { 785b6ab64b0SPaolo Abeni bool in_closed_after_out = false; 786b6ab64b0SPaolo Abeni struct timespec start, end; 787048d19d4SFlorian Westphal int file_size; 788b6ab64b0SPaolo Abeni int ret; 789b6ab64b0SPaolo Abeni 790b6ab64b0SPaolo Abeni if (cfg_time && (clock_gettime(CLOCK_MONOTONIC, &start) < 0)) 791b6ab64b0SPaolo Abeni xerror("can not fetch start time %d", errno); 792048d19d4SFlorian Westphal 793048d19d4SFlorian Westphal switch (cfg_mode) { 794048d19d4SFlorian Westphal case CFG_MODE_POLL: 795b6ab64b0SPaolo Abeni ret = copyfd_io_poll(infd, peerfd, outfd, &in_closed_after_out); 796b6ab64b0SPaolo Abeni break; 797b6ab64b0SPaolo Abeni 798048d19d4SFlorian Westphal case CFG_MODE_MMAP: 799048d19d4SFlorian Westphal file_size = get_infd_size(infd); 800048d19d4SFlorian Westphal if (file_size < 0) 801048d19d4SFlorian Westphal return file_size; 802b6ab64b0SPaolo Abeni ret = copyfd_io_mmap(infd, peerfd, outfd, file_size, &in_closed_after_out); 803b6ab64b0SPaolo Abeni break; 804b6ab64b0SPaolo Abeni 805048d19d4SFlorian Westphal case CFG_MODE_SENDFILE: 806048d19d4SFlorian Westphal file_size = get_infd_size(infd); 807048d19d4SFlorian Westphal if (file_size < 0) 808048d19d4SFlorian Westphal return file_size; 809b6ab64b0SPaolo Abeni ret = copyfd_io_sendfile(infd, peerfd, outfd, file_size, &in_closed_after_out); 810b6ab64b0SPaolo Abeni break; 811048d19d4SFlorian Westphal 812b6ab64b0SPaolo Abeni default: 813048d19d4SFlorian Westphal fprintf(stderr, "Invalid mode %d\n", cfg_mode); 814048d19d4SFlorian Westphal 815048d19d4SFlorian Westphal die_usage(); 816048d19d4SFlorian Westphal return 1; 817048d19d4SFlorian Westphal } 818048d19d4SFlorian Westphal 819b6ab64b0SPaolo Abeni if (ret) 820b6ab64b0SPaolo Abeni return ret; 821b6ab64b0SPaolo Abeni 822b6ab64b0SPaolo Abeni if (cfg_time) { 823b6ab64b0SPaolo Abeni unsigned int delta_ms; 824b6ab64b0SPaolo Abeni 825b6ab64b0SPaolo Abeni if (clock_gettime(CLOCK_MONOTONIC, &end) < 0) 826b6ab64b0SPaolo Abeni xerror("can not fetch end time %d", errno); 827b6ab64b0SPaolo Abeni delta_ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000; 828b6ab64b0SPaolo Abeni if (delta_ms > cfg_time) { 829b6ab64b0SPaolo Abeni xerror("transfer slower than expected! runtime %d ms, expected %d ms", 830b6ab64b0SPaolo Abeni delta_ms, cfg_time); 831b6ab64b0SPaolo Abeni } 832b6ab64b0SPaolo Abeni 833b6ab64b0SPaolo Abeni /* show the runtime only if this end shutdown(wr) before receiving the EOF, 834b6ab64b0SPaolo Abeni * (that is, if this end got the longer runtime) 835b6ab64b0SPaolo Abeni */ 836b6ab64b0SPaolo Abeni if (in_closed_after_out) 837b6ab64b0SPaolo Abeni fprintf(stderr, "%d", delta_ms); 838b6ab64b0SPaolo Abeni } 839b6ab64b0SPaolo Abeni 840b6ab64b0SPaolo Abeni return 0; 841b6ab64b0SPaolo Abeni } 842b6ab64b0SPaolo Abeni 843048d19d4SFlorian Westphal static void check_sockaddr(int pf, struct sockaddr_storage *ss, 844048d19d4SFlorian Westphal socklen_t salen) 845048d19d4SFlorian Westphal { 846048d19d4SFlorian Westphal struct sockaddr_in6 *sin6; 847048d19d4SFlorian Westphal struct sockaddr_in *sin; 848048d19d4SFlorian Westphal socklen_t wanted_size = 0; 849048d19d4SFlorian Westphal 850048d19d4SFlorian Westphal switch (pf) { 851048d19d4SFlorian Westphal case AF_INET: 852048d19d4SFlorian Westphal wanted_size = sizeof(*sin); 853048d19d4SFlorian Westphal sin = (void *)ss; 854048d19d4SFlorian Westphal if (!sin->sin_port) 855048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ip connection from port 0"); 856048d19d4SFlorian Westphal break; 857048d19d4SFlorian Westphal case AF_INET6: 858048d19d4SFlorian Westphal wanted_size = sizeof(*sin6); 859048d19d4SFlorian Westphal sin6 = (void *)ss; 860048d19d4SFlorian Westphal if (!sin6->sin6_port) 861048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ipv6 connection from port 0"); 862048d19d4SFlorian Westphal break; 863048d19d4SFlorian Westphal default: 864048d19d4SFlorian Westphal fprintf(stderr, "accept: Unknown pf %d, salen %u\n", pf, salen); 865048d19d4SFlorian Westphal return; 866048d19d4SFlorian Westphal } 867048d19d4SFlorian Westphal 868048d19d4SFlorian Westphal if (salen != wanted_size) 869048d19d4SFlorian Westphal fprintf(stderr, "accept: size mismatch, got %d expected %d\n", 870048d19d4SFlorian Westphal (int)salen, wanted_size); 871048d19d4SFlorian Westphal 872048d19d4SFlorian Westphal if (ss->ss_family != pf) 873048d19d4SFlorian Westphal fprintf(stderr, "accept: pf mismatch, expect %d, ss_family is %d\n", 874048d19d4SFlorian Westphal (int)ss->ss_family, pf); 875048d19d4SFlorian Westphal } 876048d19d4SFlorian Westphal 877048d19d4SFlorian Westphal static void check_getpeername(int fd, struct sockaddr_storage *ss, socklen_t salen) 878048d19d4SFlorian Westphal { 879048d19d4SFlorian Westphal struct sockaddr_storage peerss; 880048d19d4SFlorian Westphal socklen_t peersalen = sizeof(peerss); 881048d19d4SFlorian Westphal 882048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&peerss, &peersalen) < 0) { 883048d19d4SFlorian Westphal perror("getpeername"); 884048d19d4SFlorian Westphal return; 885048d19d4SFlorian Westphal } 886048d19d4SFlorian Westphal 887048d19d4SFlorian Westphal if (peersalen != salen) { 888048d19d4SFlorian Westphal fprintf(stderr, "%s: %d vs %d\n", __func__, peersalen, salen); 889048d19d4SFlorian Westphal return; 890048d19d4SFlorian Westphal } 891048d19d4SFlorian Westphal 892048d19d4SFlorian Westphal if (memcmp(ss, &peerss, peersalen)) { 893048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 894048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 895048d19d4SFlorian Westphal char c[INET6_ADDRSTRLEN]; 896048d19d4SFlorian Westphal char d[INET6_ADDRSTRLEN]; 897048d19d4SFlorian Westphal 898048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)ss, salen, 899048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 900048d19d4SFlorian Westphal 901048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&peerss, peersalen, 902048d19d4SFlorian Westphal c, sizeof(c), d, sizeof(d)); 903048d19d4SFlorian Westphal 904048d19d4SFlorian Westphal fprintf(stderr, "%s: memcmp failure: accept %s vs peername %s, %s vs %s salen %d vs %d\n", 905048d19d4SFlorian Westphal __func__, a, c, b, d, peersalen, salen); 906048d19d4SFlorian Westphal } 907048d19d4SFlorian Westphal } 908048d19d4SFlorian Westphal 909048d19d4SFlorian Westphal static void check_getpeername_connect(int fd) 910048d19d4SFlorian Westphal { 911048d19d4SFlorian Westphal struct sockaddr_storage ss; 912048d19d4SFlorian Westphal socklen_t salen = sizeof(ss); 913048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 914048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 915048d19d4SFlorian Westphal 916048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&ss, &salen) < 0) { 917048d19d4SFlorian Westphal perror("getpeername"); 918048d19d4SFlorian Westphal return; 919048d19d4SFlorian Westphal } 920048d19d4SFlorian Westphal 921048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&ss, salen, 922048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 923048d19d4SFlorian Westphal 924048d19d4SFlorian Westphal if (strcmp(cfg_host, a) || strcmp(cfg_port, b)) 925048d19d4SFlorian Westphal fprintf(stderr, "%s: %s vs %s, %s vs %s\n", __func__, 926048d19d4SFlorian Westphal cfg_host, a, cfg_port, b); 927048d19d4SFlorian Westphal } 928048d19d4SFlorian Westphal 929b0519de8SFlorian Westphal static void maybe_close(int fd) 930b0519de8SFlorian Westphal { 931b0519de8SFlorian Westphal unsigned int r = rand(); 932b0519de8SFlorian Westphal 93313153324SGeliang Tang if (!(cfg_join || cfg_remove) && (r & 1)) 934b0519de8SFlorian Westphal close(fd); 935b0519de8SFlorian Westphal } 936b0519de8SFlorian Westphal 937048d19d4SFlorian Westphal int main_loop_s(int listensock) 938048d19d4SFlorian Westphal { 939048d19d4SFlorian Westphal struct sockaddr_storage ss; 940048d19d4SFlorian Westphal struct pollfd polls; 941048d19d4SFlorian Westphal socklen_t salen; 942048d19d4SFlorian Westphal int remotesock; 943048d19d4SFlorian Westphal 944048d19d4SFlorian Westphal polls.fd = listensock; 945048d19d4SFlorian Westphal polls.events = POLLIN; 946048d19d4SFlorian Westphal 947048d19d4SFlorian Westphal switch (poll(&polls, 1, poll_timeout)) { 948048d19d4SFlorian Westphal case -1: 949048d19d4SFlorian Westphal perror("poll"); 950048d19d4SFlorian Westphal return 1; 951048d19d4SFlorian Westphal case 0: 952048d19d4SFlorian Westphal fprintf(stderr, "%s: timed out\n", __func__); 953048d19d4SFlorian Westphal close(listensock); 954048d19d4SFlorian Westphal return 2; 955048d19d4SFlorian Westphal } 956048d19d4SFlorian Westphal 957048d19d4SFlorian Westphal salen = sizeof(ss); 958048d19d4SFlorian Westphal remotesock = accept(listensock, (struct sockaddr *)&ss, &salen); 959048d19d4SFlorian Westphal if (remotesock >= 0) { 960b0519de8SFlorian Westphal maybe_close(listensock); 961048d19d4SFlorian Westphal check_sockaddr(pf, &ss, salen); 962048d19d4SFlorian Westphal check_getpeername(remotesock, &ss, salen); 963048d19d4SFlorian Westphal 964*f730b65cSFlorian Westphal SOCK_TEST_TCPULP(remotesock, 0); 965*f730b65cSFlorian Westphal 966048d19d4SFlorian Westphal return copyfd_io(0, remotesock, 1); 967048d19d4SFlorian Westphal } 968048d19d4SFlorian Westphal 969048d19d4SFlorian Westphal perror("accept"); 970048d19d4SFlorian Westphal 971048d19d4SFlorian Westphal return 1; 972048d19d4SFlorian Westphal } 973048d19d4SFlorian Westphal 974048d19d4SFlorian Westphal static void init_rng(void) 975048d19d4SFlorian Westphal { 976048d19d4SFlorian Westphal int fd = open("/dev/urandom", O_RDONLY); 977048d19d4SFlorian Westphal unsigned int foo; 978048d19d4SFlorian Westphal 979048d19d4SFlorian Westphal if (fd > 0) { 980048d19d4SFlorian Westphal int ret = read(fd, &foo, sizeof(foo)); 981048d19d4SFlorian Westphal 982048d19d4SFlorian Westphal if (ret < 0) 983048d19d4SFlorian Westphal srand(fd + foo); 984048d19d4SFlorian Westphal close(fd); 985048d19d4SFlorian Westphal } 986048d19d4SFlorian Westphal 987048d19d4SFlorian Westphal srand(foo); 988048d19d4SFlorian Westphal } 989048d19d4SFlorian Westphal 9905e6af0a7SFlorian Westphal static void xsetsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) 9915e6af0a7SFlorian Westphal { 9925e6af0a7SFlorian Westphal int err; 9935e6af0a7SFlorian Westphal 9945e6af0a7SFlorian Westphal err = setsockopt(fd, level, optname, optval, optlen); 9955e6af0a7SFlorian Westphal if (err) { 9965e6af0a7SFlorian Westphal perror("setsockopt"); 9975e6af0a7SFlorian Westphal exit(1); 9985e6af0a7SFlorian Westphal } 9995e6af0a7SFlorian Westphal } 10005e6af0a7SFlorian Westphal 10015e6af0a7SFlorian Westphal static void apply_cmsg_types(int fd, const struct cfg_cmsg_types *cmsg) 10025e6af0a7SFlorian Westphal { 10035e6af0a7SFlorian Westphal static const unsigned int on = 1; 10045e6af0a7SFlorian Westphal 10055e6af0a7SFlorian Westphal if (cmsg->timestampns) 10065e6af0a7SFlorian Westphal xsetsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW, &on, sizeof(on)); 10075cbd886cSFlorian Westphal if (cmsg->tcp_inq) 10085cbd886cSFlorian Westphal xsetsockopt(fd, IPPROTO_TCP, TCP_INQ, &on, sizeof(on)); 10095e6af0a7SFlorian Westphal } 10105e6af0a7SFlorian Westphal 10115e6af0a7SFlorian Westphal static void parse_cmsg_types(const char *type) 10125e6af0a7SFlorian Westphal { 10135e6af0a7SFlorian Westphal char *next = strchr(type, ','); 10145e6af0a7SFlorian Westphal unsigned int len = 0; 10155e6af0a7SFlorian Westphal 10165e6af0a7SFlorian Westphal cfg_cmsg_types.cmsg_enabled = 1; 10175e6af0a7SFlorian Westphal 10185e6af0a7SFlorian Westphal if (next) { 10195e6af0a7SFlorian Westphal parse_cmsg_types(next + 1); 10205e6af0a7SFlorian Westphal len = next - type; 10215e6af0a7SFlorian Westphal } else { 10225e6af0a7SFlorian Westphal len = strlen(type); 10235e6af0a7SFlorian Westphal } 10245e6af0a7SFlorian Westphal 10255e6af0a7SFlorian Westphal if (strncmp(type, "TIMESTAMPNS", len) == 0) { 10265e6af0a7SFlorian Westphal cfg_cmsg_types.timestampns = 1; 10275e6af0a7SFlorian Westphal return; 10285e6af0a7SFlorian Westphal } 10295e6af0a7SFlorian Westphal 10305cbd886cSFlorian Westphal if (strncmp(type, "TCPINQ", len) == 0) { 10315cbd886cSFlorian Westphal cfg_cmsg_types.tcp_inq = 1; 10325cbd886cSFlorian Westphal return; 10335cbd886cSFlorian Westphal } 10345cbd886cSFlorian Westphal 10355e6af0a7SFlorian Westphal fprintf(stderr, "Unrecognized cmsg option %s\n", type); 10365e6af0a7SFlorian Westphal exit(1); 10375e6af0a7SFlorian Westphal } 10385e6af0a7SFlorian Westphal 10395fb62e9cSFlorian Westphal static void parse_setsock_options(const char *name) 10405fb62e9cSFlorian Westphal { 10415fb62e9cSFlorian Westphal char *next = strchr(name, ','); 10425fb62e9cSFlorian Westphal unsigned int len = 0; 10435fb62e9cSFlorian Westphal 10445fb62e9cSFlorian Westphal if (next) { 10455fb62e9cSFlorian Westphal parse_setsock_options(next + 1); 10465fb62e9cSFlorian Westphal len = next - name; 10475fb62e9cSFlorian Westphal } else { 10485fb62e9cSFlorian Westphal len = strlen(name); 10495fb62e9cSFlorian Westphal } 10505fb62e9cSFlorian Westphal 10515fb62e9cSFlorian Westphal if (strncmp(name, "TRANSPARENT", len) == 0) { 10525fb62e9cSFlorian Westphal cfg_sockopt_types.transparent = 1; 10535fb62e9cSFlorian Westphal return; 10545fb62e9cSFlorian Westphal } 10555fb62e9cSFlorian Westphal 10565fb62e9cSFlorian Westphal fprintf(stderr, "Unrecognized setsockopt option %s\n", name); 10575fb62e9cSFlorian Westphal exit(1); 10585fb62e9cSFlorian Westphal } 10595fb62e9cSFlorian Westphal 1060048d19d4SFlorian Westphal int main_loop(void) 1061048d19d4SFlorian Westphal { 1062048d19d4SFlorian Westphal int fd; 1063048d19d4SFlorian Westphal 1064048d19d4SFlorian Westphal /* listener is ready. */ 1065048d19d4SFlorian Westphal fd = sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto); 1066048d19d4SFlorian Westphal if (fd < 0) 1067048d19d4SFlorian Westphal return 2; 1068048d19d4SFlorian Westphal 1069048d19d4SFlorian Westphal check_getpeername_connect(fd); 1070048d19d4SFlorian Westphal 1071*f730b65cSFlorian Westphal SOCK_TEST_TCPULP(fd, cfg_sock_proto); 1072*f730b65cSFlorian Westphal 10738a4b910dSFlorian Westphal if (cfg_rcvbuf) 10748a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 1075048d19d4SFlorian Westphal if (cfg_sndbuf) 1076048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 10775e6af0a7SFlorian Westphal if (cfg_cmsg_types.cmsg_enabled) 10785e6af0a7SFlorian Westphal apply_cmsg_types(fd, &cfg_cmsg_types); 1079048d19d4SFlorian Westphal 1080048d19d4SFlorian Westphal return copyfd_io(0, fd, 1); 1081048d19d4SFlorian Westphal } 1082048d19d4SFlorian Westphal 1083048d19d4SFlorian Westphal int parse_proto(const char *proto) 1084048d19d4SFlorian Westphal { 1085048d19d4SFlorian Westphal if (!strcasecmp(proto, "MPTCP")) 1086048d19d4SFlorian Westphal return IPPROTO_MPTCP; 1087048d19d4SFlorian Westphal if (!strcasecmp(proto, "TCP")) 1088048d19d4SFlorian Westphal return IPPROTO_TCP; 1089048d19d4SFlorian Westphal 1090048d19d4SFlorian Westphal fprintf(stderr, "Unknown protocol: %s\n.", proto); 1091048d19d4SFlorian Westphal die_usage(); 1092048d19d4SFlorian Westphal 1093048d19d4SFlorian Westphal /* silence compiler warning */ 1094048d19d4SFlorian Westphal return 0; 1095048d19d4SFlorian Westphal } 1096048d19d4SFlorian Westphal 1097048d19d4SFlorian Westphal int parse_mode(const char *mode) 1098048d19d4SFlorian Westphal { 1099048d19d4SFlorian Westphal if (!strcasecmp(mode, "poll")) 1100048d19d4SFlorian Westphal return CFG_MODE_POLL; 1101048d19d4SFlorian Westphal if (!strcasecmp(mode, "mmap")) 1102048d19d4SFlorian Westphal return CFG_MODE_MMAP; 1103048d19d4SFlorian Westphal if (!strcasecmp(mode, "sendfile")) 1104048d19d4SFlorian Westphal return CFG_MODE_SENDFILE; 1105048d19d4SFlorian Westphal 1106048d19d4SFlorian Westphal fprintf(stderr, "Unknown test mode: %s\n", mode); 1107048d19d4SFlorian Westphal fprintf(stderr, "Supported modes are:\n"); 1108048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"poll\" - interleaved read/write using poll()\n"); 1109048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"mmap\" - send entire input file (mmap+write), then read response (-l will read input first)\n"); 1110048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"sendfile\" - send entire input file (sendfile), then read response (-l will read input first)\n"); 1111048d19d4SFlorian Westphal 1112048d19d4SFlorian Westphal die_usage(); 1113048d19d4SFlorian Westphal 1114048d19d4SFlorian Westphal /* silence compiler warning */ 1115048d19d4SFlorian Westphal return 0; 1116048d19d4SFlorian Westphal } 1117048d19d4SFlorian Westphal 1118df8aee6dSYonglong Li int parse_peek(const char *mode) 1119df8aee6dSYonglong Li { 1120df8aee6dSYonglong Li if (!strcasecmp(mode, "saveWithPeek")) 1121df8aee6dSYonglong Li return CFG_WITH_PEEK; 1122df8aee6dSYonglong Li if (!strcasecmp(mode, "saveAfterPeek")) 1123df8aee6dSYonglong Li return CFG_AFTER_PEEK; 1124df8aee6dSYonglong Li 1125df8aee6dSYonglong Li fprintf(stderr, "Unknown: %s\n", mode); 1126df8aee6dSYonglong Li fprintf(stderr, "Supported MSG_PEEK mode are:\n"); 1127df8aee6dSYonglong Li fprintf(stderr, 1128df8aee6dSYonglong Li "\t\t\"saveWithPeek\" - recv data with flags 'MSG_PEEK' and save the peek data into file\n"); 1129df8aee6dSYonglong Li fprintf(stderr, 1130df8aee6dSYonglong Li "\t\t\"saveAfterPeek\" - read and save data into file after recv with flags 'MSG_PEEK'\n"); 1131df8aee6dSYonglong Li 1132df8aee6dSYonglong Li die_usage(); 1133df8aee6dSYonglong Li 1134df8aee6dSYonglong Li /* silence compiler warning */ 1135df8aee6dSYonglong Li return 0; 1136df8aee6dSYonglong Li } 1137df8aee6dSYonglong Li 11388a4b910dSFlorian Westphal static int parse_int(const char *size) 1139048d19d4SFlorian Westphal { 1140048d19d4SFlorian Westphal unsigned long s; 1141048d19d4SFlorian Westphal 1142048d19d4SFlorian Westphal errno = 0; 1143048d19d4SFlorian Westphal 1144048d19d4SFlorian Westphal s = strtoul(size, NULL, 0); 1145048d19d4SFlorian Westphal 1146048d19d4SFlorian Westphal if (errno) { 1147048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 1148048d19d4SFlorian Westphal size, strerror(errno)); 1149048d19d4SFlorian Westphal die_usage(); 1150048d19d4SFlorian Westphal } 1151048d19d4SFlorian Westphal 1152048d19d4SFlorian Westphal if (s > INT_MAX) { 1153048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 1154048d19d4SFlorian Westphal size, strerror(ERANGE)); 1155048d19d4SFlorian Westphal die_usage(); 1156048d19d4SFlorian Westphal } 1157048d19d4SFlorian Westphal 11588a4b910dSFlorian Westphal return (int)s; 1159048d19d4SFlorian Westphal } 1160048d19d4SFlorian Westphal 1161048d19d4SFlorian Westphal static void parse_opts(int argc, char **argv) 1162048d19d4SFlorian Westphal { 1163048d19d4SFlorian Westphal int c; 1164048d19d4SFlorian Westphal 1165*f730b65cSFlorian Westphal while ((c = getopt(argc, argv, "6jr:lp:s:ht:T:m:S:R:w:M:P:c:o:")) != -1) { 1166048d19d4SFlorian Westphal switch (c) { 1167b08fbf24SPaolo Abeni case 'j': 1168b08fbf24SPaolo Abeni cfg_join = true; 1169b08fbf24SPaolo Abeni cfg_mode = CFG_MODE_POLL; 1170b08fbf24SPaolo Abeni break; 117113153324SGeliang Tang case 'r': 117213153324SGeliang Tang cfg_remove = true; 117313153324SGeliang Tang cfg_mode = CFG_MODE_POLL; 117413153324SGeliang Tang cfg_wait = 400000; 11752e580a63SGeliang Tang cfg_do_w = atoi(optarg); 11762e580a63SGeliang Tang if (cfg_do_w <= 0) 11772e580a63SGeliang Tang cfg_do_w = 50; 117813153324SGeliang Tang break; 1179048d19d4SFlorian Westphal case 'l': 1180048d19d4SFlorian Westphal listen_mode = true; 1181048d19d4SFlorian Westphal break; 1182048d19d4SFlorian Westphal case 'p': 1183048d19d4SFlorian Westphal cfg_port = optarg; 1184048d19d4SFlorian Westphal break; 1185048d19d4SFlorian Westphal case 's': 1186048d19d4SFlorian Westphal cfg_sock_proto = parse_proto(optarg); 1187048d19d4SFlorian Westphal break; 1188048d19d4SFlorian Westphal case 'h': 1189048d19d4SFlorian Westphal die_usage(); 1190048d19d4SFlorian Westphal break; 1191048d19d4SFlorian Westphal case '6': 1192048d19d4SFlorian Westphal pf = AF_INET6; 1193048d19d4SFlorian Westphal break; 1194048d19d4SFlorian Westphal case 't': 1195048d19d4SFlorian Westphal poll_timeout = atoi(optarg) * 1000; 1196048d19d4SFlorian Westphal if (poll_timeout <= 0) 1197048d19d4SFlorian Westphal poll_timeout = -1; 1198048d19d4SFlorian Westphal break; 1199b6ab64b0SPaolo Abeni case 'T': 1200b6ab64b0SPaolo Abeni cfg_time = atoi(optarg); 1201b6ab64b0SPaolo Abeni break; 1202048d19d4SFlorian Westphal case 'm': 1203048d19d4SFlorian Westphal cfg_mode = parse_mode(optarg); 1204048d19d4SFlorian Westphal break; 12058a4b910dSFlorian Westphal case 'S': 12068a4b910dSFlorian Westphal cfg_sndbuf = parse_int(optarg); 12078a4b910dSFlorian Westphal break; 12088a4b910dSFlorian Westphal case 'R': 12098a4b910dSFlorian Westphal cfg_rcvbuf = parse_int(optarg); 1210048d19d4SFlorian Westphal break; 1211df62f2ecSPaolo Abeni case 'w': 1212df62f2ecSPaolo Abeni cfg_wait = atoi(optarg)*1000000; 1213df62f2ecSPaolo Abeni break; 1214dc65fe82SFlorian Westphal case 'M': 1215dc65fe82SFlorian Westphal cfg_mark = strtol(optarg, NULL, 0); 1216dc65fe82SFlorian Westphal break; 1217df8aee6dSYonglong Li case 'P': 1218df8aee6dSYonglong Li cfg_peek = parse_peek(optarg); 1219df8aee6dSYonglong Li break; 12205e6af0a7SFlorian Westphal case 'c': 12215e6af0a7SFlorian Westphal parse_cmsg_types(optarg); 12225e6af0a7SFlorian Westphal break; 12235fb62e9cSFlorian Westphal case 'o': 12245fb62e9cSFlorian Westphal parse_setsock_options(optarg); 12255fb62e9cSFlorian Westphal break; 1226048d19d4SFlorian Westphal } 1227048d19d4SFlorian Westphal } 1228048d19d4SFlorian Westphal 1229048d19d4SFlorian Westphal if (optind + 1 != argc) 1230048d19d4SFlorian Westphal die_usage(); 1231048d19d4SFlorian Westphal cfg_host = argv[optind]; 1232048d19d4SFlorian Westphal 1233048d19d4SFlorian Westphal if (strchr(cfg_host, ':')) 1234048d19d4SFlorian Westphal pf = AF_INET6; 1235048d19d4SFlorian Westphal } 1236048d19d4SFlorian Westphal 1237048d19d4SFlorian Westphal int main(int argc, char *argv[]) 1238048d19d4SFlorian Westphal { 1239048d19d4SFlorian Westphal init_rng(); 1240048d19d4SFlorian Westphal 1241df62f2ecSPaolo Abeni signal(SIGUSR1, handle_signal); 1242048d19d4SFlorian Westphal parse_opts(argc, argv); 1243048d19d4SFlorian Westphal 1244048d19d4SFlorian Westphal if (listen_mode) { 1245048d19d4SFlorian Westphal int fd = sock_listen_mptcp(cfg_host, cfg_port); 1246048d19d4SFlorian Westphal 1247048d19d4SFlorian Westphal if (fd < 0) 1248048d19d4SFlorian Westphal return 1; 1249048d19d4SFlorian Westphal 12508a4b910dSFlorian Westphal if (cfg_rcvbuf) 12518a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 1252048d19d4SFlorian Westphal if (cfg_sndbuf) 1253048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 1254dc65fe82SFlorian Westphal if (cfg_mark) 1255dc65fe82SFlorian Westphal set_mark(fd, cfg_mark); 12565e6af0a7SFlorian Westphal if (cfg_cmsg_types.cmsg_enabled) 12575e6af0a7SFlorian Westphal apply_cmsg_types(fd, &cfg_cmsg_types); 1258048d19d4SFlorian Westphal 1259048d19d4SFlorian Westphal return main_loop_s(fd); 1260048d19d4SFlorian Westphal } 1261048d19d4SFlorian Westphal 1262048d19d4SFlorian Westphal return main_loop(); 1263048d19d4SFlorian Westphal } 1264