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> 9048d19d4SFlorian Westphal #include <stdbool.h> 10048d19d4SFlorian Westphal #include <stdint.h> 11048d19d4SFlorian Westphal #include <stdio.h> 12048d19d4SFlorian Westphal #include <stdlib.h> 13048d19d4SFlorian Westphal #include <strings.h> 14df62f2ecSPaolo Abeni #include <signal.h> 15048d19d4SFlorian Westphal #include <unistd.h> 16048d19d4SFlorian Westphal 17048d19d4SFlorian Westphal #include <sys/poll.h> 18048d19d4SFlorian Westphal #include <sys/sendfile.h> 19048d19d4SFlorian Westphal #include <sys/stat.h> 20048d19d4SFlorian Westphal #include <sys/socket.h> 21048d19d4SFlorian Westphal #include <sys/types.h> 22048d19d4SFlorian Westphal #include <sys/mman.h> 23048d19d4SFlorian Westphal 24048d19d4SFlorian Westphal #include <netdb.h> 25048d19d4SFlorian Westphal #include <netinet/in.h> 26048d19d4SFlorian Westphal 27048d19d4SFlorian Westphal #include <linux/tcp.h> 28048d19d4SFlorian Westphal 29048d19d4SFlorian Westphal extern int optind; 30048d19d4SFlorian Westphal 31048d19d4SFlorian Westphal #ifndef IPPROTO_MPTCP 32048d19d4SFlorian Westphal #define IPPROTO_MPTCP 262 33048d19d4SFlorian Westphal #endif 34048d19d4SFlorian Westphal #ifndef TCP_ULP 35048d19d4SFlorian Westphal #define TCP_ULP 31 36048d19d4SFlorian Westphal #endif 37048d19d4SFlorian Westphal 388a4b910dSFlorian Westphal static int poll_timeout = 10 * 1000; 39048d19d4SFlorian Westphal static bool listen_mode; 40df62f2ecSPaolo Abeni static bool quit; 41048d19d4SFlorian Westphal 42048d19d4SFlorian Westphal enum cfg_mode { 43048d19d4SFlorian Westphal CFG_MODE_POLL, 44048d19d4SFlorian Westphal CFG_MODE_MMAP, 45048d19d4SFlorian Westphal CFG_MODE_SENDFILE, 46048d19d4SFlorian Westphal }; 47048d19d4SFlorian Westphal 48048d19d4SFlorian Westphal static enum cfg_mode cfg_mode = CFG_MODE_POLL; 49048d19d4SFlorian Westphal static const char *cfg_host; 50048d19d4SFlorian Westphal static const char *cfg_port = "12000"; 51048d19d4SFlorian Westphal static int cfg_sock_proto = IPPROTO_MPTCP; 52048d19d4SFlorian Westphal static bool tcpulp_audit; 53048d19d4SFlorian Westphal static int pf = AF_INET; 54048d19d4SFlorian Westphal static int cfg_sndbuf; 558a4b910dSFlorian Westphal static int cfg_rcvbuf; 56b08fbf24SPaolo Abeni static bool cfg_join; 57df62f2ecSPaolo Abeni static int cfg_wait; 58048d19d4SFlorian Westphal 59048d19d4SFlorian Westphal static void die_usage(void) 60048d19d4SFlorian Westphal { 618a4b910dSFlorian Westphal fprintf(stderr, "Usage: mptcp_connect [-6] [-u] [-s MPTCP|TCP] [-p port] [-m mode]" 62df62f2ecSPaolo Abeni "[-l] [-w sec] connect_address\n"); 638a4b910dSFlorian Westphal fprintf(stderr, "\t-6 use ipv6\n"); 648a4b910dSFlorian Westphal fprintf(stderr, "\t-t num -- set poll timeout to num\n"); 658a4b910dSFlorian Westphal fprintf(stderr, "\t-S num -- set SO_SNDBUF to num\n"); 668a4b910dSFlorian Westphal fprintf(stderr, "\t-R num -- set SO_RCVBUF to num\n"); 678a4b910dSFlorian Westphal fprintf(stderr, "\t-p num -- use port num\n"); 68*c6f4c2b0SDavide Caratti fprintf(stderr, "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n"); 69*c6f4c2b0SDavide Caratti fprintf(stderr, "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n"); 708a4b910dSFlorian Westphal fprintf(stderr, "\t-u -- check mptcp ulp\n"); 71df62f2ecSPaolo Abeni fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n"); 72048d19d4SFlorian Westphal exit(1); 73048d19d4SFlorian Westphal } 74048d19d4SFlorian Westphal 75df62f2ecSPaolo Abeni static void handle_signal(int nr) 76df62f2ecSPaolo Abeni { 77df62f2ecSPaolo Abeni quit = true; 78df62f2ecSPaolo Abeni } 79df62f2ecSPaolo Abeni 80048d19d4SFlorian Westphal static const char *getxinfo_strerr(int err) 81048d19d4SFlorian Westphal { 82048d19d4SFlorian Westphal if (err == EAI_SYSTEM) 83048d19d4SFlorian Westphal return strerror(errno); 84048d19d4SFlorian Westphal 85048d19d4SFlorian Westphal return gai_strerror(err); 86048d19d4SFlorian Westphal } 87048d19d4SFlorian Westphal 88048d19d4SFlorian Westphal static void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen, 89048d19d4SFlorian Westphal char *host, socklen_t hostlen, 90048d19d4SFlorian Westphal char *serv, socklen_t servlen) 91048d19d4SFlorian Westphal { 92048d19d4SFlorian Westphal int flags = NI_NUMERICHOST | NI_NUMERICSERV; 93048d19d4SFlorian Westphal int err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, 94048d19d4SFlorian Westphal flags); 95048d19d4SFlorian Westphal 96048d19d4SFlorian Westphal if (err) { 97048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 98048d19d4SFlorian Westphal 99048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getnameinfo: %s\n", errstr); 100048d19d4SFlorian Westphal exit(1); 101048d19d4SFlorian Westphal } 102048d19d4SFlorian Westphal } 103048d19d4SFlorian Westphal 104048d19d4SFlorian Westphal static void xgetaddrinfo(const char *node, const char *service, 105048d19d4SFlorian Westphal const struct addrinfo *hints, 106048d19d4SFlorian Westphal struct addrinfo **res) 107048d19d4SFlorian Westphal { 108048d19d4SFlorian Westphal int err = getaddrinfo(node, service, hints, res); 109048d19d4SFlorian Westphal 110048d19d4SFlorian Westphal if (err) { 111048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 112048d19d4SFlorian Westphal 113048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", 114048d19d4SFlorian Westphal node ? node : "", service ? service : "", errstr); 115048d19d4SFlorian Westphal exit(1); 116048d19d4SFlorian Westphal } 117048d19d4SFlorian Westphal } 118048d19d4SFlorian Westphal 1198a4b910dSFlorian Westphal static void set_rcvbuf(int fd, unsigned int size) 1208a4b910dSFlorian Westphal { 1218a4b910dSFlorian Westphal int err; 1228a4b910dSFlorian Westphal 1238a4b910dSFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 1248a4b910dSFlorian Westphal if (err) { 1258a4b910dSFlorian Westphal perror("set SO_RCVBUF"); 1268a4b910dSFlorian Westphal exit(1); 1278a4b910dSFlorian Westphal } 1288a4b910dSFlorian Westphal } 1298a4b910dSFlorian Westphal 130048d19d4SFlorian Westphal static void set_sndbuf(int fd, unsigned int size) 131048d19d4SFlorian Westphal { 132048d19d4SFlorian Westphal int err; 133048d19d4SFlorian Westphal 134048d19d4SFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); 135048d19d4SFlorian Westphal if (err) { 136048d19d4SFlorian Westphal perror("set SO_SNDBUF"); 137048d19d4SFlorian Westphal exit(1); 138048d19d4SFlorian Westphal } 139048d19d4SFlorian Westphal } 140048d19d4SFlorian Westphal 141048d19d4SFlorian Westphal static int sock_listen_mptcp(const char * const listenaddr, 142048d19d4SFlorian Westphal const char * const port) 143048d19d4SFlorian Westphal { 144048d19d4SFlorian Westphal int sock; 145048d19d4SFlorian Westphal struct addrinfo hints = { 146048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 147048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 148048d19d4SFlorian Westphal .ai_flags = AI_PASSIVE | AI_NUMERICHOST 149048d19d4SFlorian Westphal }; 150048d19d4SFlorian Westphal 151048d19d4SFlorian Westphal hints.ai_family = pf; 152048d19d4SFlorian Westphal 153048d19d4SFlorian Westphal struct addrinfo *a, *addr; 154048d19d4SFlorian Westphal int one = 1; 155048d19d4SFlorian Westphal 156048d19d4SFlorian Westphal xgetaddrinfo(listenaddr, port, &hints, &addr); 157048d19d4SFlorian Westphal hints.ai_family = pf; 158048d19d4SFlorian Westphal 159048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 160048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, cfg_sock_proto); 161048d19d4SFlorian Westphal if (sock < 0) 162048d19d4SFlorian Westphal continue; 163048d19d4SFlorian Westphal 164048d19d4SFlorian Westphal if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, 165048d19d4SFlorian Westphal sizeof(one))) 166048d19d4SFlorian Westphal perror("setsockopt"); 167048d19d4SFlorian Westphal 168048d19d4SFlorian Westphal if (bind(sock, a->ai_addr, a->ai_addrlen) == 0) 169048d19d4SFlorian Westphal break; /* success */ 170048d19d4SFlorian Westphal 171048d19d4SFlorian Westphal perror("bind"); 172048d19d4SFlorian Westphal close(sock); 173048d19d4SFlorian Westphal sock = -1; 174048d19d4SFlorian Westphal } 175048d19d4SFlorian Westphal 176048d19d4SFlorian Westphal freeaddrinfo(addr); 177048d19d4SFlorian Westphal 178048d19d4SFlorian Westphal if (sock < 0) { 179048d19d4SFlorian Westphal fprintf(stderr, "Could not create listen socket\n"); 180048d19d4SFlorian Westphal return sock; 181048d19d4SFlorian Westphal } 182048d19d4SFlorian Westphal 183048d19d4SFlorian Westphal if (listen(sock, 20)) { 184048d19d4SFlorian Westphal perror("listen"); 185048d19d4SFlorian Westphal close(sock); 186048d19d4SFlorian Westphal return -1; 187048d19d4SFlorian Westphal } 188048d19d4SFlorian Westphal 189048d19d4SFlorian Westphal return sock; 190048d19d4SFlorian Westphal } 191048d19d4SFlorian Westphal 192048d19d4SFlorian Westphal static bool sock_test_tcpulp(const char * const remoteaddr, 193048d19d4SFlorian Westphal const char * const port) 194048d19d4SFlorian Westphal { 195048d19d4SFlorian Westphal struct addrinfo hints = { 196048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 197048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 198048d19d4SFlorian Westphal }; 199048d19d4SFlorian Westphal struct addrinfo *a, *addr; 200048d19d4SFlorian Westphal int sock = -1, ret = 0; 201048d19d4SFlorian Westphal bool test_pass = false; 202048d19d4SFlorian Westphal 203048d19d4SFlorian Westphal hints.ai_family = AF_INET; 204048d19d4SFlorian Westphal 205048d19d4SFlorian Westphal xgetaddrinfo(remoteaddr, port, &hints, &addr); 206048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 207048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, IPPROTO_TCP); 208048d19d4SFlorian Westphal if (sock < 0) { 209048d19d4SFlorian Westphal perror("socket"); 210048d19d4SFlorian Westphal continue; 211048d19d4SFlorian Westphal } 212048d19d4SFlorian Westphal ret = setsockopt(sock, IPPROTO_TCP, TCP_ULP, "mptcp", 213048d19d4SFlorian Westphal sizeof("mptcp")); 214048d19d4SFlorian Westphal if (ret == -1 && errno == EOPNOTSUPP) 215048d19d4SFlorian Westphal test_pass = true; 216048d19d4SFlorian Westphal close(sock); 217048d19d4SFlorian Westphal 218048d19d4SFlorian Westphal if (test_pass) 219048d19d4SFlorian Westphal break; 220048d19d4SFlorian Westphal if (!ret) 221048d19d4SFlorian Westphal fprintf(stderr, 222048d19d4SFlorian Westphal "setsockopt(TCP_ULP) returned 0\n"); 223048d19d4SFlorian Westphal else 224048d19d4SFlorian Westphal perror("setsockopt(TCP_ULP)"); 225048d19d4SFlorian Westphal } 226048d19d4SFlorian Westphal return test_pass; 227048d19d4SFlorian Westphal } 228048d19d4SFlorian Westphal 229048d19d4SFlorian Westphal static int sock_connect_mptcp(const char * const remoteaddr, 230048d19d4SFlorian Westphal const char * const port, int proto) 231048d19d4SFlorian Westphal { 232048d19d4SFlorian Westphal struct addrinfo hints = { 233048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 234048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 235048d19d4SFlorian Westphal }; 236048d19d4SFlorian Westphal struct addrinfo *a, *addr; 237048d19d4SFlorian Westphal int sock = -1; 238048d19d4SFlorian Westphal 239048d19d4SFlorian Westphal hints.ai_family = pf; 240048d19d4SFlorian Westphal 241048d19d4SFlorian Westphal xgetaddrinfo(remoteaddr, port, &hints, &addr); 242048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 243048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, proto); 244048d19d4SFlorian Westphal if (sock < 0) { 245048d19d4SFlorian Westphal perror("socket"); 246048d19d4SFlorian Westphal continue; 247048d19d4SFlorian Westphal } 248048d19d4SFlorian Westphal 249048d19d4SFlorian Westphal if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) 250048d19d4SFlorian Westphal break; /* success */ 251048d19d4SFlorian Westphal 252048d19d4SFlorian Westphal perror("connect()"); 253048d19d4SFlorian Westphal close(sock); 254048d19d4SFlorian Westphal sock = -1; 255048d19d4SFlorian Westphal } 256048d19d4SFlorian Westphal 257048d19d4SFlorian Westphal freeaddrinfo(addr); 258048d19d4SFlorian Westphal return sock; 259048d19d4SFlorian Westphal } 260048d19d4SFlorian Westphal 261048d19d4SFlorian Westphal static size_t do_rnd_write(const int fd, char *buf, const size_t len) 262048d19d4SFlorian Westphal { 263b08fbf24SPaolo Abeni static bool first = true; 264048d19d4SFlorian Westphal unsigned int do_w; 265048d19d4SFlorian Westphal ssize_t bw; 266048d19d4SFlorian Westphal 267048d19d4SFlorian Westphal do_w = rand() & 0xffff; 268048d19d4SFlorian Westphal if (do_w == 0 || do_w > len) 269048d19d4SFlorian Westphal do_w = len; 270048d19d4SFlorian Westphal 271b08fbf24SPaolo Abeni if (cfg_join && first && do_w > 100) 272b08fbf24SPaolo Abeni do_w = 100; 273b08fbf24SPaolo Abeni 274048d19d4SFlorian Westphal bw = write(fd, buf, do_w); 275048d19d4SFlorian Westphal if (bw < 0) 276048d19d4SFlorian Westphal perror("write"); 277048d19d4SFlorian Westphal 278b08fbf24SPaolo Abeni /* let the join handshake complete, before going on */ 279b08fbf24SPaolo Abeni if (cfg_join && first) { 280b08fbf24SPaolo Abeni usleep(200000); 281b08fbf24SPaolo Abeni first = false; 282b08fbf24SPaolo Abeni } 283b08fbf24SPaolo Abeni 284048d19d4SFlorian Westphal return bw; 285048d19d4SFlorian Westphal } 286048d19d4SFlorian Westphal 287048d19d4SFlorian Westphal static size_t do_write(const int fd, char *buf, const size_t len) 288048d19d4SFlorian Westphal { 289048d19d4SFlorian Westphal size_t offset = 0; 290048d19d4SFlorian Westphal 291048d19d4SFlorian Westphal while (offset < len) { 292048d19d4SFlorian Westphal size_t written; 293048d19d4SFlorian Westphal ssize_t bw; 294048d19d4SFlorian Westphal 295048d19d4SFlorian Westphal bw = write(fd, buf + offset, len - offset); 296048d19d4SFlorian Westphal if (bw < 0) { 297048d19d4SFlorian Westphal perror("write"); 298048d19d4SFlorian Westphal return 0; 299048d19d4SFlorian Westphal } 300048d19d4SFlorian Westphal 301048d19d4SFlorian Westphal written = (size_t)bw; 302048d19d4SFlorian Westphal offset += written; 303048d19d4SFlorian Westphal } 304048d19d4SFlorian Westphal 305048d19d4SFlorian Westphal return offset; 306048d19d4SFlorian Westphal } 307048d19d4SFlorian Westphal 308048d19d4SFlorian Westphal static ssize_t do_rnd_read(const int fd, char *buf, const size_t len) 309048d19d4SFlorian Westphal { 310048d19d4SFlorian Westphal size_t cap = rand(); 311048d19d4SFlorian Westphal 312048d19d4SFlorian Westphal cap &= 0xffff; 313048d19d4SFlorian Westphal 314048d19d4SFlorian Westphal if (cap == 0) 315048d19d4SFlorian Westphal cap = 1; 316048d19d4SFlorian Westphal else if (cap > len) 317048d19d4SFlorian Westphal cap = len; 318048d19d4SFlorian Westphal 319048d19d4SFlorian Westphal return read(fd, buf, cap); 320048d19d4SFlorian Westphal } 321048d19d4SFlorian Westphal 322048d19d4SFlorian Westphal static void set_nonblock(int fd) 323048d19d4SFlorian Westphal { 324048d19d4SFlorian Westphal int flags = fcntl(fd, F_GETFL); 325048d19d4SFlorian Westphal 326048d19d4SFlorian Westphal if (flags == -1) 327048d19d4SFlorian Westphal return; 328048d19d4SFlorian Westphal 329048d19d4SFlorian Westphal fcntl(fd, F_SETFL, flags | O_NONBLOCK); 330048d19d4SFlorian Westphal } 331048d19d4SFlorian Westphal 332048d19d4SFlorian Westphal static int copyfd_io_poll(int infd, int peerfd, int outfd) 333048d19d4SFlorian Westphal { 334048d19d4SFlorian Westphal struct pollfd fds = { 335048d19d4SFlorian Westphal .fd = peerfd, 336048d19d4SFlorian Westphal .events = POLLIN | POLLOUT, 337048d19d4SFlorian Westphal }; 338048d19d4SFlorian Westphal unsigned int woff = 0, wlen = 0; 339048d19d4SFlorian Westphal char wbuf[8192]; 340048d19d4SFlorian Westphal 341048d19d4SFlorian Westphal set_nonblock(peerfd); 342048d19d4SFlorian Westphal 343048d19d4SFlorian Westphal for (;;) { 344048d19d4SFlorian Westphal char rbuf[8192]; 345048d19d4SFlorian Westphal ssize_t len; 346048d19d4SFlorian Westphal 347048d19d4SFlorian Westphal if (fds.events == 0) 348048d19d4SFlorian Westphal break; 349048d19d4SFlorian Westphal 350048d19d4SFlorian Westphal switch (poll(&fds, 1, poll_timeout)) { 351048d19d4SFlorian Westphal case -1: 352048d19d4SFlorian Westphal if (errno == EINTR) 353048d19d4SFlorian Westphal continue; 354048d19d4SFlorian Westphal perror("poll"); 355048d19d4SFlorian Westphal return 1; 356048d19d4SFlorian Westphal case 0: 357048d19d4SFlorian Westphal fprintf(stderr, "%s: poll timed out (events: " 358048d19d4SFlorian Westphal "POLLIN %u, POLLOUT %u)\n", __func__, 359048d19d4SFlorian Westphal fds.events & POLLIN, fds.events & POLLOUT); 360048d19d4SFlorian Westphal return 2; 361048d19d4SFlorian Westphal } 362048d19d4SFlorian Westphal 363048d19d4SFlorian Westphal if (fds.revents & POLLIN) { 364048d19d4SFlorian Westphal len = do_rnd_read(peerfd, rbuf, sizeof(rbuf)); 365048d19d4SFlorian Westphal if (len == 0) { 366048d19d4SFlorian Westphal /* no more data to receive: 367048d19d4SFlorian Westphal * peer has closed its write side 368048d19d4SFlorian Westphal */ 369048d19d4SFlorian Westphal fds.events &= ~POLLIN; 370048d19d4SFlorian Westphal 371048d19d4SFlorian Westphal if ((fds.events & POLLOUT) == 0) 372048d19d4SFlorian Westphal /* and nothing more to send */ 373048d19d4SFlorian Westphal break; 374048d19d4SFlorian Westphal 375048d19d4SFlorian Westphal /* Else, still have data to transmit */ 376048d19d4SFlorian Westphal } else if (len < 0) { 377048d19d4SFlorian Westphal perror("read"); 378048d19d4SFlorian Westphal return 3; 379048d19d4SFlorian Westphal } 380048d19d4SFlorian Westphal 381048d19d4SFlorian Westphal do_write(outfd, rbuf, len); 382048d19d4SFlorian Westphal } 383048d19d4SFlorian Westphal 384048d19d4SFlorian Westphal if (fds.revents & POLLOUT) { 385048d19d4SFlorian Westphal if (wlen == 0) { 386048d19d4SFlorian Westphal woff = 0; 387048d19d4SFlorian Westphal wlen = read(infd, wbuf, sizeof(wbuf)); 388048d19d4SFlorian Westphal } 389048d19d4SFlorian Westphal 390048d19d4SFlorian Westphal if (wlen > 0) { 391048d19d4SFlorian Westphal ssize_t bw; 392048d19d4SFlorian Westphal 393048d19d4SFlorian Westphal bw = do_rnd_write(peerfd, wbuf + woff, wlen); 394048d19d4SFlorian Westphal if (bw < 0) 395048d19d4SFlorian Westphal return 111; 396048d19d4SFlorian Westphal 397048d19d4SFlorian Westphal woff += bw; 398048d19d4SFlorian Westphal wlen -= bw; 399048d19d4SFlorian Westphal } else if (wlen == 0) { 400048d19d4SFlorian Westphal /* We have no more data to send. */ 401048d19d4SFlorian Westphal fds.events &= ~POLLOUT; 402048d19d4SFlorian Westphal 403048d19d4SFlorian Westphal if ((fds.events & POLLIN) == 0) 404048d19d4SFlorian Westphal /* ... and peer also closed already */ 405048d19d4SFlorian Westphal break; 406048d19d4SFlorian Westphal 407048d19d4SFlorian Westphal /* ... but we still receive. 408b08fbf24SPaolo Abeni * Close our write side, ev. give some time 4096bdb6211SPaolo Abeni * for address notification and/or checking 4106bdb6211SPaolo Abeni * the current status 411048d19d4SFlorian Westphal */ 4126bdb6211SPaolo Abeni if (cfg_wait) 4136bdb6211SPaolo Abeni usleep(cfg_wait); 414048d19d4SFlorian Westphal shutdown(peerfd, SHUT_WR); 415048d19d4SFlorian Westphal } else { 416048d19d4SFlorian Westphal if (errno == EINTR) 417048d19d4SFlorian Westphal continue; 418048d19d4SFlorian Westphal perror("read"); 419048d19d4SFlorian Westphal return 4; 420048d19d4SFlorian Westphal } 421048d19d4SFlorian Westphal } 422048d19d4SFlorian Westphal 423048d19d4SFlorian Westphal if (fds.revents & (POLLERR | POLLNVAL)) { 424048d19d4SFlorian Westphal fprintf(stderr, "Unexpected revents: " 425048d19d4SFlorian Westphal "POLLERR/POLLNVAL(%x)\n", fds.revents); 426048d19d4SFlorian Westphal return 5; 427048d19d4SFlorian Westphal } 428048d19d4SFlorian Westphal } 429048d19d4SFlorian Westphal 430b08fbf24SPaolo Abeni /* leave some time for late join/announce */ 4316bdb6211SPaolo Abeni if (cfg_join) 432df62f2ecSPaolo Abeni usleep(cfg_wait); 433b08fbf24SPaolo Abeni 434048d19d4SFlorian Westphal close(peerfd); 435048d19d4SFlorian Westphal return 0; 436048d19d4SFlorian Westphal } 437048d19d4SFlorian Westphal 438048d19d4SFlorian Westphal static int do_recvfile(int infd, int outfd) 439048d19d4SFlorian Westphal { 440048d19d4SFlorian Westphal ssize_t r; 441048d19d4SFlorian Westphal 442048d19d4SFlorian Westphal do { 443048d19d4SFlorian Westphal char buf[16384]; 444048d19d4SFlorian Westphal 445048d19d4SFlorian Westphal r = do_rnd_read(infd, buf, sizeof(buf)); 446048d19d4SFlorian Westphal if (r > 0) { 447048d19d4SFlorian Westphal if (write(outfd, buf, r) != r) 448048d19d4SFlorian Westphal break; 449048d19d4SFlorian Westphal } else if (r < 0) { 450048d19d4SFlorian Westphal perror("read"); 451048d19d4SFlorian Westphal } 452048d19d4SFlorian Westphal } while (r > 0); 453048d19d4SFlorian Westphal 454048d19d4SFlorian Westphal return (int)r; 455048d19d4SFlorian Westphal } 456048d19d4SFlorian Westphal 457048d19d4SFlorian Westphal static int do_mmap(int infd, int outfd, unsigned int size) 458048d19d4SFlorian Westphal { 459048d19d4SFlorian Westphal char *inbuf = mmap(NULL, size, PROT_READ, MAP_SHARED, infd, 0); 460048d19d4SFlorian Westphal ssize_t ret = 0, off = 0; 461048d19d4SFlorian Westphal size_t rem; 462048d19d4SFlorian Westphal 463048d19d4SFlorian Westphal if (inbuf == MAP_FAILED) { 464048d19d4SFlorian Westphal perror("mmap"); 465048d19d4SFlorian Westphal return 1; 466048d19d4SFlorian Westphal } 467048d19d4SFlorian Westphal 468048d19d4SFlorian Westphal rem = size; 469048d19d4SFlorian Westphal 470048d19d4SFlorian Westphal while (rem > 0) { 471048d19d4SFlorian Westphal ret = write(outfd, inbuf + off, rem); 472048d19d4SFlorian Westphal 473048d19d4SFlorian Westphal if (ret < 0) { 474048d19d4SFlorian Westphal perror("write"); 475048d19d4SFlorian Westphal break; 476048d19d4SFlorian Westphal } 477048d19d4SFlorian Westphal 478048d19d4SFlorian Westphal off += ret; 479048d19d4SFlorian Westphal rem -= ret; 480048d19d4SFlorian Westphal } 481048d19d4SFlorian Westphal 482048d19d4SFlorian Westphal munmap(inbuf, size); 483048d19d4SFlorian Westphal return rem; 484048d19d4SFlorian Westphal } 485048d19d4SFlorian Westphal 486048d19d4SFlorian Westphal static int get_infd_size(int fd) 487048d19d4SFlorian Westphal { 488048d19d4SFlorian Westphal struct stat sb; 489048d19d4SFlorian Westphal ssize_t count; 490048d19d4SFlorian Westphal int err; 491048d19d4SFlorian Westphal 492048d19d4SFlorian Westphal err = fstat(fd, &sb); 493048d19d4SFlorian Westphal if (err < 0) { 494048d19d4SFlorian Westphal perror("fstat"); 495048d19d4SFlorian Westphal return -1; 496048d19d4SFlorian Westphal } 497048d19d4SFlorian Westphal 498048d19d4SFlorian Westphal if ((sb.st_mode & S_IFMT) != S_IFREG) { 499048d19d4SFlorian Westphal fprintf(stderr, "%s: stdin is not a regular file\n", __func__); 500048d19d4SFlorian Westphal return -2; 501048d19d4SFlorian Westphal } 502048d19d4SFlorian Westphal 503048d19d4SFlorian Westphal count = sb.st_size; 504048d19d4SFlorian Westphal if (count > INT_MAX) { 505048d19d4SFlorian Westphal fprintf(stderr, "File too large: %zu\n", count); 506048d19d4SFlorian Westphal return -3; 507048d19d4SFlorian Westphal } 508048d19d4SFlorian Westphal 509048d19d4SFlorian Westphal return (int)count; 510048d19d4SFlorian Westphal } 511048d19d4SFlorian Westphal 512048d19d4SFlorian Westphal static int do_sendfile(int infd, int outfd, unsigned int count) 513048d19d4SFlorian Westphal { 514048d19d4SFlorian Westphal while (count > 0) { 515048d19d4SFlorian Westphal ssize_t r; 516048d19d4SFlorian Westphal 517048d19d4SFlorian Westphal r = sendfile(outfd, infd, NULL, count); 518048d19d4SFlorian Westphal if (r < 0) { 519048d19d4SFlorian Westphal perror("sendfile"); 520048d19d4SFlorian Westphal return 3; 521048d19d4SFlorian Westphal } 522048d19d4SFlorian Westphal 523048d19d4SFlorian Westphal count -= r; 524048d19d4SFlorian Westphal } 525048d19d4SFlorian Westphal 526048d19d4SFlorian Westphal return 0; 527048d19d4SFlorian Westphal } 528048d19d4SFlorian Westphal 529048d19d4SFlorian Westphal static int copyfd_io_mmap(int infd, int peerfd, int outfd, 530048d19d4SFlorian Westphal unsigned int size) 531048d19d4SFlorian Westphal { 532048d19d4SFlorian Westphal int err; 533048d19d4SFlorian Westphal 534048d19d4SFlorian Westphal if (listen_mode) { 535048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 536048d19d4SFlorian Westphal if (err) 537048d19d4SFlorian Westphal return err; 538048d19d4SFlorian Westphal 539048d19d4SFlorian Westphal err = do_mmap(infd, peerfd, size); 540048d19d4SFlorian Westphal } else { 541048d19d4SFlorian Westphal err = do_mmap(infd, peerfd, size); 542048d19d4SFlorian Westphal if (err) 543048d19d4SFlorian Westphal return err; 544048d19d4SFlorian Westphal 545048d19d4SFlorian Westphal shutdown(peerfd, SHUT_WR); 546048d19d4SFlorian Westphal 547048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 548048d19d4SFlorian Westphal } 549048d19d4SFlorian Westphal 550048d19d4SFlorian Westphal return err; 551048d19d4SFlorian Westphal } 552048d19d4SFlorian Westphal 553048d19d4SFlorian Westphal static int copyfd_io_sendfile(int infd, int peerfd, int outfd, 554048d19d4SFlorian Westphal unsigned int size) 555048d19d4SFlorian Westphal { 556048d19d4SFlorian Westphal int err; 557048d19d4SFlorian Westphal 558048d19d4SFlorian Westphal if (listen_mode) { 559048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 560048d19d4SFlorian Westphal if (err) 561048d19d4SFlorian Westphal return err; 562048d19d4SFlorian Westphal 563048d19d4SFlorian Westphal err = do_sendfile(infd, peerfd, size); 564048d19d4SFlorian Westphal } else { 565048d19d4SFlorian Westphal err = do_sendfile(infd, peerfd, size); 566048d19d4SFlorian Westphal if (err) 567048d19d4SFlorian Westphal return err; 568048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 569048d19d4SFlorian Westphal } 570048d19d4SFlorian Westphal 571048d19d4SFlorian Westphal return err; 572048d19d4SFlorian Westphal } 573048d19d4SFlorian Westphal 574048d19d4SFlorian Westphal static int copyfd_io(int infd, int peerfd, int outfd) 575048d19d4SFlorian Westphal { 576048d19d4SFlorian Westphal int file_size; 577048d19d4SFlorian Westphal 578048d19d4SFlorian Westphal switch (cfg_mode) { 579048d19d4SFlorian Westphal case CFG_MODE_POLL: 580048d19d4SFlorian Westphal return copyfd_io_poll(infd, peerfd, outfd); 581048d19d4SFlorian Westphal case CFG_MODE_MMAP: 582048d19d4SFlorian Westphal file_size = get_infd_size(infd); 583048d19d4SFlorian Westphal if (file_size < 0) 584048d19d4SFlorian Westphal return file_size; 585048d19d4SFlorian Westphal return copyfd_io_mmap(infd, peerfd, outfd, file_size); 586048d19d4SFlorian Westphal case CFG_MODE_SENDFILE: 587048d19d4SFlorian Westphal file_size = get_infd_size(infd); 588048d19d4SFlorian Westphal if (file_size < 0) 589048d19d4SFlorian Westphal return file_size; 590048d19d4SFlorian Westphal return copyfd_io_sendfile(infd, peerfd, outfd, file_size); 591048d19d4SFlorian Westphal } 592048d19d4SFlorian Westphal 593048d19d4SFlorian Westphal fprintf(stderr, "Invalid mode %d\n", cfg_mode); 594048d19d4SFlorian Westphal 595048d19d4SFlorian Westphal die_usage(); 596048d19d4SFlorian Westphal return 1; 597048d19d4SFlorian Westphal } 598048d19d4SFlorian Westphal 599048d19d4SFlorian Westphal static void check_sockaddr(int pf, struct sockaddr_storage *ss, 600048d19d4SFlorian Westphal socklen_t salen) 601048d19d4SFlorian Westphal { 602048d19d4SFlorian Westphal struct sockaddr_in6 *sin6; 603048d19d4SFlorian Westphal struct sockaddr_in *sin; 604048d19d4SFlorian Westphal socklen_t wanted_size = 0; 605048d19d4SFlorian Westphal 606048d19d4SFlorian Westphal switch (pf) { 607048d19d4SFlorian Westphal case AF_INET: 608048d19d4SFlorian Westphal wanted_size = sizeof(*sin); 609048d19d4SFlorian Westphal sin = (void *)ss; 610048d19d4SFlorian Westphal if (!sin->sin_port) 611048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ip connection from port 0"); 612048d19d4SFlorian Westphal break; 613048d19d4SFlorian Westphal case AF_INET6: 614048d19d4SFlorian Westphal wanted_size = sizeof(*sin6); 615048d19d4SFlorian Westphal sin6 = (void *)ss; 616048d19d4SFlorian Westphal if (!sin6->sin6_port) 617048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ipv6 connection from port 0"); 618048d19d4SFlorian Westphal break; 619048d19d4SFlorian Westphal default: 620048d19d4SFlorian Westphal fprintf(stderr, "accept: Unknown pf %d, salen %u\n", pf, salen); 621048d19d4SFlorian Westphal return; 622048d19d4SFlorian Westphal } 623048d19d4SFlorian Westphal 624048d19d4SFlorian Westphal if (salen != wanted_size) 625048d19d4SFlorian Westphal fprintf(stderr, "accept: size mismatch, got %d expected %d\n", 626048d19d4SFlorian Westphal (int)salen, wanted_size); 627048d19d4SFlorian Westphal 628048d19d4SFlorian Westphal if (ss->ss_family != pf) 629048d19d4SFlorian Westphal fprintf(stderr, "accept: pf mismatch, expect %d, ss_family is %d\n", 630048d19d4SFlorian Westphal (int)ss->ss_family, pf); 631048d19d4SFlorian Westphal } 632048d19d4SFlorian Westphal 633048d19d4SFlorian Westphal static void check_getpeername(int fd, struct sockaddr_storage *ss, socklen_t salen) 634048d19d4SFlorian Westphal { 635048d19d4SFlorian Westphal struct sockaddr_storage peerss; 636048d19d4SFlorian Westphal socklen_t peersalen = sizeof(peerss); 637048d19d4SFlorian Westphal 638048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&peerss, &peersalen) < 0) { 639048d19d4SFlorian Westphal perror("getpeername"); 640048d19d4SFlorian Westphal return; 641048d19d4SFlorian Westphal } 642048d19d4SFlorian Westphal 643048d19d4SFlorian Westphal if (peersalen != salen) { 644048d19d4SFlorian Westphal fprintf(stderr, "%s: %d vs %d\n", __func__, peersalen, salen); 645048d19d4SFlorian Westphal return; 646048d19d4SFlorian Westphal } 647048d19d4SFlorian Westphal 648048d19d4SFlorian Westphal if (memcmp(ss, &peerss, peersalen)) { 649048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 650048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 651048d19d4SFlorian Westphal char c[INET6_ADDRSTRLEN]; 652048d19d4SFlorian Westphal char d[INET6_ADDRSTRLEN]; 653048d19d4SFlorian Westphal 654048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)ss, salen, 655048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 656048d19d4SFlorian Westphal 657048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&peerss, peersalen, 658048d19d4SFlorian Westphal c, sizeof(c), d, sizeof(d)); 659048d19d4SFlorian Westphal 660048d19d4SFlorian Westphal fprintf(stderr, "%s: memcmp failure: accept %s vs peername %s, %s vs %s salen %d vs %d\n", 661048d19d4SFlorian Westphal __func__, a, c, b, d, peersalen, salen); 662048d19d4SFlorian Westphal } 663048d19d4SFlorian Westphal } 664048d19d4SFlorian Westphal 665048d19d4SFlorian Westphal static void check_getpeername_connect(int fd) 666048d19d4SFlorian Westphal { 667048d19d4SFlorian Westphal struct sockaddr_storage ss; 668048d19d4SFlorian Westphal socklen_t salen = sizeof(ss); 669048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 670048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 671048d19d4SFlorian Westphal 672048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&ss, &salen) < 0) { 673048d19d4SFlorian Westphal perror("getpeername"); 674048d19d4SFlorian Westphal return; 675048d19d4SFlorian Westphal } 676048d19d4SFlorian Westphal 677048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&ss, salen, 678048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 679048d19d4SFlorian Westphal 680048d19d4SFlorian Westphal if (strcmp(cfg_host, a) || strcmp(cfg_port, b)) 681048d19d4SFlorian Westphal fprintf(stderr, "%s: %s vs %s, %s vs %s\n", __func__, 682048d19d4SFlorian Westphal cfg_host, a, cfg_port, b); 683048d19d4SFlorian Westphal } 684048d19d4SFlorian Westphal 685b0519de8SFlorian Westphal static void maybe_close(int fd) 686b0519de8SFlorian Westphal { 687b0519de8SFlorian Westphal unsigned int r = rand(); 688b0519de8SFlorian Westphal 689b08fbf24SPaolo Abeni if (!cfg_join && (r & 1)) 690b0519de8SFlorian Westphal close(fd); 691b0519de8SFlorian Westphal } 692b0519de8SFlorian Westphal 693048d19d4SFlorian Westphal int main_loop_s(int listensock) 694048d19d4SFlorian Westphal { 695048d19d4SFlorian Westphal struct sockaddr_storage ss; 696048d19d4SFlorian Westphal struct pollfd polls; 697048d19d4SFlorian Westphal socklen_t salen; 698048d19d4SFlorian Westphal int remotesock; 699048d19d4SFlorian Westphal 700048d19d4SFlorian Westphal polls.fd = listensock; 701048d19d4SFlorian Westphal polls.events = POLLIN; 702048d19d4SFlorian Westphal 703048d19d4SFlorian Westphal switch (poll(&polls, 1, poll_timeout)) { 704048d19d4SFlorian Westphal case -1: 705048d19d4SFlorian Westphal perror("poll"); 706048d19d4SFlorian Westphal return 1; 707048d19d4SFlorian Westphal case 0: 708048d19d4SFlorian Westphal fprintf(stderr, "%s: timed out\n", __func__); 709048d19d4SFlorian Westphal close(listensock); 710048d19d4SFlorian Westphal return 2; 711048d19d4SFlorian Westphal } 712048d19d4SFlorian Westphal 713048d19d4SFlorian Westphal salen = sizeof(ss); 714048d19d4SFlorian Westphal remotesock = accept(listensock, (struct sockaddr *)&ss, &salen); 715048d19d4SFlorian Westphal if (remotesock >= 0) { 716b0519de8SFlorian Westphal maybe_close(listensock); 717048d19d4SFlorian Westphal check_sockaddr(pf, &ss, salen); 718048d19d4SFlorian Westphal check_getpeername(remotesock, &ss, salen); 719048d19d4SFlorian Westphal 720048d19d4SFlorian Westphal return copyfd_io(0, remotesock, 1); 721048d19d4SFlorian Westphal } 722048d19d4SFlorian Westphal 723048d19d4SFlorian Westphal perror("accept"); 724048d19d4SFlorian Westphal 725048d19d4SFlorian Westphal return 1; 726048d19d4SFlorian Westphal } 727048d19d4SFlorian Westphal 728048d19d4SFlorian Westphal static void init_rng(void) 729048d19d4SFlorian Westphal { 730048d19d4SFlorian Westphal int fd = open("/dev/urandom", O_RDONLY); 731048d19d4SFlorian Westphal unsigned int foo; 732048d19d4SFlorian Westphal 733048d19d4SFlorian Westphal if (fd > 0) { 734048d19d4SFlorian Westphal int ret = read(fd, &foo, sizeof(foo)); 735048d19d4SFlorian Westphal 736048d19d4SFlorian Westphal if (ret < 0) 737048d19d4SFlorian Westphal srand(fd + foo); 738048d19d4SFlorian Westphal close(fd); 739048d19d4SFlorian Westphal } 740048d19d4SFlorian Westphal 741048d19d4SFlorian Westphal srand(foo); 742048d19d4SFlorian Westphal } 743048d19d4SFlorian Westphal 744048d19d4SFlorian Westphal int main_loop(void) 745048d19d4SFlorian Westphal { 746048d19d4SFlorian Westphal int fd; 747048d19d4SFlorian Westphal 748048d19d4SFlorian Westphal /* listener is ready. */ 749048d19d4SFlorian Westphal fd = sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto); 750048d19d4SFlorian Westphal if (fd < 0) 751048d19d4SFlorian Westphal return 2; 752048d19d4SFlorian Westphal 753048d19d4SFlorian Westphal check_getpeername_connect(fd); 754048d19d4SFlorian Westphal 7558a4b910dSFlorian Westphal if (cfg_rcvbuf) 7568a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 757048d19d4SFlorian Westphal if (cfg_sndbuf) 758048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 759048d19d4SFlorian Westphal 760048d19d4SFlorian Westphal return copyfd_io(0, fd, 1); 761048d19d4SFlorian Westphal } 762048d19d4SFlorian Westphal 763048d19d4SFlorian Westphal int parse_proto(const char *proto) 764048d19d4SFlorian Westphal { 765048d19d4SFlorian Westphal if (!strcasecmp(proto, "MPTCP")) 766048d19d4SFlorian Westphal return IPPROTO_MPTCP; 767048d19d4SFlorian Westphal if (!strcasecmp(proto, "TCP")) 768048d19d4SFlorian Westphal return IPPROTO_TCP; 769048d19d4SFlorian Westphal 770048d19d4SFlorian Westphal fprintf(stderr, "Unknown protocol: %s\n.", proto); 771048d19d4SFlorian Westphal die_usage(); 772048d19d4SFlorian Westphal 773048d19d4SFlorian Westphal /* silence compiler warning */ 774048d19d4SFlorian Westphal return 0; 775048d19d4SFlorian Westphal } 776048d19d4SFlorian Westphal 777048d19d4SFlorian Westphal int parse_mode(const char *mode) 778048d19d4SFlorian Westphal { 779048d19d4SFlorian Westphal if (!strcasecmp(mode, "poll")) 780048d19d4SFlorian Westphal return CFG_MODE_POLL; 781048d19d4SFlorian Westphal if (!strcasecmp(mode, "mmap")) 782048d19d4SFlorian Westphal return CFG_MODE_MMAP; 783048d19d4SFlorian Westphal if (!strcasecmp(mode, "sendfile")) 784048d19d4SFlorian Westphal return CFG_MODE_SENDFILE; 785048d19d4SFlorian Westphal 786048d19d4SFlorian Westphal fprintf(stderr, "Unknown test mode: %s\n", mode); 787048d19d4SFlorian Westphal fprintf(stderr, "Supported modes are:\n"); 788048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"poll\" - interleaved read/write using poll()\n"); 789048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"mmap\" - send entire input file (mmap+write), then read response (-l will read input first)\n"); 790048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"sendfile\" - send entire input file (sendfile), then read response (-l will read input first)\n"); 791048d19d4SFlorian Westphal 792048d19d4SFlorian Westphal die_usage(); 793048d19d4SFlorian Westphal 794048d19d4SFlorian Westphal /* silence compiler warning */ 795048d19d4SFlorian Westphal return 0; 796048d19d4SFlorian Westphal } 797048d19d4SFlorian Westphal 7988a4b910dSFlorian Westphal static int parse_int(const char *size) 799048d19d4SFlorian Westphal { 800048d19d4SFlorian Westphal unsigned long s; 801048d19d4SFlorian Westphal 802048d19d4SFlorian Westphal errno = 0; 803048d19d4SFlorian Westphal 804048d19d4SFlorian Westphal s = strtoul(size, NULL, 0); 805048d19d4SFlorian Westphal 806048d19d4SFlorian Westphal if (errno) { 807048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 808048d19d4SFlorian Westphal size, strerror(errno)); 809048d19d4SFlorian Westphal die_usage(); 810048d19d4SFlorian Westphal } 811048d19d4SFlorian Westphal 812048d19d4SFlorian Westphal if (s > INT_MAX) { 813048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 814048d19d4SFlorian Westphal size, strerror(ERANGE)); 815048d19d4SFlorian Westphal die_usage(); 816048d19d4SFlorian Westphal } 817048d19d4SFlorian Westphal 8188a4b910dSFlorian Westphal return (int)s; 819048d19d4SFlorian Westphal } 820048d19d4SFlorian Westphal 821048d19d4SFlorian Westphal static void parse_opts(int argc, char **argv) 822048d19d4SFlorian Westphal { 823048d19d4SFlorian Westphal int c; 824048d19d4SFlorian Westphal 825df62f2ecSPaolo Abeni while ((c = getopt(argc, argv, "6jlp:s:hut:m:S:R:w:")) != -1) { 826048d19d4SFlorian Westphal switch (c) { 827b08fbf24SPaolo Abeni case 'j': 828b08fbf24SPaolo Abeni cfg_join = true; 829b08fbf24SPaolo Abeni cfg_mode = CFG_MODE_POLL; 830df62f2ecSPaolo Abeni cfg_wait = 400000; 831b08fbf24SPaolo Abeni break; 832048d19d4SFlorian Westphal case 'l': 833048d19d4SFlorian Westphal listen_mode = true; 834048d19d4SFlorian Westphal break; 835048d19d4SFlorian Westphal case 'p': 836048d19d4SFlorian Westphal cfg_port = optarg; 837048d19d4SFlorian Westphal break; 838048d19d4SFlorian Westphal case 's': 839048d19d4SFlorian Westphal cfg_sock_proto = parse_proto(optarg); 840048d19d4SFlorian Westphal break; 841048d19d4SFlorian Westphal case 'h': 842048d19d4SFlorian Westphal die_usage(); 843048d19d4SFlorian Westphal break; 844048d19d4SFlorian Westphal case 'u': 845048d19d4SFlorian Westphal tcpulp_audit = true; 846048d19d4SFlorian Westphal break; 847048d19d4SFlorian Westphal case '6': 848048d19d4SFlorian Westphal pf = AF_INET6; 849048d19d4SFlorian Westphal break; 850048d19d4SFlorian Westphal case 't': 851048d19d4SFlorian Westphal poll_timeout = atoi(optarg) * 1000; 852048d19d4SFlorian Westphal if (poll_timeout <= 0) 853048d19d4SFlorian Westphal poll_timeout = -1; 854048d19d4SFlorian Westphal break; 855048d19d4SFlorian Westphal case 'm': 856048d19d4SFlorian Westphal cfg_mode = parse_mode(optarg); 857048d19d4SFlorian Westphal break; 8588a4b910dSFlorian Westphal case 'S': 8598a4b910dSFlorian Westphal cfg_sndbuf = parse_int(optarg); 8608a4b910dSFlorian Westphal break; 8618a4b910dSFlorian Westphal case 'R': 8628a4b910dSFlorian Westphal cfg_rcvbuf = parse_int(optarg); 863048d19d4SFlorian Westphal break; 864df62f2ecSPaolo Abeni case 'w': 865df62f2ecSPaolo Abeni cfg_wait = atoi(optarg)*1000000; 866df62f2ecSPaolo Abeni break; 867048d19d4SFlorian Westphal } 868048d19d4SFlorian Westphal } 869048d19d4SFlorian Westphal 870048d19d4SFlorian Westphal if (optind + 1 != argc) 871048d19d4SFlorian Westphal die_usage(); 872048d19d4SFlorian Westphal cfg_host = argv[optind]; 873048d19d4SFlorian Westphal 874048d19d4SFlorian Westphal if (strchr(cfg_host, ':')) 875048d19d4SFlorian Westphal pf = AF_INET6; 876048d19d4SFlorian Westphal } 877048d19d4SFlorian Westphal 878048d19d4SFlorian Westphal int main(int argc, char *argv[]) 879048d19d4SFlorian Westphal { 880048d19d4SFlorian Westphal init_rng(); 881048d19d4SFlorian Westphal 882df62f2ecSPaolo Abeni signal(SIGUSR1, handle_signal); 883048d19d4SFlorian Westphal parse_opts(argc, argv); 884048d19d4SFlorian Westphal 885048d19d4SFlorian Westphal if (tcpulp_audit) 886048d19d4SFlorian Westphal return sock_test_tcpulp(cfg_host, cfg_port) ? 0 : 1; 887048d19d4SFlorian Westphal 888048d19d4SFlorian Westphal if (listen_mode) { 889048d19d4SFlorian Westphal int fd = sock_listen_mptcp(cfg_host, cfg_port); 890048d19d4SFlorian Westphal 891048d19d4SFlorian Westphal if (fd < 0) 892048d19d4SFlorian Westphal return 1; 893048d19d4SFlorian Westphal 8948a4b910dSFlorian Westphal if (cfg_rcvbuf) 8958a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 896048d19d4SFlorian Westphal if (cfg_sndbuf) 897048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 898048d19d4SFlorian Westphal 899048d19d4SFlorian Westphal return main_loop_s(fd); 900048d19d4SFlorian Westphal } 901048d19d4SFlorian Westphal 902048d19d4SFlorian Westphal return main_loop(); 903048d19d4SFlorian Westphal } 904