aboutsummaryrefslogtreecommitdiff
path: root/src/arm/arm_api.c
diff options
context:
space:
mode:
authorgrothoff <grothoff@140774ce-b5e7-0310-ab8b-a85725594a96>2009-05-29 00:46:26 +0000
committergrothoff <grothoff@140774ce-b5e7-0310-ab8b-a85725594a96>2009-05-29 00:46:26 +0000
commit6ba89ee6eee308c69d69b6bbebcf2cc67a76ce01 (patch)
tree6b552f40eb089db96409a312a98d9b12bd669102 /src/arm/arm_api.c
ng
git-svn-id: https://gnunet.org/svn/gnunet@8472 140774ce-b5e7-0310-ab8b-a85725594a96
Diffstat (limited to 'src/arm/arm_api.c')
-rw-r--r--src/arm/arm_api.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c
new file mode 100644
index 0000000000..c5bb15fd3c
--- /dev/null
+++ b/src/arm/arm_api.c
@@ -0,0 +1,337 @@
+/*
+ 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/arm_api.c
+ * @brief API for accessing the ARM service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_server_lib.h"
+#include "arm.h"
+
+
+struct ArmContext
+{
+ GNUNET_ARM_Callback callback;
+ void *cls;
+ char *service_name;
+ struct GNUNET_CLIENT_Connection *client;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_TIME_Absolute timeout;
+ uint16_t type;
+};
+
+
+static void
+arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ArmContext *pos = cls;
+ pid_t pid;
+ char *binary;
+ char *config;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+ {
+ if (pos->callback != NULL)
+ pos->callback (pos->cls, GNUNET_YES);
+ GNUNET_free (pos);
+ return;
+ }
+ binary = NULL;
+ config = NULL;
+ /* start service */
+ if ((GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (pos->cfg,
+ "arm",
+ "BINARY",
+ &binary)) ||
+ (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (pos->cfg,
+ "arm", "CONFIG", &config)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Configuration file or binary for ARM not known!\n"));
+ if (pos->callback != NULL)
+ pos->callback (pos->cls, GNUNET_SYSERR);
+ GNUNET_free_non_null (binary);
+ GNUNET_free (pos);
+ return;
+ }
+ pid = GNUNET_OS_start_process (binary, binary, "-d", "-c", config,
+#if DEBUG_ARM
+ "-L", "DEBUG",
+#endif
+ NULL);
+ GNUNET_free (binary);
+ GNUNET_free (config);
+ if (pid == -1)
+ {
+ if (pos->callback != NULL)
+ pos->callback (pos->cls, GNUNET_SYSERR);
+ GNUNET_free (pos);
+ return;
+ }
+ /* FIXME: consider checking again to see if it worked!? */
+ if (pos->callback != NULL)
+ pos->callback (pos->cls, GNUNET_YES);
+ GNUNET_free (pos);
+}
+
+
+static void
+handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct ArmContext *sc = cls;
+ int ret;
+
+ if (msg == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Error receiving response from ARM service\n"));
+ GNUNET_CLIENT_disconnect (sc->client);
+ if (sc->callback != NULL)
+ sc->callback (sc->cls, GNUNET_SYSERR);
+ GNUNET_free (sc);
+ return;
+ }
+#if DEBUG_ARM
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Received response from ARM service\n"));
+#endif
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_ARM_IS_UP:
+ ret = GNUNET_YES;
+ break;
+ case GNUNET_MESSAGE_TYPE_ARM_IS_DOWN:
+ ret = GNUNET_NO;
+ break;
+ default:
+ GNUNET_break (0);
+ ret = GNUNET_SYSERR;
+ }
+ GNUNET_CLIENT_disconnect (sc->client);
+ if (sc->callback != NULL)
+ sc->callback (sc->cls, ret);
+ GNUNET_free (sc);
+}
+
+
+static size_t
+send_service_msg (void *cls, size_t size, void *buf)
+{
+ struct ArmContext *sctx = cls;
+ struct GNUNET_MessageHeader *msg;
+ size_t slen;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Error while trying to transmit to ARM service\n"));
+ GNUNET_CLIENT_disconnect (sctx->client);
+ if (sctx->callback != NULL)
+ sctx->callback (sctx->cls, GNUNET_SYSERR);
+ GNUNET_free (sctx->service_name);
+ GNUNET_free (sctx);
+ return 0;
+ }
+#if DEBUG_ARM
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Transmitting service request to ARM.\n"));
+#endif
+ slen = strlen (sctx->service_name) + 1;
+ GNUNET_assert (size >= slen);
+ msg = buf;
+ msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen);
+ msg->type = htons (sctx->type);
+ memcpy (&msg[1], sctx->service_name, slen);
+ GNUNET_free (sctx->service_name);
+ sctx->service_name = NULL;
+ GNUNET_CLIENT_receive (sctx->client,
+ &handle_response,
+ sctx,
+ GNUNET_TIME_absolute_get_remaining (sctx->timeout));
+ return slen + sizeof (struct GNUNET_MessageHeader);
+}
+
+
+/**
+ * Start or stop a service.
+ *
+ * @param service_name name of the service
+ * @param cfg configuration to use (needed to contact ARM;
+ * the ARM service may internally use a different
+ * configuration to determine how to start the service).
+ * @param sched scheduler to use
+ * @param timeout how long to wait before failing for good
+ * @param cb callback to invoke when service is ready
+ * @param cb_cls closure for callback
+ */
+static void
+change_service (const char *service_name,
+ struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_ARM_Callback cb, void *cb_cls, uint16_t type)
+{
+ struct GNUNET_CLIENT_Connection *client;
+ struct ArmContext *sctx;
+ size_t slen;
+
+ slen = strlen (service_name) + 1;
+ if (slen + sizeof (struct GNUNET_MessageHeader) >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ if (cb != NULL)
+ cb (cb_cls, GNUNET_NO);
+ return;
+ }
+ client = GNUNET_CLIENT_connect (sched, "arm", cfg);
+ if (client == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed to connect to ARM service\n"));
+ if (cb != NULL)
+ cb (cb_cls, GNUNET_SYSERR);
+ return;
+ }
+#if DEBUG_ARM
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("ARM requests starting of service `%s'.\n"), service_name);
+#endif
+ sctx = GNUNET_malloc (sizeof (struct ArmContext));
+ sctx->callback = cb;
+ sctx->cls = cb_cls;
+ sctx->client = client;
+ sctx->service_name = GNUNET_strdup (service_name);
+ sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ sctx->type = type;
+ if (NULL ==
+ GNUNET_CLIENT_notify_transmit_ready (client,
+ slen +
+ sizeof (struct
+ GNUNET_MessageHeader),
+ timeout, &send_service_msg, sctx))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed to transmit request to ARM service\n"));
+ GNUNET_free (sctx->service_name);
+ GNUNET_free (sctx);
+ if (cb != NULL)
+ cb (cb_cls, GNUNET_SYSERR);
+ GNUNET_CLIENT_disconnect (client);
+ return;
+ }
+}
+
+
+/**
+ * Start a service.
+ *
+ * @param service_name name of the service
+ * @param cfg configuration to use (needed to contact ARM;
+ * the ARM service may internally use a different
+ * configuration to determine how to start the service).
+ * @param sched scheduler to use
+ * @param timeout how long to wait before failing for good
+ * @param cb callback to invoke when service is ready
+ * @param cb_cls closure for callback
+ */
+void
+GNUNET_ARM_start_service (const char *service_name,
+ struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_ARM_Callback cb, void *cb_cls)
+{
+ struct ArmContext *sctx;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Starting service `%s'\n"), service_name);
+ if (0 == strcmp ("arm", service_name))
+ {
+ sctx = GNUNET_malloc (sizeof (struct ArmContext));
+ sctx->callback = cb;
+ sctx->cls = cb_cls;
+ sctx->cfg = cfg;
+ GNUNET_CLIENT_service_test (sched,
+ "arm",
+ cfg, timeout, &arm_service_report, sctx);
+ return;
+ }
+ change_service (service_name,
+ cfg,
+ sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_START);
+}
+
+
+
+
+/**
+ * Stop a service.
+ *
+ * @param service_name name of the service
+ * @param cfg configuration to use (needed to contact ARM;
+ * the ARM service may internally use a different
+ * configuration to determine how to start the service).
+ * @param sched scheduler to use
+ * @param timeout how long to wait before failing for good
+ * @param cb callback to invoke when service is ready
+ * @param cb_cls closure for callback
+ */
+void
+GNUNET_ARM_stop_service (const char *service_name,
+ struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_ARM_Callback cb, void *cb_cls)
+{
+ struct GNUNET_CLIENT_Connection *client;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Stopping service `%s'\n"), service_name);
+ if (0 == strcmp ("arm", service_name))
+ {
+ client = GNUNET_CLIENT_connect (sched, "arm", cfg);
+ if (client == NULL)
+ {
+ if (cb != NULL)
+ cb (cb_cls, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_CLIENT_service_shutdown (client);
+ GNUNET_CLIENT_disconnect (client);
+ if (cb != NULL)
+ cb (cb_cls, GNUNET_NO);
+ return;
+ }
+ change_service (service_name,
+ cfg,
+ sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_STOP);
+}
+
+/* end of arm_api.c */