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 */
295 op->result_cont (h->thm->cont_cls,
296 GNUNET_ARM_REQUEST_SENT_OK,
297 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
298 GNUNET_free (h->thm);
300 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
301 h->operation_pending_tail,
306 result_cont = op->result_cont;
307 result_cont_cls = op->cont_cls;
308 GNUNET_ARM_operation_cancel (op);
309 if (NULL != result_cont)
310 result_cont (result_cont_cls,
311 GNUNET_ARM_REQUEST_SENT_OK,
317 * Read from a string pool.
319 * @param pool_start start of the string pool
320 * @param pool_size size of the string pool
321 * @param str_index index into the string pool
322 * @returns an index into the string pool, or
323 * NULL if the index is out of bounds
326 pool_get (const char *pool_start,
330 const char *str_start;
333 if (str_index >= pool_size)
335 str_start = pool_start + str_index;
336 end = memchr (str_start, 0, pool_size - str_index);
344 * Check that list result message is well-formed.
346 * @param cls our `struct GNUNET_ARM_Handle`
347 * @param lres the message received from the arm service
348 * @return #GNUNET_OK if message is well-formed
351 check_arm_list_result (void *cls,
352 const struct GNUNET_ARM_ListResultMessage *lres)
354 uint16_t rcount = ntohs (lres->count);
355 uint16_t msize = ntohs (lres->arm_msg.header.size) - sizeof(*lres);
356 struct GNUNET_ARM_ServiceInfoMessage *ssm;
361 if ((rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage) > msize))
366 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &lres[1];
367 pool_start = (char *) (ssm + rcount);
368 pool_size = msize - (rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage));
369 for (unsigned int i = 0; i < rcount; i++)
371 uint16_t name_index = ntohs (ssm->name_index);
372 uint16_t binary_index = ntohs (ssm->binary_index);
373 if (NULL == pool_get (pool_start,
380 if (NULL == pool_get (pool_start,
394 * Handler for ARM list replies.
396 * @param cls our `struct GNUNET_ARM_Handle`
397 * @param lres the message received from the arm service
400 handle_arm_list_result (void *cls,
401 const struct GNUNET_ARM_ListResultMessage *lres)
403 struct GNUNET_ARM_Handle *h = cls;
404 uint16_t rcount = ntohs (lres->count);
405 uint16_t msize = ntohs (lres->arm_msg.header.size) - sizeof(*lres);
406 struct GNUNET_ARM_ServiceInfo list[rcount];
407 struct GNUNET_ARM_ServiceInfoMessage *ssm;
408 struct GNUNET_ARM_Operation *op;
413 id = GNUNET_ntohll (lres->arm_msg.request_id);
414 op = find_op_by_id (h, id);
417 LOG (GNUNET_ERROR_TYPE_DEBUG,
418 "Message with unknown id %llu\n",
419 (unsigned long long) id);
423 GNUNET_assert ((rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage) <=
426 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &lres[1];
427 pool_start = (char *) (ssm + rcount);
428 pool_size = msize - (rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage));
430 for (unsigned int i = 0; i < rcount; i++)
432 uint16_t name_index = ntohs (ssm->name_index);
433 uint16_t binary_index = ntohs (ssm->binary_index);
437 GNUNET_assert (NULL != (name = pool_get (pool_start,
440 GNUNET_assert (NULL != (binary = pool_get (pool_start,
443 list[i] = (struct GNUNET_ARM_ServiceInfo) {
446 .status = ntohl (ssm->status),
447 .last_started_at = GNUNET_TIME_absolute_ntoh (ssm->last_started_at),
448 .restart_at = GNUNET_TIME_absolute_ntoh (ssm->restart_at),
449 .last_exit_status = ntohs (ssm->last_exit_status),
453 if (NULL != op->list_cont)
454 op->list_cont (op->cont_cls,
455 GNUNET_ARM_REQUEST_SENT_OK,
458 GNUNET_ARM_operation_cancel (op);
463 * Receive confirmation from test, ARM service is up.
465 * @param cls closure with the `struct GNUNET_ARM_Handle`
466 * @param msg message received
469 handle_confirm (void *cls,
470 const struct GNUNET_MessageHeader *msg)
472 struct GNUNET_ARM_Handle *h = cls;
475 LOG (GNUNET_ERROR_TYPE_DEBUG,
476 "Got confirmation from ARM that we are up!\n");
477 if (GNUNET_NO == h->currently_up)
479 h->currently_up = GNUNET_YES;
480 if (NULL != h->conn_status)
481 h->conn_status (h->conn_status_cls, GNUNET_YES);
487 * Generic error handler, called with the appropriate error code and
488 * the same closure specified at the creation of the message queue.
489 * Not every message queue implementation supports an error handler.
491 * @param cls closure with the `struct GNUNET_ARM_Handle *`
492 * @param error error code
495 mq_error_handler (void *cls,
496 enum GNUNET_MQ_Error error)
498 struct GNUNET_ARM_Handle *h = cls;
499 struct GNUNET_ARM_Operation *op;
502 h->currently_up = GNUNET_NO;
503 if (NULL != (op = h->thm))
506 op->result_cont (op->cont_cls,
507 GNUNET_ARM_REQUEST_SENT_OK,
508 GNUNET_ARM_RESULT_STOPPED);
511 reconnect_arm_later (h);
518 * @param h arm handle
519 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
522 reconnect_arm (struct GNUNET_ARM_Handle *h)
524 struct GNUNET_MQ_MessageHandler handlers[] = {
525 GNUNET_MQ_hd_fixed_size (arm_result,
526 GNUNET_MESSAGE_TYPE_ARM_RESULT,
527 struct GNUNET_ARM_ResultMessage,
529 GNUNET_MQ_hd_var_size (arm_list_result,
530 GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT,
531 struct GNUNET_ARM_ListResultMessage,
533 GNUNET_MQ_hd_fixed_size (confirm,
534 GNUNET_MESSAGE_TYPE_ARM_TEST,
535 struct GNUNET_MessageHeader,
537 GNUNET_MQ_handler_end ()
539 struct GNUNET_MessageHeader *test;
540 struct GNUNET_MQ_Envelope *env;
544 GNUNET_assert (GNUNET_NO == h->currently_up);
545 h->mq = GNUNET_CLIENT_connect (h->cfg,
552 LOG (GNUNET_ERROR_TYPE_DEBUG,
553 "GNUNET_CLIENT_connect returned NULL\n");
554 if (NULL != h->conn_status)
555 h->conn_status (h->conn_status_cls,
557 return GNUNET_SYSERR;
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Sending TEST message to ARM\n");
561 env = GNUNET_MQ_msg (test,
562 GNUNET_MESSAGE_TYPE_ARM_TEST);
563 GNUNET_MQ_send (h->mq, env);
569 * Set up a context for communicating with ARM, then
570 * start connecting to the ARM service using that context.
572 * @param cfg configuration to use (needed to contact ARM;
573 * the ARM service may internally use a different
574 * configuration to determine how to start the service).
575 * @param conn_status will be called when connecting/disconnecting
576 * @param conn_status_cls closure for @a conn_status
577 * @return context to use for further ARM operations, NULL on error.
579 struct GNUNET_ARM_Handle *
580 GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
581 GNUNET_ARM_ConnectionStatusCallback conn_status,
582 void *conn_status_cls)
584 struct GNUNET_ARM_Handle *h;
586 h = GNUNET_new (struct GNUNET_ARM_Handle);
588 h->conn_status = conn_status;
589 h->conn_status_cls = conn_status_cls;
590 if (GNUNET_OK != reconnect_arm (h))
600 * Disconnect from the ARM service (if connected) and destroy the context.
602 * @param h the handle that was being used
605 GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h)
607 struct GNUNET_ARM_Operation *op;
609 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from ARM service\n");
610 while (NULL != (op = h->operation_pending_head))
612 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
613 h->operation_pending_tail,
615 if (NULL != op->result_cont)
616 op->result_cont (op->cont_cls,
617 GNUNET_ARM_REQUEST_DISCONNECTED,
619 if (NULL != op->list_cont)
620 op->list_cont (op->cont_cls,
621 GNUNET_ARM_REQUEST_DISCONNECTED,
624 if (NULL != op->async)
626 GNUNET_SCHEDULER_cancel (op->async);
633 GNUNET_MQ_destroy (h->mq);
636 if (NULL != h->reconnect_task)
638 GNUNET_SCHEDULER_cancel (h->reconnect_task);
639 h->reconnect_task = NULL;
646 * A client specifically requested starting of ARM itself.
647 * Starts the ARM service.
649 * @param h the handle with configuration details
650 * @param std_inheritance inheritance of std streams
651 * @param sigfd socket to pass to ARM for signalling
652 * @return operation status code
654 static enum GNUNET_ARM_Result
655 start_arm_service (struct GNUNET_ARM_Handle *h,
656 enum GNUNET_OS_InheritStdioFlags std_inheritance,
657 struct GNUNET_DISK_FileHandle *sigfd)
659 struct GNUNET_OS_Process *proc;
679 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (h->cfg,
683 loprefix = GNUNET_strdup ("");
685 loprefix = GNUNET_CONFIGURATION_expand_dollar (h->cfg, loprefix);
686 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (h->cfg,
690 lopostfix = GNUNET_strdup ("");
692 lopostfix = GNUNET_CONFIGURATION_expand_dollar (h->cfg,
695 GNUNET_CONFIGURATION_get_value_string (h->cfg,
700 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
703 GNUNET_free (loprefix);
704 GNUNET_free (lopostfix);
705 return GNUNET_ARM_RESULT_IS_NOT_KNOWN;
707 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg,
712 binary = GNUNET_OS_get_libexec_binary_path (cbinary);
713 GNUNET_asprintf ("edbinary,
716 GNUNET_free (cbinary);
718 GNUNET_CONFIGURATION_have_value (h->cfg,
722 GNUNET_CONFIGURATION_get_value_yesno (h->cfg,
726 GNUNET_CONFIGURATION_have_value (h->cfg,
730 /* Means we are ONLY running locally */
731 /* we're clearly running a test, don't daemonize */
733 proc = GNUNET_OS_start_process_s (GNUNET_NO,
738 /* no daemonization! */
742 proc = GNUNET_OS_start_process_s (GNUNET_NO,
749 /* no daemonization! */
756 proc = GNUNET_OS_start_process_s (GNUNET_NO,
761 "-d", /* do daemonize */
765 proc = GNUNET_OS_start_process_s (GNUNET_NO,
772 "-d", /* do daemonize */
776 GNUNET_free (binary);
777 GNUNET_free (quotedbinary);
778 GNUNET_free_non_null (config);
779 GNUNET_free (loprefix);
780 GNUNET_free (lopostfix);
782 return GNUNET_ARM_RESULT_START_FAILED;
783 GNUNET_OS_process_destroy (proc);
784 return GNUNET_ARM_RESULT_STARTING;
789 * Abort an operation. Only prevents the callback from being
790 * called, the operation may still complete.
792 * @param op operation to cancel
795 GNUNET_ARM_operation_cancel (struct GNUNET_ARM_Operation *op)
797 struct GNUNET_ARM_Handle *h = op->h;
799 if (NULL != op->async)
801 GNUNET_SCHEDULER_cancel (op->async);
806 GNUNET_DISK_file_close (op->rfd);
811 op->result_cont = NULL;
814 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
815 h->operation_pending_tail,
822 * Start or stop a service.
824 * @param h handle to ARM
825 * @param service_name name of the service
826 * @param cb callback to invoke when service is ready
827 * @param cb_cls closure for @a cb
828 * @param type type of the request
829 * @return handle to queue, NULL on error
831 static struct GNUNET_ARM_Operation *
832 change_service (struct GNUNET_ARM_Handle *h,
833 const char *service_name,
834 GNUNET_ARM_ResultCallback cb,
838 struct GNUNET_ARM_Operation *op;
840 struct GNUNET_MQ_Envelope *env;
841 struct GNUNET_ARM_Message *msg;
843 slen = strlen (service_name) + 1;
844 if (slen + sizeof(struct GNUNET_ARM_Message) >= GNUNET_MAX_MESSAGE_SIZE)
849 if (0 == h->request_id_counter)
850 h->request_id_counter++;
851 op = GNUNET_new (struct GNUNET_ARM_Operation);
853 op->result_cont = cb;
854 op->cont_cls = cb_cls;
855 op->id = h->request_id_counter++;
856 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
857 h->operation_pending_tail,
859 env = GNUNET_MQ_msg_extra (msg, slen, type);
860 msg->reserved = htonl (0);
861 msg->request_id = GNUNET_htonll (op->id);
862 GNUNET_memcpy (&msg[1], service_name, slen);
863 GNUNET_MQ_send (h->mq, env);
869 * Task run to notify application that ARM is already up.
871 * @param cls the operation that asked ARM to be started
874 notify_running (void *cls)
876 struct GNUNET_ARM_Operation *op = cls;
877 struct GNUNET_ARM_Handle *h = op->h;
880 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
881 h->operation_pending_tail,
883 if (NULL != op->result_cont)
884 op->result_cont (op->cont_cls,
885 GNUNET_ARM_REQUEST_SENT_OK,
886 GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
887 if ( (GNUNET_YES == h->currently_up) &&
888 (NULL != h->conn_status) )
889 h->conn_status (h->conn_status_cls,
896 * Task run to notify application that ARM is being started.
898 * @param cls the operation that asked ARM to be started
901 notify_starting (void *cls)
903 struct GNUNET_ARM_Operation *op = cls;
904 struct GNUNET_ARM_Handle *h = op->h;
907 LOG (GNUNET_ERROR_TYPE_DEBUG,
908 "Notifying client that we started the ARM service\n");
909 GNUNET_CONTAINER_DLL_remove (h->operation_pending_head,
910 h->operation_pending_tail,
912 if (NULL != op->result_cont)
913 op->result_cont (op->cont_cls,
914 GNUNET_ARM_REQUEST_SENT_OK,
921 * Request for a service to be started.
923 * @param h handle to ARM
924 * @param service_name name of the service
925 * @param std_inheritance inheritance of std streams
926 * @param cont callback to invoke after request is sent or not sent
927 * @param cont_cls closure for @a cont
928 * @return handle for the operation, NULL on error
930 struct GNUNET_ARM_Operation *
931 GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h,
932 const char *service_name,
933 enum GNUNET_OS_InheritStdioFlags
935 GNUNET_ARM_ResultCallback cont,
938 struct GNUNET_ARM_Operation *op;
939 enum GNUNET_ARM_Result ret;
940 struct GNUNET_DISK_PipeHandle *sig;
941 struct GNUNET_DISK_FileHandle *wsig;
943 LOG (GNUNET_ERROR_TYPE_DEBUG,
944 "Starting service `%s'\n",
946 if (0 != strcasecmp ("arm",
948 return change_service (h,
952 GNUNET_MESSAGE_TYPE_ARM_START);
955 * 1) We're connected to ARM already. Invoke the callback immediately.
956 * 2) We're not connected to ARM.
957 * Cancel any reconnection attempts temporarily, then perform
960 if (GNUNET_YES == h->currently_up)
962 LOG (GNUNET_ERROR_TYPE_DEBUG,
963 "ARM is already running\n");
964 op = GNUNET_new (struct GNUNET_ARM_Operation);
966 op->result_cont = cont;
967 op->cont_cls = cont_cls;
968 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
969 h->operation_pending_tail,
971 op->async = GNUNET_SCHEDULER_add_now (¬ify_running, op);
974 /* This is an inherently uncertain choice, as it is of course
975 theoretically possible that ARM is up and we just did not
976 yet complete the MQ handshake. However, given that users
977 are unlikely to hammer 'gnunet-arm -s' on a busy system,
978 the above check should catch 99.99% of the cases where ARM
979 is already running. */
980 LOG (GNUNET_ERROR_TYPE_DEBUG,
981 "Starting ARM service\n");
982 if (NULL == (sig = GNUNET_DISK_pipe (GNUNET_NO,
987 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
990 wsig = GNUNET_DISK_pipe_detach_end (sig,
991 GNUNET_DISK_PIPE_END_WRITE);
992 ret = start_arm_service (h,
995 GNUNET_DISK_file_close (wsig);
996 if (GNUNET_ARM_RESULT_STARTING == ret)
998 op = GNUNET_new (struct GNUNET_ARM_Operation);
1000 op->result_cont = cont;
1001 op->cont_cls = cont_cls;
1002 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
1003 h->operation_pending_tail,
1005 op->starting_ret = ret;
1008 op->rfd = GNUNET_DISK_pipe_detach_end (sig,
1009 GNUNET_DISK_PIPE_END_READ);
1010 /* Wait at most a minute for gnunet-service-arm to be up, as beyond
1011 that something clearly just went wrong */
1012 op->async = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_MINUTES,
1019 op->async = GNUNET_SCHEDULER_add_now (¬ify_starting,
1022 GNUNET_DISK_pipe_close (sig);
1028 * Request a service to be stopped. Stopping arm itself will not
1029 * invalidate its handle, and ARM API will try to restore connection
1030 * to the ARM service, even if ARM connection was lost because you
1031 * asked for ARM to be stopped. Call
1032 * #GNUNET_ARM_disconnect() to free the handle and prevent
1033 * further connection attempts.
1035 * @param h handle to ARM
1036 * @param service_name name of the service
1037 * @param cont callback to invoke after request is sent or is not sent
1038 * @param cont_cls closure for @a cont
1039 * @return handle for the operation, NULL on error
1041 struct GNUNET_ARM_Operation *
1042 GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h,
1043 const char *service_name,
1044 GNUNET_ARM_ResultCallback cont,
1047 struct GNUNET_ARM_Operation *op;
1049 LOG (GNUNET_ERROR_TYPE_DEBUG,
1050 "Stopping service `%s'\n",
1052 op = change_service (h,
1056 GNUNET_MESSAGE_TYPE_ARM_STOP);
1059 /* If the service is ARM, set a flag as we will use MQ errors
1060 to detect that the process is really gone. */
1061 if (0 == strcasecmp (service_name,
1063 op->is_arm_stop = GNUNET_YES;
1069 * Request a list of running services.
1071 * @param h handle to ARM
1072 * @param cont callback to invoke after request is sent or is not sent
1073 * @param cont_cls closure for @a cont
1074 * @return handle for the operation, NULL on error
1076 struct GNUNET_ARM_Operation *
1077 GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h,
1078 GNUNET_ARM_ServiceListCallback cont,
1081 struct GNUNET_ARM_Operation *op;
1082 struct GNUNET_MQ_Envelope *env;
1083 struct GNUNET_ARM_Message *msg;
1085 LOG (GNUNET_ERROR_TYPE_DEBUG,
1086 "Requesting LIST from ARM service\n");
1087 if (0 == h->request_id_counter)
1088 h->request_id_counter++;
1089 op = GNUNET_new (struct GNUNET_ARM_Operation);
1091 op->list_cont = cont;
1092 op->cont_cls = cont_cls;
1093 op->id = h->request_id_counter++;
1094 GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head,
1095 h->operation_pending_tail,
1097 env = GNUNET_MQ_msg (msg,
1098 GNUNET_MESSAGE_TYPE_ARM_LIST);
1099 msg->reserved = htonl (0);
1100 msg->request_id = GNUNET_htonll (op->id);
1101 GNUNET_MQ_send (h->mq, env);
1106 /* end of arm_api.c */