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);
195 * Check if we have a request pending in the transmission queue and are
196 * able to transmit it right now. If so, schedule transmission.
198 * @param h handle to the service
201 trigger_transmit (struct GNUNET_SENSOR_Handle *h);
203 /******************************************************************************/
204 /******************* CONNECTION FUNCTIONS *********************/
205 /******************************************************************************/
208 * Connect to the sensor service.
210 * @return NULL on error
212 struct GNUNET_SENSOR_Handle *
213 GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
215 struct GNUNET_CLIENT_Connection *client;
216 struct GNUNET_SENSOR_Handle *h;
218 client = GNUNET_CLIENT_connect ("sensor", cfg);
221 h = GNUNET_new (struct GNUNET_SENSOR_Handle);
229 * Disconnect from the sensor service
231 * @param h handle to disconnect
234 GNUNET_SENSOR_disconnect (struct GNUNET_SENSOR_Handle *h)
236 if (NULL != h->client)
238 GNUNET_CLIENT_disconnect (h->client);
246 * Task scheduled to re-try connecting to the sensor service.
248 * @param cls the 'struct GNUNET_SENSOR_Handle'
249 * @param tc scheduler context
252 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
254 struct GNUNET_SENSOR_Handle *h = cls;
256 h->r_task = GNUNET_SCHEDULER_NO_TASK;
262 * Close the existing connection to SENSOR and reconnect.
264 * @param h handle to the service
267 reconnect (struct GNUNET_SENSOR_Handle *h)
269 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
271 GNUNET_SCHEDULER_cancel (h->r_task);
272 h->r_task = GNUNET_SCHEDULER_NO_TASK;
276 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
279 if (NULL != h->client)
281 GNUNET_CLIENT_disconnect (h->client);
284 h->in_receive = GNUNET_NO;
285 h->client = GNUNET_CLIENT_connect ("sensor", h->cfg);
286 if (NULL == h->client)
289 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
293 trigger_transmit (h);
296 /******************************************************************************/
297 /****************** SENSOR DATA FUNCTIONS *********************/
298 /******************************************************************************/
301 * Cancel an iteration over sensor information.
303 * @param ic context of the iterator to cancel
306 GNUNET_SENSOR_iterate_sensor_cancel (struct GNUNET_SENSOR_SensorIteratorContext
309 struct GNUNET_SENSOR_Handle *h;
312 if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task)
314 GNUNET_SCHEDULER_cancel (ic->timeout_task);
315 ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
318 if (GNUNET_YES == ic->request_transmitted)
319 return; /* need to finish processing */
320 GNUNET_CONTAINER_DLL_remove (h->ic_head, h->ic_tail, ic);
323 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, ic->rc);
324 GNUNET_free (ic->rc);
331 * Iteration request has timed out.
333 * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*'
334 * @param tc scheduler context
337 signal_sensor_iteration_timeout (void *cls,
338 const struct GNUNET_SCHEDULER_TaskContext *tc)
340 struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
341 GNUNET_SENSOR_SensorIteratorCB cb;
344 ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
346 cb_cls = ic->callback_cls;
347 GNUNET_SENSOR_iterate_sensor_cancel (ic);
350 _("Timeout transmitting iteration request to `SENSOR' service."));
355 * Type of a function to call when we receive a message from the
356 * service. Call the iterator with the result and (if applicable)
357 * continue to receive more messages or trigger processing the next
358 * event (if applicable).
361 * @param msg message received, NULL on timeout or fatal error
364 sensor_handler (void *cls, const struct GNUNET_MessageHeader *msg)
366 struct GNUNET_SENSOR_Handle *h = cls;
367 struct GNUNET_SENSOR_SensorIteratorContext *ic = h->ic_head;
368 GNUNET_SENSOR_SensorIteratorCB cb;
371 const struct SensorInfoMessage *im;
372 struct SensorInfoShort *sensor;
377 h->in_receive = GNUNET_NO;
380 /* sensor service died, signal error */
384 cb_cls = ic->callback_cls;
385 GNUNET_SENSOR_iterate_sensor_cancel (ic);
393 cb (cb_cls, NULL, _("Failed to receive response from `SENSOR' service."));
398 /* didn't expect a response, reconnect */
402 ic->request_transmitted = GNUNET_NO;
404 cb_cls = ic->callback_cls;
405 if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (msg->type))
407 /* normal end of list of sensors, signal end, process next pending request */
408 LOG (GNUNET_ERROR_TYPE_DEBUG,
409 "Received end of list of sensors from `%s' service\n", "SENSOR");
410 GNUNET_SENSOR_iterate_sensor_cancel (ic);
411 trigger_transmit (h);
412 if ((GNUNET_NO == h->in_receive) && (NULL != h->ic_head))
414 h->in_receive = GNUNET_YES;
415 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
416 GNUNET_TIME_absolute_get_remaining (h->
420 cb (cb_cls, NULL, NULL);
423 ms = ntohs (msg->size);
424 im = (const struct SensorInfoMessage *) msg;
425 name_len = ntohs (im->name_len);
426 desc_len = ntohs (im->description_len);
427 if ((ms != sizeof (struct SensorInfoMessage) + name_len + desc_len) ||
428 (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_SENSOR_INFO))
430 /* malformed message */
432 GNUNET_SENSOR_iterate_sensor_cancel (ic);
435 cb (cb_cls, NULL, _("Received invalid message from `SENSOR' service."));
438 sensor = GNUNET_new (struct SensorInfoShort);
439 str_ptr = (char *) &im[1];
440 sensor->name = GNUNET_strndup (str_ptr, name_len);
441 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor name (%d): %.*s\n", name_len,
446 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor description (%d): %.*s\n",
447 desc_len, desc_len, str_ptr);
448 sensor->description = GNUNET_strndup (str_ptr, desc_len);
450 sensor->version_major = ntohs (im->version_major);
451 sensor->version_minor = ntohs (im->version_minor);
452 h->in_receive = GNUNET_YES;
453 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
454 GNUNET_TIME_absolute_get_remaining (ic->timeout));
456 cb (cb_cls, sensor, NULL);
461 * We've transmitted the iteration request. Now get ready to process
462 * the results (or handle transmission error).
464 * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext'
465 * @param emsg error message, NULL if transmission worked
468 sensor_iterator_start_receive (void *cls, const char *emsg)
470 struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
471 struct GNUNET_SENSOR_Handle *h = ic->h;
472 GNUNET_SENSOR_SensorIteratorCB cb;
479 cb_cls = ic->callback_cls;
480 GNUNET_SENSOR_iterate_sensor_cancel (ic);
483 cb (cb_cls, NULL, emsg);
486 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
488 ic->request_transmitted = GNUNET_YES;
489 if (GNUNET_NO == h->in_receive)
491 h->in_receive = GNUNET_YES;
492 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
493 GNUNET_TIME_absolute_get_remaining (ic->timeout));
499 * Transmit the request at the head of the transmission queue
500 * and trigger continuation (if any).
502 * @param cls the 'struct GNUNET_SENSOR_Handle' (with the queue)
503 * @param size size of the buffer (0 on error)
504 * @param buf where to copy the message
505 * @return number of bytes copied to buf
508 do_transmit (void *cls, size_t size, void *buf)
510 struct GNUNET_SENSOR_Handle *h = cls;
511 struct GNUNET_SENSOR_RequestContext *rc = h->rc_head;
516 return 0; /* request was cancelled in the meantime */
519 /* sensor service died */
520 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
521 "Failed to transmit message to `%s' service.\n", "SENSOR");
522 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
524 if (NULL != rc->cont)
525 rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
532 /* change in head of queue (i.e. cancel + add), try again */
533 trigger_transmit (h);
536 LOG (GNUNET_ERROR_TYPE_DEBUG,
537 "Transmitting request of size %u to `%s' service.\n", ret, "SENSOR");
538 memcpy (buf, &rc[1], ret);
539 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
540 trigger_transmit (h);
541 if (NULL != rc->cont)
542 rc->cont (rc->cont_cls, NULL);
549 * Check if we have a request pending in the transmission queue and are
550 * able to transmit it right now. If so, schedule transmission.
552 * @param h handle to the service
555 trigger_transmit (struct GNUNET_SENSOR_Handle *h)
557 struct GNUNET_SENSOR_RequestContext *rc;
559 if (NULL == (rc = h->rc_head))
560 return; /* no requests queued */
562 return; /* request already pending */
563 if (NULL == h->client)
565 /* disconnected, try to reconnect */
570 GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
571 GNUNET_TIME_UNIT_FOREVER_REL,
572 GNUNET_YES, &do_transmit, h);
577 * Client asking to iterate all available sensors
579 * @param h Handle to SENSOR service
580 * @param timeout how long to wait until timing out
581 * @param sensorname information on one sensor only, can be NULL to get all
582 * @param sensorname_len length of the sensorname parameter
583 * @param callback the method to call for each sensor
584 * @param callback_cls closure for callback
585 * @return iterator context
587 struct GNUNET_SENSOR_SensorIteratorContext *
588 GNUNET_SENSOR_iterate_sensors (struct GNUNET_SENSOR_Handle *h,
589 struct GNUNET_TIME_Relative timeout,
590 const char *sensorname, size_t sensorname_len,
591 GNUNET_SENSOR_SensorIteratorCB callback,
594 struct GNUNET_SENSOR_SensorIteratorContext *ic;
595 struct GNUNET_SENSOR_RequestContext *rc;
596 struct GNUNET_MessageHeader *mh;
598 ic = GNUNET_new (struct GNUNET_SENSOR_SensorIteratorContext);
600 if (NULL == sensorname)
602 LOG (GNUNET_ERROR_TYPE_INFO,
603 "Requesting list of sensors from SENSOR service\n");
604 rc = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
605 sizeof (struct GNUNET_MessageHeader));
606 rc->size = sizeof (struct GNUNET_MessageHeader);
607 mh = (struct GNUNET_MessageHeader *) &rc[1];
608 mh->size = htons (sizeof (struct GNUNET_MessageHeader));
609 mh->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
613 LOG (GNUNET_ERROR_TYPE_INFO,
614 "Requesting information on sensor `%s' from SENSOR service\n",
616 rc = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
617 sizeof (struct GNUNET_MessageHeader) + sensorname_len);
618 rc->size = sizeof (struct GNUNET_MessageHeader) + sensorname_len;
619 mh = (struct GNUNET_MessageHeader *) &rc[1];
620 mh->size = htons (rc->size);
621 mh->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_GET);
622 memcpy (&mh[1], sensorname, sensorname_len);
626 ic->callback = callback;
627 ic->callback_cls = callback_cls;
628 ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
630 GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout,
632 rc->cont = &sensor_iterator_start_receive;
634 GNUNET_CONTAINER_DLL_insert_tail (h->rc_head, h->rc_tail, rc);
635 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, h->ic_tail, ic);
636 trigger_transmit (h);
640 /* end of sensor_api.c */