Changes in freeDiameter/server.c [20:277ec00d793e:29:5ba91682f0bc] in freeDiameter
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/server.c
r20 r29 36 36 #include "fD.h" 37 37 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 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 */ 44 44 struct server { 45 45 struct fd_list chain; /* link in the FD_SERVERS list */ 46 46 47 int socket; /* server socket, or <= 0 */ 48 47 struct cnxctx * conn; /* server connection context (listening socket) */ 49 48 int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 50 49 int secur; /* TLS is started immediatly after connection ? */ 51 50 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 */ 59 56 }; 60 57 61 /* Client (connected remote endpoint, not received CER yet) information*/58 /* Client information (connecting peer for which we don't have the CER yet) */ 62 59 struct client { 63 60 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 */ 71 64 }; 72 65 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 */ 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))); 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 */ 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; 87 112 88 113 /* 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 r c = getnameinfo((sSA *)&cf->ss, sizeof(sSS), addr + offset, sizeof(addr) - offset, NULL, 0, 0);94 if (r c)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; 99 124 } 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 */ 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 */ 129 181 pthread_detach(pthread_self()); 130 shutdown(cf->sock, SHUT_RDWR);131 free(cf);132 182 free(c); 183 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 */ 191 static 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 133 227 error: 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; 180 230 /* Send error signal to the daemon */ 181 231 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), ); 183 233 184 234 return NULL; … … 187 237 188 238 /* 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; 239 static struct server * new_serv( int proto, int secur ) 240 { 193 241 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 );199 242 200 243 /* New server structure */ … … 203 246 memset(new, 0, sizeof(struct server)); 204 247 fd_list_init(&new->chain, new); 205 new->socket = socket;206 248 new->proto = proto; 207 249 new->secur = secur; … … 209 251 fd_list_init(&new->clients, new); 210 252 211 new->serv_name = sn;212 213 253 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 }236 254 } 237 255 … … 239 257 int fd_servers_start() 240 258 { 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); 243 262 244 263 /* SCTP */ … … 249 268 250 269 /* 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 ) ); 256 285 257 286 #endif /* DISABLE_SCTP */ … … 261 290 if (!fd_g_config->cnf_flags.no_tcp) { 262 291 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 } 264 343 } 265 344 … … 268 347 269 348 /* Terminate all the servers */ 270 void fd_servers_stop() 271 { 272 273 } 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 }
Note: See TracChangeset
for help on using the changeset viewer.