diff options
author | szengel <szengel@140774ce-b5e7-0310-ab8b-a85725594a96> | 2012-02-29 08:59:39 +0000 |
---|---|---|
committer | szengel <szengel@140774ce-b5e7-0310-ab8b-a85725594a96> | 2012-02-29 08:59:39 +0000 |
commit | ea96e3284daecbd0b37c06682b68e1c8ffc8dfa8 (patch) | |
tree | 2e9c740f97f6f81c5cc7794d495e0fa6c188c0e3 /src/arm | |
parent | dd21594b1ded031fe9d663f2c0e94e3d416e2237 (diff) |
Adding arm list/info feature.
git-svn-id: https://gnunet.org/svn/gnunet@20135 140774ce-b5e7-0310-ab8b-a85725594a96
Diffstat (limited to 'src/arm')
-rw-r--r-- | src/arm/arm.h | 21 | ||||
-rw-r--r-- | src/arm/arm_api.c | 153 | ||||
-rw-r--r-- | src/arm/gnunet-arm.c | 55 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm.c | 100 |
4 files changed, 326 insertions, 3 deletions
diff --git a/src/arm/arm.h b/src/arm/arm.h index 4b9da6faba..21884107c5 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 0f4ae6a4f0..d0babf0ae7 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; i<ntohs (res->count); 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 65700ee11c..f81cefa696 100644 --- a/src/arm/gnunet-arm.c +++ b/src/arm/gnunet-arm.c @@ -49,6 +49,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). */ static int end; @@ -74,6 +79,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. */ static char *init; @@ -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<count; i++) + { + FPRINTF (stdout, "%s\n", list[i]); + } + GNUNET_free (list); + } else { + FPRINTF (stderr, "%s", _("Error communicating with ARM. ARM not running?\n")); + } +} /** * Main function that will be run by the scheduler. @@ -328,6 +363,24 @@ cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_SCHEDULER_add_now (&cps_loop, NULL); return; } + case 5: + if (list) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Going to list all running services controlled by ARM.\n"); + + if (h == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Fatal error initializing ARM API.\n")); + return; + } + + GNUNET_ARM_list_running_services (h, + (0 == + timeout.rel_value) ? LIST_TIMEOUT : + timeout, &list_cb, NULL); + return; + } /* Fall through */ default: /* last phase */ GNUNET_ARM_disconnect (h); @@ -371,6 +424,8 @@ main (int argc, char *const *argv) {'T', "timeout", NULL, gettext_noop ("timeout for completing current operation"), GNUNET_YES, &GNUNET_GETOPT_set_ulong, &temp_timeout_ms}, + {'I', "info", NULL, gettext_noop ("List currently running services"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &list}, GNUNET_GETOPT_OPTION_END }; diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index f4430ed0c8..cfe164fa6b 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c @@ -370,6 +370,43 @@ write_result (void *cls, size_t size, void *buf) 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 @@ -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; |