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