X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fservice.c;h=25a9b08dc3ef3032341491c1bd01346d4878684f;hb=f1252a5b29869c7641c348514fe16d913b2d26ea;hp=494384b20b4162059b49ada82d056e77f81c25e8;hpb=b8578fedf6a5553b25d3577664cd36eaaa1935b2;p=oweals%2Fgnunet.git diff --git a/src/util/service.c b/src/util/service.c index 494384b20..25a9b08dc 100644 --- a/src/util/service.c +++ b/src/util/service.c @@ -430,12 +430,8 @@ struct GNUNET_SERVICE_Context struct GNUNET_SERVER_Handle *server; /** - * Scheduler for the server. - */ - struct GNUNET_SCHEDULER_Handle *sched; - - /** - * NULL-terminated array of addresses to bind to. + * NULL-terminated array of addresses to bind to, NULL if we got pre-bound + * listen sockets. */ struct sockaddr **addrs; @@ -483,14 +479,19 @@ struct GNUNET_SERVICE_Context struct GNUNET_SERVER_MessageHandler *my_handlers; /** - * Idle timeout for server. + * Array of the lengths of the entries in addrs. */ - struct GNUNET_TIME_Relative timeout; + socklen_t * addrlens; + + /** + * NULL-terminated array of listen sockets we should take over. + */ + struct GNUNET_NETWORK_Handle **lsocks; /** - * Maximum buffer size for the server. + * Idle timeout for server. */ - size_t maxbuf; + struct GNUNET_TIME_Relative timeout; /** * Overall success/failure of the service start. @@ -510,21 +511,11 @@ struct GNUNET_SERVICE_Context */ int require_found; - /** - * Can clients ask us to initiate a shutdown? - */ - int allow_shutdown; - /** * Our options. */ enum GNUNET_SERVICE_Options options; - /** - * Array of the lengths of the entries in addrs. - */ - socklen_t * addrlens; - }; @@ -570,35 +561,6 @@ handle_test (void *cls, } -/** - * Handler for SHUTDOWN message. - * - * @param cls closure (refers to service) - * @param client identification of the client - * @param message the actual message - */ -static void -handle_shutdown (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_SERVICE_Context *service = cls; - if (!service->allow_shutdown) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Received shutdown request, but configured to ignore!\n")); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Initiating shutdown as requested by client.\n")); - GNUNET_assert (service->sched != NULL); - GNUNET_SCHEDULER_shutdown (service->sched); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - /** * Default handlers for all services. Will be copied and the * "callback_cls" fields will be replaced with the specific service @@ -607,8 +569,6 @@ handle_shutdown (void *cls, static const struct GNUNET_SERVER_MessageHandler defhandlers[] = { {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST, sizeof (struct GNUNET_MessageHeader)}, - {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_SHUTDOWN, - sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; @@ -648,6 +608,10 @@ check_access (void *cls, const struct sockaddr *addr, socklen_t addrlen) && ((sctx->v6_denied == NULL) || (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); break; + case AF_UNIX: + /* FIXME: support checking UID/GID in the future... */ + ret = GNUNET_OK; /* always OK for now */ + break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"), addr->sa_family); @@ -738,89 +702,103 @@ process_acl6 (struct IPv6NetworkSet **ret, return GNUNET_OK; } - /** - * Setup addr, addrlen, maxbuf, idle_timeout - * based on configuration! + * Add the given UNIX domain path as an address to the + * list (as the first entry). * - * Configuration must specify a "PORT". It may - * specify: - * - TIMEOUT (after how many ms does an inactive service timeout); - * - MAXBUF (maximum incoming message size supported) - * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) - * - ALLOW_SHUTDOWN (allow clients to shutdown this service) - * - BINDTO (hostname or IP address to bind to, otherwise we take everything) - * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) - * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets) - * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) - * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) + * @param saddrs array to update + * @param saddrlens where to store the address length + * @param unixpath path to add + */ +static void +add_unixpath (struct sockaddr **saddrs, + socklen_t *saddrlens, + const char *unixpath) +{ +#ifdef AF_UNIX + struct sockaddr_un *un; + size_t slen; + + un = GNUNET_malloc (sizeof (struct sockaddr_un)); + un->sun_family = AF_UNIX; + slen = strlen (unixpath) + 1; + if (slen >= sizeof (un->sun_path)) + slen = sizeof (un->sun_path) - 1; + memcpy (un->sun_path, + unixpath, + slen); + un->sun_path[slen] = '\0'; +#if LINUX + un->sun_path[0] = '\0'; + slen = sizeof (struct sockaddr_un); +#else + slen += sizeof (sa_family_t); +#endif + *saddrs = (struct sockaddr*) un; + *saddrlens = slen; +#else + /* this function should never be called + unless AF_UNIX is defined! */ + GNUNET_assert (0); +#endif +} + + +/** + * Get the list of addresses that a server for the given service + * should bind to. * - * @return GNUNET_OK if configuration succeeded + * @param serviceName name of the service + * @param cfg configuration (which specifies the addresses) + * @param addrs set (call by reference) to an array of pointers to the + * addresses the server should bind to and listen on; the + * array will be NULL-terminated (on success) + * @param addr_lens set (call by reference) to an array of the lengths + * of the respective 'struct sockaddr' struct in the 'addrs' + * array (on success) + * @return number of addresses found on success, + * GNUNET_SYSERR if the configuration + * did not specify reasonable finding information or + * if it specified a hostname that could not be resolved; + * GNUNET_NO if the number of addresses configured is + * zero (in this case, '*addrs' and '*addr_lens' will be + * set to NULL). */ -static int -setup_service (struct GNUNET_SERVICE_Context *sctx) +int +GNUNET_SERVICE_get_server_addresses (const char *serviceName, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct sockaddr ***addrs, + socklen_t **addr_lens) { - unsigned long long maxbuf; - struct GNUNET_TIME_Relative idleout; - char *hostname; - unsigned long long port; int disablev6; + struct GNUNET_NETWORK_Handle *desc; + unsigned long long port; + char *unixpath; struct addrinfo hints; struct addrinfo *res; struct addrinfo *pos; struct addrinfo *next; - int ret; - int tolerant; unsigned int i; - struct GNUNET_NETWORK_Handle *desc; - - if (GNUNET_CONFIGURATION_have_value (sctx->cfg, - sctx->serviceName, "TIMEOUT")) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (sctx->cfg, - sctx->serviceName, - "TIMEOUT", &idleout)) - return GNUNET_SYSERR; + int resi; + int ret; + struct sockaddr **saddrs; + socklen_t *saddrlens; + char *hostname; - sctx->timeout = idleout; - } - else - sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - if (GNUNET_CONFIGURATION_have_value (sctx->cfg, - sctx->serviceName, "MAXBUF")) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (sctx->cfg, - sctx->serviceName, - "MAXBUF", &maxbuf)) - return GNUNET_SYSERR; - } - else - maxbuf = GNUNET_SERVER_MAX_MESSAGE_SIZE; - if (GNUNET_CONFIGURATION_have_value (sctx->cfg, - sctx->serviceName, "DISABLEV6")) + *addrs = NULL; + *addr_lens = NULL; + desc = NULL; + if (GNUNET_CONFIGURATION_have_value (cfg, + serviceName, "DISABLEV6")) { if (GNUNET_SYSERR == - (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, - sctx-> - serviceName, + (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg, + serviceName, "DISABLEV6"))) return GNUNET_SYSERR; } else disablev6 = GNUNET_NO; - if (GNUNET_CONFIGURATION_have_value (sctx->cfg, - sctx->serviceName, "ALLOW_SHUTDOWN")) - { - if (GNUNET_SYSERR == - (sctx->allow_shutdown = - GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName, - "ALLOW_SHUTDOWN"))) - return GNUNET_SYSERR; - } - else - sctx->allow_shutdown = GNUNET_NO; if (!disablev6) { @@ -837,62 +815,126 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), - sctx->serviceName, STRERROR (errno)); + serviceName, STRERROR (errno)); disablev6 = GNUNET_YES; } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); + desc = NULL; } } + port = 0; + if (GNUNET_CONFIGURATION_have_value (cfg, + serviceName, "PORT")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, + serviceName, + "PORT", + &port)); + if (port > 65535) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Require valid port number for service `%s' in configuration!\n"), + serviceName); + return GNUNET_SYSERR; + } + } - - if (GNUNET_CONFIGURATION_have_value (sctx->cfg, - sctx->serviceName, "TOLERANT")) + if (GNUNET_CONFIGURATION_have_value (cfg, + serviceName, "BINDTO")) { - if (GNUNET_SYSERR == - (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, - sctx->serviceName, - "TOLERANT"))) - return GNUNET_SYSERR; + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, + serviceName, + "BINDTO", + &hostname)); } else - tolerant = GNUNET_NO; - sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; + hostname = NULL; +#ifdef AF_UNIX + if (GNUNET_CONFIGURATION_have_value (cfg, + serviceName, "UNIXPATH")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, + serviceName, + "UNIXPATH", + &unixpath)); + + /* probe UNIX support */ + struct sockaddr_un s_un; + if (strlen(unixpath) >= sizeof(s_un.sun_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("UNIXPATH `%s' too long, maximum length is %llu\n"),unixpath, sizeof(s_un.sun_path)); + GNUNET_free_non_null (hostname); + GNUNET_free (unixpath); + return GNUNET_SYSERR; + } + + desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); + if (NULL == desc) + { + if ((errno == ENOBUFS) || + (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); + GNUNET_free_non_null (hostname); + GNUNET_free (unixpath); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), + serviceName, STRERROR (errno)); + GNUNET_free (unixpath); + unixpath = NULL; + } + else + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); + desc = NULL; + } + } + else + unixpath = NULL; +#else + unixpath = NULL; +#endif - if ((GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (sctx->cfg, - sctx->serviceName, - "PORT", - &port)) || (port > 65535)) + if ( (port == 0) && + (unixpath == NULL) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ - ("Require valid port number for service `%s' in configuration!\n"), - sctx->serviceName); + _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), + serviceName); + GNUNET_free_non_null(hostname); return GNUNET_SYSERR; } - if (GNUNET_CONFIGURATION_have_value (sctx->cfg, - sctx->serviceName, "BINDTO")) + if (port == 0) { - GNUNET_break (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (sctx->cfg, - sctx->serviceName, - "BINDTO", - &hostname)); + saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr*)); + saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); + add_unixpath (saddrs, saddrlens, unixpath); + GNUNET_free_non_null (unixpath); + GNUNET_free_non_null(hostname); + *addrs = saddrs; + *addr_lens = saddrlens; + return 1; } - else - hostname = NULL; - + if (hostname != NULL) { #if DEBUG_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolving `%s' since that is where `%s' will bind to.\n", hostname, - sctx->serviceName); + serviceName); #endif memset (&hints, 0, sizeof (struct addrinfo)); if (disablev6) @@ -904,6 +946,7 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) _("Failed to resolve `%s': %s\n"), hostname, gai_strerror (ret)); GNUNET_free (hostname); + GNUNET_free (unixpath); return GNUNET_SYSERR; } next = res; @@ -922,11 +965,20 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) disablev6 ? "IPv4 " : "", hostname); freeaddrinfo (res); GNUNET_free (hostname); + GNUNET_free (unixpath); return GNUNET_SYSERR; } - sctx->addrs = GNUNET_malloc ((i+1) * sizeof(struct sockaddr*)); - sctx->addrlens = GNUNET_malloc ((i+1) * sizeof (socklen_t)); + resi = i; + if (NULL != unixpath) + resi++; + saddrs = GNUNET_malloc ((resi+1) * sizeof(struct sockaddr*)); + saddrlens = GNUNET_malloc ((resi+1) * sizeof (socklen_t)); i = 0; + if (NULL != unixpath) + { + add_unixpath (saddrs, saddrlens, unixpath); + i++; + } next = res; while (NULL != (pos = next)) { @@ -936,26 +988,26 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) #if DEBUG_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", - sctx->serviceName, + serviceName, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); #endif if (pos->ai_family == AF_INET) { GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in)); - sctx->addrlens[i] = pos->ai_addrlen; - sctx->addrs[i] = GNUNET_malloc (sctx->addrlens[i]); - memcpy (sctx->addrs[i], pos->ai_addr, sctx->addrlens[i]); - ((struct sockaddr_in *) sctx->addrs[i])->sin_port = htons (port); + saddrlens[i] = pos->ai_addrlen; + saddrs[i] = GNUNET_malloc (saddrlens[i]); + memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { GNUNET_assert (pos->ai_family == AF_INET6); GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6)); - sctx->addrlens[i] = pos->ai_addrlen; - sctx->addrs[i] = GNUNET_malloc (sctx->addrlens[i]); - memcpy (sctx->addrs[i], pos->ai_addr, sctx->addrlens[i]); - ((struct sockaddr_in6 *) sctx->addrs[i])->sin6_port = htons (port); + saddrlens[i] = pos->ai_addrlen; + saddrs[i] = GNUNET_malloc (saddrlens[i]); + memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); + ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); } i++; } @@ -968,49 +1020,173 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) if (disablev6) { /* V4-only */ - sctx->addrs = GNUNET_malloc (2 * sizeof(struct sockaddr*)); - sctx->addrlens = GNUNET_malloc (2 * sizeof (socklen_t)); - sctx->addrlens[0] = sizeof (struct sockaddr_in); - sctx->addrs[0] = GNUNET_malloc (sctx->addrlens[0]); + resi = 1; + if (NULL != unixpath) + resi++; + i = 0; + saddrs = GNUNET_malloc ((resi+1) * sizeof(struct sockaddr*)); + saddrlens = GNUNET_malloc ((resi+1) * sizeof (socklen_t)); + if (NULL != unixpath) + { + add_unixpath (saddrs, saddrlens, unixpath); + i++; + } + saddrlens[i] = sizeof (struct sockaddr_in); + saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN - ((struct sockaddr_in *) sctx->addrs[0])->sin_len = sctx->addrlens[0]; + ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; #endif - ((struct sockaddr_in *) sctx->addrs[0])->sin_family = AF_INET; - ((struct sockaddr_in *) sctx->addrs[0])->sin_port = htons (port); + ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { /* dual stack */ - sctx->addrs = GNUNET_malloc (3 * sizeof(struct sockaddr*)); - sctx->addrlens = GNUNET_malloc (3 * sizeof (socklen_t)); - - sctx->addrlens[0] = sizeof (struct sockaddr_in6); - sctx->addrs[0] = GNUNET_malloc (sctx->addrlens[0]); + resi = 2; + if (NULL != unixpath) + resi++; + saddrs = GNUNET_malloc ((resi+1) * sizeof(struct sockaddr*)); + saddrlens = GNUNET_malloc ((resi+1) * sizeof (socklen_t)); + i = 0; + if (NULL != unixpath) + { + add_unixpath (saddrs, saddrlens, unixpath); + i++; + } + saddrlens[i] = sizeof (struct sockaddr_in6); + saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN - ((struct sockaddr_in6 *) sctx->addrs[0])->sin6_len = sctx->addrlens[0]; + ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; #endif - ((struct sockaddr_in6 *) sctx->addrs[0])->sin6_family = AF_INET6; - ((struct sockaddr_in6 *) sctx->addrs[0])->sin6_port = htons (port); - - sctx->addrlens[1] = sizeof (struct sockaddr_in); - sctx->addrs[1] = GNUNET_malloc (sctx->addrlens[1]); + ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; + ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); + i++; + saddrlens[i] = sizeof (struct sockaddr_in); + saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN - ((struct sockaddr_in *) sctx->addrs[1])->sin_len = sctx->addrlens[1]; + ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; #endif - ((struct sockaddr_in *) sctx->addrs[1])->sin_family = AF_INET; - ((struct sockaddr_in *) sctx->addrs[1])->sin_port = htons (port); - + ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } } - sctx->maxbuf = (size_t) maxbuf; - if (sctx->maxbuf != maxbuf) + GNUNET_free_non_null (unixpath); + *addrs = saddrs; + *addr_lens = saddrlens; + return resi; +} + + +/** + * Setup addr, addrlen, idle_timeout + * based on configuration! + * + * Configuration may specify: + * - PORT (where to bind to for TCP) + * - UNIXPATH (where to bind to for UNIX domain sockets) + * - TIMEOUT (after how many ms does an inactive service timeout); + * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) + * - BINDTO (hostname or IP address to bind to, otherwise we take everything) + * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) + * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets) + * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) + * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) + * + * @return GNUNET_OK if configuration succeeded + */ +static int +setup_service (struct GNUNET_SERVICE_Context *sctx) +{ + struct GNUNET_TIME_Relative idleout; + int tolerant; +#ifndef MINGW + const char *lpid; + unsigned int pid; + const char *nfds; + unsigned int cnt; + int flags; +#endif + + if (GNUNET_CONFIGURATION_have_value (sctx->cfg, + sctx->serviceName, "TIMEOUT")) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ - ("Value in configuration for `%s' and service `%s' too large!\n"), - "MAXBUF", sctx->serviceName); - return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (sctx->cfg, + sctx->serviceName, + "TIMEOUT", &idleout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Specified value for `%s' of service `%s' is invalid\n"), + "TIMEOUT", + sctx->serviceName); + return GNUNET_SYSERR; + } + sctx->timeout = idleout; + } + else + sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + + if (GNUNET_CONFIGURATION_have_value (sctx->cfg, + sctx->serviceName, "TOLERANT")) + { + if (GNUNET_SYSERR == + (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, + sctx->serviceName, + "TOLERANT"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Specified value for `%s' of service `%s' is invalid\n"), + "TOLERANT", + sctx->serviceName); + return GNUNET_SYSERR; + } } + else + tolerant = GNUNET_NO; + +#ifndef MINGW + errno = 0; + if ( (NULL != (lpid = getenv ("LISTEN_PID"))) && + (1 == sscanf (lpid, "%u", &pid)) && + (getpid () == (pid_t) pid) && + (NULL != (nfds = getenv ("LISTEN_FDS"))) && + (1 == sscanf (nfds, "%u", &cnt)) && + (cnt > 0) && + (cnt < FD_SETSIZE) && + (cnt + 4 < FD_SETSIZE) ) + { + sctx->lsocks = GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle*) * (cnt+1)); + while (0 < cnt--) + { + flags = fcntl (3 + cnt, F_GETFD); + if ( (flags < 0) || + (0 != (flags & FD_CLOEXEC)) || + (NULL == (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access pre-bound socket %u, will try to bind myself\n"), + (unsigned int) 3 +cnt); + cnt++; + while (sctx->lsocks[cnt] != NULL) + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++])); + GNUNET_free (sctx->lsocks); + sctx->lsocks = NULL; + break; + } + } + unsetenv ("LISTEN_PID"); + unsetenv ("LISTEN_FDS"); + } +#endif + + if ( (sctx->lsocks == NULL) && + (GNUNET_SYSERR == + GNUNET_SERVICE_get_server_addresses (sctx->serviceName, + sctx->cfg, + &sctx->addrs, + &sctx->addrlens)) ) + return GNUNET_SYSERR; + sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); @@ -1119,24 +1295,30 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct GNUNET_SERVICE_Context *sctx = cls; unsigned int i; - sctx->sched = tc->sched; - sctx->server = GNUNET_SERVER_create (tc->sched, - &check_access, - sctx, - sctx->addrs, - sctx->addrlens, - sctx->maxbuf, - sctx->timeout, sctx->require_found); + if (sctx->lsocks != NULL) + sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, + sctx, + sctx->lsocks, + sctx->timeout, sctx->require_found); + else + sctx->server = GNUNET_SERVER_create (&check_access, + sctx, + sctx->addrs, + sctx->addrlens, + sctx->timeout, sctx->require_found); if (sctx->server == NULL) { - i = 0; - while (sctx->addrs[i] != NULL) + if (sctx->addrs != NULL) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Failed to start `%s' at `%s'\n"), - sctx->serviceName, - GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); - i++; + i = 0; + while (sctx->addrs[i] != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Failed to start `%s' at `%s'\n"), + sctx->serviceName, + GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); + i++; + } } sctx->ret = GNUNET_SYSERR; return; @@ -1145,8 +1327,7 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { /* install a task that will kill the server process if the scheduler ever gets a shutdown signal */ - GNUNET_SCHEDULER_add_delayed (tc->sched, - GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, sctx->server); } sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); @@ -1162,16 +1343,19 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) sctx->ready_confirm_fd = -1; write_pid_file (sctx, getpid ()); } - i = 0; - while (sctx->addrs[i] != NULL) + if (sctx->addrs != NULL) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Service `%s' runs at %s\n"), - sctx->serviceName, - GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); - i++; + i = 0; + while (sctx->addrs[i] != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Service `%s' runs at %s\n"), + sctx->serviceName, + GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); + i++; + } } - sctx->task (sctx->task_cls, tc->sched, sctx->server, sctx->cfg); + sctx->task (sctx->task_cls, sctx->server, sctx->cfg); } @@ -1235,10 +1419,12 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) return GNUNET_SYSERR; /* set stdin/stdout to /dev/null */ if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0)) - { + { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2"); + (void) CLOSE (nullfd); return GNUNET_SYSERR; } + (void) CLOSE (nullfd); /* Detach from controlling terminal */ pid = setsid (); if (pid == -1) @@ -1358,30 +1544,30 @@ GNUNET_SERVICE_run (int argc, do_daemonize = 0; logfile = NULL; loglev = GNUNET_strdup ("WARNING"); - cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_DAEMON_CONFIG_FILE); + cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); memset (&sctx, 0, sizeof (sctx)); sctx.options = opt; sctx.ready_confirm_fd = -1; sctx.ret = GNUNET_OK; sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; - sctx.maxbuf = GNUNET_SERVER_MAX_MESSAGE_SIZE; sctx.task = task; + sctx.task_cls = task_cls; sctx.serviceName = serviceName; sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); /* setup subsystems */ if (GNUNET_SYSERR == GNUNET_GETOPT_run (serviceName, service_options, argc, argv)) - HANDLE_ERROR; + goto shutdown; if (GNUNET_OK != GNUNET_log_setup (serviceName, loglev, logfile)) HANDLE_ERROR; if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_fn)) - HANDLE_ERROR; + goto shutdown; if (GNUNET_OK != setup_service (&sctx)) - HANDLE_ERROR; + goto shutdown; if ( (do_daemonize == 1) && (GNUNET_OK != detach_terminal (&sctx))) HANDLE_ERROR; if (GNUNET_OK != set_user_id (&sctx)) - HANDLE_ERROR; + goto shutdown; #if DEBUG_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' runs with configuration from `%s'\n", @@ -1405,8 +1591,9 @@ shutdown: GNUNET_CONFIGURATION_destroy (cfg); i = 0; - while (sctx.addrs[i] != NULL) - GNUNET_free (sctx.addrs[i++]); + if (sctx.addrs != NULL) + while (sctx.addrs[i] != NULL) + GNUNET_free (sctx.addrs[i++]); GNUNET_free_non_null (sctx.addrs); GNUNET_free_non_null (sctx.addrlens); GNUNET_free_non_null (logfile); @@ -1426,13 +1613,11 @@ shutdown: * initialized system. * * @param serviceName our service name - * @param sched scheduler to use * @param cfg configuration to use * @return NULL on error, service handle */ struct GNUNET_SERVICE_Context * GNUNET_SERVICE_start (const char *serviceName, - struct GNUNET_SCHEDULER_Handle *sched, const struct GNUNET_CONFIGURATION_Handle *cfg) { int i; @@ -1442,21 +1627,29 @@ GNUNET_SERVICE_start (const char *serviceName, sctx->ready_confirm_fd = -1; /* no daemonizing */ sctx->ret = GNUNET_OK; sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - sctx->maxbuf = GNUNET_SERVER_MAX_MESSAGE_SIZE; sctx->serviceName = serviceName; sctx->cfg = cfg; - sctx->sched = sched; /* setup subsystems */ - if ((GNUNET_OK != setup_service (sctx)) || - (NULL == (sctx->server = GNUNET_SERVER_create (sched, - &check_access, - sctx, - sctx->addrs, - sctx->addrlens, - sctx->maxbuf, - sctx->timeout, - sctx->require_found)))) + if (GNUNET_OK != setup_service (sctx)) + { + GNUNET_SERVICE_stop (sctx); + return NULL; + } + if (sctx->lsocks != NULL) + sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, + sctx, + sctx->lsocks, + sctx->timeout, sctx->require_found); + else + sctx->server = GNUNET_SERVER_create (&check_access, + sctx, + sctx->addrs, + sctx->addrlens, + sctx->timeout, + sctx->require_found); + + if (NULL == sctx->server) { GNUNET_SERVICE_stop (sctx); return NULL; @@ -1496,10 +1689,13 @@ GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx) if (NULL != sctx->server) GNUNET_SERVER_destroy (sctx->server); GNUNET_free_non_null (sctx->my_handlers); - i = 0; - while (sctx->addrs[i] != NULL) - GNUNET_free (sctx->addrs[i++]); - GNUNET_free_non_null (sctx->addrs); + if (sctx->addrs != NULL) + { + i = 0; + while (sctx->addrs[i] != NULL) + GNUNET_free (sctx->addrs[i++]); + GNUNET_free (sctx->addrs); + } GNUNET_free_non_null (sctx->addrlens); GNUNET_free_non_null (sctx->v4_denied); GNUNET_free_non_null (sctx->v6_denied);