sensor: starting modules controllable from config
[oweals/gnunet.git] / src / sensor / gnunet-service-sensor.c
1 /*
2      This file is part of GNUnet.
3      (C)
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 sensor/gnunet-service-sensor.c
23  * @brief sensor service implementation
24  * @author Omar Tarabai
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "sensor.h"
29
30 /**
31  * Our configuration.
32  */
33 static const struct GNUNET_CONFIGURATION_Handle *cfg;
34
35 /**
36  * Path to sensor definitions directory
37  */
38 static char *sensor_dir;
39
40 /**
41  * Hashmap of loaded sensor definitions
42  */
43 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
44
45 /**
46  * Start the monitoring module ?
47  */
48 static int start_monitoring;
49
50 /**
51  * Start the analysis module ?
52  */
53 static int start_analysis;
54
55 /**
56  * Start the reporting module ?
57  */
58 static int start_reporting;
59
60 /**
61  * Start the update module ?
62  */
63 static int start_update;
64
65
66 /**
67  * Resets the service by stopping components, reloading sensors and starting
68  * components. This is needed when we receive new sensor updates.
69  */
70 static void
71 reset ();
72
73
74 /**
75  * Stops components and destroys sensors
76  */
77 static void
78 stop ()
79 {
80   if (GNUNET_YES == start_update)
81     SENSOR_update_stop ();
82   if (GNUNET_YES == start_analysis)
83     SENSOR_analysis_stop ();
84   if (GNUNET_YES == start_reporting)
85     SENSOR_reporting_stop ();
86   if (GNUNET_YES == start_monitoring)
87     SENSOR_monitoring_stop ();
88   GNUNET_SENSOR_destroy_sensors (sensors);
89 }
90
91
92 /**
93  * Task run during shutdown.
94  *
95  * @param cls unused
96  * @param tc unused
97  */
98 static void
99 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
100 {
101   stop ();
102   if (NULL != sensor_dir)
103   {
104     GNUNET_free (sensor_dir);
105     sensor_dir = NULL;
106   }
107   GNUNET_SCHEDULER_shutdown ();
108 }
109
110
111 /**
112  * Creates a structure with basic sensor info to be sent to a client.
113  *
114  * @param sensor sensor information
115  * @return message ready to be sent to client
116  */
117 static struct SensorInfoMessage *
118 create_sensor_info_msg (struct GNUNET_SENSOR_SensorInfo *sensor)
119 {
120   struct SensorInfoMessage *msg;
121   uint16_t len;
122   size_t name_len;
123   size_t desc_len;
124   char *str_ptr;
125
126   name_len = strlen (sensor->name);
127   if (NULL == sensor->description)
128     desc_len = 0;
129   else
130     desc_len = strlen (sensor->description) + 1;
131   len = 0;
132   len += sizeof (struct SensorInfoMessage);
133   len += name_len;
134   len += desc_len;
135   msg = GNUNET_malloc (len);
136   msg->header.size = htons (len);
137   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SENSOR_INFO);
138   msg->name_len = htons (name_len);
139   msg->description_len = htons (desc_len);
140   msg->version_major = htons (sensor->version_major);
141   msg->version_minor = htons (sensor->version_minor);
142   str_ptr = (char *) &msg[1];
143   memcpy (str_ptr, sensor->name, name_len);
144   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending sensor name (%d): %.*s\n",
145               name_len, name_len, str_ptr);
146   str_ptr += name_len;
147   memcpy (str_ptr, sensor->description, desc_len);
148   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149               "Sending sensor description (%d): %.*s\n", desc_len, desc_len,
150               str_ptr);
151   return msg;
152 }
153
154
155 /**
156  * Handle GET SENSOR message.
157  *
158  * @param cls closure
159  * @param client identification of the client
160  * @param message the actual message
161  */
162 static void
163 handle_get_sensor (void *cls, struct GNUNET_SERVER_Client *client,
164                    const struct GNUNET_MessageHeader *message)
165 {
166   struct GNUNET_SERVER_TransmitContext *tc;
167   char *sensorname;
168   size_t sensorname_len;
169   struct GNUNET_HashCode key;
170   struct GNUNET_SENSOR_SensorInfo *sensorinfo;
171   struct SensorInfoMessage *msg;
172
173   sensorname = (char *) &message[1];
174   sensorname_len = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
175   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
176               "`%s' message received for sensor (%d) `%.*s'\n", "GET SENSOR",
177               sensorname_len, sensorname_len, sensorname);
178   tc = GNUNET_SERVER_transmit_context_create (client);
179   GNUNET_CRYPTO_hash (sensorname, sensorname_len, &key);
180   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181               "Created key hash for requested sensor\n");
182   sensorinfo =
183       (struct GNUNET_SENSOR_SensorInfo *)
184       GNUNET_CONTAINER_multihashmap_get (sensors, &key);
185   if (NULL != sensorinfo)
186   {
187     msg = create_sensor_info_msg (sensorinfo);
188     GNUNET_SERVER_transmit_context_append_message (tc,
189                                                    (struct GNUNET_MessageHeader
190                                                     *) msg);
191     GNUNET_free (msg);
192   }
193   else
194     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
195                 "Requested sensor `%.*s' was not found\n", sensorname_len,
196                 sensorname);
197   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
198                                               GNUNET_MESSAGE_TYPE_SENSOR_END);
199   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
200 }
201
202
203 /**
204  * Iterator for sensors and adds them to transmit context
205  *
206  * @param cls a `struct GNUNET_SERVER_TransmitContext *`
207  * @param key hash of sensor name, key to hashmap
208  * @param value a `struct GNUNET_SENSOR_SensorInfo *`
209  */
210 static int
211 add_sensor_to_tc (void *cls, const struct GNUNET_HashCode *key, void *value)
212 {
213   struct GNUNET_SERVER_TransmitContext *tc = cls;
214   struct GNUNET_SENSOR_SensorInfo *sensorinfo = value;
215   struct SensorInfoMessage *msg;
216
217   msg = create_sensor_info_msg (sensorinfo);
218   GNUNET_SERVER_transmit_context_append_message (tc,
219                                                  (struct GNUNET_MessageHeader *)
220                                                  msg);
221
222   GNUNET_free (msg);
223   return GNUNET_YES;
224 }
225
226
227 /**
228  * Handle GET ALL SENSORS message.
229  *
230  * @param cls closure
231  * @param client identification of the client
232  * @param message the actual message
233  */
234 static void
235 handle_get_all_sensors (void *cls, struct GNUNET_SERVER_Client *client,
236                         const struct GNUNET_MessageHeader *message)
237 {
238   struct GNUNET_SERVER_TransmitContext *tc;
239
240   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received.\n",
241               "GET ALL SENSOR");
242   tc = GNUNET_SERVER_transmit_context_create (client);
243   GNUNET_CONTAINER_multihashmap_iterate (sensors, &add_sensor_to_tc, tc);
244   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
245                                               GNUNET_MESSAGE_TYPE_SENSOR_END);
246   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
247 }
248
249
250 /**
251  * Loads sensors and starts different service components
252  */
253 static void
254 start ()
255 {
256   sensors = GNUNET_SENSOR_load_all_sensors (sensor_dir);
257   if (GNUNET_YES == start_monitoring)
258     SENSOR_monitoring_start (cfg, sensors);
259   if (GNUNET_YES == start_reporting)
260     SENSOR_reporting_start (cfg, sensors);
261   if (GNUNET_YES == start_analysis)
262     SENSOR_analysis_start (cfg, sensors);
263   if (GNUNET_YES == start_update)
264     SENSOR_update_start (cfg, sensors, &reset);
265 }
266
267
268 /**
269  * Process statistics requests.
270  *
271  * @param cls closure
272  * @param server the initialized server
273  * @param c configuration to use
274  */
275 static void
276 run (void *cls, struct GNUNET_SERVER_Handle *server,
277      const struct GNUNET_CONFIGURATION_Handle *c)
278 {
279   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
280     {&handle_get_sensor, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GET,
281      0},
282     {&handle_get_all_sensors, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GETALL,
283      sizeof (struct GNUNET_MessageHeader)},
284     {NULL, NULL, 0, 0}
285   };
286
287   cfg = c;
288   if (GNUNET_OK !=
289       GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR",
290                                                &sensor_dir))
291   {
292     sensor_dir = GNUNET_SENSOR_get_default_sensor_dir ();
293   }
294   start_monitoring = GNUNET_YES;
295   start_analysis = GNUNET_YES;
296   start_reporting = GNUNET_YES;
297   start_update = GNUNET_YES;
298   if (GNUNET_NO ==
299       GNUNET_CONFIGURATION_get_value_yesno (cfg, "SENSOR", "START_MONITORING"))
300   {
301     start_monitoring = GNUNET_NO;
302   }
303   if (GNUNET_NO ==
304       GNUNET_CONFIGURATION_get_value_yesno (cfg, "SENSOR", "START_REPORTING"))
305   {
306     start_reporting = GNUNET_NO;
307   }
308   if (GNUNET_NO ==
309       GNUNET_CONFIGURATION_get_value_yesno (cfg, "SENSOR", "START_ANALYSIS"))
310   {
311     start_analysis = GNUNET_NO;
312   }
313   if (GNUNET_NO ==
314       GNUNET_CONFIGURATION_get_value_yesno (cfg, "SENSOR", "START_UPDATE"))
315   {
316     start_update = GNUNET_NO;
317   }
318   GNUNET_SERVER_add_handlers (server, handlers);
319   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
320                                 NULL);
321   start ();
322 }
323
324
325 /**
326  * Resets the service by stopping components, reloading sensors and starting
327  * components. This is needed when we receive new sensor updates.
328  */
329 static void
330 reset ()
331 {
332   stop ();
333   start ();
334 }
335
336
337 /**
338  * The main function for the sensor service.
339  *
340  * @param argc number of arguments from the command line
341  * @param argv command line arguments
342  * @return 0 ok, 1 on error
343  */
344 int
345 main (int argc, char *const *argv)
346 {
347   return (GNUNET_OK ==
348           GNUNET_SERVICE_run (argc, argv, "sensor", GNUNET_SERVICE_OPTION_NONE,
349                               &run, NULL)) ? 0 : 1;
350 }
351
352 /* end of gnunet-service-sensor.c */