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 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 176 static 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 222 static 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 253 static 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 272 static 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 349 static 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 372 static 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 421 done: 422 do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO); 423 } 424 425 static 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 494 static 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 548 static 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 560 static 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 629 static 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 682 static 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 692 static 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 719 static 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 757 static 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 781 static 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 791 static 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 807 static 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 826 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.