Navigation



Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/server.c

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