Navigation



Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/sctp.c

    r20 r29  
    3535
    3636#include "fD.h"
    37 
    38 int fd_sctp_create_bind_server( int * socket, uint16_t port )
     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)
    3956{
    40         TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str");
    41        
    42         return ENOTSUP;
     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;
    43436}
    44437
    45 int fd_sctp_get_str_info( int socket, int *in, int *out )
     438
     439/* Post-binding socket options */
     440static int fd_setsockopt_postbind(int sk, int bound_to_default)
    46441{
    47         TODO("Retrieve streams info from the socket");
    48        
    49         return ENOTSUP;
     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;
    50482}
     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 TracChangeset for help on using the changeset viewer.