gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r11280 - gnunet/src/arm


From: gnunet
Subject: [GNUnet-SVN] r11280 - gnunet/src/arm
Date: Mon, 10 May 2010 13:33:03 +0200

Author: safey
Date: 2010-05-10 13:33:03 +0200 (Mon, 10 May 2010)
New Revision: 11280

Added:
   gnunet/src/arm/gnunet-service-manager.c
   gnunet/src/arm/gnunet_service_arm_.h
   gnunet/src/arm/test_gnunet_service_manager.c
Modified:
   gnunet/src/arm/Makefile.am
   gnunet/src/arm/gnunet-service-arm.c
Log:
gnunet service manager creates listening sockets for services having port 
fields in their configuration entries and runs those services whenever clients 
try to connect to them

Modified: gnunet/src/arm/Makefile.am
===================================================================
--- gnunet/src/arm/Makefile.am  2010-05-10 11:20:58 UTC (rev 11279)
+++ gnunet/src/arm/Makefile.am  2010-05-10 11:33:03 UTC (rev 11280)
@@ -34,7 +34,8 @@
   $(GN_LIBINTL)
 
 gnunet_service_arm_SOURCES = \
- gnunet-service-arm.c         
+ gnunet-service-arm.c  gnunet_service_arm_.h \
+ gnunet-service-manager.c       
 gnunet_service_arm_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(GN_LIBINTL)
@@ -48,7 +49,8 @@
 
 check_PROGRAMS = \
  test_arm_api \
- test_exponential_backoff
+ test_exponential_backoff \
+ test_gnunet_service_manager
 
 check_SCRIPTS = \
  test_gnunet_arm.sh
@@ -67,6 +69,12 @@
   $(top_builddir)/src/arm/libgnunetarm.la \
   $(top_builddir)/src/util/libgnunetutil.la
 
+test_gnunet_service_manager_SOURCES = \
+ test_gnunet_service_manager.c
+ test_gnunet_service_manager_LDADD = \
+  $(top_builddir)/src/arm/libgnunetarm.la \
+  $(top_builddir)/src/util/libgnunetutil.la  
+
 EXTRA_DIST = \
   test_arm_api_data.conf \
   do_start_process.c \

Modified: gnunet/src/arm/gnunet-service-arm.c
===================================================================
--- gnunet/src/arm/gnunet-service-arm.c 2010-05-10 11:20:58 UTC (rev 11279)
+++ gnunet/src/arm/gnunet-service-arm.c 2010-05-10 11:33:03 UTC (rev 11280)
@@ -41,6 +41,7 @@
 #include "gnunet_protocols.h"
 #include "gnunet_service_lib.h"
 #include "gnunet_signal_lib.h"
+#include "gnunet_service_arm_.h"
 #include "arm.h"
 
 
@@ -61,6 +62,7 @@
  */
 struct ServiceList;
 
+
 /**
  * List of our services.
  */
@@ -451,7 +453,7 @@
  * @param client who is asking for this
  * @param servicename name of the service to start
  */
-static void
+void
 start_service (struct GNUNET_SERVER_Client *client, const char *servicename)
 {
   struct ServiceList *sl;
@@ -1061,6 +1063,9 @@
 #endif
     }
 
+  /* create listening sockets for future services*/
+  prepareServices (cfg, sched);
+  
   /* process client requests */
   GNUNET_SERVER_add_handlers (server, handlers);
 

Added: gnunet/src/arm/gnunet-service-manager.c
===================================================================
--- gnunet/src/arm/gnunet-service-manager.c                             (rev 0)
+++ gnunet/src/arm/gnunet-service-manager.c     2010-05-10 11:33:03 UTC (rev 
11280)
@@ -0,0 +1,787 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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
+ */
+
+#include "platform.h"
+#include "gnunet_service_lib.h"
+#include "gnunet_configuration_lib.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_service_arm_.h"
+
+
+#define DEBUG_SERVICE_MANAGER GNUNET_NO
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+#define BUFFER_SIZE (63 * 1024)
+#define REASON_CLIENT 1
+#define REASON_SERVICE 2
+
+static char **defaultServicesList;
+static int numDefaultServices = 0;
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+static struct GNUNET_SCHEDULER_Handle *scheduler;
+
+struct StartedService
+{
+  const char *serviceName;
+  struct StartedService *next;
+};
+
+static struct StartedService *startedServices = NULL;
+
+
+/* Functions prototypes */
+static void
+receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+static void
+receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+struct ServiceListeningInfo
+{
+  struct ServiceListeningInfo *next;
+  struct ServiceListeningInfo *prev;
+  const char *serviceName;
+  struct sockaddr *service_addr;
+  socklen_t service_addr_len;
+  struct sockaddr client_addr;
+  socklen_t client_addr_len;
+  struct GNUNET_NETWORK_Handle *listeningSocket;
+  GNUNET_SCHEDULER_TaskIdentifier acceptTask;
+};
+
+static struct ServiceListeningInfo *serviceListeningInfoList_head;
+static struct ServiceListeningInfo *serviceListeningInfoList_tail;
+
+/**
+ * Information of the connection: client-arm-service
+ */
+struct ServiceInfo
+{
+  const char *serviceName;
+  struct GNUNET_NETWORK_Handle *armClientSocket;
+  struct GNUNET_NETWORK_Handle *armServiceSocket;
+  struct sockaddr *service_addr;
+  socklen_t service_addr_len;
+  char clientBuffer[BUFFER_SIZE];
+  ssize_t clientBufferDataLength;
+  char *clientBufferPos;
+  char serviceBuffer[BUFFER_SIZE];
+  ssize_t serviceBufferDataLength;
+  char *serviceBufferPos;
+  GNUNET_SCHEDULER_TaskIdentifier clientReceivingTask;
+  GNUNET_SCHEDULER_TaskIdentifier serviceReceivingTask;
+  GNUNET_SCHEDULER_TaskIdentifier acceptTask;
+};
+
+
+static struct ServiceInfo *
+newServiceInfo (const char *serviceName, struct sockaddr *service_addr,
+               socklen_t service_addr_len)
+{
+  struct ServiceInfo *serviceInfo =
+    GNUNET_malloc (sizeof (struct ServiceInfo));
+  serviceInfo->serviceName = serviceName;
+  serviceInfo->service_addr = service_addr;
+  serviceInfo->service_addr_len = service_addr_len;
+  serviceInfo->serviceBufferPos = serviceInfo->serviceBuffer;
+  serviceInfo->clientBufferPos = serviceInfo->clientBuffer;
+  return serviceInfo;
+}
+
+
+static struct ServiceListeningInfo *
+newServiceListeningInfo (const char *serviceName,
+                        struct sockaddr *sa, socklen_t service_addr_len,
+                        struct GNUNET_NETWORK_Handle *listeningSocket)
+{
+  struct ServiceListeningInfo *serviceListeningInfo =
+    GNUNET_malloc (sizeof (struct ServiceListeningInfo));
+
+  serviceListeningInfo->client_addr_len =
+    sizeof (serviceListeningInfo->client_addr);
+  serviceListeningInfo->serviceName = serviceName;
+  serviceListeningInfo->service_addr = sa;
+  serviceListeningInfo->service_addr_len = service_addr_len;
+  serviceListeningInfo->listeningSocket = listeningSocket;
+  GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
+                              serviceListeningInfoList_tail,
+                              serviceListeningInfo);
+  return serviceListeningInfo;
+}
+
+
+#if DEBUG_SERVICE_MANAGER
+static void
+printDefaultServicesList ()
+{
+  int i;
+  for (i = 0; i < numDefaultServices; i++)
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Service: %s\n",
+               defaultServicesList[i]);
+}
+#endif
+
+
+/**
+ * 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 (char *services)
+{
+  int i = 0;
+  char *token;
+
+  /* How many services are there */
+  while (services[i] != '\0')
+    {
+      if (services[i] == ' ')
+       {
+         numDefaultServices++;
+       }
+      i++;
+    }
+  numDefaultServices++;
+  defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *));
+  token = strtok ((char *) services, " ");
+
+  i = 0;
+  while (NULL != token)
+    {
+      defaultServicesList[i++] = token;
+      token = strtok (NULL, " ");
+    }
+}
+
+/**
+ * Checks whether the serviceName is in the list of default services
+ * 
+ * @param serviceName string to check its existance in the list
+ */
+static int
+isInDefaultList (const char *serviceName)
+{
+  int i;
+  for (i = 0; i < numDefaultServices; i++)
+    {
+      if (strcmp (serviceName, defaultServicesList[i]) == 0)
+       return GNUNET_YES;
+    }
+  return GNUNET_NO;
+}
+
+
+static int
+isServiceAlreadyStarted (const char *serviceName)
+{
+  struct StartedService *service;
+  service = startedServices;
+  while (NULL != service)
+    {
+      if (strcmp (service->serviceName, serviceName) == 0)
+       return GNUNET_OK;
+      service = service->next;
+    }
+  return GNUNET_NO;
+}
+
+
+static void
+setStartedService (const char *serviceName)
+{
+  if (startedServices == NULL)
+    {
+      startedServices = GNUNET_malloc (sizeof (struct StartedService));
+      startedServices->serviceName = GNUNET_strdup (serviceName);
+      startedServices->next = NULL;
+    }
+  else
+    {
+      struct StartedService *service =
+       GNUNET_malloc (sizeof (struct StartedService));
+      service->serviceName = GNUNET_strdup (serviceName);
+      service->next = startedServices;
+      startedServices = service;
+    }
+}
+
+
+static void
+closeClientAndServiceSockets (struct ServiceInfo *serviceInfo, int reason)
+{
+  if (NULL != serviceInfo->armClientSocket)
+    {
+      if (0 != (REASON_SERVICE & reason))
+       GNUNET_SCHEDULER_cancel (scheduler, serviceInfo->clientReceivingTask);
+      if (GNUNET_SYSERR ==
+         GNUNET_NETWORK_socket_close (serviceInfo->armClientSocket))
+       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
+      serviceInfo->armClientSocket = NULL;
+    }
+  if (NULL != serviceInfo->armServiceSocket)
+    {
+      if (0 != (REASON_CLIENT & reason))
+       GNUNET_SCHEDULER_cancel (scheduler,
+                                serviceInfo->serviceReceivingTask);
+
+      if (GNUNET_SYSERR ==
+         GNUNET_NETWORK_socket_close (serviceInfo->armServiceSocket))
+       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
+      serviceInfo->armServiceSocket = NULL;
+    }
+
+  GNUNET_free (serviceInfo);
+}
+
+
+/**
+ * Forward messages sent from service to client
+ * 
+ * @param cls callback data, for the communication between client and service
+ * @param tc context
+ */
+static void
+forwardToClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceInfo *serviceInfo = cls;
+  ssize_t numberOfBytesSent;
+
+  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+    {
+      /* Ignore shutdown signal, reschedule yourself */
+      GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                     serviceInfo->armClientSocket,
+                                     &forwardToClient, serviceInfo);
+      return;
+    }
+
+  /* Forwarding service response to client */
+  numberOfBytesSent =
+    GNUNET_NETWORK_socket_send (serviceInfo->armClientSocket,
+                               serviceInfo->serviceBufferPos,
+                               serviceInfo->serviceBufferDataLength);
+  if ((numberOfBytesSent == GNUNET_SYSERR) || (numberOfBytesSent == 0))
+    {
+      /* Error occured or connection closed by client */
+      closeClientAndServiceSockets (serviceInfo,
+                                   (REASON_CLIENT & REASON_SERVICE));
+      return;
+    }
+  else if (numberOfBytesSent < serviceInfo->serviceBufferDataLength)
+    {
+      /* Not all service data were sent to client */
+      serviceInfo->serviceBufferPos += numberOfBytesSent;
+      serviceInfo->serviceBufferDataLength =
+       serviceInfo->serviceBufferDataLength - numberOfBytesSent;
+
+      /* Scheduling writing again for completing the remaining data to be sent 
*/
+      GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                     serviceInfo->armClientSocket,
+                                     &forwardToClient, serviceInfo);
+    }
+  else
+    {
+      /* Data completely sent */
+      serviceInfo->serviceBufferPos = serviceInfo->serviceBuffer;
+    }
+
+  /* Now we are ready to receive more data, rescheduling receiving from 
Service */
+  serviceInfo->serviceReceivingTask =
+    GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                  serviceInfo->armServiceSocket,
+                                  &receiveFromService, serviceInfo);
+}
+
+
+/**
+ * Receive service messages sent by the service and forward it to client
+ * 
+ * @param cls callback data, serviceInfo struct for the communication between 
client and service
+ * @param tc context
+ */
+static void
+receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+
+  struct ServiceInfo *serviceInfo = cls;
+
+  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+    {
+      /* Neglect shutdown signal, reschedule yourself */
+      serviceInfo->serviceReceivingTask =
+       GNUNET_SCHEDULER_add_read_net (scheduler,
+                                      GNUNET_TIME_UNIT_FOREVER_REL,
+                                      serviceInfo->armServiceSocket,
+                                      &receiveFromService, serviceInfo);
+      return;
+    }
+
+  serviceInfo->serviceBufferDataLength =
+    GNUNET_NETWORK_socket_recv (serviceInfo->armServiceSocket,
+                               serviceInfo->serviceBuffer, BUFFER_SIZE);
+
+  if (serviceInfo->serviceBufferDataLength <= 0)
+    {
+      /* The service has closed the connection or an error occured */
+      if (serviceInfo->serviceBufferDataLength == 0)
+       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                   _("Service `%s' closed connection! \n"),
+                   serviceInfo->serviceName);
+      else
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     _("Error receiving from service:%d\n"), errno);
+       }
+      closeClientAndServiceSockets (serviceInfo, REASON_SERVICE);
+      return;
+    }
+
+  /* Forwarding Service data to Client */
+  GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                 serviceInfo->armClientSocket,
+                                 &forwardToClient, serviceInfo);
+}
+
+
+/**
+ * Forward client message to service
+ * 
+ * @param cls callback data, serviceInfo struct for the communication between 
client and service
+ * @param tc context
+ */
+static void
+forwardToService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceInfo *serviceInfo = cls;
+  ssize_t numberOfBytesSent;
+
+  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+    {
+      /* Neglect shutdown signal, reschedule yourself */
+      GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                     serviceInfo->armServiceSocket,
+                                     &forwardToService, serviceInfo);
+      return;
+    }
+
+
+  /* Forwarding client's message to service */
+  numberOfBytesSent =
+    GNUNET_NETWORK_socket_send (serviceInfo->armServiceSocket,
+                               serviceInfo->clientBufferPos,
+                               serviceInfo->clientBufferDataLength);
+  if ((numberOfBytesSent == GNUNET_SYSERR) || (numberOfBytesSent == 0))
+    {
+      /* Error occured or connection closed by service */
+      closeClientAndServiceSockets (serviceInfo,
+                                   (REASON_CLIENT & REASON_SERVICE));
+      return;
+    }
+  else if (numberOfBytesSent < serviceInfo->clientBufferDataLength)
+    {
+      /* Not all client data were sent to the service */
+      serviceInfo->clientBufferPos += numberOfBytesSent;
+      serviceInfo->clientBufferDataLength =
+       serviceInfo->clientBufferDataLength - numberOfBytesSent;
+
+      /* Scheduling writing again for completing the remaining data to be sent 
*/
+      GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                     serviceInfo->armServiceSocket,
+                                     &forwardToService, serviceInfo);
+    }
+  else
+    {
+      /* Data completely sent */
+      serviceInfo->clientBufferPos = serviceInfo->clientBuffer;
+    }
+
+  /* Now, we are ready to receive more data. Rescheduling the receiving from 
client */
+  serviceInfo->clientReceivingTask =
+    GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                  serviceInfo->armClientSocket,
+                                  &receiveFromClient, serviceInfo);
+}
+
+
+
+/**
+ * Message sent from client to service (faked by ARM, since it's the first 
connection),
+ * ARM will receive the message and forward it to the running service
+ * 
+ * @param cls callback data, serviceInfo struct for the communication between 
client and service
+ * @param tc context 
+ */
+static void
+receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceInfo *serviceInfo = cls;
+
+  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+    {
+      /* Neglect the shutdown signal, schedule yourself */
+      serviceInfo->clientReceivingTask =
+       GNUNET_SCHEDULER_add_read_net (scheduler,
+                                      GNUNET_TIME_UNIT_FOREVER_REL,
+                                      serviceInfo->armClientSocket,
+                                      &receiveFromClient, serviceInfo);
+      return;
+    }
+
+  /* Receive client's message */
+  serviceInfo->clientBufferDataLength =
+    GNUNET_NETWORK_socket_recv (serviceInfo->armClientSocket,
+                               serviceInfo->clientBuffer, BUFFER_SIZE);
+
+  if (serviceInfo->clientBufferDataLength <= 0)
+    {
+      /* The client has closed the connection or and error occured */
+      if (serviceInfo->clientBufferDataLength == 0)
+       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                   _("Client closed connection with service:`%s'\n"),
+                   serviceInfo->serviceName);
+      else
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   _("Error receiving from client!:%d \n"), errno);
+      closeClientAndServiceSockets (serviceInfo, REASON_CLIENT);
+      return;
+    }
+
+  /* Forwarding request to service */
+  GNUNET_SCHEDULER_add_write_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                 serviceInfo->armServiceSocket,
+                                 &forwardToService, serviceInfo);
+}
+
+
+/**
+ * ARM connects to the just created service, 
+ * starts the processes for relaying messages between the client and the 
service
+ * 
+ * @param cls callback data, serviceInfo struct for the communication between 
client and service
+ * @param tc context
+ */
+static void
+connectToService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceInfo *serviceInfo = cls;
+
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
+    {
+      /* Service is not up. Unable to proceed */
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Unable to start service `%s': timeout\n"),
+                 serviceInfo->serviceName);
+      closeClientAndServiceSockets (serviceInfo,
+                                   (REASON_CLIENT & REASON_SERVICE));
+      return;
+    }
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Unable to start service `%s': shutdown\n"),
+                 serviceInfo->serviceName);
+      closeClientAndServiceSockets (serviceInfo,
+                                   (REASON_CLIENT & REASON_SERVICE));
+      return;
+    }
+  GNUNET_break (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE));
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Service `%s' started\n"),
+             serviceInfo->serviceName);
+
+  /* Now service is up and running, connect to it */
+  serviceInfo->armServiceSocket =
+    GNUNET_NETWORK_socket_create (serviceInfo->service_addr->sa_family,
+                                 SOCK_STREAM, 0);
+  if (NULL == serviceInfo->armServiceSocket)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _
+                 ("Unable to start service `%s': failed to create socket\n"),
+                 serviceInfo->serviceName);
+      closeClientAndServiceSockets (serviceInfo,
+                                   (REASON_CLIENT & REASON_SERVICE));
+      return;
+    }
+
+  if ((GNUNET_SYSERR ==
+       GNUNET_NETWORK_socket_connect (serviceInfo->armServiceSocket,
+                                     serviceInfo->service_addr,
+                                     serviceInfo->service_addr_len))
+      && (EINPROGRESS != errno))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Unable to start service `%s': failed to connect\n"),
+                 serviceInfo->serviceName);
+      closeClientAndServiceSockets (serviceInfo,
+                                   (REASON_CLIENT & REASON_SERVICE));
+      return;
+    }
+  /* Handling requests from client to service */
+  serviceInfo->clientReceivingTask =
+    GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                  serviceInfo->armClientSocket,
+                                  &receiveFromClient, serviceInfo);
+
+  /* Handling service responses to client */
+  serviceInfo->serviceReceivingTask =
+    GNUNET_SCHEDULER_add_read_net (scheduler, GNUNET_TIME_UNIT_FOREVER_REL,
+                                  serviceInfo->armServiceSocket,
+                                  &receiveFromService, serviceInfo);
+}
+
+
+static void
+stopServiceListeningSockets (struct ServiceListeningInfo
+                            *serviceListeningInfo)
+{
+  struct ServiceListeningInfo *pos = serviceListeningInfoList_head;
+  struct ServiceListeningInfo *tmp;
+
+  while (NULL != pos)
+    {
+      if ((strcmp (pos->serviceName, serviceListeningInfo->serviceName) == 0)
+         && (pos != serviceListeningInfo))
+       {
+         GNUNET_SCHEDULER_cancel (scheduler, pos->acceptTask);
+         GNUNET_NETWORK_socket_close (pos->listeningSocket);
+         tmp = pos;
+         pos = pos->next;
+         GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
+                                      serviceListeningInfoList_tail, tmp);
+         GNUNET_free (tmp->service_addr);
+         GNUNET_free (tmp);
+         continue;
+       }
+      pos = pos->next;
+    }
+}
+
+
+/**
+ * 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, serviceInfo struct for the communication between 
client and service
+ * @param tc context 
+ */
+static void
+acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceListeningInfo *serviceListeningInfo = cls;
+  struct ServiceInfo *serviceInfo;
+
+  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+    return;
+
+  if ((NULL == startedServices)
+      || (GNUNET_NO ==
+         isServiceAlreadyStarted (serviceListeningInfo->serviceName)))
+    {
+      /* First request to receive at all, or first request to connect to that 
service */
+      /* Accept client's connection */
+      serviceInfo =
+       newServiceInfo (serviceListeningInfo->serviceName,
+                       serviceListeningInfo->service_addr,
+                       serviceListeningInfo->service_addr_len);
+      serviceInfo->armClientSocket =
+       GNUNET_NETWORK_socket_accept (serviceListeningInfo->listeningSocket,
+                                     &(serviceListeningInfo->client_addr),
+                                     &(serviceListeningInfo->
+                                       client_addr_len));
+      if (NULL == serviceInfo->armClientSocket)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     _
+                     ("Unable to accept connection for service `%s': Invalid 
socket\n"),
+                     serviceListeningInfo->serviceName);
+         return;
+       }
+
+
+      /* 
+       * Close listening socket, start service, 
+       * and stop all listening sockets associated with that service 
+       * and free their correspondent ServiceInfo objects
+       */
+      GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket);
+      start_service (NULL, serviceListeningInfo->serviceName);
+      setStartedService (serviceListeningInfo->serviceName);
+      stopServiceListeningSockets (serviceListeningInfo);
+
+      /* Notify me when the service is up and running */
+      GNUNET_CLIENT_service_test (scheduler,
+                                 serviceListeningInfo->serviceName, cfg,
+                                 TIMEOUT, &connectToService, serviceInfo);
+    }
+}
+
+
+/**
+ * Creating a listening socket for each of the service's addresses and wait 
for the first incoming connection to it
+ * 
+ * @param addrs list of addresses associated with the service
+ * @param addr_lens list containing length for each of the addresses in addrs
+ * @param numOfAddresses length of the addr_lens array
+ * @param serviceName the name of the service in question
+ */
+static void
+createListeningSocket (struct sockaddr **addrs, socklen_t * addr_lens,
+                      int numOfAddresses, char *serviceName)
+{
+  int i;
+  struct GNUNET_NETWORK_Handle *socket;
+  struct sockaddr *sa;
+  socklen_t addr_len;
+  struct ServiceListeningInfo *serviceListeningInfo;
+
+  for (i = 0; i < numOfAddresses; i++)
+    {
+      sa = addrs[i];
+      addr_len = addr_lens[i];
+      switch (sa->sa_family)
+       {
+       case AF_INET:
+         socket = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
+         break;
+       case AF_INET6:
+         socket = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+         break;
+       default:
+         socket = NULL;
+         break;
+       }
+      if (NULL == socket)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     "Unable to create socket for service %s", serviceName);
+         continue;
+       }
+
+      /* Bind */
+      if (GNUNET_NETWORK_socket_bind
+         (socket, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     _("Unable to bind listening socket for service `%s'\n"),
+                     serviceName);
+         continue;
+       }
+
+      /* Listen */
+      if (GNUNET_NETWORK_socket_listen (socket, 5) != GNUNET_OK)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     _("Error listening socket for service `%s'\n"),
+                     serviceName);
+       }
+
+      serviceListeningInfo =
+       newServiceListeningInfo (serviceName, sa, addr_len, socket);
+      serviceListeningInfo->listeningSocket = socket;
+      serviceListeningInfo->serviceName = serviceName;
+      serviceListeningInfo->service_addr = sa;
+      serviceListeningInfo->service_addr_len = addr_len;
+
+      /* Wait for the first incoming connection */
+      serviceListeningInfo->acceptTask =
+       GNUNET_SCHEDULER_add_read_net (scheduler,
+                                      GNUNET_TIME_UNIT_FOREVER_REL, socket,
+                                      &acceptConnection,
+                                      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 the option's value
+ */
+static void
+checkPortNumberCB (void *cls,
+                  const char *section, const char *option, const char *value)
+{
+  /* The service shouldn't be a default service */
+  if ((strcmp (section, "arm") != 0)
+      && (strcmp (option, "PORT") == 0)
+      && (isInDefaultList (section) == GNUNET_NO))
+    {
+      /* then the section is representing a service */
+      struct sockaddr **addrs;
+      socklen_t *addr_lens;
+      int ret;
+
+      ret =
+       GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs,
+                                            &addr_lens);
+      if (ret == GNUNET_SYSERR)
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   _("Unable to resolve host name for service `%s'\n"),
+                   section);
+      else if (ret != GNUNET_NO)
+       {
+         /* Addresses found for service */
+         createListeningSocket (addrs, addr_lens, ret, (char *) section);
+       }
+      else
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   _("No addresses for service `%s' in configuration\n"),
+                   section);
+    }
+}
+
+/**
+ * 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 */
+  GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES",
+                                        &defaultServicesString);
+  addDefaultServicesToList (defaultServicesString);
+
+#if DEBUG_SERVICE_MANAGER
+  printDefaultServicesList ();
+#endif
+
+  /* Spot the services from the configuration and create a listening socket 
for each */
+  GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL);
+}

Added: gnunet/src/arm/gnunet_service_arm_.h
===================================================================
--- gnunet/src/arm/gnunet_service_arm_.h                                (rev 0)
+++ gnunet/src/arm/gnunet_service_arm_.h        2010-05-10 11:33:03 UTC (rev 
11280)
@@ -0,0 +1,16 @@
+/**
+ * @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);
+void prepareServices (const struct GNUNET_CONFIGURATION_Handle
+                     *configurationHandle,
+                     struct GNUNET_SCHEDULER_Handle *sched);
+
+#endif

Added: gnunet/src/arm/test_gnunet_service_manager.c
===================================================================
--- gnunet/src/arm/test_gnunet_service_manager.c                                
(rev 0)
+++ gnunet/src/arm/test_gnunet_service_manager.c        2010-05-10 11:33:03 UTC 
(rev 11280)
@@ -0,0 +1,106 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 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/test_gnunet_service_manager.c (A mockup testcase, not 
functionally complete)
+ * @brief testcase for gnunet-service-manager.c
+ */
+
+#include "platform.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_program_lib.h"
+
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+
+/* Global Variables */
+static int isOK = GNUNET_OK;
+
+static void 
+hostNameResolveCB(void *cls, 
+                                 const struct sockaddr *addr, 
+                                 socklen_t addrlen)
+{
+       if (NULL == addr)
+               GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name not resolved!\n");
+}
+
+
+static void
+run(void *cls, 
+       struct GNUNET_SCHEDULER_Handle *sched, 
+       char * const *args,
+    const char *cfgfile, 
+    const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+       struct GNUNET_RESOLVER_RequestHandle *resolveRet;
+       
+       /* connect to the resolver service */
+       resolveRet =
+       GNUNET_RESOLVER_hostname_resolve (sched,
+                                         cfg, AF_UNSPEC,
+                                         TIMEOUT,
+                                         &hostNameResolveCB,
+                                         NULL);
+       if (NULL == resolveRet) {
+               GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Unable to resolve our own 
hostname!\n");
+               isOK = GNUNET_NO;
+       }
+}
+
+
+static int
+check()
+{
+       char *const argv[] = {
+           "test-gnunet-service-manager",
+           "-c", "test_arm_api_data.conf",
+       #if VERBOSE
+           "-L", "DEBUG",
+       #endif
+           NULL
+         };
+         struct GNUNET_GETOPT_CommandLineOption options[] = {
+           GNUNET_GETOPT_OPTION_END
+         };
+         
+         /* Running ARM  and running the do_nothing task */
+         GNUNET_assert (GNUNET_OK ==
+                        GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) 
- 1,
+                                            argv,
+                                            "test-gnunet-service-manager",
+                                            "nohelp", options, &run, NULL));
+         return isOK;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int ret;
+  GNUNET_log_setup("test-gnunet-service-manager",
+  #if VERBOSE
+        "DEBUG",
+  #else
+        "WARNING",
+  #endif
+        NULL);
+  ret = check();
+  return ret;
+}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]