diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-07-07 06:27:10 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-07-07 06:27:10 +0000 |
commit | ac2de52a5de68f6f4f13b7aa01a481869fffc6aa (patch) | |
tree | 856c9f0b2f55f8cae99f3c7b3bf22beaecbf58da /src/statistics | |
parent | c1a3c11f8665432d9db6d549c28c0329668e66af (diff) | |
download | gnunet-ac2de52a5de68f6f4f13b7aa01a481869fffc6aa.tar.gz gnunet-ac2de52a5de68f6f4f13b7aa01a481869fffc6aa.zip |
hacks from trip
Diffstat (limited to 'src/statistics')
-rw-r--r-- | src/statistics/gnunet-service-statistics.c | 332 | ||||
-rw-r--r-- | src/statistics/statistics.h | 39 | ||||
-rw-r--r-- | src/statistics/statistics_api.c | 365 | ||||
-rw-r--r-- | src/statistics/test_statistics_api.c | 37 | ||||
-rw-r--r-- | src/statistics/test_statistics_api_data.conf | 3 |
5 files changed, 719 insertions, 57 deletions
diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c index 3ff751efe..251302a66 100644 --- a/src/statistics/gnunet-service-statistics.c +++ b/src/statistics/gnunet-service-statistics.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009 Christian Grothoff (and other contributing authors) | 3 | (C) 2009, 2010 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -27,6 +27,7 @@ | |||
27 | * - use BIO for IO operations | 27 | * - use BIO for IO operations |
28 | */ | 28 | */ |
29 | #include "platform.h" | 29 | #include "platform.h" |
30 | #include "gnunet_container_lib.h" | ||
30 | #include "gnunet_disk_lib.h" | 31 | #include "gnunet_disk_lib.h" |
31 | #include "gnunet_getopt_lib.h" | 32 | #include "gnunet_getopt_lib.h" |
32 | #include "gnunet_protocols.h" | 33 | #include "gnunet_protocols.h" |
@@ -37,6 +38,41 @@ | |||
37 | #include "statistics.h" | 38 | #include "statistics.h" |
38 | 39 | ||
39 | /** | 40 | /** |
41 | * Watch entry. | ||
42 | */ | ||
43 | struct WatchEntry | ||
44 | { | ||
45 | |||
46 | struct WatchEntry *next; | ||
47 | |||
48 | struct WatchEntry *prev; | ||
49 | |||
50 | struct GNUNET_SERVER_Client *client; | ||
51 | |||
52 | uint64_t last_value; | ||
53 | |||
54 | uint32_t wid; | ||
55 | |||
56 | }; | ||
57 | |||
58 | |||
59 | /** | ||
60 | * Client entry. | ||
61 | */ | ||
62 | struct ClientEntry | ||
63 | { | ||
64 | |||
65 | struct ClientEntry *next; | ||
66 | |||
67 | struct ClientEntry *prev; | ||
68 | |||
69 | struct GNUNET_SERVER_Client *client; | ||
70 | |||
71 | uint32_t max_wid; | ||
72 | |||
73 | }; | ||
74 | |||
75 | /** | ||
40 | * Entry in the statistics list. | 76 | * Entry in the statistics list. |
41 | */ | 77 | */ |
42 | struct StatsEntry | 78 | struct StatsEntry |
@@ -66,6 +102,18 @@ struct StatsEntry | |||
66 | struct GNUNET_STATISTICS_SetMessage *msg; | 102 | struct GNUNET_STATISTICS_SetMessage *msg; |
67 | 103 | ||
68 | /** | 104 | /** |
105 | * Watch context for changes to this | ||
106 | * value, or NULL for none. | ||
107 | */ | ||
108 | struct WatchEntry *we_head; | ||
109 | |||
110 | /** | ||
111 | * Watch context for changes to this | ||
112 | * value, or NULL for none. | ||
113 | */ | ||
114 | struct WatchEntry *we_tail; | ||
115 | |||
116 | /** | ||
69 | * Our value. | 117 | * Our value. |
70 | */ | 118 | */ |
71 | uint64_t value; | 119 | uint64_t value; |
@@ -92,6 +140,21 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; | |||
92 | */ | 140 | */ |
93 | static struct StatsEntry *start; | 141 | static struct StatsEntry *start; |
94 | 142 | ||
143 | static struct ClientEntry *client_head; | ||
144 | |||
145 | static struct ClientEntry *client_tail; | ||
146 | |||
147 | /** | ||
148 | * Our notification context. | ||
149 | */ | ||
150 | static struct GNUNET_SERVER_NotificationContext *nc; | ||
151 | |||
152 | /** | ||
153 | * Counter used to generate unique values. | ||
154 | */ | ||
155 | static uint32_t uidgen; | ||
156 | |||
157 | |||
95 | /** | 158 | /** |
96 | * Load persistent values from disk. Disk format is | 159 | * Load persistent values from disk. Disk format is |
97 | * exactly the same format that we also use for | 160 | * exactly the same format that we also use for |
@@ -209,7 +272,7 @@ save () | |||
209 | * Transmit the given stats value. | 272 | * Transmit the given stats value. |
210 | */ | 273 | */ |
211 | static void | 274 | static void |
212 | transmit (struct GNUNET_SERVER_TransmitContext *tc, | 275 | transmit (struct GNUNET_SERVER_Client *client, |
213 | const struct StatsEntry *e) | 276 | const struct StatsEntry *e) |
214 | { | 277 | { |
215 | struct GNUNET_STATISTICS_ReplyMessage *m; | 278 | struct GNUNET_STATISTICS_ReplyMessage *m; |
@@ -232,10 +295,11 @@ transmit (struct GNUNET_SERVER_TransmitContext *tc, | |||
232 | 2, e->service, e->name)); | 295 | 2, e->service, e->name)); |
233 | #if DEBUG_STATISTICS | 296 | #if DEBUG_STATISTICS |
234 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 297 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
235 | "Transmitting value for `%s:%s': %llu\n", | 298 | "Transmitting value for `%s:%s' (%d): %llu\n", |
236 | e->service, e->name, e->value); | 299 | e->service, e->name, |
300 | e->persistent, e->value); | ||
237 | #endif | 301 | #endif |
238 | GNUNET_SERVER_transmit_context_append_message (tc, &m->header); | 302 | GNUNET_SERVER_notification_context_unicast (nc, client, &m->header, GNUNET_NO); |
239 | GNUNET_free (m); | 303 | GNUNET_free (m); |
240 | } | 304 | } |
241 | 305 | ||
@@ -252,6 +316,32 @@ matches (const struct StatsEntry *e, const char *service, const char *name) | |||
252 | } | 316 | } |
253 | 317 | ||
254 | 318 | ||
319 | static struct ClientEntry * | ||
320 | make_client_entry (struct GNUNET_SERVER_Client *client) | ||
321 | { | ||
322 | struct ClientEntry *ce; | ||
323 | |||
324 | if (client == NULL) | ||
325 | return NULL; | ||
326 | ce = client_head; | ||
327 | while (ce != NULL) | ||
328 | { | ||
329 | if (ce->client == client) | ||
330 | return ce; | ||
331 | ce = ce->next; | ||
332 | } | ||
333 | ce = GNUNET_malloc (sizeof (struct ClientEntry)); | ||
334 | ce->client = client; | ||
335 | GNUNET_SERVER_client_keep (client); | ||
336 | GNUNET_CONTAINER_DLL_insert (client_head, | ||
337 | client_tail, | ||
338 | ce); | ||
339 | GNUNET_SERVER_notification_context_add (nc, | ||
340 | client); | ||
341 | return ce; | ||
342 | } | ||
343 | |||
344 | |||
255 | /** | 345 | /** |
256 | * Handle GET-message. | 346 | * Handle GET-message. |
257 | * | 347 | * |
@@ -266,12 +356,13 @@ handle_get (void *cls, | |||
266 | struct GNUNET_SERVER_Client *client, | 356 | struct GNUNET_SERVER_Client *client, |
267 | const struct GNUNET_MessageHeader *message) | 357 | const struct GNUNET_MessageHeader *message) |
268 | { | 358 | { |
359 | struct GNUNET_MessageHeader end; | ||
269 | char *service; | 360 | char *service; |
270 | char *name; | 361 | char *name; |
271 | struct StatsEntry *pos; | 362 | struct StatsEntry *pos; |
272 | struct GNUNET_SERVER_TransmitContext *tc; | ||
273 | size_t size; | 363 | size_t size; |
274 | 364 | ||
365 | make_client_entry (client); | ||
275 | size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); | 366 | size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); |
276 | if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], | 367 | if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], |
277 | size, 2, &service, &name)) | 368 | size, 2, &service, &name)) |
@@ -285,20 +376,51 @@ handle_get (void *cls, | |||
285 | "Received request for statistics on `%s:%s'\n", | 376 | "Received request for statistics on `%s:%s'\n", |
286 | strlen (service) ? service : "*", strlen (name) ? name : "*"); | 377 | strlen (service) ? service : "*", strlen (name) ? name : "*"); |
287 | #endif | 378 | #endif |
288 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
289 | pos = start; | 379 | pos = start; |
290 | while (pos != NULL) | 380 | while (pos != NULL) |
291 | { | 381 | { |
292 | if (matches (pos, service, name)) | 382 | if (matches (pos, service, name)) |
293 | transmit (tc, pos); | 383 | transmit (client, pos); |
294 | pos = pos->next; | 384 | pos = pos->next; |
295 | } | 385 | } |
296 | GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, | 386 | end.size = htons (sizeof (struct GNUNET_MessageHeader)); |
297 | GNUNET_MESSAGE_TYPE_STATISTICS_END); | 387 | end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); |
298 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | 388 | GNUNET_SERVER_notification_context_unicast (nc, |
389 | client, | ||
390 | &end, | ||
391 | GNUNET_NO); | ||
392 | GNUNET_SERVER_receive_done (client, | ||
393 | GNUNET_OK); | ||
299 | } | 394 | } |
300 | 395 | ||
301 | 396 | ||
397 | static void | ||
398 | notify_change (struct StatsEntry *se) | ||
399 | { | ||
400 | struct GNUNET_STATISTICS_WatchValueMessage wvm; | ||
401 | struct WatchEntry *pos; | ||
402 | |||
403 | pos = se->we_head; | ||
404 | while (pos != NULL) | ||
405 | { | ||
406 | if (pos->last_value != se->value) | ||
407 | { | ||
408 | wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); | ||
409 | wvm.header.size = htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); | ||
410 | wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); | ||
411 | wvm.wid = htonl (pos->wid); | ||
412 | wvm.reserved = htonl (0); | ||
413 | wvm.value = GNUNET_htonll (se->value); | ||
414 | GNUNET_SERVER_notification_context_unicast (nc, | ||
415 | pos->client, | ||
416 | &wvm.header, | ||
417 | GNUNET_NO); | ||
418 | pos->last_value = se->value; | ||
419 | } | ||
420 | pos = pos->next; | ||
421 | } | ||
422 | } | ||
423 | |||
302 | /** | 424 | /** |
303 | * Handle SET-message. | 425 | * Handle SET-message. |
304 | * | 426 | * |
@@ -311,11 +433,6 @@ handle_set (void *cls, | |||
311 | struct GNUNET_SERVER_Client *client, | 433 | struct GNUNET_SERVER_Client *client, |
312 | const struct GNUNET_MessageHeader *message) | 434 | const struct GNUNET_MessageHeader *message) |
313 | { | 435 | { |
314 | /** | ||
315 | * Counter used to generate unique values. | ||
316 | */ | ||
317 | static uint32_t uidgen; | ||
318 | |||
319 | char *service; | 436 | char *service; |
320 | char *name; | 437 | char *name; |
321 | uint16_t msize; | 438 | uint16_t msize; |
@@ -326,7 +443,9 @@ handle_set (void *cls, | |||
326 | uint32_t flags; | 443 | uint32_t flags; |
327 | uint64_t value; | 444 | uint64_t value; |
328 | int64_t delta; | 445 | int64_t delta; |
446 | int changed; | ||
329 | 447 | ||
448 | make_client_entry (client); | ||
330 | msize = ntohs (message->size); | 449 | msize = ntohs (message->size); |
331 | if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) | 450 | if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) |
332 | { | 451 | { |
@@ -344,13 +463,15 @@ handle_set (void *cls, | |||
344 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 463 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
345 | return; | 464 | return; |
346 | } | 465 | } |
466 | flags = ntohl (msg->flags); | ||
467 | value = GNUNET_ntohll (msg->value); | ||
347 | #if DEBUG_STATISTICS | 468 | #if DEBUG_STATISTICS |
348 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 469 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
349 | "Received request to update statistic on `%s:%s'\n", | 470 | "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", |
350 | service, name); | 471 | service, name, |
472 | (unsigned int) flags, | ||
473 | (unsigned long long) value); | ||
351 | #endif | 474 | #endif |
352 | flags = ntohl (msg->flags); | ||
353 | value = GNUNET_ntohll (msg->value); | ||
354 | pos = start; | 475 | pos = start; |
355 | prev = NULL; | 476 | prev = NULL; |
356 | while (pos != NULL) | 477 | while (pos != NULL) |
@@ -359,17 +480,20 @@ handle_set (void *cls, | |||
359 | { | 480 | { |
360 | if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) | 481 | if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) |
361 | { | 482 | { |
483 | changed = (pos->value != value); | ||
362 | pos->value = value; | 484 | pos->value = value; |
363 | } | 485 | } |
364 | else | 486 | else |
365 | { | 487 | { |
366 | delta = (int64_t) value; | 488 | delta = (int64_t) value; |
367 | if ((delta < 0) && (pos->value < -delta)) | 489 | if ((delta < 0) && (pos->value < -delta)) |
368 | { | 490 | { |
369 | pos->value = 0; | 491 | changed = (pos->value != 0); |
492 | pos->value = 0; | ||
370 | } | 493 | } |
371 | else | 494 | else |
372 | { | 495 | { |
496 | changed = (delta != 0); | ||
373 | GNUNET_break ((delta <= 0) || | 497 | GNUNET_break ((delta <= 0) || |
374 | (pos->value + delta > pos->value)); | 498 | (pos->value + delta > pos->value)); |
375 | pos->value += delta; | 499 | pos->value += delta; |
@@ -391,6 +515,8 @@ handle_set (void *cls, | |||
391 | "Statistic `%s:%s' updated to value %llu.\n", | 515 | "Statistic `%s:%s' updated to value %llu.\n", |
392 | service, name, pos->value); | 516 | service, name, pos->value); |
393 | #endif | 517 | #endif |
518 | if (changed) | ||
519 | notify_change (pos); | ||
394 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 520 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
395 | return; | 521 | return; |
396 | } | 522 | } |
@@ -420,6 +546,86 @@ handle_set (void *cls, | |||
420 | 546 | ||
421 | 547 | ||
422 | /** | 548 | /** |
549 | * Handle WATCH-message. | ||
550 | * | ||
551 | * @param cls closure | ||
552 | * @param client identification of the client | ||
553 | * @param message the actual message | ||
554 | */ | ||
555 | static void | ||
556 | handle_watch (void *cls, | ||
557 | struct GNUNET_SERVER_Client *client, | ||
558 | const struct GNUNET_MessageHeader *message) | ||
559 | { | ||
560 | char *service; | ||
561 | char *name; | ||
562 | uint16_t msize; | ||
563 | uint16_t size; | ||
564 | struct StatsEntry *pos; | ||
565 | struct ClientEntry *ce; | ||
566 | struct WatchEntry *we; | ||
567 | |||
568 | ce = make_client_entry (client); | ||
569 | msize = ntohs (message->size); | ||
570 | if (msize < sizeof (struct GNUNET_MessageHeader)) | ||
571 | { | ||
572 | GNUNET_break (0); | ||
573 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
574 | return; | ||
575 | } | ||
576 | size = msize - sizeof (struct GNUNET_MessageHeader); | ||
577 | if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], | ||
578 | size, 2, &service, &name)) | ||
579 | { | ||
580 | GNUNET_break (0); | ||
581 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
582 | return; | ||
583 | } | ||
584 | #if DEBUG_STATISTICS | ||
585 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
586 | "Received request to watch statistic on `%s:%s'\n", | ||
587 | service, name); | ||
588 | #endif | ||
589 | pos = start; | ||
590 | while (pos != NULL) | ||
591 | { | ||
592 | if (matches (pos, service, name)) | ||
593 | break; | ||
594 | pos = pos->next; | ||
595 | } | ||
596 | if (pos == NULL) | ||
597 | { | ||
598 | pos = GNUNET_malloc (sizeof (struct StatsEntry) + | ||
599 | sizeof (struct GNUNET_STATISTICS_SetMessage) + | ||
600 | size); | ||
601 | pos->next = start; | ||
602 | pos->uid = uidgen++; | ||
603 | pos->msg = (void *) &pos[1]; | ||
604 | pos->msg->header.size = htons (sizeof (struct GNUNET_STATISTICS_SetMessage) + | ||
605 | size); | ||
606 | pos->msg->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); | ||
607 | memcpy (pos->msg, message, ntohs (message->size)); | ||
608 | pos->service = (const char *) &pos->msg[1]; | ||
609 | memcpy (&pos->msg[1], service, strlen (service)+1); | ||
610 | pos->name = &pos->service[strlen (pos->service) + 1]; | ||
611 | memcpy ((void*) pos->name, name, strlen (name)+1); | ||
612 | start = pos; | ||
613 | } | ||
614 | we = GNUNET_malloc (sizeof (struct WatchEntry)); | ||
615 | we->client = client; | ||
616 | GNUNET_SERVER_client_keep (client); | ||
617 | we->wid = ce->max_wid++; | ||
618 | GNUNET_CONTAINER_DLL_insert (pos->we_head, | ||
619 | pos->we_tail, | ||
620 | we); | ||
621 | if (pos->value != 0) | ||
622 | notify_change (pos); | ||
623 | GNUNET_SERVER_receive_done (client, | ||
624 | GNUNET_OK); | ||
625 | } | ||
626 | |||
627 | |||
628 | /** | ||
423 | * Task run during shutdown. | 629 | * Task run during shutdown. |
424 | * | 630 | * |
425 | * @param cls unused | 631 | * @param cls unused |
@@ -429,7 +635,84 @@ static void | |||
429 | shutdown_task (void *cls, | 635 | shutdown_task (void *cls, |
430 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 636 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
431 | { | 637 | { |
638 | struct ClientEntry *ce; | ||
639 | struct WatchEntry *we; | ||
640 | struct StatsEntry *se; | ||
641 | |||
432 | save (); | 642 | save (); |
643 | GNUNET_SERVER_notification_context_destroy (nc); | ||
644 | nc = NULL; | ||
645 | while (NULL != (ce = client_head)) | ||
646 | { | ||
647 | GNUNET_SERVER_client_drop (ce->client); | ||
648 | GNUNET_CONTAINER_DLL_remove (client_head, | ||
649 | client_tail, | ||
650 | ce); | ||
651 | GNUNET_free (ce); | ||
652 | } | ||
653 | while (NULL != (se = start)) | ||
654 | { | ||
655 | start = se->next; | ||
656 | while (NULL != (we = se->we_head)) | ||
657 | { | ||
658 | GNUNET_SERVER_client_drop (we->client); | ||
659 | GNUNET_CONTAINER_DLL_remove (se->we_head, | ||
660 | se->we_tail, | ||
661 | we); | ||
662 | GNUNET_free (we); | ||
663 | } | ||
664 | GNUNET_free (se); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | |||
669 | /** | ||
670 | * A client disconnected. Remove all of its data structure entries. | ||
671 | * | ||
672 | * @param cls closure, NULL | ||
673 | * @param client identification of the client | ||
674 | */ | ||
675 | static void | ||
676 | handle_client_disconnect (void *cls, | ||
677 | struct GNUNET_SERVER_Client | ||
678 | * client) | ||
679 | { | ||
680 | struct ClientEntry *ce; | ||
681 | struct WatchEntry *we; | ||
682 | struct WatchEntry *wen; | ||
683 | struct StatsEntry *se; | ||
684 | |||
685 | ce = client_head; | ||
686 | while (NULL != ce) | ||
687 | { | ||
688 | if (ce->client == client) | ||
689 | { | ||
690 | GNUNET_SERVER_client_drop (ce->client); | ||
691 | GNUNET_CONTAINER_DLL_remove (client_head, | ||
692 | client_tail, | ||
693 | ce); | ||
694 | GNUNET_free (ce); | ||
695 | break; | ||
696 | } | ||
697 | ce = ce->next; | ||
698 | } | ||
699 | se = start; | ||
700 | while (NULL != se) | ||
701 | { | ||
702 | wen = se->we_head; | ||
703 | while (NULL != (we = wen)) | ||
704 | { | ||
705 | wen = we->next; | ||
706 | if (we->client != client) | ||
707 | continue; | ||
708 | GNUNET_SERVER_client_drop (we->client); | ||
709 | GNUNET_CONTAINER_DLL_remove (se->we_head, | ||
710 | se->we_tail, | ||
711 | we); | ||
712 | GNUNET_free (we); | ||
713 | } | ||
714 | se = se->next; | ||
715 | } | ||
433 | } | 716 | } |
434 | 717 | ||
435 | 718 | ||
@@ -450,10 +733,15 @@ run (void *cls, | |||
450 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | 733 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { |
451 | {&handle_set, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_SET, 0}, | 734 | {&handle_set, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_SET, 0}, |
452 | {&handle_get, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_GET, 0}, | 735 | {&handle_get, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_GET, 0}, |
736 | {&handle_watch, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_WATCH, 0}, | ||
453 | {NULL, NULL, 0, 0} | 737 | {NULL, NULL, 0, 0} |
454 | }; | 738 | }; |
455 | cfg = c; | 739 | cfg = c; |
456 | GNUNET_SERVER_add_handlers (server, handlers); | 740 | GNUNET_SERVER_add_handlers (server, handlers); |
741 | nc = GNUNET_SERVER_notification_context_create (server, 16); | ||
742 | GNUNET_SERVER_disconnect_notify (server, | ||
743 | &handle_client_disconnect, | ||
744 | NULL); | ||
457 | load (server); | 745 | load (server); |
458 | GNUNET_SCHEDULER_add_delayed (sched, | 746 | GNUNET_SCHEDULER_add_delayed (sched, |
459 | GNUNET_TIME_UNIT_FOREVER_REL, | 747 | GNUNET_TIME_UNIT_FOREVER_REL, |
diff --git a/src/statistics/statistics.h b/src/statistics/statistics.h index c4a79765a..070a0aba5 100644 --- a/src/statistics/statistics.h +++ b/src/statistics/statistics.h | |||
@@ -91,4 +91,43 @@ struct GNUNET_STATISTICS_SetMessage | |||
91 | 91 | ||
92 | }; | 92 | }; |
93 | 93 | ||
94 | |||
95 | /** | ||
96 | * Message transmitted if a watched value changes. | ||
97 | */ | ||
98 | struct GNUNET_STATISTICS_WatchValueMessage | ||
99 | { | ||
100 | /** | ||
101 | * Type: GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE | ||
102 | */ | ||
103 | struct GNUNET_MessageHeader header; | ||
104 | |||
105 | /** | ||
106 | * 0 for absolute value, 1 for relative value; 2 to make persistent | ||
107 | * (see GNUNET_STATISTICS_SETFLAG_*). | ||
108 | */ | ||
109 | uint32_t flags GNUNET_PACKED; | ||
110 | |||
111 | /** | ||
112 | * Unique watch identification number (watch | ||
113 | * requests are enumerated in the order they | ||
114 | * are received, the first request having | ||
115 | * a wid of zero). | ||
116 | */ | ||
117 | uint32_t wid GNUNET_PACKED; | ||
118 | |||
119 | /** | ||
120 | * Reserved (always 0). | ||
121 | */ | ||
122 | uint32_t reserved GNUNET_PACKED; | ||
123 | |||
124 | /** | ||
125 | * Value. Note that if this is a relative value, it will | ||
126 | * be signed even though the type given here is unsigned. | ||
127 | */ | ||
128 | uint64_t value GNUNET_PACKED; | ||
129 | |||
130 | }; | ||
131 | |||
132 | |||
94 | #endif | 133 | #endif |
diff --git a/src/statistics/statistics_api.c b/src/statistics/statistics_api.c index 9de9f78fd..a5dde0e55 100644 --- a/src/statistics/statistics_api.c +++ b/src/statistics/statistics_api.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009 Christian Grothoff (and other contributing authors) | 3 | (C) 2009, 2010 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -25,6 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet_client_lib.h" | 27 | #include "gnunet_client_lib.h" |
28 | #include "gnunet_constants.h" | ||
28 | #include "gnunet_container_lib.h" | 29 | #include "gnunet_container_lib.h" |
29 | #include "gnunet_protocols.h" | 30 | #include "gnunet_protocols.h" |
30 | #include "gnunet_server_lib.h" | 31 | #include "gnunet_server_lib.h" |
@@ -47,7 +48,37 @@ enum ActionType | |||
47 | { | 48 | { |
48 | ACTION_GET, | 49 | ACTION_GET, |
49 | ACTION_SET, | 50 | ACTION_SET, |
50 | ACTION_UPDATE | 51 | ACTION_UPDATE, |
52 | ACTION_WATCH | ||
53 | }; | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Entry kept for each value we are watching. | ||
58 | */ | ||
59 | struct GNUNET_STATISTICS_WatchEntry | ||
60 | { | ||
61 | |||
62 | /** | ||
63 | * What subsystem is this action about? (never NULL) | ||
64 | */ | ||
65 | char *subsystem; | ||
66 | |||
67 | /** | ||
68 | * What value is this action about? (never NULL) | ||
69 | */ | ||
70 | char *name; | ||
71 | |||
72 | /** | ||
73 | * Function to call | ||
74 | */ | ||
75 | GNUNET_STATISTICS_Iterator proc; | ||
76 | |||
77 | /** | ||
78 | * Closure for proc | ||
79 | */ | ||
80 | void *proc_cls; | ||
81 | |||
51 | }; | 82 | }; |
52 | 83 | ||
53 | 84 | ||
@@ -118,7 +149,7 @@ struct GNUNET_STATISTICS_GetHandle | |||
118 | int aborted; | 149 | int aborted; |
119 | 150 | ||
120 | /** | 151 | /** |
121 | * Is this a GET, SET or UPDATE? | 152 | * Is this a GET, SET, UPDATE or WATCH? |
122 | */ | 153 | */ |
123 | enum ActionType type; | 154 | enum ActionType type; |
124 | 155 | ||
@@ -179,14 +210,103 @@ struct GNUNET_STATISTICS_Handle | |||
179 | struct GNUNET_STATISTICS_GetHandle *current; | 210 | struct GNUNET_STATISTICS_GetHandle *current; |
180 | 211 | ||
181 | /** | 212 | /** |
213 | * Array of watch entries. | ||
214 | */ | ||
215 | struct GNUNET_STATISTICS_WatchEntry **watches; | ||
216 | |||
217 | /** | ||
218 | * Task doing exponential back-off trying to reconnect. | ||
219 | */ | ||
220 | GNUNET_SCHEDULER_TaskIdentifier backoff_task; | ||
221 | |||
222 | /** | ||
223 | * Time for next connect retry. | ||
224 | */ | ||
225 | struct GNUNET_TIME_Relative backoff; | ||
226 | |||
227 | /** | ||
228 | * Size of the 'watches' array. | ||
229 | */ | ||
230 | unsigned int watches_size; | ||
231 | |||
232 | /** | ||
182 | * Should this handle auto-destruct once all actions have | 233 | * Should this handle auto-destruct once all actions have |
183 | * been processed? | 234 | * been processed? |
184 | */ | 235 | */ |
185 | int do_destroy; | 236 | int do_destroy; |
186 | 237 | ||
238 | /** | ||
239 | * Are we currently receiving from the service? | ||
240 | */ | ||
241 | int receiving; | ||
242 | |||
187 | }; | 243 | }; |
188 | 244 | ||
189 | 245 | ||
246 | |||
247 | /** | ||
248 | * Schedule the next action to be performed. | ||
249 | */ | ||
250 | static void schedule_action (struct GNUNET_STATISTICS_Handle *h); | ||
251 | |||
252 | /** | ||
253 | * Try to (re)connect to the statistics service. | ||
254 | * | ||
255 | * @return GNUNET_YES on success, GNUNET_NO on failure. | ||
256 | */ | ||
257 | static int | ||
258 | try_connect (struct GNUNET_STATISTICS_Handle *ret); | ||
259 | |||
260 | |||
261 | static void | ||
262 | insert_ai (struct GNUNET_STATISTICS_Handle *h, struct GNUNET_STATISTICS_GetHandle *ai) | ||
263 | { | ||
264 | GNUNET_CONTAINER_DLL_insert_after (h->action_head, | ||
265 | h->action_tail, | ||
266 | h->action_tail, | ||
267 | ai); | ||
268 | if (h->action_head == ai) | ||
269 | schedule_action (h); | ||
270 | } | ||
271 | |||
272 | |||
273 | static void | ||
274 | schedule_watch_request (struct GNUNET_STATISTICS_Handle *h, | ||
275 | struct GNUNET_STATISTICS_WatchEntry *watch) | ||
276 | { | ||
277 | |||
278 | struct GNUNET_STATISTICS_GetHandle *ai; | ||
279 | size_t slen; | ||
280 | size_t nlen; | ||
281 | size_t nsize; | ||
282 | |||
283 | GNUNET_assert (h != NULL); | ||
284 | if (GNUNET_YES != try_connect (h)) | ||
285 | { | ||
286 | schedule_action (h); | ||
287 | return; | ||
288 | } | ||
289 | slen = strlen (watch->subsystem) + 1; | ||
290 | nlen = strlen (watch->name) + 1; | ||
291 | nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen; | ||
292 | if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
293 | { | ||
294 | GNUNET_break (0); | ||
295 | return; | ||
296 | } | ||
297 | ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle)); | ||
298 | ai->sh = h; | ||
299 | ai->subsystem = GNUNET_strdup (watch->subsystem); | ||
300 | ai->name = GNUNET_strdup (watch->name); | ||
301 | ai->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
302 | ai->msize = nsize; | ||
303 | ai->type = ACTION_WATCH; | ||
304 | ai->proc = watch->proc; | ||
305 | ai->cls = watch->proc_cls; | ||
306 | insert_ai (h, ai); | ||
307 | } | ||
308 | |||
309 | |||
190 | /** | 310 | /** |
191 | * Try to (re)connect to the statistics service. | 311 | * Try to (re)connect to the statistics service. |
192 | * | 312 | * |
@@ -195,11 +315,16 @@ struct GNUNET_STATISTICS_Handle | |||
195 | static int | 315 | static int |
196 | try_connect (struct GNUNET_STATISTICS_Handle *ret) | 316 | try_connect (struct GNUNET_STATISTICS_Handle *ret) |
197 | { | 317 | { |
318 | unsigned int i; | ||
198 | if (ret->client != NULL) | 319 | if (ret->client != NULL) |
199 | return GNUNET_YES; | 320 | return GNUNET_YES; |
200 | ret->client = GNUNET_CLIENT_connect (ret->sched, "statistics", ret->cfg); | 321 | ret->client = GNUNET_CLIENT_connect (ret->sched, "statistics", ret->cfg); |
201 | if (ret->client != NULL) | 322 | if (ret->client != NULL) |
202 | return GNUNET_YES; | 323 | { |
324 | for (i=0;i<ret->watches_size;i++) | ||
325 | schedule_watch_request (ret, ret->watches[i]); | ||
326 | return GNUNET_YES; | ||
327 | } | ||
203 | #if DEBUG_STATISTICS | 328 | #if DEBUG_STATISTICS |
204 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 329 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
205 | _("Failed to connect to statistics service!\n")); | 330 | _("Failed to connect to statistics service!\n")); |
@@ -221,12 +346,6 @@ free_action_item (struct GNUNET_STATISTICS_GetHandle *ai) | |||
221 | 346 | ||
222 | 347 | ||
223 | /** | 348 | /** |
224 | * Schedule the next action to be performed. | ||
225 | */ | ||
226 | static void schedule_action (struct GNUNET_STATISTICS_Handle *h); | ||
227 | |||
228 | |||
229 | /** | ||
230 | * GET processing is complete, tell client about it. | 349 | * GET processing is complete, tell client about it. |
231 | */ | 350 | */ |
232 | static void | 351 | static void |
@@ -259,7 +378,13 @@ process_message (struct GNUNET_STATISTICS_Handle *h, | |||
259 | uint16_t size; | 378 | uint16_t size; |
260 | 379 | ||
261 | if (h->current->aborted) | 380 | if (h->current->aborted) |
262 | return GNUNET_OK; /* don't bother */ | 381 | { |
382 | #if DEBUG_STATISTICS | ||
383 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
384 | "Iteration was aborted, ignoring VALUE\n"); | ||
385 | #endif | ||
386 | return GNUNET_OK; /* don't bother */ | ||
387 | } | ||
263 | size = ntohs (msg->size); | 388 | size = ntohs (msg->size); |
264 | if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage)) | 389 | if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage)) |
265 | { | 390 | { |
@@ -293,6 +418,42 @@ process_message (struct GNUNET_STATISTICS_Handle *h, | |||
293 | #endif | 418 | #endif |
294 | h->current->aborted = GNUNET_YES; | 419 | h->current->aborted = GNUNET_YES; |
295 | } | 420 | } |
421 | #if DEBUG_STATISTICS | ||
422 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
423 | "VALUE processed successfully\n"); | ||
424 | #endif | ||
425 | return GNUNET_OK; | ||
426 | } | ||
427 | |||
428 | |||
429 | static int | ||
430 | process_watch_value (struct GNUNET_STATISTICS_Handle *h, | ||
431 | const struct GNUNET_MessageHeader *msg) | ||
432 | { | ||
433 | const struct GNUNET_STATISTICS_WatchValueMessage *wvm; | ||
434 | struct GNUNET_STATISTICS_WatchEntry *w; | ||
435 | uint32_t wid; | ||
436 | |||
437 | if (sizeof(struct GNUNET_STATISTICS_WatchValueMessage) != | ||
438 | ntohs (msg->size)) | ||
439 | { | ||
440 | GNUNET_break (0); | ||
441 | return GNUNET_SYSERR; | ||
442 | } | ||
443 | wvm = (const struct GNUNET_STATISTICS_WatchValueMessage *)msg; | ||
444 | wid = ntohl (wvm->wid); | ||
445 | if (wid >= h->watches_size) | ||
446 | { | ||
447 | GNUNET_break (0); | ||
448 | return GNUNET_SYSERR; | ||
449 | } | ||
450 | w = h->watches[wid]; | ||
451 | (void) w->proc (w->proc_cls, | ||
452 | w->subsystem, | ||
453 | w->name, | ||
454 | GNUNET_ntohll (wvm->value), | ||
455 | 0 != | ||
456 | (ntohl (wvm->flags) & GNUNET_STATISTICS_PERSIST_BIT)); | ||
296 | return GNUNET_OK; | 457 | return GNUNET_OK; |
297 | } | 458 | } |
298 | 459 | ||
@@ -329,21 +490,53 @@ receive_stats (void *cls, const struct GNUNET_MessageHeader *msg) | |||
329 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 490 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
330 | "Received end of statistics marker\n"); | 491 | "Received end of statistics marker\n"); |
331 | #endif | 492 | #endif |
493 | h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
332 | finish (h, GNUNET_OK); | 494 | finish (h, GNUNET_OK); |
495 | if (h->watches_size > 0) | ||
496 | { | ||
497 | GNUNET_CLIENT_receive (h->client, | ||
498 | &receive_stats, | ||
499 | h, | ||
500 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
501 | } | ||
502 | else | ||
503 | { | ||
504 | h->receiving = GNUNET_NO; | ||
505 | } | ||
333 | return; | 506 | return; |
334 | case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE: | 507 | case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE: |
335 | if (GNUNET_OK == process_message (h, msg)) | 508 | if (GNUNET_OK == process_message (h, msg)) |
336 | { | 509 | { |
337 | /* finally, look for more! */ | 510 | /* finally, look for more! */ |
511 | #if DEBUG_STATISTICS | ||
512 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
513 | "Processing VALUE done, now reading more\n"); | ||
514 | #endif | ||
338 | GNUNET_CLIENT_receive (h->client, | 515 | GNUNET_CLIENT_receive (h->client, |
339 | &receive_stats, | 516 | &receive_stats, |
340 | h, | 517 | h, |
341 | GNUNET_TIME_absolute_get_remaining | 518 | GNUNET_TIME_absolute_get_remaining |
342 | (h->current->timeout)); | 519 | (h->current->timeout)); |
520 | h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
343 | return; | 521 | return; |
344 | } | 522 | } |
345 | GNUNET_break (0); | 523 | GNUNET_break (0); |
346 | break; | 524 | break; |
525 | case GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE: | ||
526 | if (GNUNET_OK == | ||
527 | process_watch_value (h, | ||
528 | msg)) | ||
529 | { | ||
530 | h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
531 | GNUNET_assert (h->watches_size > 0); | ||
532 | GNUNET_CLIENT_receive (h->client, | ||
533 | &receive_stats, | ||
534 | h, | ||
535 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
536 | return; | ||
537 | } | ||
538 | GNUNET_break (0); | ||
539 | break; | ||
347 | default: | 540 | default: |
348 | GNUNET_break (0); | 541 | GNUNET_break (0); |
349 | break; | 542 | break; |
@@ -392,15 +585,69 @@ transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) | |||
392 | 2, | 585 | 2, |
393 | handle->current->subsystem, | 586 | handle->current->subsystem, |
394 | handle->current->name)); | 587 | handle->current->name)); |
395 | GNUNET_CLIENT_receive (handle->client, | 588 | if (! handle->receiving) |
396 | &receive_stats, | 589 | { |
397 | handle, | 590 | #if DEBUG_STATISTICS |
398 | GNUNET_TIME_absolute_get_remaining (handle-> | 591 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
399 | current->timeout)); | 592 | "Transmission of GET done, now reading response\n"); |
593 | #endif | ||
594 | handle->receiving = GNUNET_YES; | ||
595 | GNUNET_CLIENT_receive (handle->client, | ||
596 | &receive_stats, | ||
597 | handle, | ||
598 | GNUNET_TIME_absolute_get_remaining (handle-> | ||
599 | current->timeout)); | ||
600 | } | ||
400 | return msize; | 601 | return msize; |
401 | } | 602 | } |
402 | 603 | ||
403 | 604 | ||
605 | /** | ||
606 | * Transmit a WATCH request (and if successful, start to receive | ||
607 | * the response). | ||
608 | */ | ||
609 | static size_t | ||
610 | transmit_watch (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) | ||
611 | { | ||
612 | struct GNUNET_MessageHeader *hdr; | ||
613 | size_t slen1; | ||
614 | size_t slen2; | ||
615 | uint16_t msize; | ||
616 | |||
617 | if (buf == NULL) | ||
618 | { | ||
619 | /* timeout / error */ | ||
620 | #if DEBUG_STATISTICS | ||
621 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
622 | "Transmission of request for statistics failed!\n"); | ||
623 | #endif | ||
624 | finish (handle, GNUNET_SYSERR); | ||
625 | return 0; | ||
626 | } | ||
627 | slen1 = strlen (handle->current->subsystem) + 1; | ||
628 | slen2 = strlen (handle->current->name) + 1; | ||
629 | msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); | ||
630 | GNUNET_assert (msize <= size); | ||
631 | hdr = (struct GNUNET_MessageHeader *) buf; | ||
632 | hdr->size = htons (msize); | ||
633 | hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH); | ||
634 | GNUNET_assert (slen1 + slen2 == | ||
635 | GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], | ||
636 | slen1 + slen2, | ||
637 | 2, | ||
638 | handle->current->subsystem, | ||
639 | handle->current->name)); | ||
640 | if (! handle->receiving) | ||
641 | { | ||
642 | handle->receiving = GNUNET_YES; | ||
643 | GNUNET_CLIENT_receive (handle->client, | ||
644 | &receive_stats, | ||
645 | handle, | ||
646 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
647 | } | ||
648 | return msize; | ||
649 | } | ||
650 | |||
404 | 651 | ||
405 | /** | 652 | /** |
406 | * Transmit a SET/UPDATE request. | 653 | * Transmit a SET/UPDATE request. |
@@ -464,6 +711,9 @@ transmit_action (void *cls, size_t size, void *buf) | |||
464 | case ACTION_UPDATE: | 711 | case ACTION_UPDATE: |
465 | ret = transmit_set (handle, size, buf); | 712 | ret = transmit_set (handle, size, buf); |
466 | break; | 713 | break; |
714 | case ACTION_WATCH: | ||
715 | ret = transmit_watch (handle, size, buf); | ||
716 | break; | ||
467 | default: | 717 | default: |
468 | ret = 0; | 718 | ret = 0; |
469 | GNUNET_break (0); | 719 | GNUNET_break (0); |
@@ -495,6 +745,7 @@ GNUNET_STATISTICS_create (struct GNUNET_SCHEDULER_Handle *sched, | |||
495 | ret->sched = sched; | 745 | ret->sched = sched; |
496 | ret->cfg = cfg; | 746 | ret->cfg = cfg; |
497 | ret->subsystem = GNUNET_strdup (subsystem); | 747 | ret->subsystem = GNUNET_strdup (subsystem); |
748 | ret->backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
498 | try_connect (ret); | 749 | try_connect (ret); |
499 | return ret; | 750 | return ret; |
500 | } | 751 | } |
@@ -516,7 +767,11 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, | |||
516 | struct GNUNET_STATISTICS_GetHandle *next; | 767 | struct GNUNET_STATISTICS_GetHandle *next; |
517 | struct GNUNET_STATISTICS_GetHandle *prev; | 768 | struct GNUNET_STATISTICS_GetHandle *prev; |
518 | struct GNUNET_TIME_Relative timeout; | 769 | struct GNUNET_TIME_Relative timeout; |
770 | int i; | ||
519 | 771 | ||
772 | if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task) | ||
773 | GNUNET_SCHEDULER_cancel (h->sched, | ||
774 | h->backoff_task); | ||
520 | if (sync_first) | 775 | if (sync_first) |
521 | { | 776 | { |
522 | if (h->current != NULL) | 777 | if (h->current != NULL) |
@@ -591,11 +846,30 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, | |||
591 | GNUNET_CLIENT_disconnect (h->client, GNUNET_YES); | 846 | GNUNET_CLIENT_disconnect (h->client, GNUNET_YES); |
592 | h->client = NULL; | 847 | h->client = NULL; |
593 | } | 848 | } |
849 | for (i=0;i<h->watches_size;i++) | ||
850 | { | ||
851 | GNUNET_free (h->watches[i]->subsystem); | ||
852 | GNUNET_free (h->watches[i]->name); | ||
853 | GNUNET_free (h->watches[i]); | ||
854 | } | ||
855 | GNUNET_array_grow (h->watches, | ||
856 | h->watches_size, | ||
857 | 0); | ||
594 | GNUNET_free (h->subsystem); | 858 | GNUNET_free (h->subsystem); |
595 | GNUNET_free (h); | 859 | GNUNET_free (h); |
596 | } | 860 | } |
597 | 861 | ||
598 | 862 | ||
863 | static void | ||
864 | finish_task (void *cls, | ||
865 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
866 | { | ||
867 | struct GNUNET_STATISTICS_Handle *h = cls; | ||
868 | |||
869 | h->backoff_task = GNUNET_SCHEDULER_NO_TASK; | ||
870 | finish (h, GNUNET_SYSERR); | ||
871 | } | ||
872 | |||
599 | 873 | ||
600 | /** | 874 | /** |
601 | * Schedule the next action to be performed. | 875 | * Schedule the next action to be performed. |
@@ -609,7 +883,13 @@ schedule_action (struct GNUNET_STATISTICS_Handle *h) | |||
609 | return; /* action already pending */ | 883 | return; /* action already pending */ |
610 | if (GNUNET_YES != try_connect (h)) | 884 | if (GNUNET_YES != try_connect (h)) |
611 | { | 885 | { |
612 | finish (h, GNUNET_SYSERR); | 886 | h->backoff_task = GNUNET_SCHEDULER_add_delayed (h->sched, |
887 | h->backoff, | ||
888 | &finish_task, | ||
889 | h); | ||
890 | h->backoff = GNUNET_TIME_relative_multiply (h->backoff, 2); | ||
891 | h->backoff = GNUNET_TIME_relative_min (h->backoff, | ||
892 | GNUNET_CONSTANTS_SERVICE_TIMEOUT); | ||
613 | return; | 893 | return; |
614 | } | 894 | } |
615 | 895 | ||
@@ -643,19 +923,6 @@ schedule_action (struct GNUNET_STATISTICS_Handle *h) | |||
643 | } | 923 | } |
644 | } | 924 | } |
645 | 925 | ||
646 | |||
647 | static void | ||
648 | insert_ai (struct GNUNET_STATISTICS_Handle *h, struct GNUNET_STATISTICS_GetHandle *ai) | ||
649 | { | ||
650 | GNUNET_CONTAINER_DLL_insert_after (h->action_head, | ||
651 | h->action_tail, | ||
652 | h->action_tail, | ||
653 | ai); | ||
654 | if (h->action_head == ai) | ||
655 | schedule_action (h); | ||
656 | } | ||
657 | |||
658 | |||
659 | /** | 926 | /** |
660 | * Get statistic from the peer. | 927 | * Get statistic from the peer. |
661 | * | 928 | * |
@@ -742,6 +1009,40 @@ GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh) | |||
742 | } | 1009 | } |
743 | 1010 | ||
744 | 1011 | ||
1012 | /** | ||
1013 | * Watch statistics from the peer (be notified whenever they change). | ||
1014 | * Note that the only way to cancel a "watch" request is to destroy | ||
1015 | * the statistics handle given as the first argument to this call. | ||
1016 | * | ||
1017 | * @param handle identification of the statistics service | ||
1018 | * @param subsystem limit to the specified subsystem, never NULL | ||
1019 | * @param name name of the statistic value, never NULL | ||
1020 | * @param proc function to call on each value | ||
1021 | * @param proc_cls closure for proc | ||
1022 | * @return GNUNET_OK on success, GNUNET_SYSERR on error | ||
1023 | */ | ||
1024 | int | ||
1025 | GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle, | ||
1026 | const char *subsystem, | ||
1027 | const char *name, | ||
1028 | GNUNET_STATISTICS_Iterator proc, | ||
1029 | void *proc_cls) | ||
1030 | { | ||
1031 | struct GNUNET_STATISTICS_WatchEntry *w; | ||
1032 | |||
1033 | w = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_WatchEntry)); | ||
1034 | w->subsystem = GNUNET_strdup (subsystem); | ||
1035 | w->name = GNUNET_strdup (name); | ||
1036 | w->proc = proc; | ||
1037 | w->proc_cls = proc_cls; | ||
1038 | GNUNET_array_append (handle->watches, | ||
1039 | handle->watches_size, | ||
1040 | w); | ||
1041 | schedule_watch_request (handle, w); | ||
1042 | return GNUNET_OK; | ||
1043 | } | ||
1044 | |||
1045 | |||
745 | static void | 1046 | static void |
746 | add_setter_action (struct GNUNET_STATISTICS_Handle *h, | 1047 | add_setter_action (struct GNUNET_STATISTICS_Handle *h, |
747 | const char *name, | 1048 | const char *name, |
@@ -809,7 +1110,8 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h, | |||
809 | ai->type = type; | 1110 | ai->type = type; |
810 | } | 1111 | } |
811 | } | 1112 | } |
812 | ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); | 1113 | ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); |
1114 | ai->make_persistent = make_persistent; | ||
813 | return; | 1115 | return; |
814 | } | 1116 | } |
815 | ai = ai->next; | 1117 | ai = ai->next; |
@@ -824,7 +1126,6 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h, | |||
824 | ai->value = value; | 1126 | ai->value = value; |
825 | ai->type = type; | 1127 | ai->type = type; |
826 | insert_ai (h, ai); | 1128 | insert_ai (h, ai); |
827 | schedule_action (h); | ||
828 | } | 1129 | } |
829 | 1130 | ||
830 | 1131 | ||
diff --git a/src/statistics/test_statistics_api.c b/src/statistics/test_statistics_api.c index 378e17d0c..5c55a11a6 100644 --- a/src/statistics/test_statistics_api.c +++ b/src/statistics/test_statistics_api.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include "gnunet_scheduler_lib.h" | 29 | #include "gnunet_scheduler_lib.h" |
30 | #include "gnunet_statistics_service.h" | 30 | #include "gnunet_statistics_service.h" |
31 | 31 | ||
32 | #define VERBOSE GNUNET_NO | 32 | #define DEBUG_STATISTICS GNUNET_NO |
33 | 33 | ||
34 | #define START_SERVICE GNUNET_YES | 34 | #define START_SERVICE GNUNET_YES |
35 | 35 | ||
@@ -38,6 +38,11 @@ check_1 (void *cls, | |||
38 | const char *subsystem, | 38 | const char *subsystem, |
39 | const char *name, uint64_t value, int is_persistent) | 39 | const char *name, uint64_t value, int is_persistent) |
40 | { | 40 | { |
41 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
42 | "Received value %llu for `%s:%s\n", | ||
43 | (unsigned long long) value, | ||
44 | subsystem, | ||
45 | name); | ||
41 | GNUNET_assert (0 == strcmp (name, "test-1")); | 46 | GNUNET_assert (0 == strcmp (name, "test-1")); |
42 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); | 47 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); |
43 | GNUNET_assert (value == 1); | 48 | GNUNET_assert (value == 1); |
@@ -50,6 +55,11 @@ check_2 (void *cls, | |||
50 | const char *subsystem, | 55 | const char *subsystem, |
51 | const char *name, uint64_t value, int is_persistent) | 56 | const char *name, uint64_t value, int is_persistent) |
52 | { | 57 | { |
58 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
59 | "Received value %llu for `%s:%s\n", | ||
60 | (unsigned long long) value, | ||
61 | subsystem, | ||
62 | name); | ||
53 | GNUNET_assert (0 == strcmp (name, "test-2")); | 63 | GNUNET_assert (0 == strcmp (name, "test-2")); |
54 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); | 64 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); |
55 | GNUNET_assert (value == 2); | 65 | GNUNET_assert (value == 2); |
@@ -62,6 +72,11 @@ check_3 (void *cls, | |||
62 | const char *subsystem, | 72 | const char *subsystem, |
63 | const char *name, uint64_t value, int is_persistent) | 73 | const char *name, uint64_t value, int is_persistent) |
64 | { | 74 | { |
75 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
76 | "Received value %llu for `%s:%s\n", | ||
77 | (unsigned long long) value, | ||
78 | subsystem, | ||
79 | name); | ||
65 | GNUNET_assert (0 == strcmp (name, "test-3")); | 80 | GNUNET_assert (0 == strcmp (name, "test-3")); |
66 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); | 81 | GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); |
67 | GNUNET_assert (value == 3); | 82 | GNUNET_assert (value == 3); |
@@ -85,6 +100,8 @@ static void | |||
85 | next (void *cls, int success) | 100 | next (void *cls, int success) |
86 | { | 101 | { |
87 | GNUNET_assert (success == GNUNET_OK); | 102 | GNUNET_assert (success == GNUNET_OK); |
103 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
104 | "Issuing GET request\n"); | ||
88 | GNUNET_break (NULL != | 105 | GNUNET_break (NULL != |
89 | GNUNET_STATISTICS_get (h, NULL, "test-2", | 106 | GNUNET_STATISTICS_get (h, NULL, "test-2", |
90 | GNUNET_TIME_UNIT_SECONDS, &next_fin, &check_2, cls)); | 107 | GNUNET_TIME_UNIT_SECONDS, &next_fin, &check_2, cls)); |
@@ -102,6 +119,8 @@ run (void *cls, | |||
102 | GNUNET_STATISTICS_set (h, "test-2", 2, GNUNET_NO); | 119 | GNUNET_STATISTICS_set (h, "test-2", 2, GNUNET_NO); |
103 | GNUNET_STATISTICS_set (h, "test-3", 2, GNUNET_NO); | 120 | GNUNET_STATISTICS_set (h, "test-3", 2, GNUNET_NO); |
104 | GNUNET_STATISTICS_update (h, "test-3", 1, GNUNET_YES); | 121 | GNUNET_STATISTICS_update (h, "test-3", 1, GNUNET_YES); |
122 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
123 | "Issuing GET request\n"); | ||
105 | GNUNET_break (NULL != | 124 | GNUNET_break (NULL != |
106 | GNUNET_STATISTICS_get (h, NULL, "test-1", | 125 | GNUNET_STATISTICS_get (h, NULL, "test-1", |
107 | GNUNET_TIME_UNIT_SECONDS, &next, &check_1, cls)); | 126 | GNUNET_TIME_UNIT_SECONDS, &next, &check_1, cls)); |
@@ -127,6 +146,11 @@ check () | |||
127 | char *const argv[] = { "test-statistics-api", | 146 | char *const argv[] = { "test-statistics-api", |
128 | "-c", | 147 | "-c", |
129 | "test_statistics_api_data.conf", | 148 | "test_statistics_api_data.conf", |
149 | #if DEBUG_STATISTICS | ||
150 | "-L", "DEBUG", | ||
151 | #else | ||
152 | "-L", "WARNING", | ||
153 | #endif | ||
130 | NULL | 154 | NULL |
131 | }; | 155 | }; |
132 | struct GNUNET_GETOPT_CommandLineOption options[] = { | 156 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
@@ -141,7 +165,7 @@ check () | |||
141 | #endif | 165 | #endif |
142 | "-c", "test_statistics_api_data.conf", NULL); | 166 | "-c", "test_statistics_api_data.conf", NULL); |
143 | #endif | 167 | #endif |
144 | GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", | 168 | GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", |
145 | options, &run, &ok); | 169 | options, &run, &ok); |
146 | #if START_SERVICE | 170 | #if START_SERVICE |
147 | if (0 != PLIBC_KILL (pid, SIGTERM)) | 171 | if (0 != PLIBC_KILL (pid, SIGTERM)) |
@@ -163,7 +187,7 @@ check () | |||
163 | #endif | 187 | #endif |
164 | "-c", "test_statistics_api_data.conf", NULL); | 188 | "-c", "test_statistics_api_data.conf", NULL); |
165 | #endif | 189 | #endif |
166 | GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", | 190 | GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", |
167 | options, &run_more, &ok); | 191 | options, &run_more, &ok); |
168 | #if START_SERVICE | 192 | #if START_SERVICE |
169 | if (0 != PLIBC_KILL (pid, SIGTERM)) | 193 | if (0 != PLIBC_KILL (pid, SIGTERM)) |
@@ -181,6 +205,13 @@ main (int argc, char *argv[]) | |||
181 | { | 205 | { |
182 | int ret; | 206 | int ret; |
183 | 207 | ||
208 | GNUNET_log_setup ("test_statistics_api", | ||
209 | #if DEBUG_STATISTICS | ||
210 | "DEBUG", | ||
211 | #else | ||
212 | "WARNING", | ||
213 | #endif | ||
214 | NULL); | ||
184 | ret = check (); | 215 | ret = check (); |
185 | 216 | ||
186 | return ret; | 217 | return ret; |
diff --git a/src/statistics/test_statistics_api_data.conf b/src/statistics/test_statistics_api_data.conf index 41cfd9596..ba8d4d68e 100644 --- a/src/statistics/test_statistics_api_data.conf +++ b/src/statistics/test_statistics_api_data.conf | |||
@@ -4,9 +4,12 @@ DEFAULTCONFIG = test_statistics_api_data.conf | |||
4 | 4 | ||
5 | [statistics] | 5 | [statistics] |
6 | PORT = 22353 | 6 | PORT = 22353 |
7 | UNIXPATH = /tmp/test-statistics-service-statistics.unix | ||
8 | DEBUG = YES | ||
7 | 9 | ||
8 | [arm] | 10 | [arm] |
9 | PORT = 22354 | 11 | PORT = 22354 |
10 | DEFAULTSERVICES = | 12 | DEFAULTSERVICES = |
13 | UNIXPATH = /tmp/test-statistics-service-arm.unix | ||
11 | # DEBUG = YES | 14 | # DEBUG = YES |
12 | 15 | ||