2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2012, 2013, 2016, 2019 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
23 * @brief API for accessing the ARM service
24 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_arm_service.h"
30 #include "gnunet_protocols.h"
33 #define LOG(kind, ...) GNUNET_log_from (kind, "arm-api", __VA_ARGS__)
37 * Entry in a doubly-linked list of operations awaiting for replies
38 * (in-order) from the ARM service.
40 struct GNUNET_ARM_Operation
43 * This is a doubly-linked list.
45 struct GNUNET_ARM_Operation *next;
48 * This is a doubly-linked list.
50 struct GNUNET_ARM_Operation *prev;
55 struct GNUNET_ARM_Handle *h;
58 * Callback for service state change requests.
60 GNUNET_ARM_ResultCallback result_cont;
63 * Callback for service list requests.
65 GNUNET_ARM_ServiceListCallback list_cont;
68 * Closure for @e result_cont or @e list_cont.
73 * Task for async completion.
75 struct GNUNET_SCHEDULER_Task *async;
78 * Unique ID for the request.
83 * Result of this operation for #notify_starting().
85 enum GNUNET_ARM_Result starting_ret;
88 * File descriptor to close on operation stop, if not NULL.
90 struct GNUNET_DISK_FileHandle *rfd;
93 * Is this an operation to stop the ARM service?
100 * Handle for interacting with ARM.
102 struct GNUNET_ARM_Handle
105 * Our connection to the ARM service.
107 struct GNUNET_MQ_Handle *mq;
110 * The configuration that we are using.
112 const struct GNUNET_CONFIGURATION_Handle *cfg;
115 * Head of doubly-linked list of pending operations.
117 struct GNUNET_ARM_Operation *operation_pending_head;
120 * Tail of doubly-linked list of pending operations.
122 struct GNUNET_ARM_Operation *operation_pending_tail;
125 * Callback to invoke on connection/disconnection.
127 GNUNET_ARM_ConnectionStatusCallback conn_status;
130 * Closure for @e conn_status.
132 void *conn_status_cls;
135 * ARM operation where the goal is to wait for ARM shutdown to
136 * complete. This operation is special in that it waits for an
137 * error on the @e mq. So we complete it by calling the
138 * continuation in the #mq_error_handler(). Note that the operation
139 * is no longer in the @e operation_pending_head DLL once it is
140 * referenced from this field.
142 struct GNUNET_ARM_Operation *thm;
145 * ID of the reconnect task (if any).
147 struct GNUNET_SCHEDULER_Task *reconnect_task;
150 * Current delay we use for re-trying to connect to core.
152 struct GNUNET_TIME_Relative retry_backoff;
155 * Counter for request identifiers. They are used to match replies
156 * from ARM to operations in the @e operation_pending_head DLL.
158 uint64_t request_id_counter;
161 * Have we detected that ARM is up?
170 * @param h arm handle
171 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
174 reconnect_arm (struct GNUNET_ARM_Handle *h);
178 * Task scheduled to try to re-connect to arm.
180 * @param cls the `struct GNUNET_ARM_Handle`
183 reconnect_arm_task (void *cls)
185 struct GNUNET_ARM_Handle *h = cls;
187 h->reconnect_task = NULL;
193 * Close down any existing connection to the ARM service and
194 * try re-establishing it later.
196 * @param h our handle
199 reconnect_arm_later (struct GNUNET_ARM_Handle *h)
201 struct GNUNET_ARM_Operation *op;
205 GNUNET_MQ_destroy (h->mq);
208 h->currently_up = GNUNET_NO;
209 GNUNET_assert (NULL == h->reconnect_task);
211 GNUNET_SCHEDULER_add_delayed (h->retry_backoff,
214 while (NULL != (op = h->operation_pending_head))
216 if (NULL != op->result_cont)
217 op->result_cont (op->cont_cls,
218 GNUNET_ARM_REQUEST_DISCONNECTED,
220 if (NULL != op->list_cont)
221 op->list_cont (op->cont_cls,
222 GNUNET_ARM_REQUEST_DISCONNECTED,
225 GNUNET_ARM_operation_cancel (op);
227 GNUNET_assert (NULL == h->operation_pending_head);
228 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
229 if (NULL != h->conn_status)
230 h->conn_status (h->conn_status_cls,
236 * Find a control message by its unique ID.
238 * @param h ARM handle
239 * @param id unique message ID to use for the lookup
240 * @return NULL if not found
242 static struct GNUNET_ARM_Operation *
243 find_op_by_id (struct GNUNET_ARM_Handle *h,
246 for (struct GNUNET_ARM_Operation *result = h->operation_pending_head;
248 result = result->next)
249 if (id == result->id)
256 * Handler for ARM replies.
258 * @param cls our `struct GNUNET_ARM_Handle`
259 * @param res the message received from the arm service
262 handle_arm_result (void *cls,
263 const struct GNUNET_ARM_ResultMessage *res)
265 struct GNUNET_ARM_Handle *h = cls;
266 struct GNUNET_ARM_Operation *op;
268 enum GNUNET_ARM_Result result;
269 GNUNET_ARM_ResultCallback result_cont;
270 void *result_cont_cls;
272 id = GNUNET_ntohll (res->arm_msg.request_id);
273 op = find_op_by_id (h,
277 LOG (GNUNET_ERROR_TYPE_DEBUG,
278 "Message with unknown id %llu\n",
279 (unsigned long long) id);
283 result = (enum GNUNET_ARM_Result) ntohl (res->result);
284 if ( (GNUNET_YES == op->is_arm_stop) &&
285 (GNUNET_ARM_RESULT_STOPPING == result) )
287 /* special case: if we are stopping 'gnunet-service-arm', we do not just
288 wait for the result message, but also wait for the service to close
289 the connection (and then we have to close our client handle as well);
290 this is done by installing a different receive handler, waiting for
291 the connection to go down */if (NULL != h->thm)
294 op->result_cont (h->thm->cont_cls,
295 GNUNET_ARM_REQUEST_SENT_OK,
296 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
297 GNUNET_free (h->thm);
299 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
300 h->operation_pending_tail,
305 result_cont = op->result_cont;
306 result_cont_cls = op->cont_cls;
307 GNUNET_ARM_operation_cancel (op);
308 if (NULL != result_cont)
309 result_cont (result_cont_cls,
310 GNUNET_ARM_REQUEST_SENT_OK,
316 * Read from a string pool.
318 * @param pool_start start of the string pool
319 * @param pool_size size of the string pool
320 * @param str_index index into the string pool
321 * @returns an index into the string pool, or
322 * NULL if the index is out of bounds
325 pool_get (const char *pool_start,
329 const char *str_start;
332 if (str_index >= pool_size)
334 str_start = pool_start + str_index;
335 end = memchr (str_start, 0, pool_size - str_index);
343 * Check that list result message is well-formed.
345 * @param cls our `struct GNUNET_ARM_Handle`
346 * @param lres the message received from the arm service
347 * @return #GNUNET_OK if message is well-formed
350 check_arm_list_result (void *cls,
351 const struct GNUNET_ARM_ListResultMessage *lres)
353 uint16_t rcount = ntohs (lres->count);
354 uint16_t msize = ntohs (lres->arm_msg.header.size) - sizeof(*lres);
355 struct GNUNET_ARM_ServiceInfoMessage *ssm;
360 if ((rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage) > msize))
365 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &lres[1];
366 pool_start = (char *) (ssm + rcount);
367 pool_size = msize - (rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage));
368 for (unsigned int i = 0; i < rcount; i++)
370 uint16_t name_index = ntohs (ssm->name_index);
371 uint16_t binary_index = ntohs (ssm->binary_index);
372 if (NULL == pool_get (pool_start,
379 if (NULL == pool_get (pool_start,
393 * Handler for ARM list replies.
395 * @param cls our `struct GNUNET_ARM_Handle`
396 * @param lres the message received from the arm service
399 handle_arm_list_result (void *cls,
400 const struct GNUNET_ARM_ListResultMessage *lres)
402 struct GNUNET_ARM_Handle *h = cls;
403 uint16_t rcount = ntohs (lres->count);
404 uint16_t msize = ntohs (lres->arm_msg.header.size) - sizeof(*lres);
405 struct GNUNET_ARM_ServiceInfo list[rcount];
406 struct GNUNET_ARM_ServiceInfoMessage *ssm;
407 struct GNUNET_ARM_Operation *op;
412 id = GNUNET_ntohll (lres->arm_msg.request_id);
413 op = find_op_by_id (h, id);
416 LOG (GNUNET_ERROR_TYPE_DEBUG,
417 "Message with unknown id %llu\n",
418 (unsigned long long) id);
422 GNUNET_assert ((rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage) <=
425 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &lres[1];
426 pool_start = (char *) (ssm + rcount);
427 pool_size = msize - (rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage));
429 for (unsigned int i = 0; i < rcount; i++)
431 uint16_t name_index = ntohs (ssm->name_index);
432 uint16_t binary_index = ntohs (ssm->binary_index);
436 GNUNET_assert (NULL != (name = pool_get (pool_start,
439 GNUNET_assert (NULL != (binary = pool_get (pool_start,
442 list[i] = (struct GNUNET_ARM_ServiceInfo) {
445 .status = ntohl (ssm->status),
446 .last_started_at = GNUNET_TIME_absolute_ntoh (ssm->last_started_at),
447 .restart_at = GNUNET_TIME_absolute_ntoh (ssm->restart_at),
448 .last_exit_status = ntohs (ssm->last_exit_status),
452 if (NULL != op->list_cont)
453 op->list_cont (op->cont_cls,
454 GNUNET_ARM_REQUEST_SENT_OK,
457 GNUNET_ARM_operation_cancel (op);
462 * Receive confirmation from test, ARM service is up.
464 * @param cls closure with the `struct GNUNET_ARM_Handle`
465 * @param msg message received
468 handle_confirm (void *cls,
469 const struct GNUNET_MessageHeader *msg)
471 struct GNUNET_ARM_Handle *h = cls;
474 LOG (GNUNET_ERROR_TYPE_DEBUG,
475 "Got confirmation from ARM that we are up!\n");
476 if (GNUNET_NO == h->currently_up)
478 h->currently_up = GNUNET_YES;
479 if (NULL != h->conn_status)
480 h->conn_status (h->conn_status_cls, GNUNET_YES);
486 * Generic error handler, called with the appropriate error code and
487 * the same closure specified at the creation of the message queue.
488 * Not every message queue implementation supports an error handler.
490 * @param cls closure with the `struct GNUNET_ARM_Handle *`
491 * @param error error code
494 mq_error_handler (void *cls,
495 enum GNUNET_MQ_Error error)
497 struct GNUNET_ARM_Handle *h = cls;
498 struct GNUNET_ARM_Operation *op;
501 h->currently_up = GNUNET_NO;
502 if (NULL != (op = h->thm))
505 op->result_cont (op->cont_cls,
506 GNUNET_ARM_REQUEST_SENT_OK,
507 GNUNET_ARM_RESULT_STOPPED);
510 reconnect_arm_later (h);
517 * @param h arm handle
518 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
521 reconnect_arm (struct GNUNET_ARM_Handle *h)
523 struct GNUNET_MQ_MessageHandler handlers[] = {
524 GNUNET_MQ_hd_fixed_size (arm_result,
525 GNUNET_MESSAGE_TYPE_ARM_RESULT,
526 struct GNUNET_ARM_ResultMessage,
528 GNUNET_MQ_hd_var_size (arm_list_result,
529 GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT,
530 struct GNUNET_ARM_ListResultMessage,
532 GNUNET_MQ_hd_fixed_size (confirm,
533 GNUNET_MESSAGE_TYPE_ARM_TEST,
534 struct GNUNET_MessageHeader,
536 GNUNET_MQ_handler_end ()
538 struct GNUNET_MessageHeader *test;
539 struct GNUNET_MQ_Envelope *env;
543 GNUNET_assert (GNUNET_NO == h->currently_up);
544 h->mq = GNUNET_CLIENT_connect (h->cfg,
551 LOG (GNUNET_ERROR_TYPE_DEBUG,
552 "GNUNET_CLIENT_connect returned NULL\n");
553 if (NULL != h->conn_status)
554 h->conn_status (h->conn_status_cls,
556 return GNUNET_SYSERR;
558 LOG (GNUNET_ERROR_TYPE_DEBUG,
559 "Sending TEST message to ARM\n");
560 env = GNUNET_MQ_msg (test,
561 GNUNET_MESSAGE_TYPE_ARM_TEST);
562 GNUNET_MQ_send (h->mq, env);
568 * Set up a context for communicating with ARM, then
569 * start connecting to the ARM service using that context.
571 * @param cfg configuration to use (needed to contact ARM;
572 * the ARM service may internally use a different
573 * configuration to determine how to start the service).
574 * @param conn_status will be called when connecting/disconnecting
575 * @param conn_status_cls closure for @a conn_status
576 * @return context to use for further ARM operations, NULL on error.
578 struct GNUNET_ARM_Handle *
579 GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
580 GNUNET_ARM_ConnectionStatusCallback conn_status,
581 void *conn_status_cls)
583 struct GNUNET_ARM_Handle *h;
585 h = GNUNET_new (struct GNUNET_ARM_Handle);
587 h->conn_status = conn_status;
588 h->conn_status_cls = conn_status_cls;
589 if (GNUNET_OK != reconnect_arm (h))
599 * Disconnect from the ARM service (if connected) and destroy the context.
601 * @param h the handle that was being used
604 GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h)
606 struct GNUNET_ARM_Operation *op;
608 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from ARM service\n");
609 while (NULL != (op = h->operation_pending_head))
611 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
612 h->operation_pending_tail,
614 if (NULL != op->result_cont)
615 op->result_cont (op->cont_cls,
616 GNUNET_ARM_REQUEST_DISCONNECTED,
618 if (NULL != op->list_cont)
619 op->list_cont (op->cont_cls,
620 GNUNET_ARM_REQUEST_DISCONNECTED,
623 if (NULL != op->async)
625 GNUNET_SCHEDULER_cancel (op->async);
632 GNUNET_MQ_destroy (h->mq);
635 if (NULL != h->reconnect_task)
637 GNUNET_SCHEDULER_cancel (h->reconnect_task);
638 h->reconnect_task = NULL;
645 * A client specifically requested starting of ARM itself.
646 * Starts the ARM service.
648 * @param h the handle with configuration details
649 * @param std_inheritance inheritance of std streams
650 * @param sigfd socket to pass to ARM for signalling
651 * @return operation status code
653 static enum GNUNET_ARM_Result
654 start_arm_service (struct GNUNET_ARM_Handle *h,
655 enum GNUNET_OS_InheritStdioFlags std_inheritance,
656 struct GNUNET_DISK_FileHandle *sigfd)
658 struct GNUNET_OS_Process *proc;
678 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (h->cfg,
682 loprefix = GNUNET_strdup ("");
684 loprefix = GNUNET_CONFIGURATION_expand_dollar (h->cfg, loprefix);
685 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (h->cfg,
689 lopostfix = GNUNET_strdup ("");
691 lopostfix = GNUNET_CONFIGURATION_expand_dollar (h->cfg,
694 GNUNET_CONFIGURATION_get_value_string (h->cfg,
699 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
702 GNUNET_free (loprefix);
703 GNUNET_free (lopostfix);
704 return GNUNET_ARM_RESULT_IS_NOT_KNOWN;
706 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg,
711 binary = GNUNET_OS_get_libexec_binary_path (cbinary);
712 GNUNET_asprintf ("edbinary,
715 GNUNET_free (cbinary);
717 GNUNET_CONFIGURATION_have_value (h->cfg,
721 GNUNET_CONFIGURATION_get_value_yesno (h->cfg,
725 GNUNET_CONFIGURATION_have_value (h->cfg,
729 /* Means we are ONLY running locally */
730 /* we're clearly running a test, don't daemonize */
732 proc = GNUNET_OS_start_process_s (GNUNET_NO,
737 /* no daemonization! */
741 proc = GNUNET_OS_start_process_s (GNUNET_NO,
748 /* no daemonization! */
755 proc = GNUNET_OS_start_process_s (GNUNET_NO,
760 "-d", /* do daemonize */
764 proc = GNUNET_OS_start_process_s (GNUNET_NO,
771 "-d", /* do daemonize */
775 GNUNET_free (binary);
776 GNUNET_free (quotedbinary);
777 GNUNET_free_non_null (config);
778 GNUNET_free (loprefix);
779 GNUNET_free (lopostfix);
781 return GNUNET_ARM_RESULT_START_FAILED;
782 GNUNET_OS_process_destroy (proc);
783 return GNUNET_ARM_RESULT_STARTING;
788 * Abort an operation. Only prevents the callback from being
789 * called, the operation may still complete.
791 * @param op operation to cancel
794 GNUNET_ARM_operation_cancel (struct GNUNET_ARM_Operation *op)
796 struct GNUNET_ARM_Handle *h = op->h;
798 if (NULL != op->async)
800 GNUNET_SCHEDULER_cancel (op->async);
805 GNUNET_DISK_file_close (op->rfd);
810 op->result_cont = NULL;
813 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
814 h->operation_pending_tail,
821 * Start or stop a service.
823 * @param h handle to ARM
824 * @param service_name name of the service
825 * @param cb callback to invoke when service is ready
826 * @param cb_cls closure for @a cb
827 * @param type type of the request
828 * @return handle to queue, NULL on error
830 static struct GNUNET_ARM_Operation *
831 change_service (struct GNUNET_ARM_Handle *h,
832 const char *service_name,
833 GNUNET_ARM_ResultCallback cb,
837 struct GNUNET_ARM_Operation *op;
839 struct GNUNET_MQ_Envelope *env;
840 struct GNUNET_ARM_Message *msg;
842 slen = strlen (service_name) + 1;
843 if (slen + sizeof(struct GNUNET_ARM_Message) >= GNUNET_MAX_MESSAGE_SIZE)
848 if (0 == h->request_id_counter)
849 h->request_id_counter++;
850 op = GNUNET_new (struct GNUNET_ARM_Operation);
852 op->result_cont = cb;
853 op->cont_cls = cb_cls;
854 op->id = h->request_id_counter++;
855 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
856 h->operation_pending_tail,
858 env = GNUNET_MQ_msg_extra (msg, slen, type);
859 msg->reserved = htonl (0);
860 msg->request_id = GNUNET_htonll (op->id);
861 GNUNET_memcpy (&msg[1], service_name, slen);
862 GNUNET_MQ_send (h->mq, env);
868 * Task run to notify application that ARM is already up.
870 * @param cls the operation that asked ARM to be started
873 notify_running (void *cls)
875 struct GNUNET_ARM_Operation *op = cls;
876 struct GNUNET_ARM_Handle *h = op->h;
879 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
880 h->operation_pending_tail,
882 if (NULL != op->result_cont)
883 op->result_cont (op->cont_cls,
884 GNUNET_ARM_REQUEST_SENT_OK,
885 GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
886 if ( (GNUNET_YES == h->currently_up) &&
887 (NULL != h->conn_status) )
888 h->conn_status (h->conn_status_cls,
895 * Task run to notify application that ARM is being started.
897 * @param cls the operation that asked ARM to be started
900 notify_starting (void *cls)
902 struct GNUNET_ARM_Operation *op = cls;
903 struct GNUNET_ARM_Handle *h = op->h;
906 LOG (GNUNET_ERROR_TYPE_DEBUG,
907 "Notifying client that we started the ARM service\n");
908 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
909 h->operation_pending_tail,
911 if (NULL != op->result_cont)
912 op->result_cont (op->cont_cls,
913 GNUNET_ARM_REQUEST_SENT_OK,
920 * Request for a service to be started.
922 * @param h handle to ARM
923 * @param service_name name of the service
924 * @param std_inheritance inheritance of std streams
925 * @param cont callback to invoke after request is sent or not sent
926 * @param cont_cls closure for @a cont
927 * @return handle for the operation, NULL on error
929 struct GNUNET_ARM_Operation *
930 GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h,
931 const char *service_name,
932 enum GNUNET_OS_InheritStdioFlags
934 GNUNET_ARM_ResultCallback cont,
937 struct GNUNET_ARM_Operation *op;
938 enum GNUNET_ARM_Result ret;
939 struct GNUNET_DISK_PipeHandle *sig;
940 struct GNUNET_DISK_FileHandle *wsig;
942 LOG (GNUNET_ERROR_TYPE_DEBUG,
943 "Starting service `%s'\n",
945 if (0 != strcasecmp ("arm",
947 return change_service (h,
951 GNUNET_MESSAGE_TYPE_ARM_START);
954 * 1) We're connected to ARM already. Invoke the callback immediately.
955 * 2) We're not connected to ARM.
956 * Cancel any reconnection attempts temporarily, then perform
958 */if (GNUNET_YES == h->currently_up)
960 LOG (GNUNET_ERROR_TYPE_DEBUG,
961 "ARM is already running\n");
962 op = GNUNET_new (struct GNUNET_ARM_Operation);
964 op->result_cont = cont;
965 op->cont_cls = cont_cls;
966 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
967 h->operation_pending_tail,
969 op->async = GNUNET_SCHEDULER_add_now (¬ify_running, op);
972 /* This is an inherently uncertain choice, as it is of course
973 theoretically possible that ARM is up and we just did not
974 yet complete the MQ handshake. However, given that users
975 are unlikely to hammer 'gnunet-arm -s' on a busy system,
976 the above check should catch 99.99% of the cases where ARM
977 is already running. */LOG (GNUNET_ERROR_TYPE_DEBUG,
978 "Starting ARM service\n");
979 if (NULL == (sig = GNUNET_DISK_pipe (GNUNET_NO,
984 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
987 wsig = GNUNET_DISK_pipe_detach_end (sig,
988 GNUNET_DISK_PIPE_END_WRITE);
989 ret = start_arm_service (h,
992 GNUNET_DISK_file_close (wsig);
993 if (GNUNET_ARM_RESULT_STARTING == ret)
995 op = GNUNET_new (struct GNUNET_ARM_Operation);
997 op->result_cont = cont;
998 op->cont_cls = cont_cls;
999 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
1000 h->operation_pending_tail,
1002 op->starting_ret = ret;
1005 op->rfd = GNUNET_DISK_pipe_detach_end (sig,
1006 GNUNET_DISK_PIPE_END_READ);
1007 /* Wait at most a minute for gnunet-service-arm to be up, as beyond
1008 that something clearly just went wrong */
1009 op->async = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_MINUTES,
1016 op->async = GNUNET_SCHEDULER_add_now (¬ify_starting,
1019 GNUNET_DISK_pipe_close (sig);
1025 * Request a service to be stopped. Stopping arm itself will not
1026 * invalidate its handle, and ARM API will try to restore connection
1027 * to the ARM service, even if ARM connection was lost because you
1028 * asked for ARM to be stopped. Call
1029 * #GNUNET_ARM_disconnect() to free the handle and prevent
1030 * further connection attempts.
1032 * @param h handle to ARM
1033 * @param service_name name of the service
1034 * @param cont callback to invoke after request is sent or is not sent
1035 * @param cont_cls closure for @a cont
1036 * @return handle for the operation, NULL on error
1038 struct GNUNET_ARM_Operation *
1039 GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h,
1040 const char *service_name,
1041 GNUNET_ARM_ResultCallback cont,
1044 struct GNUNET_ARM_Operation *op;
1046 LOG (GNUNET_ERROR_TYPE_DEBUG,
1047 "Stopping service `%s'\n",
1049 op = change_service (h,
1053 GNUNET_MESSAGE_TYPE_ARM_STOP);
1056 /* If the service is ARM, set a flag as we will use MQ errors
1057 to detect that the process is really gone. */
1058 if (0 == strcasecmp (service_name,
1060 op->is_arm_stop = GNUNET_YES;
1066 * Request a list of running services.
1068 * @param h handle to ARM
1069 * @param cont callback to invoke after request is sent or is not sent
1070 * @param cont_cls closure for @a cont
1071 * @return handle for the operation, NULL on error
1073 struct GNUNET_ARM_Operation *
1074 GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h,
1075 GNUNET_ARM_ServiceListCallback cont,
1078 struct GNUNET_ARM_Operation *op;
1079 struct GNUNET_MQ_Envelope *env;
1080 struct GNUNET_ARM_Message *msg;
1082 LOG (GNUNET_ERROR_TYPE_DEBUG,
1083 "Requesting LIST from ARM service\n");
1084 if (0 == h->request_id_counter)
1085 h->request_id_counter++;
1086 op = GNUNET_new (struct GNUNET_ARM_Operation);
1088 op->list_cont = cont;
1089 op->cont_cls = cont_cls;
1090 op->id = h->request_id_counter++;
1091 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
1092 h->operation_pending_tail,
1094 env = GNUNET_MQ_msg (msg,
1095 GNUNET_MESSAGE_TYPE_ARM_LIST);
1096 msg->reserved = htonl (0);
1097 msg->request_id = GNUNET_htonll (op->id);
1098 GNUNET_MQ_send (h->mq, env);
1103 /* end of arm_api.c */