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 1905be5e27SPaolo Abeni #include <sys/ioctl.h> 20048d19d4SFlorian Westphal #include <sys/poll.h> 21048d19d4SFlorian Westphal #include <sys/sendfile.h> 22048d19d4SFlorian Westphal #include <sys/stat.h> 23048d19d4SFlorian Westphal #include <sys/socket.h> 24048d19d4SFlorian Westphal #include <sys/types.h> 25048d19d4SFlorian Westphal #include <sys/mman.h> 26048d19d4SFlorian Westphal 27048d19d4SFlorian Westphal #include <netdb.h> 28048d19d4SFlorian Westphal #include <netinet/in.h> 29048d19d4SFlorian Westphal 30048d19d4SFlorian Westphal #include <linux/tcp.h> 315e6af0a7SFlorian Westphal #include <linux/time_types.h> 3205be5e27SPaolo Abeni #include <linux/sockios.h> 33048d19d4SFlorian Westphal 34048d19d4SFlorian Westphal extern int optind; 35048d19d4SFlorian Westphal 36048d19d4SFlorian Westphal #ifndef IPPROTO_MPTCP 37048d19d4SFlorian Westphal #define IPPROTO_MPTCP 262 38048d19d4SFlorian Westphal #endif 39048d19d4SFlorian Westphal #ifndef TCP_ULP 40048d19d4SFlorian Westphal #define TCP_ULP 31 41048d19d4SFlorian Westphal #endif 42048d19d4SFlorian Westphal 438a4b910dSFlorian Westphal static int poll_timeout = 10 * 1000; 44048d19d4SFlorian Westphal static bool listen_mode; 45df62f2ecSPaolo Abeni static bool quit; 46048d19d4SFlorian Westphal 47048d19d4SFlorian Westphal enum cfg_mode { 48048d19d4SFlorian Westphal CFG_MODE_POLL, 49048d19d4SFlorian Westphal CFG_MODE_MMAP, 50048d19d4SFlorian Westphal CFG_MODE_SENDFILE, 51048d19d4SFlorian Westphal }; 52048d19d4SFlorian Westphal 53df8aee6dSYonglong Li enum cfg_peek { 54df8aee6dSYonglong Li CFG_NONE_PEEK, 55df8aee6dSYonglong Li CFG_WITH_PEEK, 56df8aee6dSYonglong Li CFG_AFTER_PEEK, 57df8aee6dSYonglong Li }; 58df8aee6dSYonglong Li 59048d19d4SFlorian Westphal static enum cfg_mode cfg_mode = CFG_MODE_POLL; 60df8aee6dSYonglong Li static enum cfg_peek cfg_peek = CFG_NONE_PEEK; 61048d19d4SFlorian Westphal static const char *cfg_host; 62048d19d4SFlorian Westphal static const char *cfg_port = "12000"; 63048d19d4SFlorian Westphal static int cfg_sock_proto = IPPROTO_MPTCP; 64048d19d4SFlorian Westphal static int pf = AF_INET; 65048d19d4SFlorian Westphal static int cfg_sndbuf; 668a4b910dSFlorian Westphal static int cfg_rcvbuf; 67b08fbf24SPaolo Abeni static bool cfg_join; 6813153324SGeliang Tang static bool cfg_remove; 69b6ab64b0SPaolo Abeni static unsigned int cfg_time; 702e580a63SGeliang Tang static unsigned int cfg_do_w; 71df62f2ecSPaolo Abeni static int cfg_wait; 72dc65fe82SFlorian Westphal static uint32_t cfg_mark; 7305be5e27SPaolo Abeni static char *cfg_input; 7405be5e27SPaolo Abeni static int cfg_repeat = 1; 75048d19d4SFlorian Westphal 765e6af0a7SFlorian Westphal struct cfg_cmsg_types { 775e6af0a7SFlorian Westphal unsigned int cmsg_enabled:1; 785e6af0a7SFlorian Westphal unsigned int timestampns:1; 795cbd886cSFlorian Westphal unsigned int tcp_inq:1; 805e6af0a7SFlorian Westphal }; 815e6af0a7SFlorian Westphal 825fb62e9cSFlorian Westphal struct cfg_sockopt_types { 835fb62e9cSFlorian Westphal unsigned int transparent:1; 845fb62e9cSFlorian Westphal }; 855fb62e9cSFlorian Westphal 865cbd886cSFlorian Westphal struct tcp_inq_state { 875cbd886cSFlorian Westphal unsigned int last; 885cbd886cSFlorian Westphal bool expect_eof; 895cbd886cSFlorian Westphal }; 905cbd886cSFlorian Westphal 915cbd886cSFlorian Westphal static struct tcp_inq_state tcp_inq; 925cbd886cSFlorian Westphal 935e6af0a7SFlorian Westphal static struct cfg_cmsg_types cfg_cmsg_types; 945fb62e9cSFlorian Westphal static struct cfg_sockopt_types cfg_sockopt_types; 955e6af0a7SFlorian Westphal 96048d19d4SFlorian Westphal static void die_usage(void) 97048d19d4SFlorian Westphal { 9805be5e27SPaolo Abeni fprintf(stderr, "Usage: mptcp_connect [-6] [-c cmsg] [-i file] [-I num] [-j] [-l] " 9905be5e27SPaolo Abeni "[-m mode] [-M mark] [-o option] [-p port] [-P mode] [-j] [-l] [-r num] " 10005be5e27SPaolo Abeni "[-s MPTCP|TCP] [-S num] [-r num] [-t num] [-T num] [-u] [-w sec] connect_address\n"); 1018a4b910dSFlorian Westphal fprintf(stderr, "\t-6 use ipv6\n"); 10205be5e27SPaolo Abeni fprintf(stderr, "\t-c cmsg -- test cmsg type <cmsg>\n"); 10305be5e27SPaolo Abeni fprintf(stderr, "\t-i file -- read the data to send from the given file instead of stdin"); 10405be5e27SPaolo Abeni fprintf(stderr, "\t-I num -- repeat the transfer 'num' times. In listen mode accepts num " 10505be5e27SPaolo Abeni "incoming connections, in client mode, disconnect and reconnect to the server\n"); 10605be5e27SPaolo Abeni fprintf(stderr, "\t-j -- add additional sleep at connection start and tear down " 10705be5e27SPaolo Abeni "-- for MPJ tests\n"); 10805be5e27SPaolo Abeni fprintf(stderr, "\t-l -- listens mode, accepts incoming connection\n"); 109c6f4c2b0SDavide Caratti fprintf(stderr, "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n"); 110dc65fe82SFlorian Westphal fprintf(stderr, "\t-M mark -- set socket packet mark\n"); 1115fb62e9cSFlorian Westphal fprintf(stderr, "\t-o option -- test sockopt <option>\n"); 11205be5e27SPaolo Abeni fprintf(stderr, "\t-p num -- use port num\n"); 113df8aee6dSYonglong Li fprintf(stderr, 114df8aee6dSYonglong Li "\t-P [saveWithPeek|saveAfterPeek] -- save data with/after MSG_PEEK form tcp socket\n"); 11505be5e27SPaolo Abeni fprintf(stderr, "\t-t num -- set poll timeout to num\n"); 11605be5e27SPaolo Abeni fprintf(stderr, "\t-T num -- set expected runtime to num ms\n"); 11705be5e27SPaolo Abeni fprintf(stderr, "\t-r num -- enable slow mode, limiting each write to num bytes " 11805be5e27SPaolo Abeni "-- for remove addr tests\n"); 11905be5e27SPaolo Abeni fprintf(stderr, "\t-R num -- set SO_RCVBUF to num\n"); 12005be5e27SPaolo Abeni fprintf(stderr, "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n"); 12105be5e27SPaolo Abeni fprintf(stderr, "\t-S num -- set SO_SNDBUF to num\n"); 12205be5e27SPaolo Abeni fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n"); 123048d19d4SFlorian Westphal exit(1); 124048d19d4SFlorian Westphal } 125048d19d4SFlorian Westphal 1265e6af0a7SFlorian Westphal static void xerror(const char *fmt, ...) 1275e6af0a7SFlorian Westphal { 1285e6af0a7SFlorian Westphal va_list ap; 1295e6af0a7SFlorian Westphal 1305e6af0a7SFlorian Westphal va_start(ap, fmt); 1315e6af0a7SFlorian Westphal vfprintf(stderr, fmt, ap); 1325e6af0a7SFlorian Westphal va_end(ap); 1335e6af0a7SFlorian Westphal exit(1); 1345e6af0a7SFlorian Westphal } 1355e6af0a7SFlorian Westphal 136df62f2ecSPaolo Abeni static void handle_signal(int nr) 137df62f2ecSPaolo Abeni { 138df62f2ecSPaolo Abeni quit = true; 139df62f2ecSPaolo Abeni } 140df62f2ecSPaolo Abeni 141048d19d4SFlorian Westphal static const char *getxinfo_strerr(int err) 142048d19d4SFlorian Westphal { 143048d19d4SFlorian Westphal if (err == EAI_SYSTEM) 144048d19d4SFlorian Westphal return strerror(errno); 145048d19d4SFlorian Westphal 146048d19d4SFlorian Westphal return gai_strerror(err); 147048d19d4SFlorian Westphal } 148048d19d4SFlorian Westphal 149048d19d4SFlorian Westphal static void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen, 150048d19d4SFlorian Westphal char *host, socklen_t hostlen, 151048d19d4SFlorian Westphal char *serv, socklen_t servlen) 152048d19d4SFlorian Westphal { 153048d19d4SFlorian Westphal int flags = NI_NUMERICHOST | NI_NUMERICSERV; 154048d19d4SFlorian Westphal int err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, 155048d19d4SFlorian Westphal flags); 156048d19d4SFlorian Westphal 157048d19d4SFlorian Westphal if (err) { 158048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 159048d19d4SFlorian Westphal 160048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getnameinfo: %s\n", errstr); 161048d19d4SFlorian Westphal exit(1); 162048d19d4SFlorian Westphal } 163048d19d4SFlorian Westphal } 164048d19d4SFlorian Westphal 165048d19d4SFlorian Westphal static void xgetaddrinfo(const char *node, const char *service, 166048d19d4SFlorian Westphal const struct addrinfo *hints, 167048d19d4SFlorian Westphal struct addrinfo **res) 168048d19d4SFlorian Westphal { 169048d19d4SFlorian Westphal int err = getaddrinfo(node, service, hints, res); 170048d19d4SFlorian Westphal 171048d19d4SFlorian Westphal if (err) { 172048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 173048d19d4SFlorian Westphal 174048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", 175048d19d4SFlorian Westphal node ? node : "", service ? service : "", errstr); 176048d19d4SFlorian Westphal exit(1); 177048d19d4SFlorian Westphal } 178048d19d4SFlorian Westphal } 179048d19d4SFlorian Westphal 1808a4b910dSFlorian Westphal static void set_rcvbuf(int fd, unsigned int size) 1818a4b910dSFlorian Westphal { 1828a4b910dSFlorian Westphal int err; 1838a4b910dSFlorian Westphal 1848a4b910dSFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 1858a4b910dSFlorian Westphal if (err) { 1868a4b910dSFlorian Westphal perror("set SO_RCVBUF"); 1878a4b910dSFlorian Westphal exit(1); 1888a4b910dSFlorian Westphal } 1898a4b910dSFlorian Westphal } 1908a4b910dSFlorian Westphal 191048d19d4SFlorian Westphal static void set_sndbuf(int fd, unsigned int size) 192048d19d4SFlorian Westphal { 193048d19d4SFlorian Westphal int err; 194048d19d4SFlorian Westphal 195048d19d4SFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); 196048d19d4SFlorian Westphal if (err) { 197048d19d4SFlorian Westphal perror("set SO_SNDBUF"); 198048d19d4SFlorian Westphal exit(1); 199048d19d4SFlorian Westphal } 200048d19d4SFlorian Westphal } 201048d19d4SFlorian Westphal 202dc65fe82SFlorian Westphal static void set_mark(int fd, uint32_t mark) 203dc65fe82SFlorian Westphal { 204dc65fe82SFlorian Westphal int err; 205dc65fe82SFlorian Westphal 206dc65fe82SFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); 207dc65fe82SFlorian Westphal if (err) { 208dc65fe82SFlorian Westphal perror("set SO_MARK"); 209dc65fe82SFlorian Westphal exit(1); 210dc65fe82SFlorian Westphal } 211dc65fe82SFlorian Westphal } 212dc65fe82SFlorian Westphal 2135fb62e9cSFlorian Westphal static void set_transparent(int fd, int pf) 2145fb62e9cSFlorian Westphal { 2155fb62e9cSFlorian Westphal int one = 1; 2165fb62e9cSFlorian Westphal 2175fb62e9cSFlorian Westphal switch (pf) { 2185fb62e9cSFlorian Westphal case AF_INET: 2195fb62e9cSFlorian Westphal if (-1 == setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one))) 2205fb62e9cSFlorian Westphal perror("IP_TRANSPARENT"); 2215fb62e9cSFlorian Westphal break; 2225fb62e9cSFlorian Westphal case AF_INET6: 2235fb62e9cSFlorian Westphal if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, &one, sizeof(one))) 2245fb62e9cSFlorian Westphal perror("IPV6_TRANSPARENT"); 2255fb62e9cSFlorian Westphal break; 2265fb62e9cSFlorian Westphal } 2275fb62e9cSFlorian Westphal } 2285fb62e9cSFlorian Westphal 229f730b65cSFlorian Westphal static int do_ulp_so(int sock, const char *name) 230f730b65cSFlorian Westphal { 231f730b65cSFlorian Westphal return setsockopt(sock, IPPROTO_TCP, TCP_ULP, name, strlen(name)); 232f730b65cSFlorian Westphal } 233f730b65cSFlorian Westphal 234f730b65cSFlorian Westphal #define X(m) xerror("%s:%u: %s: failed for proto %d at line %u", __FILE__, __LINE__, (m), proto, line) 235f730b65cSFlorian Westphal static void sock_test_tcpulp(int sock, int proto, unsigned int line) 236f730b65cSFlorian Westphal { 237f730b65cSFlorian Westphal socklen_t buflen = 8; 238f730b65cSFlorian Westphal char buf[8] = ""; 239f730b65cSFlorian Westphal int ret = getsockopt(sock, IPPROTO_TCP, TCP_ULP, buf, &buflen); 240f730b65cSFlorian Westphal 241f730b65cSFlorian Westphal if (ret != 0) 242f730b65cSFlorian Westphal X("getsockopt"); 243f730b65cSFlorian Westphal 244f730b65cSFlorian Westphal if (buflen > 0) { 245f730b65cSFlorian Westphal if (strcmp(buf, "mptcp") != 0) 246f730b65cSFlorian Westphal xerror("unexpected ULP '%s' for proto %d at line %u", buf, proto, line); 247f730b65cSFlorian Westphal ret = do_ulp_so(sock, "tls"); 248f730b65cSFlorian Westphal if (ret == 0) 249f730b65cSFlorian Westphal X("setsockopt"); 250f730b65cSFlorian Westphal } else if (proto == IPPROTO_MPTCP) { 251f730b65cSFlorian Westphal ret = do_ulp_so(sock, "tls"); 252f730b65cSFlorian Westphal if (ret != -1) 253f730b65cSFlorian Westphal X("setsockopt"); 254f730b65cSFlorian Westphal } 255f730b65cSFlorian Westphal 256f730b65cSFlorian Westphal ret = do_ulp_so(sock, "mptcp"); 257f730b65cSFlorian Westphal if (ret != -1) 258f730b65cSFlorian Westphal X("setsockopt"); 259f730b65cSFlorian Westphal 260f730b65cSFlorian Westphal #undef X 261f730b65cSFlorian Westphal } 262f730b65cSFlorian Westphal 263f730b65cSFlorian Westphal #define SOCK_TEST_TCPULP(s, p) sock_test_tcpulp((s), (p), __LINE__) 264f730b65cSFlorian Westphal 265048d19d4SFlorian Westphal static int sock_listen_mptcp(const char * const listenaddr, 266048d19d4SFlorian Westphal const char * const port) 267048d19d4SFlorian Westphal { 268fd37c2ecSMat Martineau int sock = -1; 269048d19d4SFlorian Westphal struct addrinfo hints = { 270048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 271048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 272048d19d4SFlorian Westphal .ai_flags = AI_PASSIVE | AI_NUMERICHOST 273048d19d4SFlorian Westphal }; 274048d19d4SFlorian Westphal 275048d19d4SFlorian Westphal hints.ai_family = pf; 276048d19d4SFlorian Westphal 277048d19d4SFlorian Westphal struct addrinfo *a, *addr; 278048d19d4SFlorian Westphal int one = 1; 279048d19d4SFlorian Westphal 280048d19d4SFlorian Westphal xgetaddrinfo(listenaddr, port, &hints, &addr); 281048d19d4SFlorian Westphal hints.ai_family = pf; 282048d19d4SFlorian Westphal 283048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 284048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, cfg_sock_proto); 285048d19d4SFlorian Westphal if (sock < 0) 286048d19d4SFlorian Westphal continue; 287048d19d4SFlorian Westphal 288f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 289f730b65cSFlorian Westphal 290048d19d4SFlorian Westphal if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, 291048d19d4SFlorian Westphal sizeof(one))) 292048d19d4SFlorian Westphal perror("setsockopt"); 293048d19d4SFlorian Westphal 2945fb62e9cSFlorian Westphal if (cfg_sockopt_types.transparent) 2955fb62e9cSFlorian Westphal set_transparent(sock, pf); 2965fb62e9cSFlorian Westphal 297048d19d4SFlorian Westphal if (bind(sock, a->ai_addr, a->ai_addrlen) == 0) 298048d19d4SFlorian Westphal break; /* success */ 299048d19d4SFlorian Westphal 300048d19d4SFlorian Westphal perror("bind"); 301048d19d4SFlorian Westphal close(sock); 302048d19d4SFlorian Westphal sock = -1; 303048d19d4SFlorian Westphal } 304048d19d4SFlorian Westphal 305048d19d4SFlorian Westphal freeaddrinfo(addr); 306048d19d4SFlorian Westphal 307048d19d4SFlorian Westphal if (sock < 0) { 308048d19d4SFlorian Westphal fprintf(stderr, "Could not create listen socket\n"); 309048d19d4SFlorian Westphal return sock; 310048d19d4SFlorian Westphal } 311048d19d4SFlorian Westphal 312f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 313f730b65cSFlorian Westphal 314048d19d4SFlorian Westphal if (listen(sock, 20)) { 315048d19d4SFlorian Westphal perror("listen"); 316048d19d4SFlorian Westphal close(sock); 317048d19d4SFlorian Westphal return -1; 318048d19d4SFlorian Westphal } 319048d19d4SFlorian Westphal 320f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 321f730b65cSFlorian Westphal 322048d19d4SFlorian Westphal return sock; 323048d19d4SFlorian Westphal } 324048d19d4SFlorian Westphal 325048d19d4SFlorian Westphal static int sock_connect_mptcp(const char * const remoteaddr, 32605be5e27SPaolo Abeni const char * const port, int proto, 32705be5e27SPaolo Abeni struct addrinfo **peer) 328048d19d4SFlorian Westphal { 329048d19d4SFlorian Westphal struct addrinfo hints = { 330048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 331048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 332048d19d4SFlorian Westphal }; 333048d19d4SFlorian Westphal struct addrinfo *a, *addr; 334048d19d4SFlorian Westphal int sock = -1; 335048d19d4SFlorian Westphal 336048d19d4SFlorian Westphal hints.ai_family = pf; 337048d19d4SFlorian Westphal 338048d19d4SFlorian Westphal xgetaddrinfo(remoteaddr, port, &hints, &addr); 339048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 340048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, proto); 341048d19d4SFlorian Westphal if (sock < 0) { 342048d19d4SFlorian Westphal perror("socket"); 343048d19d4SFlorian Westphal continue; 344048d19d4SFlorian Westphal } 345048d19d4SFlorian Westphal 346f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, proto); 347f730b65cSFlorian Westphal 348dc65fe82SFlorian Westphal if (cfg_mark) 349dc65fe82SFlorian Westphal set_mark(sock, cfg_mark); 350dc65fe82SFlorian Westphal 35105be5e27SPaolo Abeni if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) { 35205be5e27SPaolo Abeni *peer = a; 353048d19d4SFlorian Westphal break; /* success */ 35405be5e27SPaolo Abeni } 355048d19d4SFlorian Westphal 356048d19d4SFlorian Westphal perror("connect()"); 357048d19d4SFlorian Westphal close(sock); 358048d19d4SFlorian Westphal sock = -1; 359048d19d4SFlorian Westphal } 360048d19d4SFlorian Westphal 361048d19d4SFlorian Westphal freeaddrinfo(addr); 362f730b65cSFlorian Westphal if (sock != -1) 363f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, proto); 364048d19d4SFlorian Westphal return sock; 365048d19d4SFlorian Westphal } 366048d19d4SFlorian Westphal 367048d19d4SFlorian Westphal static size_t do_rnd_write(const int fd, char *buf, const size_t len) 368048d19d4SFlorian Westphal { 369b08fbf24SPaolo Abeni static bool first = true; 370048d19d4SFlorian Westphal unsigned int do_w; 371048d19d4SFlorian Westphal ssize_t bw; 372048d19d4SFlorian Westphal 373048d19d4SFlorian Westphal do_w = rand() & 0xffff; 374048d19d4SFlorian Westphal if (do_w == 0 || do_w > len) 375048d19d4SFlorian Westphal do_w = len; 376048d19d4SFlorian Westphal 377b08fbf24SPaolo Abeni if (cfg_join && first && do_w > 100) 378b08fbf24SPaolo Abeni do_w = 100; 379b08fbf24SPaolo Abeni 3802e580a63SGeliang Tang if (cfg_remove && do_w > cfg_do_w) 3812e580a63SGeliang Tang do_w = cfg_do_w; 38213153324SGeliang Tang 383048d19d4SFlorian Westphal bw = write(fd, buf, do_w); 384048d19d4SFlorian Westphal if (bw < 0) 385048d19d4SFlorian Westphal perror("write"); 386048d19d4SFlorian Westphal 387b08fbf24SPaolo Abeni /* let the join handshake complete, before going on */ 388b08fbf24SPaolo Abeni if (cfg_join && first) { 389b08fbf24SPaolo Abeni usleep(200000); 390b08fbf24SPaolo Abeni first = false; 391b08fbf24SPaolo Abeni } 392b08fbf24SPaolo Abeni 39313153324SGeliang Tang if (cfg_remove) 39413153324SGeliang Tang usleep(200000); 39513153324SGeliang Tang 396048d19d4SFlorian Westphal return bw; 397048d19d4SFlorian Westphal } 398048d19d4SFlorian Westphal 399048d19d4SFlorian Westphal static size_t do_write(const int fd, char *buf, const size_t len) 400048d19d4SFlorian Westphal { 401048d19d4SFlorian Westphal size_t offset = 0; 402048d19d4SFlorian Westphal 403048d19d4SFlorian Westphal while (offset < len) { 404048d19d4SFlorian Westphal size_t written; 405048d19d4SFlorian Westphal ssize_t bw; 406048d19d4SFlorian Westphal 407048d19d4SFlorian Westphal bw = write(fd, buf + offset, len - offset); 408048d19d4SFlorian Westphal if (bw < 0) { 409048d19d4SFlorian Westphal perror("write"); 410048d19d4SFlorian Westphal return 0; 411048d19d4SFlorian Westphal } 412048d19d4SFlorian Westphal 413048d19d4SFlorian Westphal written = (size_t)bw; 414048d19d4SFlorian Westphal offset += written; 415048d19d4SFlorian Westphal } 416048d19d4SFlorian Westphal 417048d19d4SFlorian Westphal return offset; 418048d19d4SFlorian Westphal } 419048d19d4SFlorian Westphal 4205e6af0a7SFlorian Westphal static void process_cmsg(struct msghdr *msgh) 4215e6af0a7SFlorian Westphal { 4225e6af0a7SFlorian Westphal struct __kernel_timespec ts; 4235cbd886cSFlorian Westphal bool inq_found = false; 4245e6af0a7SFlorian Westphal bool ts_found = false; 4255cbd886cSFlorian Westphal unsigned int inq = 0; 4265e6af0a7SFlorian Westphal struct cmsghdr *cmsg; 4275e6af0a7SFlorian Westphal 4285e6af0a7SFlorian Westphal for (cmsg = CMSG_FIRSTHDR(msgh); cmsg ; cmsg = CMSG_NXTHDR(msgh, cmsg)) { 4295e6af0a7SFlorian Westphal if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPNS_NEW) { 4305e6af0a7SFlorian Westphal memcpy(&ts, CMSG_DATA(cmsg), sizeof(ts)); 4315e6af0a7SFlorian Westphal ts_found = true; 4325e6af0a7SFlorian Westphal continue; 4335e6af0a7SFlorian Westphal } 4345cbd886cSFlorian Westphal if (cmsg->cmsg_level == IPPROTO_TCP && cmsg->cmsg_type == TCP_CM_INQ) { 4355cbd886cSFlorian Westphal memcpy(&inq, CMSG_DATA(cmsg), sizeof(inq)); 4365cbd886cSFlorian Westphal inq_found = true; 4375cbd886cSFlorian Westphal continue; 4385cbd886cSFlorian Westphal } 4395cbd886cSFlorian Westphal 4405e6af0a7SFlorian Westphal } 4415e6af0a7SFlorian Westphal 4425e6af0a7SFlorian Westphal if (cfg_cmsg_types.timestampns) { 4435e6af0a7SFlorian Westphal if (!ts_found) 4445e6af0a7SFlorian Westphal xerror("TIMESTAMPNS not present\n"); 4455e6af0a7SFlorian Westphal } 4465cbd886cSFlorian Westphal 4475cbd886cSFlorian Westphal if (cfg_cmsg_types.tcp_inq) { 4485cbd886cSFlorian Westphal if (!inq_found) 4495cbd886cSFlorian Westphal xerror("TCP_INQ not present\n"); 4505cbd886cSFlorian Westphal 4515cbd886cSFlorian Westphal if (inq > 1024) 4525cbd886cSFlorian Westphal xerror("tcp_inq %u is larger than one kbyte\n", inq); 4535cbd886cSFlorian Westphal tcp_inq.last = inq; 4545cbd886cSFlorian Westphal } 4555e6af0a7SFlorian Westphal } 4565e6af0a7SFlorian Westphal 4575e6af0a7SFlorian Westphal static ssize_t do_recvmsg_cmsg(const int fd, char *buf, const size_t len) 4585e6af0a7SFlorian Westphal { 4595e6af0a7SFlorian Westphal char msg_buf[8192]; 4605e6af0a7SFlorian Westphal struct iovec iov = { 4615e6af0a7SFlorian Westphal .iov_base = buf, 4625e6af0a7SFlorian Westphal .iov_len = len, 4635e6af0a7SFlorian Westphal }; 4645e6af0a7SFlorian Westphal struct msghdr msg = { 4655e6af0a7SFlorian Westphal .msg_iov = &iov, 4665e6af0a7SFlorian Westphal .msg_iovlen = 1, 4675e6af0a7SFlorian Westphal .msg_control = msg_buf, 4685e6af0a7SFlorian Westphal .msg_controllen = sizeof(msg_buf), 4695e6af0a7SFlorian Westphal }; 4705e6af0a7SFlorian Westphal int flags = 0; 4715cbd886cSFlorian Westphal unsigned int last_hint = tcp_inq.last; 4725e6af0a7SFlorian Westphal int ret = recvmsg(fd, &msg, flags); 4735e6af0a7SFlorian Westphal 4745cbd886cSFlorian Westphal if (ret <= 0) { 4755cbd886cSFlorian Westphal if (ret == 0 && tcp_inq.expect_eof) 4765e6af0a7SFlorian Westphal return ret; 4775e6af0a7SFlorian Westphal 4785cbd886cSFlorian Westphal if (ret == 0 && cfg_cmsg_types.tcp_inq) 4795cbd886cSFlorian Westphal if (last_hint != 1 && last_hint != 0) 4805cbd886cSFlorian Westphal xerror("EOF but last tcp_inq hint was %u\n", last_hint); 4815cbd886cSFlorian Westphal 4825cbd886cSFlorian Westphal return ret; 4835cbd886cSFlorian Westphal } 4845cbd886cSFlorian Westphal 4855cbd886cSFlorian Westphal if (tcp_inq.expect_eof) 4865cbd886cSFlorian Westphal xerror("expected EOF, last_hint %u, now %u\n", 4875cbd886cSFlorian Westphal last_hint, tcp_inq.last); 4885cbd886cSFlorian Westphal 4895e6af0a7SFlorian Westphal if (msg.msg_controllen && !cfg_cmsg_types.cmsg_enabled) 4905e6af0a7SFlorian Westphal xerror("got %lu bytes of cmsg data, expected 0\n", 4915e6af0a7SFlorian Westphal (unsigned long)msg.msg_controllen); 4925e6af0a7SFlorian Westphal 4935e6af0a7SFlorian Westphal if (msg.msg_controllen == 0 && cfg_cmsg_types.cmsg_enabled) 4945e6af0a7SFlorian Westphal xerror("%s\n", "got no cmsg data"); 4955e6af0a7SFlorian Westphal 4965e6af0a7SFlorian Westphal if (msg.msg_controllen) 4975e6af0a7SFlorian Westphal process_cmsg(&msg); 4985e6af0a7SFlorian Westphal 4995cbd886cSFlorian Westphal if (cfg_cmsg_types.tcp_inq) { 5005cbd886cSFlorian Westphal if ((size_t)ret < len && last_hint > (unsigned int)ret) { 5015cbd886cSFlorian Westphal if (ret + 1 != (int)last_hint) { 5025cbd886cSFlorian Westphal int next = read(fd, msg_buf, sizeof(msg_buf)); 5035cbd886cSFlorian Westphal 5045cbd886cSFlorian Westphal xerror("read %u of %u, last_hint was %u tcp_inq hint now %u next_read returned %d/%m\n", 5055cbd886cSFlorian Westphal ret, (unsigned int)len, last_hint, tcp_inq.last, next); 5065cbd886cSFlorian Westphal } else { 5075cbd886cSFlorian Westphal tcp_inq.expect_eof = true; 5085cbd886cSFlorian Westphal } 5095cbd886cSFlorian Westphal } 5105cbd886cSFlorian Westphal } 5115cbd886cSFlorian Westphal 5125e6af0a7SFlorian Westphal return ret; 5135e6af0a7SFlorian Westphal } 5145e6af0a7SFlorian Westphal 515048d19d4SFlorian Westphal static ssize_t do_rnd_read(const int fd, char *buf, const size_t len) 516048d19d4SFlorian Westphal { 517df8aee6dSYonglong Li int ret = 0; 518df8aee6dSYonglong Li char tmp[16384]; 519048d19d4SFlorian Westphal size_t cap = rand(); 520048d19d4SFlorian Westphal 521048d19d4SFlorian Westphal cap &= 0xffff; 522048d19d4SFlorian Westphal 523048d19d4SFlorian Westphal if (cap == 0) 524048d19d4SFlorian Westphal cap = 1; 525048d19d4SFlorian Westphal else if (cap > len) 526048d19d4SFlorian Westphal cap = len; 527048d19d4SFlorian Westphal 528df8aee6dSYonglong Li if (cfg_peek == CFG_WITH_PEEK) { 529df8aee6dSYonglong Li ret = recv(fd, buf, cap, MSG_PEEK); 530df8aee6dSYonglong Li ret = (ret < 0) ? ret : read(fd, tmp, ret); 531df8aee6dSYonglong Li } else if (cfg_peek == CFG_AFTER_PEEK) { 532df8aee6dSYonglong Li ret = recv(fd, buf, cap, MSG_PEEK); 533df8aee6dSYonglong Li ret = (ret < 0) ? ret : read(fd, buf, cap); 5345e6af0a7SFlorian Westphal } else if (cfg_cmsg_types.cmsg_enabled) { 5355e6af0a7SFlorian Westphal ret = do_recvmsg_cmsg(fd, buf, cap); 536df8aee6dSYonglong Li } else { 537df8aee6dSYonglong Li ret = read(fd, buf, cap); 538df8aee6dSYonglong Li } 539df8aee6dSYonglong Li 540df8aee6dSYonglong Li return ret; 541048d19d4SFlorian Westphal } 542048d19d4SFlorian Westphal 54305be5e27SPaolo Abeni static void set_nonblock(int fd, bool nonblock) 544048d19d4SFlorian Westphal { 545048d19d4SFlorian Westphal int flags = fcntl(fd, F_GETFL); 546048d19d4SFlorian Westphal 547048d19d4SFlorian Westphal if (flags == -1) 548048d19d4SFlorian Westphal return; 549048d19d4SFlorian Westphal 55005be5e27SPaolo Abeni if (nonblock) 551048d19d4SFlorian Westphal fcntl(fd, F_SETFL, flags | O_NONBLOCK); 55205be5e27SPaolo Abeni else 55305be5e27SPaolo Abeni fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 554048d19d4SFlorian Westphal } 555048d19d4SFlorian Westphal 556*df9e03aeSFlorian Westphal static void shut_wr(int fd) 557*df9e03aeSFlorian Westphal { 558*df9e03aeSFlorian Westphal /* Close our write side, ev. give some time 559*df9e03aeSFlorian Westphal * for address notification and/or checking 560*df9e03aeSFlorian Westphal * the current status 561*df9e03aeSFlorian Westphal */ 562*df9e03aeSFlorian Westphal if (cfg_wait) 563*df9e03aeSFlorian Westphal usleep(cfg_wait); 564*df9e03aeSFlorian Westphal 565*df9e03aeSFlorian Westphal shutdown(fd, SHUT_WR); 566*df9e03aeSFlorian Westphal } 567*df9e03aeSFlorian Westphal 568b6ab64b0SPaolo Abeni static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after_out) 569048d19d4SFlorian Westphal { 570048d19d4SFlorian Westphal struct pollfd fds = { 571048d19d4SFlorian Westphal .fd = peerfd, 572048d19d4SFlorian Westphal .events = POLLIN | POLLOUT, 573048d19d4SFlorian Westphal }; 574048d19d4SFlorian Westphal unsigned int woff = 0, wlen = 0; 575048d19d4SFlorian Westphal char wbuf[8192]; 576048d19d4SFlorian Westphal 57705be5e27SPaolo Abeni set_nonblock(peerfd, true); 578048d19d4SFlorian Westphal 579048d19d4SFlorian Westphal for (;;) { 580048d19d4SFlorian Westphal char rbuf[8192]; 581048d19d4SFlorian Westphal ssize_t len; 582048d19d4SFlorian Westphal 583048d19d4SFlorian Westphal if (fds.events == 0) 584048d19d4SFlorian Westphal break; 585048d19d4SFlorian Westphal 586048d19d4SFlorian Westphal switch (poll(&fds, 1, poll_timeout)) { 587048d19d4SFlorian Westphal case -1: 588048d19d4SFlorian Westphal if (errno == EINTR) 589048d19d4SFlorian Westphal continue; 590048d19d4SFlorian Westphal perror("poll"); 591048d19d4SFlorian Westphal return 1; 592048d19d4SFlorian Westphal case 0: 593048d19d4SFlorian Westphal fprintf(stderr, "%s: poll timed out (events: " 594048d19d4SFlorian Westphal "POLLIN %u, POLLOUT %u)\n", __func__, 595048d19d4SFlorian Westphal fds.events & POLLIN, fds.events & POLLOUT); 596048d19d4SFlorian Westphal return 2; 597048d19d4SFlorian Westphal } 598048d19d4SFlorian Westphal 599048d19d4SFlorian Westphal if (fds.revents & POLLIN) { 600048d19d4SFlorian Westphal len = do_rnd_read(peerfd, rbuf, sizeof(rbuf)); 601048d19d4SFlorian Westphal if (len == 0) { 602048d19d4SFlorian Westphal /* no more data to receive: 603048d19d4SFlorian Westphal * peer has closed its write side 604048d19d4SFlorian Westphal */ 605048d19d4SFlorian Westphal fds.events &= ~POLLIN; 606048d19d4SFlorian Westphal 607b6ab64b0SPaolo Abeni if ((fds.events & POLLOUT) == 0) { 608b6ab64b0SPaolo Abeni *in_closed_after_out = true; 609048d19d4SFlorian Westphal /* and nothing more to send */ 610048d19d4SFlorian Westphal break; 611b6ab64b0SPaolo Abeni } 612048d19d4SFlorian Westphal 613048d19d4SFlorian Westphal /* Else, still have data to transmit */ 614048d19d4SFlorian Westphal } else if (len < 0) { 615048d19d4SFlorian Westphal perror("read"); 616048d19d4SFlorian Westphal return 3; 617048d19d4SFlorian Westphal } 618048d19d4SFlorian Westphal 619048d19d4SFlorian Westphal do_write(outfd, rbuf, len); 620048d19d4SFlorian Westphal } 621048d19d4SFlorian Westphal 622048d19d4SFlorian Westphal if (fds.revents & POLLOUT) { 623048d19d4SFlorian Westphal if (wlen == 0) { 624048d19d4SFlorian Westphal woff = 0; 625048d19d4SFlorian Westphal wlen = read(infd, wbuf, sizeof(wbuf)); 626048d19d4SFlorian Westphal } 627048d19d4SFlorian Westphal 628048d19d4SFlorian Westphal if (wlen > 0) { 629048d19d4SFlorian Westphal ssize_t bw; 630048d19d4SFlorian Westphal 631048d19d4SFlorian Westphal bw = do_rnd_write(peerfd, wbuf + woff, wlen); 632048d19d4SFlorian Westphal if (bw < 0) 633048d19d4SFlorian Westphal return 111; 634048d19d4SFlorian Westphal 635048d19d4SFlorian Westphal woff += bw; 636048d19d4SFlorian Westphal wlen -= bw; 637048d19d4SFlorian Westphal } else if (wlen == 0) { 638048d19d4SFlorian Westphal /* We have no more data to send. */ 639048d19d4SFlorian Westphal fds.events &= ~POLLOUT; 640048d19d4SFlorian Westphal 641048d19d4SFlorian Westphal if ((fds.events & POLLIN) == 0) 642048d19d4SFlorian Westphal /* ... and peer also closed already */ 643048d19d4SFlorian Westphal break; 644048d19d4SFlorian Westphal 645*df9e03aeSFlorian Westphal shut_wr(peerfd); 646048d19d4SFlorian Westphal } else { 647048d19d4SFlorian Westphal if (errno == EINTR) 648048d19d4SFlorian Westphal continue; 649048d19d4SFlorian Westphal perror("read"); 650048d19d4SFlorian Westphal return 4; 651048d19d4SFlorian Westphal } 652048d19d4SFlorian Westphal } 653048d19d4SFlorian Westphal 654048d19d4SFlorian Westphal if (fds.revents & (POLLERR | POLLNVAL)) { 655048d19d4SFlorian Westphal fprintf(stderr, "Unexpected revents: " 656048d19d4SFlorian Westphal "POLLERR/POLLNVAL(%x)\n", fds.revents); 657048d19d4SFlorian Westphal return 5; 658048d19d4SFlorian Westphal } 659048d19d4SFlorian Westphal } 660048d19d4SFlorian Westphal 661b08fbf24SPaolo Abeni /* leave some time for late join/announce */ 662b6ab64b0SPaolo Abeni if (cfg_remove) 663df62f2ecSPaolo Abeni usleep(cfg_wait); 664b08fbf24SPaolo Abeni 665048d19d4SFlorian Westphal return 0; 666048d19d4SFlorian Westphal } 667048d19d4SFlorian Westphal 668048d19d4SFlorian Westphal static int do_recvfile(int infd, int outfd) 669048d19d4SFlorian Westphal { 670048d19d4SFlorian Westphal ssize_t r; 671048d19d4SFlorian Westphal 672048d19d4SFlorian Westphal do { 673048d19d4SFlorian Westphal char buf[16384]; 674048d19d4SFlorian Westphal 675048d19d4SFlorian Westphal r = do_rnd_read(infd, buf, sizeof(buf)); 676048d19d4SFlorian Westphal if (r > 0) { 677048d19d4SFlorian Westphal if (write(outfd, buf, r) != r) 678048d19d4SFlorian Westphal break; 679048d19d4SFlorian Westphal } else if (r < 0) { 680048d19d4SFlorian Westphal perror("read"); 681048d19d4SFlorian Westphal } 682048d19d4SFlorian Westphal } while (r > 0); 683048d19d4SFlorian Westphal 684048d19d4SFlorian Westphal return (int)r; 685048d19d4SFlorian Westphal } 686048d19d4SFlorian Westphal 687048d19d4SFlorian Westphal static int do_mmap(int infd, int outfd, unsigned int size) 688048d19d4SFlorian Westphal { 689048d19d4SFlorian Westphal char *inbuf = mmap(NULL, size, PROT_READ, MAP_SHARED, infd, 0); 690048d19d4SFlorian Westphal ssize_t ret = 0, off = 0; 691048d19d4SFlorian Westphal size_t rem; 692048d19d4SFlorian Westphal 693048d19d4SFlorian Westphal if (inbuf == MAP_FAILED) { 694048d19d4SFlorian Westphal perror("mmap"); 695048d19d4SFlorian Westphal return 1; 696048d19d4SFlorian Westphal } 697048d19d4SFlorian Westphal 698048d19d4SFlorian Westphal rem = size; 699048d19d4SFlorian Westphal 700048d19d4SFlorian Westphal while (rem > 0) { 701048d19d4SFlorian Westphal ret = write(outfd, inbuf + off, rem); 702048d19d4SFlorian Westphal 703048d19d4SFlorian Westphal if (ret < 0) { 704048d19d4SFlorian Westphal perror("write"); 705048d19d4SFlorian Westphal break; 706048d19d4SFlorian Westphal } 707048d19d4SFlorian Westphal 708048d19d4SFlorian Westphal off += ret; 709048d19d4SFlorian Westphal rem -= ret; 710048d19d4SFlorian Westphal } 711048d19d4SFlorian Westphal 712048d19d4SFlorian Westphal munmap(inbuf, size); 713048d19d4SFlorian Westphal return rem; 714048d19d4SFlorian Westphal } 715048d19d4SFlorian Westphal 716048d19d4SFlorian Westphal static int get_infd_size(int fd) 717048d19d4SFlorian Westphal { 718048d19d4SFlorian Westphal struct stat sb; 719048d19d4SFlorian Westphal ssize_t count; 720048d19d4SFlorian Westphal int err; 721048d19d4SFlorian Westphal 722048d19d4SFlorian Westphal err = fstat(fd, &sb); 723048d19d4SFlorian Westphal if (err < 0) { 724048d19d4SFlorian Westphal perror("fstat"); 725048d19d4SFlorian Westphal return -1; 726048d19d4SFlorian Westphal } 727048d19d4SFlorian Westphal 728048d19d4SFlorian Westphal if ((sb.st_mode & S_IFMT) != S_IFREG) { 729048d19d4SFlorian Westphal fprintf(stderr, "%s: stdin is not a regular file\n", __func__); 730048d19d4SFlorian Westphal return -2; 731048d19d4SFlorian Westphal } 732048d19d4SFlorian Westphal 733048d19d4SFlorian Westphal count = sb.st_size; 734048d19d4SFlorian Westphal if (count > INT_MAX) { 735048d19d4SFlorian Westphal fprintf(stderr, "File too large: %zu\n", count); 736048d19d4SFlorian Westphal return -3; 737048d19d4SFlorian Westphal } 738048d19d4SFlorian Westphal 739048d19d4SFlorian Westphal return (int)count; 740048d19d4SFlorian Westphal } 741048d19d4SFlorian Westphal 742048d19d4SFlorian Westphal static int do_sendfile(int infd, int outfd, unsigned int count) 743048d19d4SFlorian Westphal { 744048d19d4SFlorian Westphal while (count > 0) { 745048d19d4SFlorian Westphal ssize_t r; 746048d19d4SFlorian Westphal 747048d19d4SFlorian Westphal r = sendfile(outfd, infd, NULL, count); 748048d19d4SFlorian Westphal if (r < 0) { 749048d19d4SFlorian Westphal perror("sendfile"); 750048d19d4SFlorian Westphal return 3; 751048d19d4SFlorian Westphal } 752048d19d4SFlorian Westphal 753048d19d4SFlorian Westphal count -= r; 754048d19d4SFlorian Westphal } 755048d19d4SFlorian Westphal 756048d19d4SFlorian Westphal return 0; 757048d19d4SFlorian Westphal } 758048d19d4SFlorian Westphal 759048d19d4SFlorian Westphal static int copyfd_io_mmap(int infd, int peerfd, int outfd, 760b6ab64b0SPaolo Abeni unsigned int size, bool *in_closed_after_out) 761048d19d4SFlorian Westphal { 762048d19d4SFlorian Westphal int err; 763048d19d4SFlorian Westphal 764048d19d4SFlorian Westphal if (listen_mode) { 765048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 766048d19d4SFlorian Westphal if (err) 767048d19d4SFlorian Westphal return err; 768048d19d4SFlorian Westphal 769048d19d4SFlorian Westphal err = do_mmap(infd, peerfd, size); 770048d19d4SFlorian Westphal } else { 771048d19d4SFlorian Westphal err = do_mmap(infd, peerfd, size); 772048d19d4SFlorian Westphal if (err) 773048d19d4SFlorian Westphal return err; 774048d19d4SFlorian Westphal 775*df9e03aeSFlorian Westphal shut_wr(peerfd); 776048d19d4SFlorian Westphal 777048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 778b6ab64b0SPaolo Abeni *in_closed_after_out = true; 779048d19d4SFlorian Westphal } 780048d19d4SFlorian Westphal 781048d19d4SFlorian Westphal return err; 782048d19d4SFlorian Westphal } 783048d19d4SFlorian Westphal 784048d19d4SFlorian Westphal static int copyfd_io_sendfile(int infd, int peerfd, int outfd, 785b6ab64b0SPaolo Abeni unsigned int size, bool *in_closed_after_out) 786048d19d4SFlorian Westphal { 787048d19d4SFlorian Westphal int err; 788048d19d4SFlorian Westphal 789048d19d4SFlorian Westphal if (listen_mode) { 790048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 791048d19d4SFlorian Westphal if (err) 792048d19d4SFlorian Westphal return err; 793048d19d4SFlorian Westphal 794048d19d4SFlorian Westphal err = do_sendfile(infd, peerfd, size); 795048d19d4SFlorian Westphal } else { 796048d19d4SFlorian Westphal err = do_sendfile(infd, peerfd, size); 797048d19d4SFlorian Westphal if (err) 798048d19d4SFlorian Westphal return err; 799*df9e03aeSFlorian Westphal 800*df9e03aeSFlorian Westphal shut_wr(peerfd); 801*df9e03aeSFlorian Westphal 802048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 803b6ab64b0SPaolo Abeni *in_closed_after_out = true; 804048d19d4SFlorian Westphal } 805048d19d4SFlorian Westphal 806048d19d4SFlorian Westphal return err; 807048d19d4SFlorian Westphal } 808048d19d4SFlorian Westphal 80905be5e27SPaolo Abeni static int copyfd_io(int infd, int peerfd, int outfd, bool close_peerfd) 810048d19d4SFlorian Westphal { 811b6ab64b0SPaolo Abeni bool in_closed_after_out = false; 812b6ab64b0SPaolo Abeni struct timespec start, end; 813048d19d4SFlorian Westphal int file_size; 814b6ab64b0SPaolo Abeni int ret; 815b6ab64b0SPaolo Abeni 816b6ab64b0SPaolo Abeni if (cfg_time && (clock_gettime(CLOCK_MONOTONIC, &start) < 0)) 817b6ab64b0SPaolo Abeni xerror("can not fetch start time %d", errno); 818048d19d4SFlorian Westphal 819048d19d4SFlorian Westphal switch (cfg_mode) { 820048d19d4SFlorian Westphal case CFG_MODE_POLL: 821b6ab64b0SPaolo Abeni ret = copyfd_io_poll(infd, peerfd, outfd, &in_closed_after_out); 822b6ab64b0SPaolo Abeni break; 823b6ab64b0SPaolo Abeni 824048d19d4SFlorian Westphal case CFG_MODE_MMAP: 825048d19d4SFlorian Westphal file_size = get_infd_size(infd); 826048d19d4SFlorian Westphal if (file_size < 0) 827048d19d4SFlorian Westphal return file_size; 828b6ab64b0SPaolo Abeni ret = copyfd_io_mmap(infd, peerfd, outfd, file_size, &in_closed_after_out); 829b6ab64b0SPaolo Abeni break; 830b6ab64b0SPaolo Abeni 831048d19d4SFlorian Westphal case CFG_MODE_SENDFILE: 832048d19d4SFlorian Westphal file_size = get_infd_size(infd); 833048d19d4SFlorian Westphal if (file_size < 0) 834048d19d4SFlorian Westphal return file_size; 835b6ab64b0SPaolo Abeni ret = copyfd_io_sendfile(infd, peerfd, outfd, file_size, &in_closed_after_out); 836b6ab64b0SPaolo Abeni break; 837048d19d4SFlorian Westphal 838b6ab64b0SPaolo Abeni default: 839048d19d4SFlorian Westphal fprintf(stderr, "Invalid mode %d\n", cfg_mode); 840048d19d4SFlorian Westphal 841048d19d4SFlorian Westphal die_usage(); 842048d19d4SFlorian Westphal return 1; 843048d19d4SFlorian Westphal } 844048d19d4SFlorian Westphal 845b6ab64b0SPaolo Abeni if (ret) 846b6ab64b0SPaolo Abeni return ret; 847b6ab64b0SPaolo Abeni 84805be5e27SPaolo Abeni if (close_peerfd) 84905be5e27SPaolo Abeni close(peerfd); 85005be5e27SPaolo Abeni 851b6ab64b0SPaolo Abeni if (cfg_time) { 852b6ab64b0SPaolo Abeni unsigned int delta_ms; 853b6ab64b0SPaolo Abeni 854b6ab64b0SPaolo Abeni if (clock_gettime(CLOCK_MONOTONIC, &end) < 0) 855b6ab64b0SPaolo Abeni xerror("can not fetch end time %d", errno); 856b6ab64b0SPaolo Abeni delta_ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000; 857b6ab64b0SPaolo Abeni if (delta_ms > cfg_time) { 858b6ab64b0SPaolo Abeni xerror("transfer slower than expected! runtime %d ms, expected %d ms", 859b6ab64b0SPaolo Abeni delta_ms, cfg_time); 860b6ab64b0SPaolo Abeni } 861b6ab64b0SPaolo Abeni 862b6ab64b0SPaolo Abeni /* show the runtime only if this end shutdown(wr) before receiving the EOF, 863b6ab64b0SPaolo Abeni * (that is, if this end got the longer runtime) 864b6ab64b0SPaolo Abeni */ 865b6ab64b0SPaolo Abeni if (in_closed_after_out) 866b6ab64b0SPaolo Abeni fprintf(stderr, "%d", delta_ms); 867b6ab64b0SPaolo Abeni } 868b6ab64b0SPaolo Abeni 869b6ab64b0SPaolo Abeni return 0; 870b6ab64b0SPaolo Abeni } 871b6ab64b0SPaolo Abeni 872048d19d4SFlorian Westphal static void check_sockaddr(int pf, struct sockaddr_storage *ss, 873048d19d4SFlorian Westphal socklen_t salen) 874048d19d4SFlorian Westphal { 875048d19d4SFlorian Westphal struct sockaddr_in6 *sin6; 876048d19d4SFlorian Westphal struct sockaddr_in *sin; 877048d19d4SFlorian Westphal socklen_t wanted_size = 0; 878048d19d4SFlorian Westphal 879048d19d4SFlorian Westphal switch (pf) { 880048d19d4SFlorian Westphal case AF_INET: 881048d19d4SFlorian Westphal wanted_size = sizeof(*sin); 882048d19d4SFlorian Westphal sin = (void *)ss; 883048d19d4SFlorian Westphal if (!sin->sin_port) 884048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ip connection from port 0"); 885048d19d4SFlorian Westphal break; 886048d19d4SFlorian Westphal case AF_INET6: 887048d19d4SFlorian Westphal wanted_size = sizeof(*sin6); 888048d19d4SFlorian Westphal sin6 = (void *)ss; 889048d19d4SFlorian Westphal if (!sin6->sin6_port) 890048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ipv6 connection from port 0"); 891048d19d4SFlorian Westphal break; 892048d19d4SFlorian Westphal default: 893048d19d4SFlorian Westphal fprintf(stderr, "accept: Unknown pf %d, salen %u\n", pf, salen); 894048d19d4SFlorian Westphal return; 895048d19d4SFlorian Westphal } 896048d19d4SFlorian Westphal 897048d19d4SFlorian Westphal if (salen != wanted_size) 898048d19d4SFlorian Westphal fprintf(stderr, "accept: size mismatch, got %d expected %d\n", 899048d19d4SFlorian Westphal (int)salen, wanted_size); 900048d19d4SFlorian Westphal 901048d19d4SFlorian Westphal if (ss->ss_family != pf) 902048d19d4SFlorian Westphal fprintf(stderr, "accept: pf mismatch, expect %d, ss_family is %d\n", 903048d19d4SFlorian Westphal (int)ss->ss_family, pf); 904048d19d4SFlorian Westphal } 905048d19d4SFlorian Westphal 906048d19d4SFlorian Westphal static void check_getpeername(int fd, struct sockaddr_storage *ss, socklen_t salen) 907048d19d4SFlorian Westphal { 908048d19d4SFlorian Westphal struct sockaddr_storage peerss; 909048d19d4SFlorian Westphal socklen_t peersalen = sizeof(peerss); 910048d19d4SFlorian Westphal 911048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&peerss, &peersalen) < 0) { 912048d19d4SFlorian Westphal perror("getpeername"); 913048d19d4SFlorian Westphal return; 914048d19d4SFlorian Westphal } 915048d19d4SFlorian Westphal 916048d19d4SFlorian Westphal if (peersalen != salen) { 917048d19d4SFlorian Westphal fprintf(stderr, "%s: %d vs %d\n", __func__, peersalen, salen); 918048d19d4SFlorian Westphal return; 919048d19d4SFlorian Westphal } 920048d19d4SFlorian Westphal 921048d19d4SFlorian Westphal if (memcmp(ss, &peerss, peersalen)) { 922048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 923048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 924048d19d4SFlorian Westphal char c[INET6_ADDRSTRLEN]; 925048d19d4SFlorian Westphal char d[INET6_ADDRSTRLEN]; 926048d19d4SFlorian Westphal 927048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)ss, salen, 928048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 929048d19d4SFlorian Westphal 930048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&peerss, peersalen, 931048d19d4SFlorian Westphal c, sizeof(c), d, sizeof(d)); 932048d19d4SFlorian Westphal 933048d19d4SFlorian Westphal fprintf(stderr, "%s: memcmp failure: accept %s vs peername %s, %s vs %s salen %d vs %d\n", 934048d19d4SFlorian Westphal __func__, a, c, b, d, peersalen, salen); 935048d19d4SFlorian Westphal } 936048d19d4SFlorian Westphal } 937048d19d4SFlorian Westphal 938048d19d4SFlorian Westphal static void check_getpeername_connect(int fd) 939048d19d4SFlorian Westphal { 940048d19d4SFlorian Westphal struct sockaddr_storage ss; 941048d19d4SFlorian Westphal socklen_t salen = sizeof(ss); 942048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 943048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 944048d19d4SFlorian Westphal 945048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&ss, &salen) < 0) { 946048d19d4SFlorian Westphal perror("getpeername"); 947048d19d4SFlorian Westphal return; 948048d19d4SFlorian Westphal } 949048d19d4SFlorian Westphal 950048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&ss, salen, 951048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 952048d19d4SFlorian Westphal 953048d19d4SFlorian Westphal if (strcmp(cfg_host, a) || strcmp(cfg_port, b)) 954048d19d4SFlorian Westphal fprintf(stderr, "%s: %s vs %s, %s vs %s\n", __func__, 955048d19d4SFlorian Westphal cfg_host, a, cfg_port, b); 956048d19d4SFlorian Westphal } 957048d19d4SFlorian Westphal 958b0519de8SFlorian Westphal static void maybe_close(int fd) 959b0519de8SFlorian Westphal { 960b0519de8SFlorian Westphal unsigned int r = rand(); 961b0519de8SFlorian Westphal 96205be5e27SPaolo Abeni if (!(cfg_join || cfg_remove || cfg_repeat > 1) && (r & 1)) 963b0519de8SFlorian Westphal close(fd); 964b0519de8SFlorian Westphal } 965b0519de8SFlorian Westphal 966048d19d4SFlorian Westphal int main_loop_s(int listensock) 967048d19d4SFlorian Westphal { 968048d19d4SFlorian Westphal struct sockaddr_storage ss; 969048d19d4SFlorian Westphal struct pollfd polls; 970048d19d4SFlorian Westphal socklen_t salen; 971048d19d4SFlorian Westphal int remotesock; 97205be5e27SPaolo Abeni int fd = 0; 973048d19d4SFlorian Westphal 97405be5e27SPaolo Abeni again: 975048d19d4SFlorian Westphal polls.fd = listensock; 976048d19d4SFlorian Westphal polls.events = POLLIN; 977048d19d4SFlorian Westphal 978048d19d4SFlorian Westphal switch (poll(&polls, 1, poll_timeout)) { 979048d19d4SFlorian Westphal case -1: 980048d19d4SFlorian Westphal perror("poll"); 981048d19d4SFlorian Westphal return 1; 982048d19d4SFlorian Westphal case 0: 983048d19d4SFlorian Westphal fprintf(stderr, "%s: timed out\n", __func__); 984048d19d4SFlorian Westphal close(listensock); 985048d19d4SFlorian Westphal return 2; 986048d19d4SFlorian Westphal } 987048d19d4SFlorian Westphal 988048d19d4SFlorian Westphal salen = sizeof(ss); 989048d19d4SFlorian Westphal remotesock = accept(listensock, (struct sockaddr *)&ss, &salen); 990048d19d4SFlorian Westphal if (remotesock >= 0) { 991b0519de8SFlorian Westphal maybe_close(listensock); 992048d19d4SFlorian Westphal check_sockaddr(pf, &ss, salen); 993048d19d4SFlorian Westphal check_getpeername(remotesock, &ss, salen); 994048d19d4SFlorian Westphal 99505be5e27SPaolo Abeni if (cfg_input) { 99605be5e27SPaolo Abeni fd = open(cfg_input, O_RDONLY); 99705be5e27SPaolo Abeni if (fd < 0) 99805be5e27SPaolo Abeni xerror("can't open %s: %d", cfg_input, errno); 999048d19d4SFlorian Westphal } 1000048d19d4SFlorian Westphal 100105be5e27SPaolo Abeni SOCK_TEST_TCPULP(remotesock, 0); 1002048d19d4SFlorian Westphal 100305be5e27SPaolo Abeni copyfd_io(fd, remotesock, 1, true); 100405be5e27SPaolo Abeni } else { 100505be5e27SPaolo Abeni perror("accept"); 1006048d19d4SFlorian Westphal return 1; 1007048d19d4SFlorian Westphal } 1008048d19d4SFlorian Westphal 100905be5e27SPaolo Abeni if (--cfg_repeat > 0) { 101005be5e27SPaolo Abeni if (cfg_input) 101105be5e27SPaolo Abeni close(fd); 101205be5e27SPaolo Abeni goto again; 101305be5e27SPaolo Abeni } 101405be5e27SPaolo Abeni 101505be5e27SPaolo Abeni return 0; 101605be5e27SPaolo Abeni } 101705be5e27SPaolo Abeni 1018048d19d4SFlorian Westphal static void init_rng(void) 1019048d19d4SFlorian Westphal { 1020048d19d4SFlorian Westphal int fd = open("/dev/urandom", O_RDONLY); 1021048d19d4SFlorian Westphal unsigned int foo; 1022048d19d4SFlorian Westphal 1023048d19d4SFlorian Westphal if (fd > 0) { 1024048d19d4SFlorian Westphal int ret = read(fd, &foo, sizeof(foo)); 1025048d19d4SFlorian Westphal 1026048d19d4SFlorian Westphal if (ret < 0) 1027048d19d4SFlorian Westphal srand(fd + foo); 1028048d19d4SFlorian Westphal close(fd); 1029048d19d4SFlorian Westphal } 1030048d19d4SFlorian Westphal 1031048d19d4SFlorian Westphal srand(foo); 1032048d19d4SFlorian Westphal } 1033048d19d4SFlorian Westphal 10345e6af0a7SFlorian Westphal static void xsetsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) 10355e6af0a7SFlorian Westphal { 10365e6af0a7SFlorian Westphal int err; 10375e6af0a7SFlorian Westphal 10385e6af0a7SFlorian Westphal err = setsockopt(fd, level, optname, optval, optlen); 10395e6af0a7SFlorian Westphal if (err) { 10405e6af0a7SFlorian Westphal perror("setsockopt"); 10415e6af0a7SFlorian Westphal exit(1); 10425e6af0a7SFlorian Westphal } 10435e6af0a7SFlorian Westphal } 10445e6af0a7SFlorian Westphal 10455e6af0a7SFlorian Westphal static void apply_cmsg_types(int fd, const struct cfg_cmsg_types *cmsg) 10465e6af0a7SFlorian Westphal { 10475e6af0a7SFlorian Westphal static const unsigned int on = 1; 10485e6af0a7SFlorian Westphal 10495e6af0a7SFlorian Westphal if (cmsg->timestampns) 10505e6af0a7SFlorian Westphal xsetsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW, &on, sizeof(on)); 10515cbd886cSFlorian Westphal if (cmsg->tcp_inq) 10525cbd886cSFlorian Westphal xsetsockopt(fd, IPPROTO_TCP, TCP_INQ, &on, sizeof(on)); 10535e6af0a7SFlorian Westphal } 10545e6af0a7SFlorian Westphal 10555e6af0a7SFlorian Westphal static void parse_cmsg_types(const char *type) 10565e6af0a7SFlorian Westphal { 10575e6af0a7SFlorian Westphal char *next = strchr(type, ','); 10585e6af0a7SFlorian Westphal unsigned int len = 0; 10595e6af0a7SFlorian Westphal 10605e6af0a7SFlorian Westphal cfg_cmsg_types.cmsg_enabled = 1; 10615e6af0a7SFlorian Westphal 10625e6af0a7SFlorian Westphal if (next) { 10635e6af0a7SFlorian Westphal parse_cmsg_types(next + 1); 10645e6af0a7SFlorian Westphal len = next - type; 10655e6af0a7SFlorian Westphal } else { 10665e6af0a7SFlorian Westphal len = strlen(type); 10675e6af0a7SFlorian Westphal } 10685e6af0a7SFlorian Westphal 10695e6af0a7SFlorian Westphal if (strncmp(type, "TIMESTAMPNS", len) == 0) { 10705e6af0a7SFlorian Westphal cfg_cmsg_types.timestampns = 1; 10715e6af0a7SFlorian Westphal return; 10725e6af0a7SFlorian Westphal } 10735e6af0a7SFlorian Westphal 10745cbd886cSFlorian Westphal if (strncmp(type, "TCPINQ", len) == 0) { 10755cbd886cSFlorian Westphal cfg_cmsg_types.tcp_inq = 1; 10765cbd886cSFlorian Westphal return; 10775cbd886cSFlorian Westphal } 10785cbd886cSFlorian Westphal 10795e6af0a7SFlorian Westphal fprintf(stderr, "Unrecognized cmsg option %s\n", type); 10805e6af0a7SFlorian Westphal exit(1); 10815e6af0a7SFlorian Westphal } 10825e6af0a7SFlorian Westphal 10835fb62e9cSFlorian Westphal static void parse_setsock_options(const char *name) 10845fb62e9cSFlorian Westphal { 10855fb62e9cSFlorian Westphal char *next = strchr(name, ','); 10865fb62e9cSFlorian Westphal unsigned int len = 0; 10875fb62e9cSFlorian Westphal 10885fb62e9cSFlorian Westphal if (next) { 10895fb62e9cSFlorian Westphal parse_setsock_options(next + 1); 10905fb62e9cSFlorian Westphal len = next - name; 10915fb62e9cSFlorian Westphal } else { 10925fb62e9cSFlorian Westphal len = strlen(name); 10935fb62e9cSFlorian Westphal } 10945fb62e9cSFlorian Westphal 10955fb62e9cSFlorian Westphal if (strncmp(name, "TRANSPARENT", len) == 0) { 10965fb62e9cSFlorian Westphal cfg_sockopt_types.transparent = 1; 10975fb62e9cSFlorian Westphal return; 10985fb62e9cSFlorian Westphal } 10995fb62e9cSFlorian Westphal 11005fb62e9cSFlorian Westphal fprintf(stderr, "Unrecognized setsockopt option %s\n", name); 11015fb62e9cSFlorian Westphal exit(1); 11025fb62e9cSFlorian Westphal } 11035fb62e9cSFlorian Westphal 110405be5e27SPaolo Abeni void xdisconnect(int fd, int addrlen) 110505be5e27SPaolo Abeni { 110605be5e27SPaolo Abeni struct sockaddr_storage empty; 110705be5e27SPaolo Abeni int msec_sleep = 10; 110805be5e27SPaolo Abeni int queued = 1; 110905be5e27SPaolo Abeni int i; 111005be5e27SPaolo Abeni 111105be5e27SPaolo Abeni shutdown(fd, SHUT_WR); 111205be5e27SPaolo Abeni 111305be5e27SPaolo Abeni /* while until the pending data is completely flushed, the later 111405be5e27SPaolo Abeni * disconnect will bypass/ignore/drop any pending data. 111505be5e27SPaolo Abeni */ 111605be5e27SPaolo Abeni for (i = 0; ; i += msec_sleep) { 111705be5e27SPaolo Abeni if (ioctl(fd, SIOCOUTQ, &queued) < 0) 111805be5e27SPaolo Abeni xerror("can't query out socket queue: %d", errno); 111905be5e27SPaolo Abeni 112005be5e27SPaolo Abeni if (!queued) 112105be5e27SPaolo Abeni break; 112205be5e27SPaolo Abeni 112305be5e27SPaolo Abeni if (i > poll_timeout) 112405be5e27SPaolo Abeni xerror("timeout while waiting for spool to complete"); 112505be5e27SPaolo Abeni usleep(msec_sleep * 1000); 112605be5e27SPaolo Abeni } 112705be5e27SPaolo Abeni 112805be5e27SPaolo Abeni memset(&empty, 0, sizeof(empty)); 112905be5e27SPaolo Abeni empty.ss_family = AF_UNSPEC; 113005be5e27SPaolo Abeni if (connect(fd, (struct sockaddr *)&empty, addrlen) < 0) 113105be5e27SPaolo Abeni xerror("can't disconnect: %d", errno); 113205be5e27SPaolo Abeni } 113305be5e27SPaolo Abeni 1134048d19d4SFlorian Westphal int main_loop(void) 1135048d19d4SFlorian Westphal { 113605be5e27SPaolo Abeni int fd, ret, fd_in = 0; 113705be5e27SPaolo Abeni struct addrinfo *peer; 1138048d19d4SFlorian Westphal 1139048d19d4SFlorian Westphal /* listener is ready. */ 114005be5e27SPaolo Abeni fd = sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto, &peer); 1141048d19d4SFlorian Westphal if (fd < 0) 1142048d19d4SFlorian Westphal return 2; 1143048d19d4SFlorian Westphal 114405be5e27SPaolo Abeni again: 1145048d19d4SFlorian Westphal check_getpeername_connect(fd); 1146048d19d4SFlorian Westphal 1147f730b65cSFlorian Westphal SOCK_TEST_TCPULP(fd, cfg_sock_proto); 1148f730b65cSFlorian Westphal 11498a4b910dSFlorian Westphal if (cfg_rcvbuf) 11508a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 1151048d19d4SFlorian Westphal if (cfg_sndbuf) 1152048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 11535e6af0a7SFlorian Westphal if (cfg_cmsg_types.cmsg_enabled) 11545e6af0a7SFlorian Westphal apply_cmsg_types(fd, &cfg_cmsg_types); 1155048d19d4SFlorian Westphal 115605be5e27SPaolo Abeni if (cfg_input) { 115705be5e27SPaolo Abeni fd_in = open(cfg_input, O_RDONLY); 115805be5e27SPaolo Abeni if (fd < 0) 115905be5e27SPaolo Abeni xerror("can't open %s:%d", cfg_input, errno); 116005be5e27SPaolo Abeni } 116105be5e27SPaolo Abeni 116205be5e27SPaolo Abeni /* close the client socket open only if we are not going to reconnect */ 116305be5e27SPaolo Abeni ret = copyfd_io(fd_in, fd, 1, cfg_repeat == 1); 116405be5e27SPaolo Abeni if (ret) 116505be5e27SPaolo Abeni return ret; 116605be5e27SPaolo Abeni 116705be5e27SPaolo Abeni if (--cfg_repeat > 0) { 116805be5e27SPaolo Abeni xdisconnect(fd, peer->ai_addrlen); 116905be5e27SPaolo Abeni 117005be5e27SPaolo Abeni /* the socket could be unblocking at this point, we need the 117105be5e27SPaolo Abeni * connect to be blocking 117205be5e27SPaolo Abeni */ 117305be5e27SPaolo Abeni set_nonblock(fd, false); 117405be5e27SPaolo Abeni if (connect(fd, peer->ai_addr, peer->ai_addrlen)) 117505be5e27SPaolo Abeni xerror("can't reconnect: %d", errno); 117605be5e27SPaolo Abeni if (cfg_input) 117705be5e27SPaolo Abeni close(fd_in); 117805be5e27SPaolo Abeni goto again; 117905be5e27SPaolo Abeni } 118005be5e27SPaolo Abeni return 0; 1181048d19d4SFlorian Westphal } 1182048d19d4SFlorian Westphal 1183048d19d4SFlorian Westphal int parse_proto(const char *proto) 1184048d19d4SFlorian Westphal { 1185048d19d4SFlorian Westphal if (!strcasecmp(proto, "MPTCP")) 1186048d19d4SFlorian Westphal return IPPROTO_MPTCP; 1187048d19d4SFlorian Westphal if (!strcasecmp(proto, "TCP")) 1188048d19d4SFlorian Westphal return IPPROTO_TCP; 1189048d19d4SFlorian Westphal 1190048d19d4SFlorian Westphal fprintf(stderr, "Unknown protocol: %s\n.", proto); 1191048d19d4SFlorian Westphal die_usage(); 1192048d19d4SFlorian Westphal 1193048d19d4SFlorian Westphal /* silence compiler warning */ 1194048d19d4SFlorian Westphal return 0; 1195048d19d4SFlorian Westphal } 1196048d19d4SFlorian Westphal 1197048d19d4SFlorian Westphal int parse_mode(const char *mode) 1198048d19d4SFlorian Westphal { 1199048d19d4SFlorian Westphal if (!strcasecmp(mode, "poll")) 1200048d19d4SFlorian Westphal return CFG_MODE_POLL; 1201048d19d4SFlorian Westphal if (!strcasecmp(mode, "mmap")) 1202048d19d4SFlorian Westphal return CFG_MODE_MMAP; 1203048d19d4SFlorian Westphal if (!strcasecmp(mode, "sendfile")) 1204048d19d4SFlorian Westphal return CFG_MODE_SENDFILE; 1205048d19d4SFlorian Westphal 1206048d19d4SFlorian Westphal fprintf(stderr, "Unknown test mode: %s\n", mode); 1207048d19d4SFlorian Westphal fprintf(stderr, "Supported modes are:\n"); 1208048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"poll\" - interleaved read/write using poll()\n"); 1209048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"mmap\" - send entire input file (mmap+write), then read response (-l will read input first)\n"); 1210048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"sendfile\" - send entire input file (sendfile), then read response (-l will read input first)\n"); 1211048d19d4SFlorian Westphal 1212048d19d4SFlorian Westphal die_usage(); 1213048d19d4SFlorian Westphal 1214048d19d4SFlorian Westphal /* silence compiler warning */ 1215048d19d4SFlorian Westphal return 0; 1216048d19d4SFlorian Westphal } 1217048d19d4SFlorian Westphal 1218df8aee6dSYonglong Li int parse_peek(const char *mode) 1219df8aee6dSYonglong Li { 1220df8aee6dSYonglong Li if (!strcasecmp(mode, "saveWithPeek")) 1221df8aee6dSYonglong Li return CFG_WITH_PEEK; 1222df8aee6dSYonglong Li if (!strcasecmp(mode, "saveAfterPeek")) 1223df8aee6dSYonglong Li return CFG_AFTER_PEEK; 1224df8aee6dSYonglong Li 1225df8aee6dSYonglong Li fprintf(stderr, "Unknown: %s\n", mode); 1226df8aee6dSYonglong Li fprintf(stderr, "Supported MSG_PEEK mode are:\n"); 1227df8aee6dSYonglong Li fprintf(stderr, 1228df8aee6dSYonglong Li "\t\t\"saveWithPeek\" - recv data with flags 'MSG_PEEK' and save the peek data into file\n"); 1229df8aee6dSYonglong Li fprintf(stderr, 1230df8aee6dSYonglong Li "\t\t\"saveAfterPeek\" - read and save data into file after recv with flags 'MSG_PEEK'\n"); 1231df8aee6dSYonglong Li 1232df8aee6dSYonglong Li die_usage(); 1233df8aee6dSYonglong Li 1234df8aee6dSYonglong Li /* silence compiler warning */ 1235df8aee6dSYonglong Li return 0; 1236df8aee6dSYonglong Li } 1237df8aee6dSYonglong Li 12388a4b910dSFlorian Westphal static int parse_int(const char *size) 1239048d19d4SFlorian Westphal { 1240048d19d4SFlorian Westphal unsigned long s; 1241048d19d4SFlorian Westphal 1242048d19d4SFlorian Westphal errno = 0; 1243048d19d4SFlorian Westphal 1244048d19d4SFlorian Westphal s = strtoul(size, NULL, 0); 1245048d19d4SFlorian Westphal 1246048d19d4SFlorian Westphal if (errno) { 1247048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 1248048d19d4SFlorian Westphal size, strerror(errno)); 1249048d19d4SFlorian Westphal die_usage(); 1250048d19d4SFlorian Westphal } 1251048d19d4SFlorian Westphal 1252048d19d4SFlorian Westphal if (s > INT_MAX) { 1253048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 1254048d19d4SFlorian Westphal size, strerror(ERANGE)); 1255048d19d4SFlorian Westphal die_usage(); 1256048d19d4SFlorian Westphal } 1257048d19d4SFlorian Westphal 12588a4b910dSFlorian Westphal return (int)s; 1259048d19d4SFlorian Westphal } 1260048d19d4SFlorian Westphal 1261048d19d4SFlorian Westphal static void parse_opts(int argc, char **argv) 1262048d19d4SFlorian Westphal { 1263048d19d4SFlorian Westphal int c; 1264048d19d4SFlorian Westphal 126505be5e27SPaolo Abeni while ((c = getopt(argc, argv, "6c:hi:I:jlm:M:o:p:P:r:R:s:S:t:T:w:")) != -1) { 1266048d19d4SFlorian Westphal switch (c) { 1267b08fbf24SPaolo Abeni case 'j': 1268b08fbf24SPaolo Abeni cfg_join = true; 1269b08fbf24SPaolo Abeni cfg_mode = CFG_MODE_POLL; 1270b08fbf24SPaolo Abeni break; 127113153324SGeliang Tang case 'r': 127213153324SGeliang Tang cfg_remove = true; 127313153324SGeliang Tang cfg_mode = CFG_MODE_POLL; 127413153324SGeliang Tang cfg_wait = 400000; 12752e580a63SGeliang Tang cfg_do_w = atoi(optarg); 12762e580a63SGeliang Tang if (cfg_do_w <= 0) 12772e580a63SGeliang Tang cfg_do_w = 50; 127813153324SGeliang Tang break; 127905be5e27SPaolo Abeni case 'i': 128005be5e27SPaolo Abeni cfg_input = optarg; 128105be5e27SPaolo Abeni break; 128205be5e27SPaolo Abeni case 'I': 128305be5e27SPaolo Abeni cfg_repeat = atoi(optarg); 128405be5e27SPaolo Abeni break; 1285048d19d4SFlorian Westphal case 'l': 1286048d19d4SFlorian Westphal listen_mode = true; 1287048d19d4SFlorian Westphal break; 1288048d19d4SFlorian Westphal case 'p': 1289048d19d4SFlorian Westphal cfg_port = optarg; 1290048d19d4SFlorian Westphal break; 1291048d19d4SFlorian Westphal case 's': 1292048d19d4SFlorian Westphal cfg_sock_proto = parse_proto(optarg); 1293048d19d4SFlorian Westphal break; 1294048d19d4SFlorian Westphal case 'h': 1295048d19d4SFlorian Westphal die_usage(); 1296048d19d4SFlorian Westphal break; 1297048d19d4SFlorian Westphal case '6': 1298048d19d4SFlorian Westphal pf = AF_INET6; 1299048d19d4SFlorian Westphal break; 1300048d19d4SFlorian Westphal case 't': 1301048d19d4SFlorian Westphal poll_timeout = atoi(optarg) * 1000; 1302048d19d4SFlorian Westphal if (poll_timeout <= 0) 1303048d19d4SFlorian Westphal poll_timeout = -1; 1304048d19d4SFlorian Westphal break; 1305b6ab64b0SPaolo Abeni case 'T': 1306b6ab64b0SPaolo Abeni cfg_time = atoi(optarg); 1307b6ab64b0SPaolo Abeni break; 1308048d19d4SFlorian Westphal case 'm': 1309048d19d4SFlorian Westphal cfg_mode = parse_mode(optarg); 1310048d19d4SFlorian Westphal break; 13118a4b910dSFlorian Westphal case 'S': 13128a4b910dSFlorian Westphal cfg_sndbuf = parse_int(optarg); 13138a4b910dSFlorian Westphal break; 13148a4b910dSFlorian Westphal case 'R': 13158a4b910dSFlorian Westphal cfg_rcvbuf = parse_int(optarg); 1316048d19d4SFlorian Westphal break; 1317df62f2ecSPaolo Abeni case 'w': 1318df62f2ecSPaolo Abeni cfg_wait = atoi(optarg)*1000000; 1319df62f2ecSPaolo Abeni break; 1320dc65fe82SFlorian Westphal case 'M': 1321dc65fe82SFlorian Westphal cfg_mark = strtol(optarg, NULL, 0); 1322dc65fe82SFlorian Westphal break; 1323df8aee6dSYonglong Li case 'P': 1324df8aee6dSYonglong Li cfg_peek = parse_peek(optarg); 1325df8aee6dSYonglong Li break; 13265e6af0a7SFlorian Westphal case 'c': 13275e6af0a7SFlorian Westphal parse_cmsg_types(optarg); 13285e6af0a7SFlorian Westphal break; 13295fb62e9cSFlorian Westphal case 'o': 13305fb62e9cSFlorian Westphal parse_setsock_options(optarg); 13315fb62e9cSFlorian Westphal break; 1332048d19d4SFlorian Westphal } 1333048d19d4SFlorian Westphal } 1334048d19d4SFlorian Westphal 1335048d19d4SFlorian Westphal if (optind + 1 != argc) 1336048d19d4SFlorian Westphal die_usage(); 1337048d19d4SFlorian Westphal cfg_host = argv[optind]; 1338048d19d4SFlorian Westphal 1339048d19d4SFlorian Westphal if (strchr(cfg_host, ':')) 1340048d19d4SFlorian Westphal pf = AF_INET6; 1341048d19d4SFlorian Westphal } 1342048d19d4SFlorian Westphal 1343048d19d4SFlorian Westphal int main(int argc, char *argv[]) 1344048d19d4SFlorian Westphal { 1345048d19d4SFlorian Westphal init_rng(); 1346048d19d4SFlorian Westphal 1347df62f2ecSPaolo Abeni signal(SIGUSR1, handle_signal); 1348048d19d4SFlorian Westphal parse_opts(argc, argv); 1349048d19d4SFlorian Westphal 1350048d19d4SFlorian Westphal if (listen_mode) { 1351048d19d4SFlorian Westphal int fd = sock_listen_mptcp(cfg_host, cfg_port); 1352048d19d4SFlorian Westphal 1353048d19d4SFlorian Westphal if (fd < 0) 1354048d19d4SFlorian Westphal return 1; 1355048d19d4SFlorian Westphal 13568a4b910dSFlorian Westphal if (cfg_rcvbuf) 13578a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 1358048d19d4SFlorian Westphal if (cfg_sndbuf) 1359048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 1360dc65fe82SFlorian Westphal if (cfg_mark) 1361dc65fe82SFlorian Westphal set_mark(fd, cfg_mark); 13625e6af0a7SFlorian Westphal if (cfg_cmsg_types.cmsg_enabled) 13635e6af0a7SFlorian Westphal apply_cmsg_types(fd, &cfg_cmsg_types); 1364048d19d4SFlorian Westphal 1365048d19d4SFlorian Westphal return main_loop_s(fd); 1366048d19d4SFlorian Westphal } 1367048d19d4SFlorian Westphal 1368048d19d4SFlorian Westphal return main_loop(); 1369048d19d4SFlorian Westphal } 1370