diff options
Diffstat (limited to 'src/statistics')
-rw-r--r-- | src/statistics/Makefile.am | 59 | ||||
-rw-r--r-- | src/statistics/gnunet-service-statistics.c | 470 | ||||
-rw-r--r-- | src/statistics/gnunet-statistics.c | 179 | ||||
-rw-r--r-- | src/statistics/statistics.h | 94 | ||||
-rw-r--r-- | src/statistics/statistics_api.c | 688 | ||||
-rwxr-xr-x | src/statistics/test_gnunet_statistics.sh | 177 | ||||
-rw-r--r-- | src/statistics/test_statistics_api.c | 177 | ||||
-rw-r--r-- | src/statistics/test_statistics_api_data.conf | 5 |
8 files changed, 1849 insertions, 0 deletions
diff --git a/src/statistics/Makefile.am b/src/statistics/Makefile.am new file mode 100644 index 000000000..2ae254cbf --- /dev/null +++ b/src/statistics/Makefile.am | |||
@@ -0,0 +1,59 @@ | |||
1 | INCLUDES = -I$(top_srcdir)/src/include | ||
2 | |||
3 | if MINGW | ||
4 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
5 | endif | ||
6 | |||
7 | if USE_COVERAGE | ||
8 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
9 | endif | ||
10 | |||
11 | |||
12 | lib_LTLIBRARIES = libgnunetstatistics.la | ||
13 | |||
14 | libgnunetstatistics_la_SOURCES = \ | ||
15 | statistics_api.c statistics.h | ||
16 | libgnunetstatistics_la_LIBADD = \ | ||
17 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
18 | $(GN_LIBINTL) | ||
19 | libgnunetstatistics_la_LDFLAGS = \ | ||
20 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
21 | -version-info 0:0:0 | ||
22 | |||
23 | |||
24 | bin_PROGRAMS = \ | ||
25 | gnunet-statistics \ | ||
26 | gnunet-service-statistics | ||
27 | |||
28 | gnunet_statistics_SOURCES = \ | ||
29 | gnunet-statistics.c | ||
30 | gnunet_statistics_LDADD = \ | ||
31 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
32 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
33 | $(GN_LIBINTL) | ||
34 | |||
35 | gnunet_service_statistics_SOURCES = \ | ||
36 | gnunet-service-statistics.c | ||
37 | gnunet_service_statistics_LDADD = \ | ||
38 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
39 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
40 | $(GN_LIBINTL) | ||
41 | |||
42 | |||
43 | check_PROGRAMS = \ | ||
44 | test_statistics_api | ||
45 | |||
46 | TESTS = $(check_PROGRAMS) $(check_SCRIPTS) | ||
47 | |||
48 | test_statistics_api_SOURCES = \ | ||
49 | test_statistics_api.c | ||
50 | test_statistics_api_LDADD = \ | ||
51 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
52 | $(top_builddir)/src/util/libgnunetutil.la | ||
53 | |||
54 | EXTRA_DIST = \ | ||
55 | test_statistics_api_data.conf | ||
56 | |||
57 | check_SCRIPTS = \ | ||
58 | test_gnunet_statistics.sh | ||
59 | |||
diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c new file mode 100644 index 000000000..0e7b4853d --- /dev/null +++ b/src/statistics/gnunet-service-statistics.c | |||
@@ -0,0 +1,470 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, 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 statistics/gnunet-service-statistics.c | ||
23 | * @brief program that tracks statistics | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_disk_lib.h" | ||
28 | #include "gnunet_getopt_lib.h" | ||
29 | #include "gnunet_protocols.h" | ||
30 | #include "gnunet_service_lib.h" | ||
31 | #include "gnunet_statistics_service.h" | ||
32 | #include "gnunet_strings_lib.h" | ||
33 | #include "gnunet_time_lib.h" | ||
34 | #include "statistics.h" | ||
35 | |||
36 | /** | ||
37 | * Entry in the statistics list. | ||
38 | */ | ||
39 | struct StatsEntry | ||
40 | { | ||
41 | /** | ||
42 | * This is a linked list. | ||
43 | */ | ||
44 | struct StatsEntry *next; | ||
45 | |||
46 | /** | ||
47 | * Name of the service, points into the | ||
48 | * middle of msg. | ||
49 | */ | ||
50 | const char *service; | ||
51 | |||
52 | /** | ||
53 | * Name for the value, points into | ||
54 | * the middle of msg. | ||
55 | */ | ||
56 | const char *name; | ||
57 | |||
58 | /** | ||
59 | * Message that can be used to set this value, | ||
60 | * stored at the end of the memory used by | ||
61 | * this struct. | ||
62 | */ | ||
63 | struct GNUNET_STATISTICS_SetMessage *msg; | ||
64 | |||
65 | /** | ||
66 | * Our value. | ||
67 | */ | ||
68 | uint64_t value; | ||
69 | |||
70 | /** | ||
71 | * Unique ID. | ||
72 | */ | ||
73 | uint32_t uid; | ||
74 | |||
75 | /** | ||
76 | * Is this value persistent? | ||
77 | */ | ||
78 | int persistent; | ||
79 | |||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * Linked list of our active statistics. | ||
84 | */ | ||
85 | static struct StatsEntry *start; | ||
86 | |||
87 | /** | ||
88 | * Counter used to generate unique values. | ||
89 | */ | ||
90 | static uint32_t uidgen; | ||
91 | |||
92 | /** | ||
93 | * Load persistent values from disk. Disk format is | ||
94 | * exactly the same format that we also use for | ||
95 | * setting the values over the network. | ||
96 | */ | ||
97 | static void | ||
98 | load (struct GNUNET_SERVER_Handle *server, | ||
99 | struct GNUNET_CONFIGURATION_Handle *cfg) | ||
100 | { | ||
101 | char *fn; | ||
102 | int fd; | ||
103 | struct stat sb; | ||
104 | char *buf; | ||
105 | size_t off; | ||
106 | const struct GNUNET_MessageHeader *msg; | ||
107 | |||
108 | fn = GNUNET_DISK_get_home_filename (cfg, | ||
109 | "statistics", "statistics.data", NULL); | ||
110 | if (fn == NULL) | ||
111 | return; | ||
112 | if ((0 != stat (fn, &sb)) || (sb.st_size == 0)) | ||
113 | { | ||
114 | GNUNET_free (fn); | ||
115 | return; | ||
116 | } | ||
117 | fd = GNUNET_DISK_file_open (fn, O_RDONLY); | ||
118 | if (fd == -1) | ||
119 | { | ||
120 | GNUNET_free (fn); | ||
121 | return; | ||
122 | } | ||
123 | buf = mmap (NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); | ||
124 | if (MAP_FAILED == buf) | ||
125 | { | ||
126 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "mmap", fn); | ||
127 | GNUNET_break (0 == CLOSE (fd)); | ||
128 | GNUNET_free (fn); | ||
129 | return; | ||
130 | } | ||
131 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
132 | _("Loading %llu bytes of statistics from `%s'\n"), | ||
133 | (unsigned long long) sb.st_size, fn); | ||
134 | off = 0; | ||
135 | while (off + sizeof (struct GNUNET_MessageHeader) < sb.st_size) | ||
136 | { | ||
137 | msg = (const struct GNUNET_MessageHeader *) &buf[off]; | ||
138 | if ((ntohs (msg->size) + off > sb.st_size) || | ||
139 | (GNUNET_OK != GNUNET_SERVER_inject (server, NULL, msg))) | ||
140 | { | ||
141 | GNUNET_break (0); | ||
142 | break; | ||
143 | } | ||
144 | off += ntohs (msg->size); | ||
145 | } | ||
146 | GNUNET_break (0 == munmap (buf, sb.st_size)); | ||
147 | GNUNET_break (0 == CLOSE (fd)); | ||
148 | GNUNET_free (fn); | ||
149 | } | ||
150 | |||
151 | |||
152 | /** | ||
153 | * Write persistent statistics to disk. | ||
154 | * | ||
155 | * @param cls closure | ||
156 | * @param cfg configuration to use | ||
157 | */ | ||
158 | static void | ||
159 | save (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg) | ||
160 | { | ||
161 | struct StatsEntry *pos; | ||
162 | char *fn; | ||
163 | int fd; | ||
164 | uint16_t size; | ||
165 | unsigned long long total; | ||
166 | |||
167 | fd = -1; | ||
168 | fn = GNUNET_DISK_get_home_filename (cfg, | ||
169 | "statistics", "statistics.data", NULL); | ||
170 | if (fn != NULL) | ||
171 | fd = | ||
172 | GNUNET_DISK_file_open (fn, O_WRONLY | O_CREAT | O_TRUNC, | ||
173 | S_IRUSR | S_IWUSR); | ||
174 | total = 0; | ||
175 | while (NULL != (pos = start)) | ||
176 | { | ||
177 | start = pos->next; | ||
178 | if ((pos->persistent) && (fd != -1)) | ||
179 | { | ||
180 | size = htons (pos->msg->header.size); | ||
181 | if (size != WRITE (fd, pos->msg, size)) | ||
182 | { | ||
183 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
184 | "write", fn); | ||
185 | GNUNET_DISK_file_close (fn, fd); | ||
186 | fd = -1; | ||
187 | } | ||
188 | else | ||
189 | total += size; | ||
190 | } | ||
191 | GNUNET_free (pos); | ||
192 | } | ||
193 | if (fd != -1) | ||
194 | { | ||
195 | GNUNET_DISK_file_close (fn, fd); | ||
196 | if (total == 0) | ||
197 | GNUNET_break (0 == UNLINK (fn)); | ||
198 | else | ||
199 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
200 | _("Wrote %llu bytes of statistics to `%s'\n"), total, fn); | ||
201 | } | ||
202 | GNUNET_free_non_null (fn); | ||
203 | } | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Transmit the given stats value. | ||
208 | */ | ||
209 | static void | ||
210 | transmit (struct GNUNET_SERVER_TransmitContext *tc, | ||
211 | const struct StatsEntry *e) | ||
212 | { | ||
213 | struct GNUNET_STATISTICS_ReplyMessage *m; | ||
214 | struct GNUNET_MessageHeader *h; | ||
215 | size_t size; | ||
216 | uint16_t msize; | ||
217 | |||
218 | size = | ||
219 | sizeof (struct GNUNET_STATISTICS_ReplyMessage) + strlen (e->service) + 1 + | ||
220 | strlen (e->name) + 1; | ||
221 | GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
222 | msize = size - sizeof (struct GNUNET_MessageHeader); | ||
223 | m = GNUNET_malloc (size); | ||
224 | m->uid = htonl (e->uid); | ||
225 | if (e->persistent) | ||
226 | m->uid |= htonl (GNUNET_STATISTICS_PERSIST_BIT); | ||
227 | m->value = GNUNET_htonll (e->value); | ||
228 | size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); | ||
229 | GNUNET_assert (size == GNUNET_STRINGS_buffer_fill ((char *) &m[1], | ||
230 | size, | ||
231 | 2, e->service, e->name)); | ||
232 | #if DEBUG_STATISTICS | ||
233 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
234 | "Transmitting value for `%s:%s': %llu\n", | ||
235 | e->service, e->name, e->value); | ||
236 | #endif | ||
237 | h = &m->header; | ||
238 | GNUNET_SERVER_transmit_context_append (tc, | ||
239 | &h[1], | ||
240 | msize, | ||
241 | GNUNET_MESSAGE_TYPE_STATISTICS_VALUE); | ||
242 | GNUNET_free (m); | ||
243 | } | ||
244 | |||
245 | |||
246 | /** | ||
247 | * Does this entry match the request? | ||
248 | */ | ||
249 | static int | ||
250 | matches (const struct StatsEntry *e, const char *service, const char *name) | ||
251 | { | ||
252 | return ((0 == strlen (service)) || | ||
253 | (0 == strcmp (service, e->service))) | ||
254 | && ((0 == strlen (name)) || (0 == strcmp (name, e->name))); | ||
255 | } | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Handle GET-message. | ||
260 | * | ||
261 | * @param cls closure | ||
262 | * @param server the server handling the message | ||
263 | * @param client identification of the client | ||
264 | * @param message the actual message | ||
265 | * @return GNUNET_OK to keep the connection open, | ||
266 | * GNUNET_SYSERR to close it (signal serious error) | ||
267 | */ | ||
268 | static void | ||
269 | handle_get (void *cls, | ||
270 | struct GNUNET_SERVER_Handle *server, | ||
271 | struct GNUNET_SERVER_Client *client, | ||
272 | const struct GNUNET_MessageHeader *message) | ||
273 | { | ||
274 | char *service; | ||
275 | char *name; | ||
276 | struct StatsEntry *pos; | ||
277 | struct GNUNET_SERVER_TransmitContext *tc; | ||
278 | size_t size; | ||
279 | |||
280 | size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); | ||
281 | if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], | ||
282 | size, 2, &service, &name)) | ||
283 | { | ||
284 | GNUNET_break (0); | ||
285 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
286 | return; | ||
287 | } | ||
288 | #if DEBUG_STATISTICS | ||
289 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
290 | "Received request for statistics on `%s:%s'\n", | ||
291 | strlen (service) ? service : "*", strlen (name) ? name : "*"); | ||
292 | #endif | ||
293 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
294 | pos = start; | ||
295 | while (pos != NULL) | ||
296 | { | ||
297 | if (matches (pos, service, name)) | ||
298 | transmit (tc, pos); | ||
299 | pos = pos->next; | ||
300 | } | ||
301 | GNUNET_SERVER_transmit_context_append (tc, NULL, 0, | ||
302 | GNUNET_MESSAGE_TYPE_STATISTICS_END); | ||
303 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Handle SET-message. | ||
309 | * | ||
310 | * @param cls closure | ||
311 | * @param server the server handling the message | ||
312 | * @param client identification of the client | ||
313 | * @param message the actual message | ||
314 | */ | ||
315 | static void | ||
316 | handle_set (void *cls, | ||
317 | struct GNUNET_SERVER_Handle *server, | ||
318 | struct GNUNET_SERVER_Client *client, | ||
319 | const struct GNUNET_MessageHeader *message) | ||
320 | { | ||
321 | char *service; | ||
322 | char *name; | ||
323 | uint16_t msize; | ||
324 | uint16_t size; | ||
325 | const struct GNUNET_STATISTICS_SetMessage *msg; | ||
326 | struct StatsEntry *pos; | ||
327 | struct StatsEntry *prev; | ||
328 | uint32_t flags; | ||
329 | uint64_t value; | ||
330 | int64_t delta; | ||
331 | |||
332 | msize = ntohs (message->size); | ||
333 | if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) | ||
334 | { | ||
335 | GNUNET_break (0); | ||
336 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
337 | return; | ||
338 | } | ||
339 | size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage); | ||
340 | msg = (const struct GNUNET_STATISTICS_SetMessage *) message; | ||
341 | |||
342 | if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], | ||
343 | size, 2, &service, &name)) | ||
344 | { | ||
345 | GNUNET_break (0); | ||
346 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
347 | return; | ||
348 | } | ||
349 | #if DEBUG_STATISTICS | ||
350 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
351 | "Received request to update statistic on `%s:%s'\n", | ||
352 | service, name); | ||
353 | #endif | ||
354 | flags = ntohl (msg->flags); | ||
355 | value = GNUNET_ntohll (msg->value); | ||
356 | pos = start; | ||
357 | prev = NULL; | ||
358 | while (pos != NULL) | ||
359 | { | ||
360 | if (matches (pos, service, name)) | ||
361 | { | ||
362 | if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) | ||
363 | { | ||
364 | pos->value = value; | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | delta = (int64_t) value; | ||
369 | if ((delta < 0) && (pos->value < -delta)) | ||
370 | { | ||
371 | pos->value = 0; | ||
372 | } | ||
373 | else | ||
374 | { | ||
375 | GNUNET_break ((delta <= 0) || | ||
376 | (pos->value + delta > pos->value)); | ||
377 | pos->value += delta; | ||
378 | } | ||
379 | } | ||
380 | pos->msg->value = GNUNET_htonll (pos->value); | ||
381 | pos->msg->flags = msg->flags; | ||
382 | pos->persistent = | ||
383 | (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); | ||
384 | if (prev != NULL) | ||
385 | { | ||
386 | /* move to front for faster setting next time! */ | ||
387 | prev->next = pos->next; | ||
388 | pos->next = start; | ||
389 | start = pos; | ||
390 | } | ||
391 | #if DEBUG_STATISTICS | ||
392 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
393 | "Statistic `%s:%s' updated to value %llu.\n", | ||
394 | service, name, pos->value); | ||
395 | #endif | ||
396 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
397 | return; | ||
398 | } | ||
399 | prev = pos; | ||
400 | pos = pos->next; | ||
401 | } | ||
402 | pos = GNUNET_malloc (sizeof (struct StatsEntry) + msize); | ||
403 | pos->next = start; | ||
404 | if (((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) || | ||
405 | (0 < (int64_t) GNUNET_ntohll (msg->value))) | ||
406 | pos->value = GNUNET_ntohll (msg->value); | ||
407 | pos->uid = uidgen++; | ||
408 | pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); | ||
409 | pos->msg = (void *) &pos[1]; | ||
410 | memcpy (pos->msg, message, ntohs (message->size)); | ||
411 | pos->service = (const char *) &pos->msg[1]; | ||
412 | pos->name = &pos->service[strlen (pos->service) + 1]; | ||
413 | |||
414 | start = pos; | ||
415 | #if DEBUG_STATISTICS | ||
416 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
417 | "New statistic on `%s:%s' with value %llu created.\n", | ||
418 | service, name, pos->value); | ||
419 | #endif | ||
420 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
421 | } | ||
422 | |||
423 | |||
424 | /** | ||
425 | * List of handlers for the messages understood by this | ||
426 | * service. | ||
427 | */ | ||
428 | static struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
429 | {&handle_set, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_SET, 0}, | ||
430 | {&handle_get, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_GET, 0}, | ||
431 | {NULL, NULL, 0, 0} | ||
432 | }; | ||
433 | |||
434 | |||
435 | /** | ||
436 | * Process statistics requests. | ||
437 | * | ||
438 | * @param cls closure | ||
439 | * @param sched scheduler to use | ||
440 | * @param server the initialized server | ||
441 | * @param cfg configuration to use | ||
442 | */ | ||
443 | static void | ||
444 | run (void *cls, | ||
445 | struct GNUNET_SCHEDULER_Handle *sched, | ||
446 | struct GNUNET_SERVER_Handle *server, | ||
447 | struct GNUNET_CONFIGURATION_Handle *cfg) | ||
448 | { | ||
449 | GNUNET_SERVER_add_handlers (server, handlers); | ||
450 | load (server, cfg); | ||
451 | } | ||
452 | |||
453 | |||
454 | /** | ||
455 | * The main function for the statistics service. | ||
456 | * | ||
457 | * @param argc number of arguments from the command line | ||
458 | * @param argv command line arguments | ||
459 | * @return 0 ok, 1 on error | ||
460 | */ | ||
461 | int | ||
462 | main (int argc, char *const *argv) | ||
463 | { | ||
464 | return (GNUNET_OK == | ||
465 | GNUNET_SERVICE_run (argc, | ||
466 | argv, | ||
467 | "statistics", &run, NULL, &save, NULL)) ? 0 : 1; | ||
468 | } | ||
469 | |||
470 | /* end of gnunet-service-statistics.c */ | ||
diff --git a/src/statistics/gnunet-statistics.c b/src/statistics/gnunet-statistics.c new file mode 100644 index 000000000..bafb77c66 --- /dev/null +++ b/src/statistics/gnunet-statistics.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, 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 statistics/gnunet-statistics.c | ||
23 | * @brief tool to obtain statistics | ||
24 | * @author Christian Grothoff | ||
25 | * @author Igor Wronsky | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_getopt_lib.h" | ||
29 | #include "gnunet_program_lib.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "statistics.h" | ||
32 | |||
33 | #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
34 | |||
35 | /** | ||
36 | * Final status code. | ||
37 | */ | ||
38 | static int ret; | ||
39 | |||
40 | /** | ||
41 | * Set to subsystem that we're going to get stats for (or NULL for all). | ||
42 | */ | ||
43 | static char *subsystem; | ||
44 | |||
45 | /** | ||
46 | * Set to the specific stat value that we are after (or NULL for all). | ||
47 | */ | ||
48 | static char *name; | ||
49 | |||
50 | /** | ||
51 | * Make the value that is being set persistent. | ||
52 | */ | ||
53 | static int persistent; | ||
54 | |||
55 | /** | ||
56 | * Callback function to process statistic values. | ||
57 | * | ||
58 | * @param cls closure | ||
59 | * @param subsystem name of subsystem that created the statistic | ||
60 | * @param name the name of the datum | ||
61 | * @param value the current value | ||
62 | * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not | ||
63 | * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration | ||
64 | */ | ||
65 | static int | ||
66 | printer (void *cls, | ||
67 | const char *subsystem, | ||
68 | const char *sname, unsigned long long value, int is_persistent) | ||
69 | { | ||
70 | FPRINTF (stdout, | ||
71 | "%s%-20s %-40s: %16llu\n", | ||
72 | is_persistent ? "!" : " ", subsystem, _(sname), value); | ||
73 | return GNUNET_OK; | ||
74 | } | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Function called last by the statistics code. | ||
79 | * | ||
80 | * @param cls closure | ||
81 | * @param success GNUNET_OK if statistics were | ||
82 | * successfully obtained, GNUNET_SYSERR if not. | ||
83 | */ | ||
84 | static void | ||
85 | cleanup (void *cls, int success) | ||
86 | { | ||
87 | struct GNUNET_STATISTICS_Handle *h = cls; | ||
88 | |||
89 | if (success != GNUNET_OK) | ||
90 | ret = 1; | ||
91 | if (h != NULL) | ||
92 | GNUNET_STATISTICS_destroy (h); | ||
93 | } | ||
94 | |||
95 | |||
96 | /** | ||
97 | * Main function that will be run by the scheduler. | ||
98 | * | ||
99 | * @param cls closure | ||
100 | * @param sched the scheduler to use | ||
101 | * @param args remaining command-line arguments | ||
102 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
103 | * @param cfg configuration | ||
104 | */ | ||
105 | static void | ||
106 | run (void *cls, | ||
107 | struct GNUNET_SCHEDULER_Handle *sched, | ||
108 | char *const *args, | ||
109 | const char *cfgfile, struct GNUNET_CONFIGURATION_Handle *cfg) | ||
110 | { | ||
111 | struct GNUNET_STATISTICS_Handle *h; | ||
112 | unsigned long long val; | ||
113 | |||
114 | if (args[0] != NULL) | ||
115 | { | ||
116 | if ((1 != SSCANF (args[0], "%llu", &val)) || | ||
117 | (subsystem == NULL) || (name == NULL)) | ||
118 | { | ||
119 | FPRINTF (stderr, _("Invalid argument `%s'\n"), args[0]); | ||
120 | ret = 1; | ||
121 | return; | ||
122 | } | ||
123 | h = GNUNET_STATISTICS_create (sched, subsystem, cfg); | ||
124 | if (h == NULL) | ||
125 | { | ||
126 | ret = 1; | ||
127 | return; | ||
128 | } | ||
129 | GNUNET_STATISTICS_set (h, name, val, persistent); | ||
130 | GNUNET_STATISTICS_destroy (h); | ||
131 | return; | ||
132 | } | ||
133 | h = GNUNET_STATISTICS_create (sched, "gnunet-statistics", cfg); | ||
134 | if (h == NULL) | ||
135 | { | ||
136 | ret = 1; | ||
137 | return; | ||
138 | } | ||
139 | GNUNET_STATISTICS_get (h, | ||
140 | subsystem, name, GET_TIMEOUT, &cleanup, &printer, h); | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * gnunet-statistics command line options | ||
145 | */ | ||
146 | static struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
147 | {'n', "name", "NAME", | ||
148 | gettext_noop ("limit output to statistcs for the given NAME"), 1, | ||
149 | &GNUNET_GETOPT_set_string, &name}, | ||
150 | {'p', "persistent", NULL, | ||
151 | gettext_noop ("make the value being set persistent"), 0, | ||
152 | &GNUNET_GETOPT_set_one, &persistent}, | ||
153 | {'s', "subsystem", "SUBSYSTEM", | ||
154 | gettext_noop ("limit output to the given SUBSYSTEM"), 1, | ||
155 | &GNUNET_GETOPT_set_string, &subsystem}, | ||
156 | GNUNET_GETOPT_OPTION_END | ||
157 | }; | ||
158 | |||
159 | |||
160 | /** | ||
161 | * The main function to obtain statistics in GNUnet. | ||
162 | * | ||
163 | * @param argc number of arguments from the command line | ||
164 | * @param argv command line arguments | ||
165 | * @return 0 ok, 1 on error | ||
166 | */ | ||
167 | int | ||
168 | main (int argc, char *const *argv) | ||
169 | { | ||
170 | return (GNUNET_OK == | ||
171 | GNUNET_PROGRAM_run (argc, | ||
172 | argv, | ||
173 | "gnunet-statistics", | ||
174 | gettext_noop | ||
175 | ("Print statistics about GNUnet operations."), | ||
176 | options, &run, NULL)) ? ret : 1; | ||
177 | } | ||
178 | |||
179 | /* end of gnunet-statistics.c */ | ||
diff --git a/src/statistics/statistics.h b/src/statistics/statistics.h new file mode 100644 index 000000000..6eedd4d34 --- /dev/null +++ b/src/statistics/statistics.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, 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 | * @author Christian Grothoff | ||
23 | * @file statistics/statistics.h | ||
24 | */ | ||
25 | #ifndef STATISTICS_H | ||
26 | #define STATISTICS_H | ||
27 | |||
28 | #include "gnunet_common.h" | ||
29 | |||
30 | #define DEBUG_STATISTICS 0 | ||
31 | |||
32 | /** | ||
33 | * Statistics message. Contains how long the system is up | ||
34 | * and one value. | ||
35 | * | ||
36 | * The struct is be followed by the service name and | ||
37 | * name of the statistic, both 0-terminated. | ||
38 | */ | ||
39 | struct GNUNET_STATISTICS_ReplyMessage | ||
40 | { | ||
41 | /** | ||
42 | * Type: GNUNET_MESSAGE_TYPE_STATISTICS_VALUE | ||
43 | */ | ||
44 | struct GNUNET_MessageHeader header; | ||
45 | |||
46 | /** | ||
47 | * Unique numerical identifier for the value (will | ||
48 | * not change during the same client-session). Highest | ||
49 | * bit will be set for persistent values. | ||
50 | */ | ||
51 | uint32_t uid GNUNET_PACKED; | ||
52 | |||
53 | /** | ||
54 | * The value. | ||
55 | */ | ||
56 | uint64_t value GNUNET_PACKED; | ||
57 | |||
58 | }; | ||
59 | |||
60 | #define GNUNET_STATISTICS_PERSIST_BIT (1<<31) | ||
61 | |||
62 | #define GNUNET_STATISTICS_SETFLAG_ABSOLUTE 0 | ||
63 | |||
64 | #define GNUNET_STATISTICS_SETFLAG_RELATIVE 1 | ||
65 | |||
66 | #define GNUNET_STATISTICS_SETFLAG_PERSISTENT 2 | ||
67 | |||
68 | /** | ||
69 | * Message to set a statistic. Followed | ||
70 | * by the subsystem name and the name of | ||
71 | * the statistic (each 0-terminated). | ||
72 | */ | ||
73 | struct GNUNET_STATISTICS_SetMessage | ||
74 | { | ||
75 | /** | ||
76 | * Type: GNUNET_MESSAGE_TYPE_STATISTICS_SET | ||
77 | */ | ||
78 | struct GNUNET_MessageHeader header; | ||
79 | |||
80 | /** | ||
81 | * 0 for absolute value, 1 for relative value; 2 to make persistent | ||
82 | * (see GNUNET_STATISTICS_SETFLAG_*). | ||
83 | */ | ||
84 | uint32_t flags GNUNET_PACKED; | ||
85 | |||
86 | /** | ||
87 | * Value. Note that if this is a relative value, it will | ||
88 | * be signed even though the type given here is unsigned. | ||
89 | */ | ||
90 | uint64_t value GNUNET_PACKED; | ||
91 | |||
92 | }; | ||
93 | |||
94 | #endif | ||
diff --git a/src/statistics/statistics_api.c b/src/statistics/statistics_api.c new file mode 100644 index 000000000..f68cf9396 --- /dev/null +++ b/src/statistics/statistics_api.c | |||
@@ -0,0 +1,688 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, 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 statistics/statistics_api.c | ||
23 | * @brief API of the statistics service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_client_lib.h" | ||
28 | #include "gnunet_protocols.h" | ||
29 | #include "gnunet_server_lib.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "gnunet_strings_lib.h" | ||
32 | #include "statistics.h" | ||
33 | |||
34 | #define SET_TRANSMIT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Types of actions. | ||
39 | */ | ||
40 | enum ActionType | ||
41 | { | ||
42 | ACTION_GET, | ||
43 | ACTION_SET, | ||
44 | ACTION_UPDATE | ||
45 | }; | ||
46 | |||
47 | |||
48 | /** | ||
49 | * Linked list of things we still need to do. | ||
50 | */ | ||
51 | struct ActionItem | ||
52 | { | ||
53 | /** | ||
54 | * This is a linked list. | ||
55 | */ | ||
56 | struct ActionItem *next; | ||
57 | |||
58 | /** | ||
59 | * What subsystem is this action about? (can be NULL) | ||
60 | */ | ||
61 | char *subsystem; | ||
62 | |||
63 | /** | ||
64 | * What value is this action about? (can be NULL) | ||
65 | */ | ||
66 | char *name; | ||
67 | |||
68 | /** | ||
69 | * Continuation to call once action is complete. | ||
70 | */ | ||
71 | GNUNET_STATISTICS_Callback cont; | ||
72 | |||
73 | /** | ||
74 | * Function to call (for GET actions only). | ||
75 | */ | ||
76 | GNUNET_STATISTICS_Iterator proc; | ||
77 | |||
78 | /** | ||
79 | * Closure for proc and cont. | ||
80 | */ | ||
81 | void *cls; | ||
82 | |||
83 | /** | ||
84 | * Timeout for this action. | ||
85 | */ | ||
86 | struct GNUNET_TIME_Absolute timeout; | ||
87 | |||
88 | /** | ||
89 | * Associated value. | ||
90 | */ | ||
91 | unsigned long long value; | ||
92 | |||
93 | /** | ||
94 | * Flag for SET/UPDATE actions. | ||
95 | */ | ||
96 | int make_persistent; | ||
97 | |||
98 | /** | ||
99 | * Has the current iteration been aborted; for GET actions. | ||
100 | */ | ||
101 | int aborted; | ||
102 | |||
103 | /** | ||
104 | * Is this a GET, SET or UPDATE? | ||
105 | */ | ||
106 | enum ActionType type; | ||
107 | |||
108 | /** | ||
109 | * Size of the message that we will be transmitting. | ||
110 | */ | ||
111 | uint16_t msize; | ||
112 | |||
113 | }; | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Handle for the service. | ||
118 | */ | ||
119 | struct GNUNET_STATISTICS_Handle | ||
120 | { | ||
121 | /** | ||
122 | * Our scheduler. | ||
123 | */ | ||
124 | struct GNUNET_SCHEDULER_Handle *sched; | ||
125 | |||
126 | /** | ||
127 | * Name of our subsystem. | ||
128 | */ | ||
129 | char *subsystem; | ||
130 | |||
131 | /** | ||
132 | * Configuration to use. | ||
133 | */ | ||
134 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
135 | |||
136 | /** | ||
137 | * Socket (if available). | ||
138 | */ | ||
139 | struct GNUNET_CLIENT_Connection *client; | ||
140 | |||
141 | /** | ||
142 | * Head of the linked list of pending actions (first action | ||
143 | * to be performed). | ||
144 | */ | ||
145 | struct ActionItem *action_head; | ||
146 | |||
147 | /** | ||
148 | * Tail of the linked list of actions (for fast append). | ||
149 | */ | ||
150 | struct ActionItem *action_tail; | ||
151 | |||
152 | /** | ||
153 | * Action we are currently busy with (action request has been | ||
154 | * transmitted, we're now receiving the response from the | ||
155 | * service). | ||
156 | */ | ||
157 | struct ActionItem *current; | ||
158 | |||
159 | /** | ||
160 | * Should this handle be destroyed once we've processed | ||
161 | * all actions? | ||
162 | */ | ||
163 | int do_destroy; | ||
164 | |||
165 | }; | ||
166 | |||
167 | |||
168 | /** | ||
169 | * Try to (re)connect to the statistics service. | ||
170 | * | ||
171 | * @return GNUNET_YES on success, GNUNET_NO on failure. | ||
172 | */ | ||
173 | static int | ||
174 | try_connect (struct GNUNET_STATISTICS_Handle *ret) | ||
175 | { | ||
176 | if (ret->client != NULL) | ||
177 | return GNUNET_OK; | ||
178 | ret->client = GNUNET_CLIENT_connect (ret->sched, "statistics", ret->cfg); | ||
179 | if (ret->client != NULL) | ||
180 | return GNUNET_YES; | ||
181 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
182 | _("Failed to connect to statistics service!\n")); | ||
183 | return GNUNET_NO; | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Free memory associated with the given action item. | ||
189 | */ | ||
190 | static void | ||
191 | free_action_item (struct ActionItem *ai) | ||
192 | { | ||
193 | GNUNET_free_non_null (ai->subsystem); | ||
194 | GNUNET_free_non_null (ai->name); | ||
195 | GNUNET_free (ai); | ||
196 | } | ||
197 | |||
198 | |||
199 | /** | ||
200 | * Get handle for the statistics service. | ||
201 | * | ||
202 | * @param subsystem name of subsystem using the service | ||
203 | * @param cfg services configuration in use | ||
204 | * @return handle to use | ||
205 | */ | ||
206 | struct GNUNET_STATISTICS_Handle * | ||
207 | GNUNET_STATISTICS_create (struct GNUNET_SCHEDULER_Handle *sched, | ||
208 | const char *subsystem, | ||
209 | struct GNUNET_CONFIGURATION_Handle *cfg) | ||
210 | { | ||
211 | struct GNUNET_STATISTICS_Handle *ret; | ||
212 | |||
213 | GNUNET_assert (subsystem != NULL); | ||
214 | GNUNET_assert (sched != NULL); | ||
215 | GNUNET_assert (cfg != NULL); | ||
216 | ret = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_Handle)); | ||
217 | ret->sched = sched; | ||
218 | ret->cfg = cfg; | ||
219 | ret->subsystem = GNUNET_strdup (subsystem); | ||
220 | try_connect (ret); | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Actually free the handle. | ||
227 | */ | ||
228 | static void | ||
229 | do_destroy (struct GNUNET_STATISTICS_Handle *h) | ||
230 | { | ||
231 | GNUNET_assert (h->action_head == NULL); | ||
232 | GNUNET_assert (h->current == NULL); | ||
233 | if (h->client != NULL) | ||
234 | { | ||
235 | GNUNET_CLIENT_disconnect (h->client); | ||
236 | h->client = NULL; | ||
237 | } | ||
238 | GNUNET_free (h->subsystem); | ||
239 | GNUNET_free (h); | ||
240 | } | ||
241 | |||
242 | |||
243 | /** | ||
244 | * Destroy a handle (free all state associated with | ||
245 | * it). | ||
246 | */ | ||
247 | void | ||
248 | GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *handle) | ||
249 | { | ||
250 | GNUNET_assert (handle->do_destroy == GNUNET_NO); | ||
251 | if ((handle->action_head != NULL) || (handle->current != NULL)) | ||
252 | { | ||
253 | handle->do_destroy = GNUNET_YES; | ||
254 | return; | ||
255 | } | ||
256 | do_destroy (handle); | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Process the message. | ||
262 | * | ||
263 | * @return GNUNET_OK if the message was well-formed | ||
264 | */ | ||
265 | static int | ||
266 | process_message (struct GNUNET_STATISTICS_Handle *h, | ||
267 | const struct GNUNET_MessageHeader *msg) | ||
268 | { | ||
269 | char *service; | ||
270 | char *name; | ||
271 | const struct GNUNET_STATISTICS_ReplyMessage *smsg; | ||
272 | uint16_t size; | ||
273 | |||
274 | if (h->current->aborted) | ||
275 | return GNUNET_OK; /* don't bother */ | ||
276 | size = ntohs (msg->size); | ||
277 | if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage)) | ||
278 | { | ||
279 | GNUNET_break (0); | ||
280 | return GNUNET_SYSERR; | ||
281 | } | ||
282 | smsg = (const struct GNUNET_STATISTICS_ReplyMessage *) msg; | ||
283 | size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); | ||
284 | if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &smsg[1], | ||
285 | size, 2, &service, &name)) | ||
286 | { | ||
287 | GNUNET_break (0); | ||
288 | return GNUNET_SYSERR; | ||
289 | } | ||
290 | #if DEBUG_STATISTICS | ||
291 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
292 | "Received valid statistic on `%s:%s': %llu\n", | ||
293 | service, name, GNUNET_ntohll (smsg->value)); | ||
294 | #endif | ||
295 | if (GNUNET_OK != | ||
296 | h->current->proc (h->current->cls, | ||
297 | service, | ||
298 | name, | ||
299 | GNUNET_ntohll (smsg->value), | ||
300 | 0 != | ||
301 | (ntohl (smsg->uid) & GNUNET_STATISTICS_PERSIST_BIT))) | ||
302 | { | ||
303 | #if DEBUG_STATISTICS | ||
304 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
305 | "Processing of remaining statistics aborted by client.\n"); | ||
306 | #endif | ||
307 | h->current->aborted = GNUNET_YES; | ||
308 | } | ||
309 | return GNUNET_OK; | ||
310 | } | ||
311 | |||
312 | |||
313 | |||
314 | /** | ||
315 | * Schedule the next action to be performed. | ||
316 | */ | ||
317 | static void schedule_action (struct GNUNET_STATISTICS_Handle *h); | ||
318 | |||
319 | |||
320 | /** | ||
321 | * GET processing is complete, tell client about it. | ||
322 | */ | ||
323 | static void | ||
324 | finish (struct GNUNET_STATISTICS_Handle *h, int code) | ||
325 | { | ||
326 | struct ActionItem *pos = h->current; | ||
327 | h->current = NULL; | ||
328 | schedule_action (h); | ||
329 | if (pos->cont != NULL) | ||
330 | pos->cont (pos->cls, code); | ||
331 | free_action_item (pos); | ||
332 | } | ||
333 | |||
334 | |||
335 | /** | ||
336 | * Function called with messages from stats service. | ||
337 | * | ||
338 | * @param cls closure | ||
339 | * @param msg message received, NULL on timeout or fatal error | ||
340 | */ | ||
341 | static void | ||
342 | receive_stats (void *cls, const struct GNUNET_MessageHeader *msg) | ||
343 | { | ||
344 | struct GNUNET_STATISTICS_Handle *h = cls; | ||
345 | |||
346 | if (msg == NULL) | ||
347 | { | ||
348 | GNUNET_CLIENT_disconnect (h->client); | ||
349 | h->client = NULL; | ||
350 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, | ||
351 | _ | ||
352 | ("Error receiving statistics from service, is the service running?\n")); | ||
353 | finish (h, GNUNET_SYSERR); | ||
354 | return; | ||
355 | } | ||
356 | switch (ntohs (msg->type)) | ||
357 | { | ||
358 | case GNUNET_MESSAGE_TYPE_STATISTICS_END: | ||
359 | #if DEBUG_STATISTICS | ||
360 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
361 | "Received end of statistics marker\n"); | ||
362 | #endif | ||
363 | finish (h, GNUNET_OK); | ||
364 | return; | ||
365 | case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE: | ||
366 | if (GNUNET_OK == process_message (h, msg)) | ||
367 | { | ||
368 | /* finally, look for more! */ | ||
369 | GNUNET_CLIENT_receive (h->client, | ||
370 | &receive_stats, | ||
371 | h, | ||
372 | GNUNET_TIME_absolute_get_remaining (h-> | ||
373 | current-> | ||
374 | timeout)); | ||
375 | return; | ||
376 | } | ||
377 | GNUNET_break (0); | ||
378 | break; | ||
379 | default: | ||
380 | GNUNET_break (0); | ||
381 | break; | ||
382 | } | ||
383 | GNUNET_CLIENT_disconnect (h->client); | ||
384 | h->client = NULL; | ||
385 | finish (h, GNUNET_SYSERR); | ||
386 | } | ||
387 | |||
388 | |||
389 | /** | ||
390 | * Transmit a GET request (and if successful, start to receive | ||
391 | * the response). | ||
392 | */ | ||
393 | static size_t | ||
394 | transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) | ||
395 | { | ||
396 | struct GNUNET_MessageHeader *hdr; | ||
397 | size_t slen1; | ||
398 | size_t slen2; | ||
399 | uint16_t msize; | ||
400 | |||
401 | if (buf == NULL) | ||
402 | { | ||
403 | /* timeout / error */ | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
405 | _("Transmission of request for statistics failed!\n")); | ||
406 | finish (handle, GNUNET_SYSERR); | ||
407 | return 0; | ||
408 | } | ||
409 | slen1 = strlen (handle->current->subsystem) + 1; | ||
410 | slen2 = strlen (handle->current->name) + 1; | ||
411 | msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); | ||
412 | GNUNET_assert (msize <= size); | ||
413 | hdr = (struct GNUNET_MessageHeader *) buf; | ||
414 | hdr->size = htons (msize); | ||
415 | hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_GET); | ||
416 | GNUNET_assert (slen1 + slen2 == | ||
417 | GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], | ||
418 | slen1 + slen2, | ||
419 | 2, | ||
420 | handle->current->subsystem, | ||
421 | handle->current->name)); | ||
422 | GNUNET_CLIENT_receive (handle->client, | ||
423 | &receive_stats, | ||
424 | handle, | ||
425 | GNUNET_TIME_absolute_get_remaining (handle->current-> | ||
426 | timeout)); | ||
427 | return msize; | ||
428 | } | ||
429 | |||
430 | |||
431 | |||
432 | /** | ||
433 | * Transmit a SET/UPDATE request. | ||
434 | */ | ||
435 | static size_t | ||
436 | transmit_set (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) | ||
437 | { | ||
438 | struct GNUNET_STATISTICS_SetMessage *r; | ||
439 | size_t slen; | ||
440 | size_t nlen; | ||
441 | size_t nsize; | ||
442 | |||
443 | if (NULL == buf) | ||
444 | { | ||
445 | finish (handle, GNUNET_SYSERR); | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | slen = strlen (handle->current->subsystem) + 1; | ||
450 | nlen = strlen (handle->current->name) + 1; | ||
451 | nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; | ||
452 | if (size < nsize) | ||
453 | { | ||
454 | GNUNET_break (0); | ||
455 | finish (handle, GNUNET_SYSERR); | ||
456 | return 0; | ||
457 | } | ||
458 | r = buf; | ||
459 | r->header.size = htons (nsize); | ||
460 | r->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); | ||
461 | r->flags = 0; | ||
462 | r->value = GNUNET_htonll (handle->current->value); | ||
463 | if (handle->current->make_persistent) | ||
464 | r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_PERSISTENT); | ||
465 | if (handle->current->type == ACTION_UPDATE) | ||
466 | r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_RELATIVE); | ||
467 | GNUNET_assert (slen + nlen == | ||
468 | GNUNET_STRINGS_buffer_fill ((char *) &r[1], | ||
469 | slen + nlen, | ||
470 | 2, | ||
471 | handle->current->subsystem, | ||
472 | handle->current->name)); | ||
473 | finish (handle, GNUNET_OK); | ||
474 | return nsize; | ||
475 | } | ||
476 | |||
477 | |||
478 | static size_t | ||
479 | transmit_action (void *cls, size_t size, void *buf) | ||
480 | { | ||
481 | struct GNUNET_STATISTICS_Handle *handle = cls; | ||
482 | size_t ret; | ||
483 | |||
484 | switch (handle->current->type) | ||
485 | { | ||
486 | case ACTION_GET: | ||
487 | ret = transmit_get (handle, size, buf); | ||
488 | break; | ||
489 | case ACTION_SET: | ||
490 | case ACTION_UPDATE: | ||
491 | ret = transmit_set (handle, size, buf); | ||
492 | break; | ||
493 | } | ||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | |||
498 | /** | ||
499 | * Schedule the next action to be performed. | ||
500 | */ | ||
501 | static void | ||
502 | schedule_action (struct GNUNET_STATISTICS_Handle *h) | ||
503 | { | ||
504 | struct GNUNET_TIME_Relative timeout; | ||
505 | |||
506 | if (h->current != NULL) | ||
507 | return; /* action already pending */ | ||
508 | if (GNUNET_YES != try_connect (h)) | ||
509 | { | ||
510 | finish (h, GNUNET_SYSERR); | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | /* schedule next action */ | ||
515 | h->current = h->action_head; | ||
516 | if (NULL == h->current) | ||
517 | { | ||
518 | /* no pending network action, check destroy! */ | ||
519 | if (h->do_destroy != GNUNET_YES) | ||
520 | return; | ||
521 | do_destroy (h); | ||
522 | return; | ||
523 | } | ||
524 | h->action_head = h->action_head->next; | ||
525 | if (NULL == h->action_head) | ||
526 | h->action_tail = NULL; | ||
527 | h->current->next = NULL; | ||
528 | |||
529 | timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout); | ||
530 | if (NULL == | ||
531 | GNUNET_CLIENT_notify_transmit_ready (h->client, | ||
532 | h->current->msize, | ||
533 | timeout, &transmit_action, h)) | ||
534 | { | ||
535 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
536 | "Failed to transmit request to statistics service.\n"); | ||
537 | finish (h, GNUNET_SYSERR); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | |||
542 | static void | ||
543 | insert_ai (struct GNUNET_STATISTICS_Handle *h, struct ActionItem *ai) | ||
544 | { | ||
545 | if (h->action_tail == NULL) | ||
546 | { | ||
547 | h->action_head = ai; | ||
548 | h->action_tail = ai; | ||
549 | schedule_action (h); | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | h->action_tail->next = ai; | ||
554 | h->action_tail = ai; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | |||
559 | /** | ||
560 | * Get statistic from the peer. | ||
561 | * | ||
562 | * @param handle identification of the statistics service | ||
563 | * @param subsystem limit to the specified subsystem, NULL for our subsystem | ||
564 | * @param name name of the statistic value, NULL for all values | ||
565 | * @param timeout after how long should we give up (and call | ||
566 | * cont with an error code)? | ||
567 | * @param cont continuation to call when done (can be NULL) | ||
568 | * @param proc function to call on each value | ||
569 | * @param cls closure for cont and proc | ||
570 | */ | ||
571 | void | ||
572 | GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle, | ||
573 | const char *subsystem, | ||
574 | const char *name, | ||
575 | struct GNUNET_TIME_Relative timeout, | ||
576 | GNUNET_STATISTICS_Callback cont, | ||
577 | GNUNET_STATISTICS_Iterator proc, void *cls) | ||
578 | { | ||
579 | size_t slen1; | ||
580 | size_t slen2; | ||
581 | struct ActionItem *ai; | ||
582 | |||
583 | GNUNET_assert (handle != NULL); | ||
584 | GNUNET_assert (proc != NULL); | ||
585 | if (GNUNET_YES != try_connect (handle)) | ||
586 | { | ||
587 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
588 | "Failed to connect to statistics service, can not get value `%s:%s'.\n", | ||
589 | strlen (subsystem) ? subsystem : "*", | ||
590 | strlen (name) ? name : "*"); | ||
591 | cont (cls, GNUNET_SYSERR); | ||
592 | return; | ||
593 | } | ||
594 | if (subsystem == NULL) | ||
595 | subsystem = ""; | ||
596 | if (name == NULL) | ||
597 | name = ""; | ||
598 | slen1 = strlen (subsystem); | ||
599 | slen2 = strlen (name); | ||
600 | GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) < | ||
601 | GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
602 | ai = GNUNET_malloc (sizeof (struct ActionItem)); | ||
603 | ai->subsystem = GNUNET_strdup (subsystem); | ||
604 | ai->name = GNUNET_strdup (name); | ||
605 | ai->cont = cont; | ||
606 | ai->proc = proc; | ||
607 | ai->cls = cls; | ||
608 | ai->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
609 | ai->type = ACTION_GET; | ||
610 | ai->msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); | ||
611 | insert_ai (handle, ai); | ||
612 | } | ||
613 | |||
614 | |||
615 | static void | ||
616 | add_setter_action (struct GNUNET_STATISTICS_Handle *h, | ||
617 | const char *name, | ||
618 | int make_persistent, | ||
619 | unsigned long long value, enum ActionType type) | ||
620 | { | ||
621 | struct ActionItem *ai; | ||
622 | size_t slen; | ||
623 | size_t nlen; | ||
624 | size_t nsize; | ||
625 | |||
626 | GNUNET_assert (h != NULL); | ||
627 | GNUNET_assert (name != NULL); | ||
628 | if (GNUNET_YES != try_connect (h)) | ||
629 | return; | ||
630 | slen = strlen (h->subsystem) + 1; | ||
631 | nlen = strlen (name) + 1; | ||
632 | nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; | ||
633 | if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
634 | { | ||
635 | GNUNET_break (0); | ||
636 | return; | ||
637 | } | ||
638 | ai = GNUNET_malloc (sizeof (struct ActionItem)); | ||
639 | ai->subsystem = GNUNET_strdup (h->subsystem); | ||
640 | ai->name = GNUNET_strdup (name); | ||
641 | ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); | ||
642 | ai->make_persistent = make_persistent; | ||
643 | ai->msize = nsize; | ||
644 | ai->value = value; | ||
645 | ai->type = type; | ||
646 | insert_ai (h, ai); | ||
647 | schedule_action (h); | ||
648 | } | ||
649 | |||
650 | |||
651 | /** | ||
652 | * Set statistic value for the peer. Will always use our | ||
653 | * subsystem (the argument used when "handle" was created). | ||
654 | * | ||
655 | * @param handle identification of the statistics service | ||
656 | * @param name name of the statistic value | ||
657 | * @param value new value to set | ||
658 | * @param make_persistent should the value be kept across restarts? | ||
659 | */ | ||
660 | void | ||
661 | GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle, | ||
662 | const char *name, | ||
663 | unsigned long long value, int make_persistent) | ||
664 | { | ||
665 | add_setter_action (handle, name, make_persistent, value, ACTION_SET); | ||
666 | } | ||
667 | |||
668 | |||
669 | /** | ||
670 | * Set statistic value for the peer. Will always use our | ||
671 | * subsystem (the argument used when "handle" was created). | ||
672 | * | ||
673 | * @param handle identification of the statistics service | ||
674 | * @param name name of the statistic value | ||
675 | * @param delta change in value (added to existing value) | ||
676 | * @param make_persistent should the value be kept across restarts? | ||
677 | */ | ||
678 | void | ||
679 | GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle, | ||
680 | const char *name, | ||
681 | long long delta, int make_persistent) | ||
682 | { | ||
683 | add_setter_action (handle, name, make_persistent, | ||
684 | (unsigned long long) delta, ACTION_UPDATE); | ||
685 | } | ||
686 | |||
687 | |||
688 | /* end of statistics_api.c */ | ||
diff --git a/src/statistics/test_gnunet_statistics.sh b/src/statistics/test_gnunet_statistics.sh new file mode 100755 index 000000000..43f629f36 --- /dev/null +++ b/src/statistics/test_gnunet_statistics.sh | |||
@@ -0,0 +1,177 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | rm -rf /tmp/test-gnunetd-statistics/ | ||
4 | exe="./gnunet-statistics -c test_statistics_api_data.conf" | ||
5 | base=/tmp/gnunet-test-statistics | ||
6 | #DEBUG="-L DEBUG" | ||
7 | # ----------------------------------- | ||
8 | echo -n "Preparing: Starting service..." | ||
9 | ./gnunet-service-statistics $DEBUG -c test_statistics_api_data.conf & | ||
10 | sleep 1 | ||
11 | echo "DONE" | ||
12 | |||
13 | # ---------------------------------------------------------------------------------- | ||
14 | echo -n "TEST: Bad argument checking..." | ||
15 | |||
16 | if $exe -x 2> /dev/null; then | ||
17 | echo "FAIL: error running $exe" | ||
18 | kill %% | ||
19 | exit 1 | ||
20 | fi | ||
21 | echo "PASS" | ||
22 | |||
23 | # ---------------------------------------------------------------------------------- | ||
24 | echo -n "TEST: Set value..." | ||
25 | |||
26 | if ! $exe $DEBUG -n test -s subsystem 42 ; then | ||
27 | echo "FAIL: error running $exe" | ||
28 | kill %% | ||
29 | exit 1 | ||
30 | fi | ||
31 | echo "PASS" | ||
32 | |||
33 | # ---------------------------------------------------------------------------------- | ||
34 | echo -n "TEST: Set another value..." | ||
35 | |||
36 | if ! $exe $DEBUG -n other -s osystem 43 ; then | ||
37 | echo "FAIL: error running $exe" | ||
38 | kill %% | ||
39 | exit 1 | ||
40 | fi | ||
41 | echo "PASS" | ||
42 | |||
43 | # ---------------------------------------------------------------------------------- | ||
44 | echo -n "TEST: viewing all stats..." | ||
45 | |||
46 | if ! $exe $DEBUG > $base.out; then | ||
47 | echo "FAIL: error running $exe" | ||
48 | kill %% | ||
49 | exit 1 | ||
50 | fi | ||
51 | LINES=`cat $base.out | wc -l` | ||
52 | if test $LINES -ne 2; then | ||
53 | echo "FAIL: unexpected output" | ||
54 | kill %% | ||
55 | exit 1 | ||
56 | fi | ||
57 | echo "PASS" | ||
58 | |||
59 | # ---------------------------------------------------------------------------------- | ||
60 | echo -n "TEST: viewing stats by name..." | ||
61 | |||
62 | if ! $exe $DEBUG -n other > $base.out; then | ||
63 | echo "FAIL: error running $exe" | ||
64 | kill %% | ||
65 | exit 1 | ||
66 | fi | ||
67 | LINES=`cat $base.out | grep 43 | wc -l` | ||
68 | if test $LINES -ne 1; then | ||
69 | echo "FAIL: unexpected output" | ||
70 | kill %% | ||
71 | exit 1 | ||
72 | fi | ||
73 | echo "PASS" | ||
74 | |||
75 | # ---------------------------------------------------------------------------------- | ||
76 | echo -n "TEST: viewing stats by subsystem..." | ||
77 | |||
78 | if ! $exe $DEBUG -s subsystem > $base.out; then | ||
79 | echo "FAIL: error running $exe" | ||
80 | kill %% | ||
81 | exit 1 | ||
82 | fi | ||
83 | LINES=`cat $base.out | grep 42 | wc -l` | ||
84 | if test $LINES -ne 1; then | ||
85 | echo "FAIL: unexpected output" | ||
86 | kill %% | ||
87 | exit 1 | ||
88 | fi | ||
89 | echo "PASS" | ||
90 | |||
91 | |||
92 | # ---------------------------------------------------------------------------------- | ||
93 | echo -n "TEST: Set persistent value..." | ||
94 | |||
95 | if ! $exe $DEBUG -n lasting -s subsystem 40 -p; then | ||
96 | echo "FAIL: error running $exe" | ||
97 | kill %% | ||
98 | exit 1 | ||
99 | fi | ||
100 | echo "PASS" | ||
101 | |||
102 | # ----------------------------------- | ||
103 | echo -n "Restarting service..." | ||
104 | sleep 1 | ||
105 | if ! kill %%; | ||
106 | then | ||
107 | echo "FAIL: could not kill service" | ||
108 | kill %% | ||
109 | exit 1 | ||
110 | fi | ||
111 | sleep 1 | ||
112 | ./gnunet-service-statistics $DEBUG -c test_statistics_api_data.conf & | ||
113 | sleep 1 | ||
114 | |||
115 | |||
116 | # ---------------------------------------------------------------------------------- | ||
117 | echo -n "TEST: checking persistence..." | ||
118 | |||
119 | if ! $exe $DEBUG > $base.out; then | ||
120 | echo "FAIL: error running $exe" | ||
121 | kill %% | ||
122 | exit 1 | ||
123 | fi | ||
124 | LINES=`cat $base.out | grep 40 | wc -l` | ||
125 | if test $LINES -ne 1; then | ||
126 | echo "FAIL: unexpected output" | ||
127 | kill %% | ||
128 | exit 1 | ||
129 | fi | ||
130 | echo "PASS" | ||
131 | |||
132 | |||
133 | |||
134 | # ---------------------------------------------------------------------------------- | ||
135 | echo -n "TEST: Removing persistence..." | ||
136 | |||
137 | if ! $exe $DEBUG -n lasting -s subsystem 40; then | ||
138 | echo "FAIL: error running $exe" | ||
139 | kill %% | ||
140 | exit 1 | ||
141 | fi | ||
142 | echo "PASS" | ||
143 | |||
144 | |||
145 | # ----------------------------------- | ||
146 | echo -n "Restarting service..." | ||
147 | sleep 1 | ||
148 | if ! kill %%; | ||
149 | then | ||
150 | echo "FAIL: could not kill service" | ||
151 | kill %% | ||
152 | exit 1 | ||
153 | fi | ||
154 | sleep 1 | ||
155 | ./gnunet-service-statistics $DEBUG -c test_statistics_api_data.conf & | ||
156 | sleep 1 | ||
157 | |||
158 | |||
159 | # ---------------------------------------------------------------------------------- | ||
160 | echo -n "TEST: checking removed persistence..." | ||
161 | |||
162 | if ! $exe $DEBUG > $base.out; then | ||
163 | echo "FAIL: error running $exe" | ||
164 | kill %% | ||
165 | exit 1 | ||
166 | fi | ||
167 | LINES=`cat $base.out | grep 40 | wc -l` | ||
168 | if test $LINES -ne 0; then | ||
169 | echo "FAIL: unexpected output" | ||
170 | kill %% | ||
171 | exit 1 | ||
172 | fi | ||
173 | echo "PASS" | ||
174 | |||
175 | kill %% | ||
176 | rm -f $base.out | ||
177 | rm -rf /tmp/test-gnunetd-statistics/ | ||
diff --git a/src/statistics/test_statistics_api.c b/src/statistics/test_statistics_api.c new file mode 100644 index 000000000..7a39f54b6 --- /dev/null +++ b/src/statistics/test_statistics_api.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, 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 statistics/test_statistics_api.c | ||
22 | * @brief testcase for statistics_api.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_common.h" | ||
26 | #include "gnunet_getopt_lib.h" | ||
27 | #include "gnunet_os_lib.h" | ||
28 | #include "gnunet_program_lib.h" | ||
29 | #include "gnunet_scheduler_lib.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | |||
32 | #define VERBOSE GNUNET_NO | ||
33 | |||
34 | static int | ||
35 | check_1 (void *cls, | ||
36 | const char *subsystem, | ||
37 | const char *name, unsigned long long value, int is_persistent) | ||
38 | { | ||
39 | GNUNET_assert (0 == strcmp (name, "test-1")); | ||
40 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); | ||
41 | GNUNET_assert (value == 1); | ||
42 | GNUNET_assert (is_persistent == GNUNET_NO); | ||
43 | return GNUNET_OK; | ||
44 | } | ||
45 | |||
46 | static int | ||
47 | check_2 (void *cls, | ||
48 | const char *subsystem, | ||
49 | const char *name, unsigned long long value, int is_persistent) | ||
50 | { | ||
51 | GNUNET_assert (0 == strcmp (name, "test-2")); | ||
52 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); | ||
53 | GNUNET_assert (value == 2); | ||
54 | GNUNET_assert (is_persistent == GNUNET_NO); | ||
55 | return GNUNET_OK; | ||
56 | } | ||
57 | |||
58 | static int | ||
59 | check_3 (void *cls, | ||
60 | const char *subsystem, | ||
61 | const char *name, unsigned long long value, int is_persistent) | ||
62 | { | ||
63 | GNUNET_assert (0 == strcmp (name, "test-3")); | ||
64 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); | ||
65 | GNUNET_assert (value == 3); | ||
66 | GNUNET_assert (is_persistent == GNUNET_YES); | ||
67 | return GNUNET_OK; | ||
68 | } | ||
69 | |||
70 | static struct GNUNET_STATISTICS_Handle *h; | ||
71 | |||
72 | static void | ||
73 | next_fin (void *cls, int success) | ||
74 | { | ||
75 | int *ok = cls; | ||
76 | |||
77 | GNUNET_STATISTICS_destroy (h); | ||
78 | GNUNET_assert (success == GNUNET_OK); | ||
79 | *ok = 0; | ||
80 | } | ||
81 | |||
82 | static void | ||
83 | next (void *cls, int success) | ||
84 | { | ||
85 | GNUNET_assert (success == GNUNET_OK); | ||
86 | GNUNET_STATISTICS_get (h, NULL, "test-2", | ||
87 | GNUNET_TIME_UNIT_SECONDS, &next_fin, &check_2, cls); | ||
88 | } | ||
89 | |||
90 | static void | ||
91 | run (void *cls, | ||
92 | struct GNUNET_SCHEDULER_Handle *sched, | ||
93 | char *const *args, | ||
94 | const char *cfgfile, struct GNUNET_CONFIGURATION_Handle *cfg) | ||
95 | { | ||
96 | |||
97 | h = GNUNET_STATISTICS_create (sched, "test-statistics-api", cfg); | ||
98 | GNUNET_STATISTICS_set (h, "test-1", 1, GNUNET_NO); | ||
99 | GNUNET_STATISTICS_set (h, "test-2", 2, GNUNET_NO); | ||
100 | GNUNET_STATISTICS_set (h, "test-3", 2, GNUNET_NO); | ||
101 | GNUNET_STATISTICS_update (h, "test-3", 1, GNUNET_YES); | ||
102 | GNUNET_STATISTICS_get (h, NULL, "test-1", | ||
103 | GNUNET_TIME_UNIT_SECONDS, &next, &check_1, cls); | ||
104 | } | ||
105 | |||
106 | static void | ||
107 | run_more (void *cls, | ||
108 | struct GNUNET_SCHEDULER_Handle *sched, | ||
109 | char *const *args, | ||
110 | const char *cfgfile, struct GNUNET_CONFIGURATION_Handle *cfg) | ||
111 | { | ||
112 | h = GNUNET_STATISTICS_create (sched, "test-statistics-api", cfg); | ||
113 | GNUNET_STATISTICS_get (h, NULL, "test-3", | ||
114 | GNUNET_TIME_UNIT_SECONDS, &next_fin, &check_3, cls); | ||
115 | } | ||
116 | |||
117 | static int | ||
118 | check () | ||
119 | { | ||
120 | int ok = 1; | ||
121 | pid_t pid; | ||
122 | char *const argv[] = { "test-statistics-api", | ||
123 | "-c", | ||
124 | "test_statistics_api_data.conf", | ||
125 | NULL | ||
126 | }; | ||
127 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
128 | GNUNET_GETOPT_OPTION_END | ||
129 | }; | ||
130 | pid = GNUNET_OS_start_process ("gnunet-service-statistics", | ||
131 | "gnunet-service-statistics", | ||
132 | #if DEBUG_STATISTICS | ||
133 | "-L", "DEBUG", | ||
134 | #endif | ||
135 | "-c", "test_statistics_api_data.conf", NULL); | ||
136 | sleep (1); | ||
137 | GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", | ||
138 | options, &run, &ok); | ||
139 | if (0 != PLIBC_KILL (pid, SIGTERM)) | ||
140 | { | ||
141 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
142 | ok = 1; | ||
143 | } | ||
144 | waitpid (pid, NULL, 0); | ||
145 | if (ok != 0) | ||
146 | return ok; | ||
147 | ok = 1; | ||
148 | /* restart to check persistence! */ | ||
149 | pid = GNUNET_OS_start_process ("gnunet-service-statistics", | ||
150 | "gnunet-service-statistics", | ||
151 | #if DEBUG_STATISTICS | ||
152 | "-L", "DEBUG", | ||
153 | #endif | ||
154 | "-c", "test_statistics_api_data.conf", NULL); | ||
155 | sleep (1); | ||
156 | GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", | ||
157 | options, &run_more, &ok); | ||
158 | if (0 != PLIBC_KILL (pid, SIGTERM)) | ||
159 | { | ||
160 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
161 | ok = 1; | ||
162 | } | ||
163 | waitpid (pid, NULL, 0); | ||
164 | return ok; | ||
165 | } | ||
166 | |||
167 | int | ||
168 | main (int argc, char *argv[]) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | ret = check (); | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | /* end of test_statistics_api.c */ | ||
diff --git a/src/statistics/test_statistics_api_data.conf b/src/statistics/test_statistics_api_data.conf new file mode 100644 index 000000000..571a9b3e4 --- /dev/null +++ b/src/statistics/test_statistics_api_data.conf | |||
@@ -0,0 +1,5 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/test-gnunetd-statistics/ | ||
3 | |||
4 | [statistics] | ||
5 | PORT = 22353 | ||