diff options
author | Omar Tarabai <tarabai@devegypt.com> | 2014-04-14 12:08:48 +0000 |
---|---|---|
committer | Omar Tarabai <tarabai@devegypt.com> | 2014-04-14 12:08:48 +0000 |
commit | a3485503b228317cb7a9813a1049cb510384d577 (patch) | |
tree | 5606d74e66398b2596be873c03574dac6ce69866 /src/sensor | |
parent | 750b5dc4e16072de66931a8c17da8d95aba66fb7 (diff) | |
download | gnunet-a3485503b228317cb7a9813a1049cb510384d577.tar.gz gnunet-a3485503b228317cb7a9813a1049cb510384d577.zip |
SENSOR component inital commit
Diffstat (limited to 'src/sensor')
-rw-r--r-- | src/sensor/Makefile.am | 69 | ||||
-rw-r--r-- | src/sensor/gnunet-sensor.c | 149 | ||||
-rw-r--r-- | src/sensor/gnunet-service-sensor.c | 577 | ||||
-rw-r--r-- | src/sensor/sensor.conf.in | 7 | ||||
-rw-r--r-- | src/sensor/sensor.h | 63 | ||||
-rw-r--r-- | src/sensor/sensor_api.c | 627 | ||||
-rw-r--r-- | src/sensor/test_sensor_api.c | 84 |
7 files changed, 1576 insertions, 0 deletions
diff --git a/src/sensor/Makefile.am b/src/sensor/Makefile.am new file mode 100644 index 000000000..24479cff9 --- /dev/null +++ b/src/sensor/Makefile.am | |||
@@ -0,0 +1,69 @@ | |||
1 | SUBDIRS = . | ||
2 | |||
3 | INCLUDES = \ | ||
4 | -I$(top_srcdir)/src/include \ | ||
5 | -I$(top_srcdir) | ||
6 | |||
7 | AM_CPPFLAGS = \ | ||
8 | $(GNUNET_CPPFLAGS) | ||
9 | |||
10 | # Set this variable if you are using GNUNET libraries for all programs and | ||
11 | # libraries. You don't then need to target-specific _LDFLAGS with GNUNET_LDFLAGS | ||
12 | # AM_LDFLAGS = \ | ||
13 | # $(GNUNET_LDFLAGS) \ | ||
14 | # $(WINFLAGS) \ | ||
15 | # -export-dynamic | ||
16 | |||
17 | lib_LTLIBRARIES = libgnunetsensor.la | ||
18 | |||
19 | pkgcfgdir= $(prefix)/share/gnunet/config.d/ | ||
20 | |||
21 | libexecdir= $(prefix)/lib/gnunet/libexec/ | ||
22 | |||
23 | libgnunetsensor_la_SOURCES = \ | ||
24 | sensor_api.c | ||
25 | libgnunetsensor_la_LIBADD = \ | ||
26 | -lgnunetutil | ||
27 | libgnunetsensor_la_LDFLAGS = \ | ||
28 | $(GNUNET_LDFLAGS) $(WINFLAGS) \ | ||
29 | -version-info 0:0:0 | ||
30 | |||
31 | |||
32 | bin_PROGRAMS = gnunet-sensor | ||
33 | |||
34 | libexec_PROGRAMS = gnunet-service-sensor | ||
35 | |||
36 | check_PROGRAMS = \ | ||
37 | test_sensor_api | ||
38 | |||
39 | TESTS = $(check_PROGRAMS) | ||
40 | |||
41 | gnunet_service_sensor_SOURCES = \ | ||
42 | gnunet-service-sensor.c | ||
43 | gnunet_service_sensor_LDADD = \ | ||
44 | -lgnunetutil -lgnunetcore -lgnunetdht\ | ||
45 | $(INTLLIBS) | ||
46 | gnunet_service_sensor_LDFLAGS = \ | ||
47 | $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic | ||
48 | |||
49 | gnunet_sensor_SOURCES = \ | ||
50 | gnunet-sensor.c | ||
51 | gnunet_sensor_LDADD = \ | ||
52 | -lgnunetutil \ | ||
53 | libgnunetsensor.la \ | ||
54 | $(INTLLIBS) | ||
55 | gnunet_sensor_LDFLAGS = \ | ||
56 | $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic | ||
57 | |||
58 | |||
59 | |||
60 | test_sensor_api_SOURCES = \ | ||
61 | test_sensor_api.c | ||
62 | test_sensor_api_LDADD = \ | ||
63 | $(top_builddir)/src/sensor/libgnunetsensor.la \ | ||
64 | -lgnunetutil | ||
65 | test_sensor_api_LDFLAGS = \ | ||
66 | $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic | ||
67 | |||
68 | pkgcfg_DATA = sensor.conf | ||
69 | |||
diff --git a/src/sensor/gnunet-sensor.c b/src/sensor/gnunet-sensor.c new file mode 100644 index 000000000..dd06d6e0b --- /dev/null +++ b/src/sensor/gnunet-sensor.c | |||
@@ -0,0 +1,149 @@ | |||
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-sensor.c | ||
23 | * @brief sensor tool | ||
24 | * @author Omar Tarabai | ||
25 | */ | ||
26 | #include <gnunet/platform.h> | ||
27 | #include <gnunet/gnunet_util_lib.h> | ||
28 | #include "gnunet_sensor_service.h" | ||
29 | |||
30 | static int ret; | ||
31 | |||
32 | /* | ||
33 | * option '-a' | ||
34 | */ | ||
35 | static int get_all; | ||
36 | |||
37 | /* | ||
38 | * Handle to sensor service | ||
39 | */ | ||
40 | struct GNUNET_SENSOR_Handle *sensor_handle; | ||
41 | |||
42 | /** | ||
43 | * Run on shutdown | ||
44 | * | ||
45 | * @param cls unused | ||
46 | * @param tc scheduler context | ||
47 | */ | ||
48 | static void | ||
49 | shutdown_task (void *cls, | ||
50 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
51 | { | ||
52 | if(NULL != sensor_handle) | ||
53 | { | ||
54 | GNUNET_SENSOR_disconnect(sensor_handle); | ||
55 | sensor_handle = NULL; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * Callback for getting sensor info from service | ||
61 | * | ||
62 | * @param cls not used | ||
63 | * @param sensor brief information about sensor (NULL means end of transmission) | ||
64 | * @param err_msg contains error string if any | ||
65 | */ | ||
66 | void print_sensor_info(void *cls, | ||
67 | const struct SensorInfoShort *sensor, | ||
68 | const char *err_msg) | ||
69 | { | ||
70 | if(NULL != err_msg) | ||
71 | { | ||
72 | printf("Error: %s\n", err_msg); | ||
73 | GNUNET_SCHEDULER_shutdown(); | ||
74 | return; | ||
75 | } | ||
76 | if(NULL == sensor) /* no more sensors from service */ | ||
77 | { | ||
78 | GNUNET_SCHEDULER_shutdown(); | ||
79 | return; | ||
80 | } | ||
81 | printf("Name: %s\nVersion: %d.%d\n", | ||
82 | sensor->name, | ||
83 | sensor->version_major, | ||
84 | sensor->version_minor); | ||
85 | if(NULL != sensor->description) | ||
86 | printf("Description: %s\n", sensor->description); | ||
87 | printf("\n"); | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * Main function that will be run by the scheduler. | ||
92 | * | ||
93 | * @param cls closure | ||
94 | * @param args remaining command-line arguments | ||
95 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
96 | * @param cfg configuration | ||
97 | */ | ||
98 | static void | ||
99 | run (void *cls, | ||
100 | char *const *args, | ||
101 | const char *cfgfile, | ||
102 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
103 | { | ||
104 | |||
105 | sensor_handle = NULL; | ||
106 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
107 | &shutdown_task, | ||
108 | NULL); | ||
109 | if(GNUNET_YES == get_all) | ||
110 | { | ||
111 | sensor_handle = GNUNET_SENSOR_connect(cfg); | ||
112 | GNUNET_assert(NULL != sensor_handle); | ||
113 | GNUNET_SENSOR_iterate_sensors(sensor_handle, | ||
114 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
115 | NULL, | ||
116 | 0, | ||
117 | &print_sensor_info, | ||
118 | NULL); | ||
119 | } | ||
120 | |||
121 | ret = 0; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * The main function to sensor. | ||
126 | * | ||
127 | * @param argc number of arguments from the command line | ||
128 | * @param argv command line arguments | ||
129 | * @return 0 ok, 1 on error | ||
130 | */ | ||
131 | int | ||
132 | main (int argc, char *const *argv) | ||
133 | { | ||
134 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
135 | {'a', "all", NULL, | ||
136 | gettext_noop("Retrieve names of all defined sensors"), | ||
137 | 0, &GNUNET_GETOPT_set_one, &get_all}, | ||
138 | GNUNET_GETOPT_OPTION_END | ||
139 | }; | ||
140 | return (GNUNET_OK == | ||
141 | GNUNET_PROGRAM_run (argc, | ||
142 | argv, | ||
143 | "gnunet-sensor [options [value]]", | ||
144 | gettext_noop | ||
145 | ("sensor"), | ||
146 | options, &run, NULL)) ? ret : 1; | ||
147 | } | ||
148 | |||
149 | /* end of gnunet-sensor.c */ | ||
diff --git a/src/sensor/gnunet-service-sensor.c b/src/sensor/gnunet-service-sensor.c new file mode 100644 index 000000000..28c608e94 --- /dev/null +++ b/src/sensor/gnunet-service-sensor.c | |||
@@ -0,0 +1,577 @@ | |||
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 Christian Grothoff | ||
25 | */ | ||
26 | #include <gnunet/platform.h> | ||
27 | #include <gnunet/gnunet_util_lib.h> | ||
28 | #include "sensor.h" | ||
29 | |||
30 | /** | ||
31 | * Structure containing sensor definition | ||
32 | */ | ||
33 | struct SensorInfo | ||
34 | { | ||
35 | |||
36 | /* | ||
37 | * Sensor name | ||
38 | */ | ||
39 | char *name; | ||
40 | |||
41 | /* | ||
42 | * Path to definition file | ||
43 | */ | ||
44 | char *def_file; | ||
45 | |||
46 | /* | ||
47 | * First part of version number | ||
48 | */ | ||
49 | uint16_t version_major; | ||
50 | |||
51 | /* | ||
52 | * Second part of version number | ||
53 | */ | ||
54 | uint16_t version_minor; | ||
55 | |||
56 | /* | ||
57 | * Sensor description | ||
58 | */ | ||
59 | char *description; | ||
60 | |||
61 | /* | ||
62 | * Category under which the sensor falls (e.g. tcp, datastore) | ||
63 | */ | ||
64 | char *category; | ||
65 | |||
66 | /* | ||
67 | * When does the sensor become active | ||
68 | */ | ||
69 | struct GNUNET_TIME_Absolute *start_time; | ||
70 | |||
71 | /* | ||
72 | * When does the sensor expire | ||
73 | */ | ||
74 | struct GNUNET_TIME_Absolute *end_time; | ||
75 | |||
76 | /* | ||
77 | * Time interval to collect sensor information (e.g. every 1 min) | ||
78 | */ | ||
79 | struct GNUNET_TIME_Relative *interval; | ||
80 | |||
81 | /* | ||
82 | * Lifetime of an information sample after which it is deleted from storage | ||
83 | */ | ||
84 | struct GNUNET_TIME_Relative *lifetime; | ||
85 | |||
86 | /* | ||
87 | * A set of required peer capabilities for the sensor to collect meaningful information (e.g. ipv6) | ||
88 | */ | ||
89 | char *capabilities; | ||
90 | |||
91 | /* | ||
92 | * Either "gnunet-statistics" or external "process" | ||
93 | */ | ||
94 | char *source; | ||
95 | |||
96 | /* | ||
97 | * Name of the GNUnet service that is the source for the gnunet-statistics entry | ||
98 | */ | ||
99 | char *gnunet_stat_service; | ||
100 | |||
101 | /* | ||
102 | * Name of the gnunet-statistics entry | ||
103 | */ | ||
104 | char *gnunet_stat_name; | ||
105 | |||
106 | /* | ||
107 | * Name of the external process to be executed | ||
108 | */ | ||
109 | char *ext_process; | ||
110 | |||
111 | /* | ||
112 | * Arguments to be passed to the external process | ||
113 | */ | ||
114 | char *ext_args; | ||
115 | |||
116 | /* | ||
117 | * The output datatype to be expected | ||
118 | */ | ||
119 | char *expected_datatype; | ||
120 | |||
121 | /* | ||
122 | * Peer-identity of peer running collection point | ||
123 | */ | ||
124 | struct GNUNET_PeerIdentity *collection_point; | ||
125 | |||
126 | /* | ||
127 | * Time interval to send sensor information to collection point (e.g. every 30 mins) | ||
128 | */ | ||
129 | struct GNUNET_TIME_Relative *collection_interval; | ||
130 | |||
131 | /* | ||
132 | * Flag specifying if value is to be communicated to the p2p network | ||
133 | */ | ||
134 | int p2p_report; | ||
135 | |||
136 | /* | ||
137 | * Time interval to communicate value to the p2p network | ||
138 | */ | ||
139 | struct GNUNET_TIME_Relative *p2p_interval; | ||
140 | |||
141 | }; | ||
142 | |||
143 | /** | ||
144 | * Our configuration. | ||
145 | */ | ||
146 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
147 | |||
148 | /** | ||
149 | * Hashmap of loaded sensor definitions | ||
150 | */ | ||
151 | struct GNUNET_CONTAINER_MultiHashMap *sensors; | ||
152 | |||
153 | /** | ||
154 | * Task run during shutdown. | ||
155 | * | ||
156 | * @param cls unused | ||
157 | * @param tc unused | ||
158 | */ | ||
159 | static void | ||
160 | shutdown_task (void *cls, | ||
161 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
162 | { | ||
163 | } | ||
164 | |||
165 | |||
166 | /** | ||
167 | * A client disconnected. Remove all of its data structure entries. | ||
168 | * | ||
169 | * @param cls closure, NULL | ||
170 | * @param client identification of the client | ||
171 | */ | ||
172 | static void | ||
173 | handle_client_disconnect (void *cls, | ||
174 | struct GNUNET_SERVER_Client | ||
175 | * client) | ||
176 | { | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * Parses a version number string into major and minor | ||
181 | * | ||
182 | * @param version full version string | ||
183 | * @param major pointer to parsed major value | ||
184 | * @param minor pointer to parsed minor value | ||
185 | * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERROR in case of error | ||
186 | */ | ||
187 | static int | ||
188 | version_parse(char *version, uint16_t *major, uint16_t *minor) | ||
189 | { | ||
190 | int majorval = 0; | ||
191 | int minorval = 0; | ||
192 | |||
193 | for(; isdigit(*version); version++) | ||
194 | { | ||
195 | majorval *= 10; | ||
196 | majorval += *version - '0'; | ||
197 | } | ||
198 | if(*version != '.') | ||
199 | return GNUNET_SYSERR; | ||
200 | version++; | ||
201 | for(; isdigit(*version); version++) | ||
202 | { | ||
203 | minorval *= 10; | ||
204 | minorval += *version - '0'; | ||
205 | } | ||
206 | if(*version != 0) | ||
207 | return GNUNET_SYSERR; | ||
208 | *major = majorval; | ||
209 | *minor = minorval; | ||
210 | |||
211 | return GNUNET_OK; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * Load sensor definition from configuration | ||
216 | * | ||
217 | * @param cfg configuration handle | ||
218 | * @param sectionname configuration section containing definition | ||
219 | */ | ||
220 | static struct SensorInfo * | ||
221 | load_sensor_from_cfg(struct GNUNET_CONFIGURATION_Handle *cfg, char *sectionname) | ||
222 | { | ||
223 | struct SensorInfo *sensor; | ||
224 | char *versionstr; | ||
225 | |||
226 | sensor = GNUNET_new(struct SensorInfo); | ||
227 | //name | ||
228 | sensor->name = GNUNET_strdup(sectionname); | ||
229 | //version | ||
230 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "VERSION", &versionstr) || | ||
231 | NULL == versionstr) | ||
232 | { | ||
233 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n")); | ||
234 | GNUNET_free(sensor); | ||
235 | return NULL; | ||
236 | } | ||
237 | if(GNUNET_OK != version_parse(versionstr, &(sensor->version_major), &(sensor->version_minor))) | ||
238 | { | ||
239 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid sensor version number, format should be major.minor\n")); | ||
240 | GNUNET_free(sensor); | ||
241 | return NULL; | ||
242 | } | ||
243 | //description | ||
244 | GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "DESCRIPTION", &sensor->description); | ||
245 | //category | ||
246 | if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "CATEGORY", &sensor->category) || | ||
247 | NULL == sensor->category) | ||
248 | { | ||
249 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n")); | ||
250 | GNUNET_free(sensor); | ||
251 | return NULL; | ||
252 | } | ||
253 | |||
254 | return sensor; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * Load sensor definition from file | ||
259 | * | ||
260 | * @param filename full path to file containing sensor definition | ||
261 | */ | ||
262 | static struct SensorInfo * | ||
263 | load_sensor_from_file(const char *filename) | ||
264 | { | ||
265 | struct GNUNET_CONFIGURATION_Handle *sensorcfg; | ||
266 | char *filebasename; | ||
267 | struct SensorInfo *sensor; | ||
268 | |||
269 | //test file | ||
270 | if(GNUNET_YES != GNUNET_DISK_file_test(filename)) | ||
271 | { | ||
272 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"), filename); | ||
273 | return NULL; | ||
274 | } | ||
275 | //load file as configuration | ||
276 | sensorcfg = GNUNET_CONFIGURATION_create(); | ||
277 | if(GNUNET_SYSERR == GNUNET_CONFIGURATION_parse(sensorcfg, filename)) | ||
278 | { | ||
279 | GNUNET_CONFIGURATION_destroy(sensorcfg); | ||
280 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"), filename); | ||
281 | return NULL; | ||
282 | } | ||
283 | //configuration section should be the same as filename | ||
284 | filebasename = GNUNET_STRINGS_get_short_name(filename); | ||
285 | sensor = load_sensor_from_cfg(sensorcfg, filebasename); | ||
286 | sensor->def_file = GNUNET_strdup(filename); | ||
287 | |||
288 | GNUNET_CONFIGURATION_destroy(sensorcfg); | ||
289 | |||
290 | return sensor; | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * Compares version numbers of two sensors | ||
295 | * | ||
296 | * @param s1 first sensor | ||
297 | * @param s2 second sensor | ||
298 | * @return 1: s1 > s2, 0: s1 == s2, -1: s1 < s2 | ||
299 | */ | ||
300 | static int | ||
301 | sensor_version_compare(struct SensorInfo *s1, struct SensorInfo *s2) | ||
302 | { | ||
303 | if(s1->version_major == s2->version_major) | ||
304 | return (s1->version_minor < s2->version_minor) ? -1 : (s1->version_minor > s2->version_minor); | ||
305 | else | ||
306 | return (s1->version_major < s2->version_major) ? -1 : (s1->version_major > s2->version_major); | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * Adds a new sensor to given hashmap. | ||
311 | * If the same name exist, compares versions and update if old. | ||
312 | * | ||
313 | * @param sensor Sensor structure to add | ||
314 | * @param map Hashmap to add to | ||
315 | * @return #GNUNET_YES if added, #GNUNET_NO if not added which is not necessarily an error | ||
316 | */ | ||
317 | static int | ||
318 | add_sensor_to_hashmap(struct SensorInfo *sensor, struct GNUNET_CONTAINER_MultiHashMap *map) | ||
319 | { | ||
320 | struct GNUNET_HashCode key; | ||
321 | struct SensorInfo *existing; | ||
322 | |||
323 | GNUNET_CRYPTO_hash(sensor->name, sizeof(sensor->name), &key); | ||
324 | existing = GNUNET_CONTAINER_multihashmap_get(map, &key); | ||
325 | if(NULL != existing) //sensor with same name already exists | ||
326 | { | ||
327 | if(sensor_version_compare(existing, sensor) >= 0) //same or newer version already exist | ||
328 | { | ||
329 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' already exists with same or newer version\n"), sensor->name); | ||
330 | return GNUNET_NO; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | GNUNET_CONTAINER_multihashmap_remove(map, &key, existing); //remove the old version | ||
335 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Upgrading sensor `%s' to a newer version\n"), sensor->name); | ||
336 | } | ||
337 | } | ||
338 | if(GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(map, &key, sensor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
339 | { | ||
340 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error adding new sensor `%s' to global hashmap, this should not happen\n"), sensor->name); | ||
341 | return GNUNET_NO; | ||
342 | } | ||
343 | |||
344 | return GNUNET_YES; | ||
345 | } | ||
346 | |||
347 | /** | ||
348 | * Iterating over files in sensors directory | ||
349 | * | ||
350 | * @param cls closure | ||
351 | * @param filename complete filename (absolute path) | ||
352 | * @return #GNUNET_OK to continue to iterate, | ||
353 | * #GNUNET_NO to stop iteration with no error, | ||
354 | * #GNUNET_SYSERR to abort iteration with error! | ||
355 | */ | ||
356 | static int | ||
357 | reload_sensors_dir_cb(void *cls, const char *filename) | ||
358 | { | ||
359 | struct SensorInfo *sensor; | ||
360 | |||
361 | sensor = load_sensor_from_file(filename); | ||
362 | if(NULL == sensor) | ||
363 | { | ||
364 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"), filename); | ||
365 | return GNUNET_OK; | ||
366 | } | ||
367 | if(GNUNET_YES == add_sensor_to_hashmap(sensor, sensors)) | ||
368 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' added to global hashmap\n"), sensor->name); | ||
369 | else | ||
370 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, ("Could not add sensor `%s' to global hashmap\n"), sensor->name); | ||
371 | |||
372 | return GNUNET_OK; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Get path to the directory containing the sensor definition files | ||
377 | * | ||
378 | * @return sensor files directory | ||
379 | */ | ||
380 | static char * | ||
381 | get_sensor_dir() | ||
382 | { | ||
383 | char* datadir; | ||
384 | char* sensordir; | ||
385 | |||
386 | datadir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_SELF_PREFIX); | ||
387 | //should eval to '$prefix/share/gnunet-mi/sensors/' | ||
388 | //TODO: is there a better way? | ||
389 | GNUNET_asprintf(&sensordir, "%sshare%sgnunet-mi%ssensors%s", | ||
390 | datadir, DIR_SEPARATOR_STR, DIR_SEPARATOR_STR, DIR_SEPARATOR_STR); | ||
391 | |||
392 | return sensordir; | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * Reads sensor definitions from data files | ||
397 | * | ||
398 | */ | ||
399 | static void | ||
400 | reload_sensors() | ||
401 | { | ||
402 | char* sensordir; | ||
403 | int filesfound; | ||
404 | |||
405 | sensordir = get_sensor_dir(); | ||
406 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Reloading sensor definitions from directory `%s'\n"), sensordir); | ||
407 | GNUNET_assert(GNUNET_YES == GNUNET_DISK_directory_test(sensordir, GNUNET_YES)); | ||
408 | |||
409 | //read all files in sensors directory | ||
410 | filesfound = GNUNET_DISK_directory_scan(sensordir, &reload_sensors_dir_cb, NULL); | ||
411 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Loaded %d/%d sensors from directory `%s'\n"), | ||
412 | GNUNET_CONTAINER_multihashmap_size(sensors), filesfound, sensordir); | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * Creates a structure with basic sensor info to be sent to a client | ||
417 | * | ||
418 | * @parm sensor sensor information | ||
419 | * @return message ready to be sent to client | ||
420 | */ | ||
421 | static struct SensorInfoMessage * | ||
422 | create_sensor_info_msg(struct SensorInfo *sensor) | ||
423 | { | ||
424 | struct SensorInfoMessage *msg; | ||
425 | uint16_t len; | ||
426 | size_t name_len; | ||
427 | size_t desc_len; | ||
428 | |||
429 | name_len = strlen(sensor->name); | ||
430 | if(NULL == sensor->description) | ||
431 | desc_len = 0; | ||
432 | else | ||
433 | desc_len = strlen(sensor->description); | ||
434 | len = 0; | ||
435 | len += sizeof(struct SensorInfoMessage); | ||
436 | len += name_len; | ||
437 | len += desc_len; | ||
438 | msg = GNUNET_malloc(len); | ||
439 | msg->header.size = htons(len); | ||
440 | msg->header.type = htons(GNUNET_MESSAGE_TYPE_SENSOR_INFO); | ||
441 | msg->name_len = htons(name_len); | ||
442 | msg->description_len = htons(desc_len); | ||
443 | msg->version_major = htons(sensor->version_major); | ||
444 | msg->version_minor = htons(sensor->version_minor); | ||
445 | memcpy(&msg[1], sensor->name, name_len); | ||
446 | memcpy((&msg[1]) + name_len, sensor->description, desc_len); | ||
447 | |||
448 | return msg; | ||
449 | } | ||
450 | |||
451 | /** | ||
452 | * Handle GET SENSOR message. | ||
453 | * | ||
454 | * @param cls closure | ||
455 | * @param client identification of the client | ||
456 | * @param message the actual message | ||
457 | */ | ||
458 | static void | ||
459 | handle_get_sensor (void *cls, struct GNUNET_SERVER_Client *client, | ||
460 | const struct GNUNET_MessageHeader *message) | ||
461 | { | ||
462 | struct GNUNET_SERVER_TransmitContext *tc; | ||
463 | char *sensorname; | ||
464 | size_t sensorname_len; | ||
465 | struct GNUNET_HashCode key; | ||
466 | struct SensorInfo *sensorinfo; | ||
467 | struct SensorInfoMessage *msg; | ||
468 | |||
469 | sensorname = (char *)&message[1]; | ||
470 | sensorname_len = message->size - sizeof(struct GNUNET_MessageHeader); | ||
471 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received for sensor `%.*s\n", | ||
472 | "GET SENSOR", sensorname_len, sensorname); | ||
473 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
474 | GNUNET_CRYPTO_hash(sensorname, sensorname_len, &key); | ||
475 | sensorinfo = (struct SensorInfo *)GNUNET_CONTAINER_multihashmap_get(sensors, &key); | ||
476 | msg = create_sensor_info_msg(sensorinfo); | ||
477 | GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg); | ||
478 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
479 | |||
480 | GNUNET_free(msg); | ||
481 | } | ||
482 | |||
483 | /** | ||
484 | * Iterator for sensors and adds them to transmit context | ||
485 | * | ||
486 | * @param cls a 'struct GNUNET_SERVER_TransmitContext *' | ||
487 | * @param key hash of sensor name, key to hashmap | ||
488 | * @param value a 'struct SensorInfo *' | ||
489 | */ | ||
490 | int add_sensor_to_tc(void *cls, | ||
491 | const struct GNUNET_HashCode *key, void *value) | ||
492 | { | ||
493 | struct GNUNET_SERVER_TransmitContext *tc = cls; | ||
494 | struct SensorInfo *sensorinfo = value; | ||
495 | struct SensorInfoMessage *msg; | ||
496 | |||
497 | msg = create_sensor_info_msg(sensorinfo); | ||
498 | GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg); | ||
499 | |||
500 | GNUNET_free(msg); | ||
501 | |||
502 | return GNUNET_YES; | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * Handle GET ALL SENSORS message. | ||
507 | * | ||
508 | * @param cls closure | ||
509 | * @param client identification of the client | ||
510 | * @param message the actual message | ||
511 | */ | ||
512 | static void | ||
513 | handle_get_all_sensors (void *cls, struct GNUNET_SERVER_Client *client, | ||
514 | const struct GNUNET_MessageHeader *message) | ||
515 | { | ||
516 | struct GNUNET_SERVER_TransmitContext *tc; | ||
517 | |||
518 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received.\n", | ||
519 | "GET ALL SENSOR"); | ||
520 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
521 | GNUNET_CONTAINER_multihashmap_iterate(sensors, &add_sensor_to_tc, tc); | ||
522 | GNUNET_SERVER_transmit_context_append_data(tc, NULL, 0, GNUNET_MESSAGE_TYPE_SENSOR_END); | ||
523 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * Process statistics requests. | ||
528 | * | ||
529 | * @param cls closure | ||
530 | * @param server the initialized server | ||
531 | * @param c configuration to use | ||
532 | */ | ||
533 | static void | ||
534 | run (void *cls, | ||
535 | struct GNUNET_SERVER_Handle *server, | ||
536 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
537 | { | ||
538 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
539 | {&handle_get_sensor, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GET, | ||
540 | sizeof (struct GNUNET_MessageHeader)}, | ||
541 | {&handle_get_all_sensors, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GETALL, | ||
542 | 0}, | ||
543 | {NULL, NULL, 0, 0} | ||
544 | }; | ||
545 | |||
546 | cfg = c; | ||
547 | sensors = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO); | ||
548 | reload_sensors(); | ||
549 | GNUNET_SERVER_add_handlers (server, handlers); | ||
550 | GNUNET_SERVER_disconnect_notify (server, | ||
551 | &handle_client_disconnect, | ||
552 | NULL); | ||
553 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
554 | &shutdown_task, | ||
555 | NULL); | ||
556 | } | ||
557 | |||
558 | |||
559 | /** | ||
560 | * The main function for the sensor service. | ||
561 | * | ||
562 | * @param argc number of arguments from the command line | ||
563 | * @param argv command line arguments | ||
564 | * @return 0 ok, 1 on error | ||
565 | */ | ||
566 | int | ||
567 | main (int argc, char *const *argv) | ||
568 | { | ||
569 | return (GNUNET_OK == | ||
570 | GNUNET_SERVICE_run (argc, | ||
571 | argv, | ||
572 | "sensor", | ||
573 | GNUNET_SERVICE_OPTION_NONE, | ||
574 | &run, NULL)) ? 0 : 1; | ||
575 | } | ||
576 | |||
577 | /* end of gnunet-service-sensor.c */ | ||
diff --git a/src/sensor/sensor.conf.in b/src/sensor/sensor.conf.in new file mode 100644 index 000000000..c1978ef8d --- /dev/null +++ b/src/sensor/sensor.conf.in | |||
@@ -0,0 +1,7 @@ | |||
1 | [sensor] | ||
2 | BINARY = gnunet-service-sensor | ||
3 | UNIXPATH = /tmp/gnunet-service-sensor.sock | ||
4 | HOME = $SERVICEHOME | ||
5 | # PORT = 2106 | ||
6 | @UNIXONLY@ PORT = 2087 | ||
7 | |||
diff --git a/src/sensor/sensor.h b/src/sensor/sensor.h new file mode 100644 index 000000000..014eb5214 --- /dev/null +++ b/src/sensor/sensor.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2012-2013 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 | * @file sensor/sensor.h | ||
22 | * @brief example IPC messages between SENSOR API and GNS service | ||
23 | * @author Omar Tarabai | ||
24 | */ | ||
25 | |||
26 | #include "gnunet_sensor_service.h" | ||
27 | |||
28 | |||
29 | GNUNET_NETWORK_STRUCT_BEGIN | ||
30 | |||
31 | /** | ||
32 | * Carries a summary of a sensor | ||
33 | * | ||
34 | */ | ||
35 | struct SensorInfoMessage | ||
36 | { | ||
37 | /** | ||
38 | * Message header | ||
39 | */ | ||
40 | struct GNUNET_MessageHeader header; | ||
41 | |||
42 | /** | ||
43 | * Length of sensor name (name follows the struct) | ||
44 | */ | ||
45 | size_t name_len; | ||
46 | |||
47 | /** | ||
48 | * First part of version number | ||
49 | */ | ||
50 | uint16_t version_major; | ||
51 | |||
52 | /** | ||
53 | * Second part of version number | ||
54 | */ | ||
55 | uint16_t version_minor; | ||
56 | |||
57 | /** | ||
58 | * Length of sensor description (description itself follows) | ||
59 | */ | ||
60 | size_t description_len; | ||
61 | }; | ||
62 | |||
63 | GNUNET_NETWORK_STRUCT_END | ||
diff --git a/src/sensor/sensor_api.c b/src/sensor/sensor_api.c new file mode 100644 index 000000000..19ead13b3 --- /dev/null +++ b/src/sensor/sensor_api.c | |||
@@ -0,0 +1,627 @@ | |||
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_api.c | ||
23 | * @brief API for sensor | ||
24 | * @author Omar Tarabai | ||
25 | */ | ||
26 | #include <gnunet/platform.h> | ||
27 | #include <gnunet/gnunet_util_lib.h> | ||
28 | #include "sensor.h" | ||
29 | |||
30 | #define LOG(kind,...) GNUNET_log_from (kind, "sensor-api",__VA_ARGS__) | ||
31 | |||
32 | /******************************************************************************/ | ||
33 | /************************ DATA STRUCTURES ****************************/ | ||
34 | /******************************************************************************/ | ||
35 | |||
36 | /** | ||
37 | * Handle to the sensor service. | ||
38 | */ | ||
39 | struct GNUNET_SENSOR_Handle | ||
40 | { | ||
41 | |||
42 | /** | ||
43 | * Our configuration. | ||
44 | */ | ||
45 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
46 | |||
47 | /** | ||
48 | * Connection to the service. | ||
49 | */ | ||
50 | struct GNUNET_CLIENT_Connection *client; | ||
51 | |||
52 | /** | ||
53 | * Head of transmission queue. | ||
54 | */ | ||
55 | struct GNUNET_SENSOR_RequestContext *rc_head; | ||
56 | |||
57 | /** | ||
58 | * Tail of transmission queue. | ||
59 | */ | ||
60 | struct GNUNET_SENSOR_RequestContext *rc_tail; | ||
61 | |||
62 | /** | ||
63 | * Handle for the current transmission request, or NULL if none is pending. | ||
64 | */ | ||
65 | struct GNUNET_CLIENT_TransmitHandle *th; | ||
66 | |||
67 | /** | ||
68 | * Head of iterator DLL. | ||
69 | */ | ||
70 | struct GNUNET_SENSOR_SensorIteratorContext *ic_head; | ||
71 | |||
72 | /** | ||
73 | * Tail of iterator DLL. | ||
74 | */ | ||
75 | struct GNUNET_SENSOR_SensorIteratorContext *ic_tail; | ||
76 | |||
77 | /** | ||
78 | * ID for a reconnect task. | ||
79 | */ | ||
80 | GNUNET_SCHEDULER_TaskIdentifier r_task; | ||
81 | |||
82 | /** | ||
83 | * Are we now receiving? | ||
84 | */ | ||
85 | int in_receive; | ||
86 | |||
87 | }; | ||
88 | |||
89 | /** | ||
90 | * Entry in the transmission queue to SENSOR service. | ||
91 | * | ||
92 | */ | ||
93 | struct GNUNET_SENSOR_RequestContext | ||
94 | { | ||
95 | /** | ||
96 | * This is a linked list. | ||
97 | */ | ||
98 | struct GNUNET_SENSOR_RequestContext *next; | ||
99 | |||
100 | /** | ||
101 | * This is a linked list. | ||
102 | */ | ||
103 | struct GNUNET_SENSOR_RequestContext *prev; | ||
104 | |||
105 | /** | ||
106 | * Handle to the SENSOR service. | ||
107 | */ | ||
108 | struct GNUNET_SENSOR_Handle *h; | ||
109 | |||
110 | /** | ||
111 | * Function to call after request has been transmitted, or NULL. | ||
112 | */ | ||
113 | GNUNET_SENSOR_Continuation cont; | ||
114 | |||
115 | /** | ||
116 | * Closure for 'cont'. | ||
117 | */ | ||
118 | void *cont_cls; | ||
119 | |||
120 | /** | ||
121 | * Number of bytes of the request message (follows after this struct). | ||
122 | */ | ||
123 | size_t size; | ||
124 | |||
125 | }; | ||
126 | |||
127 | /** | ||
128 | * Context for an iteration request. | ||
129 | */ | ||
130 | struct GNUNET_SENSOR_SensorIteratorContext | ||
131 | { | ||
132 | |||
133 | /** | ||
134 | * Kept in a DLL. | ||
135 | */ | ||
136 | struct GNUNET_SENSOR_SensorIteratorContext *next; | ||
137 | |||
138 | /** | ||
139 | * Kept in a DLL. | ||
140 | */ | ||
141 | struct GNUNET_SENSOR_SensorIteratorContext *prev; | ||
142 | |||
143 | /** | ||
144 | * Handle to the SENSOR service. | ||
145 | */ | ||
146 | struct GNUNET_SENSOR_Handle *h; | ||
147 | |||
148 | /** | ||
149 | * Function to call with the results. | ||
150 | */ | ||
151 | GNUNET_SENSOR_SensorIteratorCB callback; | ||
152 | |||
153 | /** | ||
154 | * Closure for 'callback'. | ||
155 | */ | ||
156 | void *callback_cls; | ||
157 | |||
158 | /** | ||
159 | * Our entry in the transmission queue. | ||
160 | */ | ||
161 | struct GNUNET_SENSOR_RequestContext *rc; | ||
162 | |||
163 | /** | ||
164 | * Task responsible for timeout. | ||
165 | */ | ||
166 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
167 | |||
168 | /** | ||
169 | * Timeout for the operation. | ||
170 | */ | ||
171 | struct GNUNET_TIME_Absolute timeout; | ||
172 | |||
173 | /** | ||
174 | * Set to GNUNET_YES if we are currently receiving replies from the | ||
175 | * service. | ||
176 | */ | ||
177 | int request_transmitted; | ||
178 | |||
179 | }; | ||
180 | |||
181 | /******************************************************************************/ | ||
182 | /*********************** DECLARATIONS *************************/ | ||
183 | /******************************************************************************/ | ||
184 | |||
185 | /** | ||
186 | * Close the existing connection to SENSOR and reconnect. | ||
187 | * | ||
188 | * @param h handle to the service | ||
189 | */ | ||
190 | static void | ||
191 | reconnect (struct GNUNET_SENSOR_Handle *h); | ||
192 | |||
193 | /** | ||
194 | * Check if we have a request pending in the transmission queue and are | ||
195 | * able to transmit it right now. If so, schedule transmission. | ||
196 | * | ||
197 | * @param h handle to the service | ||
198 | */ | ||
199 | static void | ||
200 | trigger_transmit (struct GNUNET_SENSOR_Handle *h); | ||
201 | |||
202 | /******************************************************************************/ | ||
203 | /******************* CONNECTION FUNCTIONS *********************/ | ||
204 | /******************************************************************************/ | ||
205 | |||
206 | /** | ||
207 | * Connect to the sensor service. | ||
208 | * | ||
209 | * @return NULL on error | ||
210 | */ | ||
211 | struct GNUNET_SENSOR_Handle * | ||
212 | GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
213 | { | ||
214 | struct GNUNET_CLIENT_Connection *client; | ||
215 | struct GNUNET_SENSOR_Handle *h; | ||
216 | |||
217 | client = GNUNET_CLIENT_connect ("sensor", cfg); | ||
218 | if(NULL == client) | ||
219 | return NULL; | ||
220 | h = GNUNET_new (struct GNUNET_SENSOR_Handle); | ||
221 | h->client = client; | ||
222 | h->cfg = cfg; | ||
223 | return h; | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * Disconnect from the sensor service | ||
228 | * | ||
229 | * @param h handle to disconnect | ||
230 | */ | ||
231 | void | ||
232 | GNUNET_SENSOR_disconnect(struct GNUNET_SENSOR_Handle *h) | ||
233 | { | ||
234 | if (NULL != h->client) | ||
235 | { | ||
236 | GNUNET_CLIENT_disconnect (h->client); | ||
237 | h->client = NULL; | ||
238 | } | ||
239 | GNUNET_free (h); | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * Task scheduled to re-try connecting to the sensor service. | ||
244 | * | ||
245 | * @param cls the 'struct GNUNET_SENSOR_Handle' | ||
246 | * @param tc scheduler context | ||
247 | */ | ||
248 | static void | ||
249 | reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
250 | { | ||
251 | struct GNUNET_SENSOR_Handle *h = cls; | ||
252 | |||
253 | h->r_task = GNUNET_SCHEDULER_NO_TASK; | ||
254 | reconnect (h); | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * Close the existing connection to SENSOR and reconnect. | ||
259 | * | ||
260 | * @param h handle to the service | ||
261 | */ | ||
262 | static void | ||
263 | reconnect (struct GNUNET_SENSOR_Handle *h) | ||
264 | { | ||
265 | if (GNUNET_SCHEDULER_NO_TASK != h->r_task) | ||
266 | { | ||
267 | GNUNET_SCHEDULER_cancel (h->r_task); | ||
268 | h->r_task = GNUNET_SCHEDULER_NO_TASK; | ||
269 | } | ||
270 | if (NULL != h->th) | ||
271 | { | ||
272 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); | ||
273 | h->th = NULL; | ||
274 | } | ||
275 | if (NULL != h->client) | ||
276 | { | ||
277 | GNUNET_CLIENT_disconnect (h->client); | ||
278 | h->client = NULL; | ||
279 | } | ||
280 | h->in_receive = GNUNET_NO; | ||
281 | h->client = GNUNET_CLIENT_connect ("sensor", h->cfg); | ||
282 | if (NULL == h->client) | ||
283 | { | ||
284 | h->r_task = | ||
285 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, | ||
286 | h); | ||
287 | return; | ||
288 | } | ||
289 | trigger_transmit (h); | ||
290 | } | ||
291 | |||
292 | /******************************************************************************/ | ||
293 | /****************** SENSOR DATA FUNCTIONS *********************/ | ||
294 | /******************************************************************************/ | ||
295 | |||
296 | /** | ||
297 | * Cancel an iteration over sensor information. | ||
298 | * | ||
299 | * @param ic context of the iterator to cancel | ||
300 | */ | ||
301 | void | ||
302 | GNUNET_SENSOR_iterate_sensor_cancel (struct GNUNET_SENSOR_SensorIteratorContext *ic) | ||
303 | { | ||
304 | struct GNUNET_SENSOR_Handle *h; | ||
305 | |||
306 | h = ic->h; | ||
307 | if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task) | ||
308 | { | ||
309 | GNUNET_SCHEDULER_cancel (ic->timeout_task); | ||
310 | ic->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
311 | } | ||
312 | ic->callback = NULL; | ||
313 | if (GNUNET_YES == ic->request_transmitted) | ||
314 | return; /* need to finish processing */ | ||
315 | GNUNET_CONTAINER_DLL_remove (h->ic_head, | ||
316 | h->ic_tail, | ||
317 | ic); | ||
318 | if (NULL != ic->rc) | ||
319 | { | ||
320 | GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, ic->rc); | ||
321 | GNUNET_free (ic->rc); | ||
322 | } | ||
323 | GNUNET_free (ic); | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * Iteration request has timed out. | ||
328 | * | ||
329 | * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*' | ||
330 | * @param tc scheduler context | ||
331 | */ | ||
332 | static void | ||
333 | signal_sensor_iteration_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
334 | { | ||
335 | struct GNUNET_SENSOR_SensorIteratorContext *ic = cls; | ||
336 | GNUNET_SENSOR_SensorIteratorCB cb; | ||
337 | void *cb_cls; | ||
338 | |||
339 | ic->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
340 | cb = ic->callback; | ||
341 | cb_cls = ic->callback_cls; | ||
342 | GNUNET_SENSOR_iterate_sensor_cancel (ic); | ||
343 | if (NULL != cb) | ||
344 | cb (cb_cls, NULL, | ||
345 | _("Timeout transmitting iteration request to `SENSOR' service.")); | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * Type of a function to call when we receive a message from the | ||
350 | * service. Call the iterator with the result and (if applicable) | ||
351 | * continue to receive more messages or trigger processing the next | ||
352 | * event (if applicable). | ||
353 | * | ||
354 | * @param cls closure | ||
355 | * @param msg message received, NULL on timeout or fatal error | ||
356 | */ | ||
357 | static void | ||
358 | sensor_handler(void *cls, const struct GNUNET_MessageHeader *msg) | ||
359 | { | ||
360 | struct GNUNET_SENSOR_Handle *h = cls; | ||
361 | struct GNUNET_SENSOR_SensorIteratorContext *ic = h->ic_head; | ||
362 | GNUNET_SENSOR_SensorIteratorCB cb; | ||
363 | void *cb_cls; | ||
364 | uint16_t ms; | ||
365 | const struct SensorInfoMessage *im; | ||
366 | struct SensorInfoShort *sensor; | ||
367 | size_t name_len; | ||
368 | size_t desc_len; | ||
369 | |||
370 | |||
371 | h->in_receive = GNUNET_NO; | ||
372 | if (NULL == msg) | ||
373 | { | ||
374 | /* sensor service died, signal error */ | ||
375 | if (NULL != ic) | ||
376 | { | ||
377 | cb = ic->callback; | ||
378 | cb_cls = ic->callback_cls; | ||
379 | GNUNET_SENSOR_iterate_sensor_cancel(ic); | ||
380 | } | ||
381 | else | ||
382 | { | ||
383 | cb = NULL; | ||
384 | } | ||
385 | reconnect (h); | ||
386 | if (NULL != cb) | ||
387 | cb (cb_cls, NULL, | ||
388 | _("Failed to receive response from `SENSOR' service.")); | ||
389 | return; | ||
390 | } | ||
391 | if (NULL == ic) | ||
392 | { | ||
393 | /* didn't expect a response, reconnect */ | ||
394 | reconnect (h); | ||
395 | return; | ||
396 | } | ||
397 | ic->request_transmitted = GNUNET_NO; | ||
398 | cb = ic->callback; | ||
399 | cb_cls = ic->callback_cls; | ||
400 | if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (msg->type)) | ||
401 | { | ||
402 | /* normal end of list of sensors, signal end, process next pending request */ | ||
403 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
404 | "Received end of list of sensors from `%s' service\n", "SENSOR"); | ||
405 | GNUNET_SENSOR_iterate_sensor_cancel(ic); | ||
406 | trigger_transmit (h); | ||
407 | if ( (GNUNET_NO == h->in_receive) && | ||
408 | (NULL != h->ic_head) ) | ||
409 | { | ||
410 | h->in_receive = GNUNET_YES; | ||
411 | GNUNET_CLIENT_receive (h->client, &sensor_handler, h, | ||
412 | GNUNET_TIME_absolute_get_remaining (h->ic_head->timeout)); | ||
413 | } | ||
414 | if (NULL != cb) | ||
415 | cb (cb_cls, NULL, NULL); | ||
416 | return; | ||
417 | } | ||
418 | ms = ntohs (msg->size); | ||
419 | im = (const struct SensorInfoMessage *) msg; | ||
420 | name_len = ntohs(im->name_len); | ||
421 | desc_len = ntohs(im->description_len); | ||
422 | if ((ms != sizeof (struct SensorInfoMessage) + name_len + desc_len) || | ||
423 | (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_SENSOR_INFO)) | ||
424 | { | ||
425 | /* malformed message */ | ||
426 | GNUNET_break (0); | ||
427 | GNUNET_SENSOR_iterate_sensor_cancel(ic); | ||
428 | reconnect (h); | ||
429 | if (NULL != cb) | ||
430 | cb (cb_cls, NULL, | ||
431 | _("Received invalid message from `SENSOR' service.")); | ||
432 | return; | ||
433 | } | ||
434 | sensor = GNUNET_new(struct SensorInfoShort); | ||
435 | sensor->name = GNUNET_strndup((char *)&im[1], name_len); | ||
436 | if(desc_len > 0) | ||
437 | sensor->description = GNUNET_strndup((char *)((&im[1]) + name_len), desc_len); | ||
438 | sensor->version_major = ntohs(im->version_major); | ||
439 | sensor->version_minor = ntohs(im->version_minor); | ||
440 | h->in_receive = GNUNET_YES; | ||
441 | GNUNET_CLIENT_receive (h->client, &sensor_handler, h, | ||
442 | GNUNET_TIME_absolute_get_remaining (ic->timeout)); | ||
443 | if (NULL != cb) | ||
444 | cb (cb_cls, sensor, NULL); | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * We've transmitted the iteration request. Now get ready to process | ||
449 | * the results (or handle transmission error). | ||
450 | * | ||
451 | * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext' | ||
452 | * @param emsg error message, NULL if transmission worked | ||
453 | */ | ||
454 | static void | ||
455 | sensor_iterator_start_receive (void *cls, const char *emsg) | ||
456 | { | ||
457 | struct GNUNET_SENSOR_SensorIteratorContext *ic = cls; | ||
458 | struct GNUNET_SENSOR_Handle *h = ic->h; | ||
459 | GNUNET_SENSOR_SensorIteratorCB cb; | ||
460 | void *cb_cls; | ||
461 | |||
462 | ic->rc = NULL; | ||
463 | if (NULL != emsg) | ||
464 | { | ||
465 | cb = ic->callback; | ||
466 | cb_cls = ic->callback_cls; | ||
467 | GNUNET_SENSOR_iterate_sensor_cancel (ic); | ||
468 | reconnect (h); | ||
469 | if (NULL != cb) | ||
470 | cb (cb_cls, NULL, emsg); | ||
471 | return; | ||
472 | } | ||
473 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n", | ||
474 | "SENSOR"); | ||
475 | ic->request_transmitted = GNUNET_YES; | ||
476 | if (GNUNET_NO == h->in_receive) | ||
477 | { | ||
478 | h->in_receive = GNUNET_YES; | ||
479 | GNUNET_CLIENT_receive (h->client, &sensor_handler, h, | ||
480 | GNUNET_TIME_absolute_get_remaining (ic->timeout)); | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * Transmit the request at the head of the transmission queue | ||
486 | * and trigger continuation (if any). | ||
487 | * | ||
488 | * @param cls the 'struct GNUNET_SENSOR_Handle' (with the queue) | ||
489 | * @param size size of the buffer (0 on error) | ||
490 | * @param buf where to copy the message | ||
491 | * @return number of bytes copied to buf | ||
492 | */ | ||
493 | static size_t | ||
494 | do_transmit (void *cls, size_t size, void *buf) | ||
495 | { | ||
496 | struct GNUNET_SENSOR_Handle *h = cls; | ||
497 | struct GNUNET_SENSOR_RequestContext *rc = h->rc_head; | ||
498 | size_t ret; | ||
499 | |||
500 | h->th = NULL; | ||
501 | if (NULL == rc) | ||
502 | return 0; /* request was cancelled in the meantime */ | ||
503 | if (NULL == buf) | ||
504 | { | ||
505 | /* sensor service died */ | ||
506 | LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
507 | "Failed to transmit message to `%s' service.\n", "SENSOR"); | ||
508 | GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc); | ||
509 | reconnect (h); | ||
510 | if (NULL != rc->cont) | ||
511 | rc->cont (rc->cont_cls, _("failed to transmit request (service down?)")); | ||
512 | GNUNET_free (rc); | ||
513 | return 0; | ||
514 | } | ||
515 | ret = rc->size; | ||
516 | if (size < ret) | ||
517 | { | ||
518 | /* change in head of queue (i.e. cancel + add), try again */ | ||
519 | trigger_transmit (h); | ||
520 | return 0; | ||
521 | } | ||
522 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
523 | "Transmitting request of size %u to `%s' service.\n", ret, "SENSOR"); | ||
524 | memcpy (buf, &rc[1], ret); | ||
525 | GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc); | ||
526 | trigger_transmit (h); | ||
527 | if (NULL != rc->cont) | ||
528 | rc->cont (rc->cont_cls, NULL); | ||
529 | GNUNET_free (rc); | ||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * Check if we have a request pending in the transmission queue and are | ||
535 | * able to transmit it right now. If so, schedule transmission. | ||
536 | * | ||
537 | * @param h handle to the service | ||
538 | */ | ||
539 | static void | ||
540 | trigger_transmit (struct GNUNET_SENSOR_Handle *h) | ||
541 | { | ||
542 | struct GNUNET_SENSOR_RequestContext *rc; | ||
543 | |||
544 | if (NULL == (rc = h->rc_head)) | ||
545 | return; /* no requests queued */ | ||
546 | if (NULL != h->th) | ||
547 | return; /* request already pending */ | ||
548 | if (NULL == h->client) | ||
549 | { | ||
550 | /* disconnected, try to reconnect */ | ||
551 | reconnect (h); | ||
552 | return; | ||
553 | } | ||
554 | h->th = | ||
555 | GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size, | ||
556 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
557 | GNUNET_YES, | ||
558 | &do_transmit, h); | ||
559 | } | ||
560 | |||
561 | /** | ||
562 | * Client asking to iterate all available sensors | ||
563 | * | ||
564 | * @param h Handle to SENSOR service | ||
565 | * @param timeout how long to wait until timing out | ||
566 | * @param sensorname information on one sensor only, can be NULL to get all | ||
567 | * @param sensorname_len length of the sensorname parameter | ||
568 | * @param callback the method to call for each sensor | ||
569 | * @param callback_cls closure for callback | ||
570 | * @return iterator context | ||
571 | */ | ||
572 | struct GNUNET_SENSOR_SensorIteratorContext * | ||
573 | GNUNET_SENSOR_iterate_sensors (struct GNUNET_SENSOR_Handle *h, | ||
574 | struct GNUNET_TIME_Relative timeout, | ||
575 | const char* sensorname, size_t sensorname_len, | ||
576 | GNUNET_SENSOR_SensorIteratorCB callback, void *callback_cls) | ||
577 | { | ||
578 | struct GNUNET_SENSOR_SensorIteratorContext *ic; | ||
579 | struct GNUNET_SENSOR_RequestContext *rc; | ||
580 | struct GNUNET_MessageHeader *mh; | ||
581 | |||
582 | ic = GNUNET_new (struct GNUNET_SENSOR_SensorIteratorContext); | ||
583 | if (NULL == sensorname) | ||
584 | { | ||
585 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
586 | "Requesting list of sensors from SENSOR service\n"); | ||
587 | rc = | ||
588 | GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) + | ||
589 | sizeof (struct GNUNET_MessageHeader)); | ||
590 | rc->size = sizeof (struct GNUNET_MessageHeader); | ||
591 | mh = (struct GNUNET_MessageHeader *) &rc[1]; | ||
592 | mh->size = htons(sizeof (struct GNUNET_MessageHeader)); | ||
593 | mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GETALL); | ||
594 | } | ||
595 | else | ||
596 | { | ||
597 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
598 | "Requesting information on sensor `%s' from SENSOR service\n", | ||
599 | sensorname); | ||
600 | rc = | ||
601 | GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) + | ||
602 | sizeof (struct GNUNET_MessageHeader) + | ||
603 | sensorname_len); | ||
604 | rc->size = sizeof (struct GNUNET_MessageHeader) + sensorname_len; | ||
605 | mh = (struct GNUNET_MessageHeader *) &rc[1]; | ||
606 | mh->size = htons(rc->size); | ||
607 | mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GET); | ||
608 | memcpy(&mh[1], sensorname, sensorname_len); | ||
609 | } | ||
610 | ic->h = h; | ||
611 | ic->rc = rc; | ||
612 | ic->callback = callback; | ||
613 | ic->callback_cls = callback_cls; | ||
614 | ic->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
615 | ic->timeout_task = | ||
616 | GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout, ic); | ||
617 | rc->cont = &sensor_iterator_start_receive; | ||
618 | rc->cont_cls = ic; | ||
619 | GNUNET_CONTAINER_DLL_insert_tail (h->rc_head, h->rc_tail, rc); | ||
620 | GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, | ||
621 | h->ic_tail, | ||
622 | ic); | ||
623 | trigger_transmit (h); | ||
624 | return ic; | ||
625 | } | ||
626 | |||
627 | /* end of sensor_api.c */ | ||
diff --git a/src/sensor/test_sensor_api.c b/src/sensor/test_sensor_api.c new file mode 100644 index 000000000..0967f2b3f --- /dev/null +++ b/src/sensor/test_sensor_api.c | |||
@@ -0,0 +1,84 @@ | |||
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 | * @file sensor/test_sensor_api.c | ||
22 | * @brief testcase for sensor_api.c | ||
23 | */ | ||
24 | #include <gnunet/platform.h> | ||
25 | #include <gnunet/gnunet_util_lib.h> | ||
26 | #include "gnunet_sensor_service.h" | ||
27 | |||
28 | |||
29 | static int ok = 1; | ||
30 | |||
31 | |||
32 | static void | ||
33 | run (void *cls, | ||
34 | char *const *args, | ||
35 | const char *cfgfile, | ||
36 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
37 | { | ||
38 | ok = 0; | ||
39 | } | ||
40 | |||
41 | |||
42 | static int | ||
43 | check () | ||
44 | { | ||
45 | char *const argv[] = { "test-sensor-api", NULL }; | ||
46 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
47 | GNUNET_GETOPT_OPTION_END | ||
48 | }; | ||
49 | struct GNUNET_OS_Process *proc; | ||
50 | char *path = GNUNET_OS_get_libexec_binary_path ( "gnunet-service-sensor"); | ||
51 | if (NULL == path) | ||
52 | { | ||
53 | fprintf (stderr, "Service executable not found `%s'\n", "gnunet-service-sensor"); | ||
54 | return -1; | ||
55 | } | ||
56 | |||
57 | proc = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL, | ||
58 | NULL, NULL, path, "gnunet-service-sensor", NULL); | ||
59 | |||
60 | GNUNET_free (path); | ||
61 | GNUNET_assert (NULL != proc); | ||
62 | GNUNET_PROGRAM_run (1, argv, "test-sensor-api", "nohelp", | ||
63 | options, &run, &ok); | ||
64 | if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) | ||
65 | { | ||
66 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
67 | ok = 1; | ||
68 | } | ||
69 | GNUNET_OS_process_wait (proc); | ||
70 | GNUNET_OS_process_destroy (proc); | ||
71 | return ok; | ||
72 | } | ||
73 | |||
74 | |||
75 | int | ||
76 | main (int argc, char *argv[]) | ||
77 | { | ||
78 | GNUNET_log_setup ("test_statistics_api", | ||
79 | "WARNING", | ||
80 | NULL); | ||
81 | return check (); | ||
82 | } | ||
83 | |||
84 | /* end of test_sensor_api.c */ | ||