Navigation


Changes in / [30:bca243c65b56:20:277ec00d793e] in freeDiameter


Ignore:
Files:
5 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • contrib/ca_script/Makefile

    r29 r19  
    3232O = WIDE
    3333OU = "AAA WG"
    34 
    35 #Default lifetime
    36 DAYS = 365
    3734
    3835#Values for the CA
     
    133130        @openssl ca $(CONFIG) -in $(DIR)/clients/csr/$(name).csr \
    134131                -out $(DIR)/clients/certs/$(name).cert \
    135                 -days $(DAYS) \
    136132                -batch
    137133        @ln -s $(DIR)/clients/certs/$(name).cert $(DIR)/certs/`openssl x509 -noout -hash < $(DIR)/clients/certs/$(name).cert`.0
  • doc/freediameter.conf.sample

    r24 r20  
    6868#ListenOn = "202.249.37.5";
    6969#ListenOn = "2001:200:903:2::202:1";
    70 #ListenOn = "fe80::21c:5ff:fe98:7d62%eth0";
    7170
    7271##############################################################
     
    185184#  No_TLS;       # assume transparent security instead of TLS
    186185#  Port = 3868;  # The port to connect to
     186#  SCTP_streams = 30;
    187187#  TcTimer = 30;
    188188#  TwTimer = 30;
    189189#  ConnectTo = "202.249.37.5";
    190190#  ConnectTo = "2001:200:903:2::202:1";
    191 #  TLS_Prio = "NORMAL";
    192191# Examples:
    193192#ConnectPeer = "aaa.wide.ad.jp";
     
    202201SecPort = 3867;
    203202TLS_old_method;
     203No_IP;
     204Prefer_TCP;
    204205SCTP_streams = 50;
     206ListenOn = "202.249.37.5";
     207ListenOn = "2001:200:903:2::202:1";
    205208TcTimer = 60;
    206209TwTimer = 6;
    207 #ListenOn = "133.243.146.201";
    208 #ListenOn = "fe80::21d:9ff:fe89:7d68%eth0";
    209210NoRelay;
    210211LoadExtension = "extensions/dbg_monitor.fdx";
     
    212213LoadExtension = "extensions/dict_eap.fdx";
    213214ConnectPeer = "jules.nautilus6.org" ;
    214 ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; } ;
    215 TLS_Cred = "/etc/openssl-ca/clients/certs/test.cert" , "/etc/openssl-ca/clients/privkeys/test.key.pem";
     215ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; No_TCP; SCTP_streams = 60; } ;
     216TLS_Cred = "/etc/openssl-ca/clients/certs/fdtest.cert" , "/etc/openssl-ca/clients/privkeys/fdtest.key.pem";
    216217TLS_CA = "/etc/openssl-ca/public-www/cacert.pem";
    217218# TLS_CRL = "/etc/openssl-ca/public-www/crl.pem";
  • extensions/dbg_monitor/monitor.c

    r25 r11  
    4949static void got_sig(int signal)
    5050{
    51         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, 0, NULL), /* continue */);
    52         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, 0, NULL), /* continue */);
    53         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, 0, NULL), /* continue */);
     51        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, NULL), /* continue */);
     52        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, NULL), /* continue */);
     53        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, NULL), /* continue */);
    5454}
    5555/* Thread to display periodical debug information */
     
    7777                #endif /* DEBUG */
    7878                TRACE_DEBUG(NONE, "Monitor information");
    79                 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, 0, NULL), /* continue */);
    80                 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_SERV, 0, NULL), /* continue */);
    81                 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, 0, NULL), /* continue */);
     79                CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, NULL), /* continue */);
     80                CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, NULL), /* continue */);
    8281                pthread_testcancel();
    8382        }
  • freeDiameter/CMakeLists.txt

    r25 r20  
    1010SET(FD_COMMON_SRC
    1111        fD.h
    12         cnxctx.h
    1312        config.c
    1413        cnxctx.c
    1514        dispatch.c
    16         endpoints.c
    1715        extensions.c
    1816        dict_base_proto.c
     
    2321        p_psm.c
    2422        server.c
    25         tcp.c
    2623        )
    2724
    2825IF(NOT DISABLE_SCTP)
    29         SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c sctps.c)
     26        SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c)
    3027ENDIF(NOT DISABLE_SCTP)
    3128
  • freeDiameter/cnxctx.c

    r30 r20  
    3535
    3636#include "fD.h"
    37 #include "cnxctx.h"
    3837
    39 /* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */
    40 #ifndef DIAMETER_MSG_SIZE_MAX
    41 #define DIAMETER_MSG_SIZE_MAX   65535   /* in bytes */
    42 #endif /* DIAMETER_MSG_SIZE_MAX */
    43 
    44 /* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations .
    45  * They are used to hide the details of the processing to the higher layers of the daemon.
    46  * They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported.
    47  */
    48 
    49 /* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */
    50 
    51 /* Lifetime of a cnxctx object:
    52  * 1) Creation
    53  *    a) a server socket:
    54  *       - create the object with fd_cnx_serv_tcp or fd_cnx_serv_sctp
    55  *       - start listening incoming connections: fd_cnx_serv_listen
    56  *       - accept new clients with fd_cnx_serv_accept.
    57  *    b) a client socket:
    58  *       - connect to a remote server with fd_cnx_cli_connect
    59  *
    60  * 2) Initialization
    61  *    - if TLS is started first, call fd_cnx_handshake
    62  *    - otherwise to receive clear messages, call fd_cnx_start_clear. fd_cnx_handshake can be called later.
    63  *
    64  * 3) Usage
    65  *    - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not, but blocking).
    66  *    - fd_cnx_recv_setaltfifo : when a message is received, the event is sent to an external fifo list. fd_cnx_receive does not work when the alt_fifo is set.
    67  *    - fd_cnx_getid : retrieve a descriptive string for the connection (for debug)
    68  *    - fd_cnx_getremoteid : identification of the remote peer (IP address or fqdn)
    69  *    - fd_cnx_getcred : get the remote peer TLS credentials, after handshake
    70  *    - fd_cnx_getendpoints : get the endpoints (IP) of the connection
    71  *
    72  * 4) End
    73  *    - fd_cnx_destroy
    74  */
    75 
    76 
    77 /*******************************************/
    78 /*     Creation of a connection object     */
    79 /*******************************************/
    80 
    81 /* Initialize a context structure */
    82 static struct cnxctx * fd_cnx_init(int full)
     38/* Initialize a connection context */
     39struct cnxctx * fd_cnx_init(int sock, int proto)
    8340{
    8441        struct cnxctx * conn = NULL;
    85 
    86         TRACE_ENTRY("%d", full);
    87 
     42       
     43        TRACE_ENTRY("%d %d", sock, proto);
     44        CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL);
     45       
    8846        CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL );
    8947        memset(conn, 0, sizeof(struct cnxctx));
    90 
    91         if (full) {
    92                 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL );
     48       
     49        conn->cc_socket = sock;
     50        conn->cc_proto  = proto;
     51       
     52        fd_list_init(&conn->cc_ep_remote, conn);
     53        fd_list_init(&conn->cc_ep_local, conn);
     54       
     55        if (proto == IPPROTO_SCTP) {
     56#ifndef DISABLE_SCTP
     57                CHECK_FCT_DO( fd_sctp_get_str_info( sock, &conn->cc_sctp_para.str_in, &conn->cc_sctp_para.str_out ),
     58                                { free(conn); return NULL; } );
     59                conn->cc_sctp_para.pairs = (conn->cc_sctp_para.str_out < conn->cc_sctp_para.str_in) ? conn->cc_sctp_para.str_out : conn->cc_sctp_para.str_in;
     60#else /* DISABLE_SCTP */
     61                ASSERT(0);
     62#endif /* DISABLE_SCTP */
    9363        }
    94 
     64       
    9565        return conn;
    9666}
    9767
    98 /* Create and bind a server socket to the given endpoint and port */
    99 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep)
    100 {
    101         struct cnxctx * cnx = NULL;
    102         sSS dummy;
    103         sSA * sa = (sSA *) &dummy;
    104 
    105         TRACE_ENTRY("%hu %d %p", port, family, ep);
    106 
    107         CHECK_PARAMS_DO( port, return NULL );
    108         CHECK_PARAMS_DO( ep || family, return NULL );
    109         CHECK_PARAMS_DO( (! family) || (family == AF_INET) || (family == AF_INET6), return NULL );
    110         CHECK_PARAMS_DO( (! ep) || (!family) || (ep->ss.ss_family == family), return NULL );
    111 
    112         /* The connection object */
    113         CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL );
    114 
    115         /* Prepare the socket address information */
    116         if (ep) {
    117                 memcpy(sa, &ep->ss, sizeof(sSS));
    118         } else {
    119                 memset(&dummy, 0, sizeof(dummy));
    120                 sa->sa_family = family;
    121         }
    122         if (sa->sa_family == AF_INET) {
    123                 ((sSA4 *)sa)->sin_port = htons(port);
    124         } else {
    125                 ((sSA6 *)sa)->sin6_port = htons(port);
    126         }
    127 
    128         /* Create the socket */
    129         CHECK_FCT_DO( fd_tcp_create_bind_server( &cnx->cc_socket, sa, sizeof(sSS) ), goto error );
    130 
    131         /* Generate the name for the connection object */
    132         {
    133                 char addrbuf[INET6_ADDRSTRLEN];
    134                 int  rc;
    135                 rc = getnameinfo(sa, sizeof(sSS), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
    136                 if (rc)
    137                         snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
    138                 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv TCP [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket);
    139         }
    140 
    141         cnx->cc_proto = IPPROTO_TCP;
    142 
    143         return cnx;
    144 
    145 error:
    146         fd_cnx_destroy(cnx);
    147         return NULL;
    148 }
    149 
    150 /* Same function for SCTP, with a list of local endpoints to bind to */
    151 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list)
    152 {
    153 #ifdef DISABLE_SCTP
    154         TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
    155         ASSERT(0);
    156         CHECK_FCT_DO( ENOTSUP, return NULL);
    157 #else /* DISABLE_SCTP */
    158         struct cnxctx * cnx = NULL;
    159         sSS dummy;
    160         sSA * sa = (sSA *) &dummy;
    161 
    162         TRACE_ENTRY("%hu %p", port, ep_list);
    163 
    164         CHECK_PARAMS_DO( port, return NULL );
    165 
    166         /* The connection object */
    167         CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL );
    168 
    169         /* Create the socket */
    170         CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error );
    171 
    172         /* Generate the name for the connection object */
    173         snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv SCTP :%hu (%d)", port, cnx->cc_socket);
    174 
    175         cnx->cc_proto = IPPROTO_SCTP;
    176 
    177         return cnx;
    178 
    179 error:
    180         fd_cnx_destroy(cnx);
    181         return NULL;
    182 #endif /* DISABLE_SCTP */
    183 }
    184 
    185 /* Allow clients to connect on the server socket */
    186 int fd_cnx_serv_listen(struct cnxctx * conn)
    187 {
    188         CHECK_PARAMS( conn );
    189 
    190         switch (conn->cc_proto) {
    191                 case IPPROTO_TCP:
    192                         CHECK_FCT(fd_tcp_listen(conn->cc_socket));
    193                         break;
    194 
    195 #ifndef DISABLE_SCTP
    196                 case IPPROTO_SCTP:
    197                         CHECK_FCT(fd_sctp_listen(conn->cc_socket));
    198                         break;
    199 #endif /* DISABLE_SCTP */
    200 
    201                 default:
    202                         CHECK_PARAMS(0);
    203         }
    204 
    205         return 0;
    206 }
    207 
    208 /* Accept a client (blocking until a new client connects) -- cancelable */
    209 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv)
    210 {
    211         struct cnxctx * cli = NULL;
    212         sSS ss;
    213         socklen_t ss_len = sizeof(ss);
    214         int cli_sock = 0;
    215         struct fd_endpoint * ep;
    216 
    217         TRACE_ENTRY("%p", serv);
    218         CHECK_PARAMS_DO(serv, return NULL);
    219        
    220         /* Accept the new connection -- this is blocking until new client enters or cancellation */
    221         CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL );
    222        
    223         if (TRACE_BOOL(INFO)) {
    224                 fd_log_debug("%s : accepted new client [", fd_cnx_getid(serv));
    225                 sSA_DUMP_NODE( &ss, NI_NUMERICHOST );
    226                 fd_log_debug("].\n");
    227         }
    228        
    229         CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); return NULL; } );
    230         cli->cc_socket = cli_sock;
    231         cli->cc_proto = serv->cc_proto;
    232        
    233         /* Generate the name for the connection object */
    234         {
    235                 char addrbuf[INET6_ADDRSTRLEN];
    236                 char portbuf[10];
    237                 int  rc;
    238                
    239                 /* Numeric values for debug */
    240                 rc = getnameinfo((sSA *)&ss, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    241                 if (rc) {
    242                         snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
    243                         portbuf[0] = '\0';
    244                 }
    245                
    246                 snprintf(cli->cc_id, sizeof(cli->cc_id), "Incoming %s [%s]:%s (%d) @ serv (%d)",
    247                                 IPPROTO_NAME(cli->cc_proto),
    248                                 addrbuf, portbuf,
    249                                 cli->cc_socket, serv->cc_socket);
    250                
    251                 /* Name for log messages */
    252                 rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0);
    253                 if (rc)
    254                         snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc));
    255         }
    256 
    257 #ifndef DISABLE_SCTP
    258         /* SCTP-specific handlings */
    259         if (cli->cc_proto == IPPROTO_SCTP) {
    260                 /* Retrieve the number of streams */
    261                 CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out, NULL ), goto error );
    262                 if (cli->cc_sctp_para.str_out > cli->cc_sctp_para.str_in)
    263                         cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out;
    264                 else
    265                         cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in;
    266         }
    267 #endif /* DISABLE_SCTP */
    268 
    269         return cli;
    270 error:
    271         fd_cnx_destroy(cli);
    272         return NULL;
    273 }
    274 
    275 /* Client side: connect to a remote server -- cancelable */
    276 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */, socklen_t addrlen)
    277 {
    278         int sock;
    279         struct cnxctx * cnx = NULL;
    280        
    281         TRACE_ENTRY("%p %d", sa, addrlen);
    282         CHECK_PARAMS_DO( sa && addrlen, return NULL );
    283        
    284         /* Create the socket and connect, which can take some time and/or fail */
    285         CHECK_FCT_DO( fd_tcp_client( &sock, sa, addrlen ), return NULL );
    286        
    287         if (TRACE_BOOL(INFO)) {
    288                 fd_log_debug("Connection established to server '");
    289                 sSA_DUMP_NODE_SERV( sa, NI_NUMERICSERV);
    290                 fd_log_debug("' (TCP:%d).\n", sock);
    291         }
    292        
    293         /* Once the socket is created successfuly, prepare the remaining of the cnx */
    294         CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } );
    295        
    296         cnx->cc_socket = sock;
    297         cnx->cc_proto  = IPPROTO_TCP;
    298        
    299         /* Generate the names for the object */
    300         {
    301                 char addrbuf[INET6_ADDRSTRLEN];
    302                 char portbuf[10];
    303                 int  rc;
    304                
    305                 /* Numeric values for debug */
    306                 rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    307                 if (rc) {
    308                         snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
    309                         portbuf[0] = '\0';
    310                 }
    311                
    312                 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of TCP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
    313                
    314                 /* Name for log messages */
    315                 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
    316                 if (rc)
    317                         snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
    318         }
    319        
    320         return cnx;
    321 
    322 error:
    323         fd_cnx_destroy(cnx);
    324         return NULL;
    325 }
    326 
    327 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */
    328 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list)
    329 {
    330 #ifdef DISABLE_SCTP
    331         TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
    332         ASSERT(0);
    333         CHECK_FCT_DO( ENOTSUP, return NULL);
    334 #else /* DISABLE_SCTP */
    335         int sock;
    336         struct cnxctx * cnx = NULL;
    337         sSS primary;
    338        
    339         TRACE_ENTRY("%p", list);
    340         CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL );
    341        
    342         CHECK_FCT_DO( fd_sctp_client( &sock, no_ip6, port, list ), return NULL );
    343        
    344         /* Once the socket is created successfuly, prepare the remaining of the cnx */
    345         CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } );
    346        
    347         cnx->cc_socket = sock;
    348         cnx->cc_proto  = IPPROTO_SCTP;
    349        
    350         /* Retrieve the number of streams and primary address */
    351         CHECK_FCT_DO( fd_sctp_get_str_info( sock, &cnx->cc_sctp_para.str_in, &cnx->cc_sctp_para.str_out, &primary ), goto error );
    352         if (cnx->cc_sctp_para.str_out > cnx->cc_sctp_para.str_in)
    353                 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_out;
    354         else
    355                 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in;
    356        
    357         if (TRACE_BOOL(INFO)) {
    358                 fd_log_debug("Connection established to server '");
    359                 sSA_DUMP_NODE_SERV( &primary, NI_NUMERICSERV);
    360                 fd_log_debug("' (SCTP:%d, %d/%d streams).\n", sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out);
    361         }
    362        
    363         /* Generate the names for the object */
    364         {
    365                 char addrbuf[INET6_ADDRSTRLEN];
    366                 char portbuf[10];
    367                 int  rc;
    368                
    369                 /* Numeric values for debug */
    370                 rc = getnameinfo((sSA *)&primary, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    371                 if (rc) {
    372                         snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
    373                         portbuf[0] = '\0';
    374                 }
    375                
    376                 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of SCTP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
    377                
    378                 /* Name for log messages */
    379                 rc = getnameinfo((sSA *)&primary, sizeof(sSS), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
    380                 if (rc)
    381                         snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
    382         }
    383        
    384         return cnx;
    385 
    386 error:
    387         fd_cnx_destroy(cnx);
    388         return NULL;
    389 #endif /* DISABLE_SCTP */
    390 }
    391 
    392 /* Return a string describing the connection, for debug */
    393 char * fd_cnx_getid(struct cnxctx * conn)
    394 {
    395         CHECK_PARAMS_DO( conn, return "" );
    396         return conn->cc_id;
    397 }
    398 
    399 /* Return the protocol of a connection */
    400 int fd_cnx_getproto(struct cnxctx * conn)
    401 {
    402         CHECK_PARAMS_DO( conn, return 0 );
    403         return conn->cc_proto;
    404 }
    405 
    406 /* Return the TLS state of a connection */
    407 int fd_cnx_getTLS(struct cnxctx * conn)
    408 {
    409         CHECK_PARAMS_DO( conn, return 0 );
    410         return conn->cc_tls;
    411 }
    412 
    413 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
    414 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
    415 {
    416         TRACE_ENTRY("%p %p %p", conn, local, remote);
    417         CHECK_PARAMS(conn);
    418        
    419         if (local) {
    420                 /* Retrieve the local endpoint(s) of the connection */
    421                 switch (conn->cc_proto) {
    422                         case IPPROTO_TCP: {
    423                                 sSS ss;
    424                                 socklen_t sl;
    425                                 CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl));
    426                                 CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY));
    427                         }
    428                         break;
    429 
    430                         #ifndef DISABLE_SCTP
    431                         case IPPROTO_SCTP: {
    432                                 CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local));
    433                         }
    434                         break;
    435                         #endif /* DISABLE_SCTP */
    436 
    437                         default:
    438                                 CHECK_PARAMS(0);
    439                 }
    440         }
    441        
    442         if (remote) {
    443                 /* Check we have a full connection object, not a listening socket (with no remote) */
    444                 CHECK_PARAMS( conn->cc_incoming );
    445                
    446                 /* Retrieve the peer endpoint(s) of the connection */
    447                 switch (conn->cc_proto) {
    448                         case IPPROTO_TCP: {
    449                                 sSS ss;
    450                                 socklen_t sl;
    451                                 CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
    452                                 CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
    453                         }
    454                         break;
    455 
    456                         #ifndef DISABLE_SCTP
    457                         case IPPROTO_SCTP: {
    458                                 CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote));
    459                         }
    460                         break;
    461                         #endif /* DISABLE_SCTP */
    462 
    463                         default:
    464                                 CHECK_PARAMS(0);
    465                 }
    466         }
    467 
    468         return 0;
    469 }
    470 
    471 
    472 /* Get a string describing the remote peer address (ip address or fqdn) */
    473 char * fd_cnx_getremoteid(struct cnxctx * conn)
    474 {
    475         CHECK_PARAMS_DO( conn, return "" );
    476         return conn->cc_remid;
    477 }
    478 
    479 
    480 /**************************************/
    481 /*     Use of a connection object     */
    482 /**************************************/
    483 
    484 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */
    485 static void * rcvthr_notls_tcp(void * arg)
    486 {
    487         struct cnxctx * conn = arg;
    488        
    489         TRACE_ENTRY("%p", arg);
    490         CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
    491        
    492         /* Set the thread name */
    493         {
    494                 char buf[48];
    495                 snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket);
    496                 fd_log_threadname ( buf );
    497         }
    498        
    499         ASSERT( conn->cc_proto == IPPROTO_TCP );
    500         ASSERT( conn->cc_tls == 0 );
    501         ASSERT( Target_Queue(conn) );
    502        
    503         /* Receive from a TCP connection: we have to rebuild the message boundaries */
    504         do {
    505                 uint8_t header[4];
    506                 uint8_t * newmsg;
    507                 size_t  length;
    508                 ssize_t ret = 0;
    509                 size_t  received = 0;
    510 
    511                 do {
    512                         ret = recv(conn->cc_socket, &header[received], sizeof(header) - received, 0);
    513                         if (ret <= 0) {
    514                                 CHECK_SYS_DO(ret, /* continue */);
    515                                 goto error; /* Stop the thread, the recipient of the event will cleanup */
    516                         }
    517 
    518                         received += ret;
    519                 } while (received < sizeof(header));
    520 
    521                 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
    522 
    523                 /* Check the received word is a valid begining of a Diameter message */
    524                 if ((header[0] != DIAMETER_VERSION)     /* defined in <libfreeDiameter.h> */
    525                    || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
    526                         /* The message is suspect */
    527                         TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);
    528                         goto error; /* Stop the thread, the recipient of the event will cleanup */
    529                 }
    530 
    531                 /* Ok, now we can really receive the data */
    532                 CHECK_MALLOC_DO(  newmsg = malloc( length ), goto error );
    533                 memcpy(newmsg, header, sizeof(header));
    534 
    535                 while (received < length) {
    536                         pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
    537                         ret = recv(conn->cc_socket, newmsg + received, length - received, 0);
    538                         pthread_cleanup_pop(0);
    539 
    540                         if (ret <= 0) {
    541                                 CHECK_SYS_DO(ret, /* continue */);
    542                                 free(newmsg);
    543                                 goto error; /* Stop the thread, the recipient of the event will cleanup */
    544                         }
    545                         received += ret;
    546                 }
    547                
    548                 /* We have received a complete message, send it */
    549                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
    550                
    551         } while (conn->cc_loop);
    552        
    553 out:
    554         TRACE_DEBUG(FULL, "Thread terminated");
    555         return NULL;
    556 error:
    557         CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
    558         goto out;
    559 }
    560 
    561 #ifndef DISABLE_SCTP
    562 /* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */
    563 static void * rcvthr_notls_sctp(void * arg)
    564 {
    565         struct cnxctx * conn = arg;
    566         uint8_t * buf;
    567         size_t    bufsz;
    568         int       event;
    569        
    570         TRACE_ENTRY("%p", arg);
    571         CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
    572        
    573         /* Set the thread name */
    574         {
    575                 char buf[48];
    576                 snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket);
    577                 fd_log_threadname ( buf );
    578         }
    579        
    580         ASSERT( conn->cc_proto == IPPROTO_SCTP );
    581         ASSERT( conn->cc_tls == 0 );
    582         ASSERT( Target_Queue(conn) );
    583        
    584         do {
    585                 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event), goto error );
    586                 if (event == FDEVP_CNX_ERROR) {
    587                         goto error;
    588                 }
    589                
    590                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto error );
    591                
    592         } while (conn->cc_loop);
    593        
    594 out:
    595         TRACE_DEBUG(FULL, "Thread terminated");
    596         return NULL;
    597 error:
    598         CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
    599         goto out;
    600 }
    601 #endif /* DISABLE_SCTP */
    602 
    603 /* Returns 0 on error, received data size otherwise (always >= 0) */
    604 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
    605 {
    606         ssize_t ret;
    607 again: 
    608         CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz),
    609                 {
    610                         switch (ret) {
    611                                 case GNUTLS_E_REHANDSHAKE:
    612                                         CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    613                                                 {
    614                                                         if (TRACE_BOOL(INFO)) {
    615                                                                 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
    616                                                         }
    617                                                         ret = 0;
    618                                                         goto end;
    619                                                 } );
    620 
    621                                 case GNUTLS_E_AGAIN:
    622                                 case GNUTLS_E_INTERRUPTED:
    623                                         goto again;
    624 
    625                                 default:
    626                                         TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
    627                                         ret = 0;
    628                         }
    629                 } );
    630 end:   
    631         return ret;
    632 }
    633 
    634 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
    635 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
    636 {
    637         /* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */
    638         do {
    639                 uint8_t header[4];
    640                 uint8_t * newmsg;
    641                 size_t  length;
    642                 ssize_t ret = 0;
    643                 size_t  received = 0;
    644 
    645                 do {
    646                         ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received);
    647                         if (ret == 0) {
    648                                 /* The connection is closed */
    649                                 goto out;
    650                         }
    651                         received += ret;
    652                 } while (received < sizeof(header));
    653 
    654                 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
    655 
    656                 /* Check the received word is a valid beginning of a Diameter message */
    657                 if ((header[0] != DIAMETER_VERSION)     /* defined in <libfreeDiameter.h> */
    658                    || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
    659                         /* The message is suspect */
    660                         TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);
    661                         goto out;
    662                 }
    663 
    664                 /* Ok, now we can really receive the data */
    665                 CHECK_MALLOC(  newmsg = malloc( length ) );
    666                 memcpy(newmsg, header, sizeof(header));
    667 
    668                 while (received < length) {
    669                         pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
    670                         ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received);
    671                         pthread_cleanup_pop(0);
    672 
    673                         if (ret == 0) {
    674                                 free(newmsg);
    675                                 goto out; /* Stop the thread, the recipient of the event will cleanup */
    676                         }
    677                         received += ret;
    678                 }
    679                
    680                 /* We have received a complete message, send it */
    681                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
    682                
    683         } while (1);
    684 out:
    685         return ENOTCONN;
    686 }
    687 
    688 /* Receiver thread (TLS & 1 stream SCTP or TCP) : gnutls directly handles the socket, save records into the target queue */
    689 static void * rcvthr_tls_single(void * arg)
    690 {
    691         struct cnxctx * conn = arg;
    692        
    693         TRACE_ENTRY("%p", arg);
    694         CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error);
    695        
    696         /* Set the thread name */
    697         {
    698                 char buf[48];
    699                 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/ single stream)", conn->cc_socket);
    700                 fd_log_threadname ( buf );
    701         }
    702        
    703         ASSERT( conn->cc_tls == 1 );
    704         ASSERT( Target_Queue(conn) );
    705        
    706         CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */);
    707 error:
    708         CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
    709         TRACE_DEBUG(FULL, "Thread terminated");
    710         return NULL;
    711 }
    712 
    713 /* Start receving messages in clear (no TLS) on the connection */
    714 int fd_cnx_start_clear(struct cnxctx * conn, int loop)
    715 {
    716         TRACE_ENTRY("%p %i", conn, loop);
    717        
    718         CHECK_PARAMS( conn && Target_Queue(conn) && (!conn->cc_tls) && (!conn->cc_loop));
    719        
    720         /* Save the loop request */
    721         conn->cc_loop = loop;
    722        
    723         /* Release resources in case of a previous call was already made */
    724         CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
    725        
    726         switch (conn->cc_proto) {
    727                 case IPPROTO_TCP:
    728                         /* Start the tcp_notls thread */
    729                         CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_tcp, conn ) );
    730                         break;
    731 #ifndef DISABLE_SCTP
    732                 case IPPROTO_SCTP:
    733                         /* Start the tcp_notls thread */
    734                         CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_sctp, conn ) );
    735                         break;
    736 #endif /* DISABLE_SCTP */
    737                 default:
    738                         TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto);
    739                         return ENOTSUP;
    740         }
    741                        
    742         return 0;
    743 }
    744 
    745 /* Prepare a gnutls session object for handshake */
    746 int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds)
    747 {
    748         /* Create the master session context */
    749         CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM );
    750 
    751         /* Set the algorithm suite */
    752         if (priority) {
    753                 const char * errorpos;
    754                 CHECK_GNUTLS_DO( gnutls_priority_set_direct( *session, priority, &errorpos ),
    755                         { TRACE_DEBUG(INFO, "Error in priority string '%s' at position: '%s'\n", priority, errorpos); return EINVAL; } );
    756         } else {
    757                 CHECK_GNUTLS_DO( gnutls_priority_set( *session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL );
    758         }
    759 
    760         /* Set the credentials of this side of the connection */
    761         CHECK_GNUTLS_DO( gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, alt_creds ?: fd_g_config->cnf_sec_data.credentials), return EINVAL );
    762 
    763         /* Request the remote credentials as well */
    764         if (mode == GNUTLS_SERVER) {
    765                 gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE);
    766         }
    767        
    768         return 0;
    769 }
    770 
    771 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
    772 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
     68/* TLS handshake the connection */
     69int fd_cnx_handshake(struct cnxctx * conn, int mode)
    77370{
    77471        TRACE_ENTRY( "%p %d", conn, mode);
    775         CHECK_PARAMS( conn && (!conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
    776 
     72        CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) );
     73       
    77774        /* Save the mode */
    77875        conn->cc_tls_para.mode = mode;
    77976       
    780         /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */
    781         CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
     77        /* Create the master session context */
     78        CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM );
    78279       
    783         /* Once TLS handshake is done, we don't stop after the first message */
    784         conn->cc_loop = 1;
     80        /* Set the algorithm suite */
     81        CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL );
    78582       
    786         /* Prepare the master session credentials and priority */
    787         CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority, alt_creds) );
     83        /* Set the credentials of this side of the connection */
     84        CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL );
     85       
     86        /* Request the remote credentials as well */
     87        if (mode == GNUTLS_SERVER) {
     88                gnutls_certificate_server_set_request (conn->cc_tls_para.session, GNUTLS_CERT_REQUIRE);
     89        }
     90
     91        /* Set the socket info in the session */
     92        gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket);
    78893
    78994        /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */
    790         if (conn->cc_sctp_para.pairs > 1) {
    791 #ifdef DISABLE_SCTP
     95        if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {
     96#ifndef DISABLE_SCTP
     97                TODO("Initialize the SCTP TLS wrapper");
     98                TODO("Set the lowat, push and pull functions");
     99#else /* DISABLE_SCTP */
    792100                ASSERT(0);
    793                 CHECK_FCT( ENOTSUP );
    794 #else /* DISABLE_SCTP */
    795                 /* Initialize the wrapper, start the demux thread */
    796                 CHECK_FCT( fd_sctps_init(conn) );
    797101#endif /* DISABLE_SCTP */
    798         } else {
    799                 /* Set the socket info in the session */
    800                 gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket);
    801102        }
    802 
     103       
    803104        /* Handshake master session */
    804105        {
     
    807108                        {
    808109                                if (TRACE_BOOL(INFO)) {
    809                                         fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
     110                                        fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret));
    810111                                }
    811112                                return EINVAL;
    812113                        } );
    813 
     114               
    814115                /* Now verify the remote credentials are valid -- only simple test here */
    815116                CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL );
    816117                if (ret) {
    817118                        if (TRACE_BOOL(INFO)) {
    818                                 fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id);
     119                                fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket);
    819120                                if (ret & GNUTLS_CERT_INVALID)
    820121                                        fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
     
    831132                }
    832133        }
    833 
    834         /* Multi-stream TLS: handshake other streams as well */
    835         if (conn->cc_sctp_para.pairs > 1) {
     134       
     135        /* Other sessions in case of multi-stream SCTP are resumed from the master */
     136        if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {
    836137#ifndef DISABLE_SCTP
    837                 /* Resume all additional sessions from the master one. */
    838                 CHECK_FCT(fd_sctps_handshake_others(conn, priority, alt_creds));
    839                
    840                 /* Mark the connection as protected from here */
    841                 conn->cc_tls = 1;
    842 
    843                 /* Start decrypting the messages from all threads and queuing them in target queue */
    844                 CHECK_FCT(fd_sctps_startthreads(conn));
     138                TODO("Init and resume all additional sessions from the master one.");
    845139#endif /* DISABLE_SCTP */
    846         } else {
    847                 /* Mark the connection as protected from here */
    848                 conn->cc_tls = 1;
    849 
    850                 /* Start decrypting the data */
    851                 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) );
    852140        }
    853141       
    854142        return 0;
    855143}
    856 
    857 /* Retrieve TLS credentials of the remote peer, after handshake */
    858 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size)
    859 {
    860         TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size);
    861         CHECK_PARAMS( conn && (conn->cc_tls) && cert_list && cert_list_size );
    862        
    863         /* This function only works for X.509 certificates. */
    864         CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 );
    865        
    866         *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size);
    867         if (*cert_list == NULL) {
    868                 TRACE_DEBUG(INFO, "No certificate was provided by remote peer / an error occurred.");
    869                 return EINVAL;
    870         }
    871 
    872         TRACE_DEBUG( FULL, "Remote peer provided %d certificates.\n", *cert_list_size);
    873        
    874         return 0;
    875 }
    876 
    877 /* Receive next message. if timeout is not NULL, wait only until timeout. This function only pulls from a queue, mgr thread is filling that queue aynchrounously. */
    878 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)
    879 {
    880         int    ev;
    881         size_t ev_sz;
    882         void * ev_data;
    883        
    884         TRACE_ENTRY("%p %p %p %p", conn, timeout, buf, len);
    885         CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);
    886         CHECK_PARAMS(conn->cc_rcvthr != (pthread_t)NULL);
    887         CHECK_PARAMS(conn->cc_alt == NULL);
    888 
    889         /* Now, pull the first event */
    890 get_next:
    891         if (timeout) {
    892                 CHECK_FCT( fd_event_timedget(conn->cc_incoming, timeout, FDEVP_PSM_TIMEOUT, &ev, &ev_sz, &ev_data) );
    893         } else {
    894                 CHECK_FCT( fd_event_get(conn->cc_incoming, &ev, &ev_sz, &ev_data) );
    895         }
    896        
    897         switch (ev) {
    898                 case FDEVP_CNX_MSG_RECV:
    899                         /* We got one */
    900                         *len = ev_sz;
    901                         *buf = ev_data;
    902                         return 0;
    903                        
    904                 case FDEVP_PSM_TIMEOUT:
    905                         TRACE_DEBUG(FULL, "Timeout event received");
    906                         return ETIMEDOUT;
    907                        
    908                 case FDEVP_CNX_EP_CHANGE:
    909                         /* We ignore this event */
    910                         goto get_next;
    911                        
    912                 case FDEVP_CNX_ERROR:
    913                         TRACE_DEBUG(FULL, "Received ERROR event on the connection");
    914                         return ENOTCONN;
    915         }
    916        
    917         TRACE_DEBUG(INFO, "Received unexpected event %d (%s)", ev, fd_pev_str(ev));
    918         return EINVAL;
    919 }
    920 
    921 /* Set an alternate FIFO list to send FDEVP_CNX_* events to */
    922 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
    923 {
    924         TRACE_ENTRY( "%p %p", conn, alt_fifo );
    925         CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming );
    926        
    927         /* The magic function does it all */
    928         CHECK_FCT( fd_fifo_move( &conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
    929        
    930         return 0;
    931 }
    932 
    933 /* Wrapper around gnutls_record_recv to handle some error codes */
    934 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
    935 {
    936         ssize_t ret;
    937 again: 
    938         CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
    939                 {
    940                         switch (ret) {
    941                                 case GNUTLS_E_REHANDSHAKE:
    942                                         CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    943                                                 {
    944                                                         if (TRACE_BOOL(INFO)) {
    945                                                                 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
    946                                                         }
    947                                                         goto end;
    948                                                 } );
    949 
    950                                 case GNUTLS_E_AGAIN:
    951                                 case GNUTLS_E_INTERRUPTED:
    952                                         goto again;
    953 
    954                                 default:
    955                                         TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
    956                         }
    957                 } );
    958 end:   
    959         return ret;
    960 }
    961 
    962 
    963 
    964 /* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/
    965 static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len)
    966 {
    967         ssize_t ret;
    968         size_t sent = 0;
    969         TRACE_ENTRY("%p %p %zd", conn, buf, len);
    970         do {
    971                 if (conn->cc_tls) {
    972                         CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), return ENOTCONN );
    973                 } else {
    974                         CHECK_SYS( ret = send(conn->cc_socket, buf + sent, len - sent, 0) ); /* better to replace with sendmsg for atomic sending? */
    975                 }
    976                 sent += ret;
    977         } while ( sent < len );
    978         return 0;
    979 }
    980 
    981 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time, so we don't protect. */
    982 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)
    983 {
    984         TRACE_ENTRY("%p %p %zd", conn, buf, len);
    985        
    986         CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);
    987 
    988         TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, conn->cc_tls ? "TLS-protected ":"", conn->cc_id);
    989        
    990         switch (conn->cc_proto) {
    991                 case IPPROTO_TCP:
    992                         CHECK_FCT( send_simple(conn, buf, len) );
    993                         break;
    994                
    995 #ifndef DISABLE_SCTP
    996                 case IPPROTO_SCTP: {
    997                         int multistr = 0;
    998                        
    999                         if ((conn->cc_sctp_para.str_out > 1) && ((! conn->cc_tls) || (conn->cc_sctp_para.pairs > 1)))  {
    1000                                 /* Update the id of the stream we will send this message on */
    1001                                 conn->cc_sctp_para.next += 1;
    1002                                 conn->cc_sctp_para.next %= (conn->cc_tls ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
    1003                                 multistr = 1;
    1004                         }
    1005                        
    1006                         if ((!multistr) || (conn->cc_sctp_para.next == 0)) {
    1007                                 CHECK_FCT( send_simple(conn, buf, len) );
    1008                         } else {
    1009                                 if (!conn->cc_tls) {
    1010                                         CHECK_FCT( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len) );
    1011                                 } else {
    1012                                         /* push the record to the appropriate session */
    1013                                         ssize_t ret;
    1014                                         size_t sent = 0;
    1015                                         ASSERT(conn->cc_sctps_data.array != NULL);
    1016                                         do {
    1017                                                 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctps_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), return ENOTCONN );
    1018                                                 sent += ret;
    1019                                         } while ( sent < len );
    1020                                 }
    1021                         }
    1022                 }
    1023                 break;
    1024 #endif /* DISABLE_SCTP */
    1025        
    1026                 default:
    1027                         TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto);
    1028                         return ENOTSUP; /* or EINVAL... */
    1029         }
    1030        
    1031         return 0;
    1032 }
    1033 
    1034 
    1035 /**************************************/
    1036 /*     Destruction of connection      */
    1037 /**************************************/
    1038 
    1039 /* Destroy a conn structure, and shutdown the socket */
    1040 void fd_cnx_destroy(struct cnxctx * conn)
    1041 {
    1042         TRACE_ENTRY("%p", conn);
    1043        
    1044         CHECK_PARAMS_DO(conn, return);
    1045 
    1046         /* In case of TLS, stop receiver thread, then close properly the gnutls session */
    1047         if ((conn->cc_tls) && (conn->cc_sctp_para.pairs > 1)) {
    1048 #ifndef DISABLE_SCTP
    1049                 /* Multi-stream TLS: Stop all decipher threads, but not the demux thread */
    1050                 fd_sctps_stopthreads(conn);
    1051 #endif /* DISABLE_SCTP */
    1052         } else {
    1053                 /* Stop the decoding thread */
    1054                 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
    1055         }
    1056        
    1057         /* Terminate properly the TLS session(s) */
    1058         if (conn->cc_tls) {
    1059                 /* Master session */
    1060                 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */ );
    1061                 gnutls_deinit(conn->cc_tls_para.session);
    1062                
    1063 #ifndef DISABLE_SCTP
    1064                 if (conn->cc_sctp_para.pairs > 1) {
    1065                         /* Multi-stream TLS: destroy the wrapper and stop the demux thread */
    1066                         fd_sctps_destroy(conn);
    1067                 }
    1068 #endif /* DISABLE_SCTP */
    1069                
    1070         }
    1071        
    1072         /* Shut the connection down */
    1073         if (conn->cc_socket > 0) {
    1074                 shutdown(conn->cc_socket, SHUT_RDWR);
    1075         }
    1076        
    1077         /* Empty and destroy FIFO list */
    1078         if (conn->cc_incoming) {
    1079                 fd_event_destroy( &conn->cc_incoming, free );
    1080         }
    1081        
    1082         /* Free the object */
    1083         free(conn);
    1084        
    1085         /* Done! */
    1086         return;
    1087 }
  • freeDiameter/config.c

    r24 r20  
    100100                        struct fd_endpoint * ep = (struct fd_endpoint *)li;
    101101                        if (li != fd_g_config->cnf_endpoints.next) fd_log_debug("                             ");
    102                         sSA_DUMP_NODE( &ep->sa, NI_NUMERICHOST );
     102                        sSA_DUMP_NODE( &ep->ss, NI_NUMERICHOST );
    103103                        fd_log_debug("\n");
    104104                        li = li->next;
     
    229229        }
    230230       
    231         /* Validate local endpoints */
    232         if ((!FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) {
    233                 struct fd_list * li;
    234                 for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
    235                         struct fd_endpoint * ep = (struct fd_endpoint *)li;
    236                         if ( (fd_g_config->cnf_flags.no_ip4 && (ep->sa.sa_family == AF_INET))
    237                            ||(fd_g_config->cnf_flags.no_ip6 && (ep->sa.sa_family == AF_INET6)) ) {
    238                                 li = li->prev;
    239                                 fd_list_unlink(&ep->chain);
    240                                 if (TRACE_BOOL(INFO)) {
    241                                         fd_log_debug("Info: Removing local address conflicting with the flags no_IP / no_IP6 : ");
    242                                         sSA_DUMP_NODE( &ep->sa, AI_NUMERICHOST );
    243                                         fd_log_debug("\n");
    244                                 }
    245                                 free(ep);
    246                         }
    247                 }
    248         }
    249        
    250231        /* Configure TLS default parameters */
    251232        if (! fd_g_config->cnf_sec_data.prio_string) {
     
    258239        }
    259240        if (! fd_g_config->cnf_sec_data.dh_bits) {
    260                 if (TRACE_BOOL(INFO)) {
    261                         fd_log_debug("Generating Diffie-Hellman parameters of size %d (this takes a few seconds)... ", GNUTLS_DEFAULT_DHBITS);
    262                 }
     241                TRACE_DEBUG(FULL, "Generating DH parameters...");
    263242                CHECK_GNUTLS_DO( gnutls_dh_params_generate2(
    264243                                        fd_g_config->cnf_sec_data.dh_cache,
    265244                                        GNUTLS_DEFAULT_DHBITS),
    266245                                 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
    267                 if (TRACE_BOOL(INFO)) {
    268                         fd_log_debug("Done!\n");
    269                 }
    270         }
     246                TRACE_DEBUG(FULL, "DH parameters generated.");
     247        }
     248       
    271249       
    272250        return 0;
  • freeDiameter/fD.h

    r29 r20  
    152152enum {
    153153        /* Dump all info about this peer in the debug log */
    154          FDEVP_DUMP_ALL = 1500
     154         FDEVP_DUMP_ALL = 2000
    155155       
    156156        /* request to terminate this peer : disconnect, requeue all messages */
    157157        ,FDEVP_TERMINATE
    158158       
    159         /* A connection object has received a message. (data contains the buffer) */
    160         ,FDEVP_CNX_MSG_RECV
    161                          
    162         /* A connection object has encountered an error (disconnected). */
    163         ,FDEVP_CNX_ERROR
    164        
    165         /* Endpoints of a connection have been changed (multihomed SCTP). */
    166         ,FDEVP_CNX_EP_CHANGE
    167        
    168         /* A new connection has been established (data contains the appropriate info) */
    169         ,FDEVP_CNX_INCOMING
     159        /* A message was received in the peer */
     160        ,FDEVP_MSG_INCOMING
    170161       
    171162        /* The PSM state is expired */
    172163        ,FDEVP_PSM_TIMEOUT
    173        
    174164};
    175165const char * fd_pev_str(int event);
    176166#define CHECK_EVENT( _e ) \
    177167        (((int)(_e) >= FDEVP_DUMP_ALL) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
    178 
    179 /* The data structure for FDEVP_CNX_INCOMING events */
    180 struct cnx_incoming {
    181         struct msg      * cer;          /* the CER message received on this connection */
    182         struct cnxctx   * cnx;          /* The connection context */
    183         int               validate;     /* The peer is new, it must be validated (by an extension) or error CEA to be sent */
    184 };
    185168
    186169/* Structure to store a sent request */
     
    190173};
    191174
     175/* The connection context structure */
     176struct cnxctx {
     177        int             cc_socket;      /* The socket object of the connection -- <=0 if no socket is created */
     178       
     179        struct fifo   **cc_events;      /* Location of the events list to send connection events */
     180       
     181        int             cc_proto;       /* IPPROTO_TCP or IPPROTO_SCTP */
     182        int             cc_tls;         /* Is TLS already started ? */
     183       
     184        uint16_t        cc_port;        /* Remote port of the connection, when we are client */
     185        struct fd_list  cc_ep_remote;   /* The remote address(es) of the connection */
     186        struct fd_list  cc_ep_local;    /* The local address(es) of the connection */
     187       
     188        /* If cc_proto == SCTP */
     189        struct  {
     190                int             str_out;/* Out streams */
     191                int             str_in; /* In streams */
     192                int             pairs;  /* max number of pairs ( = min(in, out)) */
     193                int             next;   /* # of stream the next message will be sent to */
     194        }               cc_sctp_para;
     195       
     196        /* If cc_tls == true */
     197        struct {
     198                int                              mode;          /* GNUTLS_CLIENT / GNUTLS_SERVER */
     199                gnutls_session_t                 session;       /* Session object (stream #0 in case of SCTP) */
     200        }               cc_tls_para;
     201       
     202        /* If both conditions */
     203        struct {
     204                gnutls_session_t                *res_sessions;  /* Sessions of other pairs of streams, resumed from the first */
     205                /* Buffers, threads, ... */
     206        }               cc_sctp_tls_para;
     207};
    192208
    193209/* Functions */
    194 int  fd_peer_fini();
     210int fd_peer_fini();
    195211void fd_peer_dump_list(int details);
    196212void fd_peer_dump(struct fd_peer * peer, int details);
    197 int  fd_peer_alloc(struct fd_peer ** ptr);
    198 int  fd_peer_free(struct fd_peer ** ptr);
    199 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx );
     213int fd_peer_alloc(struct fd_peer ** ptr);
     214int fd_peer_free(struct fd_peer ** ptr);
    200215/* fd_peer_add declared in freeDiameter.h */
    201 int fd_peer_validate( struct fd_peer * peer );
    202216
    203217/* Peer expiry */
     
    207221
    208222/* Peer state machine */
    209 int  fd_psm_start();
    210 int  fd_psm_begin(struct fd_peer * peer );
    211 int  fd_psm_terminate(struct fd_peer * peer );
     223int fd_psm_start();
     224int fd_psm_begin(struct fd_peer * peer );
     225int fd_psm_terminate(struct fd_peer * peer );
    212226void fd_psm_abord(struct fd_peer * peer );
    213227
    214228/* Server sockets */
    215229void fd_servers_dump();
    216 int  fd_servers_start();
    217 int  fd_servers_stop();
    218 
    219 /* Connection contexts -- there are also definitions in cnxctx.h for the relevant files */
    220 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep);
    221 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list);
    222 int             fd_cnx_serv_listen(struct cnxctx * conn);
    223 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv);
    224 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
    225 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
    226 int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
    227 int             fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds);
    228 char *          fd_cnx_getid(struct cnxctx * conn);
    229 int             fd_cnx_getproto(struct cnxctx * conn);
    230 int             fd_cnx_getTLS(struct cnxctx * conn);
    231 int             fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
    232 int             fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote);
    233 char *          fd_cnx_getremoteid(struct cnxctx * conn);
    234 int             fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len);
    235 int             fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */
    236 int             fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len);
    237 void            fd_cnx_destroy(struct cnxctx * conn);
     230int fd_servers_start();
     231void fd_servers_stop();
     232
     233/* Connection contexts */
     234struct cnxctx * fd_cnx_init(int sock, int proto);
     235int fd_cnx_handshake(struct cnxctx * conn, int mode);
     236
     237/* SCTP */
     238#ifndef DISABLE_SCTP
     239int fd_sctp_create_bind_server( int * socket, uint16_t port );
     240int fd_sctp_get_str_info( int socket, int *in, int *out );
     241
     242#endif /* DISABLE_SCTP */
     243
    238244
    239245
  • freeDiameter/fdd.y

    r24 r20  
    212212listenon:               LISTENON '=' QSTRING ';'
    213213                        {
     214                                struct fd_endpoint * ep;
    214215                                struct addrinfo hints, *ai;
    215216                                int ret;
     217                               
     218                                CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)),
     219                                        { yyerror (&yylloc, conf, "Out of memory"); YYERROR; } );
     220                                memset(ep, 0, sizeof(struct fd_endpoint));
     221                                fd_list_init(&ep->chain, NULL);
     222                                ep->meta.conf = 1;
    216223                               
    217224                                memset(&hints, 0, sizeof(hints));
    218225                                hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
    219226                                ret = getaddrinfo($3, NULL, &hints, &ai);
    220                                 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
    221                                 CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF ), YYERROR );
     227                                if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; }
     228                                ASSERT( ai->ai_addrlen <= sizeof(sSS) );
     229                                memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);
     230                                free($3);
    222231                                freeaddrinfo(ai);
    223                                 free($3);
     232                                fd_list_insert_before(&conf->cnf_endpoints, &ep->chain);
    224233                        }
    225234                        ;
     
    327336                                /* Now destroy any content in the structure */
    328337                                free(fddpi.pi_diamid);
    329                                 free(fddpi.pi_sec_data.priority);
    330338                                while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) {
    331339                                        struct fd_list * li = fddpi.pi_endpoints.next;
     
    407415                                fddpi.pi_port = (uint16_t)$4;
    408416                        }
     417                        | peerparams SCTPSTREAMS '=' INTEGER ';'
     418                        {
     419                                CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16),
     420                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
     421                                fddpi.pi_streams = (uint16_t)$4;
     422                        }
    409423                        | peerparams TCTIMER '=' INTEGER ';'
    410424                        {
    411425                                fddpi.pi_tctimer = $4;
    412426                        }
    413                         | peerparams TLS_PRIO '=' QSTRING ';'
    414                         {
    415                                 fddpi.pi_sec_data.priority = $4;
    416                         }
    417427                        | peerparams TWTIMER '=' INTEGER ';'
    418428                        {
     
    421431                        | peerparams CONNTO '=' QSTRING ';'
    422432                        {
     433                                struct fd_endpoint * ep;
    423434                                struct addrinfo hints, *ai;
    424435                                int ret;
    425                                 int disc = 0;
    426436                               
     437                                CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)),
     438                                        { yyerror (&yylloc, conf, "Out of memory"); YYERROR; } );
     439                                memset(ep, 0, sizeof(struct fd_endpoint));
     440                                fd_list_init(&ep->chain, NULL);
     441                                ep->meta.conf = 1;
    427442                                memset(&hints, 0, sizeof(hints));
    428443                                hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
     
    430445                                if (ret == EAI_NONAME) {
    431446                                        /* The name was maybe not numeric, try again */
    432                                         disc = EP_FL_DISC;
     447                                        ep->meta.disc = 1;
    433448                                        hints.ai_flags &= ~ AI_NUMERICHOST;
    434449                                        ret = getaddrinfo($4, NULL, &hints, &ai);
    435450                                }
    436                                 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
     451                                if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; }
    437452                               
    438                                 CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | disc ), YYERROR );
     453                                memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);
    439454                                free($4);
    440455                                freeaddrinfo(ai);
     456                                fd_list_insert_before(&fddpi.pi_endpoints, &ep->chain);
    441457                        }
    442458                        ;
  • freeDiameter/main.c

    r25 r20  
    5151struct fd_config * fd_g_config = &conf;
    5252
    53 /* gcrypt functions to support posix threads */
    5453GCRY_THREAD_OPTION_PTHREAD_IMPL;
    5554
     
    106105        CHECK_FCT(  fd_ext_load()  );
    107106       
    108         fd_conf_dump();
    109        
    110         /* Start the servers */
    111         CHECK_FCT( fd_servers_start() );
    112        
    113107        /* Start the peer state machines */
    114108        CHECK_FCT( fd_psm_start() );
     
    116110        /* Now, just wait for events */
    117111        TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
     112        fd_conf_dump();
    118113        while (1) {
    119                 int code; size_t sz; void * data;
    120                 CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data),  break  );
     114                int code;
     115                CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, NULL),  break  );
    121116                switch (code) {
    122117                        case FDEV_DUMP_DICT:
     
    159154       
    160155        /* cleanups */
    161         CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );
    162156        TODO("Stop dispatch thread(s) properly (no cancel yet)");
    163157        CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
     
    339333       
    340334        TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig);
    341         CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) );
     335        CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) );
    342336        return NULL;
    343337}
  • freeDiameter/p_expiry.c

    r25 r16  
    4747static void * gc_th_fct(void * arg)
    4848{
    49         fd_log_threadname ( "Peers/garb. col." );
    50         TRACE_ENTRY( "%p", arg );
     49        fd_log_threadname ( "Peers/garbage" );
     50        TRACE_ENTRY( "" );
    5151       
    5252        do {
    5353                struct fd_list * li, purge = FD_LIST_INITIALIZER(purge);
    5454               
    55                 sleep(GC_TIME); /* sleep is a cancellation point */
     55                pthread_testcancel();
     56                sleep(GC_TIME);
    5657               
    5758                /* Now check in the peers list if any peer can be deleted */
     
    8788        TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating...");
    8889        ASSERT(0);
    89         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
     90        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
    9091        return NULL;
    9192}
     
    9596{
    9697        fd_log_threadname ( "Peers/expire" );
    97         TRACE_ENTRY( "%p", arg );
     98        TRACE_ENTRY( "" );
    9899       
    99100        CHECK_POSIX_DO( pthread_mutex_lock(&exp_mtx),  goto error );
     
    123124                       
    124125                        CHECK_POSIX_DO2(  pthread_cond_timedwait( &exp_cnd, &exp_mtx, &first->p_exp_timer ), 
    125                                         ETIMEDOUT, /* ETIMEDOUT is a normal return value, continue */,
     126                                        ETIMEDOUT, /* ETIMEDOUT is a normal error, continue */,
    126127                                        /* on other error, */ goto error );
    127128       
     
    132133                /* Now, the first peer in the list is expired; signal it */
    133134                fd_list_unlink( &first->p_expiry );
    134                 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, NULL), goto error );
     135                CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, NULL), goto error );
    135136               
    136137        } while (1);
     
    140141        TRACE_DEBUG(INFO, "An error occurred in peers module! Expiry thread is terminating...");
    141142        ASSERT(0);
    142         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
     143        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
    143144        return NULL;
    144145}
  • freeDiameter/p_psm.c

    r29 r20  
    5555        #define case_str( _val )\
    5656                case _val : return #_val
     57                case_str(FDEVP_TERMINATE);
    5758                case_str(FDEVP_DUMP_ALL);
    58                 case_str(FDEVP_TERMINATE);
    59                 case_str(FDEVP_CNX_MSG_RECV);
    60                 case_str(FDEVP_CNX_ERROR);
    61                 case_str(FDEVP_CNX_EP_CHANGE);
    62                 case_str(FDEVP_CNX_INCOMING);
     59                case_str(FDEVP_MSG_INCOMING);
    6360                case_str(FDEVP_PSM_TIMEOUT);
    6461               
     
    128125}
    129126
     127/* Wait for the next event in the PSM, or timeout */
     128static int psm_ev_timedget(struct fd_peer * peer, int *code, void ** data)
     129{
     130        struct fd_event * ev;
     131        int ret = 0;
     132       
     133        TRACE_ENTRY("%p %p %p", peer, code, data);
     134       
     135        ret = fd_fifo_timedget(peer->p_events, &ev, &peer->p_psm_timer);
     136        if (ret == ETIMEDOUT) {
     137                *code = FDEVP_PSM_TIMEOUT;
     138                *data = NULL;
     139        } else {
     140                CHECK_FCT( ret );
     141                *code = ev->code;
     142                *data = ev->data;
     143                free(ev);
     144        }
     145       
     146        return 0;
     147}
     148
    130149/* The state machine thread (controler) */
    131150static void * p_psm_th( void * arg )
     
    134153        int created_started = started;
    135154        int event;
    136         size_t ev_sz;
    137155        void * ev_data;
    138156       
     
    163181psm_loop:
    164182        /* Get next event */
    165         CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
    166         TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'",
     183        CHECK_FCT_DO( psm_ev_timedget(peer, &event, &ev_data), goto psm_end );
     184        TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p)\t'%s'",
    167185                        STATE_STR(peer->p_hdr.info.pi_state),
    168                         fd_pev_str(event), ev_data, ev_sz,
     186                        fd_pev_str(event), ev_data,
    169187                        peer->p_hdr.info.pi_diamid);
    170188
     
    209227        }
    210228       
    211         /* A new connection was established and CER containing this peer id was received */
    212         if (event == FDEVP_CNX_INCOMING) {
    213                 struct cnx_incoming * params = ev_data;
    214                 ASSERT(params);
    215                
    216                 switch (peer->p_hdr.info.pi_state) {
    217                         case STATE_CLOSED:
    218                                 TODO("Handle the CER, validate the peer if needed (and set expiry), set the alt_fifo in the connection, reply a CEA, eventually handshake, move to OPEN or REOPEN state");
    219                                 break;
    220                                
    221                         case STATE_WAITCNXACK:
    222                         case STATE_WAITCEA:
    223                                 TODO("Election");
    224                                 break;
    225                                
    226                         default:
    227                                 TODO("Reply with error CEA");
    228                                 TODO("Close the connection");
    229                                 /* reject_incoming_connection */
    230                        
    231                 }
    232                
    233                 free(ev_data);
    234                 goto psm_loop;
    235         }
    236        
    237229        /* MSG_RECEIVED: fd_p_expi_update(struct fd_peer * peer ) */
    238230        /* If timeout or OPEN : call cb if defined */
     
    249241psm_end:
    250242        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
    251         peer->p_psm = (pthread_t)NULL;
    252         pthread_detach(pthread_self());
    253243        return NULL;
    254244}       
     245       
     246       
     247
    255248
    256249/* Create the PSM thread of one peer structure */
     
    274267        TRACE_ENTRY("%p", peer);
    275268        CHECK_PARAMS( CHECK_PEER(peer) );
    276        
    277269        if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) {
    278                 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
     270                CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) );
    279271        } else {
    280272                TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
  • freeDiameter/peers.c

    r29 r20  
    101101       
    102102        p->p_hdr.info.pi_lft     = info->pi_lft;
     103        p->p_hdr.info.pi_streams = info->pi_streams;
    103104        p->p_hdr.info.pi_port    = info->pi_port;
    104105        p->p_hdr.info.pi_tctimer = info->pi_tctimer;
    105106        p->p_hdr.info.pi_twtimer = info->pi_twtimer;
    106        
    107         if (info->pi_sec_data.priority) {
    108                 CHECK_MALLOC( p->p_hdr.info.pi_sec_data.priority = strdup(info->pi_sec_data.priority) );
    109         }
    110107       
    111108        /* Move the items from one list to the other */
     
    117114                }
    118115       
    119        
    120116        /* The internal data */
    121117        if (orig_dbg) {
     
    131127       
    132128        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    133                 struct fd_peer * next = (struct fd_peer *)li;
    134                 int cmp = strcasecmp( p->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamid );
    135                 if (cmp > 0)
     129                struct fd_peer * prev = (struct fd_peer *)li;
     130                int cmp = strcasecmp( p->p_hdr.info.pi_diamid, prev->p_hdr.info.pi_diamid );
     131                if (cmp < 0)
    136132                        continue;
    137133                if (cmp == 0)
     
    233229       
    234230        if (p->p_cnxctx) {
    235                 fd_cnx_destroy(p->p_cnxctx);
     231                TODO("destroy p->p_cnxctx");
    236232        }
    237233       
     
    297293                list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
    298294                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
    299                 CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
    300295        }
    301296       
     
    375370}
    376371
    377 /* Handle an incoming CER request on a new connection */
    378 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx )
    379 {
    380         struct msg * msg;
    381         struct dict_object *avp_oh_model;
    382         avp_code_t code = AC_ORIGIN_HOST;
    383         struct avp *avp_oh;
    384         struct avp_hdr * avp_hdr;
    385         struct fd_list * li;
    386         int found = 0;
    387         int ret = 0;
    388         struct fd_peer * peer;
    389         struct cnx_incoming * ev_data;
    390        
    391         TRACE_ENTRY("%p %p", cer, cnx);
    392         CHECK_PARAMS(cer && *cer && cnx && *cnx);
    393        
    394         msg = *cer;
    395        
    396         /* Find the Diameter Identity of the remote peer in the message */
    397         CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT) );
    398         CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );
    399         CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );
    400        
    401         /* Search if we already have this peer id in our list */
    402         CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );
    403        
    404         for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    405                 peer = (struct fd_peer *)li;
    406                 int cmp = strncasecmp( avp_hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.len );
    407                 if (cmp > 0)
    408                         continue;
    409                 if (cmp == 0)
    410                         found = 1;
    411                 break;
    412         }
    413        
    414         if (!found) {
    415                 /* Create a new peer entry for this new remote peer */
    416                 peer = NULL;
    417                 CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out );
    418                
    419                 /* Set the peer Diameter Id and the responder flag parameters */
    420                 CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = malloc(avp_hdr->avp_value->os.len + 1), { ret = ENOMEM; goto out; } );
    421                 CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
    422                 peer->p_flags.pf_responder = 1;
    423                
    424                 /* Upgrade the lock to write lock */
    425                 CHECK_POSIX_DO( ret = pthread_rwlock_wrlock(&fd_g_peers_rw), goto out );
    426                
    427                 /* Insert the new peer in the list (the PSM will take care of setting the expiry after validation) */
    428                 fd_list_insert_before( li, &peer->p_hdr.chain );
    429                
    430                 /* Release the write lock */
    431                 CHECK_POSIX_DO( ret = pthread_rwlock_unlock(&fd_g_peers_rw), goto out );
    432                
    433                 /* Start the PSM, which will receive the event bellow */
    434                 CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
    435         }
    436                
    437         /* Send the new connection event to the PSM */
    438         CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
    439         memset(ev_data, 0, sizeof(ev_data));
    440        
    441         ev_data->cer = msg;
    442         ev_data->cnx = *cnx;
    443         ev_data->validate = !found;
    444        
    445         CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(ev_data), ev_data), goto out );
    446        
    447 out:   
    448         CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
    449 
    450         if (ret == 0) {
    451                 /* Reset the "out" parameters, so that they are not cleanup on function return. */
    452                 *cer = NULL;
    453                 *cnx = NULL;
    454         }
    455        
    456         return ret;
    457 }
    458 
    459 /* Save a callback to accept / reject incoming unknown peers */
    460 int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) )
    461 {
    462        
    463         TODO("...");
    464         return ENOTSUP;
    465 }
    466 
    467 /* Validate a peer by calling the callbacks in turn -- return 0 if the peer is validated, ! 0 in case of error or if the peer is rejected */
    468 int fd_peer_validate( struct fd_peer * peer )
    469 {
    470         TODO("Default to reject");
    471         TODO("Call all callbacks in turn");
    472         TODO("Save cb2 in the peer if needed");
    473         return ENOTSUP;
    474 }
  • 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 }
  • freeDiameter/server.c

    r29 r20  
    3636#include "fD.h"
    3737
    38 /* Server (listening) part of the daemon */
    39 
    40 struct fd_list          FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS);   /* The list of all server objects */
    41 /* We don't need to protect this list, it is only accessed from the main daemon thread. */
    42 
    43 /* Servers information */
     38/* This file contains the server (listening) part of the daemon */
     39
     40struct fd_list          FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS);   /* The list of all server sockets */
     41/* We don't need to protect this list, it is only accessed from the main thread. */
     42
     43/* Server (listening socket) information */
    4444struct server {
    4545        struct fd_list  chain;          /* link in the FD_SERVERS list */
    4646
    47         struct cnxctx * conn;           /* server connection context (listening socket) */
     47        int             socket;         /* server socket, or <= 0 */
     48       
    4849        int             proto;          /* IPPROTO_TCP or IPPROTO_SCTP */
    4950        int             secur;          /* TLS is started immediatly after connection ? */
    5051       
    51         pthread_t       thr;            /* The thread listening for new connections */
    52         int             status;         /* 0 : not created; 1 : running; 2 : terminated */
    53        
    54         struct fd_list  clients;        /* List of clients connected to this server, not yet identified */
    55         pthread_mutex_t clients_mtx;    /* Mutex to protect the list of clients */
     52        pthread_t       serv_thr;       /* The thread listening for new connections */
     53        int             serv_status;    /* 0 : not created; 1 : running; 2 : terminated */
     54       
     55        pthread_mutex_t clients_mtx;    /* Mutex to protect the list of clients connected to the thread */
     56        struct fd_list  clients;        /* The list of clients connecting to this server, which information is not yet known */
     57       
     58        char *          serv_name;      /* A string to identify this server */
    5659};
    5760
    58 /* Client information (connecting peer for which we don't have the CER yet) */
     61/* Client (connected remote endpoint, not received CER yet) information */
    5962struct client {
    6063        struct fd_list   chain; /* link in the server's list of clients */
    61         struct cnxctx   *conn;  /* Parameters of the connection */
    62         struct timespec  ts;    /* Deadline for receiving CER (after INCNX_TIMEOUT) */
    63         pthread_t        thr;   /* connection state machine */
     64       
     65        struct cnxctx   *conn;  /* Parameters of the connection; sends its events to the ev fifo bellow */
     66       
     67        struct timespec  ts;    /* Delay for receiving CER: INCNX_TIMEOUT */
     68        struct fifo     *ev;    /* Events of the connection -- allowed: TIMEOUT, ERROR (cnx, tls), MSG_RCV (CER, other=>error) */
     69       
     70        pthread_t        cli_thr; /* connection state machine (simplified PSM) */
    6471};
    6572
    66 
    67 /* Dump all servers information */
    68 void fd_servers_dump()
    69 {
    70         struct fd_list * li, *cli;
    71        
    72         fd_log_debug("Dumping servers list :\n");
    73         for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) {
    74                 struct server * s = (struct server *)li;
    75                 fd_log_debug("  Serv %p '%s': %s, %s, %s\n",
    76                                 s, fd_cnx_getid(s->conn),
    77                                 IPPROTO_NAME( s->proto ),
    78                                 s->secur ? "Secur" : "NotSecur",
    79                                 (s->status == 0) ? "Thread not created" :
    80                                 ((s->status == 1) ? "Thread running" :
    81                                 ((s->status == 2) ? "Thread terminated" :
    82                                                           "Thread status unknown")));
    83                 /* Dump the client list of this server */
    84                 (void) pthread_mutex_lock(&s->clients_mtx);
    85                 for (cli = s->clients.next; cli != &s->clients; cli = cli->next) {
    86                         struct client * c = (struct client *)cli;
    87                         char bufts[128];
    88                         fd_log_debug("     Connected: '%s' (timeout: %s)\n",
    89                                         fd_cnx_getid(c->conn),
    90                                         fd_log_time(&c->ts, bufts, sizeof(bufts)));
     73/* Parameter for the thread handling the new connected client, to avoid bloking the server thread */
     74struct cli_fast {
     75        struct server * serv;
     76        int             sock;
     77        sSS             ss;
     78        socklen_t       sslen;
     79};
     80
     81
     82/* This thread is called when a new client had just connected */
     83static void * handle_client_fast(void * arg)
     84{
     85        struct cli_fast * cf = arg;
     86        struct client * c = NULL;
     87       
     88        /* Name the current thread */
     89        ASSERT(arg);
     90        {
     91                char addr[128];
     92                int offset = snprintf(addr, sizeof(addr), "Srv %d/Cli %d : ", cf->serv->socket, cf->sock);
     93                int rc = getnameinfo((sSA *)&cf->ss, sizeof(sSS), addr + offset, sizeof(addr) - offset, NULL, 0, 0);
     94                if (rc)
     95                        memcpy(addr + offset, gai_strerror(rc), sizeof(addr) - offset);
     96               
     97                if (TRACE_BOOL(INFO)) {
     98                        fd_log_debug( "New connection %s, sock %d, from '%s'\n", cf->serv->serv_name, cf->sock, addr + offset);
    9199                }
    92                 (void) pthread_mutex_unlock(&s->clients_mtx);
    93         }
    94 }
    95 
    96 
    97 /* The state machine to handle incoming connection before the remote peer is identified */
    98 static void * client_sm(void * arg)
    99 {
    100         struct client * c = arg;
    101         struct server * s = NULL;
    102         uint8_t       * buf = NULL;
    103         size_t          bufsz;
    104         struct msg    * msg = NULL;
    105         struct msg_hdr *hdr = NULL;
    106        
    107         TRACE_ENTRY("%p", c);
    108        
    109         CHECK_PARAMS_DO(c && c->conn && c->chain.head, goto fatal_error );
    110        
    111         s = c->chain.head->o;
    112        
    113         /* Name the current thread */
    114         fd_log_threadname ( fd_cnx_getid(c->conn) );
    115        
    116         /* Handshake if we are a secure server port, or start clear otherwise */
    117         if (s->secur) {
    118                 int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, NULL, NULL);
    119                 if (ret != 0) {
    120                         if (TRACE_BOOL(INFO)) {
    121                                 fd_log_debug("TLS handshake failed for client '%s', connection aborted.\n", fd_cnx_getid(c->conn));
    122                         }
    123                         goto cleanup;
    124                 }
    125         } else {
    126                 CHECK_FCT_DO( fd_cnx_start_clear(c->conn, 0), goto cleanup );
    127         }
    128        
    129         /* Set the timeout to receive the first message */
    130         CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &c->ts), goto fatal_error );
    131         c->ts.tv_sec += INCNX_TIMEOUT;
    132        
    133         /* Receive the first Diameter message on the connection -- cleanup in case of timeout */
    134         CHECK_FCT_DO( fd_cnx_receive(c->conn, &c->ts, &buf, &bufsz), goto cleanup );
    135        
    136         TRACE_DEBUG(FULL, "Received %zdb from new client '%s'", bufsz, fd_cnx_getid(c->conn));
    137        
    138         /* Try parsing this message */
    139         CHECK_FCT_DO( fd_msg_parse_buffer( &buf, bufsz, &msg ), /* Parsing failed */ goto cleanup );
    140        
    141         /* We expect a CER, it must parse with our dictionary and rules */
    142         CHECK_FCT_DO( fd_msg_parse_rules( msg, fd_g_config->cnf_dict, NULL ), /* Parsing failed -- trace details ? */ goto cleanup );
    143        
    144         if (TRACE_BOOL(FULL)) {
    145                 fd_log_debug("Received Diameter message from new client '%s':\n", fd_cnx_getid(c->conn));
    146                 fd_msg_dump_walk(FULL, msg);
    147         }
    148        
    149         /* Now check we received a CER */
    150         CHECK_FCT_DO( fd_msg_hdr ( msg, &hdr ), goto fatal_error );
    151         CHECK_PARAMS_DO( (hdr->msg_appl == 0) && (hdr->msg_flags & CMD_FLAG_REQUEST) && (hdr->msg_code == CC_CAPABILITIES_EXCHANGE),
    152                 { fd_log_debug("Connection '%s', expecting CER, received something else, closing...\n", fd_cnx_getid(c->conn)); goto cleanup; } );
    153        
    154         /* Finally, pass the information to the peers module which will handle it next */
    155         pthread_cleanup_push((void *)fd_cnx_destroy, c->conn);
    156         pthread_cleanup_push((void *)fd_msg_free, msg);
    157         CHECK_FCT_DO( fd_peer_handle_newCER( &msg, &c->conn ), goto cleanup );
    158         pthread_cleanup_pop(0);
    159         pthread_cleanup_pop(0);
    160        
    161         /* The end, we cleanup the client structure */
    162 cleanup:
    163         /* Unlink the client structure */
    164         CHECK_POSIX_DO( pthread_mutex_lock(&s->clients_mtx), goto fatal_error );
    165         fd_list_unlink( &c->chain );
    166         CHECK_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), goto fatal_error );
    167        
    168         /* Destroy the connection object if present */
    169         if (c->conn)
    170                 fd_cnx_destroy(c->conn);
    171        
    172         /* Cleanup the received buffer if any */
    173         free(buf);
    174        
    175         /* Cleanup the parsed message if any */
    176         if (msg) {
    177                 CHECK_FCT_DO( fd_msg_free(msg), /* continue */);
    178         }
    179        
    180         /* Detach the thread, cleanup the client structure */
     100       
     101                fd_log_threadname ( addr );
     102        }
     103       
     104        /* Create a client structure */
     105        CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto early_error );
     106        memset(c, 0, sizeof(struct client));
     107        fd_list_init(&c->chain, c);
     108        c->cli_thr = pthread_self();
     109       
     110        /* Create the connection context */
     111        CHECK_MALLOC_DO( c->conn = fd_cnx_init(cf->sock, cf->serv->proto), goto early_error );
     112       
     113        /* In case we are a secure server, handshake now */
     114        if (cf->serv->secur) {
     115               
     116                TODO("Continue");
     117        }
     118       
     119        /* Save the client in the list */
     120        CHECK_POSIX_DO( pthread_mutex_lock( &cf->serv->clients_mtx ), goto early_error );
     121        fd_list_insert_before(&cf->serv->clients, &c->chain);
     122        CHECK_POSIX_DO( pthread_mutex_unlock( &cf->serv->clients_mtx ), goto error );
     123       
     124       
     125       
     126       
     127early_error:
     128        TRACE_DEBUG(INFO, "Thread is detaching to die");
    181129        pthread_detach(pthread_self());
     130        shutdown(cf->sock, SHUT_RDWR);
     131        free(cf);
    182132        free(c);
     133error: 
     134        TRACE_DEBUG(INFO, "Thread is terminating");
     135        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
    183136        return NULL;
    184        
    185 fatal_error:    /* This has effect to terminate the daemon */
    186         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
    187         return NULL;
    188 }
    189 
    190 /* The thread managing a server */
     137}
     138
     139/* The thread for the server */
    191140static void * serv_th(void * arg)
    192141{
    193         struct server *s = (struct server *)arg;
    194        
    195         CHECK_PARAMS_DO(s, goto error);
    196         fd_log_threadname ( fd_cnx_getid(s->conn) );
    197         s->status = 1;
     142        struct server *sv = (struct server *)arg;
     143        struct cli_fast cf;
     144       
     145        CHECK_PARAMS_DO(sv, goto error);
     146        fd_log_threadname ( sv->serv_name );
     147        sv->serv_status = 1;
     148       
     149        memset(&cf, 0, sizeof(struct cli_fast));
     150        cf.serv = sv;
     151       
    198152       
    199153        /* Accept incoming connections */
    200         CHECK_FCT_DO( fd_cnx_serv_listen(s->conn), goto error );
     154        CHECK_SYS_DO(  listen(sv->socket, 5), goto error );
    201155       
    202156        do {
    203                 struct client * c = NULL;
    204                 struct cnxctx * conn = NULL;
     157                struct cli_fast * ncf;
     158                pthread_t         thr;
     159               
     160                /* Re-init socket size */
     161                cf.sslen = sizeof(sSS);
    205162               
    206163                /* Wait for a new client */
    207                 CHECK_MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), goto error );
     164                CHECK_SYS_DO( cf.sock = accept(sv->socket, (sSA *)&cf.ss, &cf.sslen), goto error );
    208165               
    209166                TRACE_DEBUG(FULL, "New connection accepted");
    210167               
    211                 /* Create a client structure */
    212                 CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto error );
    213                 memset(c, 0, sizeof(struct client));
    214                 fd_list_init(&c->chain, c);
    215                 c->conn = conn;
    216                
    217                 /* Save the client in the list */
    218                 CHECK_POSIX_DO( pthread_mutex_lock( &s->clients_mtx ), goto error );
    219                 fd_list_insert_before(&s->clients, &c->chain);
    220                 CHECK_POSIX_DO( pthread_mutex_unlock( &s->clients_mtx ), goto error );
    221 
    222                 /* Start the client thread */
    223                 CHECK_POSIX_DO( pthread_create( &c->thr, NULL, client_sm, c ), goto error );
     168                /* Create the copy for the client thread */
     169                CHECK_MALLOC_DO( ncf = malloc(sizeof(struct cli_fast)), goto error );
     170                memcpy(ncf, &cf, sizeof(struct cli_fast));
     171               
     172                /* Create the thread to handle the new incoming connection */
     173                CHECK_POSIX_DO( pthread_create( &thr /* we don't use it, but NULL is not standard */, NULL, handle_client_fast, ncf), goto error );
    224174               
    225175        } while (1);
    226176       
    227177error: 
    228         if (s)
    229                 s->status = 2;
     178        if (sv)
     179                sv->serv_status = 2;
    230180        /* Send error signal to the daemon */
    231181        TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating...");
    232         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
     182        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
    233183
    234184        return NULL;
     
    237187
    238188/* Create a new server structure */
    239 static struct server * new_serv( int proto, int secur )
    240 {
     189static struct server * new_serv( int proto, int secur, int socket )
     190{
     191        char buf[32];
     192        char * sn = NULL;
    241193        struct server * new;
     194       
     195        /* Create the server debug name */
     196        buf[sizeof(buf) - 1] = '\0';
     197        snprintf(buf, sizeof(buf) - 1, "Serv %d (%s%s)", socket, IPPROTO_NAME( proto ), secur ? "s" : "");
     198        CHECK_MALLOC_DO( sn = strdup(buf), return NULL );
    242199       
    243200        /* New server structure */
     
    246203        memset(new, 0, sizeof(struct server));
    247204        fd_list_init(&new->chain, new);
     205        new->socket = socket;
    248206        new->proto = proto;
    249207        new->secur = secur;
     
    251209        fd_list_init(&new->clients, new);
    252210       
     211        new->serv_name = sn;
     212       
    253213        return new;
     214}
     215
     216/* Dump all servers information */
     217void fd_servers_dump()
     218{
     219        struct fd_list * li;
     220       
     221        fd_log_debug("Dumping servers list :\n");
     222        for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) {
     223                struct server * sv = (struct server *)li;
     224                fd_log_debug("  Serv '%s': %s(%d), %s, %s, %s\n",
     225                                sv->serv_name,
     226                                (sv->socket > 0) ? "Open" : "Closed", sv->socket,
     227                                IPPROTO_NAME( sv->proto ),
     228                                sv->secur ? "Secur" : "NotSecur",
     229                                (sv->serv_status == 0) ? "Thread not created" :
     230                                ((sv->serv_status == 1) ? "Thread running" :
     231                                ((sv->serv_status == 2) ? "Thread terminated" :
     232                                                          "Thread status unknown")));
     233                /* Dump the endpoints ? */
     234                /* Dump the client list ? */
     235        }
    254236}
    255237
     
    257239int fd_servers_start()
    258240{
    259         struct server * s;
    260        
    261         int empty_conf_ep = FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints);
     241        int  socket;
     242        struct server * sv;
    262243       
    263244        /* SCTP */
     
    268249               
    269250                /* Create the server on default port */
    270                 CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 0) );
    271                 CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) );
    272                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    273                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    274                
    275                 /* Retrieve the list of endpoints if it was empty */
    276                 if (empty_conf_ep) {
    277                         (void) fd_cnx_getendpoints(s->conn, &fd_g_config->cnf_endpoints, NULL);
    278                 }
    279                
    280                 /* Create the server on secure port */
    281                 CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) );
    282                 CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_tls, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) );
    283                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    284                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     251                CHECK_FCT( fd_sctp_create_bind_server( &socket, fd_g_config->cnf_port ) );
     252                CHECK_MALLOC( sv = new_serv(IPPROTO_SCTP, 0, socket) );
     253               
     254               
     255               
    285256               
    286257#endif /* DISABLE_SCTP */
     
    290261        if (!fd_g_config->cnf_flags.no_tcp) {
    291262               
    292                 if (empty_conf_ep) {
    293                         /* Bind TCP servers on [0.0.0.0] */
    294                         if (!fd_g_config->cnf_flags.no_ip4) {
    295                                
    296                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
    297                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET, NULL) );
    298                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    299                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    300 
    301                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
    302                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET, NULL) );
    303                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    304                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    305                         }
    306                         /* Bind TCP servers on [::] */
    307                         if (!fd_g_config->cnf_flags.no_ip6) {
    308                                
    309                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
    310                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET6, NULL) );
    311                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    312                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    313 
    314                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
    315                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET6, NULL) );
    316                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    317                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    318                         }
    319                 } else {
    320                         /* Create all endpoints -- check flags */
    321                         struct fd_list * li;
    322                         for (li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
    323                                 struct fd_endpoint * ep = (struct fd_endpoint *)li;
    324                                 sSA * sa = (sSA *) &ep->ss;
    325                                 if (! (ep->flags & EP_FL_CONF))
    326                                         continue;
    327                                 if (fd_g_config->cnf_flags.no_ip4 && (sa->sa_family == AF_INET))
    328                                         continue;
    329                                 if (fd_g_config->cnf_flags.no_ip6 && (sa->sa_family == AF_INET6))
    330                                         continue;
    331                                
    332                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
    333                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, sa->sa_family, ep) );
    334                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    335                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    336 
    337                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
    338                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, sa->sa_family, ep) );
    339                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    340                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    341                         }
    342                 }
     263               
    343264        }
    344265       
     
    347268
    348269/* Terminate all the servers */
    349 int fd_servers_stop()
    350 {
    351         TODO("Not implemented");
    352        
    353         /* Loop on all servers */
    354                 /* cancel thread */
    355                 /* destroy server connection context */
    356                 /* cancel and destroy all clients */
    357 }
     270void fd_servers_stop()
     271{
     272       
     273}
  • freeDiameter/tests/CMakeLists.txt

    r29 r10  
    1818        testsess
    1919        testdisp
    20         testcnx
    2120)
    2221
  • freeDiameter/tests/tests.h

    r29 r10  
    4646#include <pthread.h>
    4747#include <errno.h>
    48 #include <gcrypt.h>
    4948
    5049/* Test timeout duration, unless -n is passed on the command line */
    5150#ifndef TEST_TIMEOUT
    52 #define TEST_TIMEOUT    30      /* in seconds */
     51#define TEST_TIMEOUT    5       /* 5 seconds */
    5352#endif /* TEST_TIMEOUT */
    5453
     
    7978struct fd_config * fd_g_config = &conf;
    8079
    81 /* gcrypt functions to support posix threads */
    82 GCRY_THREAD_OPTION_PTHREAD_IMPL;
    83 
    8480/* Define the standard check routines */
    8581#define CHECK( _val, _assert ){                         \
     
    10399
    104100/* Minimum inits */
    105 #define INIT_FD() {                                                             \
    106         memset(fd_g_config, 0, sizeof(struct fd_config));                       \
    107         CHECK( 0, fd_lib_init() );                                              \
    108         fd_log_threadname(basename(__FILE__));                                  \
    109         (void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);    \
    110         (void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);                   \
    111         CHECK( 0, gnutls_global_init());                                        \
    112         CHECK( 0, fd_conf_init() );                                             \
    113         CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) );               \
    114         parse_cmdline(argc, argv);                                              \
     101#define INIT_FD() {                                             \
     102        memset(fd_g_config, 0, sizeof(struct fd_config));       \
     103        CHECK( 0, fd_lib_init() );                              \
     104        fd_log_threadname(basename(__FILE__));                  \
     105        CHECK( 0, fd_conf_init() );                             \
     106        CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) );       \
     107        parse_cmdline(argc, argv);                              \
    115108}
    116109
  • include/freeDiameter/CMakeLists.txt

    r24 r17  
    1010
    1111# Disable SCTP support completly ?
    12 OPTION(DISABLE_SCTP "Disable SCTP support?" OFF)
    13 IF (NOT DISABLE_SCTP)
    14         OPTION(DEBUG_SCTP "Verbose SCTP (for debug)?" OFF)
    15         OPTION(SCTP_USE_MAPPED_ADDRESSES "Use v6-mapped v4 addresses in SCTP (workaround some SCTP limitations)?" OFF)
    16 ENDIF (NOT DISABLE_SCTP)
     12OPTION(DISABLE_SCTP "Disable SCTP support?")
    1713
    1814# Find TODO items in the code easily ?
  • include/freeDiameter/freeDiameter-host.h.in

    r24 r13  
    4545
    4646#cmakedefine DISABLE_SCTP
    47 #cmakedefine DEBUG_SCTP
    48 #cmakedefine SCTP_USE_MAPPED_ADDRESSES
    4947#cmakedefine ERRORS_ON_TODO
    5048#cmakedefine DEBUG
  • include/freeDiameter/freeDiameter.h

    r25 r20  
    118118struct fd_endpoint {
    119119        struct fd_list  chain;  /* link in cnf_endpoints list */
    120        
    121         union {
    122                 sSS             ss;     /* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */
    123                 sSA4            sin;
    124                 sSA6            sin6;
    125                 sSA             sa;
    126         };
    127        
    128 #define EP_FL_CONF      (1 << 0)        /* This endpoint is statically configured in a configuration file */
    129 #define EP_FL_DISC      (1 << 1)        /* This endpoint was resolved from the Diameter Identity or other DNS query */
    130 #define EP_FL_ADV       (1 << 2)        /* This endpoint was advertized in Diameter CER/CEA exchange */
    131 #define EP_FL_LL        (1 << 3)        /* Lower layer mechanism provided this endpoint */
    132 #define EP_FL_PRIMARY   (1 << 4)        /* This endpoint is primary in a multihomed SCTP association */
    133         uint32_t        flags;          /* Additional information about the endpoint */
    134                
    135         /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
     120        sSS             ss;     /* the socket information. List is always ordered by ss value (memcmp) */
     121        struct {
     122                unsigned conf : 1; /* This endpoint is statically configured in a configuration file */
     123                unsigned disc : 1; /* This endpoint was resolved from the Diameter Identity or other DNS query */
     124                unsigned adv  : 1; /* This endpoint was advertized in Diameter CER/CEA exchange */
     125                unsigned ll   : 1; /* Lower layer mechanism provided this endpoint */
     126               
     127                /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
     128
     129        }               meta;   /* Additional information about the endpoint */
    136130};
    137131
     
    152146struct fd_event {
    153147        int      code; /* codespace depends on the queue */
    154         size_t   size;
    155148        void    *data;
    156149};
    157150
    158 /* Daemon's codespace: 1000->1999 */
     151static __inline__ int fd_event_send(struct fifo *queue, int code, void * data)
     152{
     153        struct fd_event * ev;
     154        CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) );
     155        ev->code = code;
     156        ev->data = data;
     157        CHECK_FCT( fd_fifo_post(queue, &ev) );
     158        return 0;
     159}
     160static __inline__ int fd_event_get(struct fifo *queue, int *code, void ** data)
     161{
     162        struct fd_event * ev;
     163        CHECK_FCT( fd_fifo_get(queue, &ev) );
     164        if (code)
     165                *code = ev->code;
     166        if (data)
     167                *data = ev->data;
     168        free(ev);
     169        return 0;
     170}
     171
     172/* Events codespace for fd_g_config->cnf_main_ev */
    159173enum {
    160          FDEV_TERMINATE = 1000  /* request to terminate */
     174         FDEV_TERMINATE = 1000  /* request to terminate */
    161175        ,FDEV_DUMP_DICT         /* Dump the content of the dictionary */
    162176        ,FDEV_DUMP_EXT          /* Dump state of extensions */
     
    166180        ,FDEV_DUMP_PEERS        /* Dump the list of peers */
    167181};
    168 
    169 static __inline__ int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data)
    170 {
    171         struct fd_event * ev;
    172         CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) );
    173         ev->code = code;
    174         ev->size = datasz;
    175         ev->data = data;
    176         CHECK_FCT( fd_fifo_post(queue, &ev) );
    177         return 0;
    178 }
    179 static __inline__ int fd_event_get(struct fifo *queue, int *code, size_t *datasz, void ** data)
    180 {
    181         struct fd_event * ev;
    182         CHECK_FCT( fd_fifo_get(queue, &ev) );
    183         if (code)
    184                 *code = ev->code;
    185         if (datasz)
    186                 *datasz = ev->size;
    187         if (data)
    188                 *data = ev->data;
    189         free(ev);
    190         return 0;
    191 }
    192 static __inline__ int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int *code, size_t *datasz, void ** data)
    193 {
    194         struct fd_event * ev;
    195         int ret = 0;
    196         ret = fd_fifo_timedget(queue, &ev, timeout);
    197         if (ret == ETIMEDOUT) {
    198                 if (code)
    199                         *code = timeoutcode;
    200                 if (datasz)
    201                         *datasz = 0;
    202                 if (data)
    203                         *data = NULL;
    204         } else {
    205                 CHECK_FCT( ret );
    206                 if (code)
    207                         *code = ev->code;
    208                 if (datasz)
    209                         *datasz = ev->size;
    210                 if (data)
    211                         *data = ev->data;
    212                 free(ev);
    213         }
    214         return 0;
    215 }
    216 static __inline__ void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data))
    217 {
    218         struct fd_event * ev;
    219         /* Purge all events, and free the associated data if any */
    220         while (fd_fifo_tryget( *queue, &ev ) == 0) {
    221                 (*free_cb)(ev->data);
    222                 free(ev);
    223         }
    224         CHECK_FCT_DO( fd_fifo_del(queue), /* continue */ );
    225         return ;
    226 
    227182const char * fd_ev_str(int event); /* defined in freeDiameter/main.c */
    228183
     
    301256        /* Additional parameters */
    302257        uint32_t        pi_lft;         /* lifetime of this peer when inactive (see pi_flags.exp definition) */
     258        uint16_t        pi_streams;     /* number of streams for SCTP. 0 = default */
    303259        uint16_t        pi_port;        /* port to connect to. 0: default. */
    304260        int             pi_tctimer;     /* use this value for TcTimer instead of global, if != 0 */
     
    315271        struct fd_list  pi_apps;        /* applications advertised by the remote peer, except relay (pi_flags.relay) */
    316272        struct {
    317                 char                    *priority;      /* In case the default priority is not appropriate */
    318273                /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo */
    319274                const gnutls_datum_t    *cert_list;     /* The (valid) credentials that the peer has presented */
     
    505460
    506461
    507 /***************************************/
    508 /*   Endpoints lists helpers           */
    509 /***************************************/
    510 
    511 int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
    512 int fd_ep_filter( struct fd_list * list, uint32_t flags );
    513 int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
    514 
    515 
    516 
    517462#endif /* _FREEDIAMETER_H */
  • include/freeDiameter/libfreeDiameter.h

    r29 r20  
    120120 *
    121121 * PARAMETERS:
    122  *  ts          : The timestamp to log, or NULL for "now"
    123122 *  buf         : An array where the time must be stored
    124123 *  len         : size of the buffer
    125124 *
    126125 * DESCRIPTION:
    127  *  Writes the timestamp (in human readable format) in a buffer.
     126 *  Writes the current timestamp (in human readable format) in a buffer.
    128127 *
    129128 * RETURN VALUE:
    130129 *  pointer to buf.
    131130 */
    132 char * fd_log_time ( struct timespec * ts, char * buf, size_t len );
     131char * fd_log_time ( char * buf, size_t len );
    133132
    134133
     
    174173                fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"                                                                \
    175174                          "\t%s|%*s" format "\n",                                                                               \
    176                                         __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,        \
     175                                        __thn, fd_log_time(__buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,      \
    177176                                        (level < FULL)?"@":" ",level, "", ## args);                                             \
    178177        }                                                                                                                       \
     
    181180/* Helper for function entry -- for very detailed trace of the execution */
    182181#define TRACE_ENTRY(_format,_args... ) \
    183         TRACE_DEBUG(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
     182        TRACE_DEBUG(FCTS, "->%s (" #_args ") = (" _format ") >", __PRETTY_FUNCTION__, ##_args );
    184183
    185184/* Helper for debugging by adding traces -- for debuging a specific location of the code */
     
    329328                        flag);                                  \
    330329          if (__rc)                                             \
    331                 fd_log_debug("%s", (char *)gai_strerror(__rc)); \
     330                fd_log_debug((char *)gai_strerror(__rc));       \
    332331          else                                                  \
    333                 fd_log_debug("%s", &__addrbuf[0]);              \
     332                fd_log_debug(&__addrbuf[0]);                    \
    334333        } else {                                                \
    335334                fd_log_debug("(NULL / ANY)");                   \
    336335        }                                                       \
    337336}
    338 /* Same but with the port (service) also */
    339 #define sSA_DUMP_NODE_SERV( sa, flag ) {                                \
    340         sSA * __sa = (sSA *)(sa);                                       \
    341         char __addrbuf[INET6_ADDRSTRLEN];                               \
    342         char __servbuf[32];                                             \
    343         if (__sa) {                                                     \
    344           int __rc = getnameinfo(__sa,                                  \
    345                         sizeof(sSS),                                    \
    346                         __addrbuf,                                      \
    347                         sizeof(__addrbuf),                              \
    348                         __servbuf,                                      \
    349                         sizeof(__servbuf),                              \
    350                         flag);                                          \
    351           if (__rc)                                                     \
    352                 fd_log_debug("%s", (char *)gai_strerror(__rc));         \
    353           else                                                          \
    354                 fd_log_debug("[%s]:%s", &__addrbuf[0],&__servbuf[0]);   \
    355         } else {                                                        \
    356                 fd_log_debug("(NULL / ANY)");                           \
    357         }                                                               \
    358 }
    359 /* Inside a debug trace */
    360 #define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix ) {                                                                            \
    361         if ( TRACE_BOOL(level) ) {                                                                                              \
    362                 char __buf[25];                                                                                                 \
    363                 char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");                                       \
    364                 fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"                                                                \
    365                           "\t%s|%*s" prefix ,                                                                                   \
    366                                         __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
    367                                         (level < FULL)?"@":" ",level, "");                                                      \
    368                 sSA_DUMP_NODE_SERV( sa, flags );                                                                                \
    369                 fd_log_debug(suffix "\n");                                                                                      \
    370         }                                                                                                                       \
    371 }
    372 
     337/* if needed, add sSA_DUMP_SERVICE */
    373338
    374339/* A l4 protocol name (TCP / SCTP) */
     
    425390        (    ((ts1)->tv_sec  < (ts2)->tv_sec )  \
    426391          || (((ts1)->tv_sec  == (ts2)->tv_sec ) && ((ts1)->tv_nsec < (ts2)->tv_nsec) ))
    427 
    428 
    429 /* Trace a binary buffer content */
    430 #define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix ) {                                                                \
    431         if ( TRACE_BOOL(level) ) {                                                                                              \
    432                 int __i;                                                                                                        \
    433                 size_t __sz = (size_t)(bufsz);                                                                                  \
    434                 uint8_t * __buf = (uint8_t *)(buf);                                                                             \
    435                 char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");                                       \
    436                 fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"                                                                \
    437                           "\t%s|%*s" prefix ,                                                                                   \
    438                                         __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
    439                                         (level < FULL)?"@":" ",level, "");                                                      \
    440                 for (__i = 0; __i < __sz; __i++) {                                                                              \
    441                         fd_log_debug("%02.2hhx", __buf[__i]);                                                                   \
    442                 }                                                                                                               \
    443                 fd_log_debug(suffix "\n");                                                                                      \
    444         }                                                                                                                       \
    445 }
    446 
    447392
    448393
     
    470415       
    471416        if (th_ret != NULL) {
    472                 TRACE_DEBUG(ANNOYING, "The thread returned the following value: %p (ignored)", th_ret);
     417                TRACE_DEBUG(FULL, "The thread returned the following value: %p (ignored)", th_ret);
    473418        }
    474419       
     
    494439        free(buffer);
    495440}
    496 static __inline__ void fd_cleanup_socket(void * sockptr)
    497 {
    498         if (sockptr) {
    499                 shutdown(*(int *)sockptr, SHUT_RDWR);
    500                 *(int *)sockptr = 0;
    501         }
    502 }
    503 
    504441
    505442/*============================================================*/
     
    528465void fd_list_insert_after  ( struct fd_list * ref, struct fd_list * item );
    529466void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item );
    530 
    531 /* Move a list at the end of another */
    532 void fd_list_move_end(struct fd_list * ref, struct fd_list * senti);
    533467
    534468/* Insert an item in an ordered list -- ordering function provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */
     
    24082342
    24092343/*
    2410  * FUNCTION:    fd_fifo_move
    2411  *
    2412  * PARAMETERS:
    2413  *  old         : Location of a FIFO that is to be emptied and deleted.
    2414  *  new         : A FIFO that will receive the old data.
    2415  *  loc_update  : if non NULL, a place to store the pointer to new FIFO atomically with the move.
    2416  *
    2417  * DESCRIPTION:
    2418  *  Delete a queue and move its content to another one atomically.
    2419  *
    2420  * RETURN VALUE:
    2421  *  0           : The queue has been destroyed successfully.
    2422  *  EINVAL      : A parameter is invalid.
    2423  */
    2424 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update );
    2425 
    2426 /*
    24272344 * FUNCTION:    fd_fifo_length
    24282345 *
  • libfreeDiameter/fifo.c

    r25 r14  
    136136}
    137137
    138 /* Delete a queue. It must be empty. */
     138/* Delete a queue. It must be unused. */
    139139int fd_fifo_del ( struct fifo  ** queue )
    140140{
    141141        struct fifo * q;
    142         int loops = 0;
    143142       
    144143        TRACE_ENTRY( "%p", queue );
     
    150149        CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
    151150       
    152         if ((q->count != 0) || (q->data != NULL)) {
    153                 TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %p)", q->count, q->data);
     151        if ((q->count != 0) || (q->thrs != 0) || (q->data != NULL)) {
     152                TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %d, %p)", q->count, q->thrs, q->data);
    154153                CHECK_POSIX_DO(  pthread_mutex_unlock( &q->mtx ), /* no fallback */  );
    155154                return EINVAL;
    156155        }
    157156       
     157        /* sanity check */
     158        ASSERT(FD_IS_LIST_EMPTY(&q->list));
     159       
    158160        /* Ok, now invalidate the queue */
    159161        q->eyec = 0xdead;
    160162       
    161         while (q->thrs) {
    162                 CHECK_POSIX(  pthread_cond_signal(&q->cond)  );
    163                 CHECK_POSIX(  pthread_mutex_unlock( &q->mtx ));
    164                 pthread_yield();
    165                 CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
    166                 ASSERT( ++loops < 10 ); /* detect infinite loops */
    167         }
    168        
    169         /* sanity check */
    170         ASSERT(FD_IS_LIST_EMPTY(&q->list));
    171        
    172163        /* And destroy it */
    173164        CHECK_POSIX(  pthread_mutex_unlock( &q->mtx )  );
     
    179170        free(q);
    180171        *queue = NULL;
    181        
    182         return 0;
    183 }
    184 
    185 /* Move the content of old into new, and update loc_update atomically */
    186 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update )
    187 {
    188         struct fifo * q;
    189         int loops = 0;
    190        
    191         TRACE_ENTRY("%p %p %p", old, new, loc_update);
    192         CHECK_PARAMS( old && CHECK_FIFO( *old ) && CHECK_FIFO( new ));
    193        
    194         q = *old;
    195         CHECK_PARAMS( ! q->data );
    196         if (new->high) {
    197                 TODO("Implement support for thresholds in fd_fifo_move...");
    198         }
    199        
    200         /* Update loc_update */
    201         *old = NULL;
    202         if (loc_update)
    203                 *loc_update = new;
    204        
    205         /* Lock the queues */
    206         CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
    207         CHECK_POSIX(  pthread_mutex_lock( &new->mtx )  );
    208        
    209         /* Any waiting thread on the old queue returns an error */
    210         q->eyec = 0xdead;
    211         while (q->thrs) {
    212                 CHECK_POSIX(  pthread_cond_signal(&q->cond)  );
    213                 CHECK_POSIX(  pthread_mutex_unlock( &q->mtx ));
    214                 pthread_yield();
    215                 CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
    216                 ASSERT( ++loops < 10 ); /* detect infinite loops */
    217         }
    218        
    219         /* Move all data from old to new */
    220         fd_list_move_end( &new->list, &q->list );
    221         if (q->count && (!new->count)) {
    222                 CHECK_POSIX(  pthread_cond_signal(&new->cond)  );
    223         }
    224         new->count += q->count;
    225        
    226         /* Destroy old */
    227         CHECK_POSIX(  pthread_mutex_unlock( &q->mtx )  );
    228         CHECK_POSIX(  pthread_cond_destroy( &q->cond )  );
    229         CHECK_POSIX(  pthread_mutex_destroy( &q->mtx )  );
    230         free(q);
    231        
    232         /* Unlock new, we're done */
    233         CHECK_POSIX(  pthread_mutex_unlock( &new->mtx )  );
    234172       
    235173        return 0;
     
    441379awaken:
    442380        /* Check queue status */
    443         if (!CHECK_FIFO( queue )) {
    444                 /* The queue is being destroyed */
    445                 CHECK_POSIX(  pthread_mutex_unlock( &queue->mtx )  );
    446                 TRACE_DEBUG(FULL, "The queue is being destroyed -> EPIPE");
    447                 return EPIPE;
    448         }
    449                
    450381        if (queue->count > 0) {
    451382                /* There are items in the queue, so pick the first one */
  • libfreeDiameter/lists.c

    r25 r14  
    7070        ASSERT(ref->head != item);
    7171        list_insert_after(ref, item);
    72 }
    73 
    74 /* Move all elements of list senti at the end of list ref */
    75 void fd_list_move_end(struct fd_list * ref, struct fd_list * senti)
    76 {
    77         ASSERT(ref->head == ref);
    78         ASSERT(senti->head == senti);
    79        
    80         if (senti->next == senti)
    81                 return;
    82        
    83         senti->next->prev = ref->prev;
    84         ref->prev->next   = senti->next;
    85         senti->prev->next = ref;
    86         ref->prev         = senti->prev;
    87         senti->prev = senti;
    88         senti->next = senti;
    89        
    9072}
    9173
  • libfreeDiameter/log.c

    r22 r2  
    8787}
    8888
    89 /* Write time into a buffer */
    90 char * fd_log_time ( struct timespec * ts, char * buf, size_t len )
     89/* Write current time into a buffer */
     90char * fd_log_time ( char * buf, size_t len )
    9191{
    9292        int ret;
     
    9696       
    9797        /* Get current time */
    98         if (!ts) {
    99                 ret = clock_gettime(CLOCK_REALTIME, &tp);
    100                 if (ret != 0) {
    101                         snprintf(buf, len, "%s", strerror(ret));
    102                         return buf;
    103                 }
    104                 ts = &tp;
     98        ret = clock_gettime(CLOCK_REALTIME, &tp);
     99        if (ret != 0) {
     100                snprintf(buf, len, "%s", strerror(ret));
     101                return buf;
    105102        }
    106103       
    107         offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &ts->tv_sec , &tm ));
    108         offset += snprintf(buf + offset, len - offset, ".%6.6ld", ts->tv_nsec / 1000);
     104        offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &tp.tv_sec , &tm ));
     105        offset += snprintf(buf + offset, len - offset, ".%6.6ld", tp.tv_nsec / 1000);
    109106
    110107        return buf;
Note: See TracChangeset for help on using the changeset viewer.