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