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