From: Christian Grothoff Date: Tue, 25 May 2010 16:44:26 +0000 (+0000) Subject: renaming files to fit conventions X-Git-Tag: initial-import-from-subversion-38251~21565 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=0b29cf7b7067f82a0de7a3660ba7f288fcee5cb5;p=oweals%2Fgnunet.git renaming files to fit conventions --- diff --git a/src/arm/Makefile.am b/src/arm/Makefile.am index 92c0fdc34..b60699e85 100644 --- a/src/arm/Makefile.am +++ b/src/arm/Makefile.am @@ -34,8 +34,8 @@ gnunet_arm_LDADD = \ $(GN_LIBINTL) gnunet_service_arm_SOURCES = \ - gnunet-service-arm.c gnunet_service_arm_.h \ - gnunet-service-manager.c + gnunet-service-arm.c gnunet-service-arm.h \ + gnunet-service-arm_interceptor.c gnunet_service_arm_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index 972ff47d0..90af2ab8e 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c @@ -37,7 +37,7 @@ #include "gnunet_protocols.h" #include "gnunet_service_lib.h" #include "gnunet_signal_lib.h" -#include "gnunet_service_arm_.h" +#include "gnunet-service-arm.h" #include "arm.h" diff --git a/src/arm/gnunet-service-arm.h b/src/arm/gnunet-service-arm.h new file mode 100644 index 000000000..1e55051e0 --- /dev/null +++ b/src/arm/gnunet-service-arm.h @@ -0,0 +1,46 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file arm/gnunet_service_arm_.h + * @brief function prototypes for gnunet_service_arm.c, and gnunet_service_manager.c + * @author Safey Abdel Halim + */ + +#ifndef GNUNET_SERVICE_ARM__H +#define GNUNET_SERVICE_ARM__H + +void start_service (struct GNUNET_SERVER_Client *client, + const char *servicename); + +/** + * Stop listening for connections to a service. + * + * @param serviceName name of service to stop listening for + * @return GNUNET_OK if we stopped to listen, GNUNET_NO if we were + * not listening + */ +int stop_listening (const char *serviceName); + +void prepareServices (const struct GNUNET_CONFIGURATION_Handle + *configurationHandle, + struct GNUNET_SCHEDULER_Handle *sched); + +#endif diff --git a/src/arm/gnunet-service-arm_interceptor.c b/src/arm/gnunet-service-arm_interceptor.c new file mode 100644 index 000000000..10847c2ba --- /dev/null +++ b/src/arm/gnunet-service-arm_interceptor.c @@ -0,0 +1,1066 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file arm/gnunet-service-arm_interceptor.c + * @brief listen to incoming connections from clients to services, + * start services for which incoming an incoming connection occur, + * and relay communication between the client and the service for + * that first incoming connection. + * + * @author Safey Abdel Halim + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_service_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_constants.h" +#include "gnunet_client_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet-service-arm.h" + + +#define DEBUG_SERVICE_MANAGER GNUNET_NO + +#define BUFFER_SIZE (64 * 1024) + +/** + * Problem forwarding from client to service. + */ +#define REASON_CLIENT_TO_SERVICE 1 + +/** + * Problem forwarding from service to client. + */ +#define REASON_SERVICE_TO_CLIENT 2 + +/** + * Problem in both directions. + */ +#define REASON_ERROR 3 + + +/** + * + */ +struct ServiceListeningInfo +{ + /** + * This is a linked list. + */ + struct ServiceListeningInfo *next; + + /** + * This is a linked list. + */ + struct ServiceListeningInfo *prev; + + /** + * Name of the service being forwarded. + */ + char *serviceName; + + /** + * + */ + struct sockaddr *service_addr; + + /** + * + */ + socklen_t service_addr_len; + + /** + * Our listening socket. + */ + struct GNUNET_NETWORK_Handle *listeningSocket; + + /** + * Task doing the accepting. + */ + GNUNET_SCHEDULER_TaskIdentifier acceptTask; +}; + +/** + * Information of the connection: client-arm-service + */ +struct ForwardedConnection +{ + /** + * + */ + struct GNUNET_NETWORK_Handle *armClientSocket; + + /** + * + */ + struct GNUNET_NETWORK_Handle *armServiceSocket; + + /** + * + */ + struct ServiceListeningInfo *listen_info; + + /** + * + */ + char service_to_client_buffer[BUFFER_SIZE]; + + /** + * + */ + char client_to_service_buffer[BUFFER_SIZE]; + + /** + * + */ + char client_addr[32]; + + /** + * + */ + const char *client_to_service_bufferPos; + + /** + * + */ + const char *service_to_client_bufferPos; + + /** + * Timeout for forwarding. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Current back-off value. + */ + struct GNUNET_TIME_Relative back_off; + + /** + * Task that tries to initiate forwarding. + */ + GNUNET_SCHEDULER_TaskIdentifier start_task; + + /** + * + */ + GNUNET_SCHEDULER_TaskIdentifier client_to_service_task; + + /** + * + */ + GNUNET_SCHEDULER_TaskIdentifier service_to_client_task; + + /** + * + */ + ssize_t client_to_service_bufferDataLength; + + /** + * + */ + ssize_t service_to_client_bufferDataLength; + + /** + * + */ + socklen_t client_addr_len; + + /** + * Have we ever successfully written data to the service? + */ + int first_write_done; +}; + + +/** + * Array with the names of the services started by default. + */ +static char **defaultServicesList; + +/** + * Size of the defaultServicesList array. + */ +static unsigned int numDefaultServices; + +/** + * + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * + */ +static struct GNUNET_SCHEDULER_Handle *scheduler; + +/** + * + */ +static struct ServiceListeningInfo *serviceListeningInfoList_head; + +/** + * + */ +static struct ServiceListeningInfo *serviceListeningInfoList_tail; + + +/** + * Put the default services represented by a space separated string into an array of strings + * + * @param services space separated string of default services + */ +static void +addDefaultServicesToList (const char *services) +{ + unsigned int i; + const char *token; + char *s; + + if (strlen (services) == 0) + return; + s = GNUNET_strdup (services); + token = strtok (s, " "); + while (NULL != token) + { + numDefaultServices++; + token = strtok (NULL, " "); + } + GNUNET_free (s); + + defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *)); + i = 0; + s = GNUNET_strdup (services); + token = strtok (s, " "); + while (NULL != token) + { + defaultServicesList[i++] = GNUNET_strdup (token); + token = strtok (NULL, " "); + } + GNUNET_free (s); + GNUNET_assert (i == numDefaultServices); +} + +/** + * Checks whether the serviceName is in the list of default services + * + * @param serviceName string to check its existance in the list + * @return GNUNET_YES if the service is started by default + */ +static int +isInDefaultList (const char *serviceName) +{ + unsigned int i; + for (i = 0; i < numDefaultServices; i++) + if (strcmp (serviceName, defaultServicesList[i]) == 0) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Close forwarded connection (partial or full). + * + * @param fc connection to close + * @param reason which direction to close + */ +static void +closeClientAndServiceSockets (struct ForwardedConnection *fc, + int reason) +{ + if (0 != (REASON_SERVICE_TO_CLIENT & reason)) + { +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping forwarding from service to client\n", + fc->listen_info->serviceName); +#endif + if (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (scheduler, fc->service_to_client_task); + fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; + } + if (fc->armClientSocket != NULL) + GNUNET_NETWORK_socket_shutdown (fc->armClientSocket, + SHUT_WR); + if (fc->armServiceSocket != NULL) + GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket, + SHUT_RD); + } + if (0 != (REASON_CLIENT_TO_SERVICE & reason)) + { +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping forwarding from client to service\n", + fc->listen_info->serviceName); +#endif + if (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (scheduler, + fc->client_to_service_task); + fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK; + } + if (fc->armClientSocket != NULL) + GNUNET_NETWORK_socket_shutdown (fc->armClientSocket, + SHUT_RD); + if (fc->armServiceSocket != NULL) + GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket, + SHUT_WR); + } + if ( (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) || + (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) ) + return; +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Closing forwarding connection (done with both directions)\n"); +#endif + if (fc->start_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (scheduler, + fc->start_task); + if ( (NULL != fc->armClientSocket) && + (GNUNET_SYSERR == + GNUNET_NETWORK_socket_close (fc->armClientSocket)) ) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close"); + if ( (NULL != fc->armServiceSocket) && + (GNUNET_SYSERR == + GNUNET_NETWORK_socket_close (fc->armServiceSocket)) ) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close"); + GNUNET_free (fc->listen_info->serviceName); + GNUNET_free (fc->listen_info->service_addr); + GNUNET_free (fc->listen_info); + GNUNET_free (fc); +} + + +/** + * + */ +static void +receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * + */ +static void +receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * + */ +static void +start_forwarding (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + + +/** + * Forward messages sent from service to client + * + * @param cls callback data, struct ForwardedConnection for the communication between client and service + * @param tc context + */ +static void +forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ForwardedConnection *fc = cls; + ssize_t numberOfBytesSent; + + fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready, + fc->armClientSocket)) + { + fc->service_to_client_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &forwardToClient, fc); + return; + } + /* Forwarding service response to client */ + numberOfBytesSent = + GNUNET_NETWORK_socket_send (fc->armClientSocket, + fc->service_to_client_bufferPos, + fc->service_to_client_bufferDataLength); + if (numberOfBytesSent <= 0) + { + if ( (errno != EPIPE) && + (errno != ECONNRESET) ) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to forward %u bytes of data to client: %s\n", + fc->service_to_client_bufferDataLength, + STRERROR (errno)); + closeClientAndServiceSockets (fc, + REASON_SERVICE_TO_CLIENT); + return; + } +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Forwarded %d bytes to client\n", + numberOfBytesSent); +#endif + if (numberOfBytesSent < fc->service_to_client_bufferDataLength) + { + fc->service_to_client_bufferPos += numberOfBytesSent; + fc->service_to_client_bufferDataLength -= numberOfBytesSent; + fc->service_to_client_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &forwardToClient, + fc); + return; + } + fc->service_to_client_task = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armServiceSocket, + &receiveFromService, + fc); +} + + +/** + * Receive service messages sent by the service and forward it to client + * + * @param cls callback data, struct ForwardedConnection for the communication between client and service + * @param tc scheduler context + */ +static void +receiveFromService (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ForwardedConnection *fc = cls; + struct GNUNET_TIME_Relative rem; + + fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; + if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && + (fc->first_write_done != GNUNET_YES) ) + { + closeClientAndServiceSockets (fc, REASON_ERROR); + return; + } + if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready, + fc->armServiceSocket)) + { + fc->service_to_client_task = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armServiceSocket, + &receiveFromService, fc); + return; + } + fc->service_to_client_bufferPos = fc->service_to_client_buffer; + fc->service_to_client_bufferDataLength = + GNUNET_NETWORK_socket_recv (fc->armServiceSocket, + fc->service_to_client_buffer, + BUFFER_SIZE); + if (fc->service_to_client_bufferDataLength <= 0) + { + if (fc->service_to_client_bufferDataLength == 0) + { +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Service `%s' stopped sending data.\n", + fc->listen_info->serviceName); +#endif + } + if (fc->first_write_done != GNUNET_YES) + { + fc->service_to_client_bufferDataLength = 0; + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (fc->armServiceSocket)); + fc->armServiceSocket = NULL; + if ( (fc->client_to_service_bufferDataLength > 0) && + (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) ) + { + GNUNET_SCHEDULER_cancel (scheduler, + fc->client_to_service_task); + fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; + } + fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2); +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connected to service `%s' at `%s', will try again in %llu ms\n", + fc->listen_info->serviceName, + GNUNET_a2s (fc->listen_info->service_addr, + fc->listen_info->service_addr_len), + (unsigned long long) GNUNET_TIME_relative_min (fc->back_off, + rem).value); +#endif + rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); + fc->start_task + = GNUNET_SCHEDULER_add_delayed (scheduler, + GNUNET_TIME_relative_min (fc->back_off, + rem), + &start_forwarding, + fc); + } + else + { +#if DEBUG_SERVICE_MANAGER + if (fc->service_to_client_bufferDataLength != 0) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Error receiving from service: %s\n", + STRERROR (errno)); +#endif + closeClientAndServiceSockets (fc, REASON_SERVICE_TO_CLIENT); + } + return; + } + fc->first_write_done = GNUNET_YES; +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %d bytes for client\n", + fc->service_to_client_bufferDataLength); +#endif + fc->service_to_client_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &forwardToClient, fc); +} + + +/** + * Forward client message to service + * + * @param cls callback data, struct ForwardedConnection for the communication between client and service + * @param tc scheduler context + */ +static void +forwardToService (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ForwardedConnection *fc = cls; + ssize_t numberOfBytesSent; + struct GNUNET_TIME_Relative rem; + + fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK; + if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && + (fc->first_write_done != GNUNET_YES) ) + { + closeClientAndServiceSockets (fc, REASON_ERROR); + return; + } + if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready, + fc->armServiceSocket)) + { + fc->client_to_service_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armServiceSocket, + &forwardToService, fc); + return; + } + numberOfBytesSent = + GNUNET_NETWORK_socket_send (fc->armServiceSocket, + fc->client_to_service_bufferPos, + fc->client_to_service_bufferDataLength); + if (numberOfBytesSent <= 0) + { + if (GNUNET_YES != fc->first_write_done) + { + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (fc->armServiceSocket)); + fc->armServiceSocket = NULL; + if ( (fc->service_to_client_bufferDataLength == 0) && + (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) ) + { + GNUNET_SCHEDULER_cancel (scheduler, + fc->service_to_client_task); + fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; + } + fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2); +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect to service `%s' at `%s', will try again in %llu ms\n", + fc->listen_info->serviceName, + GNUNET_a2s (fc->listen_info->service_addr, + fc->listen_info->service_addr_len), + (unsigned long long) GNUNET_TIME_relative_min (fc->back_off, + rem).value); +#endif + rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); + fc->start_task + = GNUNET_SCHEDULER_add_delayed (scheduler, + GNUNET_TIME_relative_min (fc->back_off, + rem), + &start_forwarding, + fc); + } + else + { + if ( (errno != EPIPE) && + (errno != ECONNRESET) ) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to forward data to service: %s\n", + STRERROR (errno)); + closeClientAndServiceSockets (fc, + REASON_CLIENT_TO_SERVICE); + } + return; + } +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Forwarded %d bytes to service\n", + numberOfBytesSent); +#endif + fc->first_write_done = GNUNET_YES; + if (numberOfBytesSent < fc->client_to_service_bufferDataLength) + { + fc->client_to_service_bufferPos += numberOfBytesSent; + fc->client_to_service_bufferDataLength -= numberOfBytesSent; + fc->client_to_service_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armServiceSocket, + &forwardToService, fc); + return; + } + fc->client_to_service_task = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &receiveFromClient, fc); +} + + +/** + * Read data from the client and then forward it to the service. + * + * @param cls callback data, struct ForwardedConnection for the communication between client and service + * @param tc context + */ +static void +receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ForwardedConnection *fc = cls; + + fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready, + fc->armClientSocket)) + { + fc->client_to_service_task = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &receiveFromClient, fc); + return; + } + fc->client_to_service_bufferPos = fc->client_to_service_buffer; + fc->client_to_service_bufferDataLength = + GNUNET_NETWORK_socket_recv (fc->armClientSocket, + fc->client_to_service_buffer, + BUFFER_SIZE); + if (fc->client_to_service_bufferDataLength <= 0) + { + if (fc->client_to_service_bufferDataLength == 0) + { +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client closed connection with service `%s'\n", + fc->listen_info->serviceName); +#endif + } + else + { +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Error receiving from client: %s\n", + STRERROR (errno)); +#endif + } + closeClientAndServiceSockets (fc, REASON_CLIENT_TO_SERVICE); + return; + } +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %d bytes for service\n", + fc->client_to_service_bufferDataLength); +#endif + if (fc->armServiceSocket != NULL) + fc->client_to_service_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armServiceSocket, + &forwardToService, fc); +} + + +/** + * + */ +static void +start_forwarding (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ForwardedConnection *fc = cls; + struct GNUNET_TIME_Relative rem; + + fc->start_task = GNUNET_SCHEDULER_NO_TASK; + if ( (NULL != tc) && + (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Unable to forward to service `%s': shutdown\n"), + fc->listen_info->serviceName); + closeClientAndServiceSockets (fc, REASON_ERROR); + return; + } + rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); + if (rem.value == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to forward to service `%s': timeout before connect\n"), + fc->listen_info->serviceName); + closeClientAndServiceSockets (fc, REASON_ERROR); + return; + } + fc->armServiceSocket = + GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family, + SOCK_STREAM, 0); + if (NULL == fc->armServiceSocket) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ ("Unable to start service `%s': %s\n"), + fc->listen_info->serviceName, + STRERROR (errno)); + closeClientAndServiceSockets (fc, REASON_ERROR); + return; + } + if ( (GNUNET_SYSERR == + GNUNET_NETWORK_socket_connect (fc->armServiceSocket, + fc->listen_info->service_addr, + fc->listen_info->service_addr_len)) && + (errno != EINPROGRESS) ) + { + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (fc->armServiceSocket)); + fc->armServiceSocket = NULL; + fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2); + #if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connected to service `%s' at `%s', will try again in %llu ms\n", + fc->listen_info->serviceName, + GNUNET_a2s (fc->listen_info->service_addr, + fc->listen_info->service_addr_len), + (unsigned long long) GNUNET_TIME_relative_min (fc->back_off, + rem).value); +#endif + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); + fc->start_task + = GNUNET_SCHEDULER_add_delayed (scheduler, + GNUNET_TIME_relative_min (fc->back_off, + rem), + &start_forwarding, + fc); + return; + } +#if DEBUG_SERVICE_MANAGER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected to service, now starting forwarding\n"); +#endif + if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK) + { + if (fc->client_to_service_bufferDataLength == 0) + fc->client_to_service_task = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &receiveFromClient, fc); + else + fc->client_to_service_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armServiceSocket, + &forwardToService, fc); + } + if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK) + { + if (fc->service_to_client_bufferDataLength == 0) + fc->service_to_client_task = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armServiceSocket, + &receiveFromService, fc); + else + fc->service_to_client_task = + GNUNET_SCHEDULER_add_write_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &forwardToClient, fc); + } +} + + + +/** + * + */ +int +stop_listening (const char *serviceName) +{ + struct ServiceListeningInfo *pos; + struct ServiceListeningInfo *next; + int ret; + + ret = GNUNET_NO; + next = serviceListeningInfoList_head; + while (NULL != (pos = next)) + { + next = pos->next; + if ( (serviceName != NULL) && + (strcmp (pos->serviceName, serviceName) != 0) ) + continue; + if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (scheduler, pos->acceptTask); + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (pos->listeningSocket)); + GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, + serviceListeningInfoList_tail, + pos); + GNUNET_free (pos->serviceName); + GNUNET_free (pos->service_addr); + GNUNET_free (pos); + ret = GNUNET_OK; + } + return ret; +} + + +/** + * First connection has come to the listening socket associated with the service, + * create the service in order to relay the incoming connection to it + * + * @param cls callback data, struct ServiceListeningInfo describing a listen socket + * @param tc context + */ +static void +acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ServiceListeningInfo *serviceListeningInfo = cls; + struct ForwardedConnection *fc; + + serviceListeningInfo->acceptTask = GNUNET_SCHEDULER_NO_TASK; + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + fc = GNUNET_malloc (sizeof (struct ForwardedConnection)); + fc->listen_info = serviceListeningInfo; + fc->service_to_client_bufferPos = fc->service_to_client_buffer; + fc->client_to_service_bufferPos = fc->client_to_service_buffer; + fc->client_addr_len = sizeof (fc->client_addr); + fc->armClientSocket = GNUNET_NETWORK_socket_accept (serviceListeningInfo->listeningSocket, + (struct sockaddr*) fc->client_addr, + &fc->client_addr_len); + if (NULL == fc->armClientSocket) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to accept connection for service `%s': %s\n"), + serviceListeningInfo->serviceName, + STRERROR (errno)); + GNUNET_free (fc); + serviceListeningInfo->acceptTask = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + serviceListeningInfo->listeningSocket, + &acceptConnection, + serviceListeningInfo); + return; + } + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket)); + GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, + serviceListeningInfoList_tail, + serviceListeningInfo); + start_service (NULL, serviceListeningInfo->serviceName); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Service `%s' started\n"), + fc->listen_info->serviceName); + fc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_SERVICE_TIMEOUT); + fc->back_off = GNUNET_TIME_UNIT_MILLISECONDS; + fc->client_to_service_task = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, + fc->armClientSocket, + &receiveFromClient, fc); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); + fc->start_task + = GNUNET_SCHEDULER_add_now (scheduler, + &start_forwarding, + fc); +} + + +/** + * Creating a listening socket for each of the service's addresses and + * wait for the first incoming connection to it + * + * @param sa address associated with the service + * @param addr_len length of sa + * @param serviceName the name of the service in question + */ +static void +createListeningSocket (struct sockaddr *sa, + socklen_t addr_len, + const char *serviceName) +{ + const static int on = 1; + struct GNUNET_NETWORK_Handle *sock; + struct ServiceListeningInfo *serviceListeningInfo; + + switch (sa->sa_family) + { + case AF_INET: + sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); + break; + case AF_INET6: + sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); + break; + default: + sock = NULL; + break; + } + if (NULL == sock) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to create socket for service `%s'"), + serviceName); + GNUNET_free (sa); + return; + } + if (GNUNET_NETWORK_socket_setsockopt + (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "setsockopt"); +#ifdef IPV6_V6ONLY + if ( (sa->sa_family == AF_INET6) && + (GNUNET_NETWORK_socket_setsockopt + (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "setsockopt"); +#endif + + if (GNUNET_NETWORK_socket_bind + (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to bind listening socket for service `%s' to address `%s': %s\n"), + serviceName, + GNUNET_a2s (sa, addr_len), + STRERROR (errno)); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + GNUNET_free (sa); + return; + } + if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "listen"); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + GNUNET_free (sa); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("ARM now monitors connections to service `%s' at `%s'\n"), + serviceName, + GNUNET_a2s (sa, addr_len)); + serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); + serviceListeningInfo->serviceName = GNUNET_strdup (serviceName); + serviceListeningInfo->service_addr = sa; + serviceListeningInfo->service_addr_len = addr_len; + serviceListeningInfo->listeningSocket = sock; + serviceListeningInfo->acceptTask = + GNUNET_SCHEDULER_add_read_net (scheduler, + GNUNET_TIME_UNIT_FOREVER_REL, sock, + &acceptConnection, + serviceListeningInfo); + GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head, + serviceListeningInfoList_tail, + serviceListeningInfo); +} + + +/** + * Callback function, checks whether the current tokens are representing a service, + * gets its addresses and create listening socket for it. + * + * @param cls callback data, not used + * @param section configuration section + * @param option configuration option + * @param value the option's value + */ +static void +checkPortNumberCB (void *cls, + const char *section, + const char *option, + const char *value) +{ + struct sockaddr **addrs; + socklen_t *addr_lens; + int ret; + unsigned int i; + + if ( (strcasecmp (section, "arm") == 0) || + (strcasecmp (option, "AUTOSTART") != 0) || + (strcasecmp (value, "YES") != 0) || + (isInDefaultList (section) == GNUNET_YES) ) + return; + if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs, + &addr_lens))) + return; + /* this will free (or capture) addrs[i] */ + for (i = 0; i < ret; i++) + createListeningSocket (addrs[i], addr_lens[i], section); + GNUNET_free (addrs); + GNUNET_free (addr_lens); +} + + +/** + * Entry point to the Service Manager + * + * @param configurationHandle configuration to use to get services + * @param sched scheduler to handle clients and services communications + */ +void +prepareServices (const struct GNUNET_CONFIGURATION_Handle + *configurationHandle, struct GNUNET_SCHEDULER_Handle *sched) +{ + char *defaultServicesString; + + scheduler = sched; + cfg = configurationHandle; + /* Split the default services into a list */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES", + &defaultServicesString)) + { + addDefaultServicesToList (defaultServicesString); + GNUNET_free (defaultServicesString); + } + /* Spot the services from the configuration and create a listening + socket for each */ + GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL); +} + +/* end of gnunet-service-arm_interceptor.c */ diff --git a/src/arm/gnunet-service-manager.c b/src/arm/gnunet-service-manager.c deleted file mode 100644 index b7095dad5..000000000 --- a/src/arm/gnunet-service-manager.c +++ /dev/null @@ -1,1066 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009, 2010 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ -/** - * @file arm/gnunet-service-manager.c - * @brief listen to incoming connections from clients to services, - * start services for which incoming an incoming connection occur, - * and relay communication between the client and the service for - * that first incoming connection. - * - * @author Safey Abdel Halim - * @author Christian Grothoff - */ - -#include "platform.h" -#include "gnunet_service_lib.h" -#include "gnunet_configuration_lib.h" -#include "gnunet_constants.h" -#include "gnunet_client_lib.h" -#include "gnunet_container_lib.h" -#include "gnunet_service_arm_.h" - - -#define DEBUG_SERVICE_MANAGER GNUNET_NO - -#define BUFFER_SIZE (64 * 1024) - -/** - * Problem forwarding from client to service. - */ -#define REASON_CLIENT_TO_SERVICE 1 - -/** - * Problem forwarding from service to client. - */ -#define REASON_SERVICE_TO_CLIENT 2 - -/** - * Problem in both directions. - */ -#define REASON_ERROR 3 - - -/** - * - */ -struct ServiceListeningInfo -{ - /** - * This is a linked list. - */ - struct ServiceListeningInfo *next; - - /** - * This is a linked list. - */ - struct ServiceListeningInfo *prev; - - /** - * Name of the service being forwarded. - */ - char *serviceName; - - /** - * - */ - struct sockaddr *service_addr; - - /** - * - */ - socklen_t service_addr_len; - - /** - * Our listening socket. - */ - struct GNUNET_NETWORK_Handle *listeningSocket; - - /** - * Task doing the accepting. - */ - GNUNET_SCHEDULER_TaskIdentifier acceptTask; -}; - -/** - * Information of the connection: client-arm-service - */ -struct ForwardedConnection -{ - /** - * - */ - struct GNUNET_NETWORK_Handle *armClientSocket; - - /** - * - */ - struct GNUNET_NETWORK_Handle *armServiceSocket; - - /** - * - */ - struct ServiceListeningInfo *listen_info; - - /** - * - */ - char service_to_client_buffer[BUFFER_SIZE]; - - /** - * - */ - char client_to_service_buffer[BUFFER_SIZE]; - - /** - * - */ - char client_addr[32]; - - /** - * - */ - const char *client_to_service_bufferPos; - - /** - * - */ - const char *service_to_client_bufferPos; - - /** - * Timeout for forwarding. - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * Current back-off value. - */ - struct GNUNET_TIME_Relative back_off; - - /** - * Task that tries to initiate forwarding. - */ - GNUNET_SCHEDULER_TaskIdentifier start_task; - - /** - * - */ - GNUNET_SCHEDULER_TaskIdentifier client_to_service_task; - - /** - * - */ - GNUNET_SCHEDULER_TaskIdentifier service_to_client_task; - - /** - * - */ - ssize_t client_to_service_bufferDataLength; - - /** - * - */ - ssize_t service_to_client_bufferDataLength; - - /** - * - */ - socklen_t client_addr_len; - - /** - * Have we ever successfully written data to the service? - */ - int first_write_done; -}; - - -/** - * Array with the names of the services started by default. - */ -static char **defaultServicesList; - -/** - * Size of the defaultServicesList array. - */ -static unsigned int numDefaultServices; - -/** - * - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * - */ -static struct GNUNET_SCHEDULER_Handle *scheduler; - -/** - * - */ -static struct ServiceListeningInfo *serviceListeningInfoList_head; - -/** - * - */ -static struct ServiceListeningInfo *serviceListeningInfoList_tail; - - -/** - * Put the default services represented by a space separated string into an array of strings - * - * @param services space separated string of default services - */ -static void -addDefaultServicesToList (const char *services) -{ - unsigned int i; - const char *token; - char *s; - - if (strlen (services) == 0) - return; - s = GNUNET_strdup (services); - token = strtok (s, " "); - while (NULL != token) - { - numDefaultServices++; - token = strtok (NULL, " "); - } - GNUNET_free (s); - - defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *)); - i = 0; - s = GNUNET_strdup (services); - token = strtok (s, " "); - while (NULL != token) - { - defaultServicesList[i++] = GNUNET_strdup (token); - token = strtok (NULL, " "); - } - GNUNET_free (s); - GNUNET_assert (i == numDefaultServices); -} - -/** - * Checks whether the serviceName is in the list of default services - * - * @param serviceName string to check its existance in the list - * @return GNUNET_YES if the service is started by default - */ -static int -isInDefaultList (const char *serviceName) -{ - unsigned int i; - for (i = 0; i < numDefaultServices; i++) - if (strcmp (serviceName, defaultServicesList[i]) == 0) - return GNUNET_YES; - return GNUNET_NO; -} - - -/** - * Close forwarded connection (partial or full). - * - * @param fc connection to close - * @param reason which direction to close - */ -static void -closeClientAndServiceSockets (struct ForwardedConnection *fc, - int reason) -{ - if (0 != (REASON_SERVICE_TO_CLIENT & reason)) - { -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping forwarding from service to client\n", - fc->listen_info->serviceName); -#endif - if (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (scheduler, fc->service_to_client_task); - fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; - } - if (fc->armClientSocket != NULL) - GNUNET_NETWORK_socket_shutdown (fc->armClientSocket, - SHUT_WR); - if (fc->armServiceSocket != NULL) - GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket, - SHUT_RD); - } - if (0 != (REASON_CLIENT_TO_SERVICE & reason)) - { -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping forwarding from client to service\n", - fc->listen_info->serviceName); -#endif - if (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (scheduler, - fc->client_to_service_task); - fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK; - } - if (fc->armClientSocket != NULL) - GNUNET_NETWORK_socket_shutdown (fc->armClientSocket, - SHUT_RD); - if (fc->armServiceSocket != NULL) - GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket, - SHUT_WR); - } - if ( (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) || - (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) ) - return; -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Closing forwarding connection (done with both directions)\n"); -#endif - if (fc->start_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (scheduler, - fc->start_task); - if ( (NULL != fc->armClientSocket) && - (GNUNET_SYSERR == - GNUNET_NETWORK_socket_close (fc->armClientSocket)) ) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close"); - if ( (NULL != fc->armServiceSocket) && - (GNUNET_SYSERR == - GNUNET_NETWORK_socket_close (fc->armServiceSocket)) ) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close"); - GNUNET_free (fc->listen_info->serviceName); - GNUNET_free (fc->listen_info->service_addr); - GNUNET_free (fc->listen_info); - GNUNET_free (fc); -} - - -/** - * - */ -static void -receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * - */ -static void -receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * - */ -static void -start_forwarding (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - - - -/** - * Forward messages sent from service to client - * - * @param cls callback data, struct ForwardedConnection for the communication between client and service - * @param tc context - */ -static void -forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ForwardedConnection *fc = cls; - ssize_t numberOfBytesSent; - - fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; - if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready, - fc->armClientSocket)) - { - fc->service_to_client_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &forwardToClient, fc); - return; - } - /* Forwarding service response to client */ - numberOfBytesSent = - GNUNET_NETWORK_socket_send (fc->armClientSocket, - fc->service_to_client_bufferPos, - fc->service_to_client_bufferDataLength); - if (numberOfBytesSent <= 0) - { - if ( (errno != EPIPE) && - (errno != ECONNRESET) ) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to forward %u bytes of data to client: %s\n", - fc->service_to_client_bufferDataLength, - STRERROR (errno)); - closeClientAndServiceSockets (fc, - REASON_SERVICE_TO_CLIENT); - return; - } -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Forwarded %d bytes to client\n", - numberOfBytesSent); -#endif - if (numberOfBytesSent < fc->service_to_client_bufferDataLength) - { - fc->service_to_client_bufferPos += numberOfBytesSent; - fc->service_to_client_bufferDataLength -= numberOfBytesSent; - fc->service_to_client_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &forwardToClient, - fc); - return; - } - fc->service_to_client_task = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armServiceSocket, - &receiveFromService, - fc); -} - - -/** - * Receive service messages sent by the service and forward it to client - * - * @param cls callback data, struct ForwardedConnection for the communication between client and service - * @param tc scheduler context - */ -static void -receiveFromService (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ForwardedConnection *fc = cls; - struct GNUNET_TIME_Relative rem; - - fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; - if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && - (fc->first_write_done != GNUNET_YES) ) - { - closeClientAndServiceSockets (fc, REASON_ERROR); - return; - } - if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready, - fc->armServiceSocket)) - { - fc->service_to_client_task = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armServiceSocket, - &receiveFromService, fc); - return; - } - fc->service_to_client_bufferPos = fc->service_to_client_buffer; - fc->service_to_client_bufferDataLength = - GNUNET_NETWORK_socket_recv (fc->armServiceSocket, - fc->service_to_client_buffer, - BUFFER_SIZE); - if (fc->service_to_client_bufferDataLength <= 0) - { - if (fc->service_to_client_bufferDataLength == 0) - { -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Service `%s' stopped sending data.\n", - fc->listen_info->serviceName); -#endif - } - if (fc->first_write_done != GNUNET_YES) - { - fc->service_to_client_bufferDataLength = 0; - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (fc->armServiceSocket)); - fc->armServiceSocket = NULL; - if ( (fc->client_to_service_bufferDataLength > 0) && - (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) ) - { - GNUNET_SCHEDULER_cancel (scheduler, - fc->client_to_service_task); - fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; - } - fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2); -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to connected to service `%s' at `%s', will try again in %llu ms\n", - fc->listen_info->serviceName, - GNUNET_a2s (fc->listen_info->service_addr, - fc->listen_info->service_addr_len), - (unsigned long long) GNUNET_TIME_relative_min (fc->back_off, - rem).value); -#endif - rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); - fc->start_task - = GNUNET_SCHEDULER_add_delayed (scheduler, - GNUNET_TIME_relative_min (fc->back_off, - rem), - &start_forwarding, - fc); - } - else - { -#if DEBUG_SERVICE_MANAGER - if (fc->service_to_client_bufferDataLength != 0) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Error receiving from service: %s\n", - STRERROR (errno)); -#endif - closeClientAndServiceSockets (fc, REASON_SERVICE_TO_CLIENT); - } - return; - } - fc->first_write_done = GNUNET_YES; -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received %d bytes for client\n", - fc->service_to_client_bufferDataLength); -#endif - fc->service_to_client_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &forwardToClient, fc); -} - - -/** - * Forward client message to service - * - * @param cls callback data, struct ForwardedConnection for the communication between client and service - * @param tc scheduler context - */ -static void -forwardToService (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ForwardedConnection *fc = cls; - ssize_t numberOfBytesSent; - struct GNUNET_TIME_Relative rem; - - fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK; - if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && - (fc->first_write_done != GNUNET_YES) ) - { - closeClientAndServiceSockets (fc, REASON_ERROR); - return; - } - if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->write_ready, - fc->armServiceSocket)) - { - fc->client_to_service_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armServiceSocket, - &forwardToService, fc); - return; - } - numberOfBytesSent = - GNUNET_NETWORK_socket_send (fc->armServiceSocket, - fc->client_to_service_bufferPos, - fc->client_to_service_bufferDataLength); - if (numberOfBytesSent <= 0) - { - if (GNUNET_YES != fc->first_write_done) - { - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (fc->armServiceSocket)); - fc->armServiceSocket = NULL; - if ( (fc->service_to_client_bufferDataLength == 0) && - (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) ) - { - GNUNET_SCHEDULER_cancel (scheduler, - fc->service_to_client_task); - fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK; - } - fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2); -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to connect to service `%s' at `%s', will try again in %llu ms\n", - fc->listen_info->serviceName, - GNUNET_a2s (fc->listen_info->service_addr, - fc->listen_info->service_addr_len), - (unsigned long long) GNUNET_TIME_relative_min (fc->back_off, - rem).value); -#endif - rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); - fc->start_task - = GNUNET_SCHEDULER_add_delayed (scheduler, - GNUNET_TIME_relative_min (fc->back_off, - rem), - &start_forwarding, - fc); - } - else - { - if ( (errno != EPIPE) && - (errno != ECONNRESET) ) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to forward data to service: %s\n", - STRERROR (errno)); - closeClientAndServiceSockets (fc, - REASON_CLIENT_TO_SERVICE); - } - return; - } -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Forwarded %d bytes to service\n", - numberOfBytesSent); -#endif - fc->first_write_done = GNUNET_YES; - if (numberOfBytesSent < fc->client_to_service_bufferDataLength) - { - fc->client_to_service_bufferPos += numberOfBytesSent; - fc->client_to_service_bufferDataLength -= numberOfBytesSent; - fc->client_to_service_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armServiceSocket, - &forwardToService, fc); - return; - } - fc->client_to_service_task = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &receiveFromClient, fc); -} - - -/** - * Read data from the client and then forward it to the service. - * - * @param cls callback data, struct ForwardedConnection for the communication between client and service - * @param tc context - */ -static void -receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ForwardedConnection *fc = cls; - - fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK; - if (GNUNET_YES != GNUNET_NETWORK_fdset_isset (tc->read_ready, - fc->armClientSocket)) - { - fc->client_to_service_task = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &receiveFromClient, fc); - return; - } - fc->client_to_service_bufferPos = fc->client_to_service_buffer; - fc->client_to_service_bufferDataLength = - GNUNET_NETWORK_socket_recv (fc->armClientSocket, - fc->client_to_service_buffer, - BUFFER_SIZE); - if (fc->client_to_service_bufferDataLength <= 0) - { - if (fc->client_to_service_bufferDataLength == 0) - { -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client closed connection with service `%s'\n", - fc->listen_info->serviceName); -#endif - } - else - { -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Error receiving from client: %s\n", - STRERROR (errno)); -#endif - } - closeClientAndServiceSockets (fc, REASON_CLIENT_TO_SERVICE); - return; - } -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received %d bytes for service\n", - fc->client_to_service_bufferDataLength); -#endif - if (fc->armServiceSocket != NULL) - fc->client_to_service_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armServiceSocket, - &forwardToService, fc); -} - - -/** - * - */ -static void -start_forwarding (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ForwardedConnection *fc = cls; - struct GNUNET_TIME_Relative rem; - - fc->start_task = GNUNET_SCHEDULER_NO_TASK; - if ( (NULL != tc) && - (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Unable to forward to service `%s': shutdown\n"), - fc->listen_info->serviceName); - closeClientAndServiceSockets (fc, REASON_ERROR); - return; - } - rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); - if (rem.value == 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to forward to service `%s': timeout before connect\n"), - fc->listen_info->serviceName); - closeClientAndServiceSockets (fc, REASON_ERROR); - return; - } - fc->armServiceSocket = - GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family, - SOCK_STREAM, 0); - if (NULL == fc->armServiceSocket) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ ("Unable to start service `%s': %s\n"), - fc->listen_info->serviceName, - STRERROR (errno)); - closeClientAndServiceSockets (fc, REASON_ERROR); - return; - } - if ( (GNUNET_SYSERR == - GNUNET_NETWORK_socket_connect (fc->armServiceSocket, - fc->listen_info->service_addr, - fc->listen_info->service_addr_len)) && - (errno != EINPROGRESS) ) - { - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (fc->armServiceSocket)); - fc->armServiceSocket = NULL; - fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2); - #if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to connected to service `%s' at `%s', will try again in %llu ms\n", - fc->listen_info->serviceName, - GNUNET_a2s (fc->listen_info->service_addr, - fc->listen_info->service_addr_len), - (unsigned long long) GNUNET_TIME_relative_min (fc->back_off, - rem).value); -#endif - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); - fc->start_task - = GNUNET_SCHEDULER_add_delayed (scheduler, - GNUNET_TIME_relative_min (fc->back_off, - rem), - &start_forwarding, - fc); - return; - } -#if DEBUG_SERVICE_MANAGER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connected to service, now starting forwarding\n"); -#endif - if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK) - { - if (fc->client_to_service_bufferDataLength == 0) - fc->client_to_service_task = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &receiveFromClient, fc); - else - fc->client_to_service_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armServiceSocket, - &forwardToService, fc); - } - if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK) - { - if (fc->service_to_client_bufferDataLength == 0) - fc->service_to_client_task = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armServiceSocket, - &receiveFromService, fc); - else - fc->service_to_client_task = - GNUNET_SCHEDULER_add_write_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &forwardToClient, fc); - } -} - - - -/** - * - */ -int -stop_listening (const char *serviceName) -{ - struct ServiceListeningInfo *pos; - struct ServiceListeningInfo *next; - int ret; - - ret = GNUNET_NO; - next = serviceListeningInfoList_head; - while (NULL != (pos = next)) - { - next = pos->next; - if ( (serviceName != NULL) && - (strcmp (pos->serviceName, serviceName) != 0) ) - continue; - if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (scheduler, pos->acceptTask); - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (pos->listeningSocket)); - GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, - serviceListeningInfoList_tail, - pos); - GNUNET_free (pos->serviceName); - GNUNET_free (pos->service_addr); - GNUNET_free (pos); - ret = GNUNET_OK; - } - return ret; -} - - -/** - * First connection has come to the listening socket associated with the service, - * create the service in order to relay the incoming connection to it - * - * @param cls callback data, struct ServiceListeningInfo describing a listen socket - * @param tc context - */ -static void -acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ServiceListeningInfo *serviceListeningInfo = cls; - struct ForwardedConnection *fc; - - serviceListeningInfo->acceptTask = GNUNET_SCHEDULER_NO_TASK; - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - return; - fc = GNUNET_malloc (sizeof (struct ForwardedConnection)); - fc->listen_info = serviceListeningInfo; - fc->service_to_client_bufferPos = fc->service_to_client_buffer; - fc->client_to_service_bufferPos = fc->client_to_service_buffer; - fc->client_addr_len = sizeof (fc->client_addr); - fc->armClientSocket = GNUNET_NETWORK_socket_accept (serviceListeningInfo->listeningSocket, - (struct sockaddr*) fc->client_addr, - &fc->client_addr_len); - if (NULL == fc->armClientSocket) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to accept connection for service `%s': %s\n"), - serviceListeningInfo->serviceName, - STRERROR (errno)); - GNUNET_free (fc); - serviceListeningInfo->acceptTask = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - serviceListeningInfo->listeningSocket, - &acceptConnection, - serviceListeningInfo); - return; - } - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket)); - GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, - serviceListeningInfoList_tail, - serviceListeningInfo); - start_service (NULL, serviceListeningInfo->serviceName); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Service `%s' started\n"), - fc->listen_info->serviceName); - fc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_SERVICE_TIMEOUT); - fc->back_off = GNUNET_TIME_UNIT_MILLISECONDS; - fc->client_to_service_task = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, - fc->armClientSocket, - &receiveFromClient, fc); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); - fc->start_task - = GNUNET_SCHEDULER_add_now (scheduler, - &start_forwarding, - fc); -} - - -/** - * Creating a listening socket for each of the service's addresses and - * wait for the first incoming connection to it - * - * @param sa address associated with the service - * @param addr_len length of sa - * @param serviceName the name of the service in question - */ -static void -createListeningSocket (struct sockaddr *sa, - socklen_t addr_len, - const char *serviceName) -{ - const static int on = 1; - struct GNUNET_NETWORK_Handle *sock; - struct ServiceListeningInfo *serviceListeningInfo; - - switch (sa->sa_family) - { - case AF_INET: - sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); - break; - case AF_INET6: - sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); - break; - default: - sock = NULL; - break; - } - if (NULL == sock) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to create socket for service `%s'"), - serviceName); - GNUNET_free (sa); - return; - } - if (GNUNET_NETWORK_socket_setsockopt - (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "setsockopt"); -#ifdef IPV6_V6ONLY - if ( (sa->sa_family == AF_INET6) && - (GNUNET_NETWORK_socket_setsockopt - (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "setsockopt"); -#endif - - if (GNUNET_NETWORK_socket_bind - (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to bind listening socket for service `%s' to address `%s': %s\n"), - serviceName, - GNUNET_a2s (sa, addr_len), - STRERROR (errno)); - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); - GNUNET_free (sa); - return; - } - if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "listen"); - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); - GNUNET_free (sa); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("ARM now monitors connections to service `%s' at `%s'\n"), - serviceName, - GNUNET_a2s (sa, addr_len)); - serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); - serviceListeningInfo->serviceName = GNUNET_strdup (serviceName); - serviceListeningInfo->service_addr = sa; - serviceListeningInfo->service_addr_len = addr_len; - serviceListeningInfo->listeningSocket = sock; - serviceListeningInfo->acceptTask = - GNUNET_SCHEDULER_add_read_net (scheduler, - GNUNET_TIME_UNIT_FOREVER_REL, sock, - &acceptConnection, - serviceListeningInfo); - GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head, - serviceListeningInfoList_tail, - serviceListeningInfo); -} - - -/** - * Callback function, checks whether the current tokens are representing a service, - * gets its addresses and create listening socket for it. - * - * @param cls callback data, not used - * @param section configuration section - * @param option configuration option - * @param value the option's value - */ -static void -checkPortNumberCB (void *cls, - const char *section, - const char *option, - const char *value) -{ - struct sockaddr **addrs; - socklen_t *addr_lens; - int ret; - unsigned int i; - - if ( (strcasecmp (section, "arm") == 0) || - (strcasecmp (option, "AUTOSTART") != 0) || - (strcasecmp (value, "YES") != 0) || - (isInDefaultList (section) == GNUNET_YES) ) - return; - if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs, - &addr_lens))) - return; - /* this will free (or capture) addrs[i] */ - for (i = 0; i < ret; i++) - createListeningSocket (addrs[i], addr_lens[i], section); - GNUNET_free (addrs); - GNUNET_free (addr_lens); -} - - -/** - * Entry point to the Service Manager - * - * @param configurationHandle configuration to use to get services - * @param sched scheduler to handle clients and services communications - */ -void -prepareServices (const struct GNUNET_CONFIGURATION_Handle - *configurationHandle, struct GNUNET_SCHEDULER_Handle *sched) -{ - char *defaultServicesString; - - scheduler = sched; - cfg = configurationHandle; - /* Split the default services into a list */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES", - &defaultServicesString)) - { - addDefaultServicesToList (defaultServicesString); - GNUNET_free (defaultServicesString); - } - /* Spot the services from the configuration and create a listening - socket for each */ - GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL); -} - -/* end of gnunet-service-manager.c */ diff --git a/src/arm/gnunet_service_arm_.h b/src/arm/gnunet_service_arm_.h deleted file mode 100644 index 1e55051e0..000000000 --- a/src/arm/gnunet_service_arm_.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2010 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file arm/gnunet_service_arm_.h - * @brief function prototypes for gnunet_service_arm.c, and gnunet_service_manager.c - * @author Safey Abdel Halim - */ - -#ifndef GNUNET_SERVICE_ARM__H -#define GNUNET_SERVICE_ARM__H - -void start_service (struct GNUNET_SERVER_Client *client, - const char *servicename); - -/** - * Stop listening for connections to a service. - * - * @param serviceName name of service to stop listening for - * @return GNUNET_OK if we stopped to listen, GNUNET_NO if we were - * not listening - */ -int stop_listening (const char *serviceName); - -void prepareServices (const struct GNUNET_CONFIGURATION_Handle - *configurationHandle, - struct GNUNET_SCHEDULER_Handle *sched); - -#endif