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