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
24 * @author Omar Tarabai
27 #include "gnunet_util_lib.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-api",__VA_ARGS__)
32 /******************************************************************************/
33 /************************ DATA STRUCTURES ****************************/
34 /******************************************************************************/
37 * Handle to the sensor service.
39 struct GNUNET_SENSOR_Handle
45 const struct GNUNET_CONFIGURATION_Handle *cfg;
48 * Connection to the service.
50 struct GNUNET_CLIENT_Connection *client;
53 * Head of transmission queue.
55 struct GNUNET_SENSOR_RequestContext *rc_head;
58 * Tail of transmission queue.
60 struct GNUNET_SENSOR_RequestContext *rc_tail;
63 * Handle for the current transmission request, or NULL if none is pending.
65 struct GNUNET_CLIENT_TransmitHandle *th;
68 * Head of iterator DLL.
70 struct GNUNET_SENSOR_SensorIteratorContext *ic_head;
73 * Tail of iterator DLL.
75 struct GNUNET_SENSOR_SensorIteratorContext *ic_tail;
78 * ID for a reconnect task.
80 GNUNET_SCHEDULER_TaskIdentifier r_task;
83 * Are we now receiving?
90 * Entry in the transmission queue to SENSOR service.
93 struct GNUNET_SENSOR_RequestContext
96 * This is a linked list.
98 struct GNUNET_SENSOR_RequestContext *next;
101 * This is a linked list.
103 struct GNUNET_SENSOR_RequestContext *prev;
106 * Handle to the SENSOR service.
108 struct GNUNET_SENSOR_Handle *h;
111 * Function to call after request has been transmitted, or NULL.
113 GNUNET_SENSOR_Continuation cont;
116 * Closure for 'cont'.
121 * Number of bytes of the request message (follows after this struct).
128 * Context for an iteration request.
130 struct GNUNET_SENSOR_SensorIteratorContext
136 struct GNUNET_SENSOR_SensorIteratorContext *next;
141 struct GNUNET_SENSOR_SensorIteratorContext *prev;
144 * Handle to the SENSOR service.
146 struct GNUNET_SENSOR_Handle *h;
149 * Function to call with the results.
151 GNUNET_SENSOR_SensorIteratorCB callback;
154 * Closure for 'callback'.
159 * Our entry in the transmission queue.
161 struct GNUNET_SENSOR_RequestContext *rc;
164 * Task responsible for timeout.
166 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
169 * Timeout for the operation.
171 struct GNUNET_TIME_Absolute timeout;
174 * Set to GNUNET_YES if we are currently receiving replies from the
177 int request_transmitted;
181 /******************************************************************************/
182 /*********************** DECLARATIONS *************************/
183 /******************************************************************************/
186 * Close the existing connection to SENSOR and reconnect.
188 * @param h handle to the service
191 reconnect (struct GNUNET_SENSOR_Handle *h);
194 * Check if we have a request pending in the transmission queue and are
195 * able to transmit it right now. If so, schedule transmission.
197 * @param h handle to the service
200 trigger_transmit (struct GNUNET_SENSOR_Handle *h);
202 /******************************************************************************/
203 /******************* CONNECTION FUNCTIONS *********************/
204 /******************************************************************************/
207 * Connect to the sensor service.
209 * @return NULL on error
211 struct GNUNET_SENSOR_Handle *
212 GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
214 struct GNUNET_CLIENT_Connection *client;
215 struct GNUNET_SENSOR_Handle *h;
217 client = GNUNET_CLIENT_connect ("sensor", cfg);
220 h = GNUNET_new (struct GNUNET_SENSOR_Handle);
227 * Disconnect from the sensor service
229 * @param h handle to disconnect
232 GNUNET_SENSOR_disconnect(struct GNUNET_SENSOR_Handle *h)
234 if (NULL != h->client)
236 GNUNET_CLIENT_disconnect (h->client);
243 * Task scheduled to re-try connecting to the sensor service.
245 * @param cls the 'struct GNUNET_SENSOR_Handle'
246 * @param tc scheduler context
249 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
251 struct GNUNET_SENSOR_Handle *h = cls;
253 h->r_task = GNUNET_SCHEDULER_NO_TASK;
258 * Close the existing connection to SENSOR and reconnect.
260 * @param h handle to the service
263 reconnect (struct GNUNET_SENSOR_Handle *h)
265 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
267 GNUNET_SCHEDULER_cancel (h->r_task);
268 h->r_task = GNUNET_SCHEDULER_NO_TASK;
272 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
275 if (NULL != h->client)
277 GNUNET_CLIENT_disconnect (h->client);
280 h->in_receive = GNUNET_NO;
281 h->client = GNUNET_CLIENT_connect ("sensor", h->cfg);
282 if (NULL == h->client)
285 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
289 trigger_transmit (h);
292 /******************************************************************************/
293 /****************** SENSOR DATA FUNCTIONS *********************/
294 /******************************************************************************/
297 * Cancel an iteration over sensor information.
299 * @param ic context of the iterator to cancel
302 GNUNET_SENSOR_iterate_sensor_cancel (struct GNUNET_SENSOR_SensorIteratorContext *ic)
304 struct GNUNET_SENSOR_Handle *h;
307 if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task)
309 GNUNET_SCHEDULER_cancel (ic->timeout_task);
310 ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
313 if (GNUNET_YES == ic->request_transmitted)
314 return; /* need to finish processing */
315 GNUNET_CONTAINER_DLL_remove (h->ic_head,
320 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, ic->rc);
321 GNUNET_free (ic->rc);
327 * Iteration request has timed out.
329 * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*'
330 * @param tc scheduler context
333 signal_sensor_iteration_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
335 struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
336 GNUNET_SENSOR_SensorIteratorCB cb;
339 ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
341 cb_cls = ic->callback_cls;
342 GNUNET_SENSOR_iterate_sensor_cancel (ic);
345 _("Timeout transmitting iteration request to `SENSOR' service."));
349 * Type of a function to call when we receive a message from the
350 * service. Call the iterator with the result and (if applicable)
351 * continue to receive more messages or trigger processing the next
352 * event (if applicable).
355 * @param msg message received, NULL on timeout or fatal error
358 sensor_handler(void *cls, const struct GNUNET_MessageHeader *msg)
360 struct GNUNET_SENSOR_Handle *h = cls;
361 struct GNUNET_SENSOR_SensorIteratorContext *ic = h->ic_head;
362 GNUNET_SENSOR_SensorIteratorCB cb;
365 const struct SensorInfoMessage *im;
366 struct SensorInfoShort *sensor;
371 h->in_receive = GNUNET_NO;
374 /* sensor service died, signal error */
378 cb_cls = ic->callback_cls;
379 GNUNET_SENSOR_iterate_sensor_cancel(ic);
388 _("Failed to receive response from `SENSOR' service."));
393 /* didn't expect a response, reconnect */
397 ic->request_transmitted = GNUNET_NO;
399 cb_cls = ic->callback_cls;
400 if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (msg->type))
402 /* normal end of list of sensors, signal end, process next pending request */
403 LOG (GNUNET_ERROR_TYPE_DEBUG,
404 "Received end of list of sensors from `%s' service\n", "SENSOR");
405 GNUNET_SENSOR_iterate_sensor_cancel(ic);
406 trigger_transmit (h);
407 if ( (GNUNET_NO == h->in_receive) &&
408 (NULL != h->ic_head) )
410 h->in_receive = GNUNET_YES;
411 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
412 GNUNET_TIME_absolute_get_remaining (h->ic_head->timeout));
415 cb (cb_cls, NULL, NULL);
418 ms = ntohs (msg->size);
419 im = (const struct SensorInfoMessage *) msg;
420 name_len = ntohs(im->name_len);
421 desc_len = ntohs(im->description_len);
422 if ((ms != sizeof (struct SensorInfoMessage) + name_len + desc_len) ||
423 (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_SENSOR_INFO))
425 /* malformed message */
427 GNUNET_SENSOR_iterate_sensor_cancel(ic);
431 _("Received invalid message from `SENSOR' service."));
434 sensor = GNUNET_new(struct SensorInfoShort);
435 str_ptr = (char *)&im[1];
436 sensor->name = GNUNET_strndup(str_ptr, name_len);
437 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor name (%d): %.*s\n",
438 name_len, name_len, str_ptr);
442 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor description (%d): %.*s\n",
443 desc_len, desc_len, str_ptr);
444 sensor->description = GNUNET_strndup(str_ptr, desc_len);
446 sensor->version_major = ntohs(im->version_major);
447 sensor->version_minor = ntohs(im->version_minor);
448 h->in_receive = GNUNET_YES;
449 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
450 GNUNET_TIME_absolute_get_remaining (ic->timeout));
452 cb (cb_cls, sensor, NULL);
456 * We've transmitted the iteration request. Now get ready to process
457 * the results (or handle transmission error).
459 * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext'
460 * @param emsg error message, NULL if transmission worked
463 sensor_iterator_start_receive (void *cls, const char *emsg)
465 struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
466 struct GNUNET_SENSOR_Handle *h = ic->h;
467 GNUNET_SENSOR_SensorIteratorCB cb;
474 cb_cls = ic->callback_cls;
475 GNUNET_SENSOR_iterate_sensor_cancel (ic);
478 cb (cb_cls, NULL, emsg);
481 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
483 ic->request_transmitted = GNUNET_YES;
484 if (GNUNET_NO == h->in_receive)
486 h->in_receive = GNUNET_YES;
487 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
488 GNUNET_TIME_absolute_get_remaining (ic->timeout));
493 * Transmit the request at the head of the transmission queue
494 * and trigger continuation (if any).
496 * @param cls the 'struct GNUNET_SENSOR_Handle' (with the queue)
497 * @param size size of the buffer (0 on error)
498 * @param buf where to copy the message
499 * @return number of bytes copied to buf
502 do_transmit (void *cls, size_t size, void *buf)
504 struct GNUNET_SENSOR_Handle *h = cls;
505 struct GNUNET_SENSOR_RequestContext *rc = h->rc_head;
510 return 0; /* request was cancelled in the meantime */
513 /* sensor service died */
514 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
515 "Failed to transmit message to `%s' service.\n", "SENSOR");
516 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
518 if (NULL != rc->cont)
519 rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
526 /* change in head of queue (i.e. cancel + add), try again */
527 trigger_transmit (h);
530 LOG (GNUNET_ERROR_TYPE_DEBUG,
531 "Transmitting request of size %u to `%s' service.\n", ret, "SENSOR");
532 memcpy (buf, &rc[1], ret);
533 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
534 trigger_transmit (h);
535 if (NULL != rc->cont)
536 rc->cont (rc->cont_cls, NULL);
542 * Check if we have a request pending in the transmission queue and are
543 * able to transmit it right now. If so, schedule transmission.
545 * @param h handle to the service
548 trigger_transmit (struct GNUNET_SENSOR_Handle *h)
550 struct GNUNET_SENSOR_RequestContext *rc;
552 if (NULL == (rc = h->rc_head))
553 return; /* no requests queued */
555 return; /* request already pending */
556 if (NULL == h->client)
558 /* disconnected, try to reconnect */
563 GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
564 GNUNET_TIME_UNIT_FOREVER_REL,
570 * Client asking to iterate all available sensors
572 * @param h Handle to SENSOR service
573 * @param timeout how long to wait until timing out
574 * @param sensorname information on one sensor only, can be NULL to get all
575 * @param sensorname_len length of the sensorname parameter
576 * @param callback the method to call for each sensor
577 * @param callback_cls closure for callback
578 * @return iterator context
580 struct GNUNET_SENSOR_SensorIteratorContext *
581 GNUNET_SENSOR_iterate_sensors (struct GNUNET_SENSOR_Handle *h,
582 struct GNUNET_TIME_Relative timeout,
583 const char* sensorname, size_t sensorname_len,
584 GNUNET_SENSOR_SensorIteratorCB callback, void *callback_cls)
586 struct GNUNET_SENSOR_SensorIteratorContext *ic;
587 struct GNUNET_SENSOR_RequestContext *rc;
588 struct GNUNET_MessageHeader *mh;
590 ic = GNUNET_new (struct GNUNET_SENSOR_SensorIteratorContext);
591 if (NULL == sensorname)
593 LOG (GNUNET_ERROR_TYPE_INFO,
594 "Requesting list of sensors from SENSOR service\n");
596 GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
597 sizeof (struct GNUNET_MessageHeader));
598 rc->size = sizeof (struct GNUNET_MessageHeader);
599 mh = (struct GNUNET_MessageHeader *) &rc[1];
600 mh->size = htons(sizeof (struct GNUNET_MessageHeader));
601 mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
605 LOG (GNUNET_ERROR_TYPE_INFO,
606 "Requesting information on sensor `%s' from SENSOR service\n",
609 GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
610 sizeof (struct GNUNET_MessageHeader) +
612 rc->size = sizeof (struct GNUNET_MessageHeader) + sensorname_len;
613 mh = (struct GNUNET_MessageHeader *) &rc[1];
614 mh->size = htons(rc->size);
615 mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GET);
616 memcpy(&mh[1], sensorname, sensorname_len);
620 ic->callback = callback;
621 ic->callback_cls = callback_cls;
622 ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
624 GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout, ic);
625 rc->cont = &sensor_iterator_start_receive;
627 GNUNET_CONTAINER_DLL_insert_tail (h->rc_head, h->rc_tail, rc);
628 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
631 trigger_transmit (h);
635 /* end of sensor_api.c */