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