File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / iperf_sctp.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:14:54 2023 UTC (18 months, 2 weeks ago) by misho
Branches: iperf, MAIN
CVS tags: v3_15, HEAD
Version 3.15

    1: /*
    2:  * iperf, Copyright (c) 2014-2019, 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@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_H)
   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_H */
   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_H)
   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_H */
  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_H)
  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:         close(s);
  135:         return -1;
  136:     }
  137: 
  138:     if (strncmp(test->cookie, cookie, COOKIE_SIZE) != 0) {
  139:         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp) < 0) {
  140:             i_errno = IESENDMESSAGE;
  141:             close(s);
  142:             return -1;
  143:         }
  144:         close(s);
  145:     }
  146: 
  147:     return s;
  148: #else
  149:     i_errno = IENOSCTP;
  150:     return -1;
  151: #endif /* HAVE_SCTP_H */
  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: {
  162: #if defined(HAVE_SCTP_H)
  163:     struct addrinfo hints, *res;
  164:     char portstr[6];
  165:     int s, opt, saved_errno;
  166: 
  167:     close(test->listener);
  168:     test->listener = -1;
  169: 
  170:     snprintf(portstr, 6, "%d", test->server_port);
  171:     memset(&hints, 0, sizeof(hints));
  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:     }
  182:     hints.ai_socktype = SOCK_STREAM;
  183:     hints.ai_flags = AI_PASSIVE;
  184:     if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
  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: 
  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: 
  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: 
  230: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
  231:     if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC ||
  232:         test->settings->domain == AF_INET6)) {
  233:         if (test->settings->domain == AF_UNSPEC)
  234:             opt = 0;
  235:         else
  236:             opt = 1;
  237:         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
  238: 		       (char *) &opt, sizeof(opt)) < 0) {
  239: 	    saved_errno = errno;
  240: 	    close(s);
  241: 	    freeaddrinfo(res);
  242: 	    errno = saved_errno;
  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) {
  251:         saved_errno = errno;
  252:         close(s);
  253:         freeaddrinfo(res);
  254:         errno = saved_errno;
  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)) {
  261:         if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER)) {
  262:             close(s);
  263:             freeaddrinfo(res);
  264:             return -1;
  265:         }
  266:     } else
  267:     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
  268:         saved_errno = errno;
  269:         close(s);
  270:         freeaddrinfo(res);
  271:         errno = saved_errno;
  272:         i_errno = IESTREAMLISTEN;
  273:         return -1;
  274:     }
  275: 
  276:     freeaddrinfo(res);
  277: 
  278:     if (listen(s, INT_MAX) < 0) {
  279:         i_errno = IESTREAMLISTEN;
  280:         return -1;
  281:     }
  282: 
  283:     test->listener = s;
  284: 
  285:     return s;
  286: #else
  287:     i_errno = IENOSCTP;
  288:     return -1;
  289: #endif /* HAVE_SCTP_H */
  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: {
  300: #if defined(HAVE_SCTP_H)
  301:     int s, opt, saved_errno;
  302:     char portstr[6];
  303:     struct addrinfo hints, *local_res = NULL, *server_res = NULL;
  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;
  309:         if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) {
  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);
  319:     if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) {
  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) {
  328: 	freeaddrinfo(local_res);
  329: 	freeaddrinfo(server_res);
  330:         i_errno = IESTREAMCONNECT;
  331:         return -1;
  332:     }
  333: 
  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: 
  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: 
  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: 
  431:     if (test->no_delay != 0) {
  432:          opt = 1;
  433:          if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(opt)) < 0) {
  434:              saved_errno = errno;
  435:              close(s);
  436:              freeaddrinfo(server_res);
  437:              errno = saved_errno;
  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) {
  467:             saved_errno = errno;
  468:             close(s);
  469:             freeaddrinfo(server_res);
  470:             errno = saved_errno;
  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) {
  483:             saved_errno = errno;
  484:             close(s);
  485:             freeaddrinfo(server_res);
  486:             errno = saved_errno;
  487:             i_errno = IESETMSS;
  488:             return -1;
  489:         }
  490: #endif /* HAVE_STRUCT_SCTP_ASSOC_VALUE */
  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) {
  500:                 saved_errno = errno;
  501:                 close(s);
  502:                 freeaddrinfo(server_res);
  503:                 errno = saved_errno;
  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)) {
  511:         if (iperf_sctp_bindx(test, s, IPERF_SCTP_CLIENT)) {
  512:             freeaddrinfo(server_res);
  513:             close(s);
  514:             return -1;
  515:         }
  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) {
  520: 	saved_errno = errno;
  521: 	close(s);
  522: 	freeaddrinfo(server_res);
  523: 	errno = saved_errno;
  524:         i_errno = IESTREAMCONNECT;
  525:         return -1;
  526:     }
  527: 
  528:     /* Send cookie for verification */
  529:     if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp) < 0) {
  530: 	saved_errno = errno;
  531: 	close(s);
  532: 	freeaddrinfo(server_res);
  533: 	errno = saved_errno;
  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) {
  548:         saved_errno = errno;
  549:         close(s);
  550:         freeaddrinfo(server_res);
  551:         errno = saved_errno;
  552:         i_errno = IESETSCTPDISABLEFRAG;
  553:         return -1;
  554:     }
  555: 
  556:     freeaddrinfo(server_res);
  557:     return s;
  558: #else
  559:     i_errno = IENOSCTP;
  560:     return -1;
  561: #endif /* HAVE_SCTP_H */
  562: }
  563: 
  564: 
  565: 
  566: int
  567: iperf_sctp_init(struct iperf_test *test)
  568: {
  569: #if defined(HAVE_SCTP_H)
  570:     return 0;
  571: #else
  572:     i_errno = IENOSCTP;
  573:     return -1;
  574: #endif /* HAVE_SCTP_H */
  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: {
  586: #if defined(HAVE_SCTP_H)
  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;
  598:     int saved_errno;
  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: 
  630:         if ((gerror = getaddrinfo(xbe0->name, servname, &hints, &xbe0->ai)) != 0) {
  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);
  674:         if ((gerror = getaddrinfo(xbe->name, servname, &hints, &xbe->ai)) != 0) {
  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) {
  707:         saved_errno = errno;
  708:         close(s);
  709:         free(xaddrs);
  710:         errno = saved_errno;
  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;
  735: #endif /* HAVE_SCTP_H */
  736: }

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