sensor: towards update functionality
[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
64
65 /**
66  * Handle to CADET service
67  */
68 static struct GNUNET_CADET_Handle *cadet;
69
70 /**
71  * Global hashmap of defined sensors
72  */
73 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
74
75 /**
76  * Handle to the peerstore service connection
77  */
78 static struct GNUNET_PEERSTORE_Handle *peerstore;
79
80 /**
81  * Name of this subsystem to be used for peerstore operations
82  */
83 static char *subsystem = "sensordashboard";
84
85 /**
86  * Head of a DLL of all connected client peers
87  */
88 static struct ClientPeerContext *cp_head;
89
90 /**
91  * Tail of a DLL of all connected client peers
92  */
93 static struct ClientPeerContext *cp_tail;
94
95
96 /**
97  * Destroy a given client peer context
98  *
99  * @param cp client peer context
100  */
101 static void
102 destroy_clientpeer (struct ClientPeerContext *cp)
103 {
104   if (NULL != cp->ch)
105   {
106     GNUNET_CADET_channel_destroy (cp->ch);
107     cp->ch = NULL;
108   }
109   GNUNET_free (cp);
110 }
111
112 /**
113  * Task run during shutdown.
114  *
115  * @param cls unused
116  * @param tc unused
117  */
118 static void
119 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
120 {
121   struct ClientPeerContext *cp;
122
123   cp = cp_head;
124   while (NULL != cp)
125   {
126     GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
127     destroy_clientpeer (cp);
128     cp = cp_head;
129   }
130   if (NULL != cadet)
131   {
132     GNUNET_CADET_disconnect (cadet);
133     cadet = NULL;
134   }
135   if (NULL != peerstore)
136   {
137     GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
138     peerstore = NULL;
139   }
140   GNUNET_SENSOR_destroy_sensors (sensors);
141   GNUNET_SCHEDULER_shutdown();
142 }
143
144 /**
145  * Function called whenever a channel is destroyed.  Should clean up
146  * any associated state.
147  *
148  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
149  *
150  * @param cls closure (set from #GNUNET_CADET_connect)
151  * @param channel connection to the other end (henceforth invalid)
152  * @param channel_ctx place where local state associated
153  *                   with the channel is stored
154  */
155 static void
156 cadet_channel_destroyed (void *cls,
157                          const struct GNUNET_CADET_Channel *channel,
158                          void *channel_ctx)
159 {
160   struct ClientPeerContext *cp = channel_ctx;
161
162   cp->ch = NULL;
163   GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
164   destroy_clientpeer (cp);
165 }
166
167 /**
168  * Method called whenever another peer has added us to a channel
169  * the other peer initiated.
170  * Only called (once) upon reception of data with a message type which was
171  * subscribed to in #GNUNET_CADET_connect.
172  *
173  * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored. In
174  * this case the handler MUST return NULL.
175  *
176  * @param cls closure
177  * @param channel new handle to the channel
178  * @param initiator peer that started the channel
179  * @param port Port this channel is for.
180  * @param options CadetOption flag field, with all active option bits set to 1.
181  *
182  * @return initial channel context for the channel
183  *         (can be NULL -- that's not an error)
184  */
185 static void *
186 cadet_channel_created (void *cls,
187                        struct GNUNET_CADET_Channel *channel,
188                        const struct GNUNET_PeerIdentity *initiator,
189                        uint32_t port, enum GNUNET_CADET_ChannelOption options)
190 {
191   struct ClientPeerContext *cp;
192
193   cp = GNUNET_new (struct ClientPeerContext);
194   cp->peerid = *initiator;
195   cp->ch = channel;
196   GNUNET_CONTAINER_DLL_insert (cp_head, cp_tail, cp);
197   return cp;
198 }
199
200 /**
201  * Called with any sensor reading messages received from CADET.
202  *
203  * Each time the function must call #GNUNET_CADET_receive_done on the channel
204  * in order to receive the next message. This doesn't need to be immediate:
205  * can be delayed if some processing is done on the message.
206  *
207  * @param cls Closure (set from #GNUNET_CADET_connect).
208  * @param channel Connection to the other end.
209  * @param channel_ctx Place to store local state associated with the channel.
210  * @param message The actual message.
211  * @return #GNUNET_OK to keep the channel open,
212  *         #GNUNET_SYSERR to close it (signal serious error).
213  */
214 static int
215 handle_sensor_reading (void *cls,
216                        struct GNUNET_CADET_Channel *channel,
217                        void **channel_ctx,
218                        const struct GNUNET_MessageHeader *message)
219 {
220   struct GNUNET_PeerIdentity *peer = *channel_ctx;
221   struct GNUNET_SENSOR_Reading *reading;
222
223   reading = GNUNET_SENSOR_parse_reading_message (message, sensors);
224   if (NULL == reading)
225   {
226     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
227                 "Received an invalid sensor reading from peer `%s'\n",
228                 GNUNET_i2s (peer));
229     return GNUNET_SYSERR;
230   }
231   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
232               "Received a sensor reading from peer `%s':\n"
233               "# Sensor name: `%s'\n"
234               "# Timestamp: %" PRIu64 "\n"
235               "# Value size: %" PRIu64 ".\n",
236               GNUNET_i2s (peer),
237               reading->sensor->name,
238               reading->timestamp,
239               reading->value_size);
240   GNUNET_PEERSTORE_store (peerstore, subsystem, peer, reading->sensor->name,
241                           reading->value, reading->value_size,
242                           GNUNET_TIME_UNIT_FOREVER_ABS,
243                           GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
244   GNUNET_free (reading->value);
245   GNUNET_free (reading);
246   GNUNET_CADET_receive_done (channel);
247   return GNUNET_OK;
248 }
249
250
251 /**
252  * Called with any sensor list request received.
253  *
254  * Each time the function must call #GNUNET_CADET_receive_done on the channel
255  * in order to receive the next message. This doesn't need to be immediate:
256  * can be delayed if some processing is done on the message.
257  *
258  * @param cls Closure (set from #GNUNET_CADET_connect).
259  * @param channel Connection to the other end.
260  * @param channel_ctx Place to store local state associated with the channel.
261  * @param message The actual message.
262  * @return #GNUNET_OK to keep the channel open,
263  *         #GNUNET_SYSERR to close it (signal serious error).
264  */
265 static int
266 handle_sensor_list_req (void *cls,
267                         struct GNUNET_CADET_Channel *channel,
268                         void **channel_ctx,
269                         const struct GNUNET_MessageHeader *message)
270 {
271   //TODO
272   GNUNET_CADET_receive_done (channel);
273   return GNUNET_OK;
274 }
275
276
277 /**
278  * Process sensordashboard requests.
279  *
280  * @param cls closure
281  * @param server the initialized server
282  * @param cfg configuration to use
283  */
284 static void
285 run (void *cls, struct GNUNET_SERVER_Handle *server,
286      const struct GNUNET_CONFIGURATION_Handle *cfg)
287 {
288   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
289     {NULL, NULL, 0, 0}
290   };
291   static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
292       {&handle_sensor_reading,
293        GNUNET_MESSAGE_TYPE_SENSOR_READING, 0},
294       {&handle_sensor_list_req,
295        GNUNET_MESSAGE_TYPE_SENSOR_LIST_REQ,
296        sizeof (struct GNUNET_MessageHeader)},
297       {NULL, 0, 0}
298   };
299   static uint32_t cadet_ports[] = {
300       GNUNET_APPLICATION_TYPE_SENSORDASHBOARD,
301       GNUNET_APPLICATION_TYPE_SENSORUPDATE,
302       GNUNET_APPLICATION_TYPE_END
303   };
304   sensors = GNUNET_SENSOR_load_all_sensors ();
305   GNUNET_assert (NULL != sensors);
306   cadet = GNUNET_CADET_connect(cfg,
307                                NULL,
308                                &cadet_channel_created,
309                                &cadet_channel_destroyed,
310                                cadet_handlers,
311                                cadet_ports);
312   if(NULL == cadet)
313   {
314     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
315                 _("Failed to connect to `%s' service.\n"), "CADET");
316     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
317     return;
318   }
319   peerstore = GNUNET_PEERSTORE_connect (cfg);
320   if (NULL == peerstore)
321   {
322     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
323                 _("Failed to connect to `%s' service.\n"), "PEERSTORE");
324     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
325     return;
326   }
327   GNUNET_SERVER_add_handlers (server, handlers);
328   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
329                                 NULL);
330 }
331
332
333 /**
334  * The main function for the sensordashboard service.
335  *
336  * @param argc number of arguments from the command line
337  * @param argv command line arguments
338  * @return 0 ok, 1 on error
339  */
340 int
341 main (int argc, char *const *argv)
342 {
343   return (GNUNET_OK ==
344           GNUNET_SERVICE_run (argc, argv, "sensordashboard",
345                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
346 }
347
348 /* end of gnunet-service-sensordashboard.c */