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