aboutsummaryrefslogtreecommitdiff
path: root/src/arm/arm_monitor_api.c
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2013-03-13 18:03:58 +0000
committerLRN <lrn1986@gmail.com>2013-03-13 18:03:58 +0000
commitbb07e7a95539641ac484e21b72b760aab5e36588 (patch)
treee8383894f12189ce8384ddc212e344a50551377c /src/arm/arm_monitor_api.c
parent405f776bc08486af4edb80e18149c0829732b347 (diff)
downloadgnunet-bb07e7a95539641ac484e21b72b760aab5e36588.tar.gz
gnunet-bb07e7a95539641ac484e21b72b760aab5e36588.zip
Forgot to add the file...
Diffstat (limited to 'src/arm/arm_monitor_api.c')
-rw-r--r--src/arm/arm_monitor_api.c367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/arm/arm_monitor_api.c b/src/arm/arm_monitor_api.c
new file mode 100644
index 000000000..dc690b904
--- /dev/null
+++ b/src/arm/arm_monitor_api.c
@@ -0,0 +1,367 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010, 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file arm/arm_monitor_api.c
23 * @brief API for monitoring the ARM service
24 * @author Christian Grothoff, LRN
25 */
26#include "platform.h"
27#include "gnunet_arm_service.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "arm.h"
31
32#define INIT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
33
34#define LOG(kind,...) GNUNET_log_from (kind, "arm-monitor-api",__VA_ARGS__)
35
36/**
37 * Handle for interacting with ARM.
38 */
39struct GNUNET_ARM_MonitorHandle
40{
41
42 /**
43 * Our control connection to the ARM service.
44 */
45 struct GNUNET_CLIENT_Connection *monitor;
46
47 /**
48 * The configuration that we are using.
49 */
50 struct GNUNET_CONFIGURATION_Handle *cfg;
51
52 /**
53 * Handle for our current transmission request.
54 */
55 struct GNUNET_CLIENT_TransmitHandle *cth;
56
57 /**
58 * ID of the reconnect task (if any).
59 */
60 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
61
62 /**
63 * Current delay we use for re-trying to connect to core.
64 */
65 struct GNUNET_TIME_Relative retry_backoff;
66
67 /**
68 * Are we currently disconnected and hence unable to send?
69 */
70 unsigned char currently_down;
71
72 /**
73 * Callback to invoke on status updates.
74 */
75 GNUNET_ARM_ServiceStatusCallback service_status;
76
77 /**
78 * Closure for service_status.
79 */
80 void *cls;
81
82 /**
83 * ID of a task to run if we fail to get a reply to the init message in time.
84 */
85 GNUNET_SCHEDULER_TaskIdentifier init_timeout_task_id;
86};
87
88static void
89monitor_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg);
90
91static void
92reconnect_arm_monitor (struct GNUNET_ARM_MonitorHandle *h);
93
94/**
95 * Task scheduled to try to re-connect to arm.
96 *
97 * @param cls the 'struct GNUNET_ARM_MonitorHandle'
98 * @param tc task context
99 */
100static void
101reconnect_arm_monitor_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
102{
103 struct GNUNET_ARM_MonitorHandle *h = cls;
104
105 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
106 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to ARM service for monitoring after delay\n");
107 reconnect_arm_monitor (h);
108}
109
110
111/**
112 * Close down any existing connection to the ARM service and
113 * try re-establishing it later.
114 *
115 * @param h our handle
116 */
117static void
118reconnect_arm_monitor_later (struct GNUNET_ARM_MonitorHandle *h)
119{
120 if (NULL != h->cth)
121 {
122 GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth);
123 h->cth = NULL;
124 }
125
126 if (NULL != h->monitor)
127 {
128 GNUNET_CLIENT_disconnect (h->monitor);
129 h->monitor = NULL;
130 }
131
132 if (GNUNET_SCHEDULER_NO_TASK != h->init_timeout_task_id)
133 {
134 GNUNET_SCHEDULER_cancel (h->init_timeout_task_id);
135 h->init_timeout_task_id = GNUNET_SCHEDULER_NO_TASK;
136 }
137
138 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task);
139 h->reconnect_task =
140 GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_arm_monitor_task, h);
141
142 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
143}
144
145
146/**
147 * Init message timed out. Disconnect and try again.
148 *
149 * @param cls arm monitor handle
150 * @param tc task context
151 */
152static void
153init_timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
154{
155 struct GNUNET_ARM_MonitorHandle *h = cls;
156 LOG (GNUNET_ERROR_TYPE_DEBUG,
157 "Init message timed out\n");
158
159 reconnect_arm_monitor_later (h);
160}
161
162
163/**
164 * Transmit the monitoring initialization message to the arm service.
165 *
166 * @param cls closure with the 'struct GNUNET_ARM_MonitorHandle'
167 * @param size number of bytes available in buf
168 * @param buf where the callee should write the message
169 * @return number of bytes written to buf
170 */
171static size_t
172transmit_monitoring_init_message (void *cls, size_t size, void *buf)
173{
174 struct GNUNET_ARM_MonitorHandle *h = cls;
175 struct GNUNET_MessageHeader *msg;
176 uint16_t msize;
177
178 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task);
179 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->init_timeout_task_id);
180 h->cth = NULL;
181 if (NULL == buf)
182 {
183 LOG (GNUNET_ERROR_TYPE_DEBUG,
184 "Transmission failed, initiating reconnect\n");
185 reconnect_arm_monitor_later (h);
186 return 0;
187 }
188 msize = sizeof (struct GNUNET_MessageHeader);
189 if (size < msize)
190 {
191 LOG (GNUNET_ERROR_TYPE_DEBUG,
192 "Request is too big (%u < %u), not sending it\n", size, msize);
193 h->cth = GNUNET_CLIENT_notify_transmit_ready (h->monitor, msize,
194 GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO,
195 transmit_monitoring_init_message, h);
196 return 0;
197 }
198
199 msg = buf;
200 msg->size = htons (msize);
201 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_MONITOR);
202 LOG (GNUNET_ERROR_TYPE_DEBUG,
203 "Transmitting ARM monitoring init message with %u bytes to arm.\n",
204 (unsigned int) msize);
205
206 h->init_timeout_task_id = GNUNET_SCHEDULER_add_delayed (
207 INIT_TIMEOUT, init_timeout_task, h);
208 GNUNET_CLIENT_receive (h->monitor, &monitor_notify_handler, h,
209 GNUNET_TIME_UNIT_FOREVER_REL);
210 return msize;
211}
212
213
214static void
215reconnect_arm_monitor (struct GNUNET_ARM_MonitorHandle *h)
216{
217 GNUNET_assert (NULL == h->monitor);
218 h->monitor = GNUNET_CLIENT_connect ("arm", h->cfg);
219 if (NULL == h->monitor)
220 {
221 LOG (GNUNET_ERROR_TYPE_DEBUG,
222 "arm_api, GNUNET_CLIENT_connect returned NULL\n");
223 GNUNET_CLIENT_disconnect (h->monitor);
224 h->monitor = NULL;
225 return;
226 }
227 LOG (GNUNET_ERROR_TYPE_DEBUG,
228 "arm_api, GNUNET_CLIENT_connect returned non-NULL\n");
229 h->cth = GNUNET_CLIENT_notify_transmit_ready (h->monitor,
230 sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL,
231 GNUNET_NO, &transmit_monitoring_init_message, h);
232}
233
234
235/**
236 * Setup a context for monitoring ARM. Note that this
237 * can be done even if the ARM service is not yet running.
238 * Never fails.
239 *
240 * @param cfg configuration to use (needed to contact ARM;
241 * the ARM service may internally use a different
242 * configuration to determine how to start the service).
243 * @return context to use for further ARM monitoring operations
244 */
245struct GNUNET_ARM_MonitorHandle *
246GNUNET_ARM_monitor_alloc (const struct GNUNET_CONFIGURATION_Handle *cfg)
247{
248 struct GNUNET_ARM_MonitorHandle *ret;
249
250 ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_MonitorHandle));
251 ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
252 ret->currently_down = GNUNET_YES;
253 ret->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
254 ret->init_timeout_task_id = GNUNET_SCHEDULER_NO_TASK;
255 return ret;
256}
257
258
259/**
260 * Start connecting to the ARM service for monitoring using the context.
261 *
262 * @param h ARM monitor handle
263 * @param cont callback to invoke on status updates
264 * @param cont_cls closure
265 */
266void
267GNUNET_ARM_monitor (struct GNUNET_ARM_MonitorHandle *h,
268 GNUNET_ARM_ServiceStatusCallback cont, void *cont_cls)
269{
270 h->service_status = cont;
271 h->cls = cont_cls;
272 reconnect_arm_monitor (h);
273}
274
275
276/**
277 * Disconnect from the ARM service (if connected) and destroy the context.
278 * Don't call inside a callback!
279 *
280 * @param h the handle that was being used
281 */
282void
283GNUNET_ARM_monitor_disconnect (struct GNUNET_ARM_MonitorHandle *handle)
284{
285 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from ARM service\n");
286 if (NULL != handle->cth)
287 {
288 GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth);
289 handle->cth = NULL;
290 }
291 if (GNUNET_SCHEDULER_NO_TASK != handle->init_timeout_task_id)
292 {
293 GNUNET_SCHEDULER_cancel (handle->init_timeout_task_id);
294 handle->init_timeout_task_id = GNUNET_SCHEDULER_NO_TASK;
295 }
296 if (NULL != handle->monitor)
297 {
298 GNUNET_CLIENT_disconnect (handle->monitor);
299 handle->monitor = NULL;
300 }
301 if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
302 {
303 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
304 handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
305 }
306 GNUNET_CONFIGURATION_destroy (handle->cfg);
307 GNUNET_free (handle);
308}
309
310
311/**
312 * Handler for notification messages received from ARM.
313 *
314 * @param cls our "struct GNUNET_ARM_MonitorHandle"
315 * @param msg the message received from the arm service
316 */
317static void
318monitor_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg)
319{
320 struct GNUNET_ARM_MonitorHandle *h = cls;
321 uint16_t msize;
322 const struct GNUNET_ARM_StatusMessage *res;
323 enum GNUNET_ARM_ServiceStatus status;
324
325 if (NULL == msg)
326 {
327 LOG (GNUNET_ERROR_TYPE_INFO,
328 _("Monitoring client was disconnected from arm service, trying to reconnect.\n"));
329 reconnect_arm_monitor_later (h);
330 return;
331 }
332 msize = ntohs (msg->size);
333 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "Processing message of type %u and size %u from arm service\n",
335 ntohs (msg->type), msize);
336 switch (ntohs (msg->type))
337 {
338 case GNUNET_MESSAGE_TYPE_ARM_STATUS:
339 if (msize <= sizeof (struct GNUNET_ARM_StatusMessage))
340 {
341 GNUNET_break (0);
342 reconnect_arm_monitor_later (h);
343 return;
344 }
345 if (GNUNET_SCHEDULER_NO_TASK != h->init_timeout_task_id)
346 {
347 GNUNET_SCHEDULER_cancel (h->init_timeout_task_id);
348 h->init_timeout_task_id = GNUNET_SCHEDULER_NO_TASK;
349 }
350 res = (const struct GNUNET_ARM_StatusMessage *) msg;
351 LOG (GNUNET_ERROR_TYPE_DEBUG,
352 "Received response from ARM for service `%s': %u\n",
353 (const char *) &res[1], ntohs (msg->type));
354 status = (enum GNUNET_ARM_ServiceStatus) ntohl (res->status);
355 if ((NULL != h->service_status))
356 h->service_status (h->cls, h, (const char *) &res[1], status);
357 break;
358 default:
359 reconnect_arm_monitor_later (h);
360 return;
361 }
362 GNUNET_CLIENT_receive (h->monitor, &monitor_notify_handler, h,
363 GNUNET_TIME_UNIT_FOREVER_REL);
364}
365
366
367/* end of arm_api.c */