18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#define _GNU_SOURCE 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <errno.h> 68c2ecf20Sopenharmony_ci#include <limits.h> 78c2ecf20Sopenharmony_ci#include <fcntl.h> 88c2ecf20Sopenharmony_ci#include <string.h> 98c2ecf20Sopenharmony_ci#include <stdbool.h> 108c2ecf20Sopenharmony_ci#include <stdint.h> 118c2ecf20Sopenharmony_ci#include <stdio.h> 128c2ecf20Sopenharmony_ci#include <stdlib.h> 138c2ecf20Sopenharmony_ci#include <strings.h> 148c2ecf20Sopenharmony_ci#include <signal.h> 158c2ecf20Sopenharmony_ci#include <unistd.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <sys/poll.h> 188c2ecf20Sopenharmony_ci#include <sys/random.h> 198c2ecf20Sopenharmony_ci#include <sys/sendfile.h> 208c2ecf20Sopenharmony_ci#include <sys/stat.h> 218c2ecf20Sopenharmony_ci#include <sys/socket.h> 228c2ecf20Sopenharmony_ci#include <sys/types.h> 238c2ecf20Sopenharmony_ci#include <sys/mman.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <netdb.h> 268c2ecf20Sopenharmony_ci#include <netinet/in.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/tcp.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciextern int optind; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#ifndef IPPROTO_MPTCP 338c2ecf20Sopenharmony_ci#define IPPROTO_MPTCP 262 348c2ecf20Sopenharmony_ci#endif 358c2ecf20Sopenharmony_ci#ifndef TCP_ULP 368c2ecf20Sopenharmony_ci#define TCP_ULP 31 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int poll_timeout = 10 * 1000; 408c2ecf20Sopenharmony_cistatic bool listen_mode; 418c2ecf20Sopenharmony_cistatic bool quit; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cienum cfg_mode { 448c2ecf20Sopenharmony_ci CFG_MODE_POLL, 458c2ecf20Sopenharmony_ci CFG_MODE_MMAP, 468c2ecf20Sopenharmony_ci CFG_MODE_SENDFILE, 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic enum cfg_mode cfg_mode = CFG_MODE_POLL; 508c2ecf20Sopenharmony_cistatic const char *cfg_host; 518c2ecf20Sopenharmony_cistatic const char *cfg_port = "12000"; 528c2ecf20Sopenharmony_cistatic int cfg_sock_proto = IPPROTO_MPTCP; 538c2ecf20Sopenharmony_cistatic bool tcpulp_audit; 548c2ecf20Sopenharmony_cistatic int pf = AF_INET; 558c2ecf20Sopenharmony_cistatic int cfg_sndbuf; 568c2ecf20Sopenharmony_cistatic int cfg_rcvbuf; 578c2ecf20Sopenharmony_cistatic bool cfg_join; 588c2ecf20Sopenharmony_cistatic bool cfg_remove; 598c2ecf20Sopenharmony_cistatic int cfg_wait; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void die_usage(void) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: mptcp_connect [-6] [-u] [-s MPTCP|TCP] [-p port] [-m mode]" 648c2ecf20Sopenharmony_ci "[-l] [-w sec] connect_address\n"); 658c2ecf20Sopenharmony_ci fprintf(stderr, "\t-6 use ipv6\n"); 668c2ecf20Sopenharmony_ci fprintf(stderr, "\t-t num -- set poll timeout to num\n"); 678c2ecf20Sopenharmony_ci fprintf(stderr, "\t-S num -- set SO_SNDBUF to num\n"); 688c2ecf20Sopenharmony_ci fprintf(stderr, "\t-R num -- set SO_RCVBUF to num\n"); 698c2ecf20Sopenharmony_ci fprintf(stderr, "\t-p num -- use port num\n"); 708c2ecf20Sopenharmony_ci fprintf(stderr, "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n"); 718c2ecf20Sopenharmony_ci fprintf(stderr, "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n"); 728c2ecf20Sopenharmony_ci fprintf(stderr, "\t-u -- check mptcp ulp\n"); 738c2ecf20Sopenharmony_ci fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n"); 748c2ecf20Sopenharmony_ci exit(1); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void handle_signal(int nr) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci quit = true; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const char *getxinfo_strerr(int err) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci if (err == EAI_SYSTEM) 858c2ecf20Sopenharmony_ci return strerror(errno); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return gai_strerror(err); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen, 918c2ecf20Sopenharmony_ci char *host, socklen_t hostlen, 928c2ecf20Sopenharmony_ci char *serv, socklen_t servlen) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int flags = NI_NUMERICHOST | NI_NUMERICSERV; 958c2ecf20Sopenharmony_ci int err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen, 968c2ecf20Sopenharmony_ci flags); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (err) { 998c2ecf20Sopenharmony_ci const char *errstr = getxinfo_strerr(err); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci fprintf(stderr, "Fatal: getnameinfo: %s\n", errstr); 1028c2ecf20Sopenharmony_ci exit(1); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void xgetaddrinfo(const char *node, const char *service, 1078c2ecf20Sopenharmony_ci const struct addrinfo *hints, 1088c2ecf20Sopenharmony_ci struct addrinfo **res) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int err = getaddrinfo(node, service, hints, res); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (err) { 1138c2ecf20Sopenharmony_ci const char *errstr = getxinfo_strerr(err); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", 1168c2ecf20Sopenharmony_ci node ? node : "", service ? service : "", errstr); 1178c2ecf20Sopenharmony_ci exit(1); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void set_rcvbuf(int fd, unsigned int size) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int err; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 1268c2ecf20Sopenharmony_ci if (err) { 1278c2ecf20Sopenharmony_ci perror("set SO_RCVBUF"); 1288c2ecf20Sopenharmony_ci exit(1); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic void set_sndbuf(int fd, unsigned int size) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int err; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); 1378c2ecf20Sopenharmony_ci if (err) { 1388c2ecf20Sopenharmony_ci perror("set SO_SNDBUF"); 1398c2ecf20Sopenharmony_ci exit(1); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int sock_listen_mptcp(const char * const listenaddr, 1448c2ecf20Sopenharmony_ci const char * const port) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int sock; 1478c2ecf20Sopenharmony_ci struct addrinfo hints = { 1488c2ecf20Sopenharmony_ci .ai_protocol = IPPROTO_TCP, 1498c2ecf20Sopenharmony_ci .ai_socktype = SOCK_STREAM, 1508c2ecf20Sopenharmony_ci .ai_flags = AI_PASSIVE | AI_NUMERICHOST 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci hints.ai_family = pf; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci struct addrinfo *a, *addr; 1568c2ecf20Sopenharmony_ci int one = 1; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci xgetaddrinfo(listenaddr, port, &hints, &addr); 1598c2ecf20Sopenharmony_ci hints.ai_family = pf; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci for (a = addr; a; a = a->ai_next) { 1628c2ecf20Sopenharmony_ci sock = socket(a->ai_family, a->ai_socktype, cfg_sock_proto); 1638c2ecf20Sopenharmony_ci if (sock < 0) 1648c2ecf20Sopenharmony_ci continue; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, 1678c2ecf20Sopenharmony_ci sizeof(one))) 1688c2ecf20Sopenharmony_ci perror("setsockopt"); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (bind(sock, a->ai_addr, a->ai_addrlen) == 0) 1718c2ecf20Sopenharmony_ci break; /* success */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci perror("bind"); 1748c2ecf20Sopenharmony_ci close(sock); 1758c2ecf20Sopenharmony_ci sock = -1; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci freeaddrinfo(addr); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (sock < 0) { 1818c2ecf20Sopenharmony_ci fprintf(stderr, "Could not create listen socket\n"); 1828c2ecf20Sopenharmony_ci return sock; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (listen(sock, 20)) { 1868c2ecf20Sopenharmony_ci perror("listen"); 1878c2ecf20Sopenharmony_ci close(sock); 1888c2ecf20Sopenharmony_ci return -1; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return sock; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic bool sock_test_tcpulp(const char * const remoteaddr, 1958c2ecf20Sopenharmony_ci const char * const port) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct addrinfo hints = { 1988c2ecf20Sopenharmony_ci .ai_protocol = IPPROTO_TCP, 1998c2ecf20Sopenharmony_ci .ai_socktype = SOCK_STREAM, 2008c2ecf20Sopenharmony_ci }; 2018c2ecf20Sopenharmony_ci struct addrinfo *a, *addr; 2028c2ecf20Sopenharmony_ci int sock = -1, ret = 0; 2038c2ecf20Sopenharmony_ci bool test_pass = false; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci hints.ai_family = AF_INET; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci xgetaddrinfo(remoteaddr, port, &hints, &addr); 2088c2ecf20Sopenharmony_ci for (a = addr; a; a = a->ai_next) { 2098c2ecf20Sopenharmony_ci sock = socket(a->ai_family, a->ai_socktype, IPPROTO_TCP); 2108c2ecf20Sopenharmony_ci if (sock < 0) { 2118c2ecf20Sopenharmony_ci perror("socket"); 2128c2ecf20Sopenharmony_ci continue; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci ret = setsockopt(sock, IPPROTO_TCP, TCP_ULP, "mptcp", 2158c2ecf20Sopenharmony_ci sizeof("mptcp")); 2168c2ecf20Sopenharmony_ci if (ret == -1 && errno == EOPNOTSUPP) 2178c2ecf20Sopenharmony_ci test_pass = true; 2188c2ecf20Sopenharmony_ci close(sock); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (test_pass) 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci if (!ret) 2238c2ecf20Sopenharmony_ci fprintf(stderr, 2248c2ecf20Sopenharmony_ci "setsockopt(TCP_ULP) returned 0\n"); 2258c2ecf20Sopenharmony_ci else 2268c2ecf20Sopenharmony_ci perror("setsockopt(TCP_ULP)"); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci return test_pass; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int sock_connect_mptcp(const char * const remoteaddr, 2328c2ecf20Sopenharmony_ci const char * const port, int proto) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct addrinfo hints = { 2358c2ecf20Sopenharmony_ci .ai_protocol = IPPROTO_TCP, 2368c2ecf20Sopenharmony_ci .ai_socktype = SOCK_STREAM, 2378c2ecf20Sopenharmony_ci }; 2388c2ecf20Sopenharmony_ci struct addrinfo *a, *addr; 2398c2ecf20Sopenharmony_ci int sock = -1; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci hints.ai_family = pf; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci xgetaddrinfo(remoteaddr, port, &hints, &addr); 2448c2ecf20Sopenharmony_ci for (a = addr; a; a = a->ai_next) { 2458c2ecf20Sopenharmony_ci sock = socket(a->ai_family, a->ai_socktype, proto); 2468c2ecf20Sopenharmony_ci if (sock < 0) { 2478c2ecf20Sopenharmony_ci perror("socket"); 2488c2ecf20Sopenharmony_ci continue; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) 2528c2ecf20Sopenharmony_ci break; /* success */ 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci perror("connect()"); 2558c2ecf20Sopenharmony_ci close(sock); 2568c2ecf20Sopenharmony_ci sock = -1; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci freeaddrinfo(addr); 2608c2ecf20Sopenharmony_ci return sock; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic size_t do_rnd_write(const int fd, char *buf, const size_t len) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci static bool first = true; 2668c2ecf20Sopenharmony_ci unsigned int do_w; 2678c2ecf20Sopenharmony_ci ssize_t bw; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci do_w = rand() & 0xffff; 2708c2ecf20Sopenharmony_ci if (do_w == 0 || do_w > len) 2718c2ecf20Sopenharmony_ci do_w = len; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (cfg_join && first && do_w > 100) 2748c2ecf20Sopenharmony_ci do_w = 100; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (cfg_remove && do_w > 50) 2778c2ecf20Sopenharmony_ci do_w = 50; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci bw = write(fd, buf, do_w); 2808c2ecf20Sopenharmony_ci if (bw < 0) 2818c2ecf20Sopenharmony_ci perror("write"); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* let the join handshake complete, before going on */ 2848c2ecf20Sopenharmony_ci if (cfg_join && first) { 2858c2ecf20Sopenharmony_ci usleep(200000); 2868c2ecf20Sopenharmony_ci first = false; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (cfg_remove) 2908c2ecf20Sopenharmony_ci usleep(200000); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return bw; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic size_t do_write(const int fd, char *buf, const size_t len) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci size_t offset = 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci while (offset < len) { 3008c2ecf20Sopenharmony_ci size_t written; 3018c2ecf20Sopenharmony_ci ssize_t bw; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci bw = write(fd, buf + offset, len - offset); 3048c2ecf20Sopenharmony_ci if (bw < 0) { 3058c2ecf20Sopenharmony_ci perror("write"); 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci written = (size_t)bw; 3108c2ecf20Sopenharmony_ci offset += written; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return offset; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic ssize_t do_rnd_read(const int fd, char *buf, const size_t len) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci size_t cap = rand(); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci cap &= 0xffff; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (cap == 0) 3238c2ecf20Sopenharmony_ci cap = 1; 3248c2ecf20Sopenharmony_ci else if (cap > len) 3258c2ecf20Sopenharmony_ci cap = len; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return read(fd, buf, cap); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic void set_nonblock(int fd) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci int flags = fcntl(fd, F_GETFL); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (flags == -1) 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci fcntl(fd, F_SETFL, flags | O_NONBLOCK); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int copyfd_io_poll(int infd, int peerfd, int outfd) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct pollfd fds = { 3438c2ecf20Sopenharmony_ci .fd = peerfd, 3448c2ecf20Sopenharmony_ci .events = POLLIN | POLLOUT, 3458c2ecf20Sopenharmony_ci }; 3468c2ecf20Sopenharmony_ci unsigned int woff = 0, wlen = 0; 3478c2ecf20Sopenharmony_ci char wbuf[8192]; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci set_nonblock(peerfd); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci for (;;) { 3528c2ecf20Sopenharmony_ci char rbuf[8192]; 3538c2ecf20Sopenharmony_ci ssize_t len; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (fds.events == 0) 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci switch (poll(&fds, 1, poll_timeout)) { 3598c2ecf20Sopenharmony_ci case -1: 3608c2ecf20Sopenharmony_ci if (errno == EINTR) 3618c2ecf20Sopenharmony_ci continue; 3628c2ecf20Sopenharmony_ci perror("poll"); 3638c2ecf20Sopenharmony_ci return 1; 3648c2ecf20Sopenharmony_ci case 0: 3658c2ecf20Sopenharmony_ci fprintf(stderr, "%s: poll timed out (events: " 3668c2ecf20Sopenharmony_ci "POLLIN %u, POLLOUT %u)\n", __func__, 3678c2ecf20Sopenharmony_ci fds.events & POLLIN, fds.events & POLLOUT); 3688c2ecf20Sopenharmony_ci return 2; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (fds.revents & POLLIN) { 3728c2ecf20Sopenharmony_ci len = do_rnd_read(peerfd, rbuf, sizeof(rbuf)); 3738c2ecf20Sopenharmony_ci if (len == 0) { 3748c2ecf20Sopenharmony_ci /* no more data to receive: 3758c2ecf20Sopenharmony_ci * peer has closed its write side 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci fds.events &= ~POLLIN; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if ((fds.events & POLLOUT) == 0) 3808c2ecf20Sopenharmony_ci /* and nothing more to send */ 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Else, still have data to transmit */ 3848c2ecf20Sopenharmony_ci } else if (len < 0) { 3858c2ecf20Sopenharmony_ci perror("read"); 3868c2ecf20Sopenharmony_ci return 3; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci do_write(outfd, rbuf, len); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (fds.revents & POLLOUT) { 3938c2ecf20Sopenharmony_ci if (wlen == 0) { 3948c2ecf20Sopenharmony_ci woff = 0; 3958c2ecf20Sopenharmony_ci wlen = read(infd, wbuf, sizeof(wbuf)); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (wlen > 0) { 3998c2ecf20Sopenharmony_ci ssize_t bw; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci bw = do_rnd_write(peerfd, wbuf + woff, wlen); 4028c2ecf20Sopenharmony_ci if (bw < 0) 4038c2ecf20Sopenharmony_ci return 111; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci woff += bw; 4068c2ecf20Sopenharmony_ci wlen -= bw; 4078c2ecf20Sopenharmony_ci } else if (wlen == 0) { 4088c2ecf20Sopenharmony_ci /* We have no more data to send. */ 4098c2ecf20Sopenharmony_ci fds.events &= ~POLLOUT; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if ((fds.events & POLLIN) == 0) 4128c2ecf20Sopenharmony_ci /* ... and peer also closed already */ 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* ... but we still receive. 4168c2ecf20Sopenharmony_ci * Close our write side, ev. give some time 4178c2ecf20Sopenharmony_ci * for address notification and/or checking 4188c2ecf20Sopenharmony_ci * the current status 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci if (cfg_wait) 4218c2ecf20Sopenharmony_ci usleep(cfg_wait); 4228c2ecf20Sopenharmony_ci shutdown(peerfd, SHUT_WR); 4238c2ecf20Sopenharmony_ci } else { 4248c2ecf20Sopenharmony_ci if (errno == EINTR) 4258c2ecf20Sopenharmony_ci continue; 4268c2ecf20Sopenharmony_ci perror("read"); 4278c2ecf20Sopenharmony_ci return 4; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (fds.revents & (POLLERR | POLLNVAL)) { 4328c2ecf20Sopenharmony_ci fprintf(stderr, "Unexpected revents: " 4338c2ecf20Sopenharmony_ci "POLLERR/POLLNVAL(%x)\n", fds.revents); 4348c2ecf20Sopenharmony_ci return 5; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* leave some time for late join/announce */ 4398c2ecf20Sopenharmony_ci if (cfg_join || cfg_remove) 4408c2ecf20Sopenharmony_ci usleep(cfg_wait); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci close(peerfd); 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int do_recvfile(int infd, int outfd) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci ssize_t r; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci do { 4518c2ecf20Sopenharmony_ci char buf[16384]; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci r = do_rnd_read(infd, buf, sizeof(buf)); 4548c2ecf20Sopenharmony_ci if (r > 0) { 4558c2ecf20Sopenharmony_ci if (write(outfd, buf, r) != r) 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci } else if (r < 0) { 4588c2ecf20Sopenharmony_ci perror("read"); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci } while (r > 0); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return (int)r; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int do_mmap(int infd, int outfd, unsigned int size) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci char *inbuf = mmap(NULL, size, PROT_READ, MAP_SHARED, infd, 0); 4688c2ecf20Sopenharmony_ci ssize_t ret = 0, off = 0; 4698c2ecf20Sopenharmony_ci size_t rem; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (inbuf == MAP_FAILED) { 4728c2ecf20Sopenharmony_ci perror("mmap"); 4738c2ecf20Sopenharmony_ci return 1; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci rem = size; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci while (rem > 0) { 4798c2ecf20Sopenharmony_ci ret = write(outfd, inbuf + off, rem); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (ret < 0) { 4828c2ecf20Sopenharmony_ci perror("write"); 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci off += ret; 4878c2ecf20Sopenharmony_ci rem -= ret; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci munmap(inbuf, size); 4918c2ecf20Sopenharmony_ci return rem; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int get_infd_size(int fd) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct stat sb; 4978c2ecf20Sopenharmony_ci ssize_t count; 4988c2ecf20Sopenharmony_ci int err; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci err = fstat(fd, &sb); 5018c2ecf20Sopenharmony_ci if (err < 0) { 5028c2ecf20Sopenharmony_ci perror("fstat"); 5038c2ecf20Sopenharmony_ci return -1; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if ((sb.st_mode & S_IFMT) != S_IFREG) { 5078c2ecf20Sopenharmony_ci fprintf(stderr, "%s: stdin is not a regular file\n", __func__); 5088c2ecf20Sopenharmony_ci return -2; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci count = sb.st_size; 5128c2ecf20Sopenharmony_ci if (count > INT_MAX) { 5138c2ecf20Sopenharmony_ci fprintf(stderr, "File too large: %zu\n", count); 5148c2ecf20Sopenharmony_ci return -3; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return (int)count; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int do_sendfile(int infd, int outfd, unsigned int count) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci while (count > 0) { 5238c2ecf20Sopenharmony_ci ssize_t r; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci r = sendfile(outfd, infd, NULL, count); 5268c2ecf20Sopenharmony_ci if (r < 0) { 5278c2ecf20Sopenharmony_ci perror("sendfile"); 5288c2ecf20Sopenharmony_ci return 3; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci count -= r; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic int copyfd_io_mmap(int infd, int peerfd, int outfd, 5388c2ecf20Sopenharmony_ci unsigned int size) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci int err; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (listen_mode) { 5438c2ecf20Sopenharmony_ci err = do_recvfile(peerfd, outfd); 5448c2ecf20Sopenharmony_ci if (err) 5458c2ecf20Sopenharmony_ci return err; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci err = do_mmap(infd, peerfd, size); 5488c2ecf20Sopenharmony_ci } else { 5498c2ecf20Sopenharmony_ci err = do_mmap(infd, peerfd, size); 5508c2ecf20Sopenharmony_ci if (err) 5518c2ecf20Sopenharmony_ci return err; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci shutdown(peerfd, SHUT_WR); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci err = do_recvfile(peerfd, outfd); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return err; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic int copyfd_io_sendfile(int infd, int peerfd, int outfd, 5628c2ecf20Sopenharmony_ci unsigned int size) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci int err; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (listen_mode) { 5678c2ecf20Sopenharmony_ci err = do_recvfile(peerfd, outfd); 5688c2ecf20Sopenharmony_ci if (err) 5698c2ecf20Sopenharmony_ci return err; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci err = do_sendfile(infd, peerfd, size); 5728c2ecf20Sopenharmony_ci } else { 5738c2ecf20Sopenharmony_ci err = do_sendfile(infd, peerfd, size); 5748c2ecf20Sopenharmony_ci if (err) 5758c2ecf20Sopenharmony_ci return err; 5768c2ecf20Sopenharmony_ci err = do_recvfile(peerfd, outfd); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return err; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic int copyfd_io(int infd, int peerfd, int outfd) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci int file_size; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci switch (cfg_mode) { 5878c2ecf20Sopenharmony_ci case CFG_MODE_POLL: 5888c2ecf20Sopenharmony_ci return copyfd_io_poll(infd, peerfd, outfd); 5898c2ecf20Sopenharmony_ci case CFG_MODE_MMAP: 5908c2ecf20Sopenharmony_ci file_size = get_infd_size(infd); 5918c2ecf20Sopenharmony_ci if (file_size < 0) 5928c2ecf20Sopenharmony_ci return file_size; 5938c2ecf20Sopenharmony_ci return copyfd_io_mmap(infd, peerfd, outfd, file_size); 5948c2ecf20Sopenharmony_ci case CFG_MODE_SENDFILE: 5958c2ecf20Sopenharmony_ci file_size = get_infd_size(infd); 5968c2ecf20Sopenharmony_ci if (file_size < 0) 5978c2ecf20Sopenharmony_ci return file_size; 5988c2ecf20Sopenharmony_ci return copyfd_io_sendfile(infd, peerfd, outfd, file_size); 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid mode %d\n", cfg_mode); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci die_usage(); 6048c2ecf20Sopenharmony_ci return 1; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void check_sockaddr(int pf, struct sockaddr_storage *ss, 6088c2ecf20Sopenharmony_ci socklen_t salen) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct sockaddr_in6 *sin6; 6118c2ecf20Sopenharmony_ci struct sockaddr_in *sin; 6128c2ecf20Sopenharmony_ci socklen_t wanted_size = 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci switch (pf) { 6158c2ecf20Sopenharmony_ci case AF_INET: 6168c2ecf20Sopenharmony_ci wanted_size = sizeof(*sin); 6178c2ecf20Sopenharmony_ci sin = (void *)ss; 6188c2ecf20Sopenharmony_ci if (!sin->sin_port) 6198c2ecf20Sopenharmony_ci fprintf(stderr, "accept: something wrong: ip connection from port 0"); 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci case AF_INET6: 6228c2ecf20Sopenharmony_ci wanted_size = sizeof(*sin6); 6238c2ecf20Sopenharmony_ci sin6 = (void *)ss; 6248c2ecf20Sopenharmony_ci if (!sin6->sin6_port) 6258c2ecf20Sopenharmony_ci fprintf(stderr, "accept: something wrong: ipv6 connection from port 0"); 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci default: 6288c2ecf20Sopenharmony_ci fprintf(stderr, "accept: Unknown pf %d, salen %u\n", pf, salen); 6298c2ecf20Sopenharmony_ci return; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (salen != wanted_size) 6338c2ecf20Sopenharmony_ci fprintf(stderr, "accept: size mismatch, got %d expected %d\n", 6348c2ecf20Sopenharmony_ci (int)salen, wanted_size); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (ss->ss_family != pf) 6378c2ecf20Sopenharmony_ci fprintf(stderr, "accept: pf mismatch, expect %d, ss_family is %d\n", 6388c2ecf20Sopenharmony_ci (int)ss->ss_family, pf); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic void check_getpeername(int fd, struct sockaddr_storage *ss, socklen_t salen) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct sockaddr_storage peerss; 6448c2ecf20Sopenharmony_ci socklen_t peersalen = sizeof(peerss); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (getpeername(fd, (struct sockaddr *)&peerss, &peersalen) < 0) { 6478c2ecf20Sopenharmony_ci perror("getpeername"); 6488c2ecf20Sopenharmony_ci return; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (peersalen != salen) { 6528c2ecf20Sopenharmony_ci fprintf(stderr, "%s: %d vs %d\n", __func__, peersalen, salen); 6538c2ecf20Sopenharmony_ci return; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (memcmp(ss, &peerss, peersalen)) { 6578c2ecf20Sopenharmony_ci char a[INET6_ADDRSTRLEN]; 6588c2ecf20Sopenharmony_ci char b[INET6_ADDRSTRLEN]; 6598c2ecf20Sopenharmony_ci char c[INET6_ADDRSTRLEN]; 6608c2ecf20Sopenharmony_ci char d[INET6_ADDRSTRLEN]; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci xgetnameinfo((struct sockaddr *)ss, salen, 6638c2ecf20Sopenharmony_ci a, sizeof(a), b, sizeof(b)); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci xgetnameinfo((struct sockaddr *)&peerss, peersalen, 6668c2ecf20Sopenharmony_ci c, sizeof(c), d, sizeof(d)); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci fprintf(stderr, "%s: memcmp failure: accept %s vs peername %s, %s vs %s salen %d vs %d\n", 6698c2ecf20Sopenharmony_ci __func__, a, c, b, d, peersalen, salen); 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void check_getpeername_connect(int fd) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct sockaddr_storage ss; 6768c2ecf20Sopenharmony_ci socklen_t salen = sizeof(ss); 6778c2ecf20Sopenharmony_ci char a[INET6_ADDRSTRLEN]; 6788c2ecf20Sopenharmony_ci char b[INET6_ADDRSTRLEN]; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (getpeername(fd, (struct sockaddr *)&ss, &salen) < 0) { 6818c2ecf20Sopenharmony_ci perror("getpeername"); 6828c2ecf20Sopenharmony_ci return; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci xgetnameinfo((struct sockaddr *)&ss, salen, 6868c2ecf20Sopenharmony_ci a, sizeof(a), b, sizeof(b)); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (strcmp(cfg_host, a) || strcmp(cfg_port, b)) 6898c2ecf20Sopenharmony_ci fprintf(stderr, "%s: %s vs %s, %s vs %s\n", __func__, 6908c2ecf20Sopenharmony_ci cfg_host, a, cfg_port, b); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic void maybe_close(int fd) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci unsigned int r = rand(); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (!(cfg_join || cfg_remove) && (r & 1)) 6988c2ecf20Sopenharmony_ci close(fd); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ciint main_loop_s(int listensock) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct sockaddr_storage ss; 7048c2ecf20Sopenharmony_ci struct pollfd polls; 7058c2ecf20Sopenharmony_ci socklen_t salen; 7068c2ecf20Sopenharmony_ci int remotesock; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci polls.fd = listensock; 7098c2ecf20Sopenharmony_ci polls.events = POLLIN; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci switch (poll(&polls, 1, poll_timeout)) { 7128c2ecf20Sopenharmony_ci case -1: 7138c2ecf20Sopenharmony_ci perror("poll"); 7148c2ecf20Sopenharmony_ci return 1; 7158c2ecf20Sopenharmony_ci case 0: 7168c2ecf20Sopenharmony_ci fprintf(stderr, "%s: timed out\n", __func__); 7178c2ecf20Sopenharmony_ci close(listensock); 7188c2ecf20Sopenharmony_ci return 2; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci salen = sizeof(ss); 7228c2ecf20Sopenharmony_ci remotesock = accept(listensock, (struct sockaddr *)&ss, &salen); 7238c2ecf20Sopenharmony_ci if (remotesock >= 0) { 7248c2ecf20Sopenharmony_ci maybe_close(listensock); 7258c2ecf20Sopenharmony_ci check_sockaddr(pf, &ss, salen); 7268c2ecf20Sopenharmony_ci check_getpeername(remotesock, &ss, salen); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return copyfd_io(0, remotesock, 1); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci perror("accept"); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci return 1; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic void init_rng(void) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci unsigned int foo; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (getrandom(&foo, sizeof(foo), 0) == -1) { 7418c2ecf20Sopenharmony_ci perror("getrandom"); 7428c2ecf20Sopenharmony_ci exit(1); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci srand(foo); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ciint main_loop(void) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci int fd; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* listener is ready. */ 7538c2ecf20Sopenharmony_ci fd = sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto); 7548c2ecf20Sopenharmony_ci if (fd < 0) 7558c2ecf20Sopenharmony_ci return 2; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci check_getpeername_connect(fd); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (cfg_rcvbuf) 7608c2ecf20Sopenharmony_ci set_rcvbuf(fd, cfg_rcvbuf); 7618c2ecf20Sopenharmony_ci if (cfg_sndbuf) 7628c2ecf20Sopenharmony_ci set_sndbuf(fd, cfg_sndbuf); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return copyfd_io(0, fd, 1); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ciint parse_proto(const char *proto) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci if (!strcasecmp(proto, "MPTCP")) 7708c2ecf20Sopenharmony_ci return IPPROTO_MPTCP; 7718c2ecf20Sopenharmony_ci if (!strcasecmp(proto, "TCP")) 7728c2ecf20Sopenharmony_ci return IPPROTO_TCP; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci fprintf(stderr, "Unknown protocol: %s\n.", proto); 7758c2ecf20Sopenharmony_ci die_usage(); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* silence compiler warning */ 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ciint parse_mode(const char *mode) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci if (!strcasecmp(mode, "poll")) 7848c2ecf20Sopenharmony_ci return CFG_MODE_POLL; 7858c2ecf20Sopenharmony_ci if (!strcasecmp(mode, "mmap")) 7868c2ecf20Sopenharmony_ci return CFG_MODE_MMAP; 7878c2ecf20Sopenharmony_ci if (!strcasecmp(mode, "sendfile")) 7888c2ecf20Sopenharmony_ci return CFG_MODE_SENDFILE; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci fprintf(stderr, "Unknown test mode: %s\n", mode); 7918c2ecf20Sopenharmony_ci fprintf(stderr, "Supported modes are:\n"); 7928c2ecf20Sopenharmony_ci fprintf(stderr, "\t\t\"poll\" - interleaved read/write using poll()\n"); 7938c2ecf20Sopenharmony_ci fprintf(stderr, "\t\t\"mmap\" - send entire input file (mmap+write), then read response (-l will read input first)\n"); 7948c2ecf20Sopenharmony_ci fprintf(stderr, "\t\t\"sendfile\" - send entire input file (sendfile), then read response (-l will read input first)\n"); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci die_usage(); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* silence compiler warning */ 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int parse_int(const char *size) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci unsigned long s; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci errno = 0; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci s = strtoul(size, NULL, 0); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (errno) { 8118c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 8128c2ecf20Sopenharmony_ci size, strerror(errno)); 8138c2ecf20Sopenharmony_ci die_usage(); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (s > INT_MAX) { 8178c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid sndbuf size %s (%s)\n", 8188c2ecf20Sopenharmony_ci size, strerror(ERANGE)); 8198c2ecf20Sopenharmony_ci die_usage(); 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return (int)s; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic void parse_opts(int argc, char **argv) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci int c; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci while ((c = getopt(argc, argv, "6jrlp:s:hut:m:S:R:w:")) != -1) { 8308c2ecf20Sopenharmony_ci switch (c) { 8318c2ecf20Sopenharmony_ci case 'j': 8328c2ecf20Sopenharmony_ci cfg_join = true; 8338c2ecf20Sopenharmony_ci cfg_mode = CFG_MODE_POLL; 8348c2ecf20Sopenharmony_ci cfg_wait = 400000; 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci case 'r': 8378c2ecf20Sopenharmony_ci cfg_remove = true; 8388c2ecf20Sopenharmony_ci cfg_mode = CFG_MODE_POLL; 8398c2ecf20Sopenharmony_ci cfg_wait = 400000; 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci case 'l': 8428c2ecf20Sopenharmony_ci listen_mode = true; 8438c2ecf20Sopenharmony_ci break; 8448c2ecf20Sopenharmony_ci case 'p': 8458c2ecf20Sopenharmony_ci cfg_port = optarg; 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci case 's': 8488c2ecf20Sopenharmony_ci cfg_sock_proto = parse_proto(optarg); 8498c2ecf20Sopenharmony_ci break; 8508c2ecf20Sopenharmony_ci case 'h': 8518c2ecf20Sopenharmony_ci die_usage(); 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci case 'u': 8548c2ecf20Sopenharmony_ci tcpulp_audit = true; 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci case '6': 8578c2ecf20Sopenharmony_ci pf = AF_INET6; 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci case 't': 8608c2ecf20Sopenharmony_ci poll_timeout = atoi(optarg) * 1000; 8618c2ecf20Sopenharmony_ci if (poll_timeout <= 0) 8628c2ecf20Sopenharmony_ci poll_timeout = -1; 8638c2ecf20Sopenharmony_ci break; 8648c2ecf20Sopenharmony_ci case 'm': 8658c2ecf20Sopenharmony_ci cfg_mode = parse_mode(optarg); 8668c2ecf20Sopenharmony_ci break; 8678c2ecf20Sopenharmony_ci case 'S': 8688c2ecf20Sopenharmony_ci cfg_sndbuf = parse_int(optarg); 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci case 'R': 8718c2ecf20Sopenharmony_ci cfg_rcvbuf = parse_int(optarg); 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci case 'w': 8748c2ecf20Sopenharmony_ci cfg_wait = atoi(optarg)*1000000; 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (optind + 1 != argc) 8808c2ecf20Sopenharmony_ci die_usage(); 8818c2ecf20Sopenharmony_ci cfg_host = argv[optind]; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (strchr(cfg_host, ':')) 8848c2ecf20Sopenharmony_ci pf = AF_INET6; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci init_rng(); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci signal(SIGUSR1, handle_signal); 8928c2ecf20Sopenharmony_ci parse_opts(argc, argv); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (tcpulp_audit) 8958c2ecf20Sopenharmony_ci return sock_test_tcpulp(cfg_host, cfg_port) ? 0 : 1; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (listen_mode) { 8988c2ecf20Sopenharmony_ci int fd = sock_listen_mptcp(cfg_host, cfg_port); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (fd < 0) 9018c2ecf20Sopenharmony_ci return 1; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (cfg_rcvbuf) 9048c2ecf20Sopenharmony_ci set_rcvbuf(fd, cfg_rcvbuf); 9058c2ecf20Sopenharmony_ci if (cfg_sndbuf) 9068c2ecf20Sopenharmony_ci set_sndbuf(fd, cfg_sndbuf); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci return main_loop_s(fd); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return main_loop(); 9128c2ecf20Sopenharmony_ci} 913