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> 2120bb3a96SWillem de Bruijn #include <sys/random.h> 22048d19d4SFlorian Westphal #include <sys/sendfile.h> 23048d19d4SFlorian Westphal #include <sys/stat.h> 24048d19d4SFlorian Westphal #include <sys/socket.h> 25048d19d4SFlorian Westphal #include <sys/types.h> 26048d19d4SFlorian Westphal #include <sys/mman.h> 27048d19d4SFlorian Westphal 28048d19d4SFlorian Westphal #include <netdb.h> 29048d19d4SFlorian Westphal #include <netinet/in.h> 30048d19d4SFlorian Westphal 31048d19d4SFlorian Westphal #include <linux/tcp.h> 325e6af0a7SFlorian Westphal #include <linux/time_types.h> 3305be5e27SPaolo Abeni #include <linux/sockios.h> 34048d19d4SFlorian Westphal 35048d19d4SFlorian Westphal extern int optind; 36048d19d4SFlorian Westphal 37048d19d4SFlorian Westphal #ifndef IPPROTO_MPTCP 38048d19d4SFlorian Westphal #define IPPROTO_MPTCP 262 39048d19d4SFlorian Westphal #endif 40048d19d4SFlorian Westphal #ifndef TCP_ULP 41048d19d4SFlorian Westphal #define TCP_ULP 31 42048d19d4SFlorian Westphal #endif 43048d19d4SFlorian Westphal 448a4b910dSFlorian Westphal static int poll_timeout = 10 * 1000; 45048d19d4SFlorian Westphal static bool listen_mode; 46df62f2ecSPaolo Abeni static bool quit; 47048d19d4SFlorian Westphal 48048d19d4SFlorian Westphal enum cfg_mode { 49048d19d4SFlorian Westphal CFG_MODE_POLL, 50048d19d4SFlorian Westphal CFG_MODE_MMAP, 51048d19d4SFlorian Westphal CFG_MODE_SENDFILE, 52048d19d4SFlorian Westphal }; 53048d19d4SFlorian Westphal 54df8aee6dSYonglong Li enum cfg_peek { 55df8aee6dSYonglong Li CFG_NONE_PEEK, 56df8aee6dSYonglong Li CFG_WITH_PEEK, 57df8aee6dSYonglong Li CFG_AFTER_PEEK, 58df8aee6dSYonglong Li }; 59df8aee6dSYonglong Li 60048d19d4SFlorian Westphal static enum cfg_mode cfg_mode = CFG_MODE_POLL; 61df8aee6dSYonglong Li static enum cfg_peek cfg_peek = CFG_NONE_PEEK; 62048d19d4SFlorian Westphal static const char *cfg_host; 63048d19d4SFlorian Westphal static const char *cfg_port = "12000"; 64048d19d4SFlorian Westphal static int cfg_sock_proto = IPPROTO_MPTCP; 65048d19d4SFlorian Westphal static int pf = AF_INET; 66048d19d4SFlorian Westphal static int cfg_sndbuf; 678a4b910dSFlorian Westphal static int cfg_rcvbuf; 68b08fbf24SPaolo Abeni static bool cfg_join; 6913153324SGeliang Tang static bool cfg_remove; 70b6ab64b0SPaolo Abeni static unsigned int cfg_time; 712e580a63SGeliang Tang static unsigned int cfg_do_w; 72df62f2ecSPaolo Abeni static int cfg_wait; 73dc65fe82SFlorian Westphal static uint32_t cfg_mark; 7405be5e27SPaolo Abeni static char *cfg_input; 7505be5e27SPaolo Abeni static int cfg_repeat = 1; 766bf41020SPaolo Abeni static int cfg_truncate; 776bf41020SPaolo Abeni static int cfg_rcv_trunc; 78048d19d4SFlorian Westphal 795e6af0a7SFlorian Westphal struct cfg_cmsg_types { 805e6af0a7SFlorian Westphal unsigned int cmsg_enabled:1; 815e6af0a7SFlorian Westphal unsigned int timestampns:1; 825cbd886cSFlorian Westphal unsigned int tcp_inq:1; 835e6af0a7SFlorian Westphal }; 845e6af0a7SFlorian Westphal 855fb62e9cSFlorian Westphal struct cfg_sockopt_types { 865fb62e9cSFlorian Westphal unsigned int transparent:1; 87ca7ae891SDmytro Shytyi unsigned int mptfo:1; 885fb62e9cSFlorian Westphal }; 895fb62e9cSFlorian Westphal 905cbd886cSFlorian Westphal struct tcp_inq_state { 915cbd886cSFlorian Westphal unsigned int last; 925cbd886cSFlorian Westphal bool expect_eof; 935cbd886cSFlorian Westphal }; 945cbd886cSFlorian Westphal 95ca7ae891SDmytro Shytyi struct wstate { 96ca7ae891SDmytro Shytyi char buf[8192]; 97ca7ae891SDmytro Shytyi unsigned int len; 98ca7ae891SDmytro Shytyi unsigned int off; 99ca7ae891SDmytro Shytyi unsigned int total_len; 100ca7ae891SDmytro Shytyi }; 101ca7ae891SDmytro Shytyi 1025cbd886cSFlorian Westphal static struct tcp_inq_state tcp_inq; 1035cbd886cSFlorian Westphal 1045e6af0a7SFlorian Westphal static struct cfg_cmsg_types cfg_cmsg_types; 1055fb62e9cSFlorian Westphal static struct cfg_sockopt_types cfg_sockopt_types; 1065e6af0a7SFlorian Westphal 107048d19d4SFlorian Westphal static void die_usage(void) 108048d19d4SFlorian Westphal { 1096bf41020SPaolo Abeni fprintf(stderr, "Usage: mptcp_connect [-6] [-c cmsg] [-f offset] [-i file] [-I num] [-j] [-l] " 1100a85264eSMatthieu Baerts "[-m mode] [-M mark] [-o option] [-p port] [-P mode] [-r num] [-R num] " 1110a85264eSMatthieu Baerts "[-s MPTCP|TCP] [-S num] [-t num] [-T num] [-w sec] connect_address\n"); 1128a4b910dSFlorian Westphal fprintf(stderr, "\t-6 use ipv6\n"); 11305be5e27SPaolo Abeni fprintf(stderr, "\t-c cmsg -- test cmsg type <cmsg>\n"); 1146bf41020SPaolo Abeni fprintf(stderr, "\t-f offset -- stop the I/O after receiving and sending the specified amount " 1156bf41020SPaolo Abeni "of bytes. If there are unread bytes in the receive queue, that will cause a MPTCP " 1166bf41020SPaolo Abeni "fastclose at close/shutdown. If offset is negative, expect the peer to close before " 1176bf41020SPaolo Abeni "all the local data as been sent, thus toleration errors on write and EPIPE signals\n"); 11805be5e27SPaolo Abeni fprintf(stderr, "\t-i file -- read the data to send from the given file instead of stdin"); 11905be5e27SPaolo Abeni fprintf(stderr, "\t-I num -- repeat the transfer 'num' times. In listen mode accepts num " 12005be5e27SPaolo Abeni "incoming connections, in client mode, disconnect and reconnect to the server\n"); 12105be5e27SPaolo Abeni fprintf(stderr, "\t-j -- add additional sleep at connection start and tear down " 12205be5e27SPaolo Abeni "-- for MPJ tests\n"); 12305be5e27SPaolo Abeni fprintf(stderr, "\t-l -- listens mode, accepts incoming connection\n"); 124c6f4c2b0SDavide Caratti fprintf(stderr, "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n"); 125dc65fe82SFlorian Westphal fprintf(stderr, "\t-M mark -- set socket packet mark\n"); 1265fb62e9cSFlorian Westphal fprintf(stderr, "\t-o option -- test sockopt <option>\n"); 12705be5e27SPaolo Abeni fprintf(stderr, "\t-p num -- use port num\n"); 128df8aee6dSYonglong Li fprintf(stderr, 129df8aee6dSYonglong Li "\t-P [saveWithPeek|saveAfterPeek] -- save data with/after MSG_PEEK form tcp socket\n"); 13005be5e27SPaolo Abeni fprintf(stderr, "\t-r num -- enable slow mode, limiting each write to num bytes " 13105be5e27SPaolo Abeni "-- for remove addr tests\n"); 13205be5e27SPaolo Abeni fprintf(stderr, "\t-R num -- set SO_RCVBUF to num\n"); 13305be5e27SPaolo Abeni fprintf(stderr, "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n"); 13405be5e27SPaolo Abeni fprintf(stderr, "\t-S num -- set SO_SNDBUF to num\n"); 1350a85264eSMatthieu Baerts fprintf(stderr, "\t-t num -- set poll timeout to num\n"); 1360a85264eSMatthieu Baerts fprintf(stderr, "\t-T num -- set expected runtime to num ms\n"); 13705be5e27SPaolo Abeni fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n"); 138048d19d4SFlorian Westphal exit(1); 139048d19d4SFlorian Westphal } 140048d19d4SFlorian Westphal 1415e6af0a7SFlorian Westphal static void xerror(const char *fmt, ...) 1425e6af0a7SFlorian Westphal { 1435e6af0a7SFlorian Westphal va_list ap; 1445e6af0a7SFlorian Westphal 1455e6af0a7SFlorian Westphal va_start(ap, fmt); 1465e6af0a7SFlorian Westphal vfprintf(stderr, fmt, ap); 1475e6af0a7SFlorian Westphal va_end(ap); 1485e6af0a7SFlorian Westphal exit(1); 1495e6af0a7SFlorian Westphal } 1505e6af0a7SFlorian Westphal 151df62f2ecSPaolo Abeni static void handle_signal(int nr) 152df62f2ecSPaolo Abeni { 153df62f2ecSPaolo Abeni quit = true; 154df62f2ecSPaolo Abeni } 155df62f2ecSPaolo Abeni 156048d19d4SFlorian Westphal static const char *getxinfo_strerr(int err) 157048d19d4SFlorian Westphal { 158048d19d4SFlorian Westphal if (err == EAI_SYSTEM) 159048d19d4SFlorian Westphal return strerror(errno); 160048d19d4SFlorian Westphal 161048d19d4SFlorian Westphal return gai_strerror(err); 162048d19d4SFlorian Westphal } 163048d19d4SFlorian Westphal 164048d19d4SFlorian Westphal static void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen, 165048d19d4SFlorian Westphal char *host, socklen_t hostlen, 166048d19d4SFlorian Westphal char *serv, socklen_t servlen) 167048d19d4SFlorian Westphal { 168048d19d4SFlorian Westphal int flags = NI_NUMERICHOST | NI_NUMERICSERV; 169048d19d4SFlorian Westphal int err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, 170048d19d4SFlorian Westphal flags); 171048d19d4SFlorian Westphal 172048d19d4SFlorian Westphal if (err) { 173048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 174048d19d4SFlorian Westphal 175048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getnameinfo: %s\n", errstr); 176048d19d4SFlorian Westphal exit(1); 177048d19d4SFlorian Westphal } 178048d19d4SFlorian Westphal } 179048d19d4SFlorian Westphal 180048d19d4SFlorian Westphal static void xgetaddrinfo(const char *node, const char *service, 181048d19d4SFlorian Westphal const struct addrinfo *hints, 182048d19d4SFlorian Westphal struct addrinfo **res) 183048d19d4SFlorian Westphal { 184048d19d4SFlorian Westphal int err = getaddrinfo(node, service, hints, res); 185048d19d4SFlorian Westphal 186048d19d4SFlorian Westphal if (err) { 187048d19d4SFlorian Westphal const char *errstr = getxinfo_strerr(err); 188048d19d4SFlorian Westphal 189048d19d4SFlorian Westphal fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", 190048d19d4SFlorian Westphal node ? node : "", service ? service : "", errstr); 191048d19d4SFlorian Westphal exit(1); 192048d19d4SFlorian Westphal } 193048d19d4SFlorian Westphal } 194048d19d4SFlorian Westphal 1958a4b910dSFlorian Westphal static void set_rcvbuf(int fd, unsigned int size) 1968a4b910dSFlorian Westphal { 1978a4b910dSFlorian Westphal int err; 1988a4b910dSFlorian Westphal 1998a4b910dSFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 2008a4b910dSFlorian Westphal if (err) { 2018a4b910dSFlorian Westphal perror("set SO_RCVBUF"); 2028a4b910dSFlorian Westphal exit(1); 2038a4b910dSFlorian Westphal } 2048a4b910dSFlorian Westphal } 2058a4b910dSFlorian Westphal 206048d19d4SFlorian Westphal static void set_sndbuf(int fd, unsigned int size) 207048d19d4SFlorian Westphal { 208048d19d4SFlorian Westphal int err; 209048d19d4SFlorian Westphal 210048d19d4SFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); 211048d19d4SFlorian Westphal if (err) { 212048d19d4SFlorian Westphal perror("set SO_SNDBUF"); 213048d19d4SFlorian Westphal exit(1); 214048d19d4SFlorian Westphal } 215048d19d4SFlorian Westphal } 216048d19d4SFlorian Westphal 217dc65fe82SFlorian Westphal static void set_mark(int fd, uint32_t mark) 218dc65fe82SFlorian Westphal { 219dc65fe82SFlorian Westphal int err; 220dc65fe82SFlorian Westphal 221dc65fe82SFlorian Westphal err = setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); 222dc65fe82SFlorian Westphal if (err) { 223dc65fe82SFlorian Westphal perror("set SO_MARK"); 224dc65fe82SFlorian Westphal exit(1); 225dc65fe82SFlorian Westphal } 226dc65fe82SFlorian Westphal } 227dc65fe82SFlorian Westphal 2285fb62e9cSFlorian Westphal static void set_transparent(int fd, int pf) 2295fb62e9cSFlorian Westphal { 2305fb62e9cSFlorian Westphal int one = 1; 2315fb62e9cSFlorian Westphal 2325fb62e9cSFlorian Westphal switch (pf) { 2335fb62e9cSFlorian Westphal case AF_INET: 2345fb62e9cSFlorian Westphal if (-1 == setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one))) 2355fb62e9cSFlorian Westphal perror("IP_TRANSPARENT"); 2365fb62e9cSFlorian Westphal break; 2375fb62e9cSFlorian Westphal case AF_INET6: 2385fb62e9cSFlorian Westphal if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, &one, sizeof(one))) 2395fb62e9cSFlorian Westphal perror("IPV6_TRANSPARENT"); 2405fb62e9cSFlorian Westphal break; 2415fb62e9cSFlorian Westphal } 2425fb62e9cSFlorian Westphal } 2435fb62e9cSFlorian Westphal 244ca7ae891SDmytro Shytyi static void set_mptfo(int fd, int pf) 245ca7ae891SDmytro Shytyi { 246ca7ae891SDmytro Shytyi int qlen = 25; 247ca7ae891SDmytro Shytyi 248ca7ae891SDmytro Shytyi if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) == -1) 249ca7ae891SDmytro Shytyi perror("TCP_FASTOPEN"); 250ca7ae891SDmytro Shytyi } 251ca7ae891SDmytro Shytyi 252f730b65cSFlorian Westphal static int do_ulp_so(int sock, const char *name) 253f730b65cSFlorian Westphal { 254f730b65cSFlorian Westphal return setsockopt(sock, IPPROTO_TCP, TCP_ULP, name, strlen(name)); 255f730b65cSFlorian Westphal } 256f730b65cSFlorian Westphal 257f730b65cSFlorian Westphal #define X(m) xerror("%s:%u: %s: failed for proto %d at line %u", __FILE__, __LINE__, (m), proto, line) 258f730b65cSFlorian Westphal static void sock_test_tcpulp(int sock, int proto, unsigned int line) 259f730b65cSFlorian Westphal { 260f730b65cSFlorian Westphal socklen_t buflen = 8; 261f730b65cSFlorian Westphal char buf[8] = ""; 262f730b65cSFlorian Westphal int ret = getsockopt(sock, IPPROTO_TCP, TCP_ULP, buf, &buflen); 263f730b65cSFlorian Westphal 264f730b65cSFlorian Westphal if (ret != 0) 265f730b65cSFlorian Westphal X("getsockopt"); 266f730b65cSFlorian Westphal 267f730b65cSFlorian Westphal if (buflen > 0) { 268f730b65cSFlorian Westphal if (strcmp(buf, "mptcp") != 0) 269f730b65cSFlorian Westphal xerror("unexpected ULP '%s' for proto %d at line %u", buf, proto, line); 270f730b65cSFlorian Westphal ret = do_ulp_so(sock, "tls"); 271f730b65cSFlorian Westphal if (ret == 0) 272f730b65cSFlorian Westphal X("setsockopt"); 273f730b65cSFlorian Westphal } else if (proto == IPPROTO_MPTCP) { 274f730b65cSFlorian Westphal ret = do_ulp_so(sock, "tls"); 275f730b65cSFlorian Westphal if (ret != -1) 276f730b65cSFlorian Westphal X("setsockopt"); 277f730b65cSFlorian Westphal } 278f730b65cSFlorian Westphal 279f730b65cSFlorian Westphal ret = do_ulp_so(sock, "mptcp"); 280f730b65cSFlorian Westphal if (ret != -1) 281f730b65cSFlorian Westphal X("setsockopt"); 282f730b65cSFlorian Westphal 283f730b65cSFlorian Westphal #undef X 284f730b65cSFlorian Westphal } 285f730b65cSFlorian Westphal 286f730b65cSFlorian Westphal #define SOCK_TEST_TCPULP(s, p) sock_test_tcpulp((s), (p), __LINE__) 287f730b65cSFlorian Westphal 288048d19d4SFlorian Westphal static int sock_listen_mptcp(const char * const listenaddr, 289048d19d4SFlorian Westphal const char * const port) 290048d19d4SFlorian Westphal { 291fd37c2ecSMat Martineau int sock = -1; 292048d19d4SFlorian Westphal struct addrinfo hints = { 293048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 294048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 295048d19d4SFlorian Westphal .ai_flags = AI_PASSIVE | AI_NUMERICHOST 296048d19d4SFlorian Westphal }; 297048d19d4SFlorian Westphal 298048d19d4SFlorian Westphal hints.ai_family = pf; 299048d19d4SFlorian Westphal 300048d19d4SFlorian Westphal struct addrinfo *a, *addr; 301048d19d4SFlorian Westphal int one = 1; 302048d19d4SFlorian Westphal 303048d19d4SFlorian Westphal xgetaddrinfo(listenaddr, port, &hints, &addr); 304048d19d4SFlorian Westphal hints.ai_family = pf; 305048d19d4SFlorian Westphal 306048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 307048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, cfg_sock_proto); 308048d19d4SFlorian Westphal if (sock < 0) 309048d19d4SFlorian Westphal continue; 310048d19d4SFlorian Westphal 311f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 312f730b65cSFlorian Westphal 313048d19d4SFlorian Westphal if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, 314048d19d4SFlorian Westphal sizeof(one))) 315048d19d4SFlorian Westphal perror("setsockopt"); 316048d19d4SFlorian Westphal 3175fb62e9cSFlorian Westphal if (cfg_sockopt_types.transparent) 3185fb62e9cSFlorian Westphal set_transparent(sock, pf); 3195fb62e9cSFlorian Westphal 320ca7ae891SDmytro Shytyi if (cfg_sockopt_types.mptfo) 321ca7ae891SDmytro Shytyi set_mptfo(sock, pf); 322ca7ae891SDmytro Shytyi 323048d19d4SFlorian Westphal if (bind(sock, a->ai_addr, a->ai_addrlen) == 0) 324048d19d4SFlorian Westphal break; /* success */ 325048d19d4SFlorian Westphal 326048d19d4SFlorian Westphal perror("bind"); 327048d19d4SFlorian Westphal close(sock); 328048d19d4SFlorian Westphal sock = -1; 329048d19d4SFlorian Westphal } 330048d19d4SFlorian Westphal 331048d19d4SFlorian Westphal freeaddrinfo(addr); 332048d19d4SFlorian Westphal 333048d19d4SFlorian Westphal if (sock < 0) { 334048d19d4SFlorian Westphal fprintf(stderr, "Could not create listen socket\n"); 335048d19d4SFlorian Westphal return sock; 336048d19d4SFlorian Westphal } 337048d19d4SFlorian Westphal 338f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 339f730b65cSFlorian Westphal 340048d19d4SFlorian Westphal if (listen(sock, 20)) { 341048d19d4SFlorian Westphal perror("listen"); 342048d19d4SFlorian Westphal close(sock); 343048d19d4SFlorian Westphal return -1; 344048d19d4SFlorian Westphal } 345048d19d4SFlorian Westphal 346f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, cfg_sock_proto); 347f730b65cSFlorian Westphal 348048d19d4SFlorian Westphal return sock; 349048d19d4SFlorian Westphal } 350048d19d4SFlorian Westphal 351048d19d4SFlorian Westphal static int sock_connect_mptcp(const char * const remoteaddr, 35205be5e27SPaolo Abeni const char * const port, int proto, 353ca7ae891SDmytro Shytyi struct addrinfo **peer, 354ca7ae891SDmytro Shytyi int infd, struct wstate *winfo) 355048d19d4SFlorian Westphal { 356048d19d4SFlorian Westphal struct addrinfo hints = { 357048d19d4SFlorian Westphal .ai_protocol = IPPROTO_TCP, 358048d19d4SFlorian Westphal .ai_socktype = SOCK_STREAM, 359048d19d4SFlorian Westphal }; 360048d19d4SFlorian Westphal struct addrinfo *a, *addr; 361ca7ae891SDmytro Shytyi int syn_copied = 0; 362048d19d4SFlorian Westphal int sock = -1; 363048d19d4SFlorian Westphal 364048d19d4SFlorian Westphal hints.ai_family = pf; 365048d19d4SFlorian Westphal 366048d19d4SFlorian Westphal xgetaddrinfo(remoteaddr, port, &hints, &addr); 367048d19d4SFlorian Westphal for (a = addr; a; a = a->ai_next) { 368048d19d4SFlorian Westphal sock = socket(a->ai_family, a->ai_socktype, proto); 369048d19d4SFlorian Westphal if (sock < 0) { 370048d19d4SFlorian Westphal perror("socket"); 371048d19d4SFlorian Westphal continue; 372048d19d4SFlorian Westphal } 373048d19d4SFlorian Westphal 374f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, proto); 375f730b65cSFlorian Westphal 376dc65fe82SFlorian Westphal if (cfg_mark) 377dc65fe82SFlorian Westphal set_mark(sock, cfg_mark); 378dc65fe82SFlorian Westphal 379ca7ae891SDmytro Shytyi if (cfg_sockopt_types.mptfo) { 380ca7ae891SDmytro Shytyi if (!winfo->total_len) 381ca7ae891SDmytro Shytyi winfo->total_len = winfo->len = read(infd, winfo->buf, 382ca7ae891SDmytro Shytyi sizeof(winfo->buf)); 383ca7ae891SDmytro Shytyi 384ca7ae891SDmytro Shytyi syn_copied = sendto(sock, winfo->buf, winfo->len, MSG_FASTOPEN, 385ca7ae891SDmytro Shytyi a->ai_addr, a->ai_addrlen); 386ca7ae891SDmytro Shytyi if (syn_copied >= 0) { 387ca7ae891SDmytro Shytyi winfo->off = syn_copied; 388ca7ae891SDmytro Shytyi winfo->len -= syn_copied; 389ca7ae891SDmytro Shytyi *peer = a; 390ca7ae891SDmytro Shytyi break; /* success */ 391ca7ae891SDmytro Shytyi } 392ca7ae891SDmytro Shytyi } else { 39305be5e27SPaolo Abeni if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) { 39405be5e27SPaolo Abeni *peer = a; 395048d19d4SFlorian Westphal break; /* success */ 39605be5e27SPaolo Abeni } 397ca7ae891SDmytro Shytyi } 398ca7ae891SDmytro Shytyi if (cfg_sockopt_types.mptfo) { 399ca7ae891SDmytro Shytyi perror("sendto()"); 400ca7ae891SDmytro Shytyi close(sock); 401ca7ae891SDmytro Shytyi sock = -1; 402ca7ae891SDmytro Shytyi } else { 403048d19d4SFlorian Westphal perror("connect()"); 404048d19d4SFlorian Westphal close(sock); 405048d19d4SFlorian Westphal sock = -1; 406048d19d4SFlorian Westphal } 407ca7ae891SDmytro Shytyi } 408048d19d4SFlorian Westphal 409048d19d4SFlorian Westphal freeaddrinfo(addr); 410f730b65cSFlorian Westphal if (sock != -1) 411f730b65cSFlorian Westphal SOCK_TEST_TCPULP(sock, proto); 412048d19d4SFlorian Westphal return sock; 413048d19d4SFlorian Westphal } 414048d19d4SFlorian Westphal 415048d19d4SFlorian Westphal static size_t do_rnd_write(const int fd, char *buf, const size_t len) 416048d19d4SFlorian Westphal { 417b08fbf24SPaolo Abeni static bool first = true; 418048d19d4SFlorian Westphal unsigned int do_w; 419048d19d4SFlorian Westphal ssize_t bw; 420048d19d4SFlorian Westphal 421048d19d4SFlorian Westphal do_w = rand() & 0xffff; 422048d19d4SFlorian Westphal if (do_w == 0 || do_w > len) 423048d19d4SFlorian Westphal do_w = len; 424048d19d4SFlorian Westphal 425b08fbf24SPaolo Abeni if (cfg_join && first && do_w > 100) 426b08fbf24SPaolo Abeni do_w = 100; 427b08fbf24SPaolo Abeni 4282e580a63SGeliang Tang if (cfg_remove && do_w > cfg_do_w) 4292e580a63SGeliang Tang do_w = cfg_do_w; 43013153324SGeliang Tang 431048d19d4SFlorian Westphal bw = write(fd, buf, do_w); 432048d19d4SFlorian Westphal if (bw < 0) 4336bf41020SPaolo Abeni return bw; 434048d19d4SFlorian Westphal 435b08fbf24SPaolo Abeni /* let the join handshake complete, before going on */ 436b08fbf24SPaolo Abeni if (cfg_join && first) { 437b08fbf24SPaolo Abeni usleep(200000); 438b08fbf24SPaolo Abeni first = false; 439b08fbf24SPaolo Abeni } 440b08fbf24SPaolo Abeni 44113153324SGeliang Tang if (cfg_remove) 44213153324SGeliang Tang usleep(200000); 44313153324SGeliang Tang 444048d19d4SFlorian Westphal return bw; 445048d19d4SFlorian Westphal } 446048d19d4SFlorian Westphal 447048d19d4SFlorian Westphal static size_t do_write(const int fd, char *buf, const size_t len) 448048d19d4SFlorian Westphal { 449048d19d4SFlorian Westphal size_t offset = 0; 450048d19d4SFlorian Westphal 451048d19d4SFlorian Westphal while (offset < len) { 452048d19d4SFlorian Westphal size_t written; 453048d19d4SFlorian Westphal ssize_t bw; 454048d19d4SFlorian Westphal 455048d19d4SFlorian Westphal bw = write(fd, buf + offset, len - offset); 456048d19d4SFlorian Westphal if (bw < 0) { 457048d19d4SFlorian Westphal perror("write"); 458048d19d4SFlorian Westphal return 0; 459048d19d4SFlorian Westphal } 460048d19d4SFlorian Westphal 461048d19d4SFlorian Westphal written = (size_t)bw; 462048d19d4SFlorian Westphal offset += written; 463048d19d4SFlorian Westphal } 464048d19d4SFlorian Westphal 465048d19d4SFlorian Westphal return offset; 466048d19d4SFlorian Westphal } 467048d19d4SFlorian Westphal 4685e6af0a7SFlorian Westphal static void process_cmsg(struct msghdr *msgh) 4695e6af0a7SFlorian Westphal { 4705e6af0a7SFlorian Westphal struct __kernel_timespec ts; 4715cbd886cSFlorian Westphal bool inq_found = false; 4725e6af0a7SFlorian Westphal bool ts_found = false; 4735cbd886cSFlorian Westphal unsigned int inq = 0; 4745e6af0a7SFlorian Westphal struct cmsghdr *cmsg; 4755e6af0a7SFlorian Westphal 4765e6af0a7SFlorian Westphal for (cmsg = CMSG_FIRSTHDR(msgh); cmsg ; cmsg = CMSG_NXTHDR(msgh, cmsg)) { 4775e6af0a7SFlorian Westphal if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPNS_NEW) { 4785e6af0a7SFlorian Westphal memcpy(&ts, CMSG_DATA(cmsg), sizeof(ts)); 4795e6af0a7SFlorian Westphal ts_found = true; 4805e6af0a7SFlorian Westphal continue; 4815e6af0a7SFlorian Westphal } 4825cbd886cSFlorian Westphal if (cmsg->cmsg_level == IPPROTO_TCP && cmsg->cmsg_type == TCP_CM_INQ) { 4835cbd886cSFlorian Westphal memcpy(&inq, CMSG_DATA(cmsg), sizeof(inq)); 4845cbd886cSFlorian Westphal inq_found = true; 4855cbd886cSFlorian Westphal continue; 4865cbd886cSFlorian Westphal } 4875cbd886cSFlorian Westphal 4885e6af0a7SFlorian Westphal } 4895e6af0a7SFlorian Westphal 4905e6af0a7SFlorian Westphal if (cfg_cmsg_types.timestampns) { 4915e6af0a7SFlorian Westphal if (!ts_found) 4925e6af0a7SFlorian Westphal xerror("TIMESTAMPNS not present\n"); 4935e6af0a7SFlorian Westphal } 4945cbd886cSFlorian Westphal 4955cbd886cSFlorian Westphal if (cfg_cmsg_types.tcp_inq) { 4965cbd886cSFlorian Westphal if (!inq_found) 4975cbd886cSFlorian Westphal xerror("TCP_INQ not present\n"); 4985cbd886cSFlorian Westphal 4995cbd886cSFlorian Westphal if (inq > 1024) 5005cbd886cSFlorian Westphal xerror("tcp_inq %u is larger than one kbyte\n", inq); 5015cbd886cSFlorian Westphal tcp_inq.last = inq; 5025cbd886cSFlorian Westphal } 5035e6af0a7SFlorian Westphal } 5045e6af0a7SFlorian Westphal 5055e6af0a7SFlorian Westphal static ssize_t do_recvmsg_cmsg(const int fd, char *buf, const size_t len) 5065e6af0a7SFlorian Westphal { 5075e6af0a7SFlorian Westphal char msg_buf[8192]; 5085e6af0a7SFlorian Westphal struct iovec iov = { 5095e6af0a7SFlorian Westphal .iov_base = buf, 5105e6af0a7SFlorian Westphal .iov_len = len, 5115e6af0a7SFlorian Westphal }; 5125e6af0a7SFlorian Westphal struct msghdr msg = { 5135e6af0a7SFlorian Westphal .msg_iov = &iov, 5145e6af0a7SFlorian Westphal .msg_iovlen = 1, 5155e6af0a7SFlorian Westphal .msg_control = msg_buf, 5165e6af0a7SFlorian Westphal .msg_controllen = sizeof(msg_buf), 5175e6af0a7SFlorian Westphal }; 5185e6af0a7SFlorian Westphal int flags = 0; 5195cbd886cSFlorian Westphal unsigned int last_hint = tcp_inq.last; 5205e6af0a7SFlorian Westphal int ret = recvmsg(fd, &msg, flags); 5215e6af0a7SFlorian Westphal 5225cbd886cSFlorian Westphal if (ret <= 0) { 5235cbd886cSFlorian Westphal if (ret == 0 && tcp_inq.expect_eof) 5245e6af0a7SFlorian Westphal return ret; 5255e6af0a7SFlorian Westphal 5265cbd886cSFlorian Westphal if (ret == 0 && cfg_cmsg_types.tcp_inq) 5275cbd886cSFlorian Westphal if (last_hint != 1 && last_hint != 0) 5285cbd886cSFlorian Westphal xerror("EOF but last tcp_inq hint was %u\n", last_hint); 5295cbd886cSFlorian Westphal 5305cbd886cSFlorian Westphal return ret; 5315cbd886cSFlorian Westphal } 5325cbd886cSFlorian Westphal 5335cbd886cSFlorian Westphal if (tcp_inq.expect_eof) 5345cbd886cSFlorian Westphal xerror("expected EOF, last_hint %u, now %u\n", 5355cbd886cSFlorian Westphal last_hint, tcp_inq.last); 5365cbd886cSFlorian Westphal 5375e6af0a7SFlorian Westphal if (msg.msg_controllen && !cfg_cmsg_types.cmsg_enabled) 5385e6af0a7SFlorian Westphal xerror("got %lu bytes of cmsg data, expected 0\n", 5395e6af0a7SFlorian Westphal (unsigned long)msg.msg_controllen); 5405e6af0a7SFlorian Westphal 5415e6af0a7SFlorian Westphal if (msg.msg_controllen == 0 && cfg_cmsg_types.cmsg_enabled) 5425e6af0a7SFlorian Westphal xerror("%s\n", "got no cmsg data"); 5435e6af0a7SFlorian Westphal 5445e6af0a7SFlorian Westphal if (msg.msg_controllen) 5455e6af0a7SFlorian Westphal process_cmsg(&msg); 5465e6af0a7SFlorian Westphal 5475cbd886cSFlorian Westphal if (cfg_cmsg_types.tcp_inq) { 5485cbd886cSFlorian Westphal if ((size_t)ret < len && last_hint > (unsigned int)ret) { 5495cbd886cSFlorian Westphal if (ret + 1 != (int)last_hint) { 5505cbd886cSFlorian Westphal int next = read(fd, msg_buf, sizeof(msg_buf)); 5515cbd886cSFlorian Westphal 5525cbd886cSFlorian Westphal xerror("read %u of %u, last_hint was %u tcp_inq hint now %u next_read returned %d/%m\n", 5535cbd886cSFlorian Westphal ret, (unsigned int)len, last_hint, tcp_inq.last, next); 5545cbd886cSFlorian Westphal } else { 5555cbd886cSFlorian Westphal tcp_inq.expect_eof = true; 5565cbd886cSFlorian Westphal } 5575cbd886cSFlorian Westphal } 5585cbd886cSFlorian Westphal } 5595cbd886cSFlorian Westphal 5605e6af0a7SFlorian Westphal return ret; 5615e6af0a7SFlorian Westphal } 5625e6af0a7SFlorian Westphal 563048d19d4SFlorian Westphal static ssize_t do_rnd_read(const int fd, char *buf, const size_t len) 564048d19d4SFlorian Westphal { 565df8aee6dSYonglong Li int ret = 0; 566df8aee6dSYonglong Li char tmp[16384]; 567048d19d4SFlorian Westphal size_t cap = rand(); 568048d19d4SFlorian Westphal 569048d19d4SFlorian Westphal cap &= 0xffff; 570048d19d4SFlorian Westphal 571048d19d4SFlorian Westphal if (cap == 0) 572048d19d4SFlorian Westphal cap = 1; 573048d19d4SFlorian Westphal else if (cap > len) 574048d19d4SFlorian Westphal cap = len; 575048d19d4SFlorian Westphal 576df8aee6dSYonglong Li if (cfg_peek == CFG_WITH_PEEK) { 577df8aee6dSYonglong Li ret = recv(fd, buf, cap, MSG_PEEK); 578df8aee6dSYonglong Li ret = (ret < 0) ? ret : read(fd, tmp, ret); 579df8aee6dSYonglong Li } else if (cfg_peek == CFG_AFTER_PEEK) { 580df8aee6dSYonglong Li ret = recv(fd, buf, cap, MSG_PEEK); 581df8aee6dSYonglong Li ret = (ret < 0) ? ret : read(fd, buf, cap); 5825e6af0a7SFlorian Westphal } else if (cfg_cmsg_types.cmsg_enabled) { 5835e6af0a7SFlorian Westphal ret = do_recvmsg_cmsg(fd, buf, cap); 584df8aee6dSYonglong Li } else { 585df8aee6dSYonglong Li ret = read(fd, buf, cap); 586df8aee6dSYonglong Li } 587df8aee6dSYonglong Li 588df8aee6dSYonglong Li return ret; 589048d19d4SFlorian Westphal } 590048d19d4SFlorian Westphal 59105be5e27SPaolo Abeni static void set_nonblock(int fd, bool nonblock) 592048d19d4SFlorian Westphal { 593048d19d4SFlorian Westphal int flags = fcntl(fd, F_GETFL); 594048d19d4SFlorian Westphal 595048d19d4SFlorian Westphal if (flags == -1) 596048d19d4SFlorian Westphal return; 597048d19d4SFlorian Westphal 59805be5e27SPaolo Abeni if (nonblock) 599048d19d4SFlorian Westphal fcntl(fd, F_SETFL, flags | O_NONBLOCK); 60005be5e27SPaolo Abeni else 60105be5e27SPaolo Abeni fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 602048d19d4SFlorian Westphal } 603048d19d4SFlorian Westphal 604df9e03aeSFlorian Westphal static void shut_wr(int fd) 605df9e03aeSFlorian Westphal { 606df9e03aeSFlorian Westphal /* Close our write side, ev. give some time 607df9e03aeSFlorian Westphal * for address notification and/or checking 608df9e03aeSFlorian Westphal * the current status 609df9e03aeSFlorian Westphal */ 610df9e03aeSFlorian Westphal if (cfg_wait) 611df9e03aeSFlorian Westphal usleep(cfg_wait); 612df9e03aeSFlorian Westphal 613df9e03aeSFlorian Westphal shutdown(fd, SHUT_WR); 614df9e03aeSFlorian Westphal } 615df9e03aeSFlorian Westphal 616ca7ae891SDmytro Shytyi static int copyfd_io_poll(int infd, int peerfd, int outfd, 617ca7ae891SDmytro Shytyi bool *in_closed_after_out, struct wstate *winfo) 618048d19d4SFlorian Westphal { 619048d19d4SFlorian Westphal struct pollfd fds = { 620048d19d4SFlorian Westphal .fd = peerfd, 621048d19d4SFlorian Westphal .events = POLLIN | POLLOUT, 622048d19d4SFlorian Westphal }; 623ca7ae891SDmytro Shytyi unsigned int total_wlen = 0, total_rlen = 0; 624048d19d4SFlorian Westphal 62505be5e27SPaolo Abeni set_nonblock(peerfd, true); 626048d19d4SFlorian Westphal 627048d19d4SFlorian Westphal for (;;) { 628048d19d4SFlorian Westphal char rbuf[8192]; 629048d19d4SFlorian Westphal ssize_t len; 630048d19d4SFlorian Westphal 6314a753ca5SMenglong Dong if (fds.events == 0 || quit) 632048d19d4SFlorian Westphal break; 633048d19d4SFlorian Westphal 634048d19d4SFlorian Westphal switch (poll(&fds, 1, poll_timeout)) { 635048d19d4SFlorian Westphal case -1: 636048d19d4SFlorian Westphal if (errno == EINTR) 637048d19d4SFlorian Westphal continue; 638048d19d4SFlorian Westphal perror("poll"); 639048d19d4SFlorian Westphal return 1; 640048d19d4SFlorian Westphal case 0: 641048d19d4SFlorian Westphal fprintf(stderr, "%s: poll timed out (events: " 642048d19d4SFlorian Westphal "POLLIN %u, POLLOUT %u)\n", __func__, 643048d19d4SFlorian Westphal fds.events & POLLIN, fds.events & POLLOUT); 644048d19d4SFlorian Westphal return 2; 645048d19d4SFlorian Westphal } 646048d19d4SFlorian Westphal 647048d19d4SFlorian Westphal if (fds.revents & POLLIN) { 6486bf41020SPaolo Abeni ssize_t rb = sizeof(rbuf); 6496bf41020SPaolo Abeni 6506bf41020SPaolo Abeni /* limit the total amount of read data to the trunc value*/ 6516bf41020SPaolo Abeni if (cfg_truncate > 0) { 6526bf41020SPaolo Abeni if (rb + total_rlen > cfg_truncate) 6536bf41020SPaolo Abeni rb = cfg_truncate - total_rlen; 6546bf41020SPaolo Abeni len = read(peerfd, rbuf, rb); 6556bf41020SPaolo Abeni } else { 656048d19d4SFlorian Westphal len = do_rnd_read(peerfd, rbuf, sizeof(rbuf)); 6576bf41020SPaolo Abeni } 658048d19d4SFlorian Westphal if (len == 0) { 659048d19d4SFlorian Westphal /* no more data to receive: 660048d19d4SFlorian Westphal * peer has closed its write side 661048d19d4SFlorian Westphal */ 662048d19d4SFlorian Westphal fds.events &= ~POLLIN; 663048d19d4SFlorian Westphal 664b6ab64b0SPaolo Abeni if ((fds.events & POLLOUT) == 0) { 665b6ab64b0SPaolo Abeni *in_closed_after_out = true; 666048d19d4SFlorian Westphal /* and nothing more to send */ 667048d19d4SFlorian Westphal break; 668b6ab64b0SPaolo Abeni } 669048d19d4SFlorian Westphal 670048d19d4SFlorian Westphal /* Else, still have data to transmit */ 671048d19d4SFlorian Westphal } else if (len < 0) { 6726bf41020SPaolo Abeni if (cfg_rcv_trunc) 6736bf41020SPaolo Abeni return 0; 674048d19d4SFlorian Westphal perror("read"); 675048d19d4SFlorian Westphal return 3; 676048d19d4SFlorian Westphal } 677048d19d4SFlorian Westphal 6786bf41020SPaolo Abeni total_rlen += len; 679048d19d4SFlorian Westphal do_write(outfd, rbuf, len); 680048d19d4SFlorian Westphal } 681048d19d4SFlorian Westphal 682048d19d4SFlorian Westphal if (fds.revents & POLLOUT) { 683ca7ae891SDmytro Shytyi if (winfo->len == 0) { 684ca7ae891SDmytro Shytyi winfo->off = 0; 685ca7ae891SDmytro Shytyi winfo->len = read(infd, winfo->buf, sizeof(winfo->buf)); 686048d19d4SFlorian Westphal } 687048d19d4SFlorian Westphal 688ca7ae891SDmytro Shytyi if (winfo->len > 0) { 689048d19d4SFlorian Westphal ssize_t bw; 690048d19d4SFlorian Westphal 6916bf41020SPaolo Abeni /* limit the total amount of written data to the trunc value */ 692ca7ae891SDmytro Shytyi if (cfg_truncate > 0 && winfo->len + total_wlen > cfg_truncate) 693ca7ae891SDmytro Shytyi winfo->len = cfg_truncate - total_wlen; 6946bf41020SPaolo Abeni 695ca7ae891SDmytro Shytyi bw = do_rnd_write(peerfd, winfo->buf + winfo->off, winfo->len); 6966bf41020SPaolo Abeni if (bw < 0) { 6976bf41020SPaolo Abeni if (cfg_rcv_trunc) 6986bf41020SPaolo Abeni return 0; 6996bf41020SPaolo Abeni perror("write"); 700048d19d4SFlorian Westphal return 111; 7016bf41020SPaolo Abeni } 702048d19d4SFlorian Westphal 703ca7ae891SDmytro Shytyi winfo->off += bw; 704ca7ae891SDmytro Shytyi winfo->len -= bw; 7056bf41020SPaolo Abeni total_wlen += bw; 706ca7ae891SDmytro Shytyi } else if (winfo->len == 0) { 707048d19d4SFlorian Westphal /* We have no more data to send. */ 708048d19d4SFlorian Westphal fds.events &= ~POLLOUT; 709048d19d4SFlorian Westphal 710048d19d4SFlorian Westphal if ((fds.events & POLLIN) == 0) 711048d19d4SFlorian Westphal /* ... and peer also closed already */ 712048d19d4SFlorian Westphal break; 713048d19d4SFlorian Westphal 714df9e03aeSFlorian Westphal shut_wr(peerfd); 715048d19d4SFlorian Westphal } else { 716048d19d4SFlorian Westphal if (errno == EINTR) 717048d19d4SFlorian Westphal continue; 718048d19d4SFlorian Westphal perror("read"); 719048d19d4SFlorian Westphal return 4; 720048d19d4SFlorian Westphal } 721048d19d4SFlorian Westphal } 722048d19d4SFlorian Westphal 723048d19d4SFlorian Westphal if (fds.revents & (POLLERR | POLLNVAL)) { 7246bf41020SPaolo Abeni if (cfg_rcv_trunc) 7256bf41020SPaolo Abeni return 0; 726048d19d4SFlorian Westphal fprintf(stderr, "Unexpected revents: " 727048d19d4SFlorian Westphal "POLLERR/POLLNVAL(%x)\n", fds.revents); 728048d19d4SFlorian Westphal return 5; 729048d19d4SFlorian Westphal } 7306bf41020SPaolo Abeni 7316bf41020SPaolo Abeni if (cfg_truncate > 0 && total_wlen >= cfg_truncate && 7326bf41020SPaolo Abeni total_rlen >= cfg_truncate) 7336bf41020SPaolo Abeni break; 734048d19d4SFlorian Westphal } 735048d19d4SFlorian Westphal 736b08fbf24SPaolo Abeni /* leave some time for late join/announce */ 7374a753ca5SMenglong Dong if (cfg_remove && !quit) 738df62f2ecSPaolo Abeni usleep(cfg_wait); 739b08fbf24SPaolo Abeni 740048d19d4SFlorian Westphal return 0; 741048d19d4SFlorian Westphal } 742048d19d4SFlorian Westphal 743048d19d4SFlorian Westphal static int do_recvfile(int infd, int outfd) 744048d19d4SFlorian Westphal { 745048d19d4SFlorian Westphal ssize_t r; 746048d19d4SFlorian Westphal 747048d19d4SFlorian Westphal do { 748048d19d4SFlorian Westphal char buf[16384]; 749048d19d4SFlorian Westphal 750048d19d4SFlorian Westphal r = do_rnd_read(infd, buf, sizeof(buf)); 751048d19d4SFlorian Westphal if (r > 0) { 752048d19d4SFlorian Westphal if (write(outfd, buf, r) != r) 753048d19d4SFlorian Westphal break; 754048d19d4SFlorian Westphal } else if (r < 0) { 755048d19d4SFlorian Westphal perror("read"); 756048d19d4SFlorian Westphal } 757048d19d4SFlorian Westphal } while (r > 0); 758048d19d4SFlorian Westphal 759048d19d4SFlorian Westphal return (int)r; 760048d19d4SFlorian Westphal } 761048d19d4SFlorian Westphal 762ca7ae891SDmytro Shytyi static int spool_buf(int fd, struct wstate *winfo) 763ca7ae891SDmytro Shytyi { 764ca7ae891SDmytro Shytyi while (winfo->len) { 765ca7ae891SDmytro Shytyi int ret = write(fd, winfo->buf + winfo->off, winfo->len); 766ca7ae891SDmytro Shytyi 767ca7ae891SDmytro Shytyi if (ret < 0) { 768ca7ae891SDmytro Shytyi perror("write"); 769ca7ae891SDmytro Shytyi return 4; 770ca7ae891SDmytro Shytyi } 771ca7ae891SDmytro Shytyi winfo->off += ret; 772ca7ae891SDmytro Shytyi winfo->len -= ret; 773ca7ae891SDmytro Shytyi } 774ca7ae891SDmytro Shytyi return 0; 775ca7ae891SDmytro Shytyi } 776ca7ae891SDmytro Shytyi 777ca7ae891SDmytro Shytyi static int do_mmap(int infd, int outfd, unsigned int size, 778ca7ae891SDmytro Shytyi struct wstate *winfo) 779048d19d4SFlorian Westphal { 780048d19d4SFlorian Westphal char *inbuf = mmap(NULL, size, PROT_READ, MAP_SHARED, infd, 0); 781ca7ae891SDmytro Shytyi ssize_t ret = 0, off = winfo->total_len; 782048d19d4SFlorian Westphal size_t rem; 783048d19d4SFlorian Westphal 784048d19d4SFlorian Westphal if (inbuf == MAP_FAILED) { 785048d19d4SFlorian Westphal perror("mmap"); 786048d19d4SFlorian Westphal return 1; 787048d19d4SFlorian Westphal } 788048d19d4SFlorian Westphal 789ca7ae891SDmytro Shytyi ret = spool_buf(outfd, winfo); 790ca7ae891SDmytro Shytyi if (ret < 0) 791ca7ae891SDmytro Shytyi return ret; 792ca7ae891SDmytro Shytyi 793ca7ae891SDmytro Shytyi rem = size - winfo->total_len; 794048d19d4SFlorian Westphal 795048d19d4SFlorian Westphal while (rem > 0) { 796048d19d4SFlorian Westphal ret = write(outfd, inbuf + off, rem); 797048d19d4SFlorian Westphal 798048d19d4SFlorian Westphal if (ret < 0) { 799048d19d4SFlorian Westphal perror("write"); 800048d19d4SFlorian Westphal break; 801048d19d4SFlorian Westphal } 802048d19d4SFlorian Westphal 803048d19d4SFlorian Westphal off += ret; 804048d19d4SFlorian Westphal rem -= ret; 805048d19d4SFlorian Westphal } 806048d19d4SFlorian Westphal 807048d19d4SFlorian Westphal munmap(inbuf, size); 808048d19d4SFlorian Westphal return rem; 809048d19d4SFlorian Westphal } 810048d19d4SFlorian Westphal 811048d19d4SFlorian Westphal static int get_infd_size(int fd) 812048d19d4SFlorian Westphal { 813048d19d4SFlorian Westphal struct stat sb; 814048d19d4SFlorian Westphal ssize_t count; 815048d19d4SFlorian Westphal int err; 816048d19d4SFlorian Westphal 817048d19d4SFlorian Westphal err = fstat(fd, &sb); 818048d19d4SFlorian Westphal if (err < 0) { 819048d19d4SFlorian Westphal perror("fstat"); 820048d19d4SFlorian Westphal return -1; 821048d19d4SFlorian Westphal } 822048d19d4SFlorian Westphal 823048d19d4SFlorian Westphal if ((sb.st_mode & S_IFMT) != S_IFREG) { 824048d19d4SFlorian Westphal fprintf(stderr, "%s: stdin is not a regular file\n", __func__); 825048d19d4SFlorian Westphal return -2; 826048d19d4SFlorian Westphal } 827048d19d4SFlorian Westphal 828048d19d4SFlorian Westphal count = sb.st_size; 829048d19d4SFlorian Westphal if (count > INT_MAX) { 830048d19d4SFlorian Westphal fprintf(stderr, "File too large: %zu\n", count); 831048d19d4SFlorian Westphal return -3; 832048d19d4SFlorian Westphal } 833048d19d4SFlorian Westphal 834048d19d4SFlorian Westphal return (int)count; 835048d19d4SFlorian Westphal } 836048d19d4SFlorian Westphal 837ca7ae891SDmytro Shytyi static int do_sendfile(int infd, int outfd, unsigned int count, 838ca7ae891SDmytro Shytyi struct wstate *winfo) 839048d19d4SFlorian Westphal { 840ca7ae891SDmytro Shytyi int ret = spool_buf(outfd, winfo); 841ca7ae891SDmytro Shytyi 842ca7ae891SDmytro Shytyi if (ret < 0) 843ca7ae891SDmytro Shytyi return ret; 844ca7ae891SDmytro Shytyi 845ca7ae891SDmytro Shytyi count -= winfo->total_len; 846ca7ae891SDmytro Shytyi 847048d19d4SFlorian Westphal while (count > 0) { 848048d19d4SFlorian Westphal ssize_t r; 849048d19d4SFlorian Westphal 850048d19d4SFlorian Westphal r = sendfile(outfd, infd, NULL, count); 851048d19d4SFlorian Westphal if (r < 0) { 852048d19d4SFlorian Westphal perror("sendfile"); 853048d19d4SFlorian Westphal return 3; 854048d19d4SFlorian Westphal } 855048d19d4SFlorian Westphal 856048d19d4SFlorian Westphal count -= r; 857048d19d4SFlorian Westphal } 858048d19d4SFlorian Westphal 859048d19d4SFlorian Westphal return 0; 860048d19d4SFlorian Westphal } 861048d19d4SFlorian Westphal 862048d19d4SFlorian Westphal static int copyfd_io_mmap(int infd, int peerfd, int outfd, 863ca7ae891SDmytro Shytyi unsigned int size, bool *in_closed_after_out, 864ca7ae891SDmytro Shytyi struct wstate *winfo) 865048d19d4SFlorian Westphal { 866048d19d4SFlorian Westphal int err; 867048d19d4SFlorian Westphal 868048d19d4SFlorian Westphal if (listen_mode) { 869048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 870048d19d4SFlorian Westphal if (err) 871048d19d4SFlorian Westphal return err; 872048d19d4SFlorian Westphal 873ca7ae891SDmytro Shytyi err = do_mmap(infd, peerfd, size, winfo); 874048d19d4SFlorian Westphal } else { 875ca7ae891SDmytro Shytyi err = do_mmap(infd, peerfd, size, winfo); 876048d19d4SFlorian Westphal if (err) 877048d19d4SFlorian Westphal return err; 878048d19d4SFlorian Westphal 879df9e03aeSFlorian Westphal shut_wr(peerfd); 880048d19d4SFlorian Westphal 881048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 882b6ab64b0SPaolo Abeni *in_closed_after_out = true; 883048d19d4SFlorian Westphal } 884048d19d4SFlorian Westphal 885048d19d4SFlorian Westphal return err; 886048d19d4SFlorian Westphal } 887048d19d4SFlorian Westphal 888048d19d4SFlorian Westphal static int copyfd_io_sendfile(int infd, int peerfd, int outfd, 889ca7ae891SDmytro Shytyi unsigned int size, bool *in_closed_after_out, struct wstate *winfo) 890048d19d4SFlorian Westphal { 891048d19d4SFlorian Westphal int err; 892048d19d4SFlorian Westphal 893048d19d4SFlorian Westphal if (listen_mode) { 894048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 895048d19d4SFlorian Westphal if (err) 896048d19d4SFlorian Westphal return err; 897048d19d4SFlorian Westphal 898ca7ae891SDmytro Shytyi err = do_sendfile(infd, peerfd, size, winfo); 899048d19d4SFlorian Westphal } else { 900ca7ae891SDmytro Shytyi err = do_sendfile(infd, peerfd, size, winfo); 901048d19d4SFlorian Westphal if (err) 902048d19d4SFlorian Westphal return err; 903df9e03aeSFlorian Westphal 904df9e03aeSFlorian Westphal shut_wr(peerfd); 905df9e03aeSFlorian Westphal 906048d19d4SFlorian Westphal err = do_recvfile(peerfd, outfd); 907b6ab64b0SPaolo Abeni *in_closed_after_out = true; 908048d19d4SFlorian Westphal } 909048d19d4SFlorian Westphal 910048d19d4SFlorian Westphal return err; 911048d19d4SFlorian Westphal } 912048d19d4SFlorian Westphal 913ca7ae891SDmytro Shytyi static int copyfd_io(int infd, int peerfd, int outfd, bool close_peerfd, struct wstate *winfo) 914048d19d4SFlorian Westphal { 915b6ab64b0SPaolo Abeni bool in_closed_after_out = false; 916b6ab64b0SPaolo Abeni struct timespec start, end; 917048d19d4SFlorian Westphal int file_size; 918b6ab64b0SPaolo Abeni int ret; 919b6ab64b0SPaolo Abeni 920b6ab64b0SPaolo Abeni if (cfg_time && (clock_gettime(CLOCK_MONOTONIC, &start) < 0)) 921b6ab64b0SPaolo Abeni xerror("can not fetch start time %d", errno); 922048d19d4SFlorian Westphal 923048d19d4SFlorian Westphal switch (cfg_mode) { 924048d19d4SFlorian Westphal case CFG_MODE_POLL: 925ca7ae891SDmytro Shytyi ret = copyfd_io_poll(infd, peerfd, outfd, &in_closed_after_out, 926ca7ae891SDmytro Shytyi winfo); 927b6ab64b0SPaolo Abeni break; 928b6ab64b0SPaolo Abeni 929048d19d4SFlorian Westphal case CFG_MODE_MMAP: 930048d19d4SFlorian Westphal file_size = get_infd_size(infd); 931048d19d4SFlorian Westphal if (file_size < 0) 932048d19d4SFlorian Westphal return file_size; 933ca7ae891SDmytro Shytyi ret = copyfd_io_mmap(infd, peerfd, outfd, file_size, 934ca7ae891SDmytro Shytyi &in_closed_after_out, winfo); 935b6ab64b0SPaolo Abeni break; 936b6ab64b0SPaolo Abeni 937048d19d4SFlorian Westphal case CFG_MODE_SENDFILE: 938048d19d4SFlorian Westphal file_size = get_infd_size(infd); 939048d19d4SFlorian Westphal if (file_size < 0) 940048d19d4SFlorian Westphal return file_size; 941ca7ae891SDmytro Shytyi ret = copyfd_io_sendfile(infd, peerfd, outfd, file_size, 942ca7ae891SDmytro Shytyi &in_closed_after_out, winfo); 943b6ab64b0SPaolo Abeni break; 944048d19d4SFlorian Westphal 945b6ab64b0SPaolo Abeni default: 946048d19d4SFlorian Westphal fprintf(stderr, "Invalid mode %d\n", cfg_mode); 947048d19d4SFlorian Westphal 948048d19d4SFlorian Westphal die_usage(); 949048d19d4SFlorian Westphal return 1; 950048d19d4SFlorian Westphal } 951048d19d4SFlorian Westphal 952b6ab64b0SPaolo Abeni if (ret) 953b6ab64b0SPaolo Abeni return ret; 954b6ab64b0SPaolo Abeni 95505be5e27SPaolo Abeni if (close_peerfd) 95605be5e27SPaolo Abeni close(peerfd); 95705be5e27SPaolo Abeni 958b6ab64b0SPaolo Abeni if (cfg_time) { 959b6ab64b0SPaolo Abeni unsigned int delta_ms; 960b6ab64b0SPaolo Abeni 961b6ab64b0SPaolo Abeni if (clock_gettime(CLOCK_MONOTONIC, &end) < 0) 962b6ab64b0SPaolo Abeni xerror("can not fetch end time %d", errno); 963b6ab64b0SPaolo Abeni delta_ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000; 964b6ab64b0SPaolo Abeni if (delta_ms > cfg_time) { 965b6ab64b0SPaolo Abeni xerror("transfer slower than expected! runtime %d ms, expected %d ms", 966b6ab64b0SPaolo Abeni delta_ms, cfg_time); 967b6ab64b0SPaolo Abeni } 968b6ab64b0SPaolo Abeni 969b6ab64b0SPaolo Abeni /* show the runtime only if this end shutdown(wr) before receiving the EOF, 970b6ab64b0SPaolo Abeni * (that is, if this end got the longer runtime) 971b6ab64b0SPaolo Abeni */ 972b6ab64b0SPaolo Abeni if (in_closed_after_out) 973b6ab64b0SPaolo Abeni fprintf(stderr, "%d", delta_ms); 974b6ab64b0SPaolo Abeni } 975b6ab64b0SPaolo Abeni 976b6ab64b0SPaolo Abeni return 0; 977b6ab64b0SPaolo Abeni } 978b6ab64b0SPaolo Abeni 979048d19d4SFlorian Westphal static void check_sockaddr(int pf, struct sockaddr_storage *ss, 980048d19d4SFlorian Westphal socklen_t salen) 981048d19d4SFlorian Westphal { 982048d19d4SFlorian Westphal struct sockaddr_in6 *sin6; 983048d19d4SFlorian Westphal struct sockaddr_in *sin; 984048d19d4SFlorian Westphal socklen_t wanted_size = 0; 985048d19d4SFlorian Westphal 986048d19d4SFlorian Westphal switch (pf) { 987048d19d4SFlorian Westphal case AF_INET: 988048d19d4SFlorian Westphal wanted_size = sizeof(*sin); 989048d19d4SFlorian Westphal sin = (void *)ss; 990048d19d4SFlorian Westphal if (!sin->sin_port) 991048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ip connection from port 0"); 992048d19d4SFlorian Westphal break; 993048d19d4SFlorian Westphal case AF_INET6: 994048d19d4SFlorian Westphal wanted_size = sizeof(*sin6); 995048d19d4SFlorian Westphal sin6 = (void *)ss; 996048d19d4SFlorian Westphal if (!sin6->sin6_port) 997048d19d4SFlorian Westphal fprintf(stderr, "accept: something wrong: ipv6 connection from port 0"); 998048d19d4SFlorian Westphal break; 999048d19d4SFlorian Westphal default: 1000048d19d4SFlorian Westphal fprintf(stderr, "accept: Unknown pf %d, salen %u\n", pf, salen); 1001048d19d4SFlorian Westphal return; 1002048d19d4SFlorian Westphal } 1003048d19d4SFlorian Westphal 1004048d19d4SFlorian Westphal if (salen != wanted_size) 1005048d19d4SFlorian Westphal fprintf(stderr, "accept: size mismatch, got %d expected %d\n", 1006048d19d4SFlorian Westphal (int)salen, wanted_size); 1007048d19d4SFlorian Westphal 1008048d19d4SFlorian Westphal if (ss->ss_family != pf) 1009048d19d4SFlorian Westphal fprintf(stderr, "accept: pf mismatch, expect %d, ss_family is %d\n", 1010048d19d4SFlorian Westphal (int)ss->ss_family, pf); 1011048d19d4SFlorian Westphal } 1012048d19d4SFlorian Westphal 1013048d19d4SFlorian Westphal static void check_getpeername(int fd, struct sockaddr_storage *ss, socklen_t salen) 1014048d19d4SFlorian Westphal { 1015048d19d4SFlorian Westphal struct sockaddr_storage peerss; 1016048d19d4SFlorian Westphal socklen_t peersalen = sizeof(peerss); 1017048d19d4SFlorian Westphal 1018048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&peerss, &peersalen) < 0) { 1019048d19d4SFlorian Westphal perror("getpeername"); 1020048d19d4SFlorian Westphal return; 1021048d19d4SFlorian Westphal } 1022048d19d4SFlorian Westphal 1023048d19d4SFlorian Westphal if (peersalen != salen) { 1024048d19d4SFlorian Westphal fprintf(stderr, "%s: %d vs %d\n", __func__, peersalen, salen); 1025048d19d4SFlorian Westphal return; 1026048d19d4SFlorian Westphal } 1027048d19d4SFlorian Westphal 1028048d19d4SFlorian Westphal if (memcmp(ss, &peerss, peersalen)) { 1029048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 1030048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 1031048d19d4SFlorian Westphal char c[INET6_ADDRSTRLEN]; 1032048d19d4SFlorian Westphal char d[INET6_ADDRSTRLEN]; 1033048d19d4SFlorian Westphal 1034048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)ss, salen, 1035048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 1036048d19d4SFlorian Westphal 1037048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&peerss, peersalen, 1038048d19d4SFlorian Westphal c, sizeof(c), d, sizeof(d)); 1039048d19d4SFlorian Westphal 1040048d19d4SFlorian Westphal fprintf(stderr, "%s: memcmp failure: accept %s vs peername %s, %s vs %s salen %d vs %d\n", 1041048d19d4SFlorian Westphal __func__, a, c, b, d, peersalen, salen); 1042048d19d4SFlorian Westphal } 1043048d19d4SFlorian Westphal } 1044048d19d4SFlorian Westphal 1045048d19d4SFlorian Westphal static void check_getpeername_connect(int fd) 1046048d19d4SFlorian Westphal { 1047048d19d4SFlorian Westphal struct sockaddr_storage ss; 1048048d19d4SFlorian Westphal socklen_t salen = sizeof(ss); 1049048d19d4SFlorian Westphal char a[INET6_ADDRSTRLEN]; 1050048d19d4SFlorian Westphal char b[INET6_ADDRSTRLEN]; 1051048d19d4SFlorian Westphal 1052048d19d4SFlorian Westphal if (getpeername(fd, (struct sockaddr *)&ss, &salen) < 0) { 1053048d19d4SFlorian Westphal perror("getpeername"); 1054048d19d4SFlorian Westphal return; 1055048d19d4SFlorian Westphal } 1056048d19d4SFlorian Westphal 1057048d19d4SFlorian Westphal xgetnameinfo((struct sockaddr *)&ss, salen, 1058048d19d4SFlorian Westphal a, sizeof(a), b, sizeof(b)); 1059048d19d4SFlorian Westphal 1060048d19d4SFlorian Westphal if (strcmp(cfg_host, a) || strcmp(cfg_port, b)) 1061048d19d4SFlorian Westphal fprintf(stderr, "%s: %s vs %s, %s vs %s\n", __func__, 1062048d19d4SFlorian Westphal cfg_host, a, cfg_port, b); 1063048d19d4SFlorian Westphal } 1064048d19d4SFlorian Westphal 1065b0519de8SFlorian Westphal static void maybe_close(int fd) 1066b0519de8SFlorian Westphal { 1067b0519de8SFlorian Westphal unsigned int r = rand(); 1068b0519de8SFlorian Westphal 106905be5e27SPaolo Abeni if (!(cfg_join || cfg_remove || cfg_repeat > 1) && (r & 1)) 1070b0519de8SFlorian Westphal close(fd); 1071b0519de8SFlorian Westphal } 1072b0519de8SFlorian Westphal 1073048d19d4SFlorian Westphal int main_loop_s(int listensock) 1074048d19d4SFlorian Westphal { 1075048d19d4SFlorian Westphal struct sockaddr_storage ss; 1076ca7ae891SDmytro Shytyi struct wstate winfo; 1077048d19d4SFlorian Westphal struct pollfd polls; 1078048d19d4SFlorian Westphal socklen_t salen; 1079048d19d4SFlorian Westphal int remotesock; 108005be5e27SPaolo Abeni int fd = 0; 1081048d19d4SFlorian Westphal 108205be5e27SPaolo Abeni again: 1083048d19d4SFlorian Westphal polls.fd = listensock; 1084048d19d4SFlorian Westphal polls.events = POLLIN; 1085048d19d4SFlorian Westphal 1086048d19d4SFlorian Westphal switch (poll(&polls, 1, poll_timeout)) { 1087048d19d4SFlorian Westphal case -1: 1088048d19d4SFlorian Westphal perror("poll"); 1089048d19d4SFlorian Westphal return 1; 1090048d19d4SFlorian Westphal case 0: 1091048d19d4SFlorian Westphal fprintf(stderr, "%s: timed out\n", __func__); 1092048d19d4SFlorian Westphal close(listensock); 1093048d19d4SFlorian Westphal return 2; 1094048d19d4SFlorian Westphal } 1095048d19d4SFlorian Westphal 1096048d19d4SFlorian Westphal salen = sizeof(ss); 1097048d19d4SFlorian Westphal remotesock = accept(listensock, (struct sockaddr *)&ss, &salen); 1098048d19d4SFlorian Westphal if (remotesock >= 0) { 1099b0519de8SFlorian Westphal maybe_close(listensock); 1100048d19d4SFlorian Westphal check_sockaddr(pf, &ss, salen); 1101048d19d4SFlorian Westphal check_getpeername(remotesock, &ss, salen); 1102048d19d4SFlorian Westphal 110305be5e27SPaolo Abeni if (cfg_input) { 110405be5e27SPaolo Abeni fd = open(cfg_input, O_RDONLY); 110505be5e27SPaolo Abeni if (fd < 0) 110605be5e27SPaolo Abeni xerror("can't open %s: %d", cfg_input, errno); 1107048d19d4SFlorian Westphal } 1108048d19d4SFlorian Westphal 110905be5e27SPaolo Abeni SOCK_TEST_TCPULP(remotesock, 0); 1110048d19d4SFlorian Westphal 1111ca7ae891SDmytro Shytyi memset(&winfo, 0, sizeof(winfo)); 1112ca7ae891SDmytro Shytyi copyfd_io(fd, remotesock, 1, true, &winfo); 111305be5e27SPaolo Abeni } else { 111405be5e27SPaolo Abeni perror("accept"); 1115048d19d4SFlorian Westphal return 1; 1116048d19d4SFlorian Westphal } 1117048d19d4SFlorian Westphal 111805be5e27SPaolo Abeni if (cfg_input) 111905be5e27SPaolo Abeni close(fd); 1120*ffe8c864SLiu Jing 1121*ffe8c864SLiu Jing if (--cfg_repeat > 0) 112205be5e27SPaolo Abeni goto again; 112305be5e27SPaolo Abeni 112405be5e27SPaolo Abeni return 0; 112505be5e27SPaolo Abeni } 112605be5e27SPaolo Abeni 1127048d19d4SFlorian Westphal static void init_rng(void) 1128048d19d4SFlorian Westphal { 1129048d19d4SFlorian Westphal unsigned int foo; 1130048d19d4SFlorian Westphal 113120bb3a96SWillem de Bruijn if (getrandom(&foo, sizeof(foo), 0) == -1) { 113220bb3a96SWillem de Bruijn perror("getrandom"); 113320bb3a96SWillem de Bruijn exit(1); 1134048d19d4SFlorian Westphal } 1135048d19d4SFlorian Westphal 1136048d19d4SFlorian Westphal srand(foo); 1137048d19d4SFlorian Westphal } 1138048d19d4SFlorian Westphal 11395e6af0a7SFlorian Westphal static void xsetsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) 11405e6af0a7SFlorian Westphal { 11415e6af0a7SFlorian Westphal int err; 11425e6af0a7SFlorian Westphal 11435e6af0a7SFlorian Westphal err = setsockopt(fd, level, optname, optval, optlen); 11445e6af0a7SFlorian Westphal if (err) { 11455e6af0a7SFlorian Westphal perror("setsockopt"); 11465e6af0a7SFlorian Westphal exit(1); 11475e6af0a7SFlorian Westphal } 11485e6af0a7SFlorian Westphal } 11495e6af0a7SFlorian Westphal 11505e6af0a7SFlorian Westphal static void apply_cmsg_types(int fd, const struct cfg_cmsg_types *cmsg) 11515e6af0a7SFlorian Westphal { 11525e6af0a7SFlorian Westphal static const unsigned int on = 1; 11535e6af0a7SFlorian Westphal 11545e6af0a7SFlorian Westphal if (cmsg->timestampns) 11555e6af0a7SFlorian Westphal xsetsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW, &on, sizeof(on)); 11565cbd886cSFlorian Westphal if (cmsg->tcp_inq) 11575cbd886cSFlorian Westphal xsetsockopt(fd, IPPROTO_TCP, TCP_INQ, &on, sizeof(on)); 11585e6af0a7SFlorian Westphal } 11595e6af0a7SFlorian Westphal 11605e6af0a7SFlorian Westphal static void parse_cmsg_types(const char *type) 11615e6af0a7SFlorian Westphal { 11625e6af0a7SFlorian Westphal char *next = strchr(type, ','); 11635e6af0a7SFlorian Westphal unsigned int len = 0; 11645e6af0a7SFlorian Westphal 11655e6af0a7SFlorian Westphal cfg_cmsg_types.cmsg_enabled = 1; 11665e6af0a7SFlorian Westphal 11675e6af0a7SFlorian Westphal if (next) { 11685e6af0a7SFlorian Westphal parse_cmsg_types(next + 1); 11695e6af0a7SFlorian Westphal len = next - type; 11705e6af0a7SFlorian Westphal } else { 11715e6af0a7SFlorian Westphal len = strlen(type); 11725e6af0a7SFlorian Westphal } 11735e6af0a7SFlorian Westphal 11745e6af0a7SFlorian Westphal if (strncmp(type, "TIMESTAMPNS", len) == 0) { 11755e6af0a7SFlorian Westphal cfg_cmsg_types.timestampns = 1; 11765e6af0a7SFlorian Westphal return; 11775e6af0a7SFlorian Westphal } 11785e6af0a7SFlorian Westphal 11795cbd886cSFlorian Westphal if (strncmp(type, "TCPINQ", len) == 0) { 11805cbd886cSFlorian Westphal cfg_cmsg_types.tcp_inq = 1; 11815cbd886cSFlorian Westphal return; 11825cbd886cSFlorian Westphal } 11835cbd886cSFlorian Westphal 11845e6af0a7SFlorian Westphal fprintf(stderr, "Unrecognized cmsg option %s\n", type); 11855e6af0a7SFlorian Westphal exit(1); 11865e6af0a7SFlorian Westphal } 11875e6af0a7SFlorian Westphal 11885fb62e9cSFlorian Westphal static void parse_setsock_options(const char *name) 11895fb62e9cSFlorian Westphal { 11905fb62e9cSFlorian Westphal char *next = strchr(name, ','); 11915fb62e9cSFlorian Westphal unsigned int len = 0; 11925fb62e9cSFlorian Westphal 11935fb62e9cSFlorian Westphal if (next) { 11945fb62e9cSFlorian Westphal parse_setsock_options(next + 1); 11955fb62e9cSFlorian Westphal len = next - name; 11965fb62e9cSFlorian Westphal } else { 11975fb62e9cSFlorian Westphal len = strlen(name); 11985fb62e9cSFlorian Westphal } 11995fb62e9cSFlorian Westphal 12005fb62e9cSFlorian Westphal if (strncmp(name, "TRANSPARENT", len) == 0) { 12015fb62e9cSFlorian Westphal cfg_sockopt_types.transparent = 1; 12025fb62e9cSFlorian Westphal return; 12035fb62e9cSFlorian Westphal } 12045fb62e9cSFlorian Westphal 1205ca7ae891SDmytro Shytyi if (strncmp(name, "MPTFO", len) == 0) { 1206ca7ae891SDmytro Shytyi cfg_sockopt_types.mptfo = 1; 1207ca7ae891SDmytro Shytyi return; 1208ca7ae891SDmytro Shytyi } 1209ca7ae891SDmytro Shytyi 12105fb62e9cSFlorian Westphal fprintf(stderr, "Unrecognized setsockopt option %s\n", name); 12115fb62e9cSFlorian Westphal exit(1); 12125fb62e9cSFlorian Westphal } 12135fb62e9cSFlorian Westphal 121405be5e27SPaolo Abeni void xdisconnect(int fd, int addrlen) 121505be5e27SPaolo Abeni { 121605be5e27SPaolo Abeni struct sockaddr_storage empty; 121705be5e27SPaolo Abeni int msec_sleep = 10; 121805be5e27SPaolo Abeni int queued = 1; 121905be5e27SPaolo Abeni int i; 122005be5e27SPaolo Abeni 122105be5e27SPaolo Abeni shutdown(fd, SHUT_WR); 122205be5e27SPaolo Abeni 122305be5e27SPaolo Abeni /* while until the pending data is completely flushed, the later 122405be5e27SPaolo Abeni * disconnect will bypass/ignore/drop any pending data. 122505be5e27SPaolo Abeni */ 122605be5e27SPaolo Abeni for (i = 0; ; i += msec_sleep) { 122705be5e27SPaolo Abeni if (ioctl(fd, SIOCOUTQ, &queued) < 0) 122805be5e27SPaolo Abeni xerror("can't query out socket queue: %d", errno); 122905be5e27SPaolo Abeni 123005be5e27SPaolo Abeni if (!queued) 123105be5e27SPaolo Abeni break; 123205be5e27SPaolo Abeni 123305be5e27SPaolo Abeni if (i > poll_timeout) 123405be5e27SPaolo Abeni xerror("timeout while waiting for spool to complete"); 123505be5e27SPaolo Abeni usleep(msec_sleep * 1000); 123605be5e27SPaolo Abeni } 123705be5e27SPaolo Abeni 123805be5e27SPaolo Abeni memset(&empty, 0, sizeof(empty)); 123905be5e27SPaolo Abeni empty.ss_family = AF_UNSPEC; 124005be5e27SPaolo Abeni if (connect(fd, (struct sockaddr *)&empty, addrlen) < 0) 124105be5e27SPaolo Abeni xerror("can't disconnect: %d", errno); 124205be5e27SPaolo Abeni } 124305be5e27SPaolo Abeni 1244048d19d4SFlorian Westphal int main_loop(void) 1245048d19d4SFlorian Westphal { 1246ca7ae891SDmytro Shytyi int fd = 0, ret, fd_in = 0; 124705be5e27SPaolo Abeni struct addrinfo *peer; 1248ca7ae891SDmytro Shytyi struct wstate winfo; 1249048d19d4SFlorian Westphal 1250ca7ae891SDmytro Shytyi if (cfg_input && cfg_sockopt_types.mptfo) { 1251ca7ae891SDmytro Shytyi fd_in = open(cfg_input, O_RDONLY); 1252ca7ae891SDmytro Shytyi if (fd < 0) 1253ca7ae891SDmytro Shytyi xerror("can't open %s:%d", cfg_input, errno); 1254ca7ae891SDmytro Shytyi } 1255ca7ae891SDmytro Shytyi 1256ca7ae891SDmytro Shytyi memset(&winfo, 0, sizeof(winfo)); 1257ca7ae891SDmytro Shytyi fd = sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto, &peer, fd_in, &winfo); 1258048d19d4SFlorian Westphal if (fd < 0) 1259048d19d4SFlorian Westphal return 2; 1260048d19d4SFlorian Westphal 126105be5e27SPaolo Abeni again: 1262048d19d4SFlorian Westphal check_getpeername_connect(fd); 1263048d19d4SFlorian Westphal 1264f730b65cSFlorian Westphal SOCK_TEST_TCPULP(fd, cfg_sock_proto); 1265f730b65cSFlorian Westphal 12668a4b910dSFlorian Westphal if (cfg_rcvbuf) 12678a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 1268048d19d4SFlorian Westphal if (cfg_sndbuf) 1269048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 12705e6af0a7SFlorian Westphal if (cfg_cmsg_types.cmsg_enabled) 12715e6af0a7SFlorian Westphal apply_cmsg_types(fd, &cfg_cmsg_types); 1272048d19d4SFlorian Westphal 1273ca7ae891SDmytro Shytyi if (cfg_input && !cfg_sockopt_types.mptfo) { 127405be5e27SPaolo Abeni fd_in = open(cfg_input, O_RDONLY); 127505be5e27SPaolo Abeni if (fd < 0) 127605be5e27SPaolo Abeni xerror("can't open %s:%d", cfg_input, errno); 127705be5e27SPaolo Abeni } 127805be5e27SPaolo Abeni 1279ca7ae891SDmytro Shytyi ret = copyfd_io(fd_in, fd, 1, 0, &winfo); 128005be5e27SPaolo Abeni if (ret) 128105be5e27SPaolo Abeni return ret; 128205be5e27SPaolo Abeni 12836bf41020SPaolo Abeni if (cfg_truncate > 0) { 12846bf41020SPaolo Abeni xdisconnect(fd, peer->ai_addrlen); 12856bf41020SPaolo Abeni } else if (--cfg_repeat > 0) { 128605be5e27SPaolo Abeni xdisconnect(fd, peer->ai_addrlen); 128705be5e27SPaolo Abeni 128805be5e27SPaolo Abeni /* the socket could be unblocking at this point, we need the 128905be5e27SPaolo Abeni * connect to be blocking 129005be5e27SPaolo Abeni */ 129105be5e27SPaolo Abeni set_nonblock(fd, false); 129205be5e27SPaolo Abeni if (connect(fd, peer->ai_addr, peer->ai_addrlen)) 129305be5e27SPaolo Abeni xerror("can't reconnect: %d", errno); 129405be5e27SPaolo Abeni if (cfg_input) 129505be5e27SPaolo Abeni close(fd_in); 1296ca7ae891SDmytro Shytyi memset(&winfo, 0, sizeof(winfo)); 129705be5e27SPaolo Abeni goto again; 12986bf41020SPaolo Abeni } else { 12996bf41020SPaolo Abeni close(fd); 130005be5e27SPaolo Abeni } 13016bf41020SPaolo Abeni 130205be5e27SPaolo Abeni return 0; 1303048d19d4SFlorian Westphal } 1304048d19d4SFlorian Westphal 1305048d19d4SFlorian Westphal int parse_proto(const char *proto) 1306048d19d4SFlorian Westphal { 1307048d19d4SFlorian Westphal if (!strcasecmp(proto, "MPTCP")) 1308048d19d4SFlorian Westphal return IPPROTO_MPTCP; 1309048d19d4SFlorian Westphal if (!strcasecmp(proto, "TCP")) 1310048d19d4SFlorian Westphal return IPPROTO_TCP; 1311048d19d4SFlorian Westphal 1312048d19d4SFlorian Westphal fprintf(stderr, "Unknown protocol: %s\n.", proto); 1313048d19d4SFlorian Westphal die_usage(); 1314048d19d4SFlorian Westphal 1315048d19d4SFlorian Westphal /* silence compiler warning */ 1316048d19d4SFlorian Westphal return 0; 1317048d19d4SFlorian Westphal } 1318048d19d4SFlorian Westphal 1319048d19d4SFlorian Westphal int parse_mode(const char *mode) 1320048d19d4SFlorian Westphal { 1321048d19d4SFlorian Westphal if (!strcasecmp(mode, "poll")) 1322048d19d4SFlorian Westphal return CFG_MODE_POLL; 1323048d19d4SFlorian Westphal if (!strcasecmp(mode, "mmap")) 1324048d19d4SFlorian Westphal return CFG_MODE_MMAP; 1325048d19d4SFlorian Westphal if (!strcasecmp(mode, "sendfile")) 1326048d19d4SFlorian Westphal return CFG_MODE_SENDFILE; 1327048d19d4SFlorian Westphal 1328048d19d4SFlorian Westphal fprintf(stderr, "Unknown test mode: %s\n", mode); 1329048d19d4SFlorian Westphal fprintf(stderr, "Supported modes are:\n"); 1330048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"poll\" - interleaved read/write using poll()\n"); 1331048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"mmap\" - send entire input file (mmap+write), then read response (-l will read input first)\n"); 1332048d19d4SFlorian Westphal fprintf(stderr, "\t\t\"sendfile\" - send entire input file (sendfile), then read response (-l will read input first)\n"); 1333048d19d4SFlorian Westphal 1334048d19d4SFlorian Westphal die_usage(); 1335048d19d4SFlorian Westphal 1336048d19d4SFlorian Westphal /* silence compiler warning */ 1337048d19d4SFlorian Westphal return 0; 1338048d19d4SFlorian Westphal } 1339048d19d4SFlorian Westphal 1340df8aee6dSYonglong Li int parse_peek(const char *mode) 1341df8aee6dSYonglong Li { 1342df8aee6dSYonglong Li if (!strcasecmp(mode, "saveWithPeek")) 1343df8aee6dSYonglong Li return CFG_WITH_PEEK; 1344df8aee6dSYonglong Li if (!strcasecmp(mode, "saveAfterPeek")) 1345df8aee6dSYonglong Li return CFG_AFTER_PEEK; 1346df8aee6dSYonglong Li 1347df8aee6dSYonglong Li fprintf(stderr, "Unknown: %s\n", mode); 1348df8aee6dSYonglong Li fprintf(stderr, "Supported MSG_PEEK mode are:\n"); 1349df8aee6dSYonglong Li fprintf(stderr, 1350df8aee6dSYonglong Li "\t\t\"saveWithPeek\" - recv data with flags 'MSG_PEEK' and save the peek data into file\n"); 1351df8aee6dSYonglong Li fprintf(stderr, 1352df8aee6dSYonglong Li "\t\t\"saveAfterPeek\" - read and save data into file after recv with flags 'MSG_PEEK'\n"); 1353df8aee6dSYonglong Li 1354df8aee6dSYonglong Li die_usage(); 1355df8aee6dSYonglong Li 1356df8aee6dSYonglong Li /* silence compiler warning */ 1357df8aee6dSYonglong Li return 0; 1358df8aee6dSYonglong Li } 1359df8aee6dSYonglong Li 13608a4b910dSFlorian Westphal static int parse_int(const char *size) 1361048d19d4SFlorian Westphal { 1362048d19d4SFlorian Westphal unsigned long s; 1363048d19d4SFlorian Westphal 1364048d19d4SFlorian Westphal errno = 0; 1365048d19d4SFlorian Westphal 1366048d19d4SFlorian Westphal s = strtoul(size, NULL, 0); 1367048d19d4SFlorian Westphal 1368048d19d4SFlorian Westphal if (errno) { 1369048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 1370048d19d4SFlorian Westphal size, strerror(errno)); 1371048d19d4SFlorian Westphal die_usage(); 1372048d19d4SFlorian Westphal } 1373048d19d4SFlorian Westphal 1374048d19d4SFlorian Westphal if (s > INT_MAX) { 1375048d19d4SFlorian Westphal fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 1376048d19d4SFlorian Westphal size, strerror(ERANGE)); 1377048d19d4SFlorian Westphal die_usage(); 1378048d19d4SFlorian Westphal } 1379048d19d4SFlorian Westphal 13808a4b910dSFlorian Westphal return (int)s; 1381048d19d4SFlorian Westphal } 1382048d19d4SFlorian Westphal 1383048d19d4SFlorian Westphal static void parse_opts(int argc, char **argv) 1384048d19d4SFlorian Westphal { 1385048d19d4SFlorian Westphal int c; 1386048d19d4SFlorian Westphal 13876bf41020SPaolo Abeni while ((c = getopt(argc, argv, "6c:f:hi:I:jlm:M:o:p:P:r:R:s:S:t:T:w:")) != -1) { 1388048d19d4SFlorian Westphal switch (c) { 13896bf41020SPaolo Abeni case 'f': 13906bf41020SPaolo Abeni cfg_truncate = atoi(optarg); 13916bf41020SPaolo Abeni 13926bf41020SPaolo Abeni /* when receiving a fastclose, ignore PIPE signals and 13936bf41020SPaolo Abeni * all the I/O errors later in the code 13946bf41020SPaolo Abeni */ 13956bf41020SPaolo Abeni if (cfg_truncate < 0) { 13966bf41020SPaolo Abeni cfg_rcv_trunc = true; 13976bf41020SPaolo Abeni signal(SIGPIPE, handle_signal); 13986bf41020SPaolo Abeni } 13996bf41020SPaolo Abeni break; 1400b08fbf24SPaolo Abeni case 'j': 1401b08fbf24SPaolo Abeni cfg_join = true; 1402b08fbf24SPaolo Abeni cfg_mode = CFG_MODE_POLL; 1403b08fbf24SPaolo Abeni break; 140413153324SGeliang Tang case 'r': 140513153324SGeliang Tang cfg_remove = true; 140613153324SGeliang Tang cfg_mode = CFG_MODE_POLL; 140713153324SGeliang Tang cfg_wait = 400000; 14082e580a63SGeliang Tang cfg_do_w = atoi(optarg); 14092e580a63SGeliang Tang if (cfg_do_w <= 0) 14102e580a63SGeliang Tang cfg_do_w = 50; 141113153324SGeliang Tang break; 141205be5e27SPaolo Abeni case 'i': 141305be5e27SPaolo Abeni cfg_input = optarg; 141405be5e27SPaolo Abeni break; 141505be5e27SPaolo Abeni case 'I': 141605be5e27SPaolo Abeni cfg_repeat = atoi(optarg); 141705be5e27SPaolo Abeni break; 1418048d19d4SFlorian Westphal case 'l': 1419048d19d4SFlorian Westphal listen_mode = true; 1420048d19d4SFlorian Westphal break; 1421048d19d4SFlorian Westphal case 'p': 1422048d19d4SFlorian Westphal cfg_port = optarg; 1423048d19d4SFlorian Westphal break; 1424048d19d4SFlorian Westphal case 's': 1425048d19d4SFlorian Westphal cfg_sock_proto = parse_proto(optarg); 1426048d19d4SFlorian Westphal break; 1427048d19d4SFlorian Westphal case 'h': 1428048d19d4SFlorian Westphal die_usage(); 1429048d19d4SFlorian Westphal break; 1430048d19d4SFlorian Westphal case '6': 1431048d19d4SFlorian Westphal pf = AF_INET6; 1432048d19d4SFlorian Westphal break; 1433048d19d4SFlorian Westphal case 't': 1434048d19d4SFlorian Westphal poll_timeout = atoi(optarg) * 1000; 1435048d19d4SFlorian Westphal if (poll_timeout <= 0) 1436048d19d4SFlorian Westphal poll_timeout = -1; 1437048d19d4SFlorian Westphal break; 1438b6ab64b0SPaolo Abeni case 'T': 1439b6ab64b0SPaolo Abeni cfg_time = atoi(optarg); 1440b6ab64b0SPaolo Abeni break; 1441048d19d4SFlorian Westphal case 'm': 1442048d19d4SFlorian Westphal cfg_mode = parse_mode(optarg); 1443048d19d4SFlorian Westphal break; 14448a4b910dSFlorian Westphal case 'S': 14458a4b910dSFlorian Westphal cfg_sndbuf = parse_int(optarg); 14468a4b910dSFlorian Westphal break; 14478a4b910dSFlorian Westphal case 'R': 14488a4b910dSFlorian Westphal cfg_rcvbuf = parse_int(optarg); 1449048d19d4SFlorian Westphal break; 1450df62f2ecSPaolo Abeni case 'w': 1451df62f2ecSPaolo Abeni cfg_wait = atoi(optarg)*1000000; 1452df62f2ecSPaolo Abeni break; 1453dc65fe82SFlorian Westphal case 'M': 1454dc65fe82SFlorian Westphal cfg_mark = strtol(optarg, NULL, 0); 1455dc65fe82SFlorian Westphal break; 1456df8aee6dSYonglong Li case 'P': 1457df8aee6dSYonglong Li cfg_peek = parse_peek(optarg); 1458df8aee6dSYonglong Li break; 14595e6af0a7SFlorian Westphal case 'c': 14605e6af0a7SFlorian Westphal parse_cmsg_types(optarg); 14615e6af0a7SFlorian Westphal break; 14625fb62e9cSFlorian Westphal case 'o': 14635fb62e9cSFlorian Westphal parse_setsock_options(optarg); 14645fb62e9cSFlorian Westphal break; 1465048d19d4SFlorian Westphal } 1466048d19d4SFlorian Westphal } 1467048d19d4SFlorian Westphal 1468048d19d4SFlorian Westphal if (optind + 1 != argc) 1469048d19d4SFlorian Westphal die_usage(); 1470048d19d4SFlorian Westphal cfg_host = argv[optind]; 1471048d19d4SFlorian Westphal 1472048d19d4SFlorian Westphal if (strchr(cfg_host, ':')) 1473048d19d4SFlorian Westphal pf = AF_INET6; 1474048d19d4SFlorian Westphal } 1475048d19d4SFlorian Westphal 1476048d19d4SFlorian Westphal int main(int argc, char *argv[]) 1477048d19d4SFlorian Westphal { 1478048d19d4SFlorian Westphal init_rng(); 1479048d19d4SFlorian Westphal 1480df62f2ecSPaolo Abeni signal(SIGUSR1, handle_signal); 1481048d19d4SFlorian Westphal parse_opts(argc, argv); 1482048d19d4SFlorian Westphal 1483048d19d4SFlorian Westphal if (listen_mode) { 1484048d19d4SFlorian Westphal int fd = sock_listen_mptcp(cfg_host, cfg_port); 1485048d19d4SFlorian Westphal 1486048d19d4SFlorian Westphal if (fd < 0) 1487048d19d4SFlorian Westphal return 1; 1488048d19d4SFlorian Westphal 14898a4b910dSFlorian Westphal if (cfg_rcvbuf) 14908a4b910dSFlorian Westphal set_rcvbuf(fd, cfg_rcvbuf); 1491048d19d4SFlorian Westphal if (cfg_sndbuf) 1492048d19d4SFlorian Westphal set_sndbuf(fd, cfg_sndbuf); 1493dc65fe82SFlorian Westphal if (cfg_mark) 1494dc65fe82SFlorian Westphal set_mark(fd, cfg_mark); 14955e6af0a7SFlorian Westphal if (cfg_cmsg_types.cmsg_enabled) 14965e6af0a7SFlorian Westphal apply_cmsg_types(fd, &cfg_cmsg_types); 1497048d19d4SFlorian Westphal 1498048d19d4SFlorian Westphal return main_loop_s(fd); 1499048d19d4SFlorian Westphal } 1500048d19d4SFlorian Westphal 1501048d19d4SFlorian Westphal return main_loop(); 1502048d19d4SFlorian Westphal } 1503