From d8b052b2dd8e0242239b14bdd06854bff21cb3d0 Mon Sep 17 00:00:00 2001 From: Maximilian Szengel Date: Wed, 29 Feb 2012 08:59:39 +0000 Subject: [PATCH] Adding arm list/info feature. --- src/arm/arm.h | 21 +++++ src/arm/arm_api.c | 153 ++++++++++++++++++++++++++++++- src/arm/gnunet-arm.c | 55 +++++++++++ src/arm/gnunet-service-arm.c | 100 +++++++++++++++++++- src/include/gnunet_arm_service.h | 25 +++++ src/include/gnunet_protocols.h | 9 ++ 6 files changed, 360 insertions(+), 3 deletions(-) diff --git a/src/arm/arm.h b/src/arm/arm.h index 4b9da6fab..21884107c 100644 --- a/src/arm/arm.h +++ b/src/arm/arm.h @@ -51,6 +51,27 @@ struct GNUNET_ARM_ResultMessage */ uint32_t status; }; + +/** + * Reply from ARM to client for the + * GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count + * '\0' terminated strings. header->size contains the + * total size (including all strings). + */ +struct GNUNET_ARM_ListResultMessage +{ + /** + * Reply to client is of type GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Number of '\0' terminated strings that follow + * this message. + */ + uint16_t count; +}; + GNUNET_NETWORK_STRUCT_END #endif diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c index 0f4ae6a4f..d0babf0ae 100644 --- a/src/arm/arm_api.c +++ b/src/arm/arm_api.c @@ -52,7 +52,6 @@ struct GNUNET_ARM_Handle }; - /** * Context for handling the shutdown of a service. */ @@ -487,6 +486,94 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg) GNUNET_free (sc); } +/** + * Internal state for a list request with ARM. + */ +struct ListRequestContext +{ + + /** + * Pointer to our handle with ARM. + */ + struct GNUNET_ARM_Handle *h; + + /** + * Function to call with a status code for the requested operation. + */ + GNUNET_ARM_List_Callback callback; + + /** + * Closure for "callback". + */ + void *cls; + + /** + * Timeout for the operation. + */ + struct GNUNET_TIME_Absolute timeout; +}; + +/** + * Process a response from ARM for the list request. + * + * @param cls the list request context + * @param msg the response + */ +static void +handle_list_response (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct ListRequestContext *sc = cls; + const struct GNUNET_ARM_ListResultMessage *res; + int success; + + if (msg == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Error receiving response to LIST request from ARM\n"); + GNUNET_CLIENT_disconnect (sc->h->client, GNUNET_NO); + sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg); + GNUNET_assert (NULL != sc->h->client); + if (sc->callback != NULL) + sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL); + GNUNET_free (sc); + return; + } + + if (sc->callback != NULL) + { + char **list; + const char *pos; + uint16_t size_check; + + size_check = 0; + res = (const struct GNUNET_ARM_ListResultMessage *) msg; + success = (ntohs (res->header.type) + == GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT ? + GNUNET_YES : GNUNET_NO); + list = GNUNET_malloc (ntohs (res->count) * sizeof (char *)); + pos = (const char *)&res[1]; + + int i; + for (i=0; icount); i++) + { + list[i] = GNUNET_malloc (strlen (pos) + 1); + memcpy (list[i], pos, strlen (pos) + 1); + pos += strlen (pos) + 1; + size_check += strlen (pos) +1; + + if (size_check > ntohs (res->header.size)) + { + GNUNET_free (list); + GNUNET_free (sc); + sc->callback (sc->cls, GNUNET_NO, 0, NULL); + return; + } + } + + sc->callback (sc->cls, success, ntohs (res->count), (const char**)list); + } + GNUNET_free (sc); +} /** * Start or stop a service. @@ -677,5 +764,69 @@ GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, GNUNET_MESSAGE_TYPE_ARM_STOP); } +/** + * List all running services. + * + * @param h handle to ARM + * @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_list_running_services (struct GNUNET_ARM_Handle *h, + struct GNUNET_TIME_Relative timeout, + GNUNET_ARM_List_Callback cb, void *cb_cls) +{ + struct ListRequestContext *sctx; + struct GNUNET_MessageHeader *msg; + struct GNUNET_CLIENT_Connection *client; + + if (h->client == NULL) + { + client = GNUNET_CLIENT_connect ("arm", h->cfg); + if (client == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "arm_api, GNUNET_CLIENT_connect returned NULL\n"); + cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); + h->client = client; + } + + sctx = GNUNET_malloc (sizeof (struct RequestContext)); + sctx->h = h; + sctx->callback = cb; + sctx->cls = cb_cls; + sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + msg = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader)); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST); + + LOG(GNUNET_ERROR_TYPE_DEBUG, + "Requesting LIST from ARM service with timeout: %llu ms\n", + (unsigned long long)timeout.rel_value); + + if (GNUNET_OK != + GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, + msg, + GNUNET_TIME_absolute_get_remaining + (sctx->timeout), + GNUNET_YES, + &handle_list_response, + sctx)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Error while trying to transmit request to list services to ARM\n"); + if (cb != NULL) + cb (cb_cls, GNUNET_SYSERR, 0, NULL); + GNUNET_free (sctx); + GNUNET_free (msg); + return; + } + GNUNET_free (msg); +} /* end of arm_api.c */ diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c index 65700ee11..f81cefa69 100644 --- a/src/arm/gnunet-arm.c +++ b/src/arm/gnunet-arm.c @@ -48,6 +48,11 @@ */ #define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) +/** + * Timeout for listing all running services. + */ +#define LIST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) + /** * Set if we are to shutdown all services (including ARM). */ @@ -73,6 +78,11 @@ static int delete; */ static int quiet; +/** + * Set if we should print a list of currently running services. + */ +static int list; + /** * Set to the name of a service to start. */ @@ -193,6 +203,31 @@ confirm_cb (void *cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } +/** + * Callback invoked with the list of running services. + * Reports to the user and then runs the next phase in the FSM. + * + * @param cls currently not used + * @param result result of the operation + * @param count number of running services + * @param list copy of the list of running services + */ +static void +list_cb (void *cls, int result, uint16_t count, const char **list) +{ + if (result == GNUNET_YES && list != NULL) + { + FPRINTF (stdout, _("Running services:\n-----------------\n")); + int i; + for (i=0; i= 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 @@ -566,7 +603,7 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client, const char *servicename; struct ServiceList *sl; uint16_t size; - + size = ntohs (message->size); size -= sizeof (struct GNUNET_MessageHeader); servicename = (const char *) &message[1]; @@ -663,6 +700,64 @@ handle_stop (void *cls, struct GNUNET_SERVER_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 += 3; + string_list_size += strlen (sl->binary) + 1; + 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) + { + //memcpy (pos, sl->name, strlen (sl->name) + 1); + size_t s = strlen (sl->name) + strlen (sl->binary) + 4; + 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 @@ -1002,7 +1097,6 @@ handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, GNUNET_SERVER_client_persist_ (client); } - /** * Signal handler called for SIGCHLD. Triggers the * respective handler by writing to the trigger pipe. @@ -1114,6 +1208,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv, {&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; diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h index af1c8cd94..42d42a0cd 100644 --- a/src/include/gnunet_arm_service.h +++ b/src/include/gnunet_arm_service.h @@ -111,6 +111,19 @@ enum GNUNET_ARM_ProcessStatus typedef void (*GNUNET_ARM_Callback) (void *cls, enum GNUNET_ARM_ProcessStatus result); +/** + * Callback function invoked when list operation is complete. + * + * @param cls closure + * @param result outcome of the operation (GNUNET_YES if successful) + * @param count number of strings in the list + * @param list list of running services + */ +typedef void (*GNUNET_ARM_List_Callback) (void *cls, + int result, + uint16_t count, + const char **list); + /** * Handle for interacting with ARM. @@ -183,6 +196,18 @@ GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name, GNUNET_ARM_Callback cb, void *cb_cls); +/** + * List all running services. + * + * @param h handle to ARM + * @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_list_running_services (struct GNUNET_ARM_Handle *h, + struct GNUNET_TIME_Relative timeout, + GNUNET_ARM_List_Callback cb, void *cb_cls); #if 0 /* keep Emacsens' auto-indent happy */ { diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index dd7c7fea5..110489491 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -87,6 +87,15 @@ extern "C" */ #define GNUNET_MESSAGE_TYPE_ARM_RESULT 11 +/** + * Request to ARM to list all currently running services + */ +#define GNUNET_MESSAGE_TYPE_ARM_LIST 12 + +/** + * Response from ARM for listing currently running services + */ +#define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT 13 /******************************************************************************* * HELLO message types -- 2.25.1