diff options
author | grothoff <grothoff@140774ce-b5e7-0310-ab8b-a85725594a96> | 2009-05-29 00:46:26 +0000 |
---|---|---|
committer | grothoff <grothoff@140774ce-b5e7-0310-ab8b-a85725594a96> | 2009-05-29 00:46:26 +0000 |
commit | 6ba89ee6eee308c69d69b6bbebcf2cc67a76ce01 (patch) | |
tree | 6b552f40eb089db96409a312a98d9b12bd669102 /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.c | 337 |
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 */ |