redundant
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
index 97d507890b1763f5bd8f796dc2f6002a28f71fb2..c7143e3a7015b1072f64d944da7a42be74153473 100644 (file)
@@ -124,7 +124,7 @@ static struct ServiceList *running;
 /**
  * Our configuration
  */
-static struct GNUNET_CONFIGURATION_Handle *cfg;
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
 /**
  * Our scheduler.
@@ -167,6 +167,8 @@ signal_result (struct GNUNET_SERVER_Client *client,
 {
   uint16_t *res;
 
+  if (NULL == client)
+    return;
 #if DEBUG_ARM
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Telling client that service `%s' is now %s\n",
@@ -182,28 +184,6 @@ signal_result (struct GNUNET_SERVER_Client *client,
 }
 
 
-/**
- * Find the process with the given PID in the
- * given list.
- *
- * @return NULL if it was not found
- */
-static struct ServiceList *
-find_pid (pid_t pid)
-{
-  struct ServiceList *pos;
-
-  pos = running;
-  while (pos != NULL)
-    {
-      if (pos->pid == pid)
-        return pos;
-      pos = pos->next;
-    }
-  return NULL;
-}
-
-
 /**
  * Find the process with the given service
  * name in the given list, remove it and return it.
@@ -257,9 +237,11 @@ static void
 start_process (struct ServiceList *sl)
 {
   char *loprefix;
+  char *options;
   char **argv;
   unsigned int argv_size;
   char *lopos;
+  char *optpos;
   const char *firstarg;
   int use_debug;
 
@@ -268,6 +250,10 @@ start_process (struct ServiceList *sl)
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              sl->name, "PREFIX", &loprefix))
     loprefix = GNUNET_strdup (prefix_command);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             sl->name, "OPTIONS", &options))
+    options = GNUNET_strdup ("");
   use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), sl->name);
@@ -276,7 +262,7 @@ start_process (struct ServiceList *sl)
               "Starting service `%s' using binary `%s' and configuration `%s'\n",
               sl->name, sl->binary, sl->config);
 #endif
-  argv_size = 5;
+  argv_size = 6;
   if (use_debug)
     argv_size += 2;
   lopos = loprefix;
@@ -286,10 +272,18 @@ start_process (struct ServiceList *sl)
         argv_size++;
       lopos++;
     }
+  optpos = options;
+  while ('\0' != *optpos)
+    {
+      if (*optpos == ' ')
+        argv_size++;
+      optpos++;
+    }
   firstarg = NULL;
   argv = GNUNET_malloc (argv_size * sizeof (char *));
   argv_size = 0;
   lopos = loprefix;
+
   while ('\0' != *lopos)
     {
       while (*lopos == ' ')
@@ -316,10 +310,26 @@ start_process (struct ServiceList *sl)
       argv[argv_size++] = "-L";
       argv[argv_size++] = "DEBUG";
     }
+  optpos = options;
+  while ('\0' != *optpos)
+    {
+      while (*optpos == ' ')
+        optpos++;
+      if (*optpos == '\0')
+        continue;
+      argv[argv_size++] = optpos;
+      while (('\0' != *optpos) && (' ' != *optpos))
+        optpos++;
+      if ('\0' == *optpos)
+        continue;
+      *optpos = '\0';
+      optpos++;
+    }
   argv[argv_size++] = NULL;
   sl->pid = GNUNET_OS_start_process_v (firstarg, argv);
   GNUNET_free (argv);
   GNUNET_free (loprefix);
+  GNUNET_free (options);
 }
 
 
@@ -327,8 +337,7 @@ start_process (struct ServiceList *sl)
  * Start the specified service.
  */
 static void
-start_service (struct GNUNET_SERVER_Handle *server,
-               struct GNUNET_SERVER_Client *client, const char *servicename)
+start_service (struct GNUNET_SERVER_Client *client, const char *servicename)
 {
   struct ServiceList *sl;
   char *binary;
@@ -368,10 +377,9 @@ start_service (struct GNUNET_SERVER_Handle *server,
                   config, servicename);
       signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
       GNUNET_free (binary);
+      GNUNET_free (config);
       return;
     }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _("Preparing to start `%s'\n"), servicename);
   sl = GNUNET_malloc (sizeof (struct ServiceList));
   sl->name = GNUNET_strdup (servicename);
   sl->next = running;
@@ -381,7 +389,8 @@ start_service (struct GNUNET_SERVER_Handle *server,
   sl->mtime = sbuf.st_mtime;
   running = sl;
   start_process (sl);
-  signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
+  if (NULL != client)
+    signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
 }
 
 
@@ -390,7 +399,6 @@ free_and_signal (void *cls, struct ServiceList *pos)
 {
   struct GNUNET_SERVER_Client *client = cls;
   /* find_name will remove "pos" from the list! */
-  GNUNET_assert (pos == find_name (pos->name));
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Service `%s' stopped\n", pos->name);
   signal_result (client, pos->name, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
@@ -403,16 +411,16 @@ free_and_signal (void *cls, struct ServiceList *pos)
  * Stop the specified service.
  */
 static void
-stop_service (struct GNUNET_SERVER_Handle *server,
-              struct GNUNET_SERVER_Client *client, const char *servicename)
+stop_service (struct GNUNET_SERVER_Client *client, const char *servicename)
 {
   struct ServiceList *pos;
   struct GNUNET_CLIENT_Connection *sc;
+  unsigned long long port;
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Preparing to stop `%s'\n", servicename);
   pos = find_name (servicename);
-  if (pos->kill_continuation != NULL)
+  if ((pos != NULL) && (pos->kill_continuation != NULL))
     {
       /* killing already in progress */
       signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
@@ -440,10 +448,21 @@ stop_service (struct GNUNET_SERVER_Handle *server,
     }
   else
     {
-      sc = GNUNET_CLIENT_connect (sched, servicename, cfg);
-      GNUNET_CLIENT_service_shutdown (sc);
-      GNUNET_CLIENT_disconnect (sc);
-      signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
+      if ( (GNUNET_OK ==
+           GNUNET_CONFIGURATION_get_value_number (cfg,
+                                                  servicename,
+                                                  "PORT",
+                                                  &port)) &&
+          (NULL != (sc = GNUNET_CLIENT_connect (sched, servicename, cfg))) )
+       {
+         GNUNET_CLIENT_service_shutdown (sc);
+         GNUNET_CLIENT_disconnect (sc);
+         signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
+       }
+      else
+       {
+         signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UNKNOWN);
+       }
       GNUNET_SERVER_receive_done (client, GNUNET_OK);
     }
 }
@@ -453,7 +472,6 @@ stop_service (struct GNUNET_SERVER_Handle *server,
  * Handle START-message.
  *
  * @param cls closure (always NULL)
- * @param server the server handling the message
  * @param client identification of the client
  * @param message the actual message
  * @return GNUNET_OK to keep the connection open,
@@ -461,7 +479,6 @@ stop_service (struct GNUNET_SERVER_Handle *server,
  */
 static void
 handle_start (void *cls,
-              struct GNUNET_SERVER_Handle *server,
               struct GNUNET_SERVER_Client *client,
               const struct GNUNET_MessageHeader *message)
 {
@@ -477,7 +494,7 @@ handle_start (void *cls,
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-  start_service (server, client, servicename);
+  start_service (client, servicename);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -486,7 +503,6 @@ handle_start (void *cls,
  * Handle STOP-message.
  *
  * @param cls closure (always NULL)
- * @param server the server handling the message
  * @param client identification of the client
  * @param message the actual message
  * @return GNUNET_OK to keep the connection open,
@@ -494,7 +510,6 @@ handle_start (void *cls,
  */
 static void
 handle_stop (void *cls,
-             struct GNUNET_SERVER_Handle *server,
              struct GNUNET_SERVER_Client *client,
              const struct GNUNET_MessageHeader *message)
 {
@@ -510,7 +525,7 @@ handle_stop (void *cls,
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-  stop_service (server, client, servicename);
+  stop_service (client, servicename);
 }
 
 
@@ -525,11 +540,12 @@ static void
 maint (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct ServiceList *pos;
-  pid_t pid;
-  int status;
+  struct ServiceList *prev;
+  struct ServiceList *next;
   const char *statstr;
   int statcode;
   struct stat sbuf;
+  int ret;
 
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     {
@@ -539,7 +555,7 @@ maint (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
           running = pos->next;
           if (0 != PLIBC_KILL (pos->pid, SIGTERM))
             GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
-          if (pos->pid != waitpid (pos->pid, NULL, 0))
+          if (GNUNET_OK != GNUNET_OS_process_wait(pos->pid))
             GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
           free_entry (pos);
         }
@@ -548,48 +564,70 @@ maint (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_SCHEDULER_add_delayed (tc->sched,
                                 GNUNET_YES,
                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
-                                MAINT_FREQUENCY, &maint, cfg);
+                                GNUNET_SCHEDULER_NO_TASK,
+                                MAINT_FREQUENCY, &maint, NULL);
 
   /* check for services that died (WAITPID) */
-  while (0 < (pid = waitpid (0, &status, WNOHANG)))
+  prev = NULL;
+  next = running;
+  while (NULL != (pos = next))
     {
-      if (WIFSTOPPED (status) || WIFCONTINUED (status))
-        continue;
-      pos = find_pid (pid);
-      if (pos == NULL)
-        {
-          /* we killed the service */
-          continue;
-        }
-      if (WIFEXITED (status))
-        {
-          statstr = _( /* process termination method */ "exit");
-          statcode = WEXITSTATUS (status);
-        }
-      else if (WTERMSIG (status))
-        {
-          statstr = _( /* process termination method */ "signal");
-          statcode = WTERMSIG (status);
-        }
+      enum GNUNET_OS_ProcessStatusType statusType;
+      unsigned long statusCode;
+     
+      next = pos->next;
+      if (pos->pid == 0)
+       {
+         if (NULL != pos->kill_continuation)
+           {
+             if (prev == NULL)
+               running = next;
+             else
+               prev->next = next;
+             pos->kill_continuation (pos->kill_continuation_cls, pos);     
+           }
+         continue;
+       }
+      if ( (GNUNET_SYSERR == (ret = GNUNET_OS_process_status(pos->pid, 
+                                                            &statusType,
+                                                            &statusCode))) ||
+          ( (ret == GNUNET_NO) ||
+            (statusType == GNUNET_OS_PROCESS_STOPPED) || 
+            (statusType == GNUNET_OS_PROCESS_RUNNING) ) )
+       {
+         prev = pos;
+         continue;
+       }
+      if (statusType == GNUNET_OS_PROCESS_EXITED)
+       {
+         statstr = _( /* process termination method */ "exit");
+         statcode = statusCode;
+       }
+      else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
+       {
+         statstr = _( /* process termination method */ "signal");
+         statcode = statusCode;
+       }
       else
-        {
-          statstr = _( /* process termination method */ "unknown");
-          statcode = 0;
-        }
+       {
+         statstr = _( /* process termination method */ "unknown");
+         statcode = 0;
+       }    
       if (NULL != pos->kill_continuation)
         {
-          pos->kill_continuation (pos->kill_continuation_cls, pos);
-        }
-      else
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                      _
-                      ("Service `%s' terminated with status %s/%d, will try to restart it!\n"),
-                      pos->name, statstr, statcode);
-          /* schedule restart */
-          pos->pid = 0;
+         if (prev == NULL)
+           running = next;
+         else
+           prev->next = next;
+         pos->kill_continuation (pos->kill_continuation_cls, pos);
+         continue;
         }
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                 _("Service `%s' terminated with status %s/%d, will try to restart it!\n"),
+                 pos->name, statstr, statcode);
+      /* schedule restart */
+      pos->pid = 0;
+      prev = pos;
     }
 
   /* check for services that need to be restarted due to
@@ -600,8 +638,7 @@ maint (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       if ((0 == STAT (pos->config, &sbuf)) && (pos->mtime < sbuf.st_mtime))
         {
           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                      _
-                      ("Restarting service `%s' due to configuration file change.\n"));
+                      _("Restarting service `%s' due to configuration file change.\n"));
           if (0 != PLIBC_KILL (pos->pid, SIGTERM))
             GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
         }
@@ -641,12 +678,11 @@ static void
 run (void *cls,
      struct GNUNET_SCHEDULER_Handle *s,
      struct GNUNET_SERVER_Handle *server,
-     struct GNUNET_CONFIGURATION_Handle *c)
+     const struct GNUNET_CONFIGURATION_Handle *c)
 {
   char *defaultservices;
   char *pos;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting...\n");
   cfg = c;
   sched = s;
   if (GNUNET_OK !=
@@ -669,7 +705,7 @@ run (void *cls,
       pos = strtok (defaultservices, " ");
       while (pos != NULL)
         {
-          start_service (server, NULL, pos);
+          start_service (NULL, pos);
           pos = strtok (NULL, " ");
         }
       GNUNET_free (defaultservices);
@@ -689,7 +725,7 @@ run (void *cls,
   GNUNET_SCHEDULER_add_delayed (sched,
                                 GNUNET_YES,
                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
+                                GNUNET_SCHEDULER_NO_TASK,
                                 MAINT_FREQUENCY, &maint, NULL);
 }