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 130 static void die_perror(const char *msg) 131 { 132 perror(msg); 133 exit(1); 134 } 135 136 static void die_usage(int r) 137 { 138 fprintf(stderr, "Usage: mptcp_sockopt [-6]\n"); 139 exit(r); 140 } 141 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 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 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 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 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 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 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 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 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 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 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 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 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 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, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret); 671 672 /* be nice when running on top of older kernel */ 673 if (s.pkt_stats_avail) { 674 if (s.last_sample.mptcpi_bytes_sent != ret2) 675 xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64, 676 s.last_sample.mptcpi_bytes_sent, ret2, 677 s.last_sample.mptcpi_bytes_sent - ret2); 678 if (s.last_sample.mptcpi_bytes_received != ret) 679 xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64, 680 s.last_sample.mptcpi_bytes_received, ret, 681 s.last_sample.mptcpi_bytes_received - ret); 682 if (s.last_sample.mptcpi_bytes_acked != ret) 683 xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64, 684 s.last_sample.mptcpi_bytes_acked, ret2, 685 s.last_sample.mptcpi_bytes_acked - ret2); 686 } 687 688 close(fd); 689 } 690 691 static int xaccept(int s) 692 { 693 int fd = accept(s, NULL, 0); 694 695 if (fd < 0) 696 die_perror("accept"); 697 698 return fd; 699 } 700 701 static int server(int pipefd) 702 { 703 int fd = -1, r; 704 705 switch (pf) { 706 case AF_INET: 707 fd = sock_listen_mptcp("127.0.0.1", "15432"); 708 break; 709 case AF_INET6: 710 fd = sock_listen_mptcp("::1", "15432"); 711 break; 712 default: 713 xerror("Unknown pf %d\n", pf); 714 break; 715 } 716 717 r = write(pipefd, "conn", 4); 718 assert(r == 4); 719 720 alarm(15); 721 r = xaccept(fd); 722 723 process_one_client(r, pipefd); 724 725 return 0; 726 } 727 728 static void test_ip_tos_sockopt(int fd) 729 { 730 uint8_t tos_in, tos_out; 731 socklen_t s; 732 int r; 733 734 tos_in = rand() & 0xfc; 735 r = setsockopt(fd, SOL_IP, IP_TOS, &tos_in, sizeof(tos_out)); 736 if (r != 0) 737 die_perror("setsockopt IP_TOS"); 738 739 tos_out = 0; 740 s = sizeof(tos_out); 741 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s); 742 if (r != 0) 743 die_perror("getsockopt IP_TOS"); 744 745 if (tos_in != tos_out) 746 xerror("tos %x != %x socklen_t %d\n", tos_in, tos_out, s); 747 748 if (s != 1) 749 xerror("tos should be 1 byte"); 750 751 s = 0; 752 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s); 753 if (r != 0) 754 die_perror("getsockopt IP_TOS 0"); 755 if (s != 0) 756 xerror("expect socklen_t == 0"); 757 758 s = -1; 759 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s); 760 if (r != -1 && errno != EINVAL) 761 die_perror("getsockopt IP_TOS did not indicate -EINVAL"); 762 if (s != -1) 763 xerror("expect socklen_t == -1"); 764 } 765 766 static int client(int pipefd) 767 { 768 int fd = -1; 769 770 alarm(15); 771 772 switch (pf) { 773 case AF_INET: 774 fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP); 775 break; 776 case AF_INET6: 777 fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP); 778 break; 779 default: 780 xerror("Unknown pf %d\n", pf); 781 } 782 783 test_ip_tos_sockopt(fd); 784 785 connect_one_server(fd, pipefd); 786 787 return 0; 788 } 789 790 static pid_t xfork(void) 791 { 792 pid_t p = fork(); 793 794 if (p < 0) 795 die_perror("fork"); 796 797 return p; 798 } 799 800 static int rcheck(int wstatus, const char *what) 801 { 802 if (WIFEXITED(wstatus)) { 803 if (WEXITSTATUS(wstatus) == 0) 804 return 0; 805 fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus)); 806 return WEXITSTATUS(wstatus); 807 } else if (WIFSIGNALED(wstatus)) { 808 xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus)); 809 } else if (WIFSTOPPED(wstatus)) { 810 xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus)); 811 } 812 813 return 111; 814 } 815 816 static void init_rng(void) 817 { 818 int fd = open("/dev/urandom", O_RDONLY); 819 820 if (fd >= 0) { 821 unsigned int foo; 822 ssize_t ret; 823 824 /* can't fail */ 825 ret = read(fd, &foo, sizeof(foo)); 826 assert(ret == sizeof(foo)); 827 828 close(fd); 829 srand(foo); 830 } else { 831 srand(time(NULL)); 832 } 833 } 834 835 int main(int argc, char *argv[]) 836 { 837 int e1, e2, wstatus; 838 pid_t s, c, ret; 839 int pipefds[2]; 840 841 parse_opts(argc, argv); 842 843 init_rng(); 844 845 e1 = pipe(pipefds); 846 if (e1 < 0) 847 die_perror("pipe"); 848 849 s = xfork(); 850 if (s == 0) 851 return server(pipefds[1]); 852 853 close(pipefds[1]); 854 855 /* wait until server bound a socket */ 856 e1 = read(pipefds[0], &e1, 4); 857 assert(e1 == 4); 858 859 c = xfork(); 860 if (c == 0) 861 return client(pipefds[0]); 862 863 close(pipefds[0]); 864 865 ret = waitpid(s, &wstatus, 0); 866 if (ret == -1) 867 die_perror("waitpid"); 868 e1 = rcheck(wstatus, "server"); 869 ret = waitpid(c, &wstatus, 0); 870 if (ret == -1) 871 die_perror("waitpid"); 872 e2 = rcheck(wstatus, "client"); 873 874 return e1 ? e1 : e2; 875 } 876