Changes in freeDiameter/server.c [29:5ba91682f0bc:20:277ec00d793e] in freeDiameter
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/server.c
r29 r20 36 36 #include "fD.h" 37 37 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 daemonthread. */42 43 /* Server sinformation */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 */ 44 44 struct server { 45 45 struct fd_list chain; /* link in the FD_SERVERS list */ 46 46 47 struct cnxctx * conn; /* server connection context (listening socket) */ 47 int socket; /* server socket, or <= 0 */ 48 48 49 int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 49 50 int secur; /* TLS is started immediatly after connection ? */ 50 51 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 */ 56 59 }; 57 60 58 /* Client information (connecting peer for which we don't have the CER yet)*/61 /* Client (connected remote endpoint, not received CER yet) information */ 59 62 struct client { 60 63 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) */ 64 71 }; 65 72 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 */ 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; 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); 91 99 } 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 127 early_error: 128 TRACE_DEBUG(INFO, "Thread is detaching to die"); 181 129 pthread_detach(pthread_self()); 130 shutdown(cf->sock, SHUT_RDWR); 131 free(cf); 182 132 free(c); 133 error: 134 TRACE_DEBUG(INFO, "Thread is terminating"); 135 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); 183 136 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 */ 191 140 static void * serv_th(void * arg) 192 141 { 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 198 152 199 153 /* 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 ); 201 155 202 156 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); 205 162 206 163 /* 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 ); 208 165 209 166 TRACE_DEBUG(FULL, "New connection accepted"); 210 167 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 ); 224 174 225 175 } while (1); 226 176 227 177 error: 228 if (s )229 s ->status = 2;178 if (sv) 179 sv->serv_status = 2; 230 180 /* Send error signal to the daemon */ 231 181 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), ); 233 183 234 184 return NULL; … … 237 187 238 188 /* Create a new server structure */ 239 static struct server * new_serv( int proto, int secur ) 240 { 189 static struct server * new_serv( int proto, int secur, int socket ) 190 { 191 char buf[32]; 192 char * sn = NULL; 241 193 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 ); 242 199 243 200 /* New server structure */ … … 246 203 memset(new, 0, sizeof(struct server)); 247 204 fd_list_init(&new->chain, new); 205 new->socket = socket; 248 206 new->proto = proto; 249 207 new->secur = secur; … … 251 209 fd_list_init(&new->clients, new); 252 210 211 new->serv_name = sn; 212 253 213 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 } 254 236 } 255 237 … … 257 239 int fd_servers_start() 258 240 { 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; 262 243 263 244 /* SCTP */ … … 268 249 269 250 /* 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 285 256 286 257 #endif /* DISABLE_SCTP */ … … 290 261 if (!fd_g_config->cnf_flags.no_tcp) { 291 262 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 343 264 } 344 265 … … 347 268 348 269 /* 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 } 270 void fd_servers_stop() 271 { 272 273 }
Note: See TracChangeset
for help on using the changeset viewer.