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