1// SPDX-License-Identifier: GPL-2.0
2
3#define _GNU_SOURCE
4
5#include <assert.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <limits.h>
9#include <string.h>
10#include <stdarg.h>
11#include <stdbool.h>
12#include <stdint.h>
13#include <inttypes.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <strings.h>
17#include <time.h>
18#include <unistd.h>
19
20#include <sys/socket.h>
21#include <sys/types.h>
22#include <sys/wait.h>
23
24#include <netdb.h>
25#include <netinet/in.h>
26
27#include <linux/tcp.h>
28
29static int pf = AF_INET;
30
31#ifndef IPPROTO_MPTCP
32#define IPPROTO_MPTCP 262
33#endif
34#ifndef SOL_MPTCP
35#define SOL_MPTCP 284
36#endif
37
38#ifndef MPTCP_INFO
39struct mptcp_info {
40	__u8	mptcpi_subflows;
41	__u8	mptcpi_add_addr_signal;
42	__u8	mptcpi_add_addr_accepted;
43	__u8	mptcpi_subflows_max;
44	__u8	mptcpi_add_addr_signal_max;
45	__u8	mptcpi_add_addr_accepted_max;
46	__u32	mptcpi_flags;
47	__u32	mptcpi_token;
48	__u64	mptcpi_write_seq;
49	__u64	mptcpi_snd_una;
50	__u64	mptcpi_rcv_nxt;
51	__u8	mptcpi_local_addr_used;
52	__u8	mptcpi_local_addr_max;
53	__u8	mptcpi_csum_enabled;
54	__u32	mptcpi_retransmits;
55	__u64	mptcpi_bytes_retrans;
56	__u64	mptcpi_bytes_sent;
57	__u64	mptcpi_bytes_received;
58	__u64	mptcpi_bytes_acked;
59};
60
61struct mptcp_subflow_data {
62	__u32		size_subflow_data;		/* size of this structure in userspace */
63	__u32		num_subflows;			/* must be 0, set by kernel */
64	__u32		size_kernel;			/* must be 0, set by kernel */
65	__u32		size_user;			/* size of one element in data[] */
66} __attribute__((aligned(8)));
67
68struct mptcp_subflow_addrs {
69	union {
70		__kernel_sa_family_t sa_family;
71		struct sockaddr sa_local;
72		struct sockaddr_in sin_local;
73		struct sockaddr_in6 sin6_local;
74		struct __kernel_sockaddr_storage ss_local;
75	};
76	union {
77		struct sockaddr sa_remote;
78		struct sockaddr_in sin_remote;
79		struct sockaddr_in6 sin6_remote;
80		struct __kernel_sockaddr_storage ss_remote;
81	};
82};
83
84#define MPTCP_INFO		1
85#define MPTCP_TCPINFO		2
86#define MPTCP_SUBFLOW_ADDRS	3
87#endif
88
89#ifndef MPTCP_FULL_INFO
90struct mptcp_subflow_info {
91	__u32				id;
92	struct mptcp_subflow_addrs	addrs;
93};
94
95struct mptcp_full_info {
96	__u32		size_tcpinfo_kernel;	/* must be 0, set by kernel */
97	__u32		size_tcpinfo_user;
98	__u32		size_sfinfo_kernel;	/* must be 0, set by kernel */
99	__u32		size_sfinfo_user;
100	__u32		num_subflows;		/* must be 0, set by kernel (real subflow count) */
101	__u32		size_arrays_user;	/* max subflows that userspace is interested in;
102						 * the buffers at subflow_info/tcp_info
103						 * are respectively at least:
104						 *  size_arrays * size_sfinfo_user
105						 *  size_arrays * size_tcpinfo_user
106						 * bytes wide
107						 */
108	__aligned_u64		subflow_info;
109	__aligned_u64		tcp_info;
110	struct mptcp_info	mptcp_info;
111};
112
113#define MPTCP_FULL_INFO		4
114#endif
115
116struct so_state {
117	struct mptcp_info mi;
118	struct mptcp_info last_sample;
119	struct tcp_info tcp_info;
120	struct mptcp_subflow_addrs addrs;
121	uint64_t mptcpi_rcv_delta;
122	uint64_t tcpi_rcv_delta;
123	bool pkt_stats_avail;
124};
125
126#ifndef MIN
127#define MIN(a, b) ((a) < (b) ? (a) : (b))
128#endif
129
130static void die_perror(const char *msg)
131{
132	perror(msg);
133	exit(1);
134}
135
136static void die_usage(int r)
137{
138	fprintf(stderr, "Usage: mptcp_sockopt [-6]\n");
139	exit(r);
140}
141
142static void xerror(const char *fmt, ...)
143{
144	va_list ap;
145
146	va_start(ap, fmt);
147	vfprintf(stderr, fmt, ap);
148	va_end(ap);
149	fputc('\n', stderr);
150	exit(1);
151}
152
153static const char *getxinfo_strerr(int err)
154{
155	if (err == EAI_SYSTEM)
156		return strerror(errno);
157
158	return gai_strerror(err);
159}
160
161static void xgetaddrinfo(const char *node, const char *service,
162			 const struct addrinfo *hints,
163			 struct addrinfo **res)
164{
165	int err = getaddrinfo(node, service, hints, res);
166
167	if (err) {
168		const char *errstr = getxinfo_strerr(err);
169
170		fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
171			node ? node : "", service ? service : "", errstr);
172		exit(1);
173	}
174}
175
176static int sock_listen_mptcp(const char * const listenaddr,
177			     const char * const port)
178{
179	int sock = -1;
180	struct addrinfo hints = {
181		.ai_protocol = IPPROTO_TCP,
182		.ai_socktype = SOCK_STREAM,
183		.ai_flags = AI_PASSIVE | AI_NUMERICHOST
184	};
185
186	hints.ai_family = pf;
187
188	struct addrinfo *a, *addr;
189	int one = 1;
190
191	xgetaddrinfo(listenaddr, port, &hints, &addr);
192	hints.ai_family = pf;
193
194	for (a = addr; a; a = a->ai_next) {
195		sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP);
196		if (sock < 0)
197			continue;
198
199		if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
200				     sizeof(one)))
201			perror("setsockopt");
202
203		if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
204			break; /* success */
205
206		perror("bind");
207		close(sock);
208		sock = -1;
209	}
210
211	freeaddrinfo(addr);
212
213	if (sock < 0)
214		xerror("could not create listen socket");
215
216	if (listen(sock, 20))
217		die_perror("listen");
218
219	return sock;
220}
221
222static int sock_connect_mptcp(const char * const remoteaddr,
223			      const char * const port, int proto)
224{
225	struct addrinfo hints = {
226		.ai_protocol = IPPROTO_TCP,
227		.ai_socktype = SOCK_STREAM,
228	};
229	struct addrinfo *a, *addr;
230	int sock = -1;
231
232	hints.ai_family = pf;
233
234	xgetaddrinfo(remoteaddr, port, &hints, &addr);
235	for (a = addr; a; a = a->ai_next) {
236		sock = socket(a->ai_family, a->ai_socktype, proto);
237		if (sock < 0)
238			continue;
239
240		if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
241			break; /* success */
242
243		die_perror("connect");
244	}
245
246	if (sock < 0)
247		xerror("could not create connect socket");
248
249	freeaddrinfo(addr);
250	return sock;
251}
252
253static void parse_opts(int argc, char **argv)
254{
255	int c;
256
257	while ((c = getopt(argc, argv, "h6")) != -1) {
258		switch (c) {
259		case 'h':
260			die_usage(0);
261			break;
262		case '6':
263			pf = AF_INET6;
264			break;
265		default:
266			die_usage(1);
267			break;
268		}
269	}
270}
271
272static void do_getsockopt_bogus_sf_data(int fd, int optname)
273{
274	struct mptcp_subflow_data good_data;
275	struct bogus_data {
276		struct mptcp_subflow_data d;
277		char buf[2];
278	} bd;
279	socklen_t olen, _olen;
280	int ret;
281
282	memset(&bd, 0, sizeof(bd));
283	memset(&good_data, 0, sizeof(good_data));
284
285	olen = sizeof(good_data);
286	good_data.size_subflow_data = olen;
287
288	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
289	assert(ret < 0); /* 0 size_subflow_data */
290	assert(olen == sizeof(good_data));
291
292	bd.d = good_data;
293
294	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
295	assert(ret == 0);
296	assert(olen == sizeof(good_data));
297	assert(bd.d.num_subflows == 1);
298	assert(bd.d.size_kernel > 0);
299	assert(bd.d.size_user == 0);
300
301	bd.d = good_data;
302	_olen = rand() % olen;
303	olen = _olen;
304	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
305	assert(ret < 0);	/* bogus olen */
306	assert(olen == _olen);	/* must be unchanged */
307
308	bd.d = good_data;
309	olen = sizeof(good_data);
310	bd.d.size_kernel = 1;
311	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
312	assert(ret < 0); /* size_kernel not 0 */
313
314	bd.d = good_data;
315	olen = sizeof(good_data);
316	bd.d.num_subflows = 1;
317	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
318	assert(ret < 0); /* num_subflows not 0 */
319
320	/* forward compat check: larger struct mptcp_subflow_data on 'old' kernel */
321	bd.d = good_data;
322	olen = sizeof(bd);
323	bd.d.size_subflow_data = sizeof(bd);
324
325	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
326	assert(ret == 0);
327
328	/* olen must be truncated to real data size filled by kernel: */
329	assert(olen == sizeof(good_data));
330
331	assert(bd.d.size_subflow_data == sizeof(bd));
332
333	bd.d = good_data;
334	bd.d.size_subflow_data += 1;
335	bd.d.size_user = 1;
336	olen = bd.d.size_subflow_data + 1;
337	_olen = olen;
338
339	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &_olen);
340	assert(ret == 0);
341
342	/* no truncation, kernel should have filled 1 byte of optname payload in buf[1]: */
343	assert(olen == _olen);
344
345	assert(bd.d.size_subflow_data == sizeof(good_data) + 1);
346	assert(bd.buf[0] == 0);
347}
348
349static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w)
350{
351	struct mptcp_info i;
352	socklen_t olen;
353	int ret;
354
355	olen = sizeof(i);
356	ret = getsockopt(fd, SOL_MPTCP, MPTCP_INFO, &i, &olen);
357
358	if (ret < 0)
359		die_perror("getsockopt MPTCP_INFO");
360
361	s->pkt_stats_avail = olen >= sizeof(i);
362
363	s->last_sample = i;
364	if (s->mi.mptcpi_write_seq == 0)
365		s->mi = i;
366
367	assert(s->mi.mptcpi_write_seq + w == i.mptcpi_write_seq);
368
369	s->mptcpi_rcv_delta = i.mptcpi_rcv_nxt - s->mi.mptcpi_rcv_nxt;
370}
371
372static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t w)
373{
374	struct my_tcp_info {
375		struct mptcp_subflow_data d;
376		struct tcp_info ti[2];
377	} ti;
378	int ret, tries = 5;
379	socklen_t olen;
380
381	do {
382		memset(&ti, 0, sizeof(ti));
383
384		ti.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
385		ti.d.size_user = sizeof(struct tcp_info);
386		olen = sizeof(ti);
387
388		ret = getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen);
389		if (ret < 0)
390			xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
391
392		assert(olen <= sizeof(ti));
393		assert(ti.d.size_kernel > 0);
394		assert(ti.d.size_user ==
395		       MIN(ti.d.size_kernel, sizeof(struct tcp_info)));
396		assert(ti.d.num_subflows == 1);
397
398		assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
399		olen -= sizeof(struct mptcp_subflow_data);
400		assert(olen == ti.d.size_user);
401
402		s->tcp_info = ti.ti[0];
403
404		if (ti.ti[0].tcpi_bytes_sent == w &&
405		    ti.ti[0].tcpi_bytes_received == r)
406			goto done;
407
408		if (r == 0 && ti.ti[0].tcpi_bytes_sent == w &&
409		    ti.ti[0].tcpi_bytes_received) {
410			s->tcpi_rcv_delta = ti.ti[0].tcpi_bytes_received;
411			goto done;
412		}
413
414		/* wait and repeat, might be that tx is still ongoing */
415		sleep(1);
416	} while (tries-- > 0);
417
418	xerror("tcpi_bytes_sent %" PRIu64 ", want %zu. tcpi_bytes_received %" PRIu64 ", want %zu",
419		ti.ti[0].tcpi_bytes_sent, w, ti.ti[0].tcpi_bytes_received, r);
420
421done:
422	do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO);
423}
424
425static void do_getsockopt_subflow_addrs(struct so_state *s, int fd)
426{
427	struct sockaddr_storage remote, local;
428	socklen_t olen, rlen, llen;
429	int ret;
430	struct my_addrs {
431		struct mptcp_subflow_data d;
432		struct mptcp_subflow_addrs addr[2];
433	} addrs;
434
435	memset(&addrs, 0, sizeof(addrs));
436	memset(&local, 0, sizeof(local));
437	memset(&remote, 0, sizeof(remote));
438
439	addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
440	addrs.d.size_user = sizeof(struct mptcp_subflow_addrs);
441	olen = sizeof(addrs);
442
443	ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
444	if (ret < 0)
445		die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
446
447	assert(olen <= sizeof(addrs));
448	assert(addrs.d.size_kernel > 0);
449	assert(addrs.d.size_user ==
450	       MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs)));
451	assert(addrs.d.num_subflows == 1);
452
453	assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
454	olen -= sizeof(struct mptcp_subflow_data);
455	assert(olen == addrs.d.size_user);
456
457	llen = sizeof(local);
458	ret = getsockname(fd, (struct sockaddr *)&local, &llen);
459	if (ret < 0)
460		die_perror("getsockname");
461	rlen = sizeof(remote);
462	ret = getpeername(fd, (struct sockaddr *)&remote, &rlen);
463	if (ret < 0)
464		die_perror("getpeername");
465
466	assert(rlen > 0);
467	assert(rlen == llen);
468
469	assert(remote.ss_family == local.ss_family);
470
471	assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0);
472	assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0);
473	s->addrs = addrs.addr[0];
474
475	memset(&addrs, 0, sizeof(addrs));
476
477	addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
478	addrs.d.size_user = sizeof(sa_family_t);
479	olen = sizeof(addrs.d) + sizeof(sa_family_t);
480
481	ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
482	assert(ret == 0);
483	assert(olen == sizeof(addrs.d) + sizeof(sa_family_t));
484
485	assert(addrs.addr[0].sa_family == pf);
486	assert(addrs.addr[0].sa_family == local.ss_family);
487
488	assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) != 0);
489	assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) != 0);
490
491	do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS);
492}
493
494static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
495{
496	size_t data_size = sizeof(struct mptcp_full_info);
497	struct mptcp_subflow_info sfinfo[2];
498	struct tcp_info tcp_info[2];
499	struct mptcp_full_info mfi;
500	socklen_t olen;
501	int ret;
502
503	memset(&mfi, 0, data_size);
504	memset(tcp_info, 0, sizeof(tcp_info));
505	memset(sfinfo, 0, sizeof(sfinfo));
506
507	mfi.size_tcpinfo_user = sizeof(struct tcp_info);
508	mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info);
509	mfi.size_arrays_user = 2;
510	mfi.subflow_info = (unsigned long)&sfinfo[0];
511	mfi.tcp_info = (unsigned long)&tcp_info[0];
512	olen = data_size;
513
514	ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen);
515	if (ret < 0) {
516		if (errno == EOPNOTSUPP) {
517			perror("MPTCP_FULL_INFO test skipped");
518			return;
519		}
520		xerror("getsockopt MPTCP_FULL_INFO");
521	}
522
523	assert(olen <= data_size);
524	assert(mfi.size_tcpinfo_kernel > 0);
525	assert(mfi.size_tcpinfo_user ==
526	       MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info)));
527	assert(mfi.size_sfinfo_kernel > 0);
528	assert(mfi.size_sfinfo_user ==
529	       MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info)));
530	assert(mfi.num_subflows == 1);
531
532	/* Tolerate future extension to mptcp_info struct and running newer
533	 * test on top of older kernel.
534	 * Anyway any kernel supporting MPTCP_FULL_INFO must at least include
535	 * the following in mptcp_info.
536	 */
537	assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info));
538	assert(mfi.mptcp_info.mptcpi_subflows == 0);
539	assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent);
540	assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received);
541
542	assert(sfinfo[0].id == 1);
543	assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent);
544	assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received);
545	assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs)));
546}
547
548static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
549{
550	do_getsockopt_mptcp_info(s, fd, w);
551
552	do_getsockopt_tcp_info(s, fd, r, w);
553
554	do_getsockopt_subflow_addrs(s, fd);
555
556	if (r)
557		do_getsockopt_mptcp_full_info(s, fd);
558}
559
560static void connect_one_server(int fd, int pipefd)
561{
562	char buf[4096], buf2[4096];
563	size_t len, i, total;
564	struct so_state s;
565	bool eof = false;
566	ssize_t ret;
567
568	memset(&s, 0, sizeof(s));
569
570	len = rand() % (sizeof(buf) - 1);
571
572	if (len < 128)
573		len = 128;
574
575	for (i = 0; i < len ; i++) {
576		buf[i] = rand() % 26;
577		buf[i] += 'A';
578	}
579
580	buf[i] = '\n';
581
582	do_getsockopts(&s, fd, 0, 0);
583
584	/* un-block server */
585	ret = read(pipefd, buf2, 4);
586	assert(ret == 4);
587	close(pipefd);
588
589	assert(strncmp(buf2, "xmit", 4) == 0);
590
591	ret = write(fd, buf, len);
592	if (ret < 0)
593		die_perror("write");
594
595	if (ret != (ssize_t)len)
596		xerror("short write");
597
598	total = 0;
599	do {
600		ret = read(fd, buf2 + total, sizeof(buf2) - total);
601		if (ret < 0)
602			die_perror("read");
603		if (ret == 0) {
604			eof = true;
605			break;
606		}
607
608		total += ret;
609	} while (total < len);
610
611	if (total != len)
612		xerror("total %lu, len %lu eof %d\n", total, len, eof);
613
614	if (memcmp(buf, buf2, len))
615		xerror("data corruption");
616
617	if (s.tcpi_rcv_delta)
618		assert(s.tcpi_rcv_delta <= total);
619
620	do_getsockopts(&s, fd, ret, ret);
621
622	if (eof)
623		total += 1; /* sequence advances due to FIN */
624
625	assert(s.mptcpi_rcv_delta == (uint64_t)total);
626	close(fd);
627}
628
629static void process_one_client(int fd, int pipefd)
630{
631	ssize_t ret, ret2, ret3;
632	struct so_state s;
633	char buf[4096];
634
635	memset(&s, 0, sizeof(s));
636	do_getsockopts(&s, fd, 0, 0);
637
638	ret = write(pipefd, "xmit", 4);
639	assert(ret == 4);
640
641	ret = read(fd, buf, sizeof(buf));
642	if (ret < 0)
643		die_perror("read");
644
645	assert(s.mptcpi_rcv_delta <= (uint64_t)ret);
646
647	if (s.tcpi_rcv_delta)
648		assert(s.tcpi_rcv_delta == (uint64_t)ret);
649
650	ret2 = write(fd, buf, ret);
651	if (ret2 < 0)
652		die_perror("write");
653
654	/* wait for hangup */
655	ret3 = read(fd, buf, 1);
656	if (ret3 != 0)
657		xerror("expected EOF, got %lu", ret3);
658
659	do_getsockopts(&s, fd, ret, ret2);
660	if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
661		xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
662
663	/* be nice when running on top of older kernel */
664	if (s.pkt_stats_avail) {
665		if (s.last_sample.mptcpi_bytes_sent != ret2)
666			xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64,
667			       s.last_sample.mptcpi_bytes_sent, ret2,
668			       s.last_sample.mptcpi_bytes_sent - ret2);
669		if (s.last_sample.mptcpi_bytes_received != ret)
670			xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64,
671			       s.last_sample.mptcpi_bytes_received, ret,
672			       s.last_sample.mptcpi_bytes_received - ret);
673		if (s.last_sample.mptcpi_bytes_acked != ret)
674			xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64,
675			       s.last_sample.mptcpi_bytes_acked, ret2,
676			       s.last_sample.mptcpi_bytes_acked - ret2);
677	}
678
679	close(fd);
680}
681
682static int xaccept(int s)
683{
684	int fd = accept(s, NULL, 0);
685
686	if (fd < 0)
687		die_perror("accept");
688
689	return fd;
690}
691
692static int server(int pipefd)
693{
694	int fd = -1, r;
695
696	switch (pf) {
697	case AF_INET:
698		fd = sock_listen_mptcp("127.0.0.1", "15432");
699		break;
700	case AF_INET6:
701		fd = sock_listen_mptcp("::1", "15432");
702		break;
703	default:
704		xerror("Unknown pf %d\n", pf);
705		break;
706	}
707
708	r = write(pipefd, "conn", 4);
709	assert(r == 4);
710
711	alarm(15);
712	r = xaccept(fd);
713
714	process_one_client(r, pipefd);
715
716	return 0;
717}
718
719static void test_ip_tos_sockopt(int fd)
720{
721	uint8_t tos_in, tos_out;
722	socklen_t s;
723	int r;
724
725	tos_in = rand() & 0xfc;
726	r = setsockopt(fd, SOL_IP, IP_TOS, &tos_in, sizeof(tos_out));
727	if (r != 0)
728		die_perror("setsockopt IP_TOS");
729
730	tos_out = 0;
731	s = sizeof(tos_out);
732	r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
733	if (r != 0)
734		die_perror("getsockopt IP_TOS");
735
736	if (tos_in != tos_out)
737		xerror("tos %x != %x socklen_t %d\n", tos_in, tos_out, s);
738
739	if (s != 1)
740		xerror("tos should be 1 byte");
741
742	s = 0;
743	r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
744	if (r != 0)
745		die_perror("getsockopt IP_TOS 0");
746	if (s != 0)
747		xerror("expect socklen_t == 0");
748
749	s = -1;
750	r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
751	if (r != -1 && errno != EINVAL)
752		die_perror("getsockopt IP_TOS did not indicate -EINVAL");
753	if (s != -1)
754		xerror("expect socklen_t == -1");
755}
756
757static int client(int pipefd)
758{
759	int fd = -1;
760
761	alarm(15);
762
763	switch (pf) {
764	case AF_INET:
765		fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP);
766		break;
767	case AF_INET6:
768		fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP);
769		break;
770	default:
771		xerror("Unknown pf %d\n", pf);
772	}
773
774	test_ip_tos_sockopt(fd);
775
776	connect_one_server(fd, pipefd);
777
778	return 0;
779}
780
781static pid_t xfork(void)
782{
783	pid_t p = fork();
784
785	if (p < 0)
786		die_perror("fork");
787
788	return p;
789}
790
791static int rcheck(int wstatus, const char *what)
792{
793	if (WIFEXITED(wstatus)) {
794		if (WEXITSTATUS(wstatus) == 0)
795			return 0;
796		fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus));
797		return WEXITSTATUS(wstatus);
798	} else if (WIFSIGNALED(wstatus)) {
799		xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus));
800	} else if (WIFSTOPPED(wstatus)) {
801		xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus));
802	}
803
804	return 111;
805}
806
807static void init_rng(void)
808{
809	int fd = open("/dev/urandom", O_RDONLY);
810
811	if (fd >= 0) {
812		unsigned int foo;
813		ssize_t ret;
814
815		/* can't fail */
816		ret = read(fd, &foo, sizeof(foo));
817		assert(ret == sizeof(foo));
818
819		close(fd);
820		srand(foo);
821	} else {
822		srand(time(NULL));
823	}
824}
825
826int main(int argc, char *argv[])
827{
828	int e1, e2, wstatus;
829	pid_t s, c, ret;
830	int pipefds[2];
831
832	parse_opts(argc, argv);
833
834	init_rng();
835
836	e1 = pipe(pipefds);
837	if (e1 < 0)
838		die_perror("pipe");
839
840	s = xfork();
841	if (s == 0)
842		return server(pipefds[1]);
843
844	close(pipefds[1]);
845
846	/* wait until server bound a socket */
847	e1 = read(pipefds[0], &e1, 4);
848	assert(e1 == 4);
849
850	c = xfork();
851	if (c == 0)
852		return client(pipefds[0]);
853
854	close(pipefds[0]);
855
856	ret = waitpid(s, &wstatus, 0);
857	if (ret == -1)
858		die_perror("waitpid");
859	e1 = rcheck(wstatus, "server");
860	ret = waitpid(c, &wstatus, 0);
861	if (ret == -1)
862		die_perror("waitpid");
863	e2 = rcheck(wstatus, "client");
864
865	return e1 ? e1 : e2;
866}
867