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_INFO,
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 sensor->name = GNUNET_strndup((char *)&im[1], name_len);
437 sensor->description = GNUNET_strndup((char *)((&im[1]) + name_len), desc_len);
438 sensor->version_major = ntohs(im->version_major);
439 sensor->version_minor = ntohs(im->version_minor);
440 h->in_receive = GNUNET_YES;
441 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
442 GNUNET_TIME_absolute_get_remaining (ic->timeout));
444 cb (cb_cls, sensor, NULL);
448 * We've transmitted the iteration request. Now get ready to process
449 * the results (or handle transmission error).
451 * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext'
452 * @param emsg error message, NULL if transmission worked
455 sensor_iterator_start_receive (void *cls, const char *emsg)
457 struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
458 struct GNUNET_SENSOR_Handle *h = ic->h;
459 GNUNET_SENSOR_SensorIteratorCB cb;
466 cb_cls = ic->callback_cls;
467 GNUNET_SENSOR_iterate_sensor_cancel (ic);
470 cb (cb_cls, NULL, emsg);
473 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
475 ic->request_transmitted = GNUNET_YES;
476 if (GNUNET_NO == h->in_receive)
478 h->in_receive = GNUNET_YES;
479 GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
480 GNUNET_TIME_absolute_get_remaining (ic->timeout));
485 * Transmit the request at the head of the transmission queue
486 * and trigger continuation (if any).
488 * @param cls the 'struct GNUNET_SENSOR_Handle' (with the queue)
489 * @param size size of the buffer (0 on error)
490 * @param buf where to copy the message
491 * @return number of bytes copied to buf
494 do_transmit (void *cls, size_t size, void *buf)
496 struct GNUNET_SENSOR_Handle *h = cls;
497 struct GNUNET_SENSOR_RequestContext *rc = h->rc_head;
502 return 0; /* request was cancelled in the meantime */
505 /* sensor service died */
506 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
507 "Failed to transmit message to `%s' service.\n", "SENSOR");
508 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
510 if (NULL != rc->cont)
511 rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
518 /* change in head of queue (i.e. cancel + add), try again */
519 trigger_transmit (h);
522 LOG (GNUNET_ERROR_TYPE_DEBUG,
523 "Transmitting request of size %u to `%s' service.\n", ret, "SENSOR");
524 memcpy (buf, &rc[1], ret);
525 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
526 trigger_transmit (h);
527 if (NULL != rc->cont)
528 rc->cont (rc->cont_cls, NULL);
534 * Check if we have a request pending in the transmission queue and are
535 * able to transmit it right now. If so, schedule transmission.
537 * @param h handle to the service
540 trigger_transmit (struct GNUNET_SENSOR_Handle *h)
542 struct GNUNET_SENSOR_RequestContext *rc;
544 if (NULL == (rc = h->rc_head))
545 return; /* no requests queued */
547 return; /* request already pending */
548 if (NULL == h->client)
550 /* disconnected, try to reconnect */
555 GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
556 GNUNET_TIME_UNIT_FOREVER_REL,
562 * Client asking to iterate all available sensors
564 * @param h Handle to SENSOR service
565 * @param timeout how long to wait until timing out
566 * @param sensorname information on one sensor only, can be NULL to get all
567 * @param sensorname_len length of the sensorname parameter
568 * @param callback the method to call for each sensor
569 * @param callback_cls closure for callback
570 * @return iterator context
572 struct GNUNET_SENSOR_SensorIteratorContext *
573 GNUNET_SENSOR_iterate_sensors (struct GNUNET_SENSOR_Handle *h,
574 struct GNUNET_TIME_Relative timeout,
575 const char* sensorname, size_t sensorname_len,
576 GNUNET_SENSOR_SensorIteratorCB callback, void *callback_cls)
578 struct GNUNET_SENSOR_SensorIteratorContext *ic;
579 struct GNUNET_SENSOR_RequestContext *rc;
580 struct GNUNET_MessageHeader *mh;
582 ic = GNUNET_new (struct GNUNET_SENSOR_SensorIteratorContext);
583 if (NULL == sensorname)
585 LOG (GNUNET_ERROR_TYPE_INFO,
586 "Requesting list of sensors from SENSOR service\n");
588 GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
589 sizeof (struct GNUNET_MessageHeader));
590 rc->size = sizeof (struct GNUNET_MessageHeader);
591 mh = (struct GNUNET_MessageHeader *) &rc[1];
592 mh->size = htons(sizeof (struct GNUNET_MessageHeader));
593 mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
597 LOG (GNUNET_ERROR_TYPE_INFO,
598 "Requesting information on sensor `%s' from SENSOR service\n",
601 GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
602 sizeof (struct GNUNET_MessageHeader) +
604 rc->size = sizeof (struct GNUNET_MessageHeader) + sensorname_len;
605 mh = (struct GNUNET_MessageHeader *) &rc[1];
606 mh->size = htons(rc->size);
607 mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GET);
608 memcpy(&mh[1], sensorname, sensorname_len);
612 ic->callback = callback;
613 ic->callback_cls = callback_cls;
614 ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
616 GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout, ic);
617 rc->cont = &sensor_iterator_start_receive;
619 GNUNET_CONTAINER_DLL_insert_tail (h->rc_head, h->rc_tail, rc);
620 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
623 trigger_transmit (h);
627 /* end of sensor_api.c */