Navigation


Changeset 22:0b3b46da2c12 in freeDiameter for freeDiameter/cnxctx.c


Ignore:
Timestamp:
Oct 19, 2009, 6:43:09 PM (15 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Progress on server code

File:
1 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/cnxctx.c

    r21 r22  
    3636#include "fD.h"
    3737
     38/* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations .
     39 * They are used to hide the details of the processing to the higher layers of the daemon.
     40 * They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported.
     41 */
     42
     43/* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */
     44
     45/* Lifetime of a cnxctx object:
     46 * 1) Creation
     47 *    a) a server socket:
     48 *       - create the object with fd_cnx_serv_tcp or fd_cnx_serv_sctp
     49 *       - start listening incoming connections: fd_cnx_serv_listen
     50 *       - accept new clients with fd_cnx_serv_accept.
     51 *    b) a client socket:
     52 *       - connect to a remote server with fd_cnx_cli_connect
     53 *
     54 * 2) Initialization
     55 *    - if TLS is started first, call fd_cnx_handshake
     56 *    - otherwise to receive clear messages, call fd_cnx_start_clear. fd_cnx_handshake can be called later.
     57 *
     58 * 3) Usage
     59 *    - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not).
     60 *    - 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.
     61 *    - fd_cnx_getid : retrieve a descriptive string for the connection (for debug)
     62 *    - fd_cnx_getremoteid : identification of the remote peer (IP address or fqdn)
     63 *    - fd_cnx_getcred : get the remote peer TLS credentials, after handshake
     64 *    - fd_cnx_getendpoints : get the endpoints (IP) of the connection
     65 *
     66 * 4) End
     67 *    - fd_cnx_destroy
     68 */
     69
    3870/* The connection context structure */
    3971struct cnxctx {
     72        char            cc_id[60];      /* The name of this connection */
     73        char            cc_remid[60];   /* Id of remote peer */
     74
    4075        int             cc_socket;      /* The socket object of the connection -- <=0 if no socket is created */
    41        
     76
    4277        int             cc_proto;       /* IPPROTO_TCP or IPPROTO_SCTP */
    4378        int             cc_tls;         /* Is TLS already started ? */
    44        
     79
    4580        struct fifo *   cc_events;      /* Events occuring on the connection */
    4681        pthread_t       cc_mgr;         /* manager thread for the connection */
    4782        struct fifo *   cc_incoming;    /* FIFO queue of messages received on the connection */
    48        
    49         uint16_t        cc_port;        /* Remote port of the connection, when we are client */
    50         struct fd_list  cc_ep_remote;   /* The remote address(es) of the connection */
    51         struct fd_list  cc_ep_local;    /* The local address(es) of the connection */
    52        
     83        struct fifo *   cc_alt;         /* alternate fifo to send FDEVP_CNX_MSG_RECV events to. */
     84
    5385        /* If cc_proto == SCTP */
    5486        struct  {
     
    5890                int             next;   /* # of stream the next message will be sent to */
    5991        }               cc_sctp_para;
    60        
     92
    6193        /* If cc_tls == true */
    6294        struct {
     
    6496                gnutls_session_t                 session;       /* Session object (stream #0 in case of SCTP) */
    6597        }               cc_tls_para;
    66        
     98
    6799        /* If both conditions */
    68100        struct {
     
    73105
    74106
    75 /* Initialize a context structure from a socket */
    76 struct cnxctx * fd_cnx_init(int sock, int proto)
     107/* Initialize a context structure */
     108static struct cnxctx * fd_cnx_init(int full)
    77109{
    78110        struct cnxctx * conn = NULL;
    79        
    80         TRACE_ENTRY("%d %d", sock, proto);
    81         CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL);
    82        
     111
     112        TRACE_ENTRY("%d", full);
     113
    83114        CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL );
    84115        memset(conn, 0, sizeof(struct cnxctx));
    85        
    86         conn->cc_socket = sock;
    87         conn->cc_proto  = proto;
    88        
    89         fd_list_init(&conn->cc_ep_remote, conn);
    90         fd_list_init(&conn->cc_ep_local, conn);
    91        
    92         if (proto == IPPROTO_SCTP) {
     116
     117        if (full) {
     118                CHECK_FCT_DO( fd_fifo_new ( &conn->cc_events ), return NULL );
     119                CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL );
     120        }
     121
     122        return conn;
     123}
     124
     125/* Create and bind a server socket to the given endpoint and port */
     126struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep)
     127{
     128        struct cnxctx * cnx = NULL;
     129        sSS dummy;
     130        sSA * sa = (sSA *) &dummy;
     131
     132        TRACE_ENTRY("%hu %d %p", port, family, ep);
     133
     134        CHECK_PARAMS_DO( port, return NULL );
     135        CHECK_PARAMS_DO( ep || family, return NULL );
     136        CHECK_PARAMS_DO( (! family) || (family == AF_INET) || (family == AF_INET6), return NULL );
     137        CHECK_PARAMS_DO( (! ep) || (!family) || (ep->ss.ss_family == family), return NULL );
     138
     139        /* The connection object */
     140        CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL );
     141
     142        /* Prepare the socket address information */
     143        if (ep) {
     144                memcpy(sa, &ep->ss, sizeof(sSS));
     145        } else {
     146                memset(&dummy, 0, sizeof(dummy));
     147                sa->sa_family = family;
     148        }
     149        if (sa->sa_family == AF_INET) {
     150                ((sSA4 *)sa)->sin_port = htons(port);
     151        } else {
     152                ((sSA6 *)sa)->sin6_port = htons(port);
     153        }
     154
     155        /* Create the socket */
     156        CHECK_FCT_DO( fd_tcp_create_bind_server( &cnx->cc_socket, sa, sizeof(sSS) ), goto error );
     157
     158        /* Generate the name for the connection object */
     159        {
     160                char addrbuf[INET6_ADDRSTRLEN];
     161                int  rc;
     162                rc = getnameinfo(sa, sizeof(sSS), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
     163                if (rc)
     164                        snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
     165                snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv TCP [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket);
     166        }
     167
     168        cnx->cc_proto = IPPROTO_TCP;
     169
     170        return cnx;
     171
     172error:
     173        fd_cnx_destroy(cnx);
     174        return NULL;
     175}
    93176#ifndef DISABLE_SCTP
    94                 CHECK_FCT_DO( fd_sctp_get_str_info( sock, &conn->cc_sctp_para.str_in, &conn->cc_sctp_para.str_out ),
    95                                 { free(conn); return NULL; } );
    96                 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;
    97 #else /* DISABLE_SCTP */
    98                 ASSERT(0);
     177struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list)
     178{
     179        struct cnxctx * cnx = NULL;
     180        sSS dummy;
     181        sSA * sa = (sSA *) &dummy;
     182
     183        TRACE_ENTRY("%hu %p", port, ep_list);
     184
     185        CHECK_PARAMS_DO( port, return NULL );
     186
     187        /* The connection object */
     188        CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL );
     189
     190        /* Create the socket */
     191        CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error );
     192
     193        /* Generate the name for the connection object */
     194        snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv SCTP :%hu (%d)", port, cnx->cc_socket);
     195
     196        cnx->cc_proto = IPPROTO_SCTP;
     197
     198        return cnx;
     199
     200error:
     201        fd_cnx_destroy(cnx);
     202        return NULL;
     203}
    99204#endif /* DISABLE_SCTP */
    100         }
    101        
    102         return conn;
     205
     206/* Allow clients to connect on the server socket */
     207int fd_cnx_serv_listen(struct cnxctx * conn)
     208{
     209        CHECK_PARAMS( conn );
     210
     211        switch (conn->cc_proto) {
     212                case IPPROTO_TCP:
     213                        CHECK_FCT(fd_tcp_listen(conn->cc_socket));
     214                        break;
     215
     216                case IPPROTO_SCTP:
     217                        CHECK_FCT(fd_sctp_listen(conn->cc_socket));
     218                        break;
     219
     220                default:
     221                        CHECK_PARAMS(0);
     222        }
     223
     224        return 0;
     225}
     226
     227/* Accept a client (blocking until a new client connects) -- cancelable */
     228struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv)
     229{
     230        struct cnxctx * cli = NULL;
     231        sSS ss;
     232        socklen_t ss_len = sizeof(ss);
     233        int cli_sock = 0;
     234        struct fd_endpoint * ep;
     235
     236        TRACE_ENTRY("%p", serv);
     237        CHECK_PARAMS_DO(serv, return NULL);
     238       
     239        CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL );
     240       
     241        if (TRACE_BOOL(INFO)) {
     242                fd_log_debug("%s - new client [", fd_cnx_getid(serv));
     243                sSA_DUMP_NODE( &ss, AI_NUMERICHOST );
     244                fd_log_debug("] connected.\n");
     245        }
     246       
     247        CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); return NULL; } );
     248        cli->cc_socket = cli_sock;
     249        cli->cc_proto = serv->cc_proto;
     250       
     251        /* Generate the name for the connection object */
     252        {
     253                char addrbuf[INET6_ADDRSTRLEN];
     254                char portbuf[10];
     255                int  rc;
     256               
     257                /* Numeric values for debug */
     258                rc = getnameinfo((sSA *)&ss, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
     259                if (rc)
     260                        snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
     261               
     262                snprintf(cli->cc_id, sizeof(cli->cc_id), "Client %s [%s]:%s (%d) / serv (%d)",
     263                                IPPROTO_NAME(cli->cc_proto),
     264                                addrbuf, portbuf,
     265                                cli->cc_socket, serv->cc_socket);
     266               
     267                /* Textual value for log messages */
     268                rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, NI_NUMERICHOST);
     269                if (rc)
     270                        snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc));
     271        }
     272
     273        /* SCTP-specific handlings */
     274#ifndef DISABLE_SCTP
     275        if (cli->cc_proto == IPPROTO_SCTP) {
     276                /* Retrieve the number of streams */
     277                CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out ), goto error );
     278                if (cli->cc_sctp_para.str_out > cli->cc_sctp_para.str_in)
     279                        cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out;
     280                else
     281                        cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in;
     282        }
     283#endif /* DISABLE_SCTP */
     284
     285        return cli;
     286error:
     287        fd_cnx_destroy(cli);
     288        return NULL;
     289}
     290
     291/* Client side: connect to a remote server */
     292struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa,  socklen_t addrlen)
     293{
     294
     295        TODO("...");
     296        return NULL;
     297}
     298
     299/* Return a string describing the connection, for debug */
     300char * fd_cnx_getid(struct cnxctx * conn)
     301{
     302        CHECK_PARAMS_DO( conn, return "" );
     303        return conn->cc_id;
    103304}
    104305
     
    106307int fd_cnx_start_clear(struct cnxctx * conn)
    107308{
    108        
     309
    109310        TODO("...");
    110311        return ENOTSUP;
     
    112313
    113314/* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
    114 int fd_cnx_handshake(struct cnxctx * conn, int mode)
     315int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority)
    115316{
    116317        TRACE_ENTRY( "%p %d", conn, mode);
    117318        CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) );
    118        
     319
    119320        /* Save the mode */
    120321        conn->cc_tls_para.mode = mode;
    121        
     322
    122323        /* Create the master session context */
    123324        CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM );
    124        
     325
    125326        /* Set the algorithm suite */
     327        TODO("Use overwrite priority if non NULL");
    126328        CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL );
    127        
     329
    128330        /* Set the credentials of this side of the connection */
    129331        CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL );
    130        
     332
    131333        /* Request the remote credentials as well */
    132334        if (mode == GNUTLS_SERVER) {
     
    146348#endif /* DISABLE_SCTP */
    147349        }
    148        
     350
    149351        /* Handshake master session */
    150352        {
     
    153355                        {
    154356                                if (TRACE_BOOL(INFO)) {
    155                                         fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret));
     357                                        fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
    156358                                }
    157359                                return EINVAL;
    158360                        } );
    159                
     361
    160362                /* Now verify the remote credentials are valid -- only simple test here */
    161363                CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL );
    162364                if (ret) {
    163365                        if (TRACE_BOOL(INFO)) {
    164                                 fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket);
     366                                fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id);
    165367                                if (ret & GNUTLS_CERT_INVALID)
    166368                                        fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
     
    177379                }
    178380        }
    179        
     381
    180382        /* Other sessions in case of multi-stream SCTP are resumed from the master */
    181383        if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {
     
    184386#endif /* DISABLE_SCTP */
    185387        }
    186        
     388
     389        TODO("Start the connection state machine thread");
     390
    187391        return 0;
    188392}
     
    191395int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size)
    192396{
    193        
     397
    194398        TODO("...");
    195399        return ENOTSUP;
    196400}
    197401
    198 /* Get the list of endpoints (IP addresses) of the remote peer on this object */
    199 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * senti)
    200 {
    201        
     402/* Get the list of endpoints (IP addresses) of the local and remote peers on this conenction */
     403int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
     404{
     405        TRACE_ENTRY("%p %p %p", conn, local, remote);
     406        CHECK_PARAMS(conn);
     407       
     408        if (local) {
     409                /* Retrieve the local endpoint(s) of the connection */
     410                TODO("TCP : getsockname");
     411                TODO("SCTP: sctp_getladdrs / _sctp_getboundaddrs (waaad)");
     412        }
     413       
     414        if (remote) {
     415                /* Retrieve the peer endpoint(s) of the connection */
     416                TODO("TCP : getpeername");
     417                TODO("SCTP: sctp_getpaddrs");
     418               
     419        }
     420
     421        return ENOTSUP;
     422}
     423
     424
     425/* Get a string describing the remote peer address (ip address or fqdn) */
     426char * fd_cnx_getremoteid(struct cnxctx * conn)
     427{
     428        CHECK_PARAMS_DO( conn, return "" );
     429        return conn->cc_remid;
     430}
     431
     432
     433/* Receive next message. if timeout is not NULL, wait only until timeout */
     434int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)
     435{
     436
    202437        TODO("...");
    203438        return ENOTSUP;
    204439}
    205440
    206 
    207 /* Get a string describing the remote peer address (ip address or fqdn) */
    208 char * fd_cnx_getremoteid(struct cnxctx * conn)
    209 {
    210        
    211         TODO("...");
    212         return NULL;
    213 }
    214 
    215 
    216 /* Receive next message. if timeout is not NULL, wait only until timeout */
    217 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)
    218 {
    219        
     441/* Set / reset alternate FIFO list to send FDEVP_CNX_MSG_RECV to when message is received */
     442int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
     443{
     444        TRACE_ENTRY( "%p %p", conn, alt_fifo );
     445        CHECK_PARAMS( conn );
     446       
     447        /* Let's cross fingers that there is no race condition here... */
     448        conn->cc_alt = alt_fifo;
     449       
     450        return 0;
     451}
     452
     453/* Send a message */
     454int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)
     455{
     456
    220457        TODO("...");
    221458        return ENOTSUP;
     
    223460
    224461
    225 /* Send a message */
    226 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)
    227 {
    228        
    229         TODO("...");
    230         return ENOTSUP;
    231 }
    232 
    233 
    234462/* Destroy a conn structure, and shutdown the socket */
    235463void fd_cnx_destroy(struct cnxctx * conn)
    236464{
    237        
    238         TODO("...");
     465        TRACE_ENTRY("%p", conn);
     466       
     467        CHECK_PARAMS_DO(conn, return);
     468
     469        TODO("End TLS session(s) if started");
     470       
     471        TODO("Stop manager thread if running");
     472       
     473        /* Shut the connection down */
     474        if (conn->cc_socket > 0) {
     475                shutdown(conn->cc_socket, SHUT_RDWR);
     476        }
     477       
     478        TODO("Empty FIFO queues");
     479       
     480        /* Destroy FIFO lists */
     481        if (conn->cc_events)
     482                CHECK_FCT_DO( fd_fifo_del ( &conn->cc_events ), /* continue */ );
     483        if (conn->cc_incoming)
     484                CHECK_FCT_DO( fd_fifo_del ( &conn->cc_incoming ), /* continue */ );
     485       
     486        /* Free the object */
     487        free(conn);
     488       
     489        /* Done! */
    239490        return;
    240491}
Note: See TracChangeset for help on using the changeset viewer.