Navigation


source: freeDiameter/freeDiameter/sctp.c @ 29:5ba91682f0bc

Last change on this file since 29:5ba91682f0bc was 29:5ba91682f0bc, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Added a test for cnxctx (tbc) and fixed some bugs

File size: 36.8 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2009, 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 "fD.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/* Level of SCTP-specific traces */
48#ifdef DEBUG_SCTP
49#define SCTP_LEVEL      FULL
50#else /* DEBUG_SCTP */
51#define SCTP_LEVEL      ANNOYING
52#endif /* DEBUG_SCTP */
53
54/* Pre-binding socket options -- # streams read in config */
55static int fd_setsockopt_prebind(int sk)
56{
57        socklen_t sz;
58       
59        TRACE_ENTRY( "%d", sk);
60       
61        CHECK_PARAMS( sk > 0 );
62       
63        /* Subscribe to some notifications */
64        {
65                struct sctp_event_subscribe event;
66
67                memset(&event, 0, sizeof(event));
68                event.sctp_data_io_event        = 1;    /* to receive the stream ID in SCTP_SNDRCV ancilliary data on message reception */
69                event.sctp_association_event    = 0;    /* new or closed associations (mostly for one-to-many style sockets) */
70                event.sctp_address_event        = 1;    /* address changes */
71                event.sctp_send_failure_event   = 1;    /* delivery failures */
72                event.sctp_peer_error_event     = 1;    /* remote peer sends an error */
73                event.sctp_shutdown_event       = 1;    /* peer has sent a SHUTDOWN */
74                event.sctp_partial_delivery_event = 1;  /* a partial delivery is aborted, probably indicating the connection is being shutdown */
75                // event.sctp_adaptation_layer_event = 0;       /* adaptation layer notifications */
76                // event.sctp_authentication_event = 0; /* when new key is made active */
77
78                /* Set the option to the socket */
79                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) );
80               
81                if (TRACE_BOOL(SCTP_LEVEL)) {
82                        sz = sizeof(event);
83                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, &sz) );
84                        if (sz != sizeof(event))
85                        {
86                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(event));
87                                return ENOTSUP;
88                        }
89
90                        fd_log_debug( "SCTP_EVENTS : sctp_data_io_event          : %hhu\n", event.sctp_data_io_event);
91                        fd_log_debug( "              sctp_association_event      : %hhu\n", event.sctp_association_event);
92                        fd_log_debug( "              sctp_address_event          : %hhu\n", event.sctp_address_event);
93                        fd_log_debug( "              sctp_send_failure_event     : %hhu\n", event.sctp_send_failure_event);
94                        fd_log_debug( "              sctp_peer_error_event       : %hhu\n", event.sctp_peer_error_event);
95                        fd_log_debug( "              sctp_shutdown_event         : %hhu\n", event.sctp_shutdown_event);
96                        fd_log_debug( "              sctp_partial_delivery_event : %hhu\n", event.sctp_partial_delivery_event);
97                        fd_log_debug( "              sctp_adaptation_layer_event : %hhu\n", event.sctp_adaptation_layer_event);
98                        // fd_log_debug( "             sctp_authentication_event    : %hhu\n", event.sctp_authentication_event);
99                }
100               
101        }
102       
103        /* Set the INIT parameters, such as number of streams */
104        {
105                struct sctp_initmsg init;
106                memset(&init, 0, sizeof(init));
107               
108                if (TRACE_BOOL(SCTP_LEVEL)) {
109                        sz = sizeof(init);
110
111                        /* Read socket defaults */
112                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz)  );
113                        if (sz != sizeof(init))
114                        {
115                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init));
116                                return ENOTSUP;
117                        }
118                        fd_log_debug( "Def SCTP_INITMSG : sinit_num_ostreams   : %hu\n", init.sinit_num_ostreams);
119                        fd_log_debug( "                   sinit_max_instreams  : %hu\n", init.sinit_max_instreams);
120                        fd_log_debug( "                   sinit_max_attempts   : %hu\n", init.sinit_max_attempts);
121                        fd_log_debug( "                   sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo);
122                }
123
124                /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters */
125                init.sinit_num_ostreams   = fd_g_config->cnf_sctp_str;  /* desired number of outgoing streams */
126                init.sinit_max_init_timeo = CNX_TIMEOUT * 1000;
127
128                /* Set the option to the socket */
129                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init))  );
130               
131                if (TRACE_BOOL(SCTP_LEVEL)) {
132                        /* Check new values */
133                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz)  );
134                        fd_log_debug( "New SCTP_INITMSG : sinit_num_ostreams   : %hu\n", init.sinit_num_ostreams);
135                        fd_log_debug( "                   sinit_max_instreams  : %hu\n", init.sinit_max_instreams);
136                        fd_log_debug( "                   sinit_max_attempts   : %hu\n", init.sinit_max_attempts);
137                        fd_log_debug( "                   sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo);
138                }
139        }
140       
141        /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */
142        #ifdef SCTP_DISABLE_FRAGMENTS
143        {
144                int nofrag;
145               
146                if (TRACE_BOOL(SCTP_LEVEL)) {
147                        sz = sizeof(nofrag);
148                        /* Read socket defaults */
149                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz)  );
150                        if (sz != sizeof(nofrag))
151                        {
152                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag));
153                                return ENOTSUP;
154                        }
155                        fd_log_debug( "Def SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false");
156                }
157
158                nofrag = 0;     /* We turn ON the fragmentation */
159               
160                /* Set the option to the socket */
161                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag))  );
162               
163                if (TRACE_BOOL(SCTP_LEVEL)) {
164                        /* Check new values */
165                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz)  );
166                        fd_log_debug( "New SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false");
167                }
168        }
169        #else /* SCTP_DISABLE_FRAGMENTS */
170        # error "TLS requires support of SCTP_DISABLE_FRAGMENTS"
171        #endif /* SCTP_DISABLE_FRAGMENTS */
172       
173       
174        /* Set the RETRANSMIT parameters */
175        #ifdef SCTP_RTOINFO
176        {
177                struct sctp_rtoinfo rtoinfo;
178                memset(&rtoinfo, 0, sizeof(rtoinfo));
179
180                if (TRACE_BOOL(SCTP_LEVEL)) {
181                        sz = sizeof(rtoinfo);
182                        /* Read socket defaults */
183                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz)  );
184                        if (sz != sizeof(rtoinfo))
185                        {
186                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo));
187                                return ENOTSUP;
188                        }
189                        fd_log_debug( "Def SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial);
190                        fd_log_debug( "                   srto_max     : %u\n", rtoinfo.srto_max);
191                        fd_log_debug( "                   srto_min     : %u\n", rtoinfo.srto_min);
192                }
193
194                rtoinfo.srto_max     = fd_g_config->cnf_timer_tw * 500 - 1000;  /* Maximum retransmit timer (in ms) (set to Tw / 2 - 1) */
195
196                /* Set the option to the socket */
197                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo))  );
198               
199                if (TRACE_BOOL(SCTP_LEVEL)) {
200                        /* Check new values */
201                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz)  );
202                        fd_log_debug( "New SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial);
203                        fd_log_debug( "                   srto_max     : %u\n", rtoinfo.srto_max);
204                        fd_log_debug( "                   srto_min     : %u\n", rtoinfo.srto_min);
205                }
206        }
207        #else /* SCTP_RTOINFO */
208        TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_RTOINFO");
209        #endif /* SCTP_RTOINFO */
210       
211        /* Set the ASSOCIATION parameters */
212        #ifdef SCTP_ASSOCINFO
213        {
214                struct sctp_assocparams assoc;
215                memset(&assoc, 0, sizeof(assoc));
216
217                if (TRACE_BOOL(SCTP_LEVEL)) {
218                        sz = sizeof(assoc);
219                        /* Read socket defaults */
220                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz)  );
221                        if (sz != sizeof(assoc))
222                        {
223                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc));
224                                return ENOTSUP;
225                        }
226                        fd_log_debug( "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu\n", assoc.sasoc_asocmaxrxt);
227                        fd_log_debug( "                     sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations);
228                        fd_log_debug( "                     sasoc_peer_rwnd                : %u\n" , assoc.sasoc_peer_rwnd);
229                        fd_log_debug( "                     sasoc_local_rwnd               : %u\n" , assoc.sasoc_local_rwnd);
230                        fd_log_debug( "                     sasoc_cookie_life              : %u\n" , assoc.sasoc_cookie_life);
231                }
232
233                assoc.sasoc_asocmaxrxt = 5;     /* Maximum retransmission attempts: we want fast detection of errors */
234               
235                /* Set the option to the socket */
236                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc))  );
237               
238                if (TRACE_BOOL(SCTP_LEVEL)) {
239                        /* Check new values */
240                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz)  );
241                        fd_log_debug( "New SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu\n", assoc.sasoc_asocmaxrxt);
242                        fd_log_debug( "                     sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations);
243                        fd_log_debug( "                     sasoc_peer_rwnd                : %u\n" , assoc.sasoc_peer_rwnd);
244                        fd_log_debug( "                     sasoc_local_rwnd               : %u\n" , assoc.sasoc_local_rwnd);
245                        fd_log_debug( "                     sasoc_cookie_life              : %u\n" , assoc.sasoc_cookie_life);
246                }
247        }
248        #else /* SCTP_ASSOCINFO */
249        TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_ASSOCINFO");
250        #endif /* SCTP_ASSOCINFO */
251       
252       
253        /* The SO_LINGER option will be re-set if we want to perform SCTP ABORT */
254        #ifdef SO_LINGER
255        {
256                struct linger linger;
257                memset(&linger, 0, sizeof(linger));
258               
259                if (TRACE_BOOL(SCTP_LEVEL)) {
260                        sz = sizeof(linger);
261                        /* Read socket defaults */
262                        CHECK_SYS(  getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz)  );
263                        if (sz != sizeof(linger))
264                        {
265                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger));
266                                return ENOTSUP;
267                        }
268                        fd_log_debug( "Def SO_LINGER : l_onoff  : %d\n", linger.l_onoff);
269                        fd_log_debug( "                l_linger : %d\n", linger.l_linger);
270                }
271               
272                linger.l_onoff  = 0;    /* Do not activate the linger */
273                linger.l_linger = 0;    /* Return immediately when closing (=> abort) */
274               
275                /* Set the option */
276                CHECK_SYS(  setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger))  );
277               
278                if (TRACE_BOOL(SCTP_LEVEL)) {
279                        /* Check new values */
280                        CHECK_SYS(  getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz)  );
281                        fd_log_debug( "New SO_LINGER : l_onoff  : %d\n", linger.l_onoff);
282                        fd_log_debug( "           l_linger : %d\n", linger.l_linger);
283                }
284        }
285        #else /* SO_LINGER */
286        TRACE_DEBUG(SCTP_LEVEL, "Skipping SO_LINGER");
287        #endif /* SO_LINGER */
288       
289        /* Set the NODELAY option (Nagle-like algorithm) */
290        #ifdef SCTP_NODELAY
291        {
292                int nodelay;
293               
294                if (TRACE_BOOL(SCTP_LEVEL)) {
295                        sz = sizeof(nodelay);
296                        /* Read socket defaults */
297                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz)  );
298                        if (sz != sizeof(nodelay))
299                        {
300                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay));
301                                return ENOTSUP;
302                        }
303                        fd_log_debug( "Def SCTP_NODELAY value : %s\n", nodelay ? "true" : "false");
304                }
305
306                nodelay = 0;    /* We turn ON the Nagle algorithm (probably the default already) */
307               
308                /* Set the option to the socket */
309                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay))  );
310               
311                if (TRACE_BOOL(SCTP_LEVEL)) {
312                        /* Check new values */
313                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz)  );
314                        fd_log_debug( "New SCTP_NODELAY value : %s\n", nodelay ? "true" : "false");
315                }
316        }
317        #else /* SCTP_NODELAY */
318        TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_NODELAY");
319        #endif /* SCTP_NODELAY */
320       
321        /* Set the interleaving option */
322        #ifdef SCTP_FRAGMENT_INTERLEAVE
323        {
324                int interleave;
325               
326                if (TRACE_BOOL(SCTP_LEVEL)) {
327                        sz = sizeof(interleave);
328                        /* Read socket defaults */
329                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz)  );
330                        if (sz != sizeof(interleave))
331                        {
332                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(interleave));
333                                return ENOTSUP;
334                        }
335                        fd_log_debug( "Def SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave);
336                }
337
338                #if 0
339                interleave = 2; /* Allow partial delivery on several streams at the same time, since we are stream-aware in our security modules */
340                #else /* 0 */
341                interleave = 1; /* hmmm actually, we are not yet capable of handling this, and we don t need it. */
342                #endif /* 0 */
343               
344                /* Set the option to the socket */
345                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, sizeof(interleave))  );
346               
347                if (TRACE_BOOL(SCTP_LEVEL)) {
348                        /* Check new values */
349                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz)  );
350                        fd_log_debug( "New SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave);
351                }
352        }
353        #else /* SCTP_FRAGMENT_INTERLEAVE */
354        TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_FRAGMENT_INTERLEAVE");
355        #endif /* SCTP_FRAGMENT_INTERLEAVE */
356       
357        /* Set the v4 mapped addresses option */
358        #ifdef SCTP_I_WANT_MAPPED_V4_ADDR
359        {
360                int v4mapped;
361               
362                if (TRACE_BOOL(SCTP_LEVEL)) {
363                        sz = sizeof(v4mapped);
364                        /* Read socket defaults */
365                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz)  );
366                        if (sz != sizeof(v4mapped))
367                        {
368                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped));
369                                return ENOTSUP;
370                        }
371                        fd_log_debug( "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false");
372                }
373
374#ifndef SCTP_USE_MAPPED_ADDRESSES
375                v4mapped = 0;   /* We don't want v4 mapped addresses */
376#else /* SCTP_USE_MAPPED_ADDRESSES */
377                v4mapped = 1;   /* but we may have to, otherwise the bind fails in some environments */
378#endif /* SCTP_USE_MAPPED_ADDRESSES */
379               
380                /* Set the option to the socket */
381                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped))  );
382               
383                if (TRACE_BOOL(SCTP_LEVEL)) {
384                        /* Check new values */
385                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz)  );
386                        fd_log_debug( "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false");
387                }
388        }
389        #else /* SCTP_I_WANT_MAPPED_V4_ADDR */
390        TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR");
391        #endif /* SCTP_I_WANT_MAPPED_V4_ADDR */
392                           
393                           
394        /* Other settable options (draft-ietf-tsvwg-sctpsocket-17):
395           SO_RCVBUF                    size of receiver window
396           SO_SNDBUF                    size of pending data to send
397           SCTP_AUTOCLOSE               for one-to-many only
398           SCTP_SET_PEER_PRIMARY_ADDR   ask remote peer to use this local address as primary
399           SCTP_PRIMARY_ADDR            use this address as primary locally
400           SCTP_ADAPTATION_LAYER        set adaptation layer indication
401           SCTP_PEER_ADDR_PARAMS        control heartbeat per peer address
402           SCTP_DEFAULT_SEND_PARAM      parameters for the sendto() call
403           SCTP_MAXSEG                  max size of fragmented segments -- bound to PMTU
404           SCTP_AUTH_CHUNK              request authentication of some type of chunk
405            SCTP_HMAC_IDENT             authentication algorithms
406            SCTP_AUTH_KEY               set a shared key
407            SCTP_AUTH_ACTIVE_KEY        set the active key
408            SCTP_AUTH_DELETE_KEY        remove a key
409            SCTP_AUTH_DEACTIVATE_KEY    will not use that key anymore
410           SCTP_DELAYED_SACK            control delayed acks
411           SCTP_PARTIAL_DELIVERY_POINT  control partial delivery size
412           SCTP_USE_EXT_RCVINFO         use extended receive info structure (information about the next message if available)
413           SCTP_MAX_BURST               number of packets that can be burst emitted
414           SCTP_CONTEXT                 save a context information along with the association.
415           SCTP_EXPLICIT_EOR            enable sending one message across several send calls
416           SCTP_REUSE_PORT              share one listening port with several sockets
417           
418           read-only options:
419           SCTP_STATUS                  retrieve info such as number of streams, pending packets, state, ...
420           SCTP_GET_PEER_ADDR_INFO      get information about a specific peer address of the association.
421           SCTP_PEER_AUTH_CHUNKS        list of chunks the remote peer wants authenticated
422           SCTP_LOCAL_AUTH_CHUNKS       list of chunks the local peer wants authenticated
423           SCTP_GET_ASSOC_NUMBER        number of associations in a one-to-many socket
424           SCTP_GET_ASSOC_ID_LIST       list of these associations
425        */
426       
427        /* In case of no_ip4, force the v6only option -- is it a valid option for SCTP ? */
428        #ifdef IPV6_V6ONLY
429        if (fd_g_config->cnf_flags.no_ip4) {
430                int opt = 1;
431                CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)));
432        }
433        #endif /* IPV6_V6ONLY */
434       
435        return 0;
436}
437
438
439/* Post-binding socket options */
440static int fd_setsockopt_postbind(int sk, int bound_to_default)
441{
442        TRACE_ENTRY( "%d %d", sk, bound_to_default);
443       
444        CHECK_PARAMS( (sk > 0) );
445       
446        /* Set the ASCONF option */
447        #ifdef SCTP_AUTO_ASCONF
448        {
449                int asconf;
450               
451                if (TRACE_BOOL(SCTP_LEVEL)) {
452                        socklen_t sz;
453
454                        sz = sizeof(asconf);
455                        /* Read socket defaults */
456                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz)  );
457                        if (sz != sizeof(asconf))
458                        {
459                                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(asconf));
460                                return ENOTSUP;
461                        }
462                        fd_log_debug( "Def SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false");
463                }
464
465                asconf = bound_to_default ? 1 : 0;      /* allow automatic use of added or removed addresses in the association (for bound-all sockets) */
466               
467                /* Set the option to the socket */
468                CHECK_SYS(  setsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, sizeof(asconf))  );
469               
470                if (TRACE_BOOL(SCTP_LEVEL)) {
471                        socklen_t sz = sizeof(asconf);
472                        /* Check new values */
473                        CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz)  );
474                        fd_log_debug( "New SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false");
475                }
476        }
477        #else /* SCTP_AUTO_ASCONF */
478        TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_AUTO_ASCONF");
479        #endif /* SCTP_AUTO_ASCONF */
480       
481        return 0;
482}
483
484/* Create a socket server and bind it according to daemon s configuration */
485int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port )
486{
487        int family;
488        int bind_default;
489       
490        TRACE_ENTRY("%p %p %hu", sock, list, port);
491        CHECK_PARAMS(sock);
492       
493        if (fd_g_config->cnf_flags.no_ip6) {
494                family = AF_INET;
495        } else {
496                family = AF_INET6; /* can create socket for both IP and IPv6 */
497        }
498       
499        /* Create the socket */
500        CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
501       
502        /* Set pre-binding socket options, including number of streams etc... */
503        CHECK_FCT( fd_setsockopt_prebind(*sock) );
504       
505        bind_default = (! list) || (FD_IS_LIST_EMPTY(list)) ;
506redo:
507        if ( bind_default ) {
508                /* Implicit endpoints : bind to default addresses */
509                union {
510                        sSS  ss;
511                        sSA  sa;
512                        sSA4 sin;
513                        sSA6 sin6;
514                } s;
515               
516                /* 0.0.0.0 and [::] are all zeros */
517                memset(&s, 0, sizeof(s));
518               
519                s.sa.sa_family = family;
520               
521                if (family == AF_INET)
522                        s.sin.sin_port = htons(port);
523                else
524                        s.sin6.sin6_port = htons(port);
525               
526                CHECK_SYS( bind(*sock, &s.sa, sizeof(s)) );
527               
528        } else {
529                /* Explicit endpoints to bind to from config */
530               
531                union {
532                        sSA     * sa;
533                        sSA4    *sin;
534                        sSA6    *sin6;
535                        uint8_t *buf;
536                } ptr;
537                union {
538                        sSA     * sa;
539                        uint8_t * buf;
540                } sar;
541                int count = 0; /* number of sock addr in sar array */
542                size_t offset = 0;
543                struct fd_list * li;
544               
545                sar.buf = NULL;
546               
547                /* Create a flat array from the list of configured addresses */
548                for (li = list->next; li != list; li = li->next) {
549                        struct fd_endpoint * ep = (struct fd_endpoint *)li;
550                        size_t sz = 0;
551                       
552                        if (! (ep->flags & EP_FL_CONF))
553                                continue;
554                       
555                        count++;
556                       
557                        /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */
558#ifndef SCTP_USE_MAPPED_ADDRESSES
559                        if (ep->sa.sa_family == AF_INET6)
560#else /* SCTP_USE_MAPPED_ADDRESSES */
561                        if (family == AF_INET6)
562#endif /* SCTP_USE_MAPPED_ADDRESSES */
563                                sz = sizeof(sSA6);
564                        else
565                                sz = sizeof(sSA4);
566                       
567                        /* augment sar to contain the additional info */
568                        CHECK_MALLOC( sar.buf = realloc(sar.buf, offset + sz)  );
569                       
570                        ptr.buf = sar.buf + offset; /* place of the new SA */
571                        offset += sz; /* update to end of sar */
572                       
573                        if (sz == sizeof(sSA4)) {
574                                memcpy(ptr.buf, &ep->sin, sz);
575                                ptr.sin->sin_port = htons(port);
576                        } else {
577                                if (ep->sa.sa_family == AF_INET) { /* We must map the address */ 
578                                        memset(ptr.buf, 0, sz);
579                                        ptr.sin6->sin6_family = AF_INET6;
580                                        IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
581                                } else {
582                                        memcpy(ptr.sin6, &ep->sin6, sz);
583                                }
584                                ptr.sin6->sin6_port = htons(port);
585                        }
586                }
587               
588                if (!count) {
589                        /* None of the addresses in the list came from configuration, we bind to default */
590                        bind_default = 1;
591                        goto redo;
592                }
593               
594                if (TRACE_BOOL(SCTP_LEVEL)) {
595                        int i;
596                        ptr.buf = sar.buf;
597                        fd_log_debug("Calling sctp_bindx with the following address array:\n");
598                        for (i = 0; i < count; i++) {
599                                TRACE_DEBUG_sSA(FULL, "    - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
600                                ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ;
601                        }
602                }
603               
604                /* Bind to this array */
605                CHECK_SYS(  sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR)  );
606               
607                /* We don't need sar anymore */
608                free(sar.buf);
609        }
610       
611        /* Now, the server is bound, set remaining sockopt */
612        CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) );
613       
614        /* Debug: show all local listening addresses */
615        if (TRACE_BOOL(SCTP_LEVEL)) {
616                sSA *sar;
617                union {
618                        sSA     *sa;
619                        uint8_t *buf;
620                } ptr;
621                int sz;
622               
623                CHECK_SYS(  sz = sctp_getladdrs(*sock, 0, &sar)  );
624               
625                fd_log_debug("SCTP server bound on :\n");
626                for (ptr.sa = sar; sz-- > 0; ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)) {
627                        TRACE_DEBUG_sSA(FULL, "    - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
628                }
629                sctp_freeladdrs(sar);
630        }
631
632        return 0;
633}
634
635/* Allow clients connections on server sockets */
636int fd_sctp_listen( int sock )
637{
638        TRACE_ENTRY("%d", sock);
639        CHECK_SYS( listen(sock, 5) );
640        return 0;
641}
642
643/* Create a client socket and connect to remote server */
644int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list )
645{
646        int family;
647        int count = 0;
648        size_t offset = 0, sz;
649        union {
650                uint8_t *buf;
651                sSA     *sa;
652        } sar;
653        union {
654                uint8_t *buf;
655                sSA     *sa;
656                sSA4    *sin;
657                sSA6    *sin6;
658        } ptr;
659        struct fd_list * li;
660        int ret;
661       
662        sar.buf = NULL;
663       
664        TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list);
665        CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) );
666       
667        if (no_ip6) {
668                family = AF_INET;
669        } else {
670                family = AF_INET6;
671        }
672       
673        /* Create the socket */
674        CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
675       
676        /* Cleanup if we are cancelled */
677        pthread_cleanup_push(fd_cleanup_socket, sock);
678       
679        /* Set the socket options */
680        CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail );
681       
682        /* Create the array of addresses for sctp_connectx */
683        for (li = list->next; li != list; li = li->next) {
684                struct fd_endpoint * ep = (struct fd_endpoint *) li;
685               
686                count++;
687               
688                /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */
689#ifndef SCTP_USE_MAPPED_ADDRESSES
690                if (ep->sa.sa_family == AF_INET6)
691#else /* SCTP_USE_MAPPED_ADDRESSES */
692                if (family == AF_INET6)
693#endif /* SCTP_USE_MAPPED_ADDRESSES */
694                        sz = sizeof(sSA6);
695                else
696                        sz = sizeof(sSA4);
697               
698                /* augment sar to contain the additional info */
699                CHECK_MALLOC_DO( sar.buf = realloc(sar.buf, offset + sz), { ret = ENOMEM; goto fail; }  );
700
701                ptr.buf = sar.buf + offset; /* place of the new SA */
702                offset += sz; /* update to end of sar */
703                       
704                if (sz == sizeof(sSA4)) {
705                        memcpy(ptr.buf, &ep->sin, sz);
706                        ptr.sin->sin_port = htons(port);
707                } else {
708                        if (ep->sa.sa_family == AF_INET) { /* We must map the address */ 
709                                memset(ptr.buf, 0, sz);
710                                ptr.sin6->sin6_family = AF_INET6;
711                                IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
712                        } else {
713                                memcpy(ptr.sin6, &ep->sin6, sz);
714                        }
715                        ptr.sin6->sin6_port = htons(port);
716                }
717        }
718       
719        /* Try connecting */
720        TRACE_DEBUG(FULL, "Attempting SCTP connection (%d addresses attempted)...", count);
721        CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } );
722        free(sar.buf); sar.buf = NULL;
723       
724        /* Set the remaining sockopts */
725        CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), goto fail );
726       
727        /* Done! */
728        pthread_cleanup_pop(0);
729        return 0;
730       
731fail:
732        if (*sock > 0) {
733                shutdown(*sock, SHUT_RDWR);
734                *sock = -1;
735        }
736        free(sar.buf);
737        return ret;
738}
739
740/* Retrieve streams information from a connected association -- optionaly provide the primary address */
741int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary )
742{
743        struct sctp_status status;
744        socklen_t sz = sizeof(status);
745       
746        TRACE_ENTRY("%d %p %p %p", sock, in, out, primary);
747        CHECK_PARAMS( (sock > 0) && in && out );
748       
749        /* Read the association parameters */
750        memset(&status, 0, sizeof(status));
751        CHECK_SYS(  getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz) );
752        if (sz != sizeof(status))
753        {
754                TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %zd", sz, sizeof(status));
755                return ENOTSUP;
756        }
757        if (TRACE_BOOL(SCTP_LEVEL)) {
758                fd_log_debug( "SCTP_STATUS : sstat_state                  : %i\n" , status.sstat_state);
759                fd_log_debug( "              sstat_rwnd                   : %u\n" , status.sstat_rwnd);
760                fd_log_debug( "              sstat_unackdata              : %hu\n", status.sstat_unackdata);
761                fd_log_debug( "              sstat_penddata               : %hu\n", status.sstat_penddata);
762                fd_log_debug( "              sstat_instrms                : %hu\n", status.sstat_instrms);
763                fd_log_debug( "              sstat_outstrms               : %hu\n", status.sstat_outstrms);
764                fd_log_debug( "              sstat_fragmentation_point    : %u\n" , status.sstat_fragmentation_point);
765                fd_log_debug( "              sstat_primary.spinfo_address : ");
766                sSA_DUMP_NODE_SERV(&status.sstat_primary.spinfo_address, NI_NUMERICHOST | NI_NUMERICSERV );
767                fd_log_debug( "\n" );
768                fd_log_debug( "              sstat_primary.spinfo_state   : %d\n" , status.sstat_primary.spinfo_state);
769                fd_log_debug( "              sstat_primary.spinfo_cwnd    : %u\n" , status.sstat_primary.spinfo_cwnd);
770                fd_log_debug( "              sstat_primary.spinfo_srtt    : %u\n" , status.sstat_primary.spinfo_srtt);
771                fd_log_debug( "              sstat_primary.spinfo_rto     : %u\n" , status.sstat_primary.spinfo_rto);
772                fd_log_debug( "              sstat_primary.spinfo_mtu     : %u\n" , status.sstat_primary.spinfo_mtu);
773        }
774       
775        *in = status.sstat_instrms;
776        *out = status.sstat_outstrms;
777       
778        if (primary)
779                memcpy(primary, &status.sstat_primary.spinfo_address, sizeof(sSS));
780       
781        return 0;
782}
783
784/* Get the list of local endpoints of the socket */
785int fd_sctp_get_local_ep(int sock, struct fd_list * list)
786{
787        union {
788                sSA     *sa;
789                uint8_t *buf;
790        } ptr;
791       
792        sSA * data;
793        int count;
794       
795        TRACE_ENTRY("%d %p", sock, list);
796        CHECK_PARAMS(list);
797       
798        /* Read the list on the socket */
799        CHECK_SYS( count = sctp_getladdrs(sock, 0, &data)  );
800        ptr.sa = data;
801       
802        while (count) {
803                socklen_t sl;
804                switch (ptr.sa->sa_family) {
805                        case AF_INET:   sl = sizeof(sSA4); break;
806                        case AF_INET6:  sl = sizeof(sSA6); break;
807                        default:
808                                TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family);
809                }
810                               
811                CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
812                ptr.buf += sl;
813                count --;
814        }
815       
816        /* Free the list */
817        sctp_freeladdrs(data);
818       
819        /* Now get the primary address, the add function will take care of merging with existing entry */
820        {
821                 
822                struct sctp_status status;
823                socklen_t sz = sizeof(status);
824                int ret;
825               
826                memset(&status, 0, sizeof(status));
827                /* Attempt to use SCTP_STATUS message to retrieve the primary address */
828                ret = getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz);
829                if (sz != sizeof(status))
830                        ret = -1;
831                sz = sizeof(sSS);
832                if (ret < 0)
833                {
834                        /* Fallback to getsockname -- not recommended by draft-ietf-tsvwg-sctpsocket-19#section-7.4 */
835                        CHECK_SYS(getsockname(sock, (sSA *)&status.sstat_primary.spinfo_address, &sz));
836                }
837                       
838                CHECK_FCT( fd_ep_add_merge( list, (sSA *)&status.sstat_primary.spinfo_address, sz, EP_FL_PRIMARY ) );
839        }
840       
841        return 0;
842}
843
844/* Get the list of remote endpoints of the socket */
845int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
846{
847        union {
848                sSA     *sa;
849                uint8_t *buf;
850        } ptr;
851       
852        sSA * data;
853        int count;
854       
855        TRACE_ENTRY("%d %p", sock, list);
856        CHECK_PARAMS(list);
857       
858        /* Read the list on the socket */
859        CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data)  );
860        ptr.sa = data;
861       
862        while (count) {
863                socklen_t sl;
864                switch (ptr.sa->sa_family) {
865                        case AF_INET:   sl = sizeof(sSA4); break;
866                        case AF_INET6:  sl = sizeof(sSA6); break;
867                        default:
868                                TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d", ptr.sa->sa_family);
869                }
870                               
871                CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
872                ptr.buf += sl;
873                count --;
874        }
875       
876        /* Free the list */
877        sctp_freepaddrs(data);
878       
879        /* Now get the primary address, the add function will take care of merging with existing entry */
880        {
881                sSS ss;
882                socklen_t sl = sizeof(sSS);
883       
884                CHECK_SYS(getpeername(sock, (sSA *)&ss, &sl));
885                CHECK_FCT( fd_ep_add_merge( list, (sSA *)&ss, sl, EP_FL_PRIMARY ) );
886        }
887       
888        /* Done! */
889        return 0;
890}
891
892/* Send a buffer over a specified stream */
893int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len)
894{
895        struct msghdr mhdr;
896        struct iovec  iov;
897        struct {
898                struct cmsghdr          hdr;
899                struct sctp_sndrcvinfo  sndrcv;
900        } anci;
901        ssize_t ret;
902       
903        TRACE_ENTRY("%d %hu %p %zd", sock, strid, buf, len);
904       
905        memset(&mhdr, 0, sizeof(mhdr));
906        memset(&iov,  0, sizeof(iov));
907        memset(&anci, 0, sizeof(anci));
908       
909        /* IO Vector: message data */
910        iov.iov_base = buf;
911        iov.iov_len  = len;
912       
913        /* Anciliary data: specify SCTP stream */
914        anci.hdr.cmsg_len   = sizeof(anci);
915        anci.hdr.cmsg_level = IPPROTO_SCTP;
916        anci.hdr.cmsg_type  = SCTP_SNDRCV;
917        anci.sndrcv.sinfo_stream = strid;
918        /* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */
919       
920        /* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */
921       
922        mhdr.msg_iov    = &iov;
923        mhdr.msg_iovlen = 1;
924       
925        mhdr.msg_control    = &anci;
926        mhdr.msg_controllen = sizeof(anci);
927       
928        TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock);
929       
930        CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) );
931        ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */
932       
933        return 0;
934}
935
936/* Receive the next data from the socket, or next notification */
937int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event)
938{
939        ssize_t                  ret = 0;
940        struct msghdr            mhdr;
941        char                     ancidata[ CMSG_BUF_LEN ];
942        struct iovec             iov;
943        uint8_t                 *data = NULL;
944        size_t                   bufsz = 0, datasize = 0;
945        size_t                   mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */
946       
947        TRACE_ENTRY("%d %p %p %p %p", sock, strid, buf, len, event);
948        CHECK_PARAMS( (sock > 0) && buf && len && event );
949       
950        /* Cleanup out parameters */
951        *buf = NULL;
952        *len = 0;
953        *event = 0;
954       
955        /* Prepare header for receiving message */
956        memset(&mhdr, 0, sizeof(mhdr));
957        mhdr.msg_iov    = &iov;
958        mhdr.msg_iovlen = 1;
959        mhdr.msg_control    = &ancidata;
960        mhdr.msg_controllen = sizeof(ancidata);
961       
962        /* We will loop while all data is not received. */
963incomplete:
964        if (datasize == bufsz) {
965                /* The buffer is full, enlarge it */
966                bufsz += mempagesz;
967                CHECK_MALLOC( data = realloc(data, bufsz) );
968        }
969        /* the new data will be received following the preceding */
970        memset(&iov,  0, sizeof(iov));
971        iov.iov_base = data + datasize ;
972        iov.iov_len  = bufsz - datasize;
973
974        /* Receive data from the socket */
975        pthread_cleanup_push(free, data);
976        ret = recvmsg(sock, &mhdr, 0);
977        pthread_cleanup_pop(0);
978       
979        /* Handle errors */
980        if (ret <= 0) { /* Socket is closed, or an error occurred */
981                CHECK_SYS_DO(ret, /* to log in case of error */);
982                free(data);
983                *event = FDEVP_CNX_ERROR;
984                return 0;
985        }
986       
987        /* Update the size of data we received */
988        datasize += ret;
989
990        /* SCTP provides an indication when we received a full record; loop if it is not the case */
991        if ( ! (mhdr.msg_flags & MSG_EOR) ) {
992                goto incomplete;
993        }
994       
995        TRACE_DEBUG(FULL, "Received %db data on socket %d", datasize, sock);
996       
997        /* Handle the case where the data received is a notification */
998        if (mhdr.msg_flags & MSG_NOTIFICATION) {
999                union sctp_notification * notif = (union sctp_notification *) data;
1000               
1001                switch (notif->sn_header.sn_type) {
1002                       
1003                        case SCTP_ASSOC_CHANGE:
1004                                TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification");
1005                                TRACE_DEBUG(SCTP_LEVEL, "    state : %hu", notif->sn_assoc_change.sac_state);
1006                                TRACE_DEBUG(SCTP_LEVEL, "    error : %hu", notif->sn_assoc_change.sac_error);
1007                                TRACE_DEBUG(SCTP_LEVEL, "    instr : %hu", notif->sn_assoc_change.sac_inbound_streams);
1008                                TRACE_DEBUG(SCTP_LEVEL, "   outstr : %hu", notif->sn_assoc_change.sac_outbound_streams);
1009                               
1010                                *event = FDEVP_CNX_EP_CHANGE;
1011                                break;
1012       
1013                        case SCTP_PEER_ADDR_CHANGE:
1014                                TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification");
1015                                TRACE_DEBUG_sSA(SCTP_LEVEL, "    intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" );
1016                                TRACE_DEBUG(SCTP_LEVEL, "          state : %d", notif->sn_paddr_change.spc_state);
1017                                TRACE_DEBUG(SCTP_LEVEL, "          error : %d", notif->sn_paddr_change.spc_error);
1018                               
1019                                *event = FDEVP_CNX_EP_CHANGE;
1020                                break;
1021       
1022                        case SCTP_SEND_FAILED:
1023                                TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification");
1024                                TRACE_DEBUG(SCTP_LEVEL, "    len : %hu", notif->sn_send_failed.ssf_length);
1025                                TRACE_DEBUG(SCTP_LEVEL, "    err : %d",  notif->sn_send_failed.ssf_error);
1026                               
1027                                *event = FDEVP_CNX_ERROR;
1028                                break;
1029                       
1030                        case SCTP_REMOTE_ERROR:
1031                                TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification");
1032                                TRACE_DEBUG(SCTP_LEVEL, "    err : %hu", ntohs(notif->sn_remote_error.sre_error));
1033                                TRACE_DEBUG(SCTP_LEVEL, "    len : %hu", ntohs(notif->sn_remote_error.sre_length));
1034                               
1035                                *event = FDEVP_CNX_ERROR;
1036                                break;
1037       
1038                        case SCTP_SHUTDOWN_EVENT:
1039                                TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification");
1040                               
1041                                *event = FDEVP_CNX_ERROR;
1042                                break;
1043                       
1044                        default:       
1045                                TRACE_DEBUG(FULL, "Received unknown notification %d, assume error", notif->sn_header.sn_type);
1046                                *event = FDEVP_CNX_ERROR;
1047                }
1048               
1049                free(data);
1050                return 0;
1051        }
1052       
1053        /* From this point, we have received a message */
1054        *event = FDEVP_CNX_MSG_RECV;
1055        *buf = data;
1056        *len = datasize;
1057       
1058        if (strid) {
1059                struct cmsghdr          *hdr;
1060                struct sctp_sndrcvinfo  *sndrcv;
1061               
1062                /* Handle the anciliary data */
1063                for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) {
1064
1065                        /* We deal only with anciliary data at SCTP level */
1066                        if (hdr->cmsg_level != IPPROTO_SCTP) {
1067                                TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level);
1068                                continue;
1069                        }
1070                       
1071                        /* Also only interested in SCTP_SNDRCV message for the moment */
1072                        if (hdr->cmsg_type != SCTP_SNDRCV) {
1073                                TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type);
1074                                continue;
1075                        }
1076                       
1077                        sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr);
1078                        if (TRACE_BOOL(SCTP_LEVEL)) {
1079                                fd_log_debug( "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV\n");
1080                                fd_log_debug( "    sinfo_stream    : %hu\n", sndrcv->sinfo_stream);
1081                                fd_log_debug( "    sinfo_ssn       : %hu\n", sndrcv->sinfo_ssn);
1082                                fd_log_debug( "    sinfo_flags     : %hu\n", sndrcv->sinfo_flags);
1083                                /* fd_log_debug( "    sinfo_pr_policy : %hu\n", sndrcv->sinfo_pr_policy); */
1084                                fd_log_debug( "    sinfo_ppid      : %u\n" , sndrcv->sinfo_ppid);
1085                                fd_log_debug( "    sinfo_context   : %u\n" , sndrcv->sinfo_context);
1086                                /* fd_log_debug( "    sinfo_pr_value  : %u\n" , sndrcv->sinfo_pr_value); */
1087                                fd_log_debug( "    sinfo_tsn       : %u\n" , sndrcv->sinfo_tsn);
1088                                fd_log_debug( "    sinfo_cumtsn    : %u\n" , sndrcv->sinfo_cumtsn);
1089                        }
1090
1091                        *strid = sndrcv->sinfo_stream;
1092                }
1093        }
1094       
1095        return 0;
1096}
Note: See TracBrowser for help on using the repository browser.