2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2012, 2013, 2016 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
22 * @file arm/arm_monitor_api.c
23 * @brief API for monitoring the ARM service
24 * @author Christian Grothoff
28 #include "gnunet_arm_service.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_protocols.h"
33 #define INIT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
35 #define LOG(kind, ...) GNUNET_log_from(kind, "arm-monitor-api", __VA_ARGS__)
38 * Handle for interacting with ARM.
40 struct GNUNET_ARM_MonitorHandle {
42 * Our control connection to the ARM service.
44 struct GNUNET_MQ_Handle *mq;
47 * The configuration that we are using.
49 const struct GNUNET_CONFIGURATION_Handle *cfg;
52 * ID of the reconnect task (if any).
54 struct GNUNET_SCHEDULER_Task *reconnect_task;
57 * Current delay we use for re-trying to connect to core.
59 struct GNUNET_TIME_Relative retry_backoff;
62 * Callback to invoke on status updates.
64 GNUNET_ARM_ServiceMonitorCallback service_status;
67 * Closure for @e service_status.
69 void *service_status_cls;
74 * Connect to the ARM service for monitoring.
76 * @param h handle to connect
77 * @return #GNUNET_OK on success
80 reconnect_arm_monitor(struct GNUNET_ARM_MonitorHandle *h);
84 * Task scheduled to try to re-connect to arm.
86 * @param cls the `struct GNUNET_ARM_MonitorHandle`
89 reconnect_arm_monitor_task(void *cls)
91 struct GNUNET_ARM_MonitorHandle *h = cls;
93 h->reconnect_task = NULL;
94 LOG(GNUNET_ERROR_TYPE_DEBUG,
95 "Connecting to ARM service for monitoring after delay\n");
96 GNUNET_break(GNUNET_OK == reconnect_arm_monitor(h));
101 * Close down any existing connection to the ARM service and
102 * try re-establishing it later.
104 * @param h our handle
107 reconnect_arm_monitor_later(struct GNUNET_ARM_MonitorHandle *h)
111 GNUNET_MQ_destroy(h->mq);
114 GNUNET_assert(NULL == h->reconnect_task);
115 h->reconnect_task = GNUNET_SCHEDULER_add_delayed(h->retry_backoff,
116 &reconnect_arm_monitor_task,
118 h->retry_backoff = GNUNET_TIME_STD_BACKOFF(h->retry_backoff);
123 * Check notification messages received from ARM is well-formed.
125 * @param cls our `struct GNUNET_ARM_MonitorHandle`
126 * @param msg the message received from the arm service
127 * @return #GNUNET_OK if the message is well-formed
130 check_monitor_notify(void *cls, const struct GNUNET_ARM_StatusMessage *msg)
133 ntohs(msg->header.size) - sizeof(struct GNUNET_ARM_StatusMessage);
134 const char *name = (const char *)&msg[1];
137 if ((0 == sl) || ('\0' != name[sl - 1]))
140 return GNUNET_SYSERR;
147 * Handler for notification messages received from ARM.
149 * @param cls our `struct GNUNET_ARM_MonitorHandle`
150 * @param res the message received from the arm service
153 handle_monitor_notify(void *cls, const struct GNUNET_ARM_StatusMessage *res)
155 struct GNUNET_ARM_MonitorHandle *h = cls;
156 enum GNUNET_ARM_ServiceMonitorStatus status;
158 status = (enum GNUNET_ARM_ServiceMonitorStatus)ntohl(res->status);
159 LOG(GNUNET_ERROR_TYPE_DEBUG,
160 "Received notification from ARM for service `%s' with status %d\n",
161 (const char *)&res[1],
163 if (NULL != h->service_status)
164 h->service_status(h->service_status_cls, (const char *)&res[1], status);
169 * Generic error handler, called with the appropriate error code and
170 * the same closure specified at the creation of the message queue.
171 * Not every message queue implementation supports an error handler.
173 * @param cls closure with the `struct GNUNET_ARM_MonitorHandle *`
174 * @param error error code
177 mq_error_handler(void *cls, enum GNUNET_MQ_Error error)
179 struct GNUNET_ARM_MonitorHandle *h = cls;
182 reconnect_arm_monitor_later(h);
187 * Connect to the ARM service for monitoring.
189 * @param h handle to connect
190 * @return #GNUNET_OK on success
193 reconnect_arm_monitor(struct GNUNET_ARM_MonitorHandle *h)
195 struct GNUNET_MQ_MessageHandler handlers[] =
196 { GNUNET_MQ_hd_var_size(monitor_notify,
197 GNUNET_MESSAGE_TYPE_ARM_STATUS,
198 struct GNUNET_ARM_StatusMessage,
200 GNUNET_MQ_handler_end() };
201 struct GNUNET_MessageHeader *msg;
202 struct GNUNET_MQ_Envelope *env;
204 GNUNET_assert(NULL == h->mq);
205 h->mq = GNUNET_CLIENT_connect(h->cfg, "arm", handlers, &mq_error_handler, h);
208 if (NULL != h->service_status)
209 h->service_status(h->service_status_cls,
211 GNUNET_ARM_SERVICE_STOPPED);
212 return GNUNET_SYSERR;
214 env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_ARM_MONITOR);
215 GNUNET_MQ_send(h->mq, env);
221 * Setup a context for monitoring ARM, then
222 * start connecting to the ARM service for monitoring using that context.
224 * @param cfg configuration to use (needed to contact ARM;
225 * the ARM service may internally use a different
226 * configuration to determine how to start the service).
227 * @param cont callback to invoke on status updates
228 * @param cont_cls closure for @a cont
229 * @return context to use for further ARM monitor operations, NULL on error.
231 struct GNUNET_ARM_MonitorHandle *
232 GNUNET_ARM_monitor_start(const struct GNUNET_CONFIGURATION_Handle *cfg,
233 GNUNET_ARM_ServiceMonitorCallback cont,
236 struct GNUNET_ARM_MonitorHandle *h;
238 h = GNUNET_new(struct GNUNET_ARM_MonitorHandle);
240 h->service_status = cont;
241 h->service_status_cls = cont_cls;
242 if (GNUNET_OK != reconnect_arm_monitor(h))
252 * Disconnect from the ARM service (if connected) and destroy the context.
254 * @param h the handle that was being used
257 GNUNET_ARM_monitor_stop(struct GNUNET_ARM_MonitorHandle *h)
261 GNUNET_MQ_destroy(h->mq);
264 if (NULL != h->reconnect_task)
266 GNUNET_SCHEDULER_cancel(h->reconnect_task);
267 h->reconnect_task = NULL;
273 /* end of arm_api.c */