*/
struct GNUNET_TIME_Absolute restart_at;
+ /**
+ * Time we asked the service to shut down (used to calculate time it took
+ * the service to terminate).
+ */
+ struct GNUNET_TIME_Absolute killed_at;
+
/**
* Is this service to be started by default (or did a client tell us explicitly
* to start it)? GNUNET_NO if the service is started only upon 'accept' on a
*/
int is_default;
+ /**
+ * Should we use pipes to signal this process? (YES for Java binaries and if we
+ * are on Windoze).
+ */
+ int pipe_control;
};
/**
"Starting service `%s' using binary `%s' and configuration `%s'\n",
sl->name, sl->binary, sl->config);
#endif
+ GNUNET_assert (NULL == sl->proc);
if (GNUNET_YES == use_debug)
sl->proc =
- do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, "-L",
+ do_start_process (sl->pipe_control,
+ lsocks, loprefix, sl->binary, "-c", sl->config, "-L",
"DEBUG", options, NULL);
else
sl->proc =
- do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config,
+ do_start_process (sl->pipe_control,
+ lsocks, loprefix, sl->binary, "-c", sl->config,
options, NULL);
if (sl->proc == NULL)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"),
return sizeof (struct GNUNET_ARM_ResultMessage);
}
+/**
+ * Transmit the list of running services.
+ *
+ * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message
+ * @param size number of bytes available in buf
+ * @param buf where to copy the message, NULL on error
+ * @return number of bytes copied to buf
+ */
+static size_t
+write_list_result (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_ARM_ListResultMessage *msg = cls;
+ struct GNUNET_ARM_ListResultMessage *rslt;
+ size_t rslt_size;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not send list result to client\n"));
+ return 0; /* error, not much we can do */
+ }
+
+ GNUNET_assert (size >= msg->header.size);
+ rslt = buf;
+ rslt->header.size = htons (msg->header.size);
+ rslt->header.type = htons (msg->header.type);
+ rslt->count = htons (msg->count);
+
+ size_t list_size = msg->header.size
+ - sizeof (struct GNUNET_ARM_ListResultMessage);
+ memcpy (&rslt[1], &msg[1], list_size);
+
+ rslt_size = msg->header.size;
+ GNUNET_free (msg);
+ return rslt_size;
+}
+
/**
* Signal our client that we will start or stop the
sl = running_head;
while (sl != NULL)
{
- if (0 == strcmp (sl->name, name))
+ if (0 == strcasecmp (sl->name, name))
return sl;
sl = sl->next;
}
const char *servicename;
struct ServiceList *sl;
uint16_t size;
-
+
size = ntohs (message->size);
size -= sizeof (struct GNUNET_MessageHeader);
servicename = (const char *) &message[1];
"Sending kill signal to service `%s', waiting for process to die.\n",
servicename);
#endif
+ sl->killed_at = GNUNET_TIME_absolute_get ();
if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM))
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
sl->killing_client = client;
GNUNET_SERVER_client_keep (client);
}
+/**
+ * Handle LIST-message.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_list (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_ARM_ListResultMessage *msg;
+ size_t string_list_size;
+ size_t total_size;
+ struct ServiceList *sl;
+ uint16_t count;
+
+ if (NULL == client)
+ return;
+
+ count = 0;
+ string_list_size = 0;
+ /* first count the running processes get their name's size */
+ for (sl = running_head; sl != NULL; sl = sl->next)
+ {
+ if (sl->proc != NULL)
+ {
+ string_list_size += strlen (sl->name);
+ string_list_size += strlen (sl->binary);
+ string_list_size += 4;
+ count++;
+ }
+ }
+ total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
+ + string_list_size;
+ msg = GNUNET_malloc (total_size);
+ msg->header.size = total_size;
+ msg->header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
+ msg->count = count;
+
+ char *pos = (char *)&msg[1];
+ for (sl = running_head; sl != NULL; sl = sl->next)
+ {
+ if (sl->proc != NULL)
+ {
+ size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
+ GNUNET_snprintf(pos, s, "%s (%s)", sl->name, sl->binary);
+ pos += s;
+ }
+ }
+
+ GNUNET_SERVER_notify_transmit_ready (client,
+ msg->header.size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &write_list_result, msg);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
/**
* We are done with everything. Stop remaining
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n",
pos->name);
+ pos->killed_at = GNUNET_TIME_absolute_get ();
if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
}
next = pos->next;
if (pos->proc == NULL)
- {
- if (GNUNET_YES == in_shutdown)
- free_service (pos);
- continue;
- }
+ {
+ if (GNUNET_YES == in_shutdown)
+ free_service (pos);
+ continue;
+ }
if ((GNUNET_SYSERR ==
(ret =
GNUNET_OS_process_status (pos->proc, &statusType, &statusCode)))
|| (statusType == GNUNET_OS_PROCESS_RUNNING)))
continue;
if (statusType == GNUNET_OS_PROCESS_EXITED)
- {
- statstr = _( /* process termination method */ "exit");
- statcode = statusCode;
- }
+ {
+ statstr = _( /* process termination method */ "exit");
+ statcode = statusCode;
+ }
else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
- {
- statstr = _( /* process termination method */ "signal");
- statcode = statusCode;
- }
+ {
+ statstr = _( /* process termination method */ "signal");
+ statcode = statusCode;
+ }
else
- {
- statstr = _( /* process termination method */ "unknown");
- statcode = 0;
- }
+ {
+ statstr = _( /* process termination method */ "unknown");
+ statcode = 0;
+ }
+ if (0 != pos->killed_at.abs_value)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Service `%s' took %llu ms to terminate\n"),
+ pos->name,
+ GNUNET_TIME_absolute_get_duration (pos->killed_at).rel_value);
+ }
GNUNET_OS_process_close (pos->proc);
pos->proc = NULL;
if (NULL != pos->killing_client)
GNUNET_SERVER_client_persist_ (client);
}
-
/**
* Signal handler called for SIGCHLD. Triggers the
* respective handler by writing to the trigger pipe.
/* not a service section */
return;
}
+ sl = find_service (section);
+ if (NULL != sl)
+ {
+ /* got the same section twice!? */
+ GNUNET_break (0);
+ return;
+ }
config = NULL;
if ((GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG",
sl->config = config;
sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
+#if WINDOWS
+ sl->pipe_control = GNUNET_YES;
+#else
+ if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
+ sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
+#endif
GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
if (GNUNET_YES !=
GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
{&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
{&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN,
sizeof (struct GNUNET_MessageHeader)},
+ {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
+ sizeof (struct GNUNET_MessageHeader)},
{NULL, NULL, 0, 0}
};
char *defaultservices;
int ret;
struct GNUNET_SIGNAL_Context *shc_chld;
- sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
+ sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
GNUNET_assert (sigpipe != NULL);
shc_chld =
GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);