2 This file is part of GNUnet.
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.
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.
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.
22 * @file sensor/sensor_api.c
23 * @brief API for sensor service
24 * @author Omar Tarabai
27 #include "gnunet_util_lib.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-api",__VA_ARGS__)
33 * Handle to the sensor service.
35 struct GNUNET_SENSOR_Handle
41 const struct GNUNET_CONFIGURATION_Handle *cfg;
44 * Connection to the service.
46 struct GNUNET_CLIENT_Connection *client;
49 * Head of iteration requests DLL.
51 struct GNUNET_SENSOR_IterateContext *ic_head;
54 * Tail of iteration requests DLL.
56 struct GNUNET_SENSOR_IterateContext *ic_tail;
59 * Head of force anomaly requests
61 struct GNUNET_SENSOR_ForceAnomalyContext *fa_head;
64 * Tail of force anomaly requests
66 struct GNUNET_SENSOR_ForceAnomalyContext *fa_tail;
69 * Message queue used to send data to service
71 struct GNUNET_MQ_Handle *mq;
76 * Context for an iteration request.
78 struct GNUNET_SENSOR_IterateContext
84 struct GNUNET_SENSOR_IterateContext *next;
89 struct GNUNET_SENSOR_IterateContext *prev;
92 * Handle to the SENSOR service.
94 struct GNUNET_SENSOR_Handle *h;
97 * Function to call with the results.
99 GNUNET_SENSOR_SensorIterateCB callback;
102 * Closure for 'callback'.
107 * Envelope containing iterate request.
109 struct GNUNET_MQ_Envelope *ev;
112 * Is the request already sent? If yes, cannot be canceled.
117 * Are we expecting records from service?
122 * Task responsible for timeout.
124 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
129 * Context of a force anomaly request
131 struct GNUNET_SENSOR_ForceAnomalyContext
137 struct GNUNET_SENSOR_ForceAnomalyContext *next;
142 struct GNUNET_SENSOR_ForceAnomalyContext *prev;
145 * Handle to the SENSOR service.
147 struct GNUNET_SENSOR_Handle *h;
150 * Envelope containing iterate request.
152 struct GNUNET_MQ_Envelope *ev;
155 * User continuation function
157 GNUNET_SENSOR_Continuation cont;
168 * Notifier of an error encountered by MQ.
170 * @param cls Closure, service handle
171 * @param error MQ error type
174 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
176 struct GNUNET_SENSOR_Handle *h = cls;
178 LOG (GNUNET_ERROR_TYPE_ERROR,
179 _("Received an error notification from MQ of type: %d\n"), error);
180 GNUNET_SENSOR_disconnect (h); //TODO: try to reconnect
185 * Handler to a message of type: #GNUNET_MESSAGE_TYPE_SENSOR_END
187 * @param cls Closure, service handle
188 * @param msg Message received
191 handle_end (void *cls, const struct GNUNET_MessageHeader *msg)
193 struct GNUNET_SENSOR_Handle *h = cls;
194 struct GNUNET_SENSOR_IterateContext *ic;
195 GNUNET_SENSOR_SensorIterateCB cb;
198 if (NULL == h->ic_head)
206 cb_cls = ic->callback_cls;
207 ic->receiving = GNUNET_NO;
208 GNUNET_SENSOR_iterate_cancel (ic);
210 cb (cb_cls, NULL, NULL);
215 * Handler to a message of type: #GNUNET_MESSAGE_TYPE_SENSOR_INFO
217 * @param cls Closure, service handle
218 * @param msg Message received
221 handle_sensor_info (void *cls, const struct GNUNET_MessageHeader *msg)
223 struct GNUNET_SENSOR_Handle *h = cls;
224 struct GNUNET_SENSOR_IterateContext *ic;
226 struct SensorInfoMessage *sensor_msg;
227 uint16_t sensor_name_len;
228 uint16_t sensor_desc_len;
229 struct SensorInfoShort *sensor;
232 if (NULL == h->ic_head)
239 if (NULL == ic->callback) /* no need to parse message */
241 msg_size = ntohs (msg->size);
242 if (msg_size < sizeof (struct SensorInfoMessage))
248 sensor_msg = (struct SensorInfoMessage *) msg;
249 sensor_name_len = ntohs (sensor_msg->name_len);
250 sensor_desc_len = ntohs (sensor_msg->description_len);
252 sizeof (struct SensorInfoMessage) + sensor_name_len + sensor_desc_len)
258 sensor = GNUNET_new (struct SensorInfoShort);
259 sensor->version_major = ntohs (sensor_msg->version_major);
260 sensor->version_minor = ntohs (sensor_msg->version_minor);
261 dummy = &sensor_msg[1];
262 sensor->name = GNUNET_strndup (dummy, sensor_name_len);
263 dummy += sensor_name_len;
264 sensor->description = GNUNET_strndup (dummy, sensor_desc_len);
265 ic->callback (ic->callback_cls, sensor, NULL);
266 GNUNET_free (sensor->name);
267 GNUNET_free (sensor->description);
268 GNUNET_free (sensor);
273 * Disconnect from the sensor service.
274 * Please disconnect only when all requests sent are complete or canceled.
276 * @param h handle to disconnect
279 GNUNET_SENSOR_disconnect (struct GNUNET_SENSOR_Handle *h)
281 struct GNUNET_SENSOR_IterateContext *ic;
282 GNUNET_SENSOR_SensorIterateCB ic_callback;
283 void *ic_callback_cls;
284 struct GNUNET_SENSOR_ForceAnomalyContext *fa;
285 GNUNET_SENSOR_Continuation fa_cont;
291 ic_callback = ic->callback;
292 ic_callback_cls = ic->callback_cls;
293 GNUNET_SENSOR_iterate_cancel (ic);
294 if (NULL != ic_callback)
295 ic_callback (ic_callback_cls, NULL,
296 _("Iterate request canceled due to disconnection.\n"));
303 fa_cont_cls = fa->cont_cls;
304 GNUNET_SENSOR_force_anomaly_cancel (fa);
306 fa_cont (fa_cont_cls,
307 _("Force anomaly request canceled due to disconnection.\n"));
312 GNUNET_MQ_destroy (h->mq);
315 if (NULL != h->client)
317 GNUNET_CLIENT_disconnect (h->client);
325 * Connect to the sensor service.
327 * @return NULL on error
329 struct GNUNET_SENSOR_Handle *
330 GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
332 struct GNUNET_CLIENT_Connection *client;
333 struct GNUNET_SENSOR_Handle *h;
335 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
336 {&handle_sensor_info, GNUNET_MESSAGE_TYPE_SENSOR_INFO, 0},
337 {&handle_end, GNUNET_MESSAGE_TYPE_SENSOR_END, 0},
338 GNUNET_MQ_HANDLERS_END
341 client = GNUNET_CLIENT_connect ("sensor", cfg);
344 h = GNUNET_new (struct GNUNET_SENSOR_Handle);
348 GNUNET_MQ_queue_for_connection_client (h->client, mq_handlers,
349 &mq_error_handler, h);
355 * Iteration request has timed out.
357 * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*'
358 * @param tc scheduler context
361 signal_sensor_iteration_timeout (void *cls,
362 const struct GNUNET_SCHEDULER_TaskContext *tc)
364 struct GNUNET_SENSOR_IterateContext *ic = cls;
365 GNUNET_SENSOR_SensorIterateCB cb;
368 ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
370 cb_cls = ic->callback_cls;
371 GNUNET_SENSOR_iterate_cancel (ic);
374 _("Timeout transmitting iteration request to `SENSOR' service."));
379 * Callback from MQ when the request has already been sent to the service.
380 * Now it can not be canelled.
385 iterate_request_sent (void *cls)
387 struct GNUNET_SENSOR_IterateContext *ic = cls;
389 ic->request_sent = GNUNET_YES;
391 ic->receiving = GNUNET_YES;
396 * Cancel an iteration request.
397 * This should be called before the iterate callback is called with a NULL value.
399 * @param ic context of the iterator to cancel
402 GNUNET_SENSOR_iterate_cancel (struct GNUNET_SENSOR_IterateContext *ic)
404 struct GNUNET_SENSOR_Handle *h;
407 if (GNUNET_NO == ic->request_sent)
409 GNUNET_MQ_send_cancel (ic->ev);
411 ic->request_sent = GNUNET_YES;
413 if (GNUNET_YES == ic->receiving)
415 /* don't remove since we are still expecting records */
417 ic->callback_cls = NULL;
420 if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task)
422 GNUNET_SCHEDULER_cancel (ic->timeout_task);
423 ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
425 GNUNET_CONTAINER_DLL_remove (h->ic_head, h->ic_tail, ic);
431 * Get one or all sensors loaded by the sensor service.
432 * The callback will be called with each sensor received and once with a NULL
433 * value to signal end of iteration.
435 * @param h Handle to SENSOR service
436 * @param timeout how long to wait until timing out
437 * @param sensorname Name of the required sensor, NULL to get all
438 * @param callback the function to call for each sensor
439 * @param callback_cls closure for callback
440 * @return iterator context
442 struct GNUNET_SENSOR_IterateContext *
443 GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h,
444 struct GNUNET_TIME_Relative timeout,
445 const char *sensor_name,
446 GNUNET_SENSOR_SensorIterateCB callback,
449 struct GNUNET_SENSOR_IterateContext *ic;
450 struct GNUNET_MessageHeader *msg;
451 struct GNUNET_MQ_Envelope *ev;
452 size_t sensor_name_len;
454 if (NULL == sensor_name)
456 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
460 sensor_name_len = strlen (sensor_name) + 1;
461 ev = GNUNET_MQ_msg_extra (msg, sensor_name_len,
462 GNUNET_MESSAGE_TYPE_SENSOR_GET);
463 memcpy (&msg[1], sensor_name, sensor_name_len);
465 GNUNET_MQ_send (h->mq, ev);
466 ic = GNUNET_new (struct GNUNET_SENSOR_IterateContext);
470 ic->request_sent = GNUNET_NO;
471 ic->receiving = GNUNET_NO;
472 ic->callback = callback;
473 ic->callback_cls = callback_cls;
475 GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout,
477 GNUNET_MQ_notify_sent (ev, &iterate_request_sent, ic);
478 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, h->ic_tail, ic);
484 * Callback from MQ when the request has already been sent to the service.
485 * Now it can not be canelled.
490 force_anomaly_sent (void *cls)
492 struct GNUNET_SENSOR_ForceAnomalyContext *fa = cls;
493 GNUNET_SENSOR_Continuation cont;
498 cont_cls = fa->cont_cls;
499 GNUNET_SENSOR_force_anomaly_cancel (fa);
501 cont (cont_cls, NULL);
506 * Cancel a force anomaly request.
508 * @param fa Force anomaly context returned by GNUNET_SENSOR_force_anomaly()
511 GNUNET_SENSOR_force_anomaly_cancel (struct GNUNET_SENSOR_ForceAnomalyContext
514 struct GNUNET_SENSOR_Handle *h = fa->h;
518 GNUNET_MQ_send_cancel (fa->ev);
521 GNUNET_CONTAINER_DLL_remove (h->fa_head, h->fa_tail, fa);
527 * Force an anomaly status change on a given sensor. If the sensor reporting
528 * module is running, this will trigger the usual reporting logic, therefore,
529 * please only use this in a test environment.
531 * Also, if the sensor analysis module is running, it might conflict and cause
532 * undefined behaviour if it detects a real anomaly.
534 * @param h Service handle
535 * @param sensor_name Sensor name to set the anomaly status
536 * @param anomalous The desired status: #GNUNET_YES / #GNUNET_NO
537 * @param cont Continuation function to be called after the request is sent
538 * @param cont_cls Closure for cont
540 struct GNUNET_SENSOR_ForceAnomalyContext *
541 GNUNET_SENSOR_force_anomaly (struct GNUNET_SENSOR_Handle *h, char *sensor_name,
542 int anomalous, GNUNET_SENSOR_Continuation cont,
545 struct ForceAnomalyMessage *msg;
546 struct GNUNET_MQ_Envelope *ev;
547 struct GNUNET_SENSOR_ForceAnomalyContext *fa;
549 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_FORCE);
550 GNUNET_CRYPTO_hash (sensor_name, strlen (sensor_name) + 1,
551 &msg->sensor_name_hash);
552 msg->anomalous = htons (anomalous);
553 GNUNET_MQ_send (h->mq, ev);
554 fa = GNUNET_new (struct GNUNET_SENSOR_ForceAnomalyContext);
558 fa->cont_cls = cont_cls;
560 GNUNET_CONTAINER_DLL_insert_tail (h->fa_head, h->fa_tail, fa);
561 GNUNET_MQ_notify_sent (ev, &force_anomaly_sent, fa);
566 /* end of sensor_api.c */