redundant
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
index c9736982fee8627e6252e55b7f423ad6371bb1a1..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);
 }
 
 
@@ -370,8 +380,6 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename)
       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_Client *client, const char *servicename)
   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);
@@ -407,6 +415,7 @@ 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);
@@ -439,10 +448,21 @@ stop_service (struct GNUNET_SERVER_Client *client, const char *servicename)
     }
   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);
     }
 }
@@ -520,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))
     {
@@ -534,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);
         }
@@ -543,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
@@ -595,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");
         }
@@ -636,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 !=
@@ -684,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);
 }