2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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 sensordashboard/gnunet-service-sensordashboard.c
23 * @brief Service collecting sensor readings from peers
24 * @author Omar Tarabai
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"
37 * Context of a connected client peer
39 struct ClientPeerContext
45 struct ClientPeerContext *prev;
50 struct ClientPeerContext *next;
53 * GNUnet Peer identity
55 struct GNUNET_PeerIdentity peerid;
58 * Handle to the cadet channel
60 struct GNUNET_CADET_Channel *ch;
63 * Are we in the process of destroying this context?
71 * Handle to CADET service
73 static struct GNUNET_CADET_Handle *cadet;
76 * Global hashmap of defined sensors
78 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
81 * Handle to the peerstore service connection
83 static struct GNUNET_PEERSTORE_Handle *peerstore;
86 * Name of this subsystem to be used for peerstore operations
88 static char *subsystem = "sensordashboard";
91 * Head of a DLL of all connected client peers
93 static struct ClientPeerContext *cp_head;
96 * Tail of a DLL of all connected client peers
98 static struct ClientPeerContext *cp_tail;
102 * Destroy a given client peer context
104 * @param cp client peer context
107 destroy_clientpeer (struct ClientPeerContext *cp)
109 cp->destroying = GNUNET_YES;
112 GNUNET_CADET_channel_destroy (cp->ch);
120 * Task run during shutdown.
126 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
128 struct ClientPeerContext *cp;
133 GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
134 destroy_clientpeer (cp);
139 GNUNET_CADET_disconnect (cadet);
142 if (NULL != peerstore)
144 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
147 GNUNET_SENSOR_destroy_sensors (sensors);
148 GNUNET_SCHEDULER_shutdown ();
153 * Function called whenever a channel is destroyed. Should clean up
154 * any associated state.
156 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
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
164 cadet_channel_destroyed (void *cls,
165 const struct GNUNET_CADET_Channel *channel,
168 struct ClientPeerContext *cp = channel_ctx;
170 if (GNUNET_YES == cp->destroying)
173 GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
174 destroy_clientpeer (cp);
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.
184 * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored. In
185 * this case the handler MUST return NULL.
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.
193 * @return initial channel context for the channel
194 * (can be NULL -- that's not an error)
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)
202 struct ClientPeerContext *cp;
204 cp = GNUNET_new (struct ClientPeerContext);
205 cp->peerid = *initiator;
207 cp->destroying = GNUNET_NO;
208 GNUNET_CONTAINER_DLL_insert (cp_head, cp_tail, cp);
214 * Parses a sensor reading message struct
216 * @param msg message header received
217 * @param sensors multihashmap of loaded sensors
218 * @return sensor reading struct or NULL if error
220 static struct GNUNET_SENSOR_Reading *
221 parse_reading_message (const struct GNUNET_MessageHeader *msg,
222 struct GNUNET_CONTAINER_MultiHashMap *sensors)
225 struct GNUNET_SENSOR_ReadingMessage *rm;
226 uint16_t sensorname_size;
230 struct GNUNET_HashCode key;
231 struct GNUNET_SENSOR_SensorInfo *sensor;
232 struct GNUNET_SENSOR_Reading *reading;
234 msg_size = ntohs (msg->size);
235 if (msg_size < sizeof (struct GNUNET_SENSOR_ReadingMessage))
237 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid reading message size.\n");
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)
246 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid reading message size.\n");
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);
257 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
258 "Unknown sensor name in reading message.\n");
261 if ((sensor->version_minor != ntohs (rm->sensorversion_minor)) ||
262 (sensor->version_major != ntohs (rm->sensorversion_major)))
264 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
265 "Sensor version mismatch in reading message.\n");
268 if (0 == strcmp (sensor->expected_datatype, "numeric") &&
269 sizeof (double) != value_size)
271 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
272 "Invalid value size for a numerical sensor.\n");
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);
287 * Called with any sensor reading messages received from CADET.
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.
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).
301 handle_sensor_reading (void *cls,
302 struct GNUNET_CADET_Channel *channel,
304 const struct GNUNET_MessageHeader *message)
306 struct ClientPeerContext *cp = *channel_ctx;
307 struct GNUNET_SENSOR_Reading *reading;
309 reading = parse_reading_message (message, sensors);
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;
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,
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);
338 * Called with any sensor list request received.
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.
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).
352 handle_sensor_list_req (void *cls,
353 struct GNUNET_CADET_Channel *channel,
355 const struct GNUNET_MessageHeader *message)
358 GNUNET_CADET_receive_done (channel);
364 * Process sensordashboard requests.
367 * @param server the initialized server
368 * @param cfg configuration to use
371 run (void *cls, struct GNUNET_SERVER_Handle *server,
372 const struct GNUNET_CONFIGURATION_Handle *cfg)
374 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
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)},
385 static uint32_t cadet_ports[] = {
386 GNUNET_APPLICATION_TYPE_SENSORDASHBOARD,
387 GNUNET_APPLICATION_TYPE_SENSORUPDATE,
388 GNUNET_APPLICATION_TYPE_END
390 sensors = GNUNET_SENSOR_load_all_sensors ();
391 GNUNET_assert (NULL != sensors);
392 cadet = GNUNET_CADET_connect(cfg,
394 &cadet_channel_created,
395 &cadet_channel_destroyed,
400 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
401 _("Failed to connect to `%s' service.\n"), "CADET");
402 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
405 peerstore = GNUNET_PEERSTORE_connect (cfg);
406 if (NULL == peerstore)
408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
409 _("Failed to connect to `%s' service.\n"), "PEERSTORE");
410 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
413 GNUNET_SERVER_add_handlers (server, handlers);
414 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
420 * The main function for the sensordashboard service.
422 * @param argc number of arguments from the command line
423 * @param argv command line arguments
424 * @return 0 ok, 1 on error
427 main (int argc, char *const *argv)
430 GNUNET_SERVICE_run (argc, argv, "sensordashboard",
431 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
434 /* end of gnunet-service-sensordashboard.c */