Navigation



Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 }
Note: See TracChangeset for help on using the changeset viewer.