1 // SPDX-License-Identifier: GPL-2.0
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
26 #include <netinet/in.h>
28 #include <linux/tcp.h>
29 #include <linux/sockios.h>
32 #define IPPROTO_MPTCP 262
38 static int pf = AF_INET;
39 static int proto_tx = IPPROTO_MPTCP;
40 static int proto_rx = IPPROTO_MPTCP;
42 static void die_perror(const char *msg)
48 static void die_usage(int r)
50 fprintf(stderr, "Usage: mptcp_inq [-6] [ -t tcp|mptcp ] [ -r tcp|mptcp]\n");
54 static void xerror(const char *fmt, ...)
59 vfprintf(stderr, fmt, ap);
65 static const char *getxinfo_strerr(int err)
67 if (err == EAI_SYSTEM)
68 return strerror(errno);
70 return gai_strerror(err);
73 static void xgetaddrinfo(const char *node, const char *service,
74 const struct addrinfo *hints,
75 struct addrinfo **res)
77 int err = getaddrinfo(node, service, hints, res);
80 const char *errstr = getxinfo_strerr(err);
82 fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
83 node ? node : "", service ? service : "", errstr);
88 static int sock_listen_mptcp(const char * const listenaddr,
89 const char * const port)
92 struct addrinfo hints = {
93 .ai_protocol = IPPROTO_TCP,
94 .ai_socktype = SOCK_STREAM,
95 .ai_flags = AI_PASSIVE | AI_NUMERICHOST
100 struct addrinfo *a, *addr;
103 xgetaddrinfo(listenaddr, port, &hints, &addr);
104 hints.ai_family = pf;
106 for (a = addr; a; a = a->ai_next) {
107 sock = socket(a->ai_family, a->ai_socktype, proto_rx);
111 if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
113 perror("setsockopt");
115 if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
126 xerror("could not create listen socket");
128 if (listen(sock, 20))
129 die_perror("listen");
134 static int sock_connect_mptcp(const char * const remoteaddr,
135 const char * const port, int proto)
137 struct addrinfo hints = {
138 .ai_protocol = IPPROTO_TCP,
139 .ai_socktype = SOCK_STREAM,
141 struct addrinfo *a, *addr;
144 hints.ai_family = pf;
146 xgetaddrinfo(remoteaddr, port, &hints, &addr);
147 for (a = addr; a; a = a->ai_next) {
148 sock = socket(a->ai_family, a->ai_socktype, proto);
152 if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
155 die_perror("connect");
159 xerror("could not create connect socket");
165 static int protostr_to_num(const char *s)
167 if (strcasecmp(s, "tcp") == 0)
169 if (strcasecmp(s, "mptcp") == 0)
170 return IPPROTO_MPTCP;
176 static void parse_opts(int argc, char **argv)
180 while ((c = getopt(argc, argv, "h6t:r:")) != -1) {
189 proto_tx = protostr_to_num(optarg);
192 proto_rx = protostr_to_num(optarg);
201 /* wait up to timeout milliseconds */
202 static void wait_for_ack(int fd, int timeout, size_t total)
206 for (i = 0; i < timeout; i++) {
207 int nsd, ret, queued = -1;
210 ret = ioctl(fd, TIOCOUTQ, &queued);
212 die_perror("TIOCOUTQ");
214 ret = ioctl(fd, SIOCOUTQNSD, &nsd);
216 die_perror("SIOCOUTQNSD");
218 if ((size_t)queued > total)
219 xerror("TIOCOUTQ %u, but only %zu expected\n", queued, total);
220 assert(nsd <= queued);
225 /* wait for peer to ack rx of all data */
227 req.tv_nsec = 1 * 1000 * 1000ul; /* 1ms */
228 nanosleep(&req, NULL);
231 xerror("still tx data queued after %u ms\n", timeout);
234 static void connect_one_server(int fd, int unixfd)
236 size_t len, i, total, sent;
237 char buf[4096], buf2[4096];
240 len = rand() % (sizeof(buf) - 1);
245 for (i = 0; i < len ; i++) {
246 buf[i] = rand() % 26;
252 /* un-block server */
253 ret = read(unixfd, buf2, 4);
256 assert(strncmp(buf2, "xmit", 4) == 0);
258 ret = write(unixfd, &len, sizeof(len));
259 assert(ret == (ssize_t)sizeof(len));
261 ret = write(fd, buf, len);
265 if (ret != (ssize_t)len)
266 xerror("short write");
268 ret = read(unixfd, buf2, 4);
269 assert(strncmp(buf2, "huge", 4) == 0);
271 total = rand() % (16 * 1024 * 1024);
272 total += (1 * 1024 * 1024);
275 ret = write(unixfd, &total, sizeof(total));
276 assert(ret == (ssize_t)sizeof(total));
278 wait_for_ack(fd, 5000, len);
281 if (total > sizeof(buf))
286 ret = write(fd, buf, len);
291 /* we don't have to care about buf content, only
292 * number of total bytes sent
296 ret = read(unixfd, buf2, 4);
298 assert(strncmp(buf2, "shut", 4) == 0);
300 wait_for_ack(fd, 5000, sent);
302 ret = write(fd, buf, 1);
305 ret = write(unixfd, "closed", 6);
311 static void get_tcp_inq(struct msghdr *msgh, unsigned int *inqv)
313 struct cmsghdr *cmsg;
315 for (cmsg = CMSG_FIRSTHDR(msgh); cmsg ; cmsg = CMSG_NXTHDR(msgh, cmsg)) {
316 if (cmsg->cmsg_level == IPPROTO_TCP && cmsg->cmsg_type == TCP_CM_INQ) {
317 memcpy(inqv, CMSG_DATA(cmsg), sizeof(*inqv));
322 xerror("could not find TCP_CM_INQ cmsg type");
325 static void process_one_client(int fd, int unixfd)
327 unsigned int tcp_inq;
336 struct msghdr msg = {
339 .msg_control = msg_buf,
340 .msg_controllen = sizeof(msg_buf),
344 ret = write(unixfd, "xmit", 4);
347 ret = read(unixfd, &expect_len, sizeof(expect_len));
348 assert(ret == (ssize_t)sizeof(expect_len));
350 if (expect_len > sizeof(buf))
351 xerror("expect len %zu exceeds buffer size", expect_len);
357 ret = ioctl(fd, FIONREAD, &queued);
359 die_perror("FIONREAD");
360 if (queued > expect_len)
361 xerror("FIONREAD returned %u, but only %zu expected\n",
363 if (queued == expect_len)
367 req.tv_nsec = 1000 * 1000ul;
368 nanosleep(&req, NULL);
371 /* read one byte, expect cmsg to return expected - 1 */
372 ret = recvmsg(fd, &msg, 0);
374 die_perror("recvmsg");
376 if (msg.msg_controllen == 0)
377 xerror("msg_controllen is 0");
379 get_tcp_inq(&msg, &tcp_inq);
381 assert((size_t)tcp_inq == (expect_len - 1));
383 iov.iov_len = sizeof(buf);
384 ret = recvmsg(fd, &msg, 0);
386 die_perror("recvmsg");
388 /* should have gotten exact remainder of all pending data */
389 assert(ret == (ssize_t)tcp_inq);
391 /* should be 0, all drained */
392 get_tcp_inq(&msg, &tcp_inq);
393 assert(tcp_inq == 0);
395 /* request a large swath of data. */
396 ret = write(unixfd, "huge", 4);
399 ret = read(unixfd, &expect_len, sizeof(expect_len));
400 assert(ret == (ssize_t)sizeof(expect_len));
402 /* peer should send us a few mb of data */
403 if (expect_len <= sizeof(buf))
404 xerror("expect len %zu too small\n", expect_len);
408 iov.iov_len = sizeof(buf);
409 ret = recvmsg(fd, &msg, 0);
411 die_perror("recvmsg");
415 get_tcp_inq(&msg, &tcp_inq);
417 if (tcp_inq > expect_len - tot)
418 xerror("inq %d, remaining %d total_len %d\n",
419 tcp_inq, expect_len - tot, (int)expect_len);
421 assert(tcp_inq <= expect_len - tot);
422 } while ((size_t)tot < expect_len);
424 ret = write(unixfd, "shut", 4);
427 /* wait for hangup. Should have received one more byte of data. */
428 ret = read(unixfd, tmp, sizeof(tmp));
430 assert(strncmp(tmp, "closed", 6) == 0);
435 ret = recvmsg(fd, &msg, 0);
437 die_perror("recvmsg");
440 get_tcp_inq(&msg, &tcp_inq);
442 /* tcp_inq should be 1 due to received fin. */
443 assert(tcp_inq == 1);
446 ret = recvmsg(fd, &msg, 0);
448 die_perror("recvmsg");
452 get_tcp_inq(&msg, &tcp_inq);
453 assert(tcp_inq == 1);
458 static int xaccept(int s)
460 int fd = accept(s, NULL, 0);
463 die_perror("accept");
468 static int server(int unixfd)
470 int fd = -1, r, on = 1;
474 fd = sock_listen_mptcp("127.0.0.1", "15432");
477 fd = sock_listen_mptcp("::1", "15432");
480 xerror("Unknown pf %d\n", pf);
484 r = write(unixfd, "conn", 4);
490 if (-1 == setsockopt(r, IPPROTO_TCP, TCP_INQ, &on, sizeof(on)))
491 die_perror("setsockopt");
493 process_one_client(r, unixfd);
498 static int client(int unixfd)
506 fd = sock_connect_mptcp("127.0.0.1", "15432", proto_tx);
509 fd = sock_connect_mptcp("::1", "15432", proto_tx);
512 xerror("Unknown pf %d\n", pf);
515 connect_one_server(fd, unixfd);
520 static void init_rng(void)
522 int fd = open("/dev/urandom", O_RDONLY);
526 int ret = read(fd, &foo, sizeof(foo));
536 static pid_t xfork(void)
548 static int rcheck(int wstatus, const char *what)
550 if (WIFEXITED(wstatus)) {
551 if (WEXITSTATUS(wstatus) == 0)
553 fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus));
554 return WEXITSTATUS(wstatus);
555 } else if (WIFSIGNALED(wstatus)) {
556 xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus));
557 } else if (WIFSTOPPED(wstatus)) {
558 xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus));
564 int main(int argc, char *argv[])
570 parse_opts(argc, argv);
572 e1 = socketpair(AF_UNIX, SOCK_DGRAM, 0, unixfds);
578 return server(unixfds[1]);
582 /* wait until server bound a socket */
583 e1 = read(unixfds[0], &e1, 4);
588 return client(unixfds[0]);
592 ret = waitpid(s, &wstatus, 0);
594 die_perror("waitpid");
595 e1 = rcheck(wstatus, "server");
596 ret = waitpid(c, &wstatus, 0);
598 die_perror("waitpid");
599 e2 = rcheck(wstatus, "client");