diff options
author | Omar Tarabai <tarabai@devegypt.com> | 2014-07-03 14:06:02 +0000 |
---|---|---|
committer | Omar Tarabai <tarabai@devegypt.com> | 2014-07-03 14:06:02 +0000 |
commit | e68aa2bf46213e33bf1bc07a335df8aeb5ac01c3 (patch) | |
tree | 7935770db2280f5b3c95b4d081e67f2a06dd2a6d /src/sensor/sensor_util_lib.c | |
parent | dc09ce9982904298e0ef97c91f7bf9218f1b0046 (diff) | |
download | gnunet-e68aa2bf46213e33bf1bc07a335df8aeb5ac01c3.tar.gz gnunet-e68aa2bf46213e33bf1bc07a335df8aeb5ac01c3.zip |
moved common sensor functionality to a util lib
Diffstat (limited to 'src/sensor/sensor_util_lib.c')
-rw-r--r-- | src/sensor/sensor_util_lib.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/src/sensor/sensor_util_lib.c b/src/sensor/sensor_util_lib.c new file mode 100644 index 000000000..90befe6af --- /dev/null +++ b/src/sensor/sensor_util_lib.c | |||
@@ -0,0 +1,424 @@ | |||
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/sensor_util_lib.c | ||
23 | * @brief senor utilities | ||
24 | * @author Omar Tarabai | ||
25 | */ | ||
26 | #include <inttypes.h> | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_sensor_util_lib.h" | ||
30 | |||
31 | #define LOG(kind,...) GNUNET_log_from (kind, "sensor-util",__VA_ARGS__) | ||
32 | |||
33 | /** | ||
34 | * Minimum sensor execution interval (in seconds) | ||
35 | */ | ||
36 | #define MIN_INTERVAL 30 | ||
37 | |||
38 | /** | ||
39 | * Supported sources of sensor information | ||
40 | */ | ||
41 | static const char *sources[] = { "gnunet-statistics", "process", NULL }; | ||
42 | |||
43 | /** | ||
44 | * Supported datatypes of sensor information | ||
45 | */ | ||
46 | static const char *datatypes[] = { "numeric", "string", NULL }; | ||
47 | |||
48 | /** | ||
49 | * Parses a version number string into major and minor | ||
50 | * | ||
51 | * @param version full version string | ||
52 | * @param major pointer to parsed major value | ||
53 | * @param minor pointer to parsed minor value | ||
54 | * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERROR in case of error | ||
55 | */ | ||
56 | static int | ||
57 | version_parse(char *version, uint16_t *major, uint16_t *minor) | ||
58 | { | ||
59 | int majorval = 0; | ||
60 | int minorval = 0; | ||
61 | |||
62 | for(; isdigit(*version); version++) | ||
63 | { | ||
64 | majorval *= 10; | ||
65 | majorval += *version - '0'; | ||
66 | } | ||
67 | if(*version != '.') | ||
68 | return GNUNET_SYSERR; | ||
69 | version++; | ||
70 | for(; isdigit(*version); version++) | ||
71 | { | ||
72 | minorval *= 10; | ||
73 | minorval += *version - '0'; | ||
74 | } | ||
75 | if(*version != 0) | ||
76 | return GNUNET_SYSERR; | ||
77 | *major = majorval; | ||
78 | *minor = minorval; | ||
79 | |||
80 | return GNUNET_OK; | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * Load sensor definition from configuration | ||
85 | * | ||
86 | * @param cfg configuration handle | ||
87 | * @param sectionname configuration section containing definition | ||
88 | */ | ||
89 | static struct SensorInfo * | ||
90 | load_sensor_from_cfg(struct GNUNET_CONFIGURATION_Handle *cfg, const char *sectionname) | ||
91 | { | ||
92 | struct SensorInfo *sensor; | ||
93 | char *version_str; | ||
94 | char *starttime_str; | ||
95 | char *endtime_str; | ||
96 | unsigned long long time_sec; | ||
97 | char *dummy; | ||
98 | struct GNUNET_CRYPTO_EddsaPublicKey public_key; | ||
99 | |||
100 | sensor = GNUNET_new(struct SensorInfo); | ||
101 | //name | ||
102 | sensor->name = GNUNET_strdup(sectionname); | ||
103 | //version | ||
104 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "VERSION", &version_str)) | ||
105 | { | ||
106 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n")); | ||
107 | GNUNET_free(sensor); | ||
108 | return NULL; | ||
109 | } | ||
110 | if(GNUNET_OK != version_parse(version_str, &(sensor->version_major), &(sensor->version_minor))) | ||
111 | { | ||
112 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid sensor version number, format should be major.minor\n")); | ||
113 | GNUNET_free(sensor); | ||
114 | GNUNET_free(version_str); | ||
115 | return NULL; | ||
116 | } | ||
117 | GNUNET_free(version_str); | ||
118 | //description | ||
119 | GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "DESCRIPTION", &sensor->description); | ||
120 | //category | ||
121 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "CATEGORY", &sensor->category) || | ||
122 | NULL == sensor->category) | ||
123 | { | ||
124 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n")); | ||
125 | GNUNET_free(sensor); | ||
126 | return NULL; | ||
127 | } | ||
128 | //enabled | ||
129 | if(GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "ENABLED")) | ||
130 | sensor->enabled = GNUNET_NO; | ||
131 | else | ||
132 | sensor->enabled = GNUNET_YES; | ||
133 | //start time | ||
134 | sensor->start_time = NULL; | ||
135 | if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "START_TIME", &starttime_str)) | ||
136 | { | ||
137 | GNUNET_STRINGS_fancy_time_to_absolute(starttime_str, sensor->start_time); | ||
138 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Start time loaded: `%s'. Parsed: %d\n", starttime_str, (NULL != sensor->start_time)); | ||
139 | GNUNET_free(starttime_str); | ||
140 | } | ||
141 | //end time | ||
142 | sensor->end_time = NULL; | ||
143 | if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "END_TIME", &endtime_str)) | ||
144 | { | ||
145 | GNUNET_STRINGS_fancy_time_to_absolute(endtime_str, sensor->end_time); | ||
146 | LOG (GNUNET_ERROR_TYPE_DEBUG, "End time loaded: `%s'. Parsed: %d\n", endtime_str, (NULL != sensor->end_time)); | ||
147 | GNUNET_free(endtime_str); | ||
148 | } | ||
149 | //interval | ||
150 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "INTERVAL", &time_sec)) | ||
151 | { | ||
152 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n")); | ||
153 | GNUNET_free(sensor); | ||
154 | return NULL; | ||
155 | } | ||
156 | if(time_sec < MIN_INTERVAL) | ||
157 | { | ||
158 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Sensor run interval too low (%" PRIu64 " < %d)\n"), | ||
159 | time_sec, MIN_INTERVAL); | ||
160 | GNUNET_free(sensor); | ||
161 | return NULL; | ||
162 | } | ||
163 | sensor->interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); | ||
164 | //lifetime | ||
165 | if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "LIFETIME", &time_sec)) | ||
166 | { | ||
167 | sensor->lifetime = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); | ||
168 | if (sensor->lifetime.rel_value_us < sensor->interval.rel_value_us) | ||
169 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
170 | "Lifetime of sensor data is preferred to be higher than interval for sensor `%s'.\n", | ||
171 | sensor->name); | ||
172 | } | ||
173 | else | ||
174 | sensor->lifetime = sensor->interval; | ||
175 | //capabilities TODO | ||
176 | //source | ||
177 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "SOURCE", sources, (const char **)&sensor->source)) | ||
178 | { | ||
179 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor source\n")); | ||
180 | GNUNET_free(sensor); | ||
181 | return NULL; | ||
182 | } | ||
183 | if(sources[0] == sensor->source) //gnunet-statistics | ||
184 | { | ||
185 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_SERVICE", &sensor->gnunet_stat_service) || | ||
186 | GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_NAME", &sensor->gnunet_stat_name)) | ||
187 | { | ||
188 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor gnunet-statistics source information\n")); | ||
189 | GNUNET_free(sensor); | ||
190 | return NULL; | ||
191 | } | ||
192 | sensor->gnunet_stat_get_handle = NULL; | ||
193 | } | ||
194 | else if(sources[1] == sensor->source) //process | ||
195 | { | ||
196 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_PROCESS", &sensor->ext_process)) | ||
197 | { | ||
198 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor process name\n")); | ||
199 | GNUNET_free(sensor); | ||
200 | return NULL; | ||
201 | } | ||
202 | GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_ARGS", &sensor->ext_args); | ||
203 | } | ||
204 | //expected datatype | ||
205 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "EXPECTED_DATATYPE", datatypes, (const char **)&sensor->expected_datatype)) | ||
206 | { | ||
207 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor expected datatype\n")); | ||
208 | GNUNET_free(sensor); | ||
209 | return NULL; | ||
210 | } | ||
211 | if(sources[0] == sensor->source && datatypes[0] != sensor->expected_datatype) | ||
212 | { | ||
213 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid expected datatype, gnunet-statistics returns uint64 values\n")); | ||
214 | GNUNET_free(sensor); | ||
215 | return NULL; | ||
216 | } | ||
217 | //reporting mechanism | ||
218 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "COLLECTION_POINT", &dummy)) | ||
219 | { | ||
220 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "COLLECTION_INTERVAL", &time_sec)) | ||
221 | { | ||
222 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor collection interval\n")); | ||
223 | } | ||
224 | else | ||
225 | { | ||
226 | sensor->collection_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); | ||
227 | if (GNUNET_OK == GNUNET_CRYPTO_eddsa_public_key_from_string(dummy, strlen(dummy), &public_key)) | ||
228 | { | ||
229 | sensor->collection_point = GNUNET_new(struct GNUNET_PeerIdentity); | ||
230 | sensor->collection_point->public_key = public_key; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | sensor->p2p_report = GNUNET_NO; | ||
235 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "P2P_REPORT")) | ||
236 | { | ||
237 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "P2P_INTERVAL", &time_sec)) | ||
238 | { | ||
239 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor p2p reporting interval\n")); | ||
240 | } | ||
241 | else | ||
242 | { | ||
243 | sensor->p2p_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); | ||
244 | sensor->p2p_report = GNUNET_YES; | ||
245 | } | ||
246 | } | ||
247 | //execution task | ||
248 | sensor->execution_task = GNUNET_SCHEDULER_NO_TASK; | ||
249 | //running | ||
250 | sensor->running = GNUNET_NO; | ||
251 | |||
252 | return sensor; | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * Load sensor definition from file | ||
257 | * | ||
258 | * @param filename full path to file containing sensor definition | ||
259 | */ | ||
260 | static struct SensorInfo * | ||
261 | load_sensor_from_file(const char *filename) | ||
262 | { | ||
263 | struct GNUNET_CONFIGURATION_Handle *sensorcfg; | ||
264 | const char *filebasename; | ||
265 | struct SensorInfo *sensor; | ||
266 | |||
267 | //test file | ||
268 | if(GNUNET_YES != GNUNET_DISK_file_test(filename)) | ||
269 | { | ||
270 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"), filename); | ||
271 | return NULL; | ||
272 | } | ||
273 | //load file as configuration | ||
274 | sensorcfg = GNUNET_CONFIGURATION_create(); | ||
275 | if(GNUNET_SYSERR == GNUNET_CONFIGURATION_parse(sensorcfg, filename)) | ||
276 | { | ||
277 | GNUNET_CONFIGURATION_destroy(sensorcfg); | ||
278 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"), filename); | ||
279 | return NULL; | ||
280 | } | ||
281 | //configuration section should be the same as filename | ||
282 | filebasename = GNUNET_STRINGS_get_short_name(filename); | ||
283 | sensor = load_sensor_from_cfg(sensorcfg, filebasename); | ||
284 | if(NULL == sensor) | ||
285 | { | ||
286 | GNUNET_CONFIGURATION_destroy(sensorcfg); | ||
287 | return NULL; | ||
288 | } | ||
289 | sensor->def_file = GNUNET_strdup(filename); | ||
290 | sensor->cfg = sensorcfg; | ||
291 | |||
292 | return sensor; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * Compares version numbers of two sensors | ||
297 | * | ||
298 | * @param s1 first sensor | ||
299 | * @param s2 second sensor | ||
300 | * @return 1: s1 > s2, 0: s1 == s2, -1: s1 < s2 | ||
301 | */ | ||
302 | static int | ||
303 | sensor_version_compare(struct SensorInfo *s1, struct SensorInfo *s2) | ||
304 | { | ||
305 | if(s1->version_major == s2->version_major) | ||
306 | return (s1->version_minor < s2->version_minor) ? -1 : (s1->version_minor > s2->version_minor); | ||
307 | else | ||
308 | return (s1->version_major < s2->version_major) ? -1 : (s1->version_major > s2->version_major); | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * Adds a new sensor to given hashmap. | ||
313 | * If the same name exist, compares versions and update if old. | ||
314 | * | ||
315 | * @param sensor Sensor structure to add | ||
316 | * @param map Hashmap to add to | ||
317 | * @return #GNUNET_YES if added, #GNUNET_NO if not added which is not necessarily an error | ||
318 | */ | ||
319 | static int | ||
320 | add_sensor_to_hashmap(struct SensorInfo *sensor, struct GNUNET_CONTAINER_MultiHashMap *map) | ||
321 | { | ||
322 | struct GNUNET_HashCode key; | ||
323 | struct SensorInfo *existing; | ||
324 | |||
325 | GNUNET_CRYPTO_hash(sensor->name, strlen(sensor->name), &key); | ||
326 | existing = GNUNET_CONTAINER_multihashmap_get(map, &key); | ||
327 | if(NULL != existing) //sensor with same name already exists | ||
328 | { | ||
329 | if(sensor_version_compare(existing, sensor) >= 0) //same or newer version already exist | ||
330 | { | ||
331 | LOG (GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' already exists with same or newer version\n"), sensor->name); | ||
332 | return GNUNET_NO; | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | GNUNET_CONTAINER_multihashmap_remove(map, &key, existing); //remove the old version | ||
337 | GNUNET_free(existing); | ||
338 | LOG (GNUNET_ERROR_TYPE_INFO, "Upgrading sensor `%s' to a newer version\n", sensor->name); | ||
339 | } | ||
340 | } | ||
341 | if(GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(map, &key, sensor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
342 | { | ||
343 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Error adding new sensor `%s' to global hashmap, this should not happen\n"), sensor->name); | ||
344 | return GNUNET_NO; | ||
345 | } | ||
346 | |||
347 | return GNUNET_YES; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * Iterating over files in sensors directory | ||
352 | * | ||
353 | * @param cls closure | ||
354 | * @param filename complete filename (absolute path) | ||
355 | * @return #GNUNET_OK to continue to iterate | ||
356 | */ | ||
357 | static int | ||
358 | reload_sensors_dir_cb(void *cls, const char *filename) | ||
359 | { | ||
360 | struct GNUNET_CONTAINER_MultiHashMap *sensors = cls; | ||
361 | struct SensorInfo *sensor; | ||
362 | |||
363 | if(GNUNET_YES != GNUNET_DISK_file_test(filename)) | ||
364 | return GNUNET_OK; | ||
365 | sensor = load_sensor_from_file(filename); | ||
366 | if(NULL == sensor) | ||
367 | { | ||
368 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
369 | _("Error loading sensor from file: %s\n"), filename); | ||
370 | return GNUNET_OK; | ||
371 | } | ||
372 | if(GNUNET_YES == add_sensor_to_hashmap(sensor, sensors)) | ||
373 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
374 | "Sensor `%s' added to global hashmap\n", sensor->name); | ||
375 | else | ||
376 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
377 | "Could not add sensor `%s' to global hashmap\n", sensor->name); | ||
378 | |||
379 | return GNUNET_OK; | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * Get path to the directory containing the sensor definition files | ||
384 | * | ||
385 | * @return sensor files directory | ||
386 | */ | ||
387 | char * | ||
388 | GNUNET_SENSOR_get_sensor_dir () | ||
389 | { | ||
390 | char* datadir; | ||
391 | char* sensordir; | ||
392 | |||
393 | datadir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_DATADIR); | ||
394 | GNUNET_asprintf(&sensordir, "%ssensors%s", | ||
395 | datadir, DIR_SEPARATOR_STR); | ||
396 | GNUNET_free(datadir); | ||
397 | |||
398 | return sensordir; | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * Reads sensor definitions from local data files | ||
403 | * | ||
404 | * @return a multihashmap of loaded sensors | ||
405 | */ | ||
406 | struct GNUNET_CONTAINER_MultiHashMap * | ||
407 | GNUNET_SENSOR_load_all_sensors () | ||
408 | { | ||
409 | char* sensordir; | ||
410 | struct GNUNET_CONTAINER_MultiHashMap *sensors; | ||
411 | |||
412 | sensors = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO); | ||
413 | sensordir = GNUNET_SENSOR_get_sensor_dir (); | ||
414 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
415 | "Loading sensor definitions from directory `%s'\n", sensordir); | ||
416 | GNUNET_assert(GNUNET_YES == GNUNET_DISK_directory_test(sensordir, GNUNET_YES)); | ||
417 | |||
418 | //read all files in sensors directory | ||
419 | GNUNET_DISK_directory_scan(sensordir, &reload_sensors_dir_cb, sensors); | ||
420 | LOG (GNUNET_ERROR_TYPE_INFO, "Loaded %d sensors from directory `%s'\n", | ||
421 | GNUNET_CONTAINER_multihashmap_size(sensors), sensordir); | ||
422 | GNUNET_free(sensordir); | ||
423 | return sensors; | ||
424 | } | ||