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