Home | History | Annotate | Download | only in src
      1 /*
      2  * iperf, Copyright (c) 2014-2018, The Regents of the University of
      3  * California, through Lawrence Berkeley National Laboratory (subject
      4  * to receipt of any required approvals from the U.S. Dept. of
      5  * Energy).  All rights reserved.
      6  *
      7  * If you have questions about your rights to use or distribute this
      8  * software, please contact Berkeley Lab's Technology Transfer
      9  * Department at TTD (at) lbl.gov.
     10  *
     11  * NOTICE.  This software is owned by the U.S. Department of Energy.
     12  * As such, the U.S. Government has been granted for itself and others
     13  * acting on its behalf a paid-up, nonexclusive, irrevocable,
     14  * worldwide license in the Software to reproduce, prepare derivative
     15  * works, and perform publicly and display publicly.  Beginning five
     16  * (5) years after the date permission to assert copyright is obtained
     17  * from the U.S. Department of Energy, and subject to any subsequent
     18  * five (5) year renewals, the U.S. Government is granted for itself
     19  * and others acting on its behalf a paid-up, nonexclusive,
     20  * irrevocable, worldwide license in the Software to reproduce,
     21  * prepare derivative works, distribute copies to the public, perform
     22  * publicly and display publicly, and to permit others to do so.
     23  *
     24  * This code is distributed under a BSD style license, see the LICENSE
     25  * file for complete information.
     26  */
     27 #include "iperf_config.h"
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <errno.h>
     33 #include <unistd.h>
     34 #include <sys/socket.h>
     35 #include <sys/types.h>
     36 #include <netinet/in.h>
     37 #include <netdb.h>
     38 #include <sys/time.h>
     39 #include <sys/select.h>
     40 #include <limits.h>
     41 
     42 #ifdef HAVE_NETINET_SCTP_H
     43 #include <netinet/sctp.h>
     44 #endif /* HAVE_NETINET_SCTP_H */
     45 
     46 #include "iperf.h"
     47 #include "iperf_api.h"
     48 #include "iperf_sctp.h"
     49 #include "net.h"
     50 
     51 
     52 
     53 /* iperf_sctp_recv
     54  *
     55  * receives the data for SCTP
     56  */
     57 int
     58 iperf_sctp_recv(struct iperf_stream *sp)
     59 {
     60 #if defined(HAVE_SCTP)
     61     int r;
     62 
     63     r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Psctp);
     64     if (r < 0)
     65         return r;
     66 
     67     /* Only count bytes received while we're in the correct state. */
     68     if (sp->test->state == TEST_RUNNING) {
     69 	sp->result->bytes_received += r;
     70 	sp->result->bytes_received_this_interval += r;
     71     }
     72     else {
     73 	if (sp->test->debug)
     74 	    printf("Late receive, state = %d\n", sp->test->state);
     75     }
     76 
     77     return r;
     78 #else
     79     i_errno = IENOSCTP;
     80     return -1;
     81 #endif /* HAVE_SCTP */
     82 }
     83 
     84 
     85 /* iperf_sctp_send
     86  *
     87  * sends the data for SCTP
     88  */
     89 int
     90 iperf_sctp_send(struct iperf_stream *sp)
     91 {
     92 #if defined(HAVE_SCTP)
     93     int r;
     94 
     95     r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Psctp);
     96     if (r < 0)
     97         return r;
     98 
     99     sp->result->bytes_sent += r;
    100     sp->result->bytes_sent_this_interval += r;
    101 
    102     return r;
    103 #else
    104     i_errno = IENOSCTP;
    105     return -1;
    106 #endif /* HAVE_SCTP */
    107 }
    108 
    109 
    110 
    111 /* iperf_sctp_accept
    112  *
    113  * accept a new SCTP stream connection
    114  */
    115 int
    116 iperf_sctp_accept(struct iperf_test * test)
    117 {
    118 #if defined(HAVE_SCTP)
    119     int     s;
    120     signed char rbuf = ACCESS_DENIED;
    121     char    cookie[COOKIE_SIZE];
    122     socklen_t len;
    123     struct sockaddr_storage addr;
    124 
    125     len = sizeof(addr);
    126     s = accept(test->listener, (struct sockaddr *) &addr, &len);
    127     if (s < 0) {
    128         i_errno = IESTREAMCONNECT;
    129         return -1;
    130     }
    131 
    132     if (Nread(s, cookie, COOKIE_SIZE, Psctp) < 0) {
    133         i_errno = IERECVCOOKIE;
    134         return -1;
    135     }
    136 
    137     if (strcmp(test->cookie, cookie) != 0) {
    138         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp) < 0) {
    139             i_errno = IESENDMESSAGE;
    140             return -1;
    141         }
    142         close(s);
    143     }
    144 
    145     return s;
    146 #else
    147     i_errno = IENOSCTP;
    148     return -1;
    149 #endif /* HAVE_SCTP */
    150 }
    151 
    152 
    153 /* iperf_sctp_listen
    154  *
    155  * start up a listener for SCTP stream connections
    156  */
    157 int
    158 iperf_sctp_listen(struct iperf_test *test)
    159 {
    160 #if defined(HAVE_SCTP)
    161     struct addrinfo hints, *res;
    162     char portstr[6];
    163     int s, opt, saved_errno;
    164 
    165     close(test->listener);
    166 
    167     snprintf(portstr, 6, "%d", test->server_port);
    168     memset(&hints, 0, sizeof(hints));
    169     /*
    170      * If binding to the wildcard address with no explicit address
    171      * family specified, then force us to get an AF_INET6 socket.
    172      * More details in the comments in netanounce().
    173      */
    174     if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
    175         hints.ai_family = AF_INET6;
    176     } else {
    177         hints.ai_family = test->settings->domain;
    178     }
    179     hints.ai_socktype = SOCK_STREAM;
    180     hints.ai_flags = AI_PASSIVE;
    181     if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
    182         i_errno = IESTREAMLISTEN;
    183         return -1;
    184     }
    185 
    186     if ((s = socket(res->ai_family, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
    187         freeaddrinfo(res);
    188         i_errno = IESTREAMLISTEN;
    189         return -1;
    190     }
    191 
    192 #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
    193     if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC ||
    194         test->settings->domain == AF_INET6)) {
    195         if (test->settings->domain == AF_UNSPEC)
    196             opt = 0;
    197         else
    198             opt = 1;
    199         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
    200 		       (char *) &opt, sizeof(opt)) < 0) {
    201 	    saved_errno = errno;
    202 	    close(s);
    203 	    freeaddrinfo(res);
    204 	    errno = saved_errno;
    205 	    i_errno = IEPROTOCOL;
    206 	    return -1;
    207 	}
    208     }
    209 #endif /* IPV6_V6ONLY */
    210 
    211     opt = 1;
    212     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
    213         saved_errno = errno;
    214         close(s);
    215         freeaddrinfo(res);
    216         errno = saved_errno;
    217         i_errno = IEREUSEADDR;
    218         return -1;
    219     }
    220 
    221     /* servers must call sctp_bindx() _instead_ of bind() */
    222     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
    223         freeaddrinfo(res);
    224         if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER))
    225             return -1;
    226     } else
    227     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
    228         saved_errno = errno;
    229         close(s);
    230         freeaddrinfo(res);
    231         errno = saved_errno;
    232         i_errno = IESTREAMLISTEN;
    233         return -1;
    234     }
    235 
    236     freeaddrinfo(res);
    237 
    238     if (listen(s, INT_MAX) < 0) {
    239         i_errno = IESTREAMLISTEN;
    240         return -1;
    241     }
    242 
    243     test->listener = s;
    244 
    245     return s;
    246 #else
    247     i_errno = IENOSCTP;
    248     return -1;
    249 #endif /* HAVE_SCTP */
    250 }
    251 
    252 
    253 /* iperf_sctp_connect
    254  *
    255  * connect to a SCTP stream listener
    256  */
    257 int
    258 iperf_sctp_connect(struct iperf_test *test)
    259 {
    260 #if defined(HAVE_SCTP)
    261     int s, opt, saved_errno;
    262     char portstr[6];
    263     struct addrinfo hints, *local_res, *server_res;
    264 
    265     if (test->bind_address) {
    266         memset(&hints, 0, sizeof(hints));
    267         hints.ai_family = test->settings->domain;
    268         hints.ai_socktype = SOCK_STREAM;
    269         if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
    270             i_errno = IESTREAMCONNECT;
    271             return -1;
    272         }
    273     }
    274 
    275     memset(&hints, 0, sizeof(hints));
    276     hints.ai_family = test->settings->domain;
    277     hints.ai_socktype = SOCK_STREAM;
    278     snprintf(portstr, sizeof(portstr), "%d", test->server_port);
    279     if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) {
    280 	if (test->bind_address)
    281 	    freeaddrinfo(local_res);
    282         i_errno = IESTREAMCONNECT;
    283         return -1;
    284     }
    285 
    286     s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP);
    287     if (s < 0) {
    288 	if (test->bind_address)
    289 	    freeaddrinfo(local_res);
    290 	freeaddrinfo(server_res);
    291         i_errno = IESTREAMCONNECT;
    292         return -1;
    293     }
    294 
    295     /*
    296      * Various ways to bind the local end of the connection.
    297      * 1.  --bind (with or without --cport).
    298      */
    299     if (test->bind_address) {
    300         struct sockaddr_in *lcladdr;
    301         lcladdr = (struct sockaddr_in *)local_res->ai_addr;
    302         lcladdr->sin_port = htons(test->bind_port);
    303 
    304         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
    305 	    saved_errno = errno;
    306 	    close(s);
    307 	    freeaddrinfo(local_res);
    308 	    freeaddrinfo(server_res);
    309 	    errno = saved_errno;
    310             i_errno = IESTREAMCONNECT;
    311             return -1;
    312         }
    313         freeaddrinfo(local_res);
    314     }
    315     /* --cport, no --bind */
    316     else if (test->bind_port) {
    317 	size_t addrlen;
    318 	struct sockaddr_storage lcl;
    319 
    320 	/* IPv4 */
    321 	if (server_res->ai_family == AF_INET) {
    322 	    struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
    323 	    lcladdr->sin_family = AF_INET;
    324 	    lcladdr->sin_port = htons(test->bind_port);
    325 	    lcladdr->sin_addr.s_addr = INADDR_ANY;
    326 	    addrlen = sizeof(struct sockaddr_in);
    327 	}
    328 	/* IPv6 */
    329 	else if (server_res->ai_family == AF_INET6) {
    330 	    struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
    331 	    lcladdr->sin6_family = AF_INET6;
    332 	    lcladdr->sin6_port = htons(test->bind_port);
    333 	    lcladdr->sin6_addr = in6addr_any;
    334 	    addrlen = sizeof(struct sockaddr_in6);
    335 	}
    336 	/* Unknown protocol */
    337 	else {
    338 	    saved_errno = errno;
    339 	    close(s);
    340 	    freeaddrinfo(server_res);
    341 	    errno = saved_errno;
    342             i_errno = IEPROTOCOL;
    343             return -1;
    344 	}
    345 
    346         if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
    347 	    saved_errno = errno;
    348 	    close(s);
    349 	    freeaddrinfo(server_res);
    350 	    errno = saved_errno;
    351             i_errno = IESTREAMCONNECT;
    352             return -1;
    353         }
    354     }
    355 
    356     if (test->no_delay != 0) {
    357          opt = 1;
    358          if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(opt)) < 0) {
    359              saved_errno = errno;
    360              close(s);
    361              freeaddrinfo(server_res);
    362              errno = saved_errno;
    363              i_errno = IESETNODELAY;
    364              return -1;
    365          }
    366     }
    367 
    368     if ((test->settings->mss >= 512 && test->settings->mss <= 131072)) {
    369 
    370 	/*
    371 	 * Some platforms use a struct sctp_assoc_value as the
    372 	 * argument to SCTP_MAXSEG.  Other (older API implementations)
    373 	 * take an int.  FreeBSD 10 and CentOS 6 support SCTP_MAXSEG,
    374 	 * but OpenSolaris 11 doesn't.
    375 	 */
    376 #ifdef HAVE_STRUCT_SCTP_ASSOC_VALUE
    377         struct sctp_assoc_value av;
    378 
    379 	/*
    380 	 * Some platforms support SCTP_FUTURE_ASSOC, others need to
    381 	 * (equivalently) do 0 here.  FreeBSD 10 is an example of the
    382 	 * former, CentOS 6 Linux is an example of the latter.
    383 	 */
    384 #ifdef SCTP_FUTURE_ASSOC
    385         av.assoc_id = SCTP_FUTURE_ASSOC;
    386 #else
    387 	av.assoc_id = 0;
    388 #endif
    389         av.assoc_value = test->settings->mss;
    390 
    391         if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &av, sizeof(av)) < 0) {
    392             saved_errno = errno;
    393             close(s);
    394             freeaddrinfo(server_res);
    395             errno = saved_errno;
    396             i_errno = IESETMSS;
    397             return -1;
    398         }
    399 #else
    400 	opt = test->settings->mss;
    401 
    402 	/*
    403 	 * Solaris might not support this option.  If it doesn't work,
    404 	 * ignore the error (at least for now).
    405 	 */
    406         if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &opt, sizeof(opt)) < 0 &&
    407 	    errno != ENOPROTOOPT) {
    408             saved_errno = errno;
    409             close(s);
    410             freeaddrinfo(server_res);
    411             errno = saved_errno;
    412             i_errno = IESETMSS;
    413             return -1;
    414         }
    415 #endif /* HAVE_STRUCT_SCTP_ASSOC_VALUE */
    416     }
    417 
    418     if (test->settings->num_ostreams > 0) {
    419         struct sctp_initmsg initmsg;
    420 
    421         memset(&initmsg, 0, sizeof(struct sctp_initmsg));
    422         initmsg.sinit_num_ostreams = test->settings->num_ostreams;
    423 
    424         if (setsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(struct sctp_initmsg)) < 0) {
    425                 saved_errno = errno;
    426                 close(s);
    427                 freeaddrinfo(server_res);
    428                 errno = saved_errno;
    429                 i_errno = IESETSCTPNSTREAM;
    430                 return -1;
    431         }
    432     }
    433 
    434     /* clients must call bind() followed by sctp_bindx() before connect() */
    435     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
    436         if (iperf_sctp_bindx(test, s, IPERF_SCTP_CLIENT))
    437             return -1;
    438     }
    439 
    440     /* TODO support sctp_connectx() to avoid heartbeating. */
    441     if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
    442 	saved_errno = errno;
    443 	close(s);
    444 	freeaddrinfo(server_res);
    445 	errno = saved_errno;
    446         i_errno = IESTREAMCONNECT;
    447         return -1;
    448     }
    449     freeaddrinfo(server_res);
    450 
    451     /* Send cookie for verification */
    452     if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp) < 0) {
    453 	saved_errno = errno;
    454 	close(s);
    455 	errno = saved_errno;
    456         i_errno = IESENDCOOKIE;
    457         return -1;
    458     }
    459 
    460     /*
    461      * We want to allow fragmentation.  But there's at least one
    462      * implementation (Solaris) that doesn't support this option,
    463      * even though it defines SCTP_DISABLE_FRAGMENTS.  So we have to
    464      * try setting the option and ignore the error, if it doesn't
    465      * work.
    466      */
    467     opt = 0;
    468     if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &opt, sizeof(opt)) < 0 &&
    469 	errno != ENOPROTOOPT) {
    470         saved_errno = errno;
    471         close(s);
    472         freeaddrinfo(server_res);
    473         errno = saved_errno;
    474         i_errno = IESETSCTPDISABLEFRAG;
    475         return -1;
    476     }
    477 
    478     return s;
    479 #else
    480     i_errno = IENOSCTP;
    481     return -1;
    482 #endif /* HAVE_SCTP */
    483 }
    484 
    485 
    486 
    487 int
    488 iperf_sctp_init(struct iperf_test *test)
    489 {
    490 #if defined(HAVE_SCTP)
    491     return 0;
    492 #else
    493     i_errno = IENOSCTP;
    494     return -1;
    495 #endif /* HAVE_SCTP */
    496 }
    497 
    498 
    499 
    500 /* iperf_sctp_bindx
    501  *
    502  * handle binding to multiple endpoints (-X parameters)
    503  */
    504 int
    505 iperf_sctp_bindx(struct iperf_test *test, int s, int is_server)
    506 {
    507 #if defined(HAVE_SCTP)
    508     struct addrinfo hints;
    509     char portstr[6];
    510     char *servname;
    511     struct addrinfo *ai, *ai0;
    512     struct sockaddr *xaddrs;
    513     struct xbind_entry *xbe, *xbe0;
    514     char *bp;
    515     size_t xaddrlen;
    516     int nxaddrs;
    517     int retval;
    518     int domain;
    519     int saved_errno;
    520 
    521     domain = test->settings->domain;
    522     xbe0 = NULL;
    523     retval = 0;
    524 
    525     if (TAILQ_EMPTY(&test->xbind_addrs))
    526         return retval; /* nothing to do */
    527 
    528     memset(&hints, 0, sizeof(hints));
    529     hints.ai_family = (domain == AF_UNSPEC ? AF_INET6 : domain);
    530     hints.ai_socktype = SOCK_STREAM;
    531     servname = NULL;
    532     if (is_server) {
    533         hints.ai_flags |= AI_PASSIVE;
    534         snprintf(portstr, 6, "%d", test->server_port);
    535         servname = portstr;
    536     }
    537 
    538     /* client: must pop first -X address and call bind().
    539      * sctp_bindx() must see the ephemeral port chosen by bind().
    540      * we deliberately ignore the -B argument in this case.
    541      */
    542     if (!is_server) {
    543         struct sockaddr *sa;
    544         struct sockaddr_in *sin;
    545         struct sockaddr_in6 *sin6;
    546         int eport;
    547 
    548         xbe0 = TAILQ_FIRST(&test->xbind_addrs);
    549         TAILQ_REMOVE(&test->xbind_addrs, xbe0, link);
    550 
    551         if (getaddrinfo(xbe0->name, servname, &hints, &xbe0->ai) != 0) {
    552             i_errno = IESETSCTPBINDX;
    553             retval = -1;
    554             goto out;
    555         }
    556 
    557         ai = xbe0->ai;
    558         if (domain != AF_UNSPEC && domain != ai->ai_family) {
    559             i_errno = IESETSCTPBINDX;
    560             retval = -1;
    561             goto out;
    562         }
    563         if (bind(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) < 0) {
    564             i_errno = IESETSCTPBINDX;
    565             retval = -1;
    566             goto out;
    567         }
    568 
    569         /* if only one -X argument, nothing more to do */
    570         if (TAILQ_EMPTY(&test->xbind_addrs))
    571             goto out;
    572 
    573         sa = (struct sockaddr *)ai->ai_addr;
    574         if (sa->sa_family == AF_INET) {
    575             sin = (struct sockaddr_in *)ai->ai_addr;
    576             eport = sin->sin_port;
    577         } else if (sa->sa_family == AF_INET6) {
    578             sin6 = (struct sockaddr_in6 *)ai->ai_addr;
    579             eport = sin6->sin6_port;
    580         } else {
    581             i_errno = IESETSCTPBINDX;
    582             retval = -1;
    583             goto out;
    584         }
    585         snprintf(portstr, 6, "%d", ntohs(eport));
    586         servname = portstr;
    587     }
    588 
    589     /* pass 1: resolve and compute lengths. */
    590     nxaddrs = 0;
    591     xaddrlen = 0;
    592     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
    593         if (xbe->ai != NULL)
    594             freeaddrinfo(xbe->ai);
    595         if (getaddrinfo(xbe->name, servname, &hints, &xbe->ai) != 0) {
    596             i_errno = IESETSCTPBINDX;
    597             retval = -1;
    598             goto out;
    599         }
    600         ai0 = xbe->ai;
    601         for (ai = ai0; ai; ai = ai->ai_next) {
    602             if (domain != AF_UNSPEC && domain != ai->ai_family)
    603                 continue;
    604             xaddrlen += ai->ai_addrlen;
    605             ++nxaddrs;
    606         }
    607     }
    608 
    609     /* pass 2: copy into flat buffer. */
    610     xaddrs = (struct sockaddr *)malloc(xaddrlen);
    611     if (!xaddrs) {
    612             i_errno = IESETSCTPBINDX;
    613             retval = -1;
    614             goto out;
    615     }
    616     bp = (char *)xaddrs;
    617     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
    618         ai0 = xbe->ai;
    619         for (ai = ai0; ai; ai = ai->ai_next) {
    620             if (domain != AF_UNSPEC && domain != ai->ai_family)
    621                 continue;
    622 	    memcpy(bp, ai->ai_addr, ai->ai_addrlen);
    623             bp += ai->ai_addrlen;
    624         }
    625     }
    626 
    627     if (sctp_bindx(s, xaddrs, nxaddrs, SCTP_BINDX_ADD_ADDR) == -1) {
    628         saved_errno = errno;
    629         close(s);
    630         free(xaddrs);
    631         errno = saved_errno;
    632         i_errno = IESETSCTPBINDX;
    633         retval = -1;
    634         goto out;
    635     }
    636 
    637     free(xaddrs);
    638     retval = 0;
    639 
    640 out:
    641     /* client: put head node back. */
    642     if (!is_server && xbe0)
    643         TAILQ_INSERT_HEAD(&test->xbind_addrs, xbe0, link);
    644 
    645     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
    646         if (xbe->ai) {
    647             freeaddrinfo(xbe->ai);
    648             xbe->ai = NULL;
    649         }
    650     }
    651 
    652     return retval;
    653 #else
    654     i_errno = IENOSCTP;
    655     return -1;
    656 #endif /* HAVE_SCTP */
    657 }
    658