Navigation


Changeset 25:67ca08d5bc48 in freeDiameter


Ignore:
Timestamp:
Oct 26, 2009, 4:00:49 PM (15 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Completed connection context files

Files:
2 added
14 edited

Legend:

Unmodified
Added
Removed
  • extensions/dbg_monitor/monitor.c

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

    r24 r25  
    1010SET(FD_COMMON_SRC
    1111        fD.h
     12        cnxctx.h
    1213        config.c
    1314        cnxctx.c
     
    2627
    2728IF(NOT DISABLE_SCTP)
    28         SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c)
     29        SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c sctps.c)
    2930ENDIF(NOT DISABLE_SCTP)
    3031
  • freeDiameter/cnxctx.c

    r24 r25  
    3535
    3636#include "fD.h"
     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 */
    3743
    3844/* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations .
     
    5763 *
    5864 * 3) Usage
    59  *    - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not).
     65 *    - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not, but blocking).
    6066 *    - 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.
    6167 *    - fd_cnx_getid : retrieve a descriptive string for the connection (for debug)
     
    6874 */
    6975
    70 /* The connection context structure */
    71 struct cnxctx {
    72         char            cc_id[60];      /* The name of this connection */
    73         char            cc_remid[60];   /* Id of remote peer */
    74 
    75         int             cc_socket;      /* The socket object of the connection -- <=0 if no socket is created */
    76 
    77         int             cc_proto;       /* IPPROTO_TCP or IPPROTO_SCTP */
    78         int             cc_tls;         /* Is TLS already started ? */
    79 
    80         struct fifo *   cc_events;      /* Events occuring on the connection */
    81         pthread_t       cc_mgr;         /* manager thread for the connection */
    82         struct fifo *   cc_incoming;    /* FIFO queue of messages received on the connection */
    83         struct fifo *   cc_alt;         /* alternate fifo to send FDEVP_CNX_MSG_RECV events to. */
    84 
    85         /* If cc_proto == SCTP */
    86         struct  {
    87                 int             str_out;/* Out streams */
    88                 int             str_in; /* In streams */
    89                 int             pairs;  /* max number of pairs ( = min(in, out)) */
    90                 int             next;   /* # of stream the next message will be sent to */
    91         }               cc_sctp_para;
    92 
    93         /* If cc_tls == true */
    94         struct {
    95                 int                              mode;          /* GNUTLS_CLIENT / GNUTLS_SERVER */
    96                 gnutls_session_t                 session;       /* Session object (stream #0 in case of SCTP) */
    97         }               cc_tls_para;
    98 
    99         /* If both conditions */
    100         struct {
    101                 gnutls_session_t                *res_sessions;  /* Sessions of other pairs of streams, resumed from the first */
    102                 /* Buffers, threads, ... */
    103         }               cc_sctp_tls_para;
    104 };
    105 
     76
     77/*******************************************/
     78/*     Creation of a connection object     */
     79/*******************************************/
    10680
    10781/* Initialize a context structure */
     
    11690
    11791        if (full) {
    118                 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_events ), return NULL );
    11992                CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL );
    12093        }
     
    352325}
    353326
    354 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx) */
     327/* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */
    355328struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list)
    356329{
     
    382355                cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in;
    383356       
     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       
    384363        /* Generate the names for the object */
    385364        {
     
    403382        }
    404383       
    405         if (TRACE_BOOL(INFO)) {
    406                 fd_log_debug("Connection established to server '");
    407                 sSA_DUMP_NODE_SERV( &primary, NI_NUMERICSERV);
    408                 fd_log_debug("' (SCTP:%d).\n", sock);
    409         }
    410        
    411384        return cnx;
    412385
     
    424397}
    425398
     399/* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
     400int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
     401{
     402        TRACE_ENTRY("%p %p %p", conn, local, remote);
     403        CHECK_PARAMS(conn);
     404       
     405        if (local) {
     406                /* Retrieve the local endpoint(s) of the connection */
     407                switch (conn->cc_proto) {
     408                        case IPPROTO_TCP: {
     409                                sSS ss;
     410                                socklen_t sl;
     411                                CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl));
     412                                CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY));
     413                        }
     414                        break;
     415
     416                        #ifndef DISABLE_SCTP
     417                        case IPPROTO_SCTP: {
     418                                CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local));
     419                        }
     420                        break;
     421                        #endif /* DISABLE_SCTP */
     422
     423                        default:
     424                                CHECK_PARAMS(0);
     425                }
     426        }
     427       
     428        if (remote) {
     429                /* Check we have a full connection object, not a listening socket (with no remote) */
     430                CHECK_PARAMS( conn->cc_incoming );
     431               
     432                /* Retrieve the peer endpoint(s) of the connection */
     433                switch (conn->cc_proto) {
     434                        case IPPROTO_TCP: {
     435                                sSS ss;
     436                                socklen_t sl;
     437                                CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
     438                                CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
     439                        }
     440                        break;
     441
     442                        #ifndef DISABLE_SCTP
     443                        case IPPROTO_SCTP: {
     444                                CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote));
     445                        }
     446                        break;
     447                        #endif /* DISABLE_SCTP */
     448
     449                        default:
     450                                CHECK_PARAMS(0);
     451                }
     452        }
     453
     454        return 0;
     455}
     456
     457
     458/* Get a string describing the remote peer address (ip address or fqdn) */
     459char * fd_cnx_getremoteid(struct cnxctx * conn)
     460{
     461        CHECK_PARAMS_DO( conn, return "" );
     462        return conn->cc_remid;
     463}
     464
     465
     466/**************************************/
     467/*     Use of a connection object     */
     468/**************************************/
     469
     470/* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */
     471static void * rcvthr_notls_tcp(void * arg)
     472{
     473        struct cnxctx * conn = arg;
     474       
     475        TRACE_ENTRY("%p", arg);
     476       
     477        CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
     478        ASSERT( conn->cc_proto == IPPROTO_TCP );
     479        ASSERT( conn->cc_tls == 0 );
     480        ASSERT( Target_Queue(conn) );
     481       
     482        /* Receive from a TCP connection: we have to rebuild the message boundaries */
     483        do {
     484                uint8_t header[4];
     485                uint8_t * newmsg;
     486                size_t  length;
     487                ssize_t ret = 0;
     488                size_t  received = 0;
     489
     490                do {
     491                        ret = recv(conn->cc_socket, &header[received], sizeof(header) - received, 0);
     492                        if (ret <= 0) {
     493                                CHECK_SYS_DO(ret, /* continue */);
     494                                goto error; /* Stop the thread, the recipient of the event will cleanup */
     495                        }
     496
     497                        received += ret;
     498                } while (received < sizeof(header));
     499
     500                length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
     501
     502                /* Check the received word is a valid begining of a Diameter message */
     503                if ((header[0] != DIAMETER_VERSION)     /* defined in <libfreeDiameter.h> */
     504                   || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
     505                        /* The message is suspect */
     506                        TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %g], assume disconnection", (int)header[0], length);
     507                        goto error; /* Stop the thread, the recipient of the event will cleanup */
     508                }
     509
     510                /* Ok, now we can really receive the data */
     511                CHECK_MALLOC_DO(  newmsg = malloc( length ), goto error );
     512                memcpy(newmsg, header, sizeof(header));
     513
     514                while (received < length) {
     515                        pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
     516                        ret = recv(conn->cc_socket, newmsg + received, length - received, 0);
     517                        pthread_cleanup_pop(0);
     518
     519                        if (ret <= 0) {
     520                                CHECK_SYS_DO(ret, /* continue */);
     521                                free(newmsg);
     522                                goto error; /* Stop the thread, the recipient of the event will cleanup */
     523                        }
     524                        received += ret;
     525                }
     526               
     527                /* We have received a complete message, send it */
     528                CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
     529               
     530        } while (conn->cc_loop);
     531       
     532out:
     533        TRACE_DEBUG(FULL, "Thread terminated");
     534        return NULL;
     535error:
     536        CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
     537        goto out;
     538}
     539
     540#ifndef DISABLE_SCTP
     541/* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */
     542static void * rcvthr_notls_sctp(void * arg)
     543{
     544        struct cnxctx * conn = arg;
     545        uint8_t * buf;
     546        size_t    bufsz;
     547        int       event;
     548       
     549        TRACE_ENTRY("%p", arg);
     550       
     551        CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
     552        ASSERT( conn->cc_proto == IPPROTO_SCTP );
     553        ASSERT( conn->cc_tls == 0 );
     554        ASSERT( Target_Queue(conn) );
     555       
     556        do {
     557                CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event), goto error );
     558                if (event == FDEVP_CNX_ERROR) {
     559                        goto error;
     560                }
     561               
     562                CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto error );
     563               
     564        } while (conn->cc_loop);
     565       
     566out:
     567        TRACE_DEBUG(FULL, "Thread terminated");
     568        return NULL;
     569error:
     570        CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
     571        goto out;
     572}
     573#endif /* DISABLE_SCTP */
     574
     575/* Returns 0 on error, received data size otherwise (always >= 0) */
     576static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
     577{
     578        ssize_t ret;
     579again: 
     580        CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz),
     581                {
     582                        switch (ret) {
     583                                case GNUTLS_E_REHANDSHAKE:
     584                                        CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
     585                                                {
     586                                                        if (TRACE_BOOL(INFO)) {
     587                                                                fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
     588                                                        }
     589                                                        ret = 0;
     590                                                        goto end;
     591                                                } );
     592
     593                                case GNUTLS_E_AGAIN:
     594                                case GNUTLS_E_INTERRUPTED:
     595                                        goto again;
     596
     597                                default:
     598                                        TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
     599                                        ret = 0;
     600                        }
     601                } );
     602end:   
     603        return ret;
     604}
     605
     606/* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
     607int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
     608{
     609        /* No guaranty that GnuTLS preserves the message boundaries, so we re-build it as in TCP */
     610        do {
     611                uint8_t header[4];
     612                uint8_t * newmsg;
     613                size_t  length;
     614                ssize_t ret = 0;
     615                size_t  received = 0;
     616
     617                do {
     618                        ret = fd_tls_recv_handle_error(conn, conn->cc_tls_para.session, &header[received], sizeof(header) - received);
     619                        if (ret == 0) {
     620                                /* The connection is closed */
     621                                goto out;
     622                        }
     623                        received += ret;
     624                } while (received < sizeof(header));
     625
     626                length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
     627
     628                /* Check the received word is a valid beginning of a Diameter message */
     629                if ((header[0] != DIAMETER_VERSION)     /* defined in <libfreeDiameter.h> */
     630                   || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
     631                        /* The message is suspect */
     632                        TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %g], assume disconnection", (int)header[0], length);
     633                        goto out;
     634                }
     635
     636                /* Ok, now we can really receive the data */
     637                CHECK_MALLOC(  newmsg = malloc( length ) );
     638                memcpy(newmsg, header, sizeof(header));
     639
     640                while (received < length) {
     641                        pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
     642                        ret = fd_tls_recv_handle_error(conn, conn->cc_tls_para.session, newmsg + received, length - received);
     643                        pthread_cleanup_pop(0);
     644
     645                        if (ret == 0) {
     646                                free(newmsg);
     647                                goto out; /* Stop the thread, the recipient of the event will cleanup */
     648                        }
     649                        received += ret;
     650                }
     651               
     652                /* We have received a complete message, send it */
     653                CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
     654               
     655        } while (1);
     656out:
     657        return ENOTCONN;
     658}
     659
     660/* Receiver thread (TLS & 1 stream SCTP or TCP) : gnutls directly handles the socket, save records into the target queue */
     661static void * rcvthr_tls_single(void * arg)
     662{
     663        struct cnxctx * conn = arg;
     664       
     665        TRACE_ENTRY("%p", arg);
     666       
     667        CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error);
     668        ASSERT( conn->cc_tls == 1 );
     669        ASSERT( Target_Queue(conn) );
     670       
     671        CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */);
     672error:
     673        CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
     674        TRACE_DEBUG(FULL, "Thread terminated");
     675        return NULL;
     676}
     677
    426678/* Start receving messages in clear (no TLS) on the connection */
    427 int fd_cnx_start_clear(struct cnxctx * conn)
    428 {
    429 
    430         TODO("...");
    431         return ENOTSUP;
     679int fd_cnx_start_clear(struct cnxctx * conn, int loop)
     680{
     681        TRACE_ENTRY("%p %i", conn, loop);
     682       
     683        CHECK_PARAMS( conn && Target_Queue(conn) && (!conn->cc_tls) && (!conn->cc_loop));
     684       
     685        /* Save the loop request */
     686        conn->cc_loop = loop;
     687       
     688        /* Release resources in case of a previous call was already made */
     689        CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
     690       
     691        switch (conn->cc_proto) {
     692                case IPPROTO_TCP:
     693                        /* Start the tcp_notls thread */
     694                        CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_tcp, conn ) );
     695                        break;
     696#ifndef DISABLE_SCTP
     697                case IPPROTO_SCTP:
     698                        /* Start the tcp_notls thread */
     699                        CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_sctp, conn ) );
     700                        break;
     701#endif /* DISABLE_SCTP */
     702                default:
     703                        TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto);
     704                        return ENOTSUP;
     705        }
     706                       
     707        return 0;
     708}
     709
     710/* Prepare a gnutls session object for handshake */
     711int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority)
     712{
     713        /* Create the master session context */
     714        CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM );
     715
     716        /* Set the algorithm suite */
     717        if (priority) {
     718                const char * errorpos;
     719                CHECK_GNUTLS_DO( gnutls_priority_set_direct( *session, priority, &errorpos ),
     720                        { TRACE_DEBUG(INFO, "Error in priority string '%s' at position: '%s'\n", priority, errorpos); return EINVAL; } );
     721        } else {
     722                CHECK_GNUTLS_DO( gnutls_priority_set( *session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL );
     723        }
     724
     725        /* Set the credentials of this side of the connection */
     726        CHECK_GNUTLS_DO( gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL );
     727
     728        /* Request the remote credentials as well */
     729        if (mode == GNUTLS_SERVER) {
     730                gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE);
     731        }
     732       
     733        return 0;
    432734}
    433735
     
    436738{
    437739        TRACE_ENTRY( "%p %d", conn, mode);
    438         CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) );
     740        CHECK_PARAMS( conn && (!conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
    439741
    440742        /* Save the mode */
    441743        conn->cc_tls_para.mode = mode;
    442 
    443         /* Create the master session context */
    444         CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM );
    445 
    446         /* Set the algorithm suite */
    447         TODO("Use overwrite priority if non NULL");
    448         CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL );
    449 
    450         /* Set the credentials of this side of the connection */
    451         CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL );
    452 
    453         /* Request the remote credentials as well */
    454         if (mode == GNUTLS_SERVER) {
    455                 gnutls_certificate_server_set_request (conn->cc_tls_para.session, GNUTLS_CERT_REQUIRE);
    456         }
    457 
    458         /* Set the socket info in the session */
    459         gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket);
     744       
     745        /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */
     746        CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
     747       
     748        /* Once TLS handshake is done, we don't stop after the first message */
     749        conn->cc_loop = 1;
     750       
     751        /* Prepare the master session credentials and priority */
     752        CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority) );
    460753
    461754        /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */
    462         if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {
    463 #ifndef DISABLE_SCTP
    464                 TODO("Initialize the SCTP TLS wrapper");
    465                 TODO("Set the lowat, push and pull functions");
     755        if (conn->cc_sctp_para.pairs > 1) {
     756#ifdef DISABLE_SCTP
     757                ASSERT(0);
     758                CHECK_FCT( ENOTSUP );
    466759#else /* DISABLE_SCTP */
    467                 ASSERT(0);
     760                /* Initialize the wrapper, start the demux thread */
     761                CHECK_FCT( fd_sctps_init(conn) );
    468762#endif /* DISABLE_SCTP */
     763        } else {
     764                /* Set the socket info in the session */
     765                gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket);
    469766        }
    470767
     
    500797        }
    501798
    502         /* Other sessions in case of multi-stream SCTP are resumed from the master */
    503         if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {
     799        /* Multi-stream TLS: handshake other streams as well */
     800        if (conn->cc_sctp_para.pairs > 1) {
    504801#ifndef DISABLE_SCTP
    505                 TODO("Init and resume all additional sessions from the master one.");
     802                /* Resume all additional sessions from the master one. */
     803                CHECK_FCT(fd_sctps_handshake_others(conn, priority));
     804               
     805                /* Start decrypting the messages from all threads and queuing them in target queue */
     806                CHECK_FCT(fd_sctps_startthreads(conn));
    506807#endif /* DISABLE_SCTP */
    507         }
    508 
    509         TODO("Start the connection state machine thread");
     808        } else {
     809                /* Start decrypting the data */
     810                CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) );
     811        }
    510812
    511813        return 0;
     
    515817int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size)
    516818{
    517 
    518         TODO("...");
    519         return ENOTSUP;
    520 }
    521 
    522 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
    523 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
    524 {
    525         TRACE_ENTRY("%p %p %p", conn, local, remote);
    526         CHECK_PARAMS(conn);
    527        
    528         if (local) {
    529                 /* Retrieve the local endpoint(s) of the connection */
    530                 switch (conn->cc_proto) {
    531                         case IPPROTO_TCP: {
    532                                 sSS ss;
    533                                 socklen_t sl;
    534                                 CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl));
    535                                 CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY));
    536                         }
     819        TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size);
     820        CHECK_PARAMS( conn && (conn->cc_tls) && cert_list && cert_list_size );
     821       
     822        /* This function only works for X.509 certificates. */
     823        CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 );
     824       
     825        *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size);
     826        if (*cert_list == NULL) {
     827                TRACE_DEBUG(INFO, "No certificate was provided by remote peer / an error occurred.");
     828                return EINVAL;
     829        }
     830
     831        TRACE_DEBUG( FULL, "Remote peer provided %d certificates.\n", *cert_list_size);
     832       
     833        return 0;
     834}
     835
     836/* 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. */
     837int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)
     838{
     839        int    ev;
     840        size_t ev_sz;
     841        void * ev_data;
     842       
     843        TRACE_ENTRY("%p %p %p %p", conn, timeout, buf, len);
     844        CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);
     845        CHECK_PARAMS(conn->cc_rcvthr != (pthread_t)NULL);
     846        CHECK_PARAMS(conn->cc_alt == NULL);
     847
     848        /* Now, pull the first event */
     849get_next:
     850        if (timeout) {
     851                CHECK_FCT( fd_event_timedget(conn->cc_incoming, timeout, FDEVP_PSM_TIMEOUT, &ev, &ev_sz, &ev_data) );
     852        } else {
     853                CHECK_FCT( fd_event_get(conn->cc_incoming, &ev, &ev_sz, &ev_data) );
     854        }
     855       
     856        switch (ev) {
     857                case FDEVP_CNX_MSG_RECV:
     858                        /* We got one */
     859                        *len = ev_sz;
     860                        *buf = ev_data;
     861                        return 0;
     862                       
     863                case FDEVP_PSM_TIMEOUT:
     864                        TRACE_DEBUG(FULL, "Timeout event received");
     865                        return ETIMEDOUT;
     866                       
     867                case FDEVP_CNX_EP_CHANGE:
     868                        /* We ignore this event */
     869                        goto get_next;
     870                       
     871                case FDEVP_CNX_ERROR:
     872                        TRACE_DEBUG(FULL, "Received ERROR event on the connection");
     873                        return ENOTCONN;
     874        }
     875       
     876        TRACE_DEBUG(INFO, "Received unexpected event %d (%s)", ev, fd_pev_str(ev));
     877        return EINVAL;
     878}
     879
     880/* Set an alternate FIFO list to send FDEVP_CNX_* events to */
     881int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
     882{
     883        TRACE_ENTRY( "%p %p", conn, alt_fifo );
     884        CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming );
     885       
     886        /* The magic function does it all */
     887        CHECK_FCT( fd_fifo_move( &conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
     888       
     889        return 0;
     890}
     891
     892/* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/
     893static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len)
     894{
     895        ssize_t ret;
     896        size_t sent = 0;
     897        TRACE_ENTRY("%p %p %g", conn, buf, len);
     898        do {
     899                if (conn->cc_tls) {
     900                        CHECK_GNUTLS_DO( ret = gnutls_record_send (conn->cc_tls_para.session, buf + sent, len - sent), return ENOTCONN );
     901                } else {
     902                        CHECK_SYS( ret = send(conn->cc_socket, buf + sent, len - sent, 0) ); /* better to replace with sendmsg for atomic sending? */
     903                }
     904                sent += ret;
     905        } while ( sent < len );
     906        return 0;
     907}
     908
     909/* 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. */
     910int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)
     911{
     912        TRACE_ENTRY("%p %p %g", conn, buf, len);
     913       
     914        CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);
     915
     916        TRACE_DEBUG(FULL, "Sending %gb %sdata on connection %s", len, conn->cc_tls ? "TLS-protected ":"", conn->cc_id);
     917       
     918        switch (conn->cc_proto) {
     919                case IPPROTO_TCP:
     920                        CHECK_FCT( send_simple(conn, buf, len) );
    537921                        break;
    538 
    539                         #ifndef DISABLE_SCTP
    540                         case IPPROTO_SCTP: {
    541                                 CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local));
    542                         }
    543                         break;
    544                         #endif /* DISABLE_SCTP */
    545 
    546                         default:
    547                                 CHECK_PARAMS(0);
    548                 }
    549         }
    550        
    551         if (remote) {
    552                 /* Check we have a full connection object, not a listening socket (with no remote) */
    553                 CHECK_PARAMS( conn->cc_events );
    554                
    555                 /* Retrieve the peer endpoint(s) of the connection */
    556                 switch (conn->cc_proto) {
    557                         case IPPROTO_TCP: {
    558                                 sSS ss;
    559                                 socklen_t sl;
    560                                 CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
    561                                 CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
    562                         }
    563                         break;
    564 
    565                         #ifndef DISABLE_SCTP
    566                         case IPPROTO_SCTP: {
    567                                 CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote));
    568                         }
    569                         break;
    570                         #endif /* DISABLE_SCTP */
    571 
    572                         default:
    573                                 CHECK_PARAMS(0);
    574                 }
    575         }
    576 
     922               
     923#ifndef DISABLE_SCTP
     924                case IPPROTO_SCTP: {
     925                        int multistr = 0;
     926                       
     927                        if ((conn->cc_sctp_para.str_out > 1) && ((! conn->cc_tls) || (conn->cc_sctp_para.pairs > 1)))  {
     928                                /* Update the id of the stream we will send this message on */
     929                                conn->cc_sctp_para.next += 1;
     930                                conn->cc_sctp_para.next %= (conn->cc_tls ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
     931                                multistr = 1;
     932                        }
     933                       
     934                        if ((!multistr) || (conn->cc_sctp_para.next == 0)) {
     935                                CHECK_FCT( send_simple(conn, buf, len) );
     936                        } else {
     937                                if (!conn->cc_tls) {
     938                                        CHECK_FCT( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len) );
     939                                } else {
     940                                        /* push the record to the appropriate session */
     941                                        ssize_t ret;
     942                                        size_t sent = 0;
     943                                        ASSERT(conn->cc_sctps_data.array != NULL);
     944                                        do {
     945                                                CHECK_GNUTLS_DO( ret = gnutls_record_send (conn->cc_sctps_data.array[conn->cc_sctp_para.next - 1].session, buf + sent, len - sent), { TODO("Handle error (re-handshake, etc.."); return ENOTCONN; } );
     946                                                sent += ret;
     947                                        } while ( sent < len );
     948                                }
     949                        }
     950                }
     951                break;
     952#endif /* DISABLE_SCTP */
     953       
     954                default:
     955                        TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto);
     956                        return ENOTSUP; /* or EINVAL... */
     957        }
     958       
    577959        return 0;
    578960}
    579961
    580962
    581 /* Get a string describing the remote peer address (ip address or fqdn) */
    582 char * fd_cnx_getremoteid(struct cnxctx * conn)
    583 {
    584         CHECK_PARAMS_DO( conn, return "" );
    585         return conn->cc_remid;
    586 }
    587 
    588 
    589 /* Receive next message. if timeout is not NULL, wait only until timeout */
    590 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)
    591 {
    592 
    593         TODO("...");
    594         return ENOTSUP;
    595 }
    596 
    597 /* Set / reset alternate FIFO list to send FDEVP_CNX_MSG_RECV to when message is received */
    598 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
    599 {
    600         TRACE_ENTRY( "%p %p", conn, alt_fifo );
    601         CHECK_PARAMS( conn );
    602        
    603         /* Let's cross fingers that there is no race condition here... */
    604         conn->cc_alt = alt_fifo;
    605        
    606         return 0;
    607 }
    608 
    609 /* Send a message */
    610 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)
    611 {
    612 
    613         TODO("...");
    614         return ENOTSUP;
    615 }
    616 
     963/**************************************/
     964/*     Destruction of connection      */
     965/**************************************/
    617966
    618967/* Destroy a conn structure, and shutdown the socket */
     
    623972        CHECK_PARAMS_DO(conn, return);
    624973
    625         TODO("End TLS session(s) if started");
    626        
    627         TODO("Stop manager thread if running");
     974        /* In case of TLS, stop receiver thread, then close properly the gnutls session */
     975        if ((conn->cc_tls) && (conn->cc_sctp_para.pairs > 1)) {
     976#ifndef DISABLE_SCTP
     977                /* Multi-stream TLS: Stop all decipher threads, but not the demux thread */
     978                fd_sctps_stopthreads(conn);
     979#endif /* DISABLE_SCTP */
     980        } else {
     981                /* Stop the decoding thread */
     982                CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
     983        }
     984       
     985        /* Terminate properly the TLS session(s) */
     986        if (conn->cc_tls) {
     987                /* Master session */
     988                CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */ );
     989                gnutls_deinit(conn->cc_tls_para.session);
     990               
     991#ifndef DISABLE_SCTP
     992                if (conn->cc_sctp_para.pairs > 1) {
     993                        /* Multi-stream TLS: destroy the wrapper and stop the demux thread */
     994                        fd_sctps_destroy(conn);
     995                }
     996#endif /* DISABLE_SCTP */
     997               
     998        }
    628999       
    6291000        /* Shut the connection down */
     
    6321003        }
    6331004       
    634         TODO("Empty FIFO queues");
    635        
    636         /* Destroy FIFO lists */
    637         if (conn->cc_events)
    638                 CHECK_FCT_DO( fd_fifo_del ( &conn->cc_events ), /* continue */ );
    639         if (conn->cc_incoming)
    640                 CHECK_FCT_DO( fd_fifo_del ( &conn->cc_incoming ), /* continue */ );
     1005        /* Empty and destroy FIFO list */
     1006        if (conn->cc_incoming) {
     1007                fd_event_destroy( &conn->cc_incoming, free );
     1008        }
    6411009       
    6421010        /* Free the object */
  • freeDiameter/fD.h

    r24 r25  
    152152enum {
    153153        /* Dump all info about this peer in the debug log */
    154          FDEVP_DUMP_ALL = 2000
     154         FDEVP_DUMP_ALL = 1500
    155155       
    156156        /* request to terminate this peer : disconnect, requeue all messages */
    157157        ,FDEVP_TERMINATE
    158158       
    159         /* A connection object has received a message -- stored in event->data */
     159        /* A connection object has received a message. */
    160160        ,FDEVP_CNX_MSG_RECV
     161                         
     162        /* A connection object has encountered an error (disconnected). */
     163        ,FDEVP_CNX_ERROR
     164       
     165        /* Endpoints of a connection have been changed (multihomed SCTP). */
     166        ,FDEVP_CNX_EP_CHANGE
    161167       
    162168        /* A message was received in the peer */
     
    210216struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
    211217char * fd_cnx_getid(struct cnxctx * conn);
    212 int fd_cnx_start_clear(struct cnxctx * conn);
     218int fd_cnx_start_clear(struct cnxctx * conn, int loop);
    213219int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority);
    214220int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
     
    220226void fd_cnx_destroy(struct cnxctx * conn);
    221227
    222 /* TCP */
    223 int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen );
    224 int fd_tcp_listen( int sock );
    225 int fd_tcp_client( int *sock, sSA * sa, socklen_t salen );
    226 int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl);
    227 int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl);
    228 
    229 /* SCTP */
    230 #ifndef DISABLE_SCTP
    231 int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port );
    232 int fd_sctp_listen( int sock );
    233 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list );
    234 int fd_sctp_get_local_ep(int sock, struct fd_list * list);
    235 int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
    236 int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary );
    237 
    238 #endif /* DISABLE_SCTP */
    239 
    240 
    241228
    242229#endif /* _FD_H */
  • freeDiameter/main.c

    r23 r25  
    117117        TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
    118118        while (1) {
    119                 int code;
    120                 CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, NULL),  break  );
     119                int code; size_t sz; void * data;
     120                CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data),  break  );
    121121                switch (code) {
    122122                        case FDEV_DUMP_DICT:
     
    339339       
    340340        TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig);
    341         CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) );
     341        CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) );
    342342        return NULL;
    343343}
  • freeDiameter/p_expiry.c

    r22 r25  
    8787        TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating...");
    8888        ASSERT(0);
    89         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
     89        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
    9090        return NULL;
    9191}
     
    132132                /* Now, the first peer in the list is expired; signal it */
    133133                fd_list_unlink( &first->p_expiry );
    134                 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, NULL), goto error );
     134                CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, NULL), goto error );
    135135               
    136136        } while (1);
     
    140140        TRACE_DEBUG(INFO, "An error occurred in peers module! Expiry thread is terminating...");
    141141        ASSERT(0);
    142         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
     142        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
    143143        return NULL;
    144144}
  • freeDiameter/p_psm.c

    r22 r25  
    5858                case_str(FDEVP_TERMINATE);
    5959                case_str(FDEVP_CNX_MSG_RECV);
     60                case_str(FDEVP_CNX_ERROR);
     61                case_str(FDEVP_CNX_EP_CHANGE);
    6062                case_str(FDEVP_MSG_INCOMING);
    6163                case_str(FDEVP_PSM_TIMEOUT);
     
    126128}
    127129
    128 /* Wait for the next event in the PSM, or timeout */
    129 static int psm_ev_timedget(struct fd_peer * peer, int *code, void ** data)
    130 {
    131         struct fd_event * ev;
    132         int ret = 0;
    133        
    134         TRACE_ENTRY("%p %p %p", peer, code, data);
    135        
    136         ret = fd_fifo_timedget(peer->p_events, &ev, &peer->p_psm_timer);
    137         if (ret == ETIMEDOUT) {
    138                 *code = FDEVP_PSM_TIMEOUT;
    139                 *data = NULL;
    140         } else {
    141                 CHECK_FCT( ret );
    142                 *code = ev->code;
    143                 *data = ev->data;
    144                 free(ev);
    145         }
    146        
    147         return 0;
    148 }
    149 
    150130/* The state machine thread (controler) */
    151131static void * p_psm_th( void * arg )
     
    154134        int created_started = started;
    155135        int event;
     136        size_t ev_sz;
    156137        void * ev_data;
    157138       
     
    182163psm_loop:
    183164        /* Get next event */
    184         CHECK_FCT_DO( psm_ev_timedget(peer, &event, &ev_data), goto psm_end );
    185         TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p)\t'%s'",
     165        CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
     166        TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%g)\t'%s'",
    186167                        STATE_STR(peer->p_hdr.info.pi_state),
    187                         fd_pev_str(event), ev_data,
     168                        fd_pev_str(event), ev_data, ev_sz,
    188169                        peer->p_hdr.info.pi_diamid);
    189170
     
    272253       
    273254        if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) {
    274                 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) );
     255                CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
    275256        } else {
    276257                TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
  • freeDiameter/sctp.c

    r24 r25  
    3535
    3636#include "fD.h"
     37#include "cnxctx.h"
     38
    3739#include <netinet/sctp.h>
    3840#include <sys/uio.h>
     41
     42/* Size of buffer to receive ancilliary data. May need to be enlarged if more sockopt are set... */
     43#ifndef CMSG_BUF_LEN
     44#define CMSG_BUF_LEN    1024
     45#endif /* CMSG_BUF_LEN */
    3946
    4047/* Pre-binding socket options -- # streams read in config */
     
    744751
    745752/* Retrieve streams information from a connected association -- optionaly provide the primary address */
    746 int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary )
     753int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary )
    747754{
    748755        struct sctp_status status;
     
    776783        #endif /* DEBUG_SCTP */
    777784       
    778         *in = (int)status.sstat_instrms;
    779         *out = (int)status.sstat_outstrms;
     785        *in = status.sstat_instrms;
     786        *out = status.sstat_outstrms;
    780787       
    781788        if (primary)
     
    893900}
    894901
     902/* Send a buffer over a specified stream */
     903int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len)
     904{
     905        struct msghdr mhdr;
     906        struct iovec  iov;
     907        struct {
     908                struct cmsghdr          hdr;
     909                struct sctp_sndrcvinfo  sndrcv;
     910        } anci;
     911        ssize_t ret;
     912       
     913        TRACE_ENTRY("%d %hu %p %g", sock, strid, buf, len);
     914       
     915        memset(&mhdr, 0, sizeof(mhdr));
     916        memset(&iov,  0, sizeof(iov));
     917        memset(&anci, 0, sizeof(anci));
     918       
     919        /* IO Vector: message data */
     920        iov.iov_base = buf;
     921        iov.iov_len  = len;
     922       
     923        /* Anciliary data: specify SCTP stream */
     924        anci.hdr.cmsg_len   = sizeof(anci);
     925        anci.hdr.cmsg_level = IPPROTO_SCTP;
     926        anci.hdr.cmsg_type  = SCTP_SNDRCV;
     927        anci.sndrcv.sinfo_stream = strid;
     928        /* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */
     929       
     930        /* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */
     931       
     932        mhdr.msg_iov    = &iov;
     933        mhdr.msg_iovlen = 1;
     934       
     935        mhdr.msg_control    = &anci;
     936        mhdr.msg_controllen = sizeof(anci);
     937       
     938        #ifdef DEBUG_SCTP
     939        TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock);
     940        #endif /* DEBUG_SCTP */
     941       
     942        CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) );
     943        ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */
     944       
     945        return 0;
     946}
     947
     948/* Receive the next data from the socket, or next notification */
     949int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event)
     950{
     951        ssize_t                  ret = 0;
     952        struct msghdr            mhdr;
     953        char                     ancidata[ CMSG_BUF_LEN ];
     954        struct iovec             iov;
     955        uint8_t                 *data = NULL;
     956        size_t                   bufsz = 0, datasize = 0;
     957        size_t                   mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */
     958       
     959        TRACE_ENTRY("%d %p %p %p %p", sock, strid, buf, len, event);
     960        CHECK_PARAMS( (sock > 0) && buf && len && event );
     961       
     962        /* Cleanup out parameters */
     963        *buf = NULL;
     964        *len = 0;
     965        *event = 0;
     966       
     967        /* Prepare header for receiving message */
     968        memset(&mhdr, 0, sizeof(mhdr));
     969        mhdr.msg_iov    = &iov;
     970        mhdr.msg_iovlen = 1;
     971        mhdr.msg_control    = &ancidata;
     972        mhdr.msg_controllen = sizeof(ancidata);
     973       
     974        /* We will loop while all data is not received. */
     975incomplete:
     976        if (datasize == bufsz) {
     977                /* The buffer is full, enlarge it */
     978                bufsz += mempagesz;
     979                CHECK_MALLOC( data = realloc(data, bufsz) );
     980        }
     981        /* the new data will be received following the preceding */
     982        memset(&iov,  0, sizeof(iov));
     983        iov.iov_base = data + datasize ;
     984        iov.iov_len  = bufsz - datasize;
     985
     986        /* Receive data from the socket */
     987        pthread_cleanup_push(free, data);
     988        ret = recvmsg(sock, &mhdr, 0);
     989        pthread_cleanup_pop(0);
     990       
     991        /* Handle errors */
     992        if (ret <= 0) { /* Socket is closed, or an error occurred */
     993                CHECK_SYS_DO(ret, /* to log in case of error */);
     994                free(data);
     995                *event = FDEVP_CNX_ERROR;
     996                return 0;
     997        }
     998       
     999        /* Update the size of data we received */
     1000        datasize += ret;
     1001
     1002        /* SCTP provides an indication when we received a full record; loop if it is not the case */
     1003        if ( ! (mhdr.msg_flags & MSG_EOR) ) {
     1004                goto incomplete;
     1005        }
     1006       
     1007        /* Handle the case where the data received is a notification */
     1008        if (mhdr.msg_flags & MSG_NOTIFICATION) {
     1009                union sctp_notification * notif = (union sctp_notification *) data;
     1010               
     1011                switch (notif->sn_header.sn_type) {
     1012                       
     1013                        case SCTP_ASSOC_CHANGE:
     1014                                #ifdef DEBUG_SCTP
     1015                                TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification");
     1016                                TRACE_DEBUG(FULL, "    state : %hu", notif->sn_assoc_change.sac_state);
     1017                                TRACE_DEBUG(FULL, "    error : %hu", notif->sn_assoc_change.sac_error);
     1018                                TRACE_DEBUG(FULL, "    instr : %hu", notif->sn_assoc_change.sac_inbound_streams);
     1019                                TRACE_DEBUG(FULL, "   outstr : %hu", notif->sn_assoc_change.sac_outbound_streams);
     1020                                #endif /* DEBUG_SCTP */
     1021                               
     1022                                *event = FDEVP_CNX_EP_CHANGE;
     1023                                break;
     1024       
     1025                        case SCTP_PEER_ADDR_CHANGE:
     1026                                #ifdef DEBUG_SCTP
     1027                                TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification");
     1028                                TRACE_DEBUG_sSA(FULL, "    intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" );
     1029                                TRACE_DEBUG(FULL, "          state : %d", notif->sn_paddr_change.spc_state);
     1030                                TRACE_DEBUG(FULL, "          error : %d", notif->sn_paddr_change.spc_error);
     1031                                #endif /* DEBUG_SCTP */
     1032                               
     1033                                *event = FDEVP_CNX_EP_CHANGE;
     1034                                break;
     1035       
     1036                        case SCTP_SEND_FAILED:
     1037                                #ifdef DEBUG_SCTP
     1038                                TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification");
     1039                                TRACE_DEBUG(FULL, "    len : %hu", notif->sn_send_failed.ssf_length);
     1040                                TRACE_DEBUG(FULL, "    err : %d",  notif->sn_send_failed.ssf_error);
     1041                                #endif /* DEBUG_SCTP */
     1042                               
     1043                                *event = FDEVP_CNX_ERROR;
     1044                                break;
     1045                       
     1046                        case SCTP_REMOTE_ERROR:
     1047                                #ifdef DEBUG_SCTP
     1048                                TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification");
     1049                                TRACE_DEBUG(FULL, "    err : %hu", ntohs(notif->sn_remote_error.sre_error));
     1050                                TRACE_DEBUG(FULL, "    len : %hu", ntohs(notif->sn_remote_error.sre_length));
     1051                                #endif /* DEBUG_SCTP */
     1052                               
     1053                                *event = FDEVP_CNX_ERROR;
     1054                                break;
     1055       
     1056                        case SCTP_SHUTDOWN_EVENT:
     1057                                #ifdef DEBUG_SCTP
     1058                                TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification");
     1059                                #endif /* DEBUG_SCTP */
     1060                               
     1061                                *event = FDEVP_CNX_ERROR;
     1062                                break;
     1063                       
     1064                        default:       
     1065                                TRACE_DEBUG(FULL, "Received unknown notification %d, assume error", notif->sn_header.sn_type);
     1066                                *event = FDEVP_CNX_ERROR;
     1067                }
     1068               
     1069                free(data);
     1070                return 0;
     1071        }
     1072       
     1073        /* From this point, we have received a message */
     1074        *event = FDEVP_CNX_MSG_RECV;
     1075        *buf = data;
     1076        *len = datasize;
     1077       
     1078        if (strid) {
     1079                struct cmsghdr          *hdr;
     1080                struct sctp_sndrcvinfo  *sndrcv;
     1081               
     1082                /* Handle the anciliary data */
     1083                for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) {
     1084
     1085                        /* We deal only with anciliary data at SCTP level */
     1086                        if (hdr->cmsg_level != IPPROTO_SCTP) {
     1087                                TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level);
     1088                                continue;
     1089                        }
     1090                       
     1091                        /* Also only interested in SCTP_SNDRCV message for the moment */
     1092                        if (hdr->cmsg_type != SCTP_SNDRCV) {
     1093                                TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type);
     1094                                continue;
     1095                        }
     1096                       
     1097                        sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr);
     1098                        #ifdef DEBUG_SCTP
     1099                        TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV");
     1100                        TRACE_DEBUG(FULL, "    sinfo_stream    : %hu", sndrcv->sinfo_stream);
     1101                        TRACE_DEBUG(FULL, "    sinfo_ssn       : %hu", sndrcv->sinfo_ssn);
     1102                        TRACE_DEBUG(FULL, "    sinfo_flags     : %hu", sndrcv->sinfo_flags);
     1103                        /* TRACE_DEBUG(FULL, "    sinfo_pr_policy : %hu", sndrcv->sinfo_pr_policy); */
     1104                        TRACE_DEBUG(FULL, "    sinfo_ppid      : %u" , sndrcv->sinfo_ppid);
     1105                        TRACE_DEBUG(FULL, "    sinfo_context   : %u" , sndrcv->sinfo_context);
     1106                        /* TRACE_DEBUG(FULL, "    sinfo_pr_value  : %u" , sndrcv->sinfo_pr_value); */
     1107                        TRACE_DEBUG(FULL, "    sinfo_tsn       : %u" , sndrcv->sinfo_tsn);
     1108                        TRACE_DEBUG(FULL, "    sinfo_cumtsn    : %u" , sndrcv->sinfo_cumtsn);
     1109                        #endif /* DEBUG_SCTP */
     1110
     1111                        *strid = sndrcv->sinfo_stream;
     1112                }
     1113        }
     1114       
     1115        return 0;
     1116}
  • freeDiameter/server.c

    r24 r25  
    120120                }
    121121        } else {
    122                 CHECK_FCT_DO( fd_cnx_start_clear(c->conn), goto cleanup );
     122                CHECK_FCT_DO( fd_cnx_start_clear(c->conn, 0), goto cleanup );
    123123        }
    124124       
     
    135135        TODO("Send event to the peer");
    136136       
     137        TODO("(later) handshake or start_clear(.., 1)");
    137138        /* The end */
    138139cleanup:
     
    152153       
    153154fatal_error:    /* This has effect to terminate the daemon */
    154         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
     155        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
    155156        return NULL;
    156157}
     
    198199        /* Send error signal to the daemon */
    199200        TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating...");
    200         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
     201        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
    201202
    202203        return NULL;
  • freeDiameter/tcp.c

    r24 r25  
    3535
    3636#include "fD.h"
     37#include "cnxctx.h"
     38
    3739#include <netinet/tcp.h>
    3840#include <netinet/ip6.h>
  • include/freeDiameter/freeDiameter.h

    r24 r25  
    152152struct fd_event {
    153153        int      code; /* codespace depends on the queue */
     154        size_t   size;
    154155        void    *data;
    155156};
    156157
    157 static __inline__ int fd_event_send(struct fifo *queue, int code, void * data)
    158 {
    159         struct fd_event * ev;
    160         CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) );
    161         ev->code = code;
    162         ev->data = data;
    163         CHECK_FCT( fd_fifo_post(queue, &ev) );
    164         return 0;
    165 }
    166 static __inline__ int fd_event_get(struct fifo *queue, int *code, void ** data)
    167 {
    168         struct fd_event * ev;
    169         CHECK_FCT( fd_fifo_get(queue, &ev) );
    170         if (code)
    171                 *code = ev->code;
    172         if (data)
    173                 *data = ev->data;
    174         free(ev);
    175         return 0;
    176 }
    177 
    178 /* Events codespace for fd_g_config->cnf_main_ev */
     158/* Daemon's codespace: 1000->1999 */
    179159enum {
    180          FDEV_TERMINATE = 1000  /* request to terminate */
     160         FDEV_TERMINATE = 1000  /* request to terminate */
    181161        ,FDEV_DUMP_DICT         /* Dump the content of the dictionary */
    182162        ,FDEV_DUMP_EXT          /* Dump state of extensions */
     
    186166        ,FDEV_DUMP_PEERS        /* Dump the list of peers */
    187167};
     168
     169static __inline__ int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data)
     170{
     171        struct fd_event * ev;
     172        CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) );
     173        ev->code = code;
     174        ev->size = datasz;
     175        ev->data = data;
     176        CHECK_FCT( fd_fifo_post(queue, &ev) );
     177        return 0;
     178}
     179static __inline__ int fd_event_get(struct fifo *queue, int *code, size_t *datasz, void ** data)
     180{
     181        struct fd_event * ev;
     182        CHECK_FCT( fd_fifo_get(queue, &ev) );
     183        if (code)
     184                *code = ev->code;
     185        if (datasz)
     186                *datasz = ev->size;
     187        if (data)
     188                *data = ev->data;
     189        free(ev);
     190        return 0;
     191}
     192static __inline__ int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int *code, size_t *datasz, void ** data)
     193{
     194        struct fd_event * ev;
     195        int ret = 0;
     196        ret = fd_fifo_timedget(queue, &ev, timeout);
     197        if (ret == ETIMEDOUT) {
     198                if (code)
     199                        *code = timeoutcode;
     200                if (datasz)
     201                        *datasz = 0;
     202                if (data)
     203                        *data = NULL;
     204        } else {
     205                CHECK_FCT( ret );
     206                if (code)
     207                        *code = ev->code;
     208                if (datasz)
     209                        *datasz = ev->size;
     210                if (data)
     211                        *data = ev->data;
     212                free(ev);
     213        }
     214        return 0;
     215}
     216static __inline__ void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data))
     217{
     218        struct fd_event * ev;
     219        /* Purge all events, and free the associated data if any */
     220        while (fd_fifo_tryget( *queue, &ev ) == 0) {
     221                (*free_cb)(ev->data);
     222                free(ev);
     223        }
     224        CHECK_FCT_DO( fd_fifo_del(queue), /* continue */ );
     225        return ;
     226
    188227const char * fd_ev_str(int event); /* defined in freeDiameter/main.c */
    189228
  • include/freeDiameter/libfreeDiameter.h

    r24 r25  
    427427
    428428
     429/* Trace a binary buffer content */
     430#define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix ) {                                                                \
     431        if ( TRACE_BOOL(level) ) {                                                                                              \
     432                int __i;                                                                                                        \
     433                size_t __sz = (size_t)(bufsz);                                                                                  \
     434                uint8_t * __buf = (uint8_t *)(buf);                                                                             \
     435                char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");                                       \
     436                fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"                                                                \
     437                          "\t%s|%*s" prefix ,                                                                                   \
     438                                        __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
     439                                        (level < FULL)?"@":" ",level, "");                                                      \
     440                for (__i = 0; __i < __sz; __i++) {                                                                              \
     441                        fd_log_debug("%02.2hhx", __buf[__i]);                                                                   \
     442                }                                                                                                               \
     443                fd_log_debug(suffix "\n");                                                                                      \
     444        }                                                                                                                       \
     445}
     446
     447
     448
    429449/*============================================================*/
    430450/*                          THREADS                           */
     
    508528void fd_list_insert_after  ( struct fd_list * ref, struct fd_list * item );
    509529void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item );
     530
     531/* Move a list at the end of another */
     532void fd_list_move_end(struct fd_list * ref, struct fd_list * senti);
    510533
    511534/* Insert an item in an ordered list -- ordering function provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */
     
    23852408
    23862409/*
     2410 * FUNCTION:    fd_fifo_move
     2411 *
     2412 * PARAMETERS:
     2413 *  old         : Location of a FIFO that is to be emptied and deleted.
     2414 *  new         : A FIFO that will receive the old data.
     2415 *  loc_update  : if non NULL, a place to store the pointer to new FIFO atomically with the move.
     2416 *
     2417 * DESCRIPTION:
     2418 *  Delete a queue and move its content to another one atomically.
     2419 *
     2420 * RETURN VALUE:
     2421 *  0           : The queue has been destroyed successfully.
     2422 *  EINVAL      : A parameter is invalid.
     2423 */
     2424int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update );
     2425
     2426/*
    23872427 * FUNCTION:    fd_fifo_length
    23882428 *
  • libfreeDiameter/fifo.c

    r21 r25  
    150150        CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
    151151       
    152         /* Ok, now invalidate the queue */
    153         q->eyec = 0xdead;
    154        
    155152        if ((q->count != 0) || (q->data != NULL)) {
    156153                TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %p)", q->count, q->data);
     
    158155                return EINVAL;
    159156        }
     157       
     158        /* Ok, now invalidate the queue */
     159        q->eyec = 0xdead;
    160160       
    161161        while (q->thrs) {
     
    179179        free(q);
    180180        *queue = NULL;
     181       
     182        return 0;
     183}
     184
     185/* Move the content of old into new, and update loc_update atomically */
     186int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update )
     187{
     188        struct fifo * q;
     189        int loops = 0;
     190       
     191        TRACE_ENTRY("%p %p %p", old, new, loc_update);
     192        CHECK_PARAMS( old && CHECK_FIFO( *old ) && CHECK_FIFO( new ));
     193       
     194        q = *old;
     195        CHECK_PARAMS( ! q->data );
     196        if (new->high) {
     197                TODO("Implement support for thresholds in fd_fifo_move...");
     198        }
     199       
     200        /* Update loc_update */
     201        *old = NULL;
     202        if (loc_update)
     203                *loc_update = new;
     204       
     205        /* Lock the queues */
     206        CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
     207        CHECK_POSIX(  pthread_mutex_lock( &new->mtx )  );
     208       
     209        /* Any waiting thread on the old queue returns an error */
     210        q->eyec = 0xdead;
     211        while (q->thrs) {
     212                CHECK_POSIX(  pthread_cond_signal(&q->cond)  );
     213                CHECK_POSIX(  pthread_mutex_unlock( &q->mtx ));
     214                pthread_yield();
     215                CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
     216                ASSERT( ++loops < 10 ); /* detect infinite loops */
     217        }
     218       
     219        /* Move all data from old to new */
     220        fd_list_move_end( &new->list, &q->list );
     221        if (q->count && (!new->count)) {
     222                CHECK_POSIX(  pthread_cond_signal(&new->cond)  );
     223        }
     224        new->count += q->count;
     225       
     226        /* Destroy old */
     227        CHECK_POSIX(  pthread_mutex_unlock( &q->mtx )  );
     228        CHECK_POSIX(  pthread_cond_destroy( &q->cond )  );
     229        CHECK_POSIX(  pthread_mutex_destroy( &q->mtx )  );
     230        free(q);
     231       
     232        /* Unlock new, we're done */
     233        CHECK_POSIX(  pthread_mutex_unlock( &new->mtx )  );
    181234       
    182235        return 0;
  • libfreeDiameter/lists.c

    r14 r25  
    7070        ASSERT(ref->head != item);
    7171        list_insert_after(ref, item);
     72}
     73
     74/* Move all elements of list senti at the end of list ref */
     75void fd_list_move_end(struct fd_list * ref, struct fd_list * senti)
     76{
     77        ASSERT(ref->head == ref);
     78        ASSERT(senti->head == senti);
     79       
     80        if (senti->next == senti)
     81                return;
     82       
     83        senti->next->prev = ref->prev;
     84        ref->prev->next   = senti->next;
     85        senti->prev->next = ref;
     86        ref->prev         = senti->prev;
     87        senti->prev = senti;
     88        senti->next = senti;
     89       
    7290}
    7391
Note: See TracChangeset for help on using the changeset viewer.