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