Annotation of embedaddon/iperf/src/iperf_sctp.c, revision 1.1.1.3

1.1       misho       1: /*
1.1.1.2   misho       2:  * iperf, Copyright (c) 2014-2019, The Regents of the University of
1.1       misho       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@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>
1.1.1.2   misho      40: #include <limits.h>
1.1       misho      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: {
1.1.1.2   misho      60: #if defined(HAVE_SCTP_H)
1.1       misho      61:     int r;
                     62: 
                     63:     r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Psctp);
                     64:     if (r < 0)
                     65:         return r;
                     66: 
1.1.1.2   misho      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:     }
1.1       misho      76: 
                     77:     return r;
                     78: #else
                     79:     i_errno = IENOSCTP;
                     80:     return -1;
1.1.1.2   misho      81: #endif /* HAVE_SCTP_H */
1.1       misho      82: }
                     83: 
                     84: 
1.1.1.3 ! misho      85: /* iperf_sctp_send
1.1       misho      86:  *
                     87:  * sends the data for SCTP
                     88:  */
                     89: int
                     90: iperf_sctp_send(struct iperf_stream *sp)
                     91: {
1.1.1.2   misho      92: #if defined(HAVE_SCTP_H)
1.1       misho      93:     int r;
                     94: 
                     95:     r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Psctp);
                     96:     if (r < 0)
1.1.1.3 ! misho      97:         return r;
1.1       misho      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;
1.1.1.2   misho     106: #endif /* HAVE_SCTP_H */
1.1       misho     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: {
1.1.1.2   misho     118: #if defined(HAVE_SCTP_H)
1.1       misho     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;
1.1.1.2   misho     134:         close(s);
1.1       misho     135:         return -1;
                    136:     }
                    137: 
1.1.1.2   misho     138:     if (strncmp(test->cookie, cookie, COOKIE_SIZE) != 0) {
1.1       misho     139:         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp) < 0) {
                    140:             i_errno = IESENDMESSAGE;
1.1.1.2   misho     141:             close(s);
1.1       misho     142:             return -1;
                    143:         }
                    144:         close(s);
                    145:     }
                    146: 
                    147:     return s;
                    148: #else
                    149:     i_errno = IENOSCTP;
                    150:     return -1;
1.1.1.2   misho     151: #endif /* HAVE_SCTP_H */
1.1       misho     152: }
                    153: 
                    154: 
                    155: /* iperf_sctp_listen
                    156:  *
                    157:  * start up a listener for SCTP stream connections
                    158:  */
                    159: int
                    160: iperf_sctp_listen(struct iperf_test *test)
                    161: {
1.1.1.2   misho     162: #if defined(HAVE_SCTP_H)
1.1       misho     163:     struct addrinfo hints, *res;
                    164:     char portstr[6];
1.1.1.2   misho     165:     int s, opt, saved_errno;
1.1       misho     166: 
                    167:     close(test->listener);
1.1.1.3 ! misho     168:     test->listener = -1;
        !           169: 
1.1       misho     170:     snprintf(portstr, 6, "%d", test->server_port);
                    171:     memset(&hints, 0, sizeof(hints));
1.1.1.2   misho     172:     /*
                    173:      * If binding to the wildcard address with no explicit address
                    174:      * family specified, then force us to get an AF_INET6 socket.
                    175:      * More details in the comments in netanounce().
                    176:      */
                    177:     if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
                    178:         hints.ai_family = AF_INET6;
                    179:     } else {
                    180:         hints.ai_family = test->settings->domain;
                    181:     }
1.1       misho     182:     hints.ai_socktype = SOCK_STREAM;
                    183:     hints.ai_flags = AI_PASSIVE;
1.1.1.2   misho     184:     if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
1.1       misho     185:         i_errno = IESTREAMLISTEN;
                    186:         return -1;
                    187:     }
                    188: 
                    189:     if ((s = socket(res->ai_family, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
                    190:         freeaddrinfo(res);
                    191:         i_errno = IESTREAMLISTEN;
                    192:         return -1;
                    193:     }
                    194: 
1.1.1.2   misho     195:     if ((opt = test->settings->socket_bufsize)) {
                    196:         int saved_errno;
                    197:         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
                    198:             saved_errno = errno;
                    199:             close(s);
                    200:             freeaddrinfo(res);
                    201:             errno = saved_errno;
                    202:             i_errno = IESETBUF;
                    203:             return -1;
                    204:         }
                    205:         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
                    206:             saved_errno = errno;
                    207:             close(s);
                    208:             freeaddrinfo(res);
                    209:             errno = saved_errno;
                    210:             i_errno = IESETBUF;
                    211:             return -1;
                    212:         }
                    213:     }
                    214: 
1.1.1.3 ! misho     215:     if (test->bind_dev) {
        !           216: #if defined(SO_BINDTODEVICE)
        !           217:         if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
        !           218:                        test->bind_dev, IFNAMSIZ) < 0)
        !           219: #endif // SO_BINDTODEVICE
        !           220:         {
        !           221:             saved_errno = errno;
        !           222:             close(s);
        !           223:             freeaddrinfo(res);
        !           224:             i_errno = IEBINDDEV;
        !           225:             errno = saved_errno;
        !           226:             return -1;
        !           227:         }
        !           228:     }
        !           229: 
1.1       misho     230: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
1.1.1.3 ! misho     231:     if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC ||
1.1.1.2   misho     232:         test->settings->domain == AF_INET6)) {
1.1       misho     233:         if (test->settings->domain == AF_UNSPEC)
                    234:             opt = 0;
1.1.1.2   misho     235:         else
1.1       misho     236:             opt = 1;
1.1.1.3 ! misho     237:         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
1.1       misho     238:                       (char *) &opt, sizeof(opt)) < 0) {
1.1.1.2   misho     239:            saved_errno = errno;
1.1       misho     240:            close(s);
                    241:            freeaddrinfo(res);
1.1.1.2   misho     242:            errno = saved_errno;
1.1       misho     243:            i_errno = IEPROTOCOL;
                    244:            return -1;
                    245:        }
                    246:     }
                    247: #endif /* IPV6_V6ONLY */
                    248: 
                    249:     opt = 1;
                    250:     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
1.1.1.2   misho     251:         saved_errno = errno;
1.1       misho     252:         close(s);
                    253:         freeaddrinfo(res);
1.1.1.2   misho     254:         errno = saved_errno;
1.1       misho     255:         i_errno = IEREUSEADDR;
                    256:         return -1;
                    257:     }
                    258: 
                    259:     /* servers must call sctp_bindx() _instead_ of bind() */
                    260:     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
1.1.1.2   misho     261:         if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER)) {
                    262:             close(s);
                    263:             freeaddrinfo(res);
1.1       misho     264:             return -1;
1.1.1.2   misho     265:         }
1.1       misho     266:     } else
                    267:     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
1.1.1.2   misho     268:         saved_errno = errno;
1.1       misho     269:         close(s);
                    270:         freeaddrinfo(res);
1.1.1.2   misho     271:         errno = saved_errno;
1.1       misho     272:         i_errno = IESTREAMLISTEN;
                    273:         return -1;
                    274:     }
                    275: 
                    276:     freeaddrinfo(res);
                    277: 
1.1.1.2   misho     278:     if (listen(s, INT_MAX) < 0) {
1.1       misho     279:         i_errno = IESTREAMLISTEN;
                    280:         return -1;
                    281:     }
                    282: 
                    283:     test->listener = s;
1.1.1.3 ! misho     284: 
1.1       misho     285:     return s;
                    286: #else
                    287:     i_errno = IENOSCTP;
                    288:     return -1;
1.1.1.2   misho     289: #endif /* HAVE_SCTP_H */
1.1       misho     290: }
                    291: 
                    292: 
                    293: /* iperf_sctp_connect
                    294:  *
                    295:  * connect to a SCTP stream listener
                    296:  */
                    297: int
                    298: iperf_sctp_connect(struct iperf_test *test)
                    299: {
1.1.1.2   misho     300: #if defined(HAVE_SCTP_H)
                    301:     int s, opt, saved_errno;
1.1       misho     302:     char portstr[6];
1.1.1.3 ! misho     303:     struct addrinfo hints, *local_res = NULL, *server_res = NULL;
1.1       misho     304: 
                    305:     if (test->bind_address) {
                    306:         memset(&hints, 0, sizeof(hints));
                    307:         hints.ai_family = test->settings->domain;
                    308:         hints.ai_socktype = SOCK_STREAM;
1.1.1.2   misho     309:         if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) {
1.1       misho     310:             i_errno = IESTREAMCONNECT;
                    311:             return -1;
                    312:         }
                    313:     }
                    314: 
                    315:     memset(&hints, 0, sizeof(hints));
                    316:     hints.ai_family = test->settings->domain;
                    317:     hints.ai_socktype = SOCK_STREAM;
                    318:     snprintf(portstr, sizeof(portstr), "%d", test->server_port);
1.1.1.2   misho     319:     if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) {
1.1       misho     320:        if (test->bind_address)
                    321:            freeaddrinfo(local_res);
                    322:         i_errno = IESTREAMCONNECT;
                    323:         return -1;
                    324:     }
                    325: 
                    326:     s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP);
                    327:     if (s < 0) {
1.1.1.3 ! misho     328:        freeaddrinfo(local_res);
1.1       misho     329:        freeaddrinfo(server_res);
                    330:         i_errno = IESTREAMCONNECT;
                    331:         return -1;
                    332:     }
                    333: 
1.1.1.2   misho     334:     if ((opt = test->settings->socket_bufsize)) {
                    335:         int saved_errno;
                    336:         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
                    337:             saved_errno = errno;
                    338:             close(s);
                    339:             freeaddrinfo(server_res);
                    340:             errno = saved_errno;
                    341:             i_errno = IESETBUF;
                    342:             return -1;
                    343:         }
                    344:         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
                    345:             saved_errno = errno;
                    346:             close(s);
                    347:             freeaddrinfo(server_res);
                    348:             errno = saved_errno;
                    349:             i_errno = IESETBUF;
                    350:             return -1;
                    351:         }
                    352:     }
                    353: 
1.1.1.3 ! misho     354:     if (test->bind_dev) {
        !           355: #if defined(SO_BINDTODEVICE)
        !           356:         if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
        !           357:                        test->bind_dev, IFNAMSIZ) < 0)
        !           358: #endif // SO_BINDTODEVICE
        !           359:         {
        !           360:             saved_errno = errno;
        !           361:             close(s);
        !           362:             freeaddrinfo(local_res);
        !           363:             freeaddrinfo(server_res);
        !           364:             i_errno = IEBINDDEV;
        !           365:             errno = saved_errno;
        !           366:             return -1;
        !           367:         }
        !           368:     }
        !           369: 
1.1.1.2   misho     370:     /*
                    371:      * Various ways to bind the local end of the connection.
                    372:      * 1.  --bind (with or without --cport).
                    373:      */
                    374:     if (test->bind_address) {
                    375:         struct sockaddr_in *lcladdr;
                    376:         lcladdr = (struct sockaddr_in *)local_res->ai_addr;
                    377:         lcladdr->sin_port = htons(test->bind_port);
                    378: 
                    379:         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
                    380:            saved_errno = errno;
                    381:            close(s);
                    382:            freeaddrinfo(local_res);
                    383:            freeaddrinfo(server_res);
                    384:            errno = saved_errno;
                    385:             i_errno = IESTREAMCONNECT;
                    386:             return -1;
                    387:         }
                    388:         freeaddrinfo(local_res);
                    389:     }
                    390:     /* --cport, no --bind */
                    391:     else if (test->bind_port) {
                    392:        size_t addrlen;
                    393:        struct sockaddr_storage lcl;
                    394: 
                    395:        /* IPv4 */
                    396:        if (server_res->ai_family == AF_INET) {
                    397:            struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
                    398:            lcladdr->sin_family = AF_INET;
                    399:            lcladdr->sin_port = htons(test->bind_port);
                    400:            lcladdr->sin_addr.s_addr = INADDR_ANY;
                    401:            addrlen = sizeof(struct sockaddr_in);
                    402:        }
                    403:        /* IPv6 */
                    404:        else if (server_res->ai_family == AF_INET6) {
                    405:            struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
                    406:            lcladdr->sin6_family = AF_INET6;
                    407:            lcladdr->sin6_port = htons(test->bind_port);
                    408:            lcladdr->sin6_addr = in6addr_any;
                    409:            addrlen = sizeof(struct sockaddr_in6);
                    410:        }
                    411:        /* Unknown protocol */
                    412:        else {
                    413:            saved_errno = errno;
                    414:            close(s);
                    415:            freeaddrinfo(server_res);
                    416:            errno = saved_errno;
                    417:             i_errno = IEPROTOCOL;
                    418:             return -1;
                    419:        }
                    420: 
                    421:         if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
                    422:            saved_errno = errno;
                    423:            close(s);
                    424:            freeaddrinfo(server_res);
                    425:            errno = saved_errno;
                    426:             i_errno = IESTREAMCONNECT;
                    427:             return -1;
                    428:         }
                    429:     }
                    430: 
1.1       misho     431:     if (test->no_delay != 0) {
                    432:          opt = 1;
                    433:          if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(opt)) < 0) {
1.1.1.2   misho     434:              saved_errno = errno;
1.1       misho     435:              close(s);
                    436:              freeaddrinfo(server_res);
1.1.1.2   misho     437:              errno = saved_errno;
1.1       misho     438:              i_errno = IESETNODELAY;
                    439:              return -1;
                    440:          }
                    441:     }
                    442: 
                    443:     if ((test->settings->mss >= 512 && test->settings->mss <= 131072)) {
                    444: 
                    445:        /*
                    446:         * Some platforms use a struct sctp_assoc_value as the
                    447:         * argument to SCTP_MAXSEG.  Other (older API implementations)
                    448:         * take an int.  FreeBSD 10 and CentOS 6 support SCTP_MAXSEG,
                    449:         * but OpenSolaris 11 doesn't.
                    450:         */
                    451: #ifdef HAVE_STRUCT_SCTP_ASSOC_VALUE
                    452:         struct sctp_assoc_value av;
                    453: 
                    454:        /*
                    455:         * Some platforms support SCTP_FUTURE_ASSOC, others need to
                    456:         * (equivalently) do 0 here.  FreeBSD 10 is an example of the
                    457:         * former, CentOS 6 Linux is an example of the latter.
                    458:         */
                    459: #ifdef SCTP_FUTURE_ASSOC
                    460:         av.assoc_id = SCTP_FUTURE_ASSOC;
                    461: #else
                    462:        av.assoc_id = 0;
                    463: #endif
                    464:         av.assoc_value = test->settings->mss;
                    465: 
                    466:         if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &av, sizeof(av)) < 0) {
1.1.1.2   misho     467:             saved_errno = errno;
1.1       misho     468:             close(s);
                    469:             freeaddrinfo(server_res);
1.1.1.2   misho     470:             errno = saved_errno;
1.1       misho     471:             i_errno = IESETMSS;
                    472:             return -1;
                    473:         }
                    474: #else
                    475:        opt = test->settings->mss;
                    476: 
                    477:        /*
                    478:         * Solaris might not support this option.  If it doesn't work,
                    479:         * ignore the error (at least for now).
                    480:         */
                    481:         if (setsockopt(s, IPPROTO_SCTP, SCTP_MAXSEG, &opt, sizeof(opt)) < 0 &&
                    482:            errno != ENOPROTOOPT) {
1.1.1.2   misho     483:             saved_errno = errno;
1.1       misho     484:             close(s);
                    485:             freeaddrinfo(server_res);
1.1.1.2   misho     486:             errno = saved_errno;
1.1       misho     487:             i_errno = IESETMSS;
                    488:             return -1;
                    489:         }
1.1.1.2   misho     490: #endif /* HAVE_STRUCT_SCTP_ASSOC_VALUE */
1.1       misho     491:     }
                    492: 
                    493:     if (test->settings->num_ostreams > 0) {
                    494:         struct sctp_initmsg initmsg;
                    495: 
                    496:         memset(&initmsg, 0, sizeof(struct sctp_initmsg));
                    497:         initmsg.sinit_num_ostreams = test->settings->num_ostreams;
                    498: 
                    499:         if (setsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(struct sctp_initmsg)) < 0) {
1.1.1.2   misho     500:                 saved_errno = errno;
1.1       misho     501:                 close(s);
                    502:                 freeaddrinfo(server_res);
1.1.1.2   misho     503:                 errno = saved_errno;
1.1       misho     504:                 i_errno = IESETSCTPNSTREAM;
                    505:                 return -1;
                    506:         }
                    507:     }
                    508: 
                    509:     /* clients must call bind() followed by sctp_bindx() before connect() */
                    510:     if (!TAILQ_EMPTY(&test->xbind_addrs)) {
1.1.1.2   misho     511:         if (iperf_sctp_bindx(test, s, IPERF_SCTP_CLIENT)) {
                    512:             freeaddrinfo(server_res);
                    513:             close(s);
1.1       misho     514:             return -1;
1.1.1.2   misho     515:         }
1.1       misho     516:     }
                    517: 
                    518:     /* TODO support sctp_connectx() to avoid heartbeating. */
                    519:     if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
1.1.1.2   misho     520:        saved_errno = errno;
1.1       misho     521:        close(s);
                    522:        freeaddrinfo(server_res);
1.1.1.2   misho     523:        errno = saved_errno;
1.1       misho     524:         i_errno = IESTREAMCONNECT;
                    525:         return -1;
                    526:     }
                    527: 
                    528:     /* Send cookie for verification */
                    529:     if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp) < 0) {
1.1.1.2   misho     530:        saved_errno = errno;
1.1       misho     531:        close(s);
1.1.1.2   misho     532:        freeaddrinfo(server_res);
                    533:        errno = saved_errno;
1.1       misho     534:         i_errno = IESENDCOOKIE;
                    535:         return -1;
                    536:     }
                    537: 
                    538:     /*
                    539:      * We want to allow fragmentation.  But there's at least one
                    540:      * implementation (Solaris) that doesn't support this option,
                    541:      * even though it defines SCTP_DISABLE_FRAGMENTS.  So we have to
                    542:      * try setting the option and ignore the error, if it doesn't
                    543:      * work.
                    544:      */
                    545:     opt = 0;
                    546:     if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &opt, sizeof(opt)) < 0 &&
                    547:        errno != ENOPROTOOPT) {
1.1.1.2   misho     548:         saved_errno = errno;
1.1       misho     549:         close(s);
                    550:         freeaddrinfo(server_res);
1.1.1.2   misho     551:         errno = saved_errno;
1.1       misho     552:         i_errno = IESETSCTPDISABLEFRAG;
                    553:         return -1;
                    554:     }
                    555: 
1.1.1.2   misho     556:     freeaddrinfo(server_res);
1.1       misho     557:     return s;
                    558: #else
                    559:     i_errno = IENOSCTP;
                    560:     return -1;
1.1.1.2   misho     561: #endif /* HAVE_SCTP_H */
1.1       misho     562: }
                    563: 
                    564: 
                    565: 
                    566: int
                    567: iperf_sctp_init(struct iperf_test *test)
                    568: {
1.1.1.2   misho     569: #if defined(HAVE_SCTP_H)
1.1       misho     570:     return 0;
                    571: #else
                    572:     i_errno = IENOSCTP;
                    573:     return -1;
1.1.1.2   misho     574: #endif /* HAVE_SCTP_H */
1.1       misho     575: }
                    576: 
                    577: 
                    578: 
                    579: /* iperf_sctp_bindx
                    580:  *
                    581:  * handle binding to multiple endpoints (-X parameters)
                    582:  */
                    583: int
                    584: iperf_sctp_bindx(struct iperf_test *test, int s, int is_server)
                    585: {
1.1.1.2   misho     586: #if defined(HAVE_SCTP_H)
1.1       misho     587:     struct addrinfo hints;
                    588:     char portstr[6];
                    589:     char *servname;
                    590:     struct addrinfo *ai, *ai0;
                    591:     struct sockaddr *xaddrs;
                    592:     struct xbind_entry *xbe, *xbe0;
                    593:     char *bp;
                    594:     size_t xaddrlen;
                    595:     int nxaddrs;
                    596:     int retval;
                    597:     int domain;
1.1.1.2   misho     598:     int saved_errno;
1.1       misho     599: 
                    600:     domain = test->settings->domain;
                    601:     xbe0 = NULL;
                    602:     retval = 0;
                    603: 
                    604:     if (TAILQ_EMPTY(&test->xbind_addrs))
                    605:         return retval; /* nothing to do */
                    606: 
                    607:     memset(&hints, 0, sizeof(hints));
                    608:     hints.ai_family = (domain == AF_UNSPEC ? AF_INET6 : domain);
                    609:     hints.ai_socktype = SOCK_STREAM;
                    610:     servname = NULL;
                    611:     if (is_server) {
                    612:         hints.ai_flags |= AI_PASSIVE;
                    613:         snprintf(portstr, 6, "%d", test->server_port);
                    614:         servname = portstr;
                    615:     }
                    616: 
                    617:     /* client: must pop first -X address and call bind().
                    618:      * sctp_bindx() must see the ephemeral port chosen by bind().
                    619:      * we deliberately ignore the -B argument in this case.
                    620:      */
                    621:     if (!is_server) {
                    622:         struct sockaddr *sa;
                    623:         struct sockaddr_in *sin;
                    624:         struct sockaddr_in6 *sin6;
                    625:         int eport;
                    626: 
                    627:         xbe0 = TAILQ_FIRST(&test->xbind_addrs);
                    628:         TAILQ_REMOVE(&test->xbind_addrs, xbe0, link);
                    629: 
1.1.1.2   misho     630:         if ((gerror = getaddrinfo(xbe0->name, servname, &hints, &xbe0->ai)) != 0) {
1.1       misho     631:             i_errno = IESETSCTPBINDX;
                    632:             retval = -1;
                    633:             goto out;
                    634:         }
                    635: 
                    636:         ai = xbe0->ai;
                    637:         if (domain != AF_UNSPEC && domain != ai->ai_family) {
                    638:             i_errno = IESETSCTPBINDX;
                    639:             retval = -1;
                    640:             goto out;
                    641:         }
                    642:         if (bind(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) < 0) {
                    643:             i_errno = IESETSCTPBINDX;
                    644:             retval = -1;
                    645:             goto out;
                    646:         }
                    647: 
                    648:         /* if only one -X argument, nothing more to do */
                    649:         if (TAILQ_EMPTY(&test->xbind_addrs))
                    650:             goto out;
                    651: 
                    652:         sa = (struct sockaddr *)ai->ai_addr;
                    653:         if (sa->sa_family == AF_INET) {
                    654:             sin = (struct sockaddr_in *)ai->ai_addr;
                    655:             eport = sin->sin_port;
                    656:         } else if (sa->sa_family == AF_INET6) {
                    657:             sin6 = (struct sockaddr_in6 *)ai->ai_addr;
                    658:             eport = sin6->sin6_port;
                    659:         } else {
                    660:             i_errno = IESETSCTPBINDX;
                    661:             retval = -1;
                    662:             goto out;
                    663:         }
                    664:         snprintf(portstr, 6, "%d", ntohs(eport));
                    665:         servname = portstr;
                    666:     }
                    667: 
                    668:     /* pass 1: resolve and compute lengths. */
                    669:     nxaddrs = 0;
                    670:     xaddrlen = 0;
                    671:     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
                    672:         if (xbe->ai != NULL)
                    673:             freeaddrinfo(xbe->ai);
1.1.1.2   misho     674:         if ((gerror = getaddrinfo(xbe->name, servname, &hints, &xbe->ai)) != 0) {
1.1       misho     675:             i_errno = IESETSCTPBINDX;
                    676:             retval = -1;
                    677:             goto out;
                    678:         }
                    679:         ai0 = xbe->ai;
                    680:         for (ai = ai0; ai; ai = ai->ai_next) {
                    681:             if (domain != AF_UNSPEC && domain != ai->ai_family)
                    682:                 continue;
                    683:             xaddrlen += ai->ai_addrlen;
                    684:             ++nxaddrs;
                    685:         }
                    686:     }
                    687: 
                    688:     /* pass 2: copy into flat buffer. */
                    689:     xaddrs = (struct sockaddr *)malloc(xaddrlen);
                    690:     if (!xaddrs) {
                    691:             i_errno = IESETSCTPBINDX;
                    692:             retval = -1;
                    693:             goto out;
                    694:     }
                    695:     bp = (char *)xaddrs;
                    696:     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
                    697:         ai0 = xbe->ai;
                    698:         for (ai = ai0; ai; ai = ai->ai_next) {
                    699:             if (domain != AF_UNSPEC && domain != ai->ai_family)
                    700:                 continue;
                    701:            memcpy(bp, ai->ai_addr, ai->ai_addrlen);
                    702:             bp += ai->ai_addrlen;
                    703:         }
                    704:     }
                    705: 
                    706:     if (sctp_bindx(s, xaddrs, nxaddrs, SCTP_BINDX_ADD_ADDR) == -1) {
1.1.1.2   misho     707:         saved_errno = errno;
1.1       misho     708:         close(s);
                    709:         free(xaddrs);
1.1.1.2   misho     710:         errno = saved_errno;
1.1       misho     711:         i_errno = IESETSCTPBINDX;
                    712:         retval = -1;
                    713:         goto out;
                    714:     }
                    715: 
                    716:     free(xaddrs);
                    717:     retval = 0;
                    718: 
                    719: out:
                    720:     /* client: put head node back. */
                    721:     if (!is_server && xbe0)
                    722:         TAILQ_INSERT_HEAD(&test->xbind_addrs, xbe0, link);
                    723: 
                    724:     TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
                    725:         if (xbe->ai) {
                    726:             freeaddrinfo(xbe->ai);
                    727:             xbe->ai = NULL;
                    728:         }
                    729:     }
                    730: 
                    731:     return retval;
                    732: #else
                    733:     i_errno = IENOSCTP;
                    734:     return -1;
1.1.1.2   misho     735: #endif /* HAVE_SCTP_H */
1.1       misho     736: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>