2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file statistics/statistics_api.c
23 * @brief API of the statistics service
24 * @author Christian Grothoff
27 #include "gnunet_client_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_server_lib.h"
32 #include "gnunet_statistics_service.h"
33 #include "gnunet_strings_lib.h"
34 #include "statistics.h"
37 * How long do we wait until a statistics request for setting
38 * a value times out? (The update will be lost if the
39 * service does not react within this timeframe).
41 #define SET_TRANSMIT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
43 #define LOG(kind,...) GNUNET_log_from (kind, "statistics-api",__VA_ARGS__)
73 * Entry kept for each value we are watching.
75 struct GNUNET_STATISTICS_WatchEntry
79 * What subsystem is this action about? (never NULL)
84 * What value is this action about? (never NULL)
91 GNUNET_STATISTICS_Iterator proc;
102 * Linked list of things we still need to do.
104 struct GNUNET_STATISTICS_GetHandle
108 * This is a doubly linked list.
110 struct GNUNET_STATISTICS_GetHandle *next;
113 * This is a doubly linked list.
115 struct GNUNET_STATISTICS_GetHandle *prev;
118 * Main statistics handle.
120 struct GNUNET_STATISTICS_Handle *sh;
123 * What subsystem is this action about? (can be NULL)
128 * What value is this action about? (can be NULL)
133 * Continuation to call once action is complete.
135 GNUNET_STATISTICS_Callback cont;
138 * Function to call (for GET actions only).
140 GNUNET_STATISTICS_Iterator proc;
143 * Closure for proc and cont.
148 * Timeout for this action.
150 struct GNUNET_TIME_Absolute timeout;
158 * Flag for SET/UPDATE actions.
163 * Has the current iteration been aborted; for GET actions.
168 * Is this a GET, SET, UPDATE or WATCH?
170 enum ActionType type;
173 * Size of the message that we will be transmitting.
181 * Handle for the service.
183 struct GNUNET_STATISTICS_Handle
186 * Name of our subsystem.
191 * Configuration to use.
193 const struct GNUNET_CONFIGURATION_Handle *cfg;
196 * Socket (if available).
198 struct GNUNET_CLIENT_Connection *client;
201 * Currently pending transmission request.
203 struct GNUNET_CLIENT_TransmitHandle *th;
206 * Head of the linked list of pending actions (first action
209 struct GNUNET_STATISTICS_GetHandle *action_head;
212 * Tail of the linked list of actions (for fast append).
214 struct GNUNET_STATISTICS_GetHandle *action_tail;
217 * Action we are currently busy with (action request has been
218 * transmitted, we're now receiving the response from the
221 struct GNUNET_STATISTICS_GetHandle *current;
224 * Array of watch entries.
226 struct GNUNET_STATISTICS_WatchEntry **watches;
229 * Task doing exponential back-off trying to reconnect.
231 GNUNET_SCHEDULER_TaskIdentifier backoff_task;
234 * Time for next connect retry.
236 struct GNUNET_TIME_Relative backoff;
239 * Size of the 'watches' array.
241 unsigned int watches_size;
244 * Should this handle auto-destruct once all actions have
250 * Are we currently receiving from the service?
258 * Schedule the next action to be performed.
260 * @param h statistics handle to reconnect
263 schedule_action (struct GNUNET_STATISTICS_Handle *h);
267 * Transmit request to service that we want to watch
268 * the development of a particular value.
270 * @param h statistics handle
271 * @param watch watch entry of the value to watch
274 schedule_watch_request (struct GNUNET_STATISTICS_Handle *h,
275 struct GNUNET_STATISTICS_WatchEntry *watch)
278 struct GNUNET_STATISTICS_GetHandle *ai;
283 GNUNET_assert (h != NULL);
284 slen = strlen (watch->subsystem) + 1;
285 nlen = strlen (watch->name) + 1;
286 nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen;
287 if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
292 ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
294 ai->subsystem = GNUNET_strdup (watch->subsystem);
295 ai->name = GNUNET_strdup (watch->name);
296 ai->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
298 ai->type = ACTION_WATCH;
299 ai->proc = watch->proc;
300 ai->cls = watch->proc_cls;
301 GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail,
308 * Free memory associated with the given action item.
310 * @param gh action item to free
313 free_action_item (struct GNUNET_STATISTICS_GetHandle *gh)
315 GNUNET_free_non_null (gh->subsystem);
316 GNUNET_free_non_null (gh->name);
322 * Disconnect from the statistics service.
324 * @param h statistics handle to disconnect from
327 do_disconnect (struct GNUNET_STATISTICS_Handle *h)
329 struct GNUNET_STATISTICS_GetHandle *c;
334 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
336 GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
338 h->receiving = GNUNET_NO;
339 if (NULL != (c = h->current))
343 c->cont (c->cls, GNUNET_SYSERR);
344 free_action_item (c);
350 * Try to (re)connect to the statistics service.
352 * @param h statistics handle to reconnect
353 * @return GNUNET_YES on success, GNUNET_NO on failure.
356 try_connect (struct GNUNET_STATISTICS_Handle *h)
358 struct GNUNET_STATISTICS_GetHandle *gh;
359 struct GNUNET_STATISTICS_GetHandle *gn;
362 if (h->backoff_task != GNUNET_SCHEDULER_NO_TASK)
364 if (h->client != NULL)
366 h->client = GNUNET_CLIENT_connect ("statistics", h->cfg);
367 if (h->client != NULL)
370 while (NULL != (gh = gn))
373 if (gh->type == ACTION_WATCH)
375 GNUNET_CONTAINER_DLL_remove (h->action_head,
378 free_action_item (gh);
381 for (i = 0; i < h->watches_size; i++)
382 schedule_watch_request (h, h->watches[i]);
386 LOG (GNUNET_ERROR_TYPE_DEBUG,
387 _("Failed to connect to statistics service!\n"));
394 * We've waited long enough, reconnect now.
396 * @param cls the 'struct GNUNET_STATISTICS_Handle' to reconnect
397 * @param tc scheduler context (unused)
400 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
402 struct GNUNET_STATISTICS_Handle *h = cls;
404 h->backoff_task = GNUNET_SCHEDULER_NO_TASK;
410 * Reconnect at a later time, respecting back-off.
412 * @param h statistics handle
415 reconnect_later (struct GNUNET_STATISTICS_Handle *h)
417 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->backoff_task);
419 GNUNET_SCHEDULER_add_delayed (h->backoff, &reconnect_task, h);
420 h->backoff = GNUNET_TIME_relative_multiply (h->backoff, 2);
422 GNUNET_TIME_relative_min (h->backoff, GNUNET_CONSTANTS_SERVICE_TIMEOUT);
427 * Process a 'GNUNET_MESSAGE_TYPE_STATISTICS_VALUE' message.
429 * @param h statistics handle
430 * @param msg message received from the service, never NULL
431 * @return GNUNET_OK if the message was well-formed
434 process_statistics_value_message (struct GNUNET_STATISTICS_Handle *h,
435 const struct GNUNET_MessageHeader *msg)
439 const struct GNUNET_STATISTICS_ReplyMessage *smsg;
442 if (h->current->aborted)
445 LOG (GNUNET_ERROR_TYPE_DEBUG, "Iteration was aborted, ignoring VALUE\n");
447 return GNUNET_OK; /* don't bother */
449 size = ntohs (msg->size);
450 if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage))
453 return GNUNET_SYSERR;
455 smsg = (const struct GNUNET_STATISTICS_ReplyMessage *) msg;
456 size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage);
458 GNUNET_STRINGS_buffer_tokenize ((const char *) &smsg[1], size, 2,
462 return GNUNET_SYSERR;
465 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received valid statistic on `%s:%s': %llu\n",
466 service, name, GNUNET_ntohll (smsg->value));
469 h->current->proc (h->current->cls, service, name,
470 GNUNET_ntohll (smsg->value),
472 (ntohl (smsg->uid) & GNUNET_STATISTICS_PERSIST_BIT)))
475 LOG (GNUNET_ERROR_TYPE_DEBUG,
476 "Processing of remaining statistics aborted by client.\n");
478 h->current->aborted = GNUNET_YES;
481 LOG (GNUNET_ERROR_TYPE_DEBUG, "VALUE processed successfully\n");
488 * We have received a watch value from the service. Process it.
490 * @param h statistics handle
491 * @param msg the watch value message
492 * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
495 process_watch_value (struct GNUNET_STATISTICS_Handle *h,
496 const struct GNUNET_MessageHeader *msg)
498 const struct GNUNET_STATISTICS_WatchValueMessage *wvm;
499 struct GNUNET_STATISTICS_WatchEntry *w;
502 if (sizeof (struct GNUNET_STATISTICS_WatchValueMessage) != ntohs (msg->size))
505 return GNUNET_SYSERR;
507 wvm = (const struct GNUNET_STATISTICS_WatchValueMessage *) msg;
508 GNUNET_break (0 == ntohl (wvm->reserved));
509 wid = ntohl (wvm->wid);
510 if (wid >= h->watches_size)
513 return GNUNET_SYSERR;
516 (void) w->proc (w->proc_cls, w->subsystem, w->name,
517 GNUNET_ntohll (wvm->value),
518 0 != (ntohl (wvm->flags) & GNUNET_STATISTICS_PERSIST_BIT));
524 * Function called with messages from stats service.
527 * @param msg message received, NULL on timeout or fatal error
530 receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
532 struct GNUNET_STATISTICS_Handle *h = cls;
533 struct GNUNET_STATISTICS_GetHandle *c;
539 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
540 "Error receiving statistics from service, is the service running?\n");
546 switch (ntohs (msg->type))
548 case GNUNET_MESSAGE_TYPE_STATISTICS_END:
550 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of statistics marker\n");
552 if (NULL == (c = h->current))
559 h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
560 if (h->watches_size > 0)
562 GNUNET_CLIENT_receive (h->client, &receive_stats, h,
563 GNUNET_TIME_UNIT_FOREVER_REL);
567 h->receiving = GNUNET_NO;
572 c->cont (c->cls, GNUNET_OK);
573 free_action_item (c);
575 case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE:
576 if (GNUNET_OK != process_statistics_value_message (h, msg))
582 /* finally, look for more! */
584 LOG (GNUNET_ERROR_TYPE_DEBUG,
585 "Processing VALUE done, now reading more\n");
587 GNUNET_CLIENT_receive (h->client, &receive_stats, h,
588 GNUNET_TIME_absolute_get_remaining (h->
590 h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
592 case GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE:
594 process_watch_value (h, msg))
600 h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
601 GNUNET_assert (h->watches_size > 0);
602 GNUNET_CLIENT_receive (h->client, &receive_stats, h,
603 GNUNET_TIME_UNIT_FOREVER_REL);
615 * Transmit a GET request (and if successful, start to receive
618 * @param handle statistics handle
619 * @param size how many bytes can we write to buf
620 * @param buf where to write requests to the service
621 * @return number of bytes written to buf
624 transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
626 struct GNUNET_STATISTICS_GetHandle *c;
627 struct GNUNET_MessageHeader *hdr;
632 GNUNET_assert (NULL != (c = handle->current));
635 /* timeout / error */
637 LOG (GNUNET_ERROR_TYPE_DEBUG,
638 "Transmission of request for statistics failed!\n");
640 do_disconnect (handle);
641 reconnect_later (handle);
644 slen1 = strlen (c->subsystem) + 1;
645 slen2 = strlen (c->name) + 1;
646 msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader);
647 GNUNET_assert (msize <= size);
648 hdr = (struct GNUNET_MessageHeader *) buf;
649 hdr->size = htons (msize);
650 hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_GET);
651 GNUNET_assert (slen1 + slen2 ==
652 GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2,
655 if (GNUNET_YES != handle->receiving)
658 LOG (GNUNET_ERROR_TYPE_DEBUG,
659 "Transmission of GET done, now reading response\n");
661 handle->receiving = GNUNET_YES;
662 GNUNET_CLIENT_receive (handle->client, &receive_stats, handle,
663 GNUNET_TIME_absolute_get_remaining (c->timeout));
670 * Transmit a WATCH request (and if successful, start to receive
673 * @param handle statistics handle
674 * @param size how many bytes can we write to buf
675 * @param buf where to write requests to the service
676 * @return number of bytes written to buf
679 transmit_watch (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
681 struct GNUNET_MessageHeader *hdr;
688 /* timeout / error */
690 LOG (GNUNET_ERROR_TYPE_DEBUG,
691 "Transmission of request for statistics failed!\n");
693 do_disconnect (handle);
694 reconnect_later (handle);
698 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting watch request for `%s'\n",
699 handle->current->name);
701 slen1 = strlen (handle->current->subsystem) + 1;
702 slen2 = strlen (handle->current->name) + 1;
703 msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader);
704 GNUNET_assert (msize <= size);
705 hdr = (struct GNUNET_MessageHeader *) buf;
706 hdr->size = htons (msize);
707 hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH);
708 GNUNET_assert (slen1 + slen2 ==
709 GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2,
710 handle->current->subsystem,
711 handle->current->name));
712 if (GNUNET_YES != handle->receiving)
714 handle->receiving = GNUNET_YES;
715 GNUNET_CLIENT_receive (handle->client, &receive_stats, handle,
716 GNUNET_TIME_UNIT_FOREVER_REL);
718 GNUNET_assert (NULL == handle->current->cont);
719 free_action_item (handle->current);
720 handle->current = NULL;
726 * Transmit a SET/UPDATE request.
728 * @param handle statistics handle
729 * @param size how many bytes can we write to buf
730 * @param buf where to write requests to the service
731 * @return number of bytes written to buf
734 transmit_set (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
736 struct GNUNET_STATISTICS_SetMessage *r;
743 do_disconnect (handle);
744 reconnect_later (handle);
747 slen = strlen (handle->current->subsystem) + 1;
748 nlen = strlen (handle->current->name) + 1;
749 nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
753 do_disconnect (handle);
754 reconnect_later (handle);
758 r->header.size = htons (nsize);
759 r->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET);
761 r->value = GNUNET_htonll (handle->current->value);
762 if (handle->current->make_persistent)
763 r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_PERSISTENT);
764 if (handle->current->type == ACTION_UPDATE)
765 r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_RELATIVE);
766 GNUNET_assert (slen + nlen ==
767 GNUNET_STRINGS_buffer_fill ((char *) &r[1], slen + nlen, 2,
768 handle->current->subsystem,
769 handle->current->name));
770 GNUNET_assert (NULL == handle->current->cont);
771 free_action_item (handle->current);
772 handle->current = NULL;
778 * Function called when we are ready to transmit a request to the service.
780 * @param cls the 'struct GNUNET_STATISTICS_Handle'
781 * @param size how many bytes can we write to buf
782 * @param buf where to write requests to the service
783 * @return number of bytes written to buf
786 transmit_action (void *cls, size_t size, void *buf)
788 struct GNUNET_STATISTICS_Handle *h = cls;
793 if (NULL != h->current)
794 switch (h->current->type)
797 ret = transmit_get (h, size, buf);
801 ret = transmit_set (h, size, buf);
804 ret = transmit_watch (h, size, buf);
816 * Get handle for the statistics service.
818 * @param subsystem name of subsystem using the service
819 * @param cfg services configuration in use
820 * @return handle to use
822 struct GNUNET_STATISTICS_Handle *
823 GNUNET_STATISTICS_create (const char *subsystem,
824 const struct GNUNET_CONFIGURATION_Handle *cfg)
826 struct GNUNET_STATISTICS_Handle *ret;
828 GNUNET_assert (subsystem != NULL);
829 GNUNET_assert (cfg != NULL);
830 ret = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_Handle));
832 ret->subsystem = GNUNET_strdup (subsystem);
833 ret->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
839 * Destroy a handle (free all state associated with
842 * @param h statistics handle to destroy
843 * @param sync_first set to GNUNET_YES if pending SET requests should
847 GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
849 struct GNUNET_STATISTICS_GetHandle *pos;
850 struct GNUNET_STATISTICS_GetHandle *next;
851 struct GNUNET_STATISTICS_GetHandle *prev;
852 struct GNUNET_TIME_Relative timeout;
857 if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task)
858 GNUNET_SCHEDULER_cancel (h->backoff_task);
861 if (h->current != NULL)
863 if (h->current->type == ACTION_GET)
865 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
867 free_action_item (h->current);
871 pos = h->action_head;
876 if (pos->type == ACTION_GET)
879 h->action_head = next;
882 free_action_item (pos);
890 h->action_tail = prev;
891 if (h->current == NULL)
893 h->current = h->action_head;
894 if (h->action_head != NULL)
896 h->action_head = h->action_head->next;
897 if (h->action_head == NULL)
898 h->action_tail = NULL;
901 h->do_destroy = GNUNET_YES;
902 if ((h->current != NULL) && (h->th == NULL))
904 timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout);
906 GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize,
908 &transmit_action, h);
909 GNUNET_assert (NULL != h->th);
914 while (NULL != (pos = h->action_head))
916 GNUNET_CONTAINER_DLL_remove (h->action_head,
919 free_action_item (pos);
922 for (i = 0; i < h->watches_size; i++)
924 if (NULL == h->watches[i])
926 GNUNET_free (h->watches[i]->subsystem);
927 GNUNET_free (h->watches[i]->name);
928 GNUNET_free (h->watches[i]);
930 GNUNET_array_grow (h->watches, h->watches_size, 0);
931 GNUNET_free (h->subsystem);
937 * Schedule the next action to be performed.
939 * @param h statistics handle
942 schedule_action (struct GNUNET_STATISTICS_Handle *h)
944 struct GNUNET_TIME_Relative timeout;
946 if ( (h->th != NULL) ||
947 (h->backoff_task != GNUNET_SCHEDULER_NO_TASK) )
948 return; /* action already pending */
949 if (GNUNET_YES != try_connect (h))
954 if (NULL != h->current)
955 return; /* action already pending */
956 /* schedule next action */
957 h->current = h->action_head;
958 if (NULL == h->current)
962 h->do_destroy = GNUNET_NO;
963 GNUNET_STATISTICS_destroy (h, GNUNET_YES);
967 GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, h->current);
968 timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout);
971 GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize,
973 &transmit_action, h)))
976 LOG (GNUNET_ERROR_TYPE_DEBUG,
977 "Failed to transmit request to statistics service.\n");
986 * Get statistic from the peer.
988 * @param handle identification of the statistics service
989 * @param subsystem limit to the specified subsystem, NULL for our subsystem
990 * @param name name of the statistic value, NULL for all values
991 * @param timeout after how long should we give up (and call
992 * cont with an error code)?
993 * @param cont continuation to call when done (can be NULL)
994 * @param proc function to call on each value
995 * @param cls closure for cont and proc
996 * @return NULL on error
998 struct GNUNET_STATISTICS_GetHandle *
999 GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle,
1000 const char *subsystem, const char *name,
1001 struct GNUNET_TIME_Relative timeout,
1002 GNUNET_STATISTICS_Callback cont,
1003 GNUNET_STATISTICS_Iterator proc, void *cls)
1007 struct GNUNET_STATISTICS_GetHandle *ai;
1011 GNUNET_assert (proc != NULL);
1012 GNUNET_assert (GNUNET_NO == handle->do_destroy);
1013 if (subsystem == NULL)
1017 slen1 = strlen (subsystem) + 1;
1018 slen2 = strlen (name) + 1;
1019 GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) <
1020 GNUNET_SERVER_MAX_MESSAGE_SIZE);
1021 ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
1023 ai->subsystem = GNUNET_strdup (subsystem);
1024 ai->name = GNUNET_strdup (name);
1028 ai->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1029 ai->type = ACTION_GET;
1030 ai->msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader);
1031 GNUNET_CONTAINER_DLL_insert_tail (handle->action_head, handle->action_tail,
1033 schedule_action (handle);
1039 * Cancel a 'get' request. Must be called before the 'cont'
1040 * function is called.
1042 * @param gh handle of the request to cancel
1045 GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh)
1049 if (gh->sh->current == gh)
1051 gh->aborted = GNUNET_YES;
1055 GNUNET_CONTAINER_DLL_remove (gh->sh->action_head, gh->sh->action_tail, gh);
1056 GNUNET_free (gh->name);
1057 GNUNET_free (gh->subsystem);
1064 * Watch statistics from the peer (be notified whenever they change).
1065 * Note that the only way to cancel a "watch" request is to destroy
1066 * the statistics handle given as the first argument to this call.
1068 * @param handle identification of the statistics service
1069 * @param subsystem limit to the specified subsystem, never NULL
1070 * @param name name of the statistic value, never NULL
1071 * @param proc function to call on each value
1072 * @param proc_cls closure for proc
1073 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1076 GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle,
1077 const char *subsystem, const char *name,
1078 GNUNET_STATISTICS_Iterator proc, void *proc_cls)
1080 struct GNUNET_STATISTICS_WatchEntry *w;
1083 return GNUNET_SYSERR;
1084 w = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_WatchEntry));
1085 w->subsystem = GNUNET_strdup (subsystem);
1086 w->name = GNUNET_strdup (name);
1088 w->proc_cls = proc_cls;
1089 GNUNET_array_append (handle->watches, handle->watches_size, w);
1090 schedule_watch_request (handle, w);
1096 * Queue a request to change a statistic.
1098 * @param h statistics handle
1099 * @param name name of the value
1100 * @param make_persistent should the value be kept across restarts?
1101 * @param value new value or change
1102 * @param type type of the action (ACTION_SET or ACTION_UPDATE)
1105 add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name,
1106 int make_persistent, uint64_t value, enum ActionType type)
1108 struct GNUNET_STATISTICS_GetHandle *ai;
1114 GNUNET_assert (h != NULL);
1115 GNUNET_assert (name != NULL);
1116 slen = strlen (h->subsystem) + 1;
1117 nlen = strlen (name) + 1;
1118 nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
1119 if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1124 for (ai = h->action_head; ai != NULL; ai = ai->next)
1126 if (! ( (0 == strcmp (ai->subsystem, h->subsystem)) &&
1127 (0 == strcmp (ai->name, name)) &&
1128 ( (ai->type == ACTION_UPDATE) ||
1129 (ai->type == ACTION_SET) ) ) )
1131 if (ai->type == ACTION_SET)
1133 if (type == ACTION_UPDATE)
1135 delta = (int64_t) value;
1138 /* update old set by new delta */
1143 /* update old set by new delta, but never go negative */
1144 if (ai->value < -delta)
1152 /* new set overrides old set */
1158 if (type == ACTION_UPDATE)
1160 /* make delta cummulative */
1161 delta = (int64_t) value;
1166 /* drop old 'update', use new 'set' instead */
1171 ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT);
1172 ai->make_persistent = make_persistent;
1175 /* no existing entry matches, create a fresh one */
1176 ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
1178 ai->subsystem = GNUNET_strdup (h->subsystem);
1179 ai->name = GNUNET_strdup (name);
1180 ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT);
1181 ai->make_persistent = make_persistent;
1185 GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail,
1187 schedule_action (h);
1192 * Set statistic value for the peer. Will always use our
1193 * subsystem (the argument used when "handle" was created).
1195 * @param handle identification of the statistics service
1196 * @param name name of the statistic value
1197 * @param value new value to set
1198 * @param make_persistent should the value be kept across restarts?
1201 GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle,
1202 const char *name, uint64_t value, int make_persistent)
1206 GNUNET_assert (GNUNET_NO == handle->do_destroy);
1207 add_setter_action (handle, name, make_persistent, value, ACTION_SET);
1212 * Set statistic value for the peer. Will always use our
1213 * subsystem (the argument used when "handle" was created).
1215 * @param handle identification of the statistics service
1216 * @param name name of the statistic value
1217 * @param delta change in value (added to existing value)
1218 * @param make_persistent should the value be kept across restarts?
1221 GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle,
1222 const char *name, int64_t delta, int make_persistent)
1228 GNUNET_assert (GNUNET_NO == handle->do_destroy);
1229 add_setter_action (handle, name, make_persistent, (uint64_t) delta,
1234 /* end of statistics_api.c */