aboutsummaryrefslogtreecommitdiff
path: root/src/util/server.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-01-15 16:36:30 +0000
committerChristian Grothoff <christian@grothoff.org>2010-01-15 16:36:30 +0000
commit2ea6ea66581947fce7820357f9a260896ffd4199 (patch)
tree18f2cb95bdc77b2978cc8e53de10a186aa37ab72 /src/util/server.c
parenta257f028184102b04995c6774f065200919a3dff (diff)
downloadgnunet-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.c165
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 *
406GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched, 430GNUNET_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;