Navigation



Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/server.c

    r29 r20  
    3636#include "fD.h"
    3737
    38 /* Server (listening) part of the daemon */
    39 
    40 struct 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 */
     38/* This file contains the server (listening) part of the daemon */
     39
     40struct 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 */
    4444struct server {
    4545        struct fd_list  chain;          /* link in the FD_SERVERS list */
    4646
    47         struct cnxctx * conn;           /* server connection context (listening socket) */
     47        int             socket;         /* server socket, or <= 0 */
     48       
    4849        int             proto;          /* IPPROTO_TCP or IPPROTO_SCTP */
    4950        int             secur;          /* TLS is started immediatly after connection ? */
    5051       
    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 */
     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 */
    5659};
    5760
    58 /* Client information (connecting peer for which we don't have the CER yet) */
     61/* Client (connected remote endpoint, not received CER yet) information */
    5962struct client {
    6063        struct fd_list   chain; /* link in the server's list of clients */
    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 */
     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) */
    6471};
    6572
    66 
    67 /* Dump all servers information */
    68 void 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)));
     73/* Parameter for the thread handling the new connected client, to avoid bloking the server thread */
     74struct 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 */
     83static void * handle_client_fast(void * arg)
     84{
     85        struct cli_fast * cf = arg;
     86        struct client * c = NULL;
     87       
     88        /* 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);
    9199                }
    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 */
    98 static 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;
    112        
    113         /* Name the current thread */
    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;
    124                 }
    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 */
    162 cleanup:
    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 */
     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       
     127early_error:
     128        TRACE_DEBUG(INFO, "Thread is detaching to die");
    181129        pthread_detach(pthread_self());
     130        shutdown(cf->sock, SHUT_RDWR);
     131        free(cf);
    182132        free(c);
     133error: 
     134        TRACE_DEBUG(INFO, "Thread is terminating");
     135        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
    183136        return NULL;
    184        
    185 fatal_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 */
     137}
     138
     139/* The thread for the server */
    191140static void * serv_th(void * arg)
    192141{
    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;
     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       
    198152       
    199153        /* Accept incoming connections */
    200         CHECK_FCT_DO( fd_cnx_serv_listen(s->conn), goto error );
     154        CHECK_SYS_DO(  listen(sv->socket, 5), goto error );
    201155       
    202156        do {
    203                 struct client * c = NULL;
    204                 struct cnxctx * conn = NULL;
     157                struct cli_fast * ncf;
     158                pthread_t         thr;
     159               
     160                /* Re-init socket size */
     161                cf.sslen = sizeof(sSS);
    205162               
    206163                /* Wait for a new client */
    207                 CHECK_MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), goto error );
     164                CHECK_SYS_DO( cf.sock = accept(sv->socket, (sSA *)&cf.ss, &cf.sslen), goto error );
    208165               
    209166                TRACE_DEBUG(FULL, "New connection accepted");
    210167               
    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 );
     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 );
    224174               
    225175        } while (1);
    226176       
    227177error: 
    228         if (s)
    229                 s->status = 2;
     178        if (sv)
     179                sv->serv_status = 2;
    230180        /* Send error signal to the daemon */
    231181        TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating...");
    232         CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
     182        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
    233183
    234184        return NULL;
     
    237187
    238188/* Create a new server structure */
    239 static struct server * new_serv( int proto, int secur )
    240 {
     189static struct server * new_serv( int proto, int secur, int socket )
     190{
     191        char buf[32];
     192        char * sn = NULL;
    241193        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 );
    242199       
    243200        /* New server structure */
     
    246203        memset(new, 0, sizeof(struct server));
    247204        fd_list_init(&new->chain, new);
     205        new->socket = socket;
    248206        new->proto = proto;
    249207        new->secur = secur;
     
    251209        fd_list_init(&new->clients, new);
    252210       
     211        new->serv_name = sn;
     212       
    253213        return new;
     214}
     215
     216/* Dump all servers information */
     217void 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        }
    254236}
    255237
     
    257239int fd_servers_start()
    258240{
    259         struct server * s;
    260        
    261         int empty_conf_ep = FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints);
     241        int  socket;
     242        struct server * sv;
    262243       
    263244        /* SCTP */
     
    268249               
    269250                /* Create the server on default port */
    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 ) );
     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               
    285256               
    286257#endif /* DISABLE_SCTP */
     
    290261        if (!fd_g_config->cnf_flags.no_tcp) {
    291262               
    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                 }
     263               
    343264        }
    344265       
     
    347268
    348269/* Terminate all the servers */
    349 int 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 }
     270void fd_servers_stop()
     271{
     272       
     273}
Note: See TracChangeset for help on using the changeset viewer.