1 /*********************************************************************************************************
2 * Software License Agreement (BSD License) *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net> *
4 * *
5 * Copyright (c) 2020, WIDE Project and NICT *
6 * All rights reserved. *
7 * *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are *
9 * permitted provided that the following conditions are met: *
10 * *
11 * * Redistributions of source code must retain the above *
12 * copyright notice, this list of conditions and the *
13 * following disclaimer. *
14 * *
15 * * Redistributions in binary form must reproduce the above *
16 * copyright notice, this list of conditions and the *
17 * following disclaimer in the documentation and/or other *
18 * materials provided with the distribution. *
19 * *
20 * * Neither the name of the WIDE Project or NICT nor the *
21 * names of its contributors may be used to endorse or *
22 * promote products derived from this software without *
23 * specific prior written permission of WIDE Project and *
24 * NICT. *
25 * *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34 *********************************************************************************************************/
35
36 #include "fdcore-internal.h"
37 #include "cnxctx.h"
38
39 #include <netinet/sctp.h>
40 #include <sys/uio.h>
41
42 /* Size of buffer to receive ancilliary data. May need to be enlarged if more sockopt are set... */
43 #ifndef CMSG_BUF_LEN
44 #define CMSG_BUF_LEN 1024
45 #endif /* CMSG_BUF_LEN */
46
47 /* Use old draft-ietf-tsvwg-sctpsocket-17 API ? If not defined, RFC6458 API will be used */
48 /* #define OLD_SCTP_SOCKET_API */
49
50 /* Automatically fallback to old API if some of the new symbols are not defined */
51 #if (!defined(SCTP_CONNECTX_4_ARGS) || (!defined(SCTP_RECVRCVINFO)) || (!defined(SCTP_SNDINFO)) || (!defined(SCTP_SEND_FAILED_EVENT)))
52 # define OLD_SCTP_SOCKET_API
53 #endif
54
55
56 /* Temper with the retransmission timers to try and improve disconnection detection response? Undef this to keep the defaults of SCTP stack */
57 #ifndef USE_DEFAULT_SCTP_RTX_PARAMS /* make this a configuration option if useful */
58 #define ADJUST_RTX_PARAMS
59 #endif /* USE_DEFAULT_SCTP_RTX_PARAMS */
60
61
DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_array,sSA * saddrs,int saddrs_count)62 DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_array, sSA * saddrs, int saddrs_count)
63 {
64 union {
65 sSA *sa;
66 uint8_t *buf;
67 } ptr;
68 int i;
69 int salen;
70
71 FD_DUMP_HANDLE_OFFSET();
72
73 ptr.sa = saddrs;
74 for (i = 0; i < saddrs_count; i++) {
75 salen = sSAlen(ptr.sa);
76 if (salen == 0) {
77 LOG_E("fd_sa_dump_array: Unknown sockaddr family");
78 break;
79 }
80 if (i > 0) {
81 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " "), return NULL);
82 }
83 CHECK_MALLOC_DO( fd_sa_dump( FD_DUMP_STD_PARAMS, ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV), return NULL);
84 ptr.buf += salen;
85 }
86 return *buf;
87 }
88
89 /* Pre-binding socket options -- # streams read in config */
fd_setsockopt_prebind(int sk)90 static int fd_setsockopt_prebind(int sk)
91 {
92 socklen_t sz;
93
94 TRACE_ENTRY( "%d", sk);
95
96 CHECK_PARAMS( sk > 0 );
97
98 {
99 int reuse = 1;
100 CHECK_SYS( setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) );
101 }
102
103 #ifdef ADJUST_RTX_PARAMS
104 /* Set the retransmit parameters */
105 #ifdef SCTP_RTOINFO
106 {
107 struct sctp_rtoinfo rtoinfo;
108 memset(&rtoinfo, 0, sizeof(rtoinfo));
109
110 if (TRACE_BOOL(ANNOYING)) {
111 sz = sizeof(rtoinfo);
112 /* Read socket defaults */
113 CHECK_SYS( sctp_opt_info(sk, 0, SCTP_RTOINFO, &rtoinfo, &sz) );
114 if (sz != sizeof(rtoinfo))
115 {
116 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo));
117 return ENOTSUP;
118 }
119 fd_log_debug( "Def SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial);
120 fd_log_debug( " srto_min : %u", rtoinfo.srto_min);
121 fd_log_debug( " srto_max : %u", rtoinfo.srto_max);
122 }
123
124 /* rtoinfo.srto_initial: Estimate of the RTT before it can be measured; keep the default value */
125 rtoinfo.srto_max = 5000; /* Maximum retransmit timer (in ms), we want fast retransmission time. */
126 rtoinfo.srto_min = 1000; /* Value under which the RTO does not descend, we set this value to not conflict with srto_max */
127
128 /* Set the option to the socket */
129 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo)) );
130
131 if (TRACE_BOOL(ANNOYING)) {
132 /* Check new values */
133 CHECK_SYS( sctp_opt_info(sk, 0, SCTP_RTOINFO, &rtoinfo, &sz) );
134 fd_log_debug( "New SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial);
135 fd_log_debug( " srto_max : %u", rtoinfo.srto_max);
136 fd_log_debug( " srto_min : %u", rtoinfo.srto_min);
137 }
138 }
139 #else /* SCTP_RTOINFO */
140 TRACE_DEBUG(ANNOYING, "Skipping SCTP_RTOINFO");
141 #endif /* SCTP_RTOINFO */
142
143 /* Set the association parameters: max number of retransmits, ... */
144 #ifdef SCTP_ASSOCINFO
145 {
146 struct sctp_assocparams assoc;
147 memset(&assoc, 0, sizeof(assoc));
148
149 if (TRACE_BOOL(ANNOYING)) {
150 sz = sizeof(assoc);
151 /* Read socket defaults */
152 CHECK_SYS( sctp_opt_info(sk, 0, SCTP_ASSOCINFO, &assoc, &sz) );
153 if (sz != sizeof(assoc))
154 {
155 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc));
156 return ENOTSUP;
157 }
158 fd_log_debug( "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu", assoc.sasoc_asocmaxrxt);
159 fd_log_debug( " sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
160 fd_log_debug( " sasoc_peer_rwnd : %u" , assoc.sasoc_peer_rwnd);
161 fd_log_debug( " sasoc_local_rwnd : %u" , assoc.sasoc_local_rwnd);
162 fd_log_debug( " sasoc_cookie_life : %u" , assoc.sasoc_cookie_life);
163 }
164
165 assoc.sasoc_asocmaxrxt = 4; /* Maximum number of retransmission attempts: we want fast detection of errors */
166 /* Note that this must remain less than the sum of retransmission parameters of the different paths. */
167
168 /* Set the option to the socket */
169 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) );
170
171 if (TRACE_BOOL(ANNOYING)) {
172 /* Check new values */
173 CHECK_SYS( sctp_opt_info(sk, 0, SCTP_ASSOCINFO, &assoc, &sz) );
174 fd_log_debug( "New SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu", assoc.sasoc_asocmaxrxt);
175 fd_log_debug( " sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
176 fd_log_debug( " sasoc_peer_rwnd : %u" , assoc.sasoc_peer_rwnd);
177 fd_log_debug( " sasoc_local_rwnd : %u" , assoc.sasoc_local_rwnd);
178 fd_log_debug( " sasoc_cookie_life : %u" , assoc.sasoc_cookie_life);
179 }
180 }
181 #else /* SCTP_ASSOCINFO */
182 TRACE_DEBUG(ANNOYING, "Skipping SCTP_ASSOCINFO");
183 #endif /* SCTP_ASSOCINFO */
184 #endif /* ADJUST_RTX_PARAMS */
185
186 /* Set the INIT parameters, such as number of streams */
187 #ifdef SCTP_INITMSG
188 {
189 struct sctp_initmsg init;
190 memset(&init, 0, sizeof(init));
191
192 if (TRACE_BOOL(ANNOYING)) {
193 sz = sizeof(init);
194
195 /* Read socket defaults */
196 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) );
197 if (sz != sizeof(init))
198 {
199 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init));
200 return ENOTSUP;
201 }
202 fd_log_debug( "Def SCTP_INITMSG : sinit_num_ostreams : %hu", init.sinit_num_ostreams);
203 fd_log_debug( " sinit_max_instreams : %hu", init.sinit_max_instreams);
204 fd_log_debug( " sinit_max_attempts : %hu", init.sinit_max_attempts);
205 fd_log_debug( " sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
206 }
207
208 /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters, but we don't care (best effort) */
209 init.sinit_num_ostreams = fd_g_config->cnf_sctp_str; /* desired number of outgoing streams */
210 init.sinit_max_init_timeo = CNX_TIMEOUT * 1000;
211
212 /* Set the option to the socket */
213 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init)) );
214
215 if (TRACE_BOOL(ANNOYING)) {
216 /* Check new values */
217 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) );
218 fd_log_debug( "New SCTP_INITMSG : sinit_num_ostreams : %hu", init.sinit_num_ostreams);
219 fd_log_debug( " sinit_max_instreams : %hu", init.sinit_max_instreams);
220 fd_log_debug( " sinit_max_attempts : %hu", init.sinit_max_attempts);
221 fd_log_debug( " sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
222 }
223 }
224 #else /* SCTP_INITMSG */
225 TRACE_DEBUG(ANNOYING, "Skipping SCTP_INITMSG");
226 #endif /* SCTP_INITMSG */
227
228 /* The SO_LINGER option will be reset if we want to perform SCTP ABORT */
229 #ifdef SO_LINGER
230 {
231 struct linger linger;
232 memset(&linger, 0, sizeof(linger));
233
234 if (TRACE_BOOL(ANNOYING)) {
235 sz = sizeof(linger);
236 /* Read socket defaults */
237 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) );
238 if (sz != sizeof(linger))
239 {
240 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger));
241 return ENOTSUP;
242 }
243 fd_log_debug( "Def SO_LINGER : l_onoff : %d", linger.l_onoff);
244 fd_log_debug( " l_linger : %d", linger.l_linger);
245 }
246
247 linger.l_onoff = 0; /* Do not activate the linger */
248 linger.l_linger = 0; /* Ignored, but it would mean : Return immediately when closing (=> abort) (graceful shutdown in background) */
249
250 /* Set the option */
251 CHECK_SYS( setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) );
252
253 if (TRACE_BOOL(ANNOYING)) {
254 /* Check new values */
255 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) );
256 fd_log_debug( "New SO_LINGER : l_onoff : %d", linger.l_onoff);
257 fd_log_debug( " l_linger : %d", linger.l_linger);
258 }
259 }
260 #else /* SO_LINGER */
261 TRACE_DEBUG(ANNOYING, "Skipping SO_LINGER");
262 #endif /* SO_LINGER */
263
264 /* Set the NODELAY option (Nagle-like algorithm) */
265 #ifdef SCTP_NODELAY
266 {
267 int nodelay;
268
269 if (TRACE_BOOL(ANNOYING)) {
270 sz = sizeof(nodelay);
271 /* Read socket defaults */
272 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) );
273 if (sz != sizeof(nodelay))
274 {
275 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay));
276 return ENOTSUP;
277 }
278 fd_log_debug( "Def SCTP_NODELAY value : %s", nodelay ? "true" : "false");
279 }
280
281 nodelay = 1; /* We turn ON to disable the Nagle algorithm, so that packets are sent ASAP. */
282
283 /* Set the option to the socket */
284 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)) );
285
286 if (TRACE_BOOL(ANNOYING)) {
287 /* Check new values */
288 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) );
289 fd_log_debug( "New SCTP_NODELAY value : %s", nodelay ? "true" : "false");
290 }
291 }
292 #else /* SCTP_NODELAY */
293 TRACE_DEBUG(ANNOYING, "Skipping SCTP_NODELAY");
294 #endif /* SCTP_NODELAY */
295
296 /*
297 SO_RCVBUF size of receiver window
298 SO_SNDBUF size of pending data to send
299 SCTP_AUTOCLOSE for one-to-many only
300 SCTP_PRIMARY_ADDR use this address as primary locally
301 SCTP_ADAPTATION_LAYER set adaptation layer indication, we don't use this
302 */
303
304 /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */
305 #ifdef SCTP_DISABLE_FRAGMENTS
306 {
307 int nofrag;
308
309 if (TRACE_BOOL(ANNOYING)) {
310 sz = sizeof(nofrag);
311 /* Read socket defaults */
312 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) );
313 if (sz != sizeof(nofrag))
314 {
315 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag));
316 return ENOTSUP;
317 }
318 fd_log_debug( "Def SCTP_DISABLE_FRAGMENTS value : %s", nofrag ? "true" : "false");
319 }
320
321 nofrag = 0; /* We turn ON the fragmentation, since Diameter messages & TLS messages can be quite large. */
322
323 /* Set the option to the socket */
324 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag)) );
325
326 if (TRACE_BOOL(ANNOYING)) {
327 /* Check new values */
328 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) );
329 fd_log_debug( "New SCTP_DISABLE_FRAGMENTS value : %s", nofrag ? "true" : "false");
330 }
331 }
332 #else /* SCTP_DISABLE_FRAGMENTS */
333 # error "TLS requires support of SCTP_DISABLE_FRAGMENTS"
334 #endif /* SCTP_DISABLE_FRAGMENTS */
335
336 /* SCTP_PEER_ADDR_PARAMS control heartbeat per peer address. We set it as a default for all addresses in the association; not sure if it works ... */
337 #ifdef SCTP_PEER_ADDR_PARAMS
338 {
339 struct sctp_paddrparams parms;
340 memset(&parms, 0, sizeof(parms));
341
342 /* Some kernel versions need this to be set */
343 parms.spp_address.ss_family = AF_INET;
344
345 if (TRACE_BOOL(ANNOYING)) {
346 sz = sizeof(parms);
347
348 /* Read socket defaults */
349 CHECK_SYS( sctp_opt_info(sk, 0, SCTP_PEER_ADDR_PARAMS, &parms, &sz) );
350 if (sz != sizeof(parms))
351 {
352 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(parms));
353 return ENOTSUP;
354 }
355 fd_log_debug( "Def SCTP_PEER_ADDR_PARAMS : spp_hbinterval : %u", parms.spp_hbinterval);
356 fd_log_debug( " spp_pathmaxrxt : %hu", parms.spp_pathmaxrxt);
357 fd_log_debug( " spp_pathmtu : %u", parms.spp_pathmtu);
358 fd_log_debug( " spp_flags : %x", parms.spp_flags);
359 // fd_log_debug( " spp_ipv6_flowlabel: %u", parms.spp_ipv6_flowlabel);
360 // fd_log_debug( " spp_ipv4_tos : %hhu",parms.spp_ipv4_tos);
361 }
362
363 parms.spp_flags = SPP_HB_ENABLE; /* Enable heartbeat for the association */
364 #ifdef SPP_PMTUD_ENABLE
365 parms.spp_flags |= SPP_PMTUD_ENABLE; /* also enable path MTU discovery mechanism */
366 #endif /* SPP_PMTUD_ENABLE */
367
368 #ifdef ADJUST_RTX_PARAMS
369 parms.spp_hbinterval = 6000; /* Send an heartbeat every 6 seconds to quickly start retransmissions */
370 /* parms.spp_pathmaxrxt : max nbr of restransmissions on this address. There is a relationship with sasoc_asocmaxrxt, so we leave the default here */
371 #endif /* ADJUST_RTX_PARAMS */
372
373 /* Set the option to the socket */
374 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &parms, sizeof(parms)) );
375
376 if (TRACE_BOOL(ANNOYING)) {
377 /* Check new values */
378 CHECK_SYS( sctp_opt_info(sk, 0, SCTP_PEER_ADDR_PARAMS, &parms, &sz) );
379 fd_log_debug( "New SCTP_PEER_ADDR_PARAMS : spp_hbinterval : %u", parms.spp_hbinterval);
380 fd_log_debug( " spp_pathmaxrxt : %hu", parms.spp_pathmaxrxt);
381 fd_log_debug( " spp_pathmtu : %u", parms.spp_pathmtu);
382 fd_log_debug( " spp_flags : %x", parms.spp_flags);
383 // fd_log_debug( " spp_ipv6_flowlabel: %u", parms.spp_ipv6_flowlabel);
384 // fd_log_debug( " spp_ipv4_tos : %hhu",parms.spp_ipv4_tos);
385 }
386 }
387 #else /* SCTP_PEER_ADDR_PARAMS */
388 TRACE_DEBUG(ANNOYING, "Skipping SCTP_PEER_ADDR_PARAMS");
389 #endif /* SCTP_PEER_ADDR_PARAMS */
390
391 /*
392 SCTP_DEFAULT_SEND_PARAM - DEPRECATED // parameters for the sendto() call, we don't use it.
393 */
394
395 /* Subscribe to some notifications */
396 #ifdef OLD_SCTP_SOCKET_API
397 #ifdef SCTP_EVENTS /* DEPRECATED */
398 {
399 struct sctp_event_subscribe event;
400
401 memset(&event, 0, sizeof(event));
402 event.sctp_data_io_event = 1; /* to receive the stream ID in SCTP_SNDRCV ancilliary data on message reception */
403 event.sctp_association_event = 0; /* new or closed associations (mostly for one-to-many style sockets) */
404 event.sctp_address_event = 1; /* address changes */
405 event.sctp_send_failure_event = 1; /* delivery failures */
406 event.sctp_peer_error_event = 1; /* remote peer sends an error */
407 event.sctp_shutdown_event = 1; /* peer has sent a SHUTDOWN */
408 event.sctp_partial_delivery_event = 1; /* a partial delivery is aborted, probably indicating the connection is being shutdown */
409 // event.sctp_adaptation_layer_event = 0; /* adaptation layer notifications */
410 // event.sctp_authentication_event = 0; /* when new key is made active */
411
412 /* Set the option to the socket */
413 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) );
414
415 if (TRACE_BOOL(ANNOYING)) {
416 sz = sizeof(event);
417 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, &sz) );
418 if (sz != sizeof(event))
419 {
420 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(event));
421 return ENOTSUP;
422 }
423
424 fd_log_debug( "SCTP_EVENTS : sctp_data_io_event : %hhu", event.sctp_data_io_event);
425 fd_log_debug( " sctp_association_event : %hhu", event.sctp_association_event);
426 fd_log_debug( " sctp_address_event : %hhu", event.sctp_address_event);
427 fd_log_debug( " sctp_send_failure_event : %hhu", event.sctp_send_failure_event);
428 fd_log_debug( " sctp_peer_error_event : %hhu", event.sctp_peer_error_event);
429 fd_log_debug( " sctp_shutdown_event : %hhu", event.sctp_shutdown_event);
430 fd_log_debug( " sctp_partial_delivery_event : %hhu", event.sctp_partial_delivery_event);
431 // fd_log_debug( " sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event);
432 // fd_log_debug( " sctp_authentication_event : %hhu", event.sctp_authentication_event);
433 }
434 }
435 #else /* SCTP_EVENTS */
436 TRACE_DEBUG(ANNOYING, "Skipping SCTP_EVENTS");
437 #endif /* SCTP_EVENTS */
438 #endif /* OLD_SCTP_SOCKET_API */
439
440 /* Set the v4 mapped addresses option */
441 #ifdef SCTP_I_WANT_MAPPED_V4_ADDR
442 if (!fd_g_config->cnf_flags.no_ip6) {
443 int v4mapped;
444
445 if (TRACE_BOOL(ANNOYING)) {
446 sz = sizeof(v4mapped);
447 /* Read socket defaults */
448 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) );
449 if (sz != sizeof(v4mapped))
450 {
451 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped));
452 return ENOTSUP;
453 }
454 fd_log_debug( "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false");
455 }
456
457 #ifndef SCTP_USE_MAPPED_ADDRESSES
458 v4mapped = 0; /* We don't want v4 mapped addresses */
459 #else /* SCTP_USE_MAPPED_ADDRESSES */
460 v4mapped = 1; /* but we may have to, otherwise the bind fails in some environments */
461 #endif /* SCTP_USE_MAPPED_ADDRESSES */
462
463 /* Set the option to the socket */
464 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped)) );
465
466 if (TRACE_BOOL(ANNOYING)) {
467 /* Check new values */
468 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) );
469 fd_log_debug( "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false");
470 }
471 } else {
472 TRACE_DEBUG(ANNOYING, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR, since IPv6 disabled.");
473 }
474 #else /* SCTP_I_WANT_MAPPED_V4_ADDR */
475 TRACE_DEBUG(ANNOYING, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR");
476 #endif /* SCTP_I_WANT_MAPPED_V4_ADDR */
477
478 /*
479 SCTP_MAXSEG max size of fragmented segments -- bound to PMTU
480 SCTP_HMAC_IDENT authentication algorithms
481 SCTP_AUTH_ACTIVE_KEY set the active key
482 SCTP_DELAYED_SACK control delayed acks
483 */
484
485
486 /* Set the interleaving option */
487 #ifdef SCTP_FRAGMENT_INTERLEAVE
488 {
489 int interleave;
490
491 if (TRACE_BOOL(ANNOYING)) {
492 sz = sizeof(interleave);
493 /* Read socket defaults */
494 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) );
495 if (sz != sizeof(interleave))
496 {
497 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(interleave));
498 return ENOTSUP;
499 }
500 fd_log_debug( "Def SCTP_FRAGMENT_INTERLEAVE value : %d", interleave);
501 }
502
503 #if 0
504 interleave = 2; /* Allow partial delivery on several streams at the same time, since we are stream-aware in our security modules */
505 #else /* 0 */
506 interleave = 1; /* hmmm actually, we are not yet capable of handling this, and we don t need it. */
507 #endif /* 0 */
508
509 /* Set the option to the socket */
510 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, sizeof(interleave)) );
511
512 if (TRACE_BOOL(ANNOYING)) {
513 /* Check new values */
514 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) );
515 fd_log_debug( "New SCTP_FRAGMENT_INTERLEAVE value : %d", interleave);
516 }
517 }
518 #else /* SCTP_FRAGMENT_INTERLEAVE */
519 TRACE_DEBUG(ANNOYING, "Skipping SCTP_FRAGMENT_INTERLEAVE");
520 #endif /* SCTP_FRAGMENT_INTERLEAVE */
521
522 /*
523 SCTP_PARTIAL_DELIVERY_POINT control partial delivery size
524 SCTP_USE_EXT_RCVINFO - DEPRECATED use extended receive info structure (information about the next message if available)
525 */
526 /* SCTP_AUTO_ASCONF is set by the postbind function */
527 /*
528 SCTP_MAX_BURST number of packets that can be burst emitted
529 SCTP_CONTEXT save a context information along with the association.
530 */
531
532 /* SCTP_EXPLICIT_EOR: we assume implicit EOR in freeDiameter, so let's ensure this is known by the stack */
533 #ifdef SCTP_EXPLICIT_EOR
534 {
535 int bool;
536
537 if (TRACE_BOOL(ANNOYING)) {
538 sz = sizeof(bool);
539 /* Read socket defaults */
540 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, &bool, &sz) );
541 if (sz != sizeof(bool))
542 {
543 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(bool));
544 return ENOTSUP;
545 }
546 fd_log_debug( "Def SCTP_EXPLICIT_EOR value : %s", bool ? "true" : "false");
547 }
548
549 bool = 0;
550
551 /* Set the option to the socket */
552 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, &bool, sizeof(bool)) );
553
554 if (TRACE_BOOL(ANNOYING)) {
555 /* Check new values */
556 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, &bool, &sz) );
557 fd_log_debug( "New SCTP_EXPLICIT_EOR value : %s", bool ? "true" : "false");
558 }
559 }
560 #else /* SCTP_EXPLICIT_EOR */
561 TRACE_DEBUG(ANNOYING, "Skipping SCTP_EXPLICIT_EOR");
562 #endif /* SCTP_EXPLICIT_EOR */
563
564 /*
565 SCTP_REUSE_PORT share one listening port with several sockets
566 */
567
568 #ifndef OLD_SCTP_SOCKET_API
569 #ifdef SCTP_EVENT
570 {
571 /* Subscribe to the following events */
572 int events_I_want[] = {
573 #ifdef SCTP_ASSOC_CHANGE
574 /* SCTP_ASSOC_CHANGE, */
575 #endif
576 #ifdef SCTP_PEER_ADDR_CHANGE
577 SCTP_PEER_ADDR_CHANGE,
578 #endif
579 #ifdef SCTP_REMOTE_ERROR
580 SCTP_REMOTE_ERROR,
581 #endif
582 #ifdef SCTP_SEND_FAILED_EVENT
583 SCTP_SEND_FAILED_EVENT,
584 #endif
585 #ifdef SCTP_SHUTDOWN_EVENT
586 SCTP_SHUTDOWN_EVENT,
587 #endif
588 #ifdef SCTP_ADAPTATION_INDICATION
589 /* SCTP_ADAPTATION_INDICATION, */
590 #endif
591 #ifdef SCTP_PARTIAL_DELIVERY_EVENT
592 /* SCTP_PARTIAL_DELIVERY_EVENT, */
593 #endif
594 #ifdef SCTP_AUTHENTICATION_EVENT
595 /* SCTP_AUTHENTICATION_EVENT, */
596 #endif
597 #ifdef SCTP_SENDER_DRY_EVENT
598 /* SCTP_SENDER_DRY_EVENT, */
599 #endif
600 0
601 };
602 int i;
603
604 struct sctp_event event;
605
606 for (i = 0; i < (sizeof(events_I_want) / sizeof(events_I_want[0]) - 1); i++) {
607 memset(&event, 0, sizeof(event));
608 event.se_type = events_I_want[i];
609 event.se_on = 1;
610
611 /* Set the option to the socket */
612 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) );
613 }
614 }
615 #else /* SCTP_EVENT */
616 TRACE_DEBUG(ANNOYING, "Skipping SCTP_EVENT");
617 #endif /* SCTP_EVENT */
618
619
620 #ifdef SCTP_RECVRCVINFO /* Replaces SCTP_SNDRCV */
621 {
622 int bool = 1;
623
624 /* Set the option to the socket */
625 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_RECVRCVINFO, &bool, sizeof(bool)) );
626
627 }
628 #else /* SCTP_RECVRCVINFO */
629 TRACE_DEBUG(ANNOYING, "Skipping SCTP_RECVRCVINFO");
630 #endif /* SCTP_RECVRCVINFO */
631
632
633 #endif /* OLD_SCTP_SOCKET_API */
634
635 /*
636 SCTP_RECVNXTINFO
637
638 SCTP_DEFAULT_SNDINFO : send defaults
639 SCTP_DEFAULT_PRINFO : default PR-SCTP
640 */
641
642
643 /* In case of no_ip4, force the v6only option */
644 #ifdef IPV6_V6ONLY
645 if (fd_g_config->cnf_flags.no_ip4) {
646 int opt = 1;
647 CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)));
648 }
649 #endif /* IPV6_V6ONLY */
650
651 return 0;
652 }
653
654
655 /* Post-binding socket options */
fd_setsockopt_postbind(int sk,int bound_to_default)656 static int fd_setsockopt_postbind(int sk, int bound_to_default)
657 {
658 TRACE_ENTRY( "%d %d", sk, bound_to_default);
659
660 CHECK_PARAMS( (sk > 0) );
661
662 /* Set the ASCONF option */
663 #ifdef SCTP_AUTO_ASCONF
664 if (bound_to_default) {
665 int asconf;
666
667 if (TRACE_BOOL(ANNOYING)) {
668 socklen_t sz;
669
670 sz = sizeof(asconf);
671 /* Read socket defaults */
672 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) );
673 if (sz != sizeof(asconf))
674 {
675 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(asconf));
676 return ENOTSUP;
677 }
678 fd_log_debug( "Def SCTP_AUTO_ASCONF value : %s", asconf ? "true" : "false");
679 }
680
681 asconf = 1; /* allow automatic use of added or removed addresses in the association (for bound-all sockets) */
682
683 /* Set the option to the socket */
684 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, sizeof(asconf)) );
685
686 if (TRACE_BOOL(ANNOYING)) {
687 socklen_t sz = sizeof(asconf);
688 /* Check new values */
689 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) );
690 fd_log_debug( "New SCTP_AUTO_ASCONF value : %s", asconf ? "true" : "false");
691 }
692 }
693 #else /* SCTP_AUTO_ASCONF */
694 TRACE_DEBUG(ANNOYING, "Skipping SCTP_AUTO_ASCONF");
695 #endif /* SCTP_AUTO_ASCONF */
696
697 return 0;
698 }
699
700 /* Add addresses from a list to an array, with filter on the flags */
add_addresses_from_list_mask(uint8_t ** array,size_t * size,int * addr_count,int target_family,uint16_t port,struct fd_list * list,uint32_t mask,uint32_t val)701 static int add_addresses_from_list_mask(uint8_t ** array, size_t * size, int * addr_count, int target_family, uint16_t port, struct fd_list * list, uint32_t mask, uint32_t val)
702 {
703 struct fd_list * li;
704 int to_add4 = 0;
705 int to_add6 = 0;
706 union {
707 uint8_t *buf;
708 sSA4 *sin;
709 sSA6 *sin6;
710 } ptr;
711 size_t sz;
712
713 /* First, count the number of addresses to add */
714 for (li = list->next; li != list; li = li->next) {
715 struct fd_endpoint * ep = (struct fd_endpoint *) li;
716
717 /* Do the flag match ? */
718 if ((val & mask) != (ep->flags & mask))
719 continue;
720
721 if (ep->sa.sa_family == AF_INET) {
722 to_add4 ++;
723 } else {
724 to_add6 ++;
725 }
726 }
727
728 if ((to_add4 + to_add6) == 0)
729 return 0; /* nothing to do */
730
731 /* The size to add */
732 if (target_family == AF_INET) {
733 sz = to_add4 * sizeof(sSA4);
734 } else {
735 #ifndef SCTP_USE_MAPPED_ADDRESSES
736 sz = (to_add4 * sizeof(sSA4)) + (to_add6 * sizeof(sSA6));
737 #else /* SCTP_USE_MAPPED_ADDRESSES */
738 sz = (to_add4 + to_add6) * sizeof(sSA6);
739 #endif /* SCTP_USE_MAPPED_ADDRESSES */
740 }
741
742 /* Now, (re)alloc the array to store the new addresses */
743 CHECK_MALLOC( *array = realloc(*array, *size + sz) );
744
745 /* Finally, add the addresses */
746 for (li = list->next; li != list; li = li->next) {
747 struct fd_endpoint * ep = (struct fd_endpoint *) li;
748
749 /* Skip v6 addresses for v4 socket */
750 if ((target_family == AF_INET) && (ep->sa.sa_family == AF_INET6))
751 continue;
752
753 /* Are the flags matching ? */
754 if ((val & mask) != (ep->flags & mask))
755 continue;
756
757 /* Size of the new SA we are adding (array may contain a mix of sockaddr_in and sockaddr_in6) */
758 #ifndef SCTP_USE_MAPPED_ADDRESSES
759 if (ep->sa.sa_family == AF_INET6)
760 #else /* SCTP_USE_MAPPED_ADDRESSES */
761 if (target_family == AF_INET6)
762 #endif /* SCTP_USE_MAPPED_ADDRESSES */
763 sz = sizeof(sSA6);
764 else
765 sz = sizeof(sSA4);
766
767 /* Place where we add the new address */
768 ptr.buf = *array + *size; /* place of the new SA */
769
770 /* Update other information */
771 *size += sz;
772 *addr_count += 1;
773
774 /* And write the addr in the buffer */
775 if (sz == sizeof(sSA4)) {
776 memcpy(ptr.buf, &ep->sin, sz);
777 ptr.sin->sin_port = port;
778 } else {
779 if (ep->sa.sa_family == AF_INET) { /* We must map the address */
780 memset(ptr.buf, 0, sz);
781 ptr.sin6->sin6_family = AF_INET6;
782 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
783 } else {
784 memcpy(ptr.sin6, &ep->sin6, sz);
785 }
786 ptr.sin6->sin6_port = port;
787 }
788 }
789
790 return 0;
791 }
792
793 /* Create a socket server and bind it according to daemon s configuration */
fd_sctp_create_bind_server(int * sock,int family,struct fd_list * list,uint16_t port)794 int fd_sctp_create_bind_server( int * sock, int family, struct fd_list * list, uint16_t port )
795 {
796 int bind_default;
797
798 TRACE_ENTRY("%p %i %p %hu", sock, family, list, port);
799 CHECK_PARAMS(sock);
800
801 /* Create the socket */
802 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
803
804 /* Set pre-binding socket options, including number of streams etc... */
805 CHECK_FCT( fd_setsockopt_prebind(*sock) );
806
807 bind_default = (! list) || (FD_IS_LIST_EMPTY(list)) ;
808 redo:
809 if ( bind_default ) {
810 /* Implicit endpoints : bind to default addresses */
811 union {
812 sSS ss;
813 sSA sa;
814 sSA4 sin;
815 sSA6 sin6;
816 } s;
817
818 /* 0.0.0.0 and [::] are all zeros */
819 memset(&s, 0, sizeof(s));
820
821 s.sa.sa_family = family;
822
823 if (family == AF_INET)
824 s.sin.sin_port = htons(port);
825 else
826 s.sin6.sin6_port = htons(port);
827
828 CHECK_SYS( bind(*sock, &s.sa, sSAlen(&s)) );
829
830 } else {
831 /* Explicit endpoints to bind to from config */
832
833 sSA * sar = NULL; /* array of addresses */
834 size_t sz = 0; /* size of the array */
835 int count = 0; /* number of sock addr in the array */
836
837 /* Create the array of configured addresses */
838 CHECK_FCT( add_addresses_from_list_mask((void *)&sar, &sz, &count, family, htons(port), list, EP_FL_CONF, EP_FL_CONF) );
839
840 if (!count) {
841 /* None of the addresses in the list came from configuration, we bind to default */
842 bind_default = 1;
843 goto redo;
844 }
845
846 /* Debug: show bound addresses */
847 {
848 char * buf = NULL;
849 size_t len = 0;
850 CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, sar, count), );
851 LOG_D("SCTP server binding local addresses: %s", buf);
852 free(buf);
853 }
854
855 /* Bind to this array */
856 CHECK_SYS( sctp_bindx(*sock, sar, count, SCTP_BINDX_ADD_ADDR) );
857
858 /* We don't need sar anymore */
859 free(sar);
860 }
861
862 /* Now, the server is bound, set remaining sockopt */
863 CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) );
864
865 /* Debug: show all local listening addresses */
866 {
867 sSA *sar = NULL;
868 int sz = 0;
869 char * buf = NULL;
870 size_t len = 0;
871
872 CHECK_SYS( sz = sctp_getladdrs(*sock, 0, &sar) );
873
874 CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, sar, sz), );
875 LOG_D("SCTP server locally bound addresses: %s", buf);
876 sctp_freeladdrs(sar);
877 free(buf);
878 }
879
880 return 0;
881 }
882
883 /* Allow clients connections on server sockets */
fd_sctp_listen(int sock)884 int fd_sctp_listen( int sock )
885 {
886 TRACE_ENTRY("%d", sock);
887 CHECK_SYS( listen(sock, 5) );
888 return 0;
889 }
890
891 /* Create a client socket and connect to remote server */
fd_sctp_client(int * sock,int no_ip6,uint16_t port,struct fd_list * list,struct fd_list * src_list)892 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list, struct fd_list * src_list )
893 {
894 int family;
895 union {
896 uint8_t *buf;
897 sSA *sa;
898 } sar;
899 size_t size = 0;
900 int count = 0;
901 int ret;
902 int bind_default = 1; /* enable ASCONF in postbind */
903
904 sar.buf = NULL;
905
906 TRACE_ENTRY("%p %i %hu %p %p", sock, no_ip6, port, list, src_list);
907 CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) );
908 CHECK_PARAMS( !src_list || (src_list && (!FD_IS_LIST_EMPTY(src_list))) );
909
910 if (no_ip6) {
911 family = AF_INET;
912 } else {
913 family = AF_INET6;
914 }
915
916 /* Create the socket */
917 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
918
919 /* Cleanup if we are cancelled */
920 pthread_cleanup_push(fd_cleanup_socket, sock);
921
922 /* Set the socket options */
923 CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto out );
924
925 /* Bind to explicit source addresses if requested */
926 if (src_list && !FD_IS_LIST_EMPTY(src_list)) {
927 sSA * bindsar = NULL; /* array of addresses */
928 size_t sz = 0; /* size of the array */
929 int sarcount = 0; /* number of sock addr in the array */
930
931 /* Create the array of configured addresses */
932 CHECK_FCT_DO( ret = add_addresses_from_list_mask((void *)&bindsar, &sz, &sarcount, family, 0, src_list, EP_FL_CONF, EP_FL_CONF), goto out );
933
934 if (sarcount) {
935 char * buf = NULL;
936 size_t len = 0;
937 CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, bindsar, sarcount), goto out );
938 LOG_A("SCTP client binding local addresses: %s", buf);
939 free(buf);
940
941 CHECK_SYS_DO( ret = sctp_bindx(*sock, bindsar, sarcount, SCTP_BINDX_ADD_ADDR), goto out );
942 }
943
944 /* Disable ASCONF option in postbind */
945 bind_default = 0;
946
947 /* We don't need bindsar anymore */
948 free(bindsar);
949 }
950
951 /* Create the array of addresses, add first the configured addresses, then the discovered, then the other ones */
952 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF, EP_FL_CONF ), goto out );
953 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF | EP_FL_DISC, EP_FL_DISC ), goto out );
954 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF | EP_FL_DISC, 0 ), goto out );
955
956 /* Try connecting */
957 {
958 char * buf = NULL;
959 size_t len = 0;
960 CHECK_MALLOC_DO( fd_sa_dump_array( &buf, &len, 0, sar.sa, count), goto out );
961 LOG_A("SCTP client connecting to addresses: %s", buf);
962 free(buf);
963 }
964
965 /* Bug in some Linux kernel, the sctp_connectx is not a cancellation point. To avoid blocking freeDiameter, we allow async cancel here */
966 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
967 #ifdef SCTP_CONNECTX_4_ARGS
968 ret = sctp_connectx(*sock, sar.sa, count, NULL);
969 #else /* SCTP_CONNECTX_4_ARGS */
970 ret = sctp_connectx(*sock, sar.sa, count);
971 #endif /* SCTP_CONNECTX_4_ARGS */
972 /* back to normal cancelation behabior */
973 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
974
975 if (ret < 0) {
976 ret = errno;
977 /* Some errors are expected, we log at different level */
978 LOG_A("sctp_connectx returned an error: %s", strerror(ret));
979 goto out;
980 }
981
982 free(sar.buf); sar.buf = NULL;
983
984 /* Set the remaining sockopts */
985 CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, bind_default),
986 {
987 CHECK_SYS_DO( shutdown(*sock, SHUT_RDWR), /* continue */ );
988 } );
989
990 out:
991 ;
992 pthread_cleanup_pop(0);
993
994 if (ret) {
995 if (*sock > 0) {
996 CHECK_SYS_DO( close(*sock), /* continue */ );
997 *sock = -1;
998 }
999 free(sar.buf);
1000 }
1001 return ret;
1002 }
1003
1004 /* Retrieve streams information from a connected association -- optionally provide the primary address */
fd_sctp_get_str_info(int sock,uint16_t * in,uint16_t * out,sSS * primary)1005 int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary )
1006 {
1007 struct sctp_status status;
1008 socklen_t sz = sizeof(status);
1009
1010 TRACE_ENTRY("%d %p %p %p", sock, in, out, primary);
1011 CHECK_PARAMS( (sock > 0) && in && out );
1012
1013 /* Read the association parameters */
1014 memset(&status, 0, sizeof(status));
1015 CHECK_SYS( getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz) );
1016 if (sz != sizeof(status))
1017 {
1018 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %zd", sz, sizeof(status));
1019 return ENOTSUP;
1020 }
1021 #if 0
1022 char sa_buf[sSA_DUMP_STRLEN];
1023 fd_sa_sdump_numeric(sa_buf, (sSA *)&status.sstat_primary.spinfo_address);
1024 fd_log_debug( "SCTP_STATUS : sstat_state : %i" , status.sstat_state);
1025 fd_log_debug( " sstat_rwnd : %u" , status.sstat_rwnd);
1026 fd_log_debug( " sstat_unackdata : %hu", status.sstat_unackdata);
1027 fd_log_debug( " sstat_penddata : %hu", status.sstat_penddata);
1028 fd_log_debug( " sstat_instrms : %hu", status.sstat_instrms);
1029 fd_log_debug( " sstat_outstrms : %hu", status.sstat_outstrms);
1030 fd_log_debug( " sstat_fragmentation_point : %u" , status.sstat_fragmentation_point);
1031 fd_log_debug( " sstat_primary.spinfo_address : %s" , sa_buf);
1032 fd_log_debug( " sstat_primary.spinfo_state : %d" , status.sstat_primary.spinfo_state);
1033 fd_log_debug( " sstat_primary.spinfo_cwnd : %u" , status.sstat_primary.spinfo_cwnd);
1034 fd_log_debug( " sstat_primary.spinfo_srtt : %u" , status.sstat_primary.spinfo_srtt);
1035 fd_log_debug( " sstat_primary.spinfo_rto : %u" , status.sstat_primary.spinfo_rto);
1036 fd_log_debug( " sstat_primary.spinfo_mtu : %u" , status.sstat_primary.spinfo_mtu);
1037 #endif /* 0 */
1038
1039 *in = status.sstat_instrms;
1040 *out = status.sstat_outstrms;
1041
1042 if (primary)
1043 memcpy(primary, &status.sstat_primary.spinfo_address, sizeof(sSS));
1044
1045 return 0;
1046 }
1047
1048 /* Get the list of remote endpoints of the socket */
fd_sctp_get_remote_ep(int sock,struct fd_list * list)1049 int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
1050 {
1051 union {
1052 sSA *sa;
1053 uint8_t *buf;
1054 } ptr;
1055
1056 sSA * data = NULL;
1057 int count;
1058
1059 TRACE_ENTRY("%d %p", sock, list);
1060 CHECK_PARAMS(list);
1061
1062 /* Read the list on the socket */
1063 CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data) );
1064 ptr.sa = data;
1065
1066 while (count) {
1067 socklen_t sl;
1068 switch (ptr.sa->sa_family) {
1069 case AF_INET: sl = sizeof(sSA4); break;
1070 case AF_INET6: sl = sizeof(sSA6); break;
1071 default:
1072 TRACE_DEBUG(INFO, "Unknown address family returned in sctp_getpaddrs: %d, skip", ptr.sa->sa_family);
1073 /* There is a bug in current Linux kernel: http://www.spinics.net/lists/linux-sctp/msg00760.html */
1074 goto stop;
1075 }
1076
1077 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
1078 ptr.buf += sl;
1079 count --;
1080 }
1081 stop:
1082 /* Free the list */
1083 sctp_freepaddrs(data);
1084
1085 /* Now get the primary address, the add function will take care of merging with existing entry */
1086 {
1087
1088 struct sctp_status status;
1089 socklen_t sz = sizeof(status);
1090 int ret;
1091
1092 memset(&status, 0, sizeof(status));
1093 /* Attempt to use SCTP_STATUS message to retrieve the primary address */
1094 CHECK_SYS_DO( ret = getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz), /* continue */);
1095 if (sz != sizeof(status))
1096 ret = -1;
1097 sz = sizeof(sSS);
1098 if (ret < 0)
1099 {
1100 /* Fallback to getsockname -- not recommended by draft-ietf-tsvwg-sctpsocket-19#section-7.4 */
1101 CHECK_SYS(getpeername(sock, (sSA *)&status.sstat_primary.spinfo_address, &sz));
1102 }
1103
1104 CHECK_FCT( fd_ep_add_merge( list, (sSA *)&status.sstat_primary.spinfo_address, sz, EP_FL_PRIMARY ) );
1105 }
1106
1107 /* Done! */
1108 return 0;
1109 }
1110
1111 /* Send a vector over a specified stream */
fd_sctp_sendstrv(struct cnxctx * conn,uint16_t strid,const struct iovec * iov,int iovcnt)1112 ssize_t fd_sctp_sendstrv(struct cnxctx * conn, uint16_t strid, const struct iovec *iov, int iovcnt)
1113 {
1114 struct msghdr mhdr;
1115 struct cmsghdr *hdr;
1116 #ifdef OLD_SCTP_SOCKET_API
1117 struct sctp_sndrcvinfo *sndrcv;
1118 uint8_t anci[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
1119 #else /* OLD_SCTP_SOCKET_API */
1120 struct sctp_sndinfo *sndinf;
1121 uint8_t anci[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
1122 #endif /* OLD_SCTP_SOCKET_API */
1123 ssize_t ret;
1124 struct timespec ts, now;
1125
1126 TRACE_ENTRY("%p %hu %p %d", conn, strid, iov, iovcnt);
1127 CHECK_PARAMS_DO(conn && iov && iovcnt, { errno = EINVAL; return -1; } );
1128 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return -1 );
1129
1130 memset(&mhdr, 0, sizeof(mhdr));
1131 memset(&anci, 0, sizeof(anci));
1132
1133 /* Anciliary data: specify SCTP stream */
1134 hdr = (struct cmsghdr *)anci;
1135 hdr->cmsg_len = sizeof(anci);
1136 hdr->cmsg_level = IPPROTO_SCTP;
1137 #ifdef OLD_SCTP_SOCKET_API
1138 hdr->cmsg_type = SCTP_SNDRCV;
1139 sndrcv = (struct sctp_sndrcvinfo *)CMSG_DATA(hdr);
1140 sndrcv->sinfo_stream = strid;
1141 #else /* OLD_SCTP_SOCKET_API */
1142 hdr->cmsg_type = SCTP_SNDINFO;
1143 sndinf = (struct sctp_sndinfo *)CMSG_DATA(hdr);
1144 sndinf->snd_sid = strid;
1145 #endif /* OLD_SCTP_SOCKET_API */
1146 /* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */
1147
1148 /* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */
1149
1150 mhdr.msg_iov = (struct iovec *)iov;
1151 mhdr.msg_iovlen = iovcnt;
1152
1153 mhdr.msg_control = anci;
1154 mhdr.msg_controllen = sizeof(anci);
1155
1156 TRACE_DEBUG(FULL, "Sending %d chunks of data (first:%zdb) on stream %hu of socket %d", iovcnt, iov[0].iov_len, strid, conn->cc_socket);
1157 again:
1158 ret = sendmsg(conn->cc_socket, &mhdr, 0);
1159 /* Handle special case of timeout */
1160 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
1161 pthread_testcancel();
1162 /* Check how much time we were blocked for this sending. */
1163 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), return -1 );
1164 if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) {
1165 LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME);
1166 } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) {
1167 goto again; /* don't care, just ignore */
1168 }
1169
1170 /* propagate the error */
1171 errno = -ret;
1172 ret = -1;
1173 }
1174
1175 CHECK_SYS_DO( ret, ); /* for tracing error only */
1176
1177 return ret;
1178 }
1179
1180 /* Receive the next data from the socket, or next notification */
fd_sctp_recvmeta(struct cnxctx * conn,uint16_t * strid,uint8_t ** buf,size_t * len,int * event)1181 int fd_sctp_recvmeta(struct cnxctx * conn, uint16_t * strid, uint8_t ** buf, size_t * len, int *event)
1182 {
1183 ssize_t ret = 0;
1184 struct msghdr mhdr;
1185 char ancidata[ CMSG_BUF_LEN ];
1186 struct iovec iov;
1187 uint8_t *data = NULL;
1188 size_t bufsz = 0, datasize = 0;
1189 size_t mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */
1190 int timedout = 0;
1191
1192 TRACE_ENTRY("%p %p %p %p %p", conn, strid, buf, len, event);
1193 CHECK_PARAMS( conn && buf && len && event );
1194
1195 /* Cleanup out parameters */
1196 *buf = NULL;
1197 *len = 0;
1198 *event = 0;
1199
1200 /* Prepare header for receiving message */
1201 memset(&mhdr, 0, sizeof(mhdr));
1202 mhdr.msg_iov = &iov;
1203 mhdr.msg_iovlen = 1;
1204 mhdr.msg_control = &ancidata;
1205 mhdr.msg_controllen = sizeof(ancidata);
1206
1207 next_message:
1208 datasize = 0;
1209
1210 /* We will loop while all data is not received. */
1211 incomplete:
1212 while (datasize >= bufsz ) {
1213 /* The buffer is full, enlarge it */
1214 bufsz += mempagesz;
1215 CHECK_MALLOC( data = realloc(data, bufsz ) );
1216 }
1217 /* the new data will be received following the preceding */
1218 memset(&iov, 0, sizeof(iov));
1219 iov.iov_base = data + datasize ;
1220 iov.iov_len = bufsz - datasize;
1221
1222 /* Receive data from the socket */
1223 again:
1224 pthread_cleanup_push(free, data);
1225 ret = recvmsg(conn->cc_socket, &mhdr, 0);
1226 pthread_testcancel();
1227 pthread_cleanup_pop(0);
1228
1229 /* First, handle timeouts (same as fd_cnx_s_recv) */
1230 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
1231 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
1232 goto again; /* don't care, just ignore */
1233 if (!timedout) {
1234 timedout ++; /* allow for one timeout while closing */
1235 goto again;
1236 }
1237 /* fallback to normal handling */
1238 }
1239
1240 /* Handle errors */
1241 if (ret <= 0) { /* Socket timedout, closed, or an error occurred */
1242 CHECK_SYS_DO(ret, /* to log in case of error */);
1243 free(data);
1244 *event = FDEVP_CNX_ERROR;
1245 return 0;
1246 }
1247
1248 /* Update the size of data we received */
1249 datasize += ret;
1250
1251 /* SCTP provides an indication when we received a full record; loop if it is not the case */
1252 if ( ! (mhdr.msg_flags & MSG_EOR) ) {
1253 goto incomplete;
1254 }
1255
1256 /* Handle the case where the data received is a notification */
1257 if (mhdr.msg_flags & MSG_NOTIFICATION) {
1258 union sctp_notification * notif = (union sctp_notification *) data;
1259 char sa_buf[sSA_DUMP_STRLEN];
1260
1261 TRACE_DEBUG(FULL, "Received %zdb data of notification on socket %d", datasize, conn->cc_socket);
1262
1263 switch (notif->sn_header.sn_type) {
1264
1265 case SCTP_ASSOC_CHANGE: /* We should not receive these as we did not subscribe for it */
1266 TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification");
1267 TRACE_DEBUG(ANNOYING, " state : %hu", notif->sn_assoc_change.sac_state);
1268 TRACE_DEBUG(ANNOYING, " error : %hu", notif->sn_assoc_change.sac_error);
1269 TRACE_DEBUG(ANNOYING, " instr : %hu", notif->sn_assoc_change.sac_inbound_streams);
1270 TRACE_DEBUG(ANNOYING, " outstr : %hu", notif->sn_assoc_change.sac_outbound_streams);
1271
1272 *event = FDEVP_CNX_EP_CHANGE;
1273 break;
1274
1275 case SCTP_PEER_ADDR_CHANGE:
1276 TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification");
1277 fd_sa_sdump_numeric(sa_buf, (sSA *)&(notif->sn_paddr_change.spc_aaddr));
1278 TRACE_DEBUG(ANNOYING, " intf_change : %s", sa_buf);
1279 TRACE_DEBUG(ANNOYING, " state : %d", notif->sn_paddr_change.spc_state);
1280 TRACE_DEBUG(ANNOYING, " error : %d", notif->sn_paddr_change.spc_error);
1281
1282 *event = FDEVP_CNX_EP_CHANGE;
1283 break;
1284
1285 case SCTP_REMOTE_ERROR:
1286 TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification");
1287 TRACE_DEBUG(ANNOYING, " err : %hu", ntohs(notif->sn_remote_error.sre_error));
1288 TRACE_DEBUG(ANNOYING, " len : %hu", ntohs(notif->sn_remote_error.sre_length));
1289
1290 *event = FDEVP_CNX_ERROR;
1291 break;
1292
1293 #ifdef OLD_SCTP_SOCKET_API
1294 case SCTP_SEND_FAILED:
1295 TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification");
1296 TRACE_DEBUG(ANNOYING, " len : %hu", notif->sn_send_failed.ssf_length);
1297 TRACE_DEBUG(ANNOYING, " err : %d", notif->sn_send_failed.ssf_error);
1298
1299 *event = FDEVP_CNX_ERROR;
1300 break;
1301 #else /* OLD_SCTP_SOCKET_API */
1302 case SCTP_SEND_FAILED_EVENT:
1303 TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED_EVENT notification");
1304 *event = FDEVP_CNX_ERROR;
1305 break;
1306 #endif /* OLD_SCTP_SOCKET_API */
1307 case SCTP_SHUTDOWN_EVENT:
1308 TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification");
1309
1310 *event = FDEVP_CNX_SHUTDOWN;
1311 break;
1312
1313 #ifndef OLD_SCTP_SOCKET_API
1314 #ifdef SCTP_NOTIFICATIONS_STOPPED_EVENT
1315 case SCTP_NOTIFICATIONS_STOPPED_EVENT:
1316 TRACE_DEBUG(INFO, "Received SCTP_NOTIFICATIONS_STOPPED_EVENT notification, marking the association in error state");
1317 *event = FDEVP_CNX_ERROR;
1318 break;
1319 #endif /* SCTP_NOTIFICATIONS_STOPPED_EVENT */
1320 #endif /* OLD_SCTP_SOCKET_API */
1321
1322 default:
1323 TRACE_DEBUG(FULL, "Received unknown notification %d, ignored", notif->sn_header.sn_type);
1324 goto next_message;
1325 }
1326
1327 free(data);
1328 return 0;
1329 }
1330
1331 /* From this point, we have received a message */
1332 *event = FDEVP_CNX_MSG_RECV;
1333 *buf = data;
1334 *len = datasize;
1335
1336 if (strid) {
1337 struct cmsghdr *hdr;
1338 #ifdef OLD_SCTP_SOCKET_API
1339 struct sctp_sndrcvinfo *sndrcv;
1340 #else /* OLD_SCTP_SOCKET_API */
1341 struct sctp_rcvinfo *rcvinf;
1342 #endif /* OLD_SCTP_SOCKET_API */
1343
1344 /* Handle the anciliary data */
1345 for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) {
1346
1347 /* We deal only with anciliary data at SCTP level */
1348 if (hdr->cmsg_level != IPPROTO_SCTP) {
1349 TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level);
1350 continue;
1351 }
1352
1353 #ifdef OLD_SCTP_SOCKET_API
1354 /* Also only interested in SCTP_SNDRCV message for the moment */
1355 if (hdr->cmsg_type != SCTP_SNDRCV) {
1356 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type);
1357 continue;
1358 }
1359
1360 sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr);
1361 if (TRACE_BOOL(ANNOYING)) {
1362 fd_log_debug( "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV");
1363 fd_log_debug( " sinfo_stream : %hu", sndrcv->sinfo_stream);
1364 fd_log_debug( " sinfo_ssn : %hu", sndrcv->sinfo_ssn);
1365 fd_log_debug( " sinfo_flags : %hu", sndrcv->sinfo_flags);
1366 /* fd_log_debug( " sinfo_pr_policy : %hu", sndrcv->sinfo_pr_policy); */
1367 fd_log_debug( " sinfo_ppid : %u" , sndrcv->sinfo_ppid);
1368 fd_log_debug( " sinfo_context : %u" , sndrcv->sinfo_context);
1369 /* fd_log_debug( " sinfo_pr_value : %u" , sndrcv->sinfo_pr_value); */
1370 fd_log_debug( " sinfo_tsn : %u" , sndrcv->sinfo_tsn);
1371 fd_log_debug( " sinfo_cumtsn : %u" , sndrcv->sinfo_cumtsn);
1372 }
1373
1374 *strid = sndrcv->sinfo_stream;
1375 #else /* OLD_SCTP_SOCKET_API */
1376 /* Also only interested in SCTP_RCVINFO message for the moment */
1377 if (hdr->cmsg_type != SCTP_RCVINFO) {
1378 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type);
1379 continue;
1380 }
1381
1382 rcvinf = (struct sctp_rcvinfo *) CMSG_DATA(hdr);
1383
1384 *strid = rcvinf->rcv_sid;
1385 #endif /* OLD_SCTP_SOCKET_API */
1386
1387
1388 }
1389 TRACE_DEBUG(FULL, "Received %zdb data on socket %d, stream %hu", datasize, conn->cc_socket, *strid);
1390 } else {
1391 TRACE_DEBUG(FULL, "Received %zdb data on socket %d (stream ignored)", datasize, conn->cc_socket);
1392 }
1393
1394 return 0;
1395 }
1396