Navigation



Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/cnxctx.c

    r20 r30  
    3535
    3636#include "fD.h"
    37 
    38 /* Initialize a connection context */
    39 struct cnxctx * fd_cnx_init(int sock, int proto)
     37#include "cnxctx.h"
     38
     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 */
     82static struct cnxctx * fd_cnx_init(int full)
    4083{
    4184        struct cnxctx * conn = NULL;
    42        
    43         TRACE_ENTRY("%d %d", sock, proto);
    44         CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL);
    45        
     85
     86        TRACE_ENTRY("%d", full);
     87
    4688        CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL );
    4789        memset(conn, 0, sizeof(struct cnxctx));
    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) {
     90
     91        if (full) {
     92                CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL );
     93        }
     94
     95        return conn;
     96}
     97
     98/* Create and bind a server socket to the given endpoint and port */
     99struct 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
     145error:
     146        fd_cnx_destroy(cnx);
     147        return NULL;
     148}
     149
     150/* Same function for SCTP, with a list of local endpoints to bind to */
     151struct 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
     179error:
     180        fd_cnx_destroy(cnx);
     181        return NULL;
     182#endif /* DISABLE_SCTP */
     183}
     184
     185/* Allow clients to connect on the server socket */
     186int 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
    56195#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;
     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 */
     209struct 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;
     270error:
     271        fd_cnx_destroy(cli);
     272        return NULL;
     273}
     274
     275/* Client side: connect to a remote server -- cancelable */
     276struct 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
     322error:
     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) */
     328struct 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);
    60334#else /* DISABLE_SCTP */
    61                 ASSERT(0);
     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
     386error:
     387        fd_cnx_destroy(cnx);
     388        return NULL;
    62389#endif /* DISABLE_SCTP */
    63         }
    64        
    65         return conn;
    66 }
    67 
    68 /* TLS handshake the connection */
    69 int fd_cnx_handshake(struct cnxctx * conn, int mode)
     390}
     391
     392/* Return a string describing the connection, for debug */
     393char * 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 */
     400int 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 */
     407int 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 */
     414int 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) */
     473char * 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 */
     485static 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       
     553out:
     554        TRACE_DEBUG(FULL, "Thread terminated");
     555        return NULL;
     556error:
     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 */
     563static 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       
     594out:
     595        TRACE_DEBUG(FULL, "Thread terminated");
     596        return NULL;
     597error:
     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) */
     604static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
     605{
     606        ssize_t ret;
     607again: 
     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                } );
     630end:   
     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 */
     635int 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);
     684out:
     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 */
     689static 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 */);
     707error:
     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 */
     714int 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 */
     746int 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 */
     772int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
    70773{
    71774        TRACE_ENTRY( "%p %d", conn, mode);
    72         CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) );
    73        
     775        CHECK_PARAMS( conn && (!conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
     776
    74777        /* Save the mode */
    75778        conn->cc_tls_para.mode = mode;
    76779       
    77         /* Create the master session context */
    78         CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM );
    79        
    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 );
    82        
    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);
     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 */);
     782       
     783        /* Once TLS handshake is done, we don't stop after the first message */
     784        conn->cc_loop = 1;
     785       
     786        /* Prepare the master session credentials and priority */
     787        CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority, alt_creds) );
    93788
    94789        /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */
    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");
     790        if (conn->cc_sctp_para.pairs > 1) {
     791#ifdef DISABLE_SCTP
     792                ASSERT(0);
     793                CHECK_FCT( ENOTSUP );
    99794#else /* DISABLE_SCTP */
    100                 ASSERT(0);
     795                /* Initialize the wrapper, start the demux thread */
     796                CHECK_FCT( fd_sctps_init(conn) );
    101797#endif /* DISABLE_SCTP */
    102         }
    103        
     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);
     801        }
     802
    104803        /* Handshake master session */
    105804        {
     
    108807                        {
    109808                                if (TRACE_BOOL(INFO)) {
    110                                         fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret));
     809                                        fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
    111810                                }
    112811                                return EINVAL;
    113812                        } );
    114                
     813
    115814                /* Now verify the remote credentials are valid -- only simple test here */
    116815                CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL );
    117816                if (ret) {
    118817                        if (TRACE_BOOL(INFO)) {
    119                                 fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket);
     818                                fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id);
    120819                                if (ret & GNUTLS_CERT_INVALID)
    121820                                        fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
     
    132831                }
    133832        }
    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)) {
     833
     834        /* Multi-stream TLS: handshake other streams as well */
     835        if (conn->cc_sctp_para.pairs > 1) {
    137836#ifndef DISABLE_SCTP
    138                 TODO("Init and resume all additional sessions from the master one.");
     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));
    139845#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 ) );
    140852        }
    141853       
    142854        return 0;
    143855}
     856
     857/* Retrieve TLS credentials of the remote peer, after handshake */
     858int 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. */
     878int 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 */
     890get_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 */
     922int 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 */
     934static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
     935{
     936        ssize_t ret;
     937again: 
     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                } );
     958end:   
     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)*/
     965static 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. */
     982int 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 */
     1040void 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.