Navigation



Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/sctp.c

    r29 r20  
    3535
    3636#include "fD.h"
    37 #include "cnxctx.h"
    3837
    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 */
    55 static int fd_setsockopt_prebind(int sk)
     38int fd_sctp_create_bind_server( int * socket, uint16_t port )
    5639{
    57         socklen_t sz;
     40        TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str");
    5841       
    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;
     42        return ENOTSUP;
    43643}
    43744
    438 
    439 /* Post-binding socket options */
    440 static int fd_setsockopt_postbind(int sk, int bound_to_default)
     45int fd_sctp_get_str_info( int socket, int *in, int *out )
    44146{
    442         TRACE_ENTRY( "%d %d", sk, bound_to_default);
     47        TODO("Retrieve streams info from the socket");
    44348       
    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;
     49        return ENOTSUP;
    48250}
    483 
    484 /* Create a socket server and bind it according to daemon s configuration */
    485 int 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)) ;
    506 redo:
    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 */
    636 int 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 */
    644 int 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        
    731 fail:
    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 */
    741 int 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 */
    785 int 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 */
    845 int 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 */
    893 int 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 */
    937 int 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. */
    963 incomplete:
    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 TracChangeset for help on using the changeset viewer.