Mercurial > hg > freeDiameter-dtls
comparison libfdcore/server.c @ 1214:76ac4bb75f0e
Merged with latest proposed version
author | Sebastien Decugis <sdecugis@freediameter.net> |
---|---|
date | Mon, 17 Jun 2013 10:11:57 +0800 |
parents | 9ff57791a5ab |
children |
comparison
equal
deleted
inserted
replaced
1188:e1ced4db7f67 | 1214:76ac4bb75f0e |
---|---|
53 | 53 |
54 struct cnxctx * conn; /* server connection context (listening socket) */ | 54 struct cnxctx * conn; /* server connection context (listening socket) */ |
55 int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ | 55 int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ |
56 int secur; /* TLS is started immediatly after connection ? 0: no; 1: yes (TLS/TCP or DTLS/SCTP); 2: yes (TLS/TCP or TLS/SCTP) */ | 56 int secur; /* TLS is started immediatly after connection ? 0: no; 1: yes (TLS/TCP or DTLS/SCTP); 2: yes (TLS/TCP or TLS/SCTP) */ |
57 | 57 |
58 pthread_t thr; /* The thread listening for new connections */ | 58 pthread_t thr; /* The thread waiting for new connections (will store the data in the clients fifo) */ |
59 enum s_state state; /* state of the thread */ | 59 enum s_state state; /* state of the thread */ |
60 | 60 |
61 struct fd_list clients; /* List of clients connected to this server, not yet identified */ | 61 struct fifo *pending; /* FIFO of struct cnxctx */ |
62 pthread_mutex_t clients_mtx; /* Mutex to protect the list of clients */ | 62 struct pool_workers { |
63 struct server * s; /* pointer to the parent server structure */ | |
64 int id; /* The worker id for logs */ | |
65 pthread_t worker; /* The thread */ | |
66 } *workers; /* array of cnf_thr_srv items */ | |
63 }; | 67 }; |
64 | |
65 | |
66 /* Client information (connecting peer for which we don't have the CER yet) */ | |
67 struct client { | |
68 struct fd_list chain; /* link in the server's list of clients */ | |
69 struct cnxctx *conn; /* Parameters of the connection */ | |
70 struct timespec ts; /* Deadline for receiving CER (after INCNX_TIMEOUT) */ | |
71 pthread_t thr; /* connection state machine */ | |
72 }; | |
73 | |
74 | 68 |
75 | 69 |
76 /* Micro functions to read/change the status thread-safely */ | 70 /* Micro functions to read/change the status thread-safely */ |
77 static pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER; | 71 static pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER; |
78 static enum s_state get_status(struct server * s) | 72 static enum s_state get_status(struct server * s) |
89 s->state = st; | 83 s->state = st; |
90 CHECK_POSIX_DO( pthread_mutex_unlock(&s_lock), return ); | 84 CHECK_POSIX_DO( pthread_mutex_unlock(&s_lock), return ); |
91 } | 85 } |
92 | 86 |
93 | 87 |
88 /* dump one item of the server->pending fifo */ | |
89 static DECLARE_FD_DUMP_PROTOTYPE(dump_cnx, void * item) { | |
90 struct cnxctx * c = item; | |
91 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " '%s'", fd_cnx_getid(c)), return NULL); | |
92 return *buf; | |
93 } | |
94 | 94 |
95 /* Dump all servers information */ | 95 /* Dump all servers information */ |
96 DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump, int details) | 96 DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump, int details) |
97 { | 97 { |
98 struct fd_list * li, *cli; | 98 struct fd_list * li; |
99 | 99 |
100 FD_DUMP_HANDLE_OFFSET(); | 100 FD_DUMP_HANDLE_OFFSET(); |
101 | 101 |
102 for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { | 102 for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { |
103 struct server * s = (struct server *)li; | 103 struct server * s = (struct server *)li; |
110 (st == NOT_CREATED) ? "Thread not created" : | 110 (st == NOT_CREATED) ? "Thread not created" : |
111 ((st == RUNNING) ? "Thread running" : | 111 ((st == RUNNING) ? "Thread running" : |
112 ((st == TERMINATED) ? "Thread terminated" : | 112 ((st == TERMINATED) ? "Thread terminated" : |
113 "Thread status unknown"))), return NULL); | 113 "Thread status unknown"))), return NULL); |
114 /* Dump the client list of this server */ | 114 /* Dump the client list of this server */ |
115 CHECK_POSIX_DO( pthread_mutex_lock(&s->clients_mtx), ); | 115 CHECK_MALLOC_DO( fd_fifo_dump(FD_DUMP_STD_PARAMS, "pending connections", s->pending, dump_cnx), return NULL ); |
116 for (cli = s->clients.next; cli != &s->clients; cli = cli->next) { | |
117 struct client * c = (struct client *)cli; | |
118 char bufts[128]; | |
119 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {client}(@%p)'%s': to:%s", c, fd_cnx_getid(c->conn), fd_log_time(&c->ts, bufts, sizeof(bufts))), break); | |
120 } | |
121 CHECK_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), ); | |
122 | 116 |
123 if (li->next != &FD_SERVERS) { | 117 if (li->next != &FD_SERVERS) { |
124 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL); | 118 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL); |
125 } | 119 } |
126 } else { | 120 } else { |
131 | 125 |
132 return *buf; | 126 return *buf; |
133 } | 127 } |
134 | 128 |
135 | 129 |
136 /* The state machine to handle incoming connection before the remote peer is identified */ | 130 /* The thread in the pool for handling new clients connecting to a server */ |
137 static void * client_sm(void * arg) | 131 static void * client_worker(void * arg) |
138 { | 132 { |
139 struct client * c = arg; | 133 struct pool_workers * pw = arg; |
140 struct server * s = NULL; | 134 struct server * s = pw->s; |
135 struct cnxctx * c = NULL; | |
136 int fatal = 0; | |
137 struct timespec ts; | |
141 struct fd_cnx_rcvdata rcv_data; | 138 struct fd_cnx_rcvdata rcv_data; |
142 struct fd_msg_pmdl * pmdl = NULL; | 139 struct fd_msg_pmdl * pmdl = NULL; |
143 struct msg * msg = NULL; | 140 struct msg * msg = NULL; |
144 struct msg_hdr *hdr = NULL; | 141 struct msg_hdr *hdr = NULL; |
145 struct fd_pei pei; | 142 struct fd_pei pei; |
146 | 143 |
147 TRACE_ENTRY("%p", c); | 144 TRACE_ENTRY("%p", arg); |
148 | 145 |
146 /* Set the thread name */ | |
147 { | |
148 char buf[48]; | |
149 snprintf(buf, sizeof(buf), "Worker#%d[%s%s]", pw->id, IPPROTO_NAME(s->proto), s->secur?", Sec" : ""); | |
150 fd_log_threadname ( buf ); | |
151 } | |
152 | |
153 /* Loop until canceled / error */ | |
154 next_client: | |
155 LOG_A("Ready to process next incoming connection"); | |
156 | |
149 memset(&rcv_data, 0, sizeof(rcv_data)); | 157 memset(&rcv_data, 0, sizeof(rcv_data)); |
150 | 158 |
151 CHECK_PARAMS_DO(c && c->conn && c->chain.head, goto fatal_error ); | 159 /* Get the next connection */ |
152 | 160 CHECK_FCT_DO( fd_fifo_get( s->pending, &c ), { fatal = 1; goto cleanup; } ); |
153 | 161 |
154 s = c->chain.head->o; | |
155 | |
156 /* Name the current thread */ | |
157 fd_log_threadname ( fd_cnx_getid(c->conn) ); | |
158 | |
159 /* Handshake if we are a secure server port, or start clear otherwise */ | 162 /* Handshake if we are a secure server port, or start clear otherwise */ |
160 if (s->secur) { | 163 if (s->secur) { |
161 int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, (s->secur == 1) ? ALGO_HANDSHAKE_DEFAULT : ALGO_HANDSHAKE_3436, NULL, NULL); | 164 LOG_D("Starting handshake with %s", fd_cnx_getid(c)); |
165 | |
166 int ret = fd_cnx_handshake(c, GNUTLS_SERVER, (s->secur == 1) ? ALGO_HANDSHAKE_DEFAULT : ALGO_HANDSHAKE_3436, NULL, NULL); | |
162 if (ret != 0) { | 167 if (ret != 0) { |
163 char buf[1024]; | 168 char buf[1024]; |
164 snprintf(buf, sizeof(buf), "TLS handshake failed for client '%s', connection aborted.", fd_cnx_getid(c->conn)); | 169 snprintf(buf, sizeof(buf), "TLS handshake failed for connection '%s', connection closed.", fd_cnx_getid(c)); |
165 | 170 |
166 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); | 171 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); |
167 | 172 |
168 goto cleanup; | 173 goto cleanup; |
169 } | 174 } |
170 } else { | 175 } else { |
171 CHECK_FCT_DO( fd_cnx_start_clear(c->conn, 0), goto cleanup ); | 176 CHECK_FCT_DO( fd_cnx_start_clear(c, 0), goto cleanup ); |
172 } | 177 } |
173 | 178 |
174 /* Set the timeout to receive the first message */ | 179 /* Set the timeout to receive the first message */ |
175 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &c->ts), goto fatal_error ); | 180 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), { fatal = 1; goto cleanup; } ); |
176 c->ts.tv_sec += INCNX_TIMEOUT; | 181 ts.tv_sec += INCNX_TIMEOUT; |
177 | 182 |
178 /* Receive the first Diameter message on the connection -- cleanup in case of timeout */ | 183 /* Receive the first Diameter message on the connection -- cleanup in case of timeout */ |
179 CHECK_FCT_DO( fd_cnx_receive(c->conn, &c->ts, &rcv_data.buffer, &rcv_data.length), | 184 CHECK_FCT_DO( fd_cnx_receive(c, &ts, &rcv_data.buffer, &rcv_data.length), |
180 { | 185 { |
181 char buf[1024]; | 186 char buf[1024]; |
182 | 187 |
183 switch (__ret__) { | 188 switch (__ret__) { |
184 case ETIMEDOUT: | 189 case ETIMEDOUT: |
185 snprintf(buf, sizeof(buf), "Client '%s' did not send CER within %ds, connection aborted.", fd_cnx_getid(c->conn), INCNX_TIMEOUT); | 190 snprintf(buf, sizeof(buf), "Client '%s' did not send CER within %ds, connection aborted.", fd_cnx_getid(c), INCNX_TIMEOUT); |
186 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); | 191 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); |
187 break; | 192 break; |
188 | 193 |
189 case ENOTCONN: | 194 case ENOTCONN: |
190 snprintf(buf, sizeof(buf), "Connection from '%s' in error before CER was received.", fd_cnx_getid(c->conn)); | 195 snprintf(buf, sizeof(buf), "Connection from '%s' in error before CER was received.", fd_cnx_getid(c)); |
191 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); | 196 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); |
192 break; | 197 break; |
193 | 198 |
194 default: | 199 default: |
195 snprintf(buf, sizeof(buf), "Connection from '%s': unspecified error, connection aborted.", fd_cnx_getid(c->conn)); | 200 snprintf(buf, sizeof(buf), "Connection from '%s': unspecified error, connection aborted.", fd_cnx_getid(c)); |
196 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); | 201 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); |
197 } | 202 } |
198 goto cleanup; | 203 goto cleanup; |
199 } ); | 204 } ); |
200 | 205 |
201 TRACE_DEBUG(FULL, "Received %zdb from new client '%s'", rcv_data.length, fd_cnx_getid(c->conn)); | 206 TRACE_DEBUG(FULL, "Received %zdb from new client '%s'", rcv_data.length, fd_cnx_getid(c)); |
202 | 207 |
203 pmdl = fd_msg_pmdl_get_inbuf(rcv_data.buffer, rcv_data.length); | 208 pmdl = fd_msg_pmdl_get_inbuf(rcv_data.buffer, rcv_data.length); |
204 | 209 |
205 /* Try parsing this message */ | 210 /* Try parsing this message */ |
206 CHECK_FCT_DO( fd_msg_parse_buffer( &rcv_data.buffer, rcv_data.length, &msg ), | 211 CHECK_FCT_DO( fd_msg_parse_buffer( &rcv_data.buffer, rcv_data.length, &msg ), |
209 goto cleanup; | 214 goto cleanup; |
210 } ); | 215 } ); |
211 | 216 |
212 /* Log incoming message */ | 217 /* Log incoming message */ |
213 fd_hook_associate(msg, pmdl); | 218 fd_hook_associate(msg, pmdl); |
214 fd_hook_call(HOOK_MESSAGE_RECEIVED, msg, NULL, fd_cnx_getid(c->conn), fd_msg_pmdl_get(msg)); | 219 fd_hook_call(HOOK_MESSAGE_RECEIVED, msg, NULL, fd_cnx_getid(c), fd_msg_pmdl_get(msg)); |
215 | 220 |
216 /* We expect a CER, it must parse with our dictionary and rules */ | 221 /* We expect a CER, it must parse with our dictionary and rules */ |
217 CHECK_FCT_DO( fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ), | 222 CHECK_FCT_DO( fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ), |
218 { /* Parsing failed -- trace details */ | 223 { /* Parsing failed -- trace details */ |
219 char buf[1024]; | 224 char buf[1024]; |
220 | 225 |
221 fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, msg, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(msg)); | 226 fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, msg, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(msg)); |
222 | 227 |
223 snprintf(buf, sizeof(buf), "Error parsing CER from '%s', connection aborted.", fd_cnx_getid(c->conn)); | 228 snprintf(buf, sizeof(buf), "Error parsing CER from '%s', connection aborted.", fd_cnx_getid(c)); |
224 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); | 229 fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL); |
225 | 230 |
226 goto cleanup; | 231 goto cleanup; |
227 } ); | 232 } ); |
228 | 233 |
229 /* Now check we received a CER */ | 234 /* Now check we received a CER */ |
230 CHECK_FCT_DO( fd_msg_hdr ( msg, &hdr ), goto fatal_error ); | 235 CHECK_FCT_DO( fd_msg_hdr ( msg, &hdr ), { fatal = 1; goto cleanup; } ); |
231 CHECK_PARAMS_DO( (hdr->msg_appl == 0) && (hdr->msg_flags & CMD_FLAG_REQUEST) && (hdr->msg_code == CC_CAPABILITIES_EXCHANGE), | 236 CHECK_PARAMS_DO( (hdr->msg_appl == 0) && (hdr->msg_flags & CMD_FLAG_REQUEST) && (hdr->msg_code == CC_CAPABILITIES_EXCHANGE), |
232 { /* Parsing failed -- trace details */ | 237 { /* Parsing failed -- trace details */ |
233 char buf[1024]; | 238 char buf[1024]; |
234 snprintf(buf, sizeof(buf), "Expected CER from '%s', received a different message, connection aborted.", fd_cnx_getid(c->conn)); | 239 snprintf(buf, sizeof(buf), "Expected CER from '%s', received a different message, connection aborted.", fd_cnx_getid(c)); |
235 fd_hook_call(HOOK_PEER_CONNECT_FAILED, msg, NULL, buf, NULL); | 240 fd_hook_call(HOOK_PEER_CONNECT_FAILED, msg, NULL, buf, NULL); |
236 goto cleanup; | 241 goto cleanup; |
237 } ); | 242 } ); |
238 | 243 |
239 /* Finally, pass the information to the peers module which will handle it next */ | 244 /* Finally, pass the information to the peers module which will handle it in a separate thread */ |
240 pthread_cleanup_push((void *)fd_cnx_destroy, c->conn); | 245 pthread_cleanup_push((void *)fd_cnx_destroy, c); |
241 pthread_cleanup_push((void *)fd_msg_free, msg); | 246 pthread_cleanup_push((void *)fd_msg_free, msg); |
242 CHECK_FCT_DO( fd_peer_handle_newCER( &msg, &c->conn ), ); | 247 CHECK_FCT_DO( fd_peer_handle_newCER( &msg, &c ), ); |
243 pthread_cleanup_pop(0); | 248 pthread_cleanup_pop(0); |
244 pthread_cleanup_pop(0); | 249 pthread_cleanup_pop(0); |
245 | 250 |
246 /* The end, we cleanup the client structure */ | |
247 cleanup: | 251 cleanup: |
248 /* Unlink the client structure */ | |
249 CHECK_POSIX_DO( pthread_mutex_lock(&s->clients_mtx), goto fatal_error ); | |
250 fd_list_unlink( &c->chain ); | |
251 CHECK_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), goto fatal_error ); | |
252 | |
253 /* Cleanup the parsed message if any */ | 252 /* Cleanup the parsed message if any */ |
254 if (msg) { | 253 if (msg) { |
255 CHECK_FCT_DO( fd_msg_free(msg), /* continue */); | 254 CHECK_FCT_DO( fd_msg_free(msg), /* continue */); |
256 } | 255 msg = NULL; |
257 | 256 } |
258 /* Destroy the connection object if present */ | 257 |
259 if (c->conn) | 258 /* Close the connection if needed */ |
260 fd_cnx_destroy(c->conn); | 259 if (c != NULL) { |
260 fd_cnx_destroy(c); | |
261 c = NULL; | |
262 } | |
261 | 263 |
262 /* Cleanup the received buffer if any */ | 264 /* Cleanup the received buffer if any */ |
263 free(rcv_data.buffer); | 265 free(rcv_data.buffer); |
264 | 266 |
265 /* Detach the thread, cleanup the client structure */ | 267 |
266 pthread_detach(pthread_self()); | 268 if (!fatal) |
267 free(c); | 269 goto next_client; |
270 | |
271 LOG_E("Worker thread exiting."); | |
268 return NULL; | 272 return NULL; |
269 | 273 } |
270 fatal_error: /* This has effect to terminate the daemon */ | |
271 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); | |
272 return NULL; | |
273 } | |
274 | 274 |
275 /* The thread managing a server */ | 275 /* The thread managing a server */ |
276 static void * serv_th(void * arg) | 276 static void * serv_th(void * arg) |
277 { | 277 { |
278 struct server *s = (struct server *)arg; | 278 struct server *s = (struct server *)arg; |
279 | 279 |
280 CHECK_PARAMS_DO(s, goto error); | 280 CHECK_PARAMS_DO(s, goto error); |
281 fd_log_threadname ( fd_cnx_getid(s->conn) ); | 281 fd_log_threadname ( fd_cnx_getid(s->conn) ); |
282 | |
282 set_status(s, RUNNING); | 283 set_status(s, RUNNING); |
283 | 284 |
284 /* Accept incoming connections */ | 285 /* Accept incoming connections */ |
285 CHECK_FCT_DO( fd_cnx_serv_listen(s->conn), goto error ); | 286 CHECK_FCT_DO( fd_cnx_serv_listen(s->conn), goto error ); |
286 | 287 |
287 do { | 288 do { |
288 struct client * c = NULL; | |
289 struct cnxctx * conn = NULL; | 289 struct cnxctx * conn = NULL; |
290 | 290 |
291 /* Wait for a new client or cancel */ | 291 /* Wait for a new client or cancel */ |
292 CHECK_MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), goto error ); | 292 CHECK_MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), break ); |
293 | 293 |
294 /* Create a client structure */ | 294 /* Store this connection in the fifo for processing by the worker pool. Will block when the fifo is full */ |
295 CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto error ); | 295 pthread_cleanup_push((void *)fd_cnx_destroy, conn); |
296 memset(c, 0, sizeof(struct client)); | 296 CHECK_FCT_DO( fd_fifo_post( s->pending, &conn ), break ); |
297 fd_list_init(&c->chain, c); | 297 pthread_cleanup_pop(0); |
298 c->conn = conn; | |
299 | |
300 /* Save the client in the list */ | |
301 CHECK_POSIX_DO( pthread_mutex_lock( &s->clients_mtx ), goto error ); | |
302 fd_list_insert_before(&s->clients, &c->chain); | |
303 CHECK_POSIX_DO( pthread_mutex_unlock( &s->clients_mtx ), goto error ); | |
304 | |
305 /* Start the client thread */ | |
306 CHECK_POSIX_DO( pthread_create( &c->thr, NULL, client_sm, c ), goto error ); | |
307 | 298 |
308 } while (1); | 299 } while (1); |
309 | |
310 error: | 300 error: |
311 if (s) | 301 if (s) |
312 set_status(s, TERMINATED); | 302 set_status(s, TERMINATED); |
313 | 303 |
314 /* Send error signal to the core */ | 304 /* Send error signal to the core */ |
315 LOG_F( "An error occurred in server module! Thread is terminating..."); | 305 LOG_F( "An error occurred in server module! Thread is terminating..."); |
316 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); | 306 CHECK_FCT_DO(fd_core_shutdown(), ); |
317 | 307 |
318 return NULL; | 308 return NULL; |
319 } | 309 } |
320 | 310 |
321 | 311 |
322 /* Create a new server structure */ | 312 /* Create a new server structure */ |
323 static struct server * new_serv( int proto, int secur ) | 313 static struct server * new_serv( int proto, int secur ) |
324 { | 314 { |
325 struct server * new; | 315 struct server * new; |
316 int i; | |
326 | 317 |
327 /* New server structure */ | 318 /* New server structure */ |
328 CHECK_MALLOC_DO( new = malloc(sizeof(struct server)), return NULL ); | 319 CHECK_MALLOC_DO( new = malloc(sizeof(struct server)), return NULL ); |
329 | 320 |
330 memset(new, 0, sizeof(struct server)); | 321 memset(new, 0, sizeof(struct server)); |
331 fd_list_init(&new->chain, new); | 322 fd_list_init(&new->chain, new); |
332 new->proto = proto; | 323 new->proto = proto; |
333 new->secur = secur; | 324 new->secur = secur; |
334 CHECK_POSIX_DO( pthread_mutex_init(&new->clients_mtx, NULL), return NULL ); | 325 |
335 fd_list_init(&new->clients, new); | 326 CHECK_FCT_DO( fd_fifo_new(&new->pending, 5), return NULL); |
327 CHECK_MALLOC_DO( new->workers = calloc( fd_g_config->cnf_thr_srv, sizeof(struct pool_workers) ), return NULL ); | |
328 | |
329 for (i = 0; i < fd_g_config->cnf_thr_srv; i++) { | |
330 /* Create the pool */ | |
331 new->workers[i].s = new; | |
332 new->workers[i].id = i; | |
333 CHECK_POSIX_DO( pthread_create( &new->workers[i].worker, NULL, client_worker, &new->workers[i]), return NULL ); | |
334 } | |
336 | 335 |
337 return new; | 336 return new; |
338 } | 337 } |
339 | 338 |
340 /* Start all the servers */ | 339 /* Start all the servers */ |
476 TRACE_DEBUG(INFO, "Shutting down server sockets..."); | 475 TRACE_DEBUG(INFO, "Shutting down server sockets..."); |
477 | 476 |
478 /* Loop on all servers */ | 477 /* Loop on all servers */ |
479 while (!FD_IS_LIST_EMPTY(&FD_SERVERS)) { | 478 while (!FD_IS_LIST_EMPTY(&FD_SERVERS)) { |
480 struct server * s = (struct server *)(FD_SERVERS.next); | 479 struct server * s = (struct server *)(FD_SERVERS.next); |
481 | 480 int i; |
482 /* Lock client list now */ | 481 struct cnxctx * c; |
483 CHECK_FCT_DO( pthread_mutex_lock(&s->clients_mtx), /* continue anyway */); | |
484 | 482 |
485 /* cancel thread */ | 483 /* cancel thread */ |
486 CHECK_FCT_DO( fd_thr_term(&s->thr), /* continue */); | 484 CHECK_FCT_DO( fd_thr_term(&s->thr), /* continue */); |
487 | 485 |
488 /* destroy server connection context */ | 486 /* destroy server connection context */ |
489 fd_cnx_destroy(s->conn); | 487 fd_cnx_destroy(s->conn); |
490 | 488 |
491 /* cancel and destroy all clients */ | 489 /* cancel and destroy all worker threads */ |
492 while (!FD_IS_LIST_EMPTY(&s->clients)) { | 490 for (i = 0; i < fd_g_config->cnf_thr_srv; i++) { |
493 struct client * c = (struct client *)(s->clients.next); | 491 /* Destroy worker thread */ |
494 | 492 CHECK_FCT_DO( fd_thr_term(&s->workers[i].worker), /* continue */); |
495 /* Destroy client's thread */ | 493 } |
496 CHECK_FCT_DO( fd_thr_term(&c->thr), /* continue */); | 494 free(s->workers); |
497 | 495 |
498 /* Destroy client's connection */ | 496 /* Close any pending connection */ |
499 fd_cnx_destroy(c->conn); | 497 while ( fd_fifo_tryget( s->pending, &c ) == 0 ) { |
500 | 498 fd_cnx_destroy(c); |
501 /* Unlink and free the client */ | 499 } |
502 fd_list_unlink(&c->chain); | 500 CHECK_FCT_DO( fd_fifo_del(&s->pending), ); |
503 free(c); | |
504 } | |
505 /* Unlock & destroy */ | |
506 CHECK_FCT_DO( pthread_mutex_unlock(&s->clients_mtx), /* continue anyway */); | |
507 CHECK_FCT_DO( pthread_mutex_destroy(&s->clients_mtx), /* continue */); | |
508 | 501 |
509 /* Now destroy the server object */ | 502 /* Now destroy the server object */ |
510 fd_list_unlink(&s->chain); | 503 fd_list_unlink(&s->chain); |
511 free(s); | 504 free(s); |
512 } | 505 } |