diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-01-15 16:36:30 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-01-15 16:36:30 +0000 |
commit | 2ea6ea66581947fce7820357f9a260896ffd4199 (patch) | |
tree | 18f2cb95bdc77b2978cc8e53de10a186aa37ab72 /src/util/server.c | |
parent | a257f028184102b04995c6774f065200919a3dff (diff) | |
download | gnunet-2ea6ea66581947fce7820357f9a260896ffd4199.tar.gz gnunet-2ea6ea66581947fce7820357f9a260896ffd4199.zip |
making code work better with dual-stack, preparing for triple-stack
Diffstat (limited to 'src/util/server.c')
-rw-r--r-- | src/util/server.c | 165 |
1 files changed, 111 insertions, 54 deletions
diff --git a/src/util/server.c b/src/util/server.c index 72eceac44..036c8a441 100644 --- a/src/util/server.c +++ b/src/util/server.c | |||
@@ -112,6 +112,12 @@ struct GNUNET_SERVER_Handle | |||
112 | void *access_cls; | 112 | void *access_cls; |
113 | 113 | ||
114 | /** | 114 | /** |
115 | * NULL-terminated array of sockets used to listen for new | ||
116 | * connections. | ||
117 | */ | ||
118 | struct GNUNET_NETWORK_Handle **listen_sockets; | ||
119 | |||
120 | /** | ||
115 | * After how long should an idle connection time | 121 | * After how long should an idle connection time |
116 | * out (on write). | 122 | * out (on write). |
117 | */ | 123 | */ |
@@ -123,12 +129,6 @@ struct GNUNET_SERVER_Handle | |||
123 | size_t maxbuf; | 129 | size_t maxbuf; |
124 | 130 | ||
125 | /** | 131 | /** |
126 | * Socket used to listen for new connections. Set to | ||
127 | * "-1" by GNUNET_SERVER_destroy to initiate shutdown. | ||
128 | */ | ||
129 | struct GNUNET_NETWORK_Handle *listen_socket; | ||
130 | |||
131 | /** | ||
132 | * Task scheduled to do the listening. | 132 | * Task scheduled to do the listening. |
133 | */ | 133 | */ |
134 | GNUNET_SCHEDULER_TaskIdentifier listen_task; | 134 | GNUNET_SCHEDULER_TaskIdentifier listen_task; |
@@ -265,8 +265,7 @@ struct GNUNET_SERVER_Client | |||
265 | 265 | ||
266 | 266 | ||
267 | /** | 267 | /** |
268 | * Scheduler says our listen socket is ready. | 268 | * Scheduler says our listen socket is ready. Process it! |
269 | * Process it! | ||
270 | * | 269 | * |
271 | * @param cls handle to our server for which we are processing the listen | 270 | * @param cls handle to our server for which we are processing the listen |
272 | * socket | 271 | * socket |
@@ -280,10 +279,13 @@ process_listen_socket (void *cls, | |||
280 | struct GNUNET_CONNECTION_Handle *sock; | 279 | struct GNUNET_CONNECTION_Handle *sock; |
281 | struct GNUNET_SERVER_Client *client; | 280 | struct GNUNET_SERVER_Client *client; |
282 | struct GNUNET_NETWORK_FDSet *r; | 281 | struct GNUNET_NETWORK_FDSet *r; |
282 | unsigned int i; | ||
283 | 283 | ||
284 | server->listen_task = GNUNET_SCHEDULER_NO_TASK; | 284 | server->listen_task = GNUNET_SCHEDULER_NO_TASK; |
285 | r = GNUNET_NETWORK_fdset_create (); | 285 | r = GNUNET_NETWORK_fdset_create (); |
286 | GNUNET_NETWORK_fdset_set (r, server->listen_socket); | 286 | i = 0; |
287 | while (NULL != server->listen_sockets[i]) | ||
288 | GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]); | ||
287 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 289 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) |
288 | { | 290 | { |
289 | /* ignore shutdown, someone else will take care of it! */ | 291 | /* ignore shutdown, someone else will take care of it! */ |
@@ -297,27 +299,33 @@ process_listen_socket (void *cls, | |||
297 | GNUNET_NETWORK_fdset_destroy (r); | 299 | GNUNET_NETWORK_fdset_destroy (r); |
298 | return; | 300 | return; |
299 | } | 301 | } |
300 | GNUNET_assert (GNUNET_NETWORK_fdset_isset | 302 | i = 0; |
301 | (tc->read_ready, server->listen_socket)); | 303 | while (NULL != server->listen_sockets[i]) |
302 | sock = | ||
303 | GNUNET_CONNECTION_create_from_accept (tc->sched, server->access, | ||
304 | server->access_cls, | ||
305 | server->listen_socket, | ||
306 | server->maxbuf); | ||
307 | if (sock != NULL) | ||
308 | { | 304 | { |
305 | if (GNUNET_NETWORK_fdset_isset (tc->read_ready, server->listen_sockets[i])) | ||
306 | { | ||
307 | sock = | ||
308 | GNUNET_CONNECTION_create_from_accept (tc->sched, server->access, | ||
309 | server->access_cls, | ||
310 | server->listen_sockets[i], | ||
311 | server->maxbuf); | ||
312 | if (sock != NULL) | ||
313 | { | ||
309 | #if DEBUG_SERVER | 314 | #if DEBUG_SERVER |
310 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 315 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
311 | "Server accepted incoming connection.\n"); | 316 | "Server accepted incoming connection.\n"); |
312 | #endif | 317 | #endif |
313 | client = GNUNET_SERVER_connect_socket (server, sock); | 318 | client = GNUNET_SERVER_connect_socket (server, sock); |
314 | GNUNET_CONNECTION_ignore_shutdown (sock, server->clients_ignore_shutdown); | 319 | GNUNET_CONNECTION_ignore_shutdown (sock, server->clients_ignore_shutdown); |
315 | /* decrement reference count, we don't keep "client" alive */ | 320 | /* decrement reference count, we don't keep "client" alive */ |
316 | GNUNET_SERVER_client_drop (client); | 321 | GNUNET_SERVER_client_drop (client); |
317 | } | 322 | } |
323 | } | ||
324 | i++; | ||
325 | } | ||
318 | /* listen for more! */ | 326 | /* listen for more! */ |
319 | server->listen_task = GNUNET_SCHEDULER_add_select (server->sched, | 327 | server->listen_task = GNUNET_SCHEDULER_add_select (server->sched, |
320 | GNUNET_SCHEDULER_PRIORITY_HIGH, | 328 | GNUNET_SCHEDULER_PRIORITY_HIGH, |
321 | GNUNET_SCHEDULER_NO_TASK, | 329 | GNUNET_SCHEDULER_NO_TASK, |
322 | GNUNET_TIME_UNIT_FOREVER_REL, | 330 | GNUNET_TIME_UNIT_FOREVER_REL, |
323 | r, NULL, | 331 | r, NULL, |
@@ -338,6 +346,7 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) | |||
338 | const static int on = 1; | 346 | const static int on = 1; |
339 | struct GNUNET_NETWORK_Handle *sock; | 347 | struct GNUNET_NETWORK_Handle *sock; |
340 | uint16_t port; | 348 | uint16_t port; |
349 | int eno; | ||
341 | 350 | ||
342 | switch (serverAddr->sa_family) | 351 | switch (serverAddr->sa_family) |
343 | { | 352 | { |
@@ -348,39 +357,55 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) | |||
348 | port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port); | 357 | port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port); |
349 | break; | 358 | break; |
350 | default: | 359 | default: |
351 | GNUNET_break (0); | 360 | port = 0; |
352 | return NULL; | 361 | break; |
353 | } | 362 | } |
354 | sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0); | 363 | sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0); |
355 | if (NULL == sock) | 364 | if (NULL == sock) |
356 | { | 365 | { |
357 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); | 366 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); |
367 | errno = 0; | ||
358 | return NULL; | 368 | return NULL; |
359 | } | 369 | } |
360 | if (GNUNET_NETWORK_socket_setsockopt | 370 | if ( (port != 0) && |
361 | (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) | 371 | (GNUNET_NETWORK_socket_setsockopt |
372 | (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)) | ||
362 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | 373 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
363 | "setsockopt"); | 374 | "setsockopt"); |
364 | /* bind the socket */ | 375 | /* bind the socket */ |
365 | if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK) | 376 | if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK) |
366 | { | 377 | { |
367 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); | 378 | eno = errno; |
368 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 379 | if (errno != EADDRINUSE) |
369 | _ | 380 | { |
370 | ("`%s' failed for port %d. Is the service already running?\n"), | 381 | /* we don't log 'EADDRINUSE' here since an IPv4 bind may |
371 | "bind", port); | 382 | fail if we already took the port on IPv6; if both IPv4 and |
383 | IPv6 binds fail, then our caller will log using the | ||
384 | errno preserved in 'eno' */ | ||
385 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); | ||
386 | if (port != 0) | ||
387 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
388 | _ | ||
389 | ("`%s' failed for port %d (%s).\n"), | ||
390 | "bind", port, | ||
391 | (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6"); | ||
392 | eno = 0; | ||
393 | } | ||
372 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | 394 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); |
395 | errno = eno; | ||
373 | return NULL; | 396 | return NULL; |
374 | } | 397 | } |
375 | if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5)) | 398 | if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5)) |
376 | { | 399 | { |
377 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); | 400 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); |
378 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | 401 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); |
402 | errno = 0; | ||
379 | return NULL; | 403 | return NULL; |
380 | } | 404 | } |
381 | #if DEBUG_SERVER | 405 | #if DEBUG_SERVER |
382 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 406 | if (port != 0) |
383 | "Server starts to listen on port %u.\n", port); | 407 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
408 | "Server starts to listen on port %u.\n", port); | ||
384 | #endif | 409 | #endif |
385 | return sock; | 410 | return sock; |
386 | } | 411 | } |
@@ -392,8 +417,7 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) | |||
392 | * @param sched scheduler to use | 417 | * @param sched scheduler to use |
393 | * @param access function for access control | 418 | * @param access function for access control |
394 | * @param access_cls closure for access | 419 | * @param access_cls closure for access |
395 | * @param serverAddr address to listen on (including port), use NULL | 420 | * @param serverAddr address to listen on (including port), NULL terminated array |
396 | * for internal server (no listening) | ||
397 | * @param socklen length of serverAddr | 421 | * @param socklen length of serverAddr |
398 | * @param maxbuf maximum write buffer size for accepted sockets | 422 | * @param maxbuf maximum write buffer size for accepted sockets |
399 | * @param idle_timeout after how long should we timeout idle connections? | 423 | * @param idle_timeout after how long should we timeout idle connections? |
@@ -406,35 +430,61 @@ struct GNUNET_SERVER_Handle * | |||
406 | GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched, | 430 | GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched, |
407 | GNUNET_CONNECTION_AccessCheck access, | 431 | GNUNET_CONNECTION_AccessCheck access, |
408 | void *access_cls, | 432 | void *access_cls, |
409 | const struct sockaddr *serverAddr, | 433 | struct sockaddr *const *serverAddr, |
410 | socklen_t socklen, | 434 | const socklen_t *socklen, |
411 | size_t maxbuf, | 435 | size_t maxbuf, |
412 | struct GNUNET_TIME_Relative | 436 | struct GNUNET_TIME_Relative |
413 | idle_timeout, int require_found) | 437 | idle_timeout, |
438 | int require_found) | ||
414 | { | 439 | { |
415 | struct GNUNET_SERVER_Handle *ret; | 440 | struct GNUNET_SERVER_Handle *ret; |
416 | struct GNUNET_NETWORK_Handle *lsock; | 441 | struct GNUNET_NETWORK_Handle **lsocks; |
417 | struct GNUNET_NETWORK_FDSet *r; | 442 | struct GNUNET_NETWORK_FDSet *r; |
443 | unsigned int i; | ||
444 | unsigned int j; | ||
418 | 445 | ||
419 | lsock = NULL; | 446 | i = 0; |
420 | if (serverAddr != NULL) | 447 | while (serverAddr[i] != NULL) |
448 | i++; | ||
449 | if (i > 0) | ||
450 | { | ||
451 | lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle*) * (i+1)); | ||
452 | i = 0; | ||
453 | j = 0; | ||
454 | while (serverAddr[i] != NULL) | ||
455 | { | ||
456 | lsocks[j] = open_listen_socket (serverAddr[i], socklen[i]); | ||
457 | if (lsocks[j] != NULL) | ||
458 | j++; | ||
459 | i++; | ||
460 | } | ||
461 | if (j == 0) | ||
462 | { | ||
463 | if (errno != 0) | ||
464 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); | ||
465 | GNUNET_free (lsocks); | ||
466 | lsocks = NULL; | ||
467 | } | ||
468 | } | ||
469 | else | ||
421 | { | 470 | { |
422 | lsock = open_listen_socket (serverAddr, socklen); | 471 | lsocks = NULL; |
423 | if (lsock == NULL) | ||
424 | return NULL; | ||
425 | } | 472 | } |
426 | ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle)); | 473 | ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle)); |
427 | ret->sched = sched; | 474 | ret->sched = sched; |
428 | ret->maxbuf = maxbuf; | 475 | ret->maxbuf = maxbuf; |
429 | ret->idle_timeout = idle_timeout; | 476 | ret->idle_timeout = idle_timeout; |
430 | ret->listen_socket = lsock; | 477 | ret->listen_sockets = lsocks; |
431 | ret->access = access; | 478 | ret->access = access; |
432 | ret->access_cls = access_cls; | 479 | ret->access_cls = access_cls; |
433 | ret->require_found = require_found; | 480 | ret->require_found = require_found; |
434 | if (lsock != NULL) | 481 | if (lsocks != NULL) |
435 | { | 482 | { |
483 | |||
436 | r = GNUNET_NETWORK_fdset_create (); | 484 | r = GNUNET_NETWORK_fdset_create (); |
437 | GNUNET_NETWORK_fdset_set (r, ret->listen_socket); | 485 | i = 0; |
486 | while (NULL != ret->listen_sockets[i]) | ||
487 | GNUNET_NETWORK_fdset_set (r, ret->listen_sockets[i++]); | ||
438 | ret->listen_task = GNUNET_SCHEDULER_add_select (sched, | 488 | ret->listen_task = GNUNET_SCHEDULER_add_select (sched, |
439 | GNUNET_SCHEDULER_PRIORITY_HIGH, | 489 | GNUNET_SCHEDULER_PRIORITY_HIGH, |
440 | GNUNET_SCHEDULER_NO_TASK, | 490 | GNUNET_SCHEDULER_NO_TASK, |
@@ -457,6 +507,7 @@ GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) | |||
457 | struct GNUNET_SERVER_Client *pos; | 507 | struct GNUNET_SERVER_Client *pos; |
458 | struct HandlerList *hpos; | 508 | struct HandlerList *hpos; |
459 | struct NotifyList *npos; | 509 | struct NotifyList *npos; |
510 | unsigned int i; | ||
460 | 511 | ||
461 | #if DEBUG_SERVER | 512 | #if DEBUG_SERVER |
462 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n"); | 513 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n"); |
@@ -466,8 +517,14 @@ GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) | |||
466 | GNUNET_SCHEDULER_cancel (s->sched, s->listen_task); | 517 | GNUNET_SCHEDULER_cancel (s->sched, s->listen_task); |
467 | s->listen_task = GNUNET_SCHEDULER_NO_TASK; | 518 | s->listen_task = GNUNET_SCHEDULER_NO_TASK; |
468 | } | 519 | } |
469 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s->listen_socket)); | 520 | if (s->listen_sockets != NULL) |
470 | s->listen_socket = NULL; | 521 | { |
522 | i = 0; | ||
523 | while (s->listen_sockets[i] != NULL) | ||
524 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s->listen_sockets[i++])); | ||
525 | GNUNET_free (s->listen_sockets); | ||
526 | s->listen_sockets = NULL; | ||
527 | } | ||
471 | while (s->clients != NULL) | 528 | while (s->clients != NULL) |
472 | { | 529 | { |
473 | pos = s->clients; | 530 | pos = s->clients; |