* configuration were changed (anything in the section for the service)
* - should have a way to specify dependencies between services and
* manage restarts of groups of services
+ *
+ * + install handler for disconnecting clients!?
*/
#include "platform.h"
-#include "gnunet_client_lib.h"
-#include "gnunet_getopt_lib.h"
-#include "gnunet_os_lib.h"
+#include "gnunet_util_lib.h"
#include "gnunet_protocols.h"
-#include "gnunet_service_lib.h"
-#include "gnunet_signal_lib.h"
#include "gnunet-service-arm.h"
#include "arm.h"
*/
#define EXPONENTIAL_BACKOFF_THRESHOLD (1000 * 60 * 30)
-#define DELAY_SHUTDOWN GNUNET_NO
-
/**
* List of our services.
*/
struct ServiceList
{
/**
- * This is a linked list.
+ * This is a doubly-linked list.
*/
struct ServiceList *next;
+ /**
+ * This is a doubly-linked list.
+ */
+ struct ServiceList *prev;
+
/**
* Name of the service.
*/
/**
* List of running services.
*/
-static struct ServiceList *running;
+static struct ServiceList *running_head;
+
+/**
+ * List of running services.
+ */
+static struct ServiceList *running_tail;
/**
* Our configuration
struct ServiceList *pos;
struct stat sbuf;
- pos = running;
+ pos = running_head;
while (pos != NULL)
{
- /* FIXME: this test for config change is a bit too coarse grained */
+ /* FIXME: this test for config change may be a bit too coarse grained */
if ( (0 == STAT (pos->config, &sbuf)) &&
(pos->mtime < sbuf.st_mtime) &&
(pos->proc != NULL) )
}
-
/**
* Transmit a status result message.
*
}
-
/**
* Signal our client that we will start or stop the
* service.
/**
* Find the process with the given service
- * name in the given list, remove it and return it.
+ * name in the given list and return it.
*
* @param name which service entry to look up
* @return NULL if it was not found
*/
static struct ServiceList *
-find_name (const char *name)
+find_service (const char *name)
{
struct ServiceList *pos;
- struct ServiceList *prev;
- pos = running;
- prev = NULL;
+ pos = running_head;
while (pos != NULL)
{
if (0 == strcmp (pos->name, name))
- {
- if (prev == NULL)
- running = pos->next;
- else
- prev->next = pos->next;
- pos->next = NULL;
- return pos;
- }
- prev = pos;
+ return pos;
pos = pos->next;
}
return NULL;
/**
- * Free an entry in the service list.
+ * Remove and free an entry in the service list.
*
* @param pos entry to free
*/
static void
-free_entry (struct ServiceList *pos)
+free_service (struct ServiceList *pos)
{
+ GNUNET_CONTAINER_DLL_remove (running_head,
+ running_tail,
+ pos);
GNUNET_free_non_null (pos->config);
GNUNET_free_non_null (pos->binary);
GNUNET_free (pos->name);
GNUNET_free (pos);
}
+
#include "do_start_process.c"
+
/**
* Actually start the process for the given service.
*
signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
return GNUNET_SYSERR;
}
- sl = find_name (servicename);
+ sl = find_service (servicename);
if (sl != NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
_("Service `%s' already running.\n"), servicename);
- sl->next = running;
- running = sl;
signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
return GNUNET_SYSERR;
}
(void) stop_listening (servicename);
sl = GNUNET_malloc (sizeof (struct ServiceList));
sl->name = GNUNET_strdup (servicename);
- sl->next = running;
sl->binary = binary;
sl->config = config;
sl->mtime = sbuf.st_mtime;
sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
sl->restartAt = GNUNET_TIME_UNIT_FOREVER_ABS;
-
- running = sl;
+ GNUNET_CONTAINER_DLL_insert (running_head,
+ running_tail,
+ sl);
start_process (sl, lsocks);
if (NULL != client)
signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Preparing to stop `%s'\n"), servicename);
- pos = find_name (servicename);
+ pos = find_service (servicename);
if (pos == NULL)
{
if (GNUNET_OK == stop_listening (servicename))
#endif
signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
- pos->next = running;
- running = pos;
return;
}
#endif
signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
- pos->next = running;
- running = pos;
return;
}
if (pos->proc == NULL)
{
/* process is in delayed restart, simply remove it! */
- free_entry (pos);
+ free_service (pos);
signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
#endif
if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
- pos->next = running;
- running = pos;
pos->killing_client = client;
GNUNET_SERVER_client_keep (client);
}
{
struct ServiceList *pos;
struct ServiceList *next;
- struct ServiceList *prev;
- pos = running;
- prev = NULL;
- while (NULL != pos)
+ next = running_head;
+ while (NULL != (pos = next))
{
next = pos->next;
if (pos->proc == NULL)
- {
- if (prev == NULL)
- running = next;
- else
- prev->next = next;
- free_entry (pos);
- }
- else
- prev = pos;
- pos = next;
+ free_service (pos);
}
}
}
}
-#if DELAY_SHUTDOWN
-/**
- * Dummy task to delay arm shutdown.
- */
-void dummy_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext * tc)
-{
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Dummy task executing\n");
- return;
-}
-#endif
/**
* Task run for shutdown.
* @param tc context
*/
static void
-shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+shutdown_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct ServiceList *pos;
#if DEBUG_ARM
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Stopping all services\n"));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Stopping all services\n"));
#endif
- stop_listening (NULL);
+ if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
+ {
+ GNUNET_SCHEDULER_cancel (child_restart_task);
+ child_restart_task = GNUNET_SCHEDULER_NO_TASK;
+ }
in_shutdown = GNUNET_YES;
- pos = running;
+ stop_listening (NULL);
+ pos = running_head;
while (NULL != pos)
{
if (pos->proc != NULL)
}
pos = pos->next;
}
-#if DELAY_SHUTDOWN
- GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &dummy_task, NULL);
-#endif
- if (running == NULL)
+ if (running_head == NULL)
do_shutdown ();
}
child_restart_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- clean_up_running ();
- if (NULL == running)
- do_shutdown ();
- return;
- }
+ return;
+ GNUNET_assert (GNUNET_NO == in_shutdown);
lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
/* check for services that need to be restarted due to
configuration changes or because the last restart failed */
- pos = running;
+ pos = running_head;
while (pos != NULL)
{
- if ( (pos->proc == NULL) &&
- (GNUNET_YES != in_shutdown) )
+ if (pos->proc == NULL)
{
if (GNUNET_TIME_absolute_get_remaining (pos->restartAt).rel_value == 0)
{
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct ServiceList *pos;
- struct ServiceList *prev;
struct ServiceList *next;
const char *statstr;
int statcode;
child_death_task = GNUNET_SCHEDULER_NO_TASK;
if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
{
+ /* shutdown scheduled us, ignore! */
child_death_task =
GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr,
&maint_child_death, NULL);
GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
/* check for services that died (WAITPID) */
- prev = NULL;
- next = running;
+ next = running_head;
while (NULL != (pos = next))
{
next = pos->next;
if (pos->proc == NULL)
- {
- prev = pos;
- continue;
- }
+ continue;
if ((GNUNET_SYSERR == (ret = GNUNET_OS_process_status (pos->proc,
&statusType,
&statusCode))) ||
( (ret == GNUNET_NO) ||
(statusType == GNUNET_OS_PROCESS_STOPPED) ||
(statusType == GNUNET_OS_PROCESS_RUNNING)) )
- {
- prev = pos;
- continue;
- }
+ continue;
if (statusType == GNUNET_OS_PROCESS_EXITED)
{
pos->proc = NULL;
if (NULL != pos->killing_client)
{
- if (prev == NULL)
- running = next;
- else
- prev->next = next;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Service `%s' stopped\n"),
pos->name);
pos->name, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
GNUNET_SERVER_receive_done (pos->killing_client, GNUNET_OK);
GNUNET_SERVER_client_drop (pos->killing_client);
- free_entry (pos);
+ free_service (pos);
continue;
}
- if ( (GNUNET_YES != in_shutdown) &&
- (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
+ if (GNUNET_YES != in_shutdown)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _
- ("Service `%s' terminated with status %s/%d, will try to restart it!\n"),
- pos->name, statstr, statcode);
+ if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ 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->restartAt
= GNUNET_TIME_relative_to_absolute (pos->backoff);
"Service `%s' terminated with status %s/%d\n",
pos->name, statstr, statcode);
#endif
- prev = pos;
}
- if (in_shutdown)
+ child_death_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr,
+ &maint_child_death, NULL);
+ if (GNUNET_YES == in_shutdown)
clean_up_running ();
- if ( (running == NULL) &&
- (in_shutdown) )
- {
- GNUNET_SERVER_destroy (server);
- }
- else
- {
- child_death_task =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr,
- &maint_child_death, NULL);
- }
+ if ( (NULL == running_head) &&
+ (GNUNET_YES == in_shutdown) )
+ do_shutdown ();
}
return sizeof (struct GNUNET_MessageHeader);
}
+
/**
* Handler for SHUTDOWN message.
*
GNUNET_SERVER_client_keep(client);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Initiating shutdown as requested by client.\n"));
-
GNUNET_SERVER_notify_transmit_ready (client,
sizeof(struct GNUNET_MessageHeader),
GNUNET_TIME_UNIT_FOREVER_REL,