sensor: minor fixes
[oweals/gnunet.git] / src / sensordashboard / gnunet-service-sensordashboard.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 sensordashboard/gnunet-service-sensordashboard.c
23  * @brief Service collecting sensor readings from peers
24  * @author Omar Tarabai
25  */
26 #include <inttypes.h>
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_applications.h"
30 #include "sensordashboard.h"
31 #include "gnunet_cadet_service.h"
32 #include "gnunet_sensor_util_lib.h"
33 #include "gnunet_peerstore_service.h"
34
35
36 /**
37  * Context of a connected client peer
38  */
39 struct ClientPeerContext
40 {
41
42   /**
43    * DLL
44    */
45   struct ClientPeerContext *prev;
46
47   /*
48    * DLL
49    */
50   struct ClientPeerContext *next;
51
52   /**
53    * GNUnet Peer identity
54    */
55   struct GNUNET_PeerIdentity peerid;
56
57   /**
58    * Handle to the cadet channel
59    */
60   struct GNUNET_CADET_Channel *ch;
61
62   /**
63    * Are we in the process of destroying this context?
64    */
65   int destroying;
66
67 };
68
69
70 /**
71  * Handle to CADET service
72  */
73 static struct GNUNET_CADET_Handle *cadet;
74
75 /**
76  * Global hashmap of defined sensors
77  */
78 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
79
80 /**
81  * Handle to the peerstore service connection
82  */
83 static struct GNUNET_PEERSTORE_Handle *peerstore;
84
85 /**
86  * Name of this subsystem to be used for peerstore operations
87  */
88 static char *subsystem = "sensordashboard";
89
90 /**
91  * Head of a DLL of all connected client peers
92  */
93 static struct ClientPeerContext *cp_head;
94
95 /**
96  * Tail of a DLL of all connected client peers
97  */
98 static struct ClientPeerContext *cp_tail;
99
100
101 /**
102  * Destroy a given client peer context
103  *
104  * @param cp client peer context
105  */
106 static void
107 destroy_clientpeer (struct ClientPeerContext *cp)
108 {
109   cp->destroying = GNUNET_YES;
110   if (NULL != cp->ch)
111   {
112     GNUNET_CADET_channel_destroy (cp->ch);
113     cp->ch = NULL;
114   }
115   GNUNET_free (cp);
116 }
117
118
119 /**
120  * Task run during shutdown.
121  *
122  * @param cls unused
123  * @param tc unused
124  */
125 static void
126 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
127 {
128   struct ClientPeerContext *cp;
129
130   cp = cp_head;
131   while (NULL != cp)
132   {
133     GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
134     destroy_clientpeer (cp);
135     cp = cp_head;
136   }
137   if (NULL != cadet)
138   {
139     GNUNET_CADET_disconnect (cadet);
140     cadet = NULL;
141   }
142   if (NULL != peerstore)
143   {
144     GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
145     peerstore = NULL;
146   }
147   GNUNET_SENSOR_destroy_sensors (sensors);
148   GNUNET_SCHEDULER_shutdown ();
149 }
150
151
152 /**
153  * Function called whenever a channel is destroyed.  Should clean up
154  * any associated state.
155  *
156  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
157  *
158  * @param cls closure (set from #GNUNET_CADET_connect)
159  * @param channel connection to the other end (henceforth invalid)
160  * @param channel_ctx place where local state associated
161  *                   with the channel is stored
162  */
163 static void
164 cadet_channel_destroyed (void *cls,
165                          const struct GNUNET_CADET_Channel *channel,
166                          void *channel_ctx)
167 {
168   struct ClientPeerContext *cp = channel_ctx;
169
170   if (GNUNET_YES == cp->destroying)
171     return;
172   cp->ch = NULL;
173   GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
174   destroy_clientpeer (cp);
175 }
176
177
178 /**
179  * Method called whenever another peer has added us to a channel
180  * the other peer initiated.
181  * Only called (once) upon reception of data with a message type which was
182  * subscribed to in #GNUNET_CADET_connect.
183  *
184  * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored. In
185  * this case the handler MUST return NULL.
186  *
187  * @param cls closure
188  * @param channel new handle to the channel
189  * @param initiator peer that started the channel
190  * @param port Port this channel is for.
191  * @param options CadetOption flag field, with all active option bits set to 1.
192  *
193  * @return initial channel context for the channel
194  *         (can be NULL -- that's not an error)
195  */
196 static void *
197 cadet_channel_created (void *cls,
198                        struct GNUNET_CADET_Channel *channel,
199                        const struct GNUNET_PeerIdentity *initiator,
200                        uint32_t port, enum GNUNET_CADET_ChannelOption options)
201 {
202   struct ClientPeerContext *cp;
203
204   cp = GNUNET_new (struct ClientPeerContext);
205   cp->peerid = *initiator;
206   cp->ch = channel;
207   cp->destroying = GNUNET_NO;
208   GNUNET_CONTAINER_DLL_insert (cp_head, cp_tail, cp);
209   return cp;
210 }
211
212
213 /**
214  * Parses a sensor reading message struct
215  *
216  * @param msg message header received
217  * @param sensors multihashmap of loaded sensors
218  * @return sensor reading struct or NULL if error
219  */
220 static struct GNUNET_SENSOR_Reading *
221 parse_reading_message (const struct GNUNET_MessageHeader *msg,
222                        struct GNUNET_CONTAINER_MultiHashMap *sensors)
223 {
224   uint16_t msg_size;
225   struct GNUNET_SENSOR_ReadingMessage *rm;
226   uint16_t sensorname_size;
227   uint16_t value_size;
228   void *dummy;
229   char *sensorname;
230   struct GNUNET_HashCode key;
231   struct GNUNET_SENSOR_SensorInfo *sensor;
232   struct GNUNET_SENSOR_Reading *reading;
233
234   msg_size = ntohs (msg->size);
235   if (msg_size < sizeof (struct GNUNET_SENSOR_ReadingMessage))
236   {
237     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid reading message size.\n");
238     return NULL;
239   }
240   rm = (struct GNUNET_SENSOR_ReadingMessage *)msg;
241   sensorname_size = ntohs (rm->sensorname_size);
242   value_size = ntohs (rm->value_size);
243   if ((sizeof (struct GNUNET_SENSOR_ReadingMessage)
244       + sensorname_size + value_size) != msg_size)
245   {
246     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid reading message size.\n");
247     return NULL;
248   }
249   dummy = &rm[1];
250   sensorname = GNUNET_malloc (sensorname_size);
251   memcpy (sensorname, dummy, sensorname_size);
252   GNUNET_CRYPTO_hash(sensorname, sensorname_size, &key);
253   GNUNET_free (sensorname);
254   sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &key);
255   if (NULL == sensor)
256   {
257     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
258         "Unknown sensor name in reading message.\n");
259     return NULL;
260   }
261   if ((sensor->version_minor != ntohs (rm->sensorversion_minor)) ||
262       (sensor->version_major != ntohs (rm->sensorversion_major)))
263   {
264     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
265                 "Sensor version mismatch in reading message.\n");
266     return NULL;
267   }
268   if (0 == strcmp (sensor->expected_datatype, "numeric") &&
269       sizeof (double) != value_size)
270   {
271     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
272                 "Invalid value size for a numerical sensor.\n");
273     return NULL;
274   }
275   reading = GNUNET_new (struct GNUNET_SENSOR_Reading);
276   reading->sensor = sensor;
277   reading->timestamp = GNUNET_be64toh (rm->timestamp);
278   reading->value_size = value_size;
279   reading->value = GNUNET_malloc (value_size);
280   dummy += sensorname_size;
281   memcpy (reading->value, dummy, value_size);
282   return reading;
283 }
284
285
286 /**
287  * Called with any sensor reading messages received from CADET.
288  *
289  * Each time the function must call #GNUNET_CADET_receive_done on the channel
290  * in order to receive the next message. This doesn't need to be immediate:
291  * can be delayed if some processing is done on the message.
292  *
293  * @param cls Closure (set from #GNUNET_CADET_connect).
294  * @param channel Connection to the other end.
295  * @param channel_ctx Place to store local state associated with the channel.
296  * @param message The actual message.
297  * @return #GNUNET_OK to keep the channel open,
298  *         #GNUNET_SYSERR to close it (signal serious error).
299  */
300 static int
301 handle_sensor_reading (void *cls,
302                        struct GNUNET_CADET_Channel *channel,
303                        void **channel_ctx,
304                        const struct GNUNET_MessageHeader *message)
305 {
306   struct ClientPeerContext *cp = *channel_ctx;
307   struct GNUNET_SENSOR_Reading *reading;
308
309   reading = parse_reading_message (message, sensors);
310   if (NULL == reading)
311   {
312     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
313                 "Received an invalid sensor reading from peer `%s'\n",
314                 GNUNET_i2s (&cp->peerid));
315     return GNUNET_SYSERR;
316   }
317   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
318               "Received a sensor reading from peer `%s':\n"
319               "# Sensor name: `%s'\n"
320               "# Timestamp: %" PRIu64 "\n"
321               "# Value size: %" PRIu64 ".\n",
322               GNUNET_i2s (&cp->peerid),
323               reading->sensor->name,
324               reading->timestamp,
325               reading->value_size);
326   GNUNET_PEERSTORE_store (peerstore, subsystem, &cp->peerid,
327                           reading->sensor->name, reading->value,
328                           reading->value_size, GNUNET_TIME_UNIT_FOREVER_ABS,
329                           GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
330   GNUNET_free (reading->value);
331   GNUNET_free (reading);
332   GNUNET_CADET_receive_done (channel);
333   return GNUNET_OK;
334 }
335
336
337 /**
338  * Called with any sensor list request received.
339  *
340  * Each time the function must call #GNUNET_CADET_receive_done on the channel
341  * in order to receive the next message. This doesn't need to be immediate:
342  * can be delayed if some processing is done on the message.
343  *
344  * @param cls Closure (set from #GNUNET_CADET_connect).
345  * @param channel Connection to the other end.
346  * @param channel_ctx Place to store local state associated with the channel.
347  * @param message The actual message.
348  * @return #GNUNET_OK to keep the channel open,
349  *         #GNUNET_SYSERR to close it (signal serious error).
350  */
351 static int
352 handle_sensor_list_req (void *cls,
353                         struct GNUNET_CADET_Channel *channel,
354                         void **channel_ctx,
355                         const struct GNUNET_MessageHeader *message)
356 {
357   //TODO
358   GNUNET_CADET_receive_done (channel);
359   return GNUNET_OK;
360 }
361
362
363 /**
364  * Process sensordashboard requests.
365  *
366  * @param cls closure
367  * @param server the initialized server
368  * @param cfg configuration to use
369  */
370 static void
371 run (void *cls, struct GNUNET_SERVER_Handle *server,
372      const struct GNUNET_CONFIGURATION_Handle *cfg)
373 {
374   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
375       {NULL, NULL, 0, 0}
376   };
377   static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
378       {&handle_sensor_reading,
379        GNUNET_MESSAGE_TYPE_SENSOR_READING, 0},
380       {&handle_sensor_list_req,
381        GNUNET_MESSAGE_TYPE_SENSOR_LIST_REQ,
382        sizeof (struct GNUNET_MessageHeader)},
383       {NULL, 0, 0}
384   };
385   static uint32_t cadet_ports[] = {
386       GNUNET_APPLICATION_TYPE_SENSORDASHBOARD,
387       GNUNET_APPLICATION_TYPE_SENSORUPDATE,
388       GNUNET_APPLICATION_TYPE_END
389   };
390   sensors = GNUNET_SENSOR_load_all_sensors ();
391   GNUNET_assert (NULL != sensors);
392   cadet = GNUNET_CADET_connect(cfg,
393                                NULL,
394                                &cadet_channel_created,
395                                &cadet_channel_destroyed,
396                                cadet_handlers,
397                                cadet_ports);
398   if (NULL == cadet)
399   {
400     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
401                 _("Failed to connect to `%s' service.\n"), "CADET");
402     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
403     return;
404   }
405   peerstore = GNUNET_PEERSTORE_connect (cfg);
406   if (NULL == peerstore)
407   {
408     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
409                 _("Failed to connect to `%s' service.\n"), "PEERSTORE");
410     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
411     return;
412   }
413   GNUNET_SERVER_add_handlers (server, handlers);
414   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
415                                 NULL);
416 }
417
418
419 /**
420  * The main function for the sensordashboard service.
421  *
422  * @param argc number of arguments from the command line
423  * @param argv command line arguments
424  * @return 0 ok, 1 on error
425  */
426 int
427 main (int argc, char *const *argv)
428 {
429   return (GNUNET_OK ==
430           GNUNET_SERVICE_run (argc, argv, "sensordashboard",
431                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
432 }
433
434 /* end of gnunet-service-sensordashboard.c */