~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/net/mptcp/mptcp_connect.c

Version: ~ [ linux-5.16 ] ~ [ linux-5.15.13 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.90 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.170 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.224 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.261 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.296 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.298 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 #define _GNU_SOURCE
  4 
  5 #include <errno.h>
  6 #include <limits.h>
  7 #include <fcntl.h>
  8 #include <string.h>
  9 #include <stdbool.h>
 10 #include <stdint.h>
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #include <strings.h>
 14 #include <unistd.h>
 15 
 16 #include <sys/poll.h>
 17 #include <sys/sendfile.h>
 18 #include <sys/stat.h>
 19 #include <sys/socket.h>
 20 #include <sys/types.h>
 21 #include <sys/mman.h>
 22 
 23 #include <netdb.h>
 24 #include <netinet/in.h>
 25 
 26 #include <linux/tcp.h>
 27 
 28 extern int optind;
 29 
 30 #ifndef IPPROTO_MPTCP
 31 #define IPPROTO_MPTCP 262
 32 #endif
 33 #ifndef TCP_ULP
 34 #define TCP_ULP 31
 35 #endif
 36 
 37 static int  poll_timeout = 10 * 1000;
 38 static bool listen_mode;
 39 
 40 enum cfg_mode {
 41         CFG_MODE_POLL,
 42         CFG_MODE_MMAP,
 43         CFG_MODE_SENDFILE,
 44 };
 45 
 46 static enum cfg_mode cfg_mode = CFG_MODE_POLL;
 47 static const char *cfg_host;
 48 static const char *cfg_port     = "12000";
 49 static int cfg_sock_proto       = IPPROTO_MPTCP;
 50 static bool tcpulp_audit;
 51 static int pf = AF_INET;
 52 static int cfg_sndbuf;
 53 static int cfg_rcvbuf;
 54 static bool cfg_join;
 55 
 56 static void die_usage(void)
 57 {
 58         fprintf(stderr, "Usage: mptcp_connect [-6] [-u] [-s MPTCP|TCP] [-p port] [-m mode]"
 59                 "[-l] connect_address\n");
 60         fprintf(stderr, "\t-6 use ipv6\n");
 61         fprintf(stderr, "\t-t num -- set poll timeout to num\n");
 62         fprintf(stderr, "\t-S num -- set SO_SNDBUF to num\n");
 63         fprintf(stderr, "\t-R num -- set SO_RCVBUF to num\n");
 64         fprintf(stderr, "\t-p num -- use port num\n");
 65         fprintf(stderr, "\t-m [MPTCP|TCP] -- use tcp or mptcp sockets\n");
 66         fprintf(stderr, "\t-s [mmap|poll] -- use poll (default) or mmap\n");
 67         fprintf(stderr, "\t-u -- check mptcp ulp\n");
 68         exit(1);
 69 }
 70 
 71 static const char *getxinfo_strerr(int err)
 72 {
 73         if (err == EAI_SYSTEM)
 74                 return strerror(errno);
 75 
 76         return gai_strerror(err);
 77 }
 78 
 79 static void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen,
 80                          char *host, socklen_t hostlen,
 81                          char *serv, socklen_t servlen)
 82 {
 83         int flags = NI_NUMERICHOST | NI_NUMERICSERV;
 84         int err = getnameinfo(addr, addrlen, host, hostlen, serv, servlen,
 85                               flags);
 86 
 87         if (err) {
 88                 const char *errstr = getxinfo_strerr(err);
 89 
 90                 fprintf(stderr, "Fatal: getnameinfo: %s\n", errstr);
 91                 exit(1);
 92         }
 93 }
 94 
 95 static void xgetaddrinfo(const char *node, const char *service,
 96                          const struct addrinfo *hints,
 97                          struct addrinfo **res)
 98 {
 99         int err = getaddrinfo(node, service, hints, res);
100 
101         if (err) {
102                 const char *errstr = getxinfo_strerr(err);
103 
104                 fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
105                         node ? node : "", service ? service : "", errstr);
106                 exit(1);
107         }
108 }
109 
110 static void set_rcvbuf(int fd, unsigned int size)
111 {
112         int err;
113 
114         err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
115         if (err) {
116                 perror("set SO_RCVBUF");
117                 exit(1);
118         }
119 }
120 
121 static void set_sndbuf(int fd, unsigned int size)
122 {
123         int err;
124 
125         err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
126         if (err) {
127                 perror("set SO_SNDBUF");
128                 exit(1);
129         }
130 }
131 
132 static int sock_listen_mptcp(const char * const listenaddr,
133                              const char * const port)
134 {
135         int sock;
136         struct addrinfo hints = {
137                 .ai_protocol = IPPROTO_TCP,
138                 .ai_socktype = SOCK_STREAM,
139                 .ai_flags = AI_PASSIVE | AI_NUMERICHOST
140         };
141 
142         hints.ai_family = pf;
143 
144         struct addrinfo *a, *addr;
145         int one = 1;
146 
147         xgetaddrinfo(listenaddr, port, &hints, &addr);
148         hints.ai_family = pf;
149 
150         for (a = addr; a; a = a->ai_next) {
151                 sock = socket(a->ai_family, a->ai_socktype, cfg_sock_proto);
152                 if (sock < 0)
153                         continue;
154 
155                 if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
156                                      sizeof(one)))
157                         perror("setsockopt");
158 
159                 if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
160                         break; /* success */
161 
162                 perror("bind");
163                 close(sock);
164                 sock = -1;
165         }
166 
167         freeaddrinfo(addr);
168 
169         if (sock < 0) {
170                 fprintf(stderr, "Could not create listen socket\n");
171                 return sock;
172         }
173 
174         if (listen(sock, 20)) {
175                 perror("listen");
176                 close(sock);
177                 return -1;
178         }
179 
180         return sock;
181 }
182 
183 static bool sock_test_tcpulp(const char * const remoteaddr,
184                              const char * const port)
185 {
186         struct addrinfo hints = {
187                 .ai_protocol = IPPROTO_TCP,
188                 .ai_socktype = SOCK_STREAM,
189         };
190         struct addrinfo *a, *addr;
191         int sock = -1, ret = 0;
192         bool test_pass = false;
193 
194         hints.ai_family = AF_INET;
195 
196         xgetaddrinfo(remoteaddr, port, &hints, &addr);
197         for (a = addr; a; a = a->ai_next) {
198                 sock = socket(a->ai_family, a->ai_socktype, IPPROTO_TCP);
199                 if (sock < 0) {
200                         perror("socket");
201                         continue;
202                 }
203                 ret = setsockopt(sock, IPPROTO_TCP, TCP_ULP, "mptcp",
204                                  sizeof("mptcp"));
205                 if (ret == -1 && errno == EOPNOTSUPP)
206                         test_pass = true;
207                 close(sock);
208 
209                 if (test_pass)
210                         break;
211                 if (!ret)
212                         fprintf(stderr,
213                                 "setsockopt(TCP_ULP) returned 0\n");
214                 else
215                         perror("setsockopt(TCP_ULP)");
216         }
217         return test_pass;
218 }
219 
220 static int sock_connect_mptcp(const char * const remoteaddr,
221                               const char * const port, int proto)
222 {
223         struct addrinfo hints = {
224                 .ai_protocol = IPPROTO_TCP,
225                 .ai_socktype = SOCK_STREAM,
226         };
227         struct addrinfo *a, *addr;
228         int sock = -1;
229 
230         hints.ai_family = pf;
231 
232         xgetaddrinfo(remoteaddr, port, &hints, &addr);
233         for (a = addr; a; a = a->ai_next) {
234                 sock = socket(a->ai_family, a->ai_socktype, proto);
235                 if (sock < 0) {
236                         perror("socket");
237                         continue;
238                 }
239 
240                 if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
241                         break; /* success */
242 
243                 perror("connect()");
244                 close(sock);
245                 sock = -1;
246         }
247 
248         freeaddrinfo(addr);
249         return sock;
250 }
251 
252 static size_t do_rnd_write(const int fd, char *buf, const size_t len)
253 {
254         static bool first = true;
255         unsigned int do_w;
256         ssize_t bw;
257 
258         do_w = rand() & 0xffff;
259         if (do_w == 0 || do_w > len)
260                 do_w = len;
261 
262         if (cfg_join && first && do_w > 100)
263                 do_w = 100;
264 
265         bw = write(fd, buf, do_w);
266         if (bw < 0)
267                 perror("write");
268 
269         /* let the join handshake complete, before going on */
270         if (cfg_join && first) {
271                 usleep(200000);
272                 first = false;
273         }
274 
275         return bw;
276 }
277 
278 static size_t do_write(const int fd, char *buf, const size_t len)
279 {
280         size_t offset = 0;
281 
282         while (offset < len) {
283                 size_t written;
284                 ssize_t bw;
285 
286                 bw = write(fd, buf + offset, len - offset);
287                 if (bw < 0) {
288                         perror("write");
289                         return 0;
290                 }
291 
292                 written = (size_t)bw;
293                 offset += written;
294         }
295 
296         return offset;
297 }
298 
299 static ssize_t do_rnd_read(const int fd, char *buf, const size_t len)
300 {
301         size_t cap = rand();
302 
303         cap &= 0xffff;
304 
305         if (cap == 0)
306                 cap = 1;
307         else if (cap > len)
308                 cap = len;
309 
310         return read(fd, buf, cap);
311 }
312 
313 static void set_nonblock(int fd)
314 {
315         int flags = fcntl(fd, F_GETFL);
316 
317         if (flags == -1)
318                 return;
319 
320         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
321 }
322 
323 static int copyfd_io_poll(int infd, int peerfd, int outfd)
324 {
325         struct pollfd fds = {
326                 .fd = peerfd,
327                 .events = POLLIN | POLLOUT,
328         };
329         unsigned int woff = 0, wlen = 0;
330         char wbuf[8192];
331 
332         set_nonblock(peerfd);
333 
334         for (;;) {
335                 char rbuf[8192];
336                 ssize_t len;
337 
338                 if (fds.events == 0)
339                         break;
340 
341                 switch (poll(&fds, 1, poll_timeout)) {
342                 case -1:
343                         if (errno == EINTR)
344                                 continue;
345                         perror("poll");
346                         return 1;
347                 case 0:
348                         fprintf(stderr, "%s: poll timed out (events: "
349                                 "POLLIN %u, POLLOUT %u)\n", __func__,
350                                 fds.events & POLLIN, fds.events & POLLOUT);
351                         return 2;
352                 }
353 
354                 if (fds.revents & POLLIN) {
355                         len = do_rnd_read(peerfd, rbuf, sizeof(rbuf));
356                         if (len == 0) {
357                                 /* no more data to receive:
358                                  * peer has closed its write side
359                                  */
360                                 fds.events &= ~POLLIN;
361 
362                                 if ((fds.events & POLLOUT) == 0)
363                                         /* and nothing more to send */
364                                         break;
365 
366                         /* Else, still have data to transmit */
367                         } else if (len < 0) {
368                                 perror("read");
369                                 return 3;
370                         }
371 
372                         do_write(outfd, rbuf, len);
373                 }
374 
375                 if (fds.revents & POLLOUT) {
376                         if (wlen == 0) {
377                                 woff = 0;
378                                 wlen = read(infd, wbuf, sizeof(wbuf));
379                         }
380 
381                         if (wlen > 0) {
382                                 ssize_t bw;
383 
384                                 bw = do_rnd_write(peerfd, wbuf + woff, wlen);
385                                 if (bw < 0)
386                                         return 111;
387 
388                                 woff += bw;
389                                 wlen -= bw;
390                         } else if (wlen == 0) {
391                                 /* We have no more data to send. */
392                                 fds.events &= ~POLLOUT;
393 
394                                 if ((fds.events & POLLIN) == 0)
395                                         /* ... and peer also closed already */
396                                         break;
397 
398                                 /* ... but we still receive.
399                                  * Close our write side, ev. give some time
400                                  * for address notification
401                                  */
402                                 if (cfg_join)
403                                         usleep(400000);
404                                 shutdown(peerfd, SHUT_WR);
405                         } else {
406                                 if (errno == EINTR)
407                                         continue;
408                                 perror("read");
409                                 return 4;
410                         }
411                 }
412 
413                 if (fds.revents & (POLLERR | POLLNVAL)) {
414                         fprintf(stderr, "Unexpected revents: "
415                                 "POLLERR/POLLNVAL(%x)\n", fds.revents);
416                         return 5;
417                 }
418         }
419 
420         /* leave some time for late join/announce */
421         if (cfg_join)
422                 usleep(400000);
423 
424         close(peerfd);
425         return 0;
426 }
427 
428 static int do_recvfile(int infd, int outfd)
429 {
430         ssize_t r;
431 
432         do {
433                 char buf[16384];
434 
435                 r = do_rnd_read(infd, buf, sizeof(buf));
436                 if (r > 0) {
437                         if (write(outfd, buf, r) != r)
438                                 break;
439                 } else if (r < 0) {
440                         perror("read");
441                 }
442         } while (r > 0);
443 
444         return (int)r;
445 }
446 
447 static int do_mmap(int infd, int outfd, unsigned int size)
448 {
449         char *inbuf = mmap(NULL, size, PROT_READ, MAP_SHARED, infd, 0);
450         ssize_t ret = 0, off = 0;
451         size_t rem;
452 
453         if (inbuf == MAP_FAILED) {
454                 perror("mmap");
455                 return 1;
456         }
457 
458         rem = size;
459 
460         while (rem > 0) {
461                 ret = write(outfd, inbuf + off, rem);
462 
463                 if (ret < 0) {
464                         perror("write");
465                         break;
466                 }
467 
468                 off += ret;
469                 rem -= ret;
470         }
471 
472         munmap(inbuf, size);
473         return rem;
474 }
475 
476 static int get_infd_size(int fd)
477 {
478         struct stat sb;
479         ssize_t count;
480         int err;
481 
482         err = fstat(fd, &sb);
483         if (err < 0) {
484                 perror("fstat");
485                 return -1;
486         }
487 
488         if ((sb.st_mode & S_IFMT) != S_IFREG) {
489                 fprintf(stderr, "%s: stdin is not a regular file\n", __func__);
490                 return -2;
491         }
492 
493         count = sb.st_size;
494         if (count > INT_MAX) {
495                 fprintf(stderr, "File too large: %zu\n", count);
496                 return -3;
497         }
498 
499         return (int)count;
500 }
501 
502 static int do_sendfile(int infd, int outfd, unsigned int count)
503 {
504         while (count > 0) {
505                 ssize_t r;
506 
507                 r = sendfile(outfd, infd, NULL, count);
508                 if (r < 0) {
509                         perror("sendfile");
510                         return 3;
511                 }
512 
513                 count -= r;
514         }
515 
516         return 0;
517 }
518 
519 static int copyfd_io_mmap(int infd, int peerfd, int outfd,
520                           unsigned int size)
521 {
522         int err;
523 
524         if (listen_mode) {
525                 err = do_recvfile(peerfd, outfd);
526                 if (err)
527                         return err;
528 
529                 err = do_mmap(infd, peerfd, size);
530         } else {
531                 err = do_mmap(infd, peerfd, size);
532                 if (err)
533                         return err;
534 
535                 shutdown(peerfd, SHUT_WR);
536 
537                 err = do_recvfile(peerfd, outfd);
538         }
539 
540         return err;
541 }
542 
543 static int copyfd_io_sendfile(int infd, int peerfd, int outfd,
544                               unsigned int size)
545 {
546         int err;
547 
548         if (listen_mode) {
549                 err = do_recvfile(peerfd, outfd);
550                 if (err)
551                         return err;
552 
553                 err = do_sendfile(infd, peerfd, size);
554         } else {
555                 err = do_sendfile(infd, peerfd, size);
556                 if (err)
557                         return err;
558                 err = do_recvfile(peerfd, outfd);
559         }
560 
561         return err;
562 }
563 
564 static int copyfd_io(int infd, int peerfd, int outfd)
565 {
566         int file_size;
567 
568         switch (cfg_mode) {
569         case CFG_MODE_POLL:
570                 return copyfd_io_poll(infd, peerfd, outfd);
571         case CFG_MODE_MMAP:
572                 file_size = get_infd_size(infd);
573                 if (file_size < 0)
574                         return file_size;
575                 return copyfd_io_mmap(infd, peerfd, outfd, file_size);
576         case CFG_MODE_SENDFILE:
577                 file_size = get_infd_size(infd);
578                 if (file_size < 0)
579                         return file_size;
580                 return copyfd_io_sendfile(infd, peerfd, outfd, file_size);
581         }
582 
583         fprintf(stderr, "Invalid mode %d\n", cfg_mode);
584 
585         die_usage();
586         return 1;
587 }
588 
589 static void check_sockaddr(int pf, struct sockaddr_storage *ss,
590                            socklen_t salen)
591 {
592         struct sockaddr_in6 *sin6;
593         struct sockaddr_in *sin;
594         socklen_t wanted_size = 0;
595 
596         switch (pf) {
597         case AF_INET:
598                 wanted_size = sizeof(*sin);
599                 sin = (void *)ss;
600                 if (!sin->sin_port)
601                         fprintf(stderr, "accept: something wrong: ip connection from port 0");
602                 break;
603         case AF_INET6:
604                 wanted_size = sizeof(*sin6);
605                 sin6 = (void *)ss;
606                 if (!sin6->sin6_port)
607                         fprintf(stderr, "accept: something wrong: ipv6 connection from port 0");
608                 break;
609         default:
610                 fprintf(stderr, "accept: Unknown pf %d, salen %u\n", pf, salen);
611                 return;
612         }
613 
614         if (salen != wanted_size)
615                 fprintf(stderr, "accept: size mismatch, got %d expected %d\n",
616                         (int)salen, wanted_size);
617 
618         if (ss->ss_family != pf)
619                 fprintf(stderr, "accept: pf mismatch, expect %d, ss_family is %d\n",
620                         (int)ss->ss_family, pf);
621 }
622 
623 static void check_getpeername(int fd, struct sockaddr_storage *ss, socklen_t salen)
624 {
625         struct sockaddr_storage peerss;
626         socklen_t peersalen = sizeof(peerss);
627 
628         if (getpeername(fd, (struct sockaddr *)&peerss, &peersalen) < 0) {
629                 perror("getpeername");
630                 return;
631         }
632 
633         if (peersalen != salen) {
634                 fprintf(stderr, "%s: %d vs %d\n", __func__, peersalen, salen);
635                 return;
636         }
637 
638         if (memcmp(ss, &peerss, peersalen)) {
639                 char a[INET6_ADDRSTRLEN];
640                 char b[INET6_ADDRSTRLEN];
641                 char c[INET6_ADDRSTRLEN];
642                 char d[INET6_ADDRSTRLEN];
643 
644                 xgetnameinfo((struct sockaddr *)ss, salen,
645                              a, sizeof(a), b, sizeof(b));
646 
647                 xgetnameinfo((struct sockaddr *)&peerss, peersalen,
648                              c, sizeof(c), d, sizeof(d));
649 
650                 fprintf(stderr, "%s: memcmp failure: accept %s vs peername %s, %s vs %s salen %d vs %d\n",
651                         __func__, a, c, b, d, peersalen, salen);
652         }
653 }
654 
655 static void check_getpeername_connect(int fd)
656 {
657         struct sockaddr_storage ss;
658         socklen_t salen = sizeof(ss);
659         char a[INET6_ADDRSTRLEN];
660         char b[INET6_ADDRSTRLEN];
661 
662         if (getpeername(fd, (struct sockaddr *)&ss, &salen) < 0) {
663                 perror("getpeername");
664                 return;
665         }
666 
667         xgetnameinfo((struct sockaddr *)&ss, salen,
668                      a, sizeof(a), b, sizeof(b));
669 
670         if (strcmp(cfg_host, a) || strcmp(cfg_port, b))
671                 fprintf(stderr, "%s: %s vs %s, %s vs %s\n", __func__,
672                         cfg_host, a, cfg_port, b);
673 }
674 
675 static void maybe_close(int fd)
676 {
677         unsigned int r = rand();
678 
679         if (!cfg_join && (r & 1))
680                 close(fd);
681 }
682 
683 int main_loop_s(int listensock)
684 {
685         struct sockaddr_storage ss;
686         struct pollfd polls;
687         socklen_t salen;
688         int remotesock;
689 
690         polls.fd = listensock;
691         polls.events = POLLIN;
692 
693         switch (poll(&polls, 1, poll_timeout)) {
694         case -1:
695                 perror("poll");
696                 return 1;
697         case 0:
698                 fprintf(stderr, "%s: timed out\n", __func__);
699                 close(listensock);
700                 return 2;
701         }
702 
703         salen = sizeof(ss);
704         remotesock = accept(listensock, (struct sockaddr *)&ss, &salen);
705         if (remotesock >= 0) {
706                 maybe_close(listensock);
707                 check_sockaddr(pf, &ss, salen);
708                 check_getpeername(remotesock, &ss, salen);
709 
710                 return copyfd_io(0, remotesock, 1);
711         }
712 
713         perror("accept");
714 
715         return 1;
716 }
717 
718 static void init_rng(void)
719 {
720         int fd = open("/dev/urandom", O_RDONLY);
721         unsigned int foo;
722 
723         if (fd > 0) {
724                 int ret = read(fd, &foo, sizeof(foo));
725 
726                 if (ret < 0)
727                         srand(fd + foo);
728                 close(fd);
729         }
730 
731         srand(foo);
732 }
733 
734 int main_loop(void)
735 {
736         int fd;
737 
738         /* listener is ready. */
739         fd = sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto);
740         if (fd < 0)
741                 return 2;
742 
743         check_getpeername_connect(fd);
744 
745         if (cfg_rcvbuf)
746                 set_rcvbuf(fd, cfg_rcvbuf);
747         if (cfg_sndbuf)
748                 set_sndbuf(fd, cfg_sndbuf);
749 
750         return copyfd_io(0, fd, 1);
751 }
752 
753 int parse_proto(const char *proto)
754 {
755         if (!strcasecmp(proto, "MPTCP"))
756                 return IPPROTO_MPTCP;
757         if (!strcasecmp(proto, "TCP"))
758                 return IPPROTO_TCP;
759 
760         fprintf(stderr, "Unknown protocol: %s\n.", proto);
761         die_usage();
762 
763         /* silence compiler warning */
764         return 0;
765 }
766 
767 int parse_mode(const char *mode)
768 {
769         if (!strcasecmp(mode, "poll"))
770                 return CFG_MODE_POLL;
771         if (!strcasecmp(mode, "mmap"))
772                 return CFG_MODE_MMAP;
773         if (!strcasecmp(mode, "sendfile"))
774                 return CFG_MODE_SENDFILE;
775 
776         fprintf(stderr, "Unknown test mode: %s\n", mode);
777         fprintf(stderr, "Supported modes are:\n");
778         fprintf(stderr, "\t\t\"poll\" - interleaved read/write using poll()\n");
779         fprintf(stderr, "\t\t\"mmap\" - send entire input file (mmap+write), then read response (-l will read input first)\n");
780         fprintf(stderr, "\t\t\"sendfile\" - send entire input file (sendfile), then read response (-l will read input first)\n");
781 
782         die_usage();
783 
784         /* silence compiler warning */
785         return 0;
786 }
787 
788 static int parse_int(const char *size)
789 {
790         unsigned long s;
791 
792         errno = 0;
793 
794         s = strtoul(size, NULL, 0);
795 
796         if (errno) {
797                 fprintf(stderr, "Invalid sndbuf size %s (%s)\n",
798                         size, strerror(errno));
799                 die_usage();
800         }
801 
802         if (s > INT_MAX) {
803                 fprintf(stderr, "Invalid sndbuf size %s (%s)\n",
804                         size, strerror(ERANGE));
805                 die_usage();
806         }
807 
808         return (int)s;
809 }
810 
811 static void parse_opts(int argc, char **argv)
812 {
813         int c;
814 
815         while ((c = getopt(argc, argv, "6jlp:s:hut:m:S:R:")) != -1) {
816                 switch (c) {
817                 case 'j':
818                         cfg_join = true;
819                         cfg_mode = CFG_MODE_POLL;
820                         break;
821                 case 'l':
822                         listen_mode = true;
823                         break;
824                 case 'p':
825                         cfg_port = optarg;
826                         break;
827                 case 's':
828                         cfg_sock_proto = parse_proto(optarg);
829                         break;
830                 case 'h':
831                         die_usage();
832                         break;
833                 case 'u':
834                         tcpulp_audit = true;
835                         break;
836                 case '6':
837                         pf = AF_INET6;
838                         break;
839                 case 't':
840                         poll_timeout = atoi(optarg) * 1000;
841                         if (poll_timeout <= 0)
842                                 poll_timeout = -1;
843                         break;
844                 case 'm':
845                         cfg_mode = parse_mode(optarg);
846                         break;
847                 case 'S':
848                         cfg_sndbuf = parse_int(optarg);
849                         break;
850                 case 'R':
851                         cfg_rcvbuf = parse_int(optarg);
852                         break;
853                 }
854         }
855 
856         if (optind + 1 != argc)
857                 die_usage();
858         cfg_host = argv[optind];
859 
860         if (strchr(cfg_host, ':'))
861                 pf = AF_INET6;
862 }
863 
864 int main(int argc, char *argv[])
865 {
866         init_rng();
867 
868         parse_opts(argc, argv);
869 
870         if (tcpulp_audit)
871                 return sock_test_tcpulp(cfg_host, cfg_port) ? 0 : 1;
872 
873         if (listen_mode) {
874                 int fd = sock_listen_mptcp(cfg_host, cfg_port);
875 
876                 if (fd < 0)
877                         return 1;
878 
879                 if (cfg_rcvbuf)
880                         set_rcvbuf(fd, cfg_rcvbuf);
881                 if (cfg_sndbuf)
882                         set_sndbuf(fd, cfg_sndbuf);
883 
884                 return main_loop_s(fd);
885         }
886 
887         return main_loop();
888 }
889 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp