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