GNUnet  0.10.x
gnunet-service-statistics.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2009, 2010, 2012, 2014, 2016 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 
26 #include "platform.h"
27 #include "gnunet_bio_lib.h"
28 #include "gnunet_container_lib.h"
29 #include "gnunet_disk_lib.h"
30 #include "gnunet_getopt_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_service_lib.h"
34 #include "gnunet_strings_lib.h"
35 #include "gnunet_time_lib.h"
36 #include "statistics.h"
37 
41 struct WatchEntry
42 {
43 
47  struct WatchEntry *next;
48 
52  struct WatchEntry *prev;
53 
57  struct ClientEntry *ce;
58 
62  uint64_t last_value;
63 
67  uint32_t wid;
68 
74 
75 };
76 
77 
82 struct SubsystemEntry;
83 
84 
88 struct StatsEntry
89 {
93  struct StatsEntry *next;
94 
98  struct StatsEntry *prev;
99 
104 
109  const char *name;
110 
115 
120 
124  uint64_t value;
125 
129  uint32_t uid;
130 
135 
140  int set;
141 
142 };
143 
144 
150 {
155 
160 
165 
170 
175  const char *service;
176 
177 };
178 
179 
183 struct ClientEntry
184 {
188  struct GNUNET_SERVICE_Client *client;
189 
193  struct GNUNET_MQ_Handle *mq;
194 
199 
203  uint32_t max_wid;
204 
205 };
206 
207 
211 static const struct GNUNET_CONFIGURATION_Handle *cfg;
212 
216 static struct SubsystemEntry *sub_head;
217 
221 static struct SubsystemEntry *sub_tail;
222 
226 static unsigned int client_count;
227 
232 
236 static uint32_t uidgen;
237 
241 static int in_shutdown;
242 
243 
247 static void
249 {
250  struct SubsystemEntry *se;
251  struct StatsEntry *pos;
252  char *fn;
253  struct GNUNET_BIO_WriteHandle *wh;
254  uint16_t size;
255  unsigned long long total;
256  size_t nlen;
257  size_t slen;
259 
260  if (GNUNET_OK !=
262  "STATISTICS",
263  "DATABASE",
264  &fn))
265  {
267  "STATISTICS",
268  "DATABASE");
269  return;
270  }
272  wh = GNUNET_BIO_write_open (fn);
273  total = 0;
274  while (NULL != (se = sub_head))
275  {
276  GNUNET_CONTAINER_DLL_remove (sub_head,
277  sub_tail,
278  se);
279  slen = strlen (se->service) + 1;
280  while (NULL != (pos = se->stat_head))
281  {
283  se->stat_tail,
284  pos);
285  if ( (pos->persistent) &&
286  (NULL != wh) )
287  {
288  nlen = strlen (pos->name) + 1;
289  size = sizeof (struct GNUNET_STATISTICS_SetMessage) + nlen + slen;
290  GNUNET_assert (size < UINT16_MAX);
291  msg = GNUNET_malloc (size);
292 
293  msg->header.size = htons ((uint16_t) size);
295  GNUNET_assert (nlen + slen ==
296  GNUNET_STRINGS_buffer_fill ((char *) &msg[1],
297  nlen + slen,
298  2,
299  se->service,
300  pos->name));
301  msg->flags = htonl (pos->persistent ? GNUNET_STATISTICS_SETFLAG_PERSISTENT : 0);
302  msg->value = GNUNET_htonll (pos->value);
303  if (GNUNET_OK != GNUNET_BIO_write (wh,
304  msg,
305  size))
306  {
308  "write",
309  fn);
310  if (GNUNET_OK != GNUNET_BIO_write_close (wh))
312  "close",
313  fn);
314  wh = NULL;
315  }
316  else
317  {
318  total += size;
319  }
320  GNUNET_free (msg);
321  }
322  GNUNET_free (pos);
323  }
324  GNUNET_free (se);
325  }
326  if (NULL != wh)
327  {
328  if (GNUNET_OK !=
331  "close",
332  fn);
333  if (0 == total)
334  GNUNET_break (0 ==
335  UNLINK (fn));
336  else
338  _("Wrote %llu bytes of statistics to `%s'\n"),
339  total,
340  fn);
341  }
343 }
344 
345 
352 static void
354  const struct StatsEntry *e)
355 {
356  struct GNUNET_MQ_Envelope *env;
358  size_t size;
359 
360  size = strlen (e->subsystem->service) + 1 +
361  strlen (e->name) + 1;
363  env = GNUNET_MQ_msg_extra (m,
364  size,
366  m->uid = htonl (e->uid);
367  if (e->persistent)
368  m->uid |= htonl (GNUNET_STATISTICS_PERSIST_BIT);
369  m->value = GNUNET_htonll (e->value);
370  GNUNET_assert (size ==
371  GNUNET_STRINGS_buffer_fill ((char *) &m[1],
372  size,
373  2,
374  e->subsystem->service,
375  e->name));
377  "Transmitting value for `%s:%s' (%d): %llu\n",
378  e->subsystem->service,
379  e->name,
380  e->persistent,
381  (unsigned long long) e->value);
382  GNUNET_MQ_send (ce->mq,
383  env);
384 }
385 
386 
395 static void *
396 client_connect_cb (void *cls,
397  struct GNUNET_SERVICE_Client *c,
398  struct GNUNET_MQ_Handle *mq)
399 {
400  struct ClientEntry *ce;
401 
402  ce = GNUNET_new (struct ClientEntry);
403  ce->client = c;
404  ce->mq = mq;
405  client_count++;
407  mq);
408  return ce;
409 }
410 
411 
419 static int
420 check_get (void *cls,
421  const struct GNUNET_MessageHeader *message)
422 {
423  const char *service;
424  const char *name;
425  size_t size;
426 
427  size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
428  if (size !=
429  GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
430  size,
431  2,
432  &service,
433  &name))
434  {
435  GNUNET_break (0);
436  return GNUNET_SYSERR;
437  }
438  return GNUNET_OK;
439 }
440 
441 
448 static void
449 handle_get (void *cls,
450  const struct GNUNET_MessageHeader *message)
451 {
452  struct ClientEntry *ce = cls;
453  struct GNUNET_MQ_Envelope *env;
454  struct GNUNET_MessageHeader *end;
455  const char *service;
456  const char *name;
457  size_t slen;
458  size_t nlen;
459  struct SubsystemEntry *se;
460  struct StatsEntry *pos;
461  size_t size;
462 
463  size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
464  GNUNET_assert (size ==
465  GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
466  size,
467  2,
468  &service,
469  &name));
470  slen = strlen (service);
471  nlen = strlen (name);
473  "Received request for statistics on `%s:%s'\n",
474  slen ? service : "*",
475  nlen ? name : "*");
476  for (se = sub_head; NULL != se; se = se->next)
477  {
478  if (! ( (0 == slen) ||
479  (0 == strcmp (service, se->service))) )
480  continue;
481  for (pos = se->stat_head; NULL != pos; pos = pos->next)
482  {
483  if (! ( (0 == nlen) ||
484  (0 == strcmp (name,
485  pos->name))) )
486  continue;
487  transmit (ce,
488  pos);
489  }
490  }
491  env = GNUNET_MQ_msg (end,
493  GNUNET_MQ_send (ce->mq,
494  env);
496 }
497 
498 
504 static void
506 {
507  struct GNUNET_MQ_Envelope *env;
509  struct WatchEntry *pos;
510 
511  for (pos = se->we_head; NULL != pos; pos = pos->next)
512  {
513  if (GNUNET_YES == pos->last_value_set)
514  {
515  if (pos->last_value == se->value)
516  continue;
517  }
518  else
519  {
520  pos->last_value_set = GNUNET_YES;
521  }
522  env = GNUNET_MQ_msg (wvm,
524  wvm->flags = htonl (se->persistent ? GNUNET_STATISTICS_SETFLAG_PERSISTENT : 0);
525  wvm->wid = htonl (pos->wid);
526  wvm->reserved = htonl (0);
527  wvm->value = GNUNET_htonll (se->value);
528  GNUNET_MQ_send (pos->ce->mq,
529  env);
530  pos->last_value = se->value;
531  }
532 }
533 
534 
543 static struct SubsystemEntry *
545  const char *service)
546 {
547  size_t slen;
548  struct SubsystemEntry *se;
549 
550  if (NULL != ce)
551  se = ce->subsystem;
552  else
553  se = NULL;
554  if ( (NULL == se) ||
555  (0 != strcmp (service,
556  se->service)) )
557  {
558  for (se = sub_head; NULL != se; se = se->next)
559  if (0 == strcmp (service,
560  se->service))
561  break;
562  if (NULL != ce)
563  ce->subsystem = se;
564  }
565  if (NULL != se)
566  return se;
568  "Allocating new subsystem entry `%s'\n",
569  service);
570  slen = strlen (service) + 1;
571  se = GNUNET_malloc (sizeof (struct SubsystemEntry) +
572  slen);
573  GNUNET_memcpy (&se[1],
574  service,
575  slen);
576  se->service = (const char *) &se[1];
577  GNUNET_CONTAINER_DLL_insert (sub_head,
578  sub_tail,
579  se);
580  if (NULL != ce)
581  ce->subsystem = se;
582  return se;
583 }
584 
585 
593 static struct StatsEntry *
595  const char *name)
596 {
597  struct StatsEntry *pos;
598 
599  for (pos = se->stat_head; NULL != pos; pos = pos->next)
600  if (0 == strcmp (name, pos->name))
601  return pos;
602  return NULL;
603 }
604 
605 
613 static int
614 check_set (void *cls,
615  const struct GNUNET_STATISTICS_SetMessage *msg)
616 {
617  const char *service;
618  const char *name;
619  size_t msize;
620 
621  msize = ntohs (msg->header.size) - sizeof (*msg);
622  if (msize !=
623  GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1],
624  msize,
625  2,
626  &service,
627  &name))
628  {
629  GNUNET_break (0);
630  return GNUNET_SYSERR;
631  }
632  return GNUNET_OK;
633 }
634 
635 
642 static void
643 handle_set (void *cls,
644  const struct GNUNET_STATISTICS_SetMessage *msg)
645 {
646  struct ClientEntry *ce = cls;
647  const char *service;
648  const char *name;
649  size_t nlen;
650  uint16_t msize;
651  uint16_t size;
652  struct SubsystemEntry *se;
653  struct StatsEntry *pos;
654  uint32_t flags;
655  uint64_t value;
656  int64_t delta;
657  int changed;
658  int initial_set;
659 
660  msize = ntohs (msg->header.size);
661  size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage);
662  GNUNET_assert (size ==
663  GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1],
664  size,
665  2,
666  &service,
667  &name));
668  se = find_subsystem_entry (ce,
669  service);
670  flags = ntohl (msg->flags);
671  value = GNUNET_ntohll (msg->value);
673  "Received request to update statistic on `%s:%s' (%u) to/by %llu\n",
674  service,
675  name,
676  (unsigned int) flags,
677  (unsigned long long) value);
678  pos = find_stat_entry (se,
679  name);
680  if (NULL != pos)
681  {
682  initial_set = 0;
683  if (0 == (flags & GNUNET_STATISTICS_SETFLAG_RELATIVE))
684  {
685  changed = (pos->value != value);
686  pos->value = value;
687  }
688  else
689  {
690  delta = (int64_t) value;
691  if ((delta < 0) && (pos->value < -delta))
692  {
693  changed = (0 != pos->value);
694  pos->value = 0;
695  }
696  else
697  {
698  changed = (0 != delta);
699  GNUNET_break ( (delta <= 0) ||
700  (pos->value + delta > pos->value) );
701  pos->value += delta;
702  }
703  }
704  if (GNUNET_NO == pos->set)
705  {
706  pos->set = GNUNET_YES;
707  initial_set = 1;
708  }
709  pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT));
710  if (pos != se->stat_head)
711  {
712  /* move to front for faster setting next time! */
714  se->stat_tail,
715  pos);
717  se->stat_tail,
718  pos);
719  }
721  "Statistic `%s:%s' updated to value %llu (%d).\n",
722  service,
723  name,
724  (unsigned long long) pos->value,
725  pos->persistent);
726  if ( (changed) ||
727  (1 == initial_set) )
728  notify_change (pos);
730  return;
731  }
732  /* not found, create a new entry */
733  nlen = strlen (name) + 1;
734  pos = GNUNET_malloc (sizeof (struct StatsEntry) + nlen);
735  GNUNET_memcpy (&pos[1],
736  name,
737  nlen);
738  pos->name = (const char *) &pos[1];
739  pos->subsystem = se;
740  if ( (0 == (flags & GNUNET_STATISTICS_SETFLAG_RELATIVE)) ||
741  (0 < (int64_t) GNUNET_ntohll (msg->value)) )
742  {
743  pos->value = GNUNET_ntohll (msg->value);
744  pos->set = GNUNET_YES;
745  }
746  else
747  {
748  pos->set = GNUNET_NO;
749  }
750  pos->uid = uidgen++;
751  pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT));
753  se->stat_tail,
754  pos);
756  "New statistic on `%s:%s' with value %llu created.\n",
757  service,
758  name,
759  (unsigned long long) pos->value);
760  if (NULL != ce)
762 }
763 
764 
772 static int
773 check_watch (void *cls,
774  const struct GNUNET_MessageHeader *message)
775 {
776  size_t size;
777  const char *service;
778  const char *name;
779 
780  size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
781  if (size !=
782  GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
783  size,
784  2,
785  &service,
786  &name))
787  {
788  GNUNET_break (0);
789  return GNUNET_SYSERR;
790  }
791  return GNUNET_OK;
792 }
793 
794 
801 static void
802 handle_watch (void *cls,
803  const struct GNUNET_MessageHeader *message)
804 {
805  struct ClientEntry *ce = cls;
806  const char *service;
807  const char *name;
808  uint16_t msize;
809  uint16_t size;
810  struct SubsystemEntry *se;
811  struct StatsEntry *pos;
812  struct WatchEntry *we;
813  size_t nlen;
814 
815  if (NULL == nc)
816  {
818  return;
819  }
821  msize = ntohs (message->size);
822  size = msize - sizeof (struct GNUNET_MessageHeader);
823  GNUNET_assert (size ==
824  GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
825  size,
826  2,
827  &service,
828  &name));
830  "Received request to watch statistic on `%s:%s'\n",
831  service,
832  name);
833  se = find_subsystem_entry (ce,
834  service);
835  pos = find_stat_entry (se,
836  name);
837  if (NULL == pos)
838  {
839  nlen = strlen (name) + 1;
840  pos = GNUNET_malloc (sizeof (struct StatsEntry) +
841  nlen);
842  GNUNET_memcpy (&pos[1],
843  name,
844  nlen);
845  pos->name = (const char *) &pos[1];
846  pos->subsystem = se;
848  se->stat_tail,
849  pos);
850  pos->uid = uidgen++;
851  pos->set = GNUNET_NO;
853  "New statistic on `%s:%s' with value %llu created.\n",
854  service,
855  name,
856  (unsigned long long) pos->value);
857  }
858  we = GNUNET_new (struct WatchEntry);
859  we->ce = ce;
861  we->wid = ce->max_wid++;
863  pos->we_tail,
864  we);
865  if (0 != pos->value)
866  notify_change (pos);
868 }
869 
870 
879 static void
880 handle_disconnect (void *cls,
881  const struct GNUNET_MessageHeader *message)
882 {
883  struct ClientEntry *ce = cls;
884  struct GNUNET_MQ_Envelope *env;
885  struct GNUNET_MessageHeader *msg;
886 
887  env = GNUNET_MQ_msg (msg,
889  GNUNET_MQ_send (ce->mq,
890  env);
892 }
893 
894 
898 static void
900 {
901  struct WatchEntry *we;
902  struct StatsEntry *pos;
903  struct SubsystemEntry *se;
904 
905  if (NULL == nc)
906  return;
907  save ();
909  nc = NULL;
911  while (NULL != (se = sub_head))
912  {
913  GNUNET_CONTAINER_DLL_remove (sub_head,
914  sub_tail,
915  se);
916  while (NULL != (pos = se->stat_head))
917  {
919  se->stat_tail,
920  pos);
921  while (NULL != (we = pos->we_head))
922  {
923  GNUNET_break (0);
925  pos->we_tail,
926  we);
927  GNUNET_free (we);
928  }
929  GNUNET_free (pos);
930  }
931  GNUNET_free (se);
932  }
933 }
934 
935 
941 static void
942 shutdown_task (void *cls)
943 {
945  if (0 != client_count)
946  return;
947  do_shutdown ();
948 }
949 
950 
958 static void
960  struct GNUNET_SERVICE_Client *client,
961  void *app_cls)
962 {
963  struct ClientEntry *ce = app_cls;
964  struct WatchEntry *we;
965  struct WatchEntry *wen;
966  struct StatsEntry *pos;
967  struct SubsystemEntry *se;
968 
969  client_count--;
970  for (se = sub_head; NULL != se; se = se->next)
971  {
972  for (pos = se->stat_head; NULL != pos; pos = pos->next)
973  {
974  wen = pos->we_head;
975  while (NULL != (we = wen))
976  {
977  wen = we->next;
978  if (we->ce != ce)
979  continue;
981  pos->we_tail,
982  we);
983  GNUNET_free (we);
984  }
985  }
986  }
987  GNUNET_free (ce);
988  if ( (0 == client_count) &&
989  (GNUNET_YES == in_shutdown) )
990  do_shutdown ();
991 }
992 
993 
1005 static int
1006 inject_message (void *cls,
1007  const struct GNUNET_MessageHeader *message)
1008 {
1009  uint16_t msize = ntohs (message->size);
1010  const struct GNUNET_STATISTICS_SetMessage *sm;
1011 
1012  sm = (const struct GNUNET_STATISTICS_SetMessage *) message;
1013  if ( (sizeof (struct GNUNET_STATISTICS_SetMessage) > msize) ||
1014  (GNUNET_OK !=
1015  check_set (NULL,
1016  sm)) )
1017  {
1018  GNUNET_break (0);
1019  return GNUNET_SYSERR;
1020  }
1021  handle_set (NULL,
1022  sm);
1023  return GNUNET_OK;
1024 }
1025 
1026 
1031 static void
1033 {
1034  char *fn;
1035  struct GNUNET_BIO_ReadHandle *rh;
1036  uint64_t fsize;
1037  char *buf;
1038  struct GNUNET_MessageStreamTokenizer *mst;
1039 
1040  if (GNUNET_OK !=
1042  "STATISTICS",
1043  "DATABASE",
1044  &fn))
1045  {
1047  "STATISTICS",
1048  "DATABASE");
1049  return;
1050  }
1051  if ( (GNUNET_OK !=
1053  &fsize,
1054  GNUNET_NO,
1055  GNUNET_YES)) ||
1056  (0 == fsize) )
1057  {
1058  GNUNET_free (fn);
1059  return;
1060  }
1061  buf = GNUNET_malloc (fsize);
1062  rh = GNUNET_BIO_read_open (fn);
1063  if (! rh)
1064  {
1065  GNUNET_free (buf);
1066  GNUNET_free (fn);
1067  return;
1068  }
1069  if (GNUNET_OK !=
1070  GNUNET_BIO_read (rh,
1071  fn,
1072  buf,
1073  fsize))
1074  {
1076  "read",
1077  fn);
1080  NULL));
1081  GNUNET_free (buf);
1082  GNUNET_free (fn);
1083  return;
1084  }
1086  _("Loading %llu bytes of statistics from `%s'\n"),
1087  (unsigned long long) fsize,
1088  fn);
1090  NULL);
1093  buf,
1094  (size_t) fsize,
1095  GNUNET_YES,
1096  GNUNET_NO));
1097  GNUNET_MST_destroy (mst);
1098  GNUNET_free (buf);
1101  NULL));
1102  GNUNET_free (fn);
1103 }
1104 
1105 
1113 static void
1114 run (void *cls,
1115  const struct GNUNET_CONFIGURATION_Handle *c,
1117 {
1118  cfg = c;
1120  load ();
1122  NULL);
1123 }
1124 
1125 
1130 ("statistics",
1132  &run,
1135  NULL,
1136  GNUNET_MQ_hd_var_size (set,
1139  NULL),
1140  GNUNET_MQ_hd_var_size (get,
1142  struct GNUNET_MessageHeader,
1143  NULL),
1146  struct GNUNET_MessageHeader,
1147  NULL),
1150  struct GNUNET_MessageHeader,
1151  NULL),
1153 
1154 
1155 #if defined(LINUX) && defined(__GLIBC__)
1156 #include <malloc.h>
1157 
1161 void __attribute__ ((constructor))
1162 GNUNET_STATISTICS_memory_init ()
1163 {
1164  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1165  mallopt (M_TOP_PAD, 1 * 1024);
1166  malloc_trim (0);
1167 }
1168 #endif
1169 
1170 
1171 /* end of gnunet-service-statistics.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void handle_get(void *cls, const struct GNUNET_MessageHeader *message)
Handle GET-message.
struct StatsEntry * stat_head
Head of list of values kept for this subsystem.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
The notification context is the key datastructure for a convenience API used for transmission of noti...
Definition: nc.c:77
#define GNUNET_MESSAGE_TYPE_STATISTICS_SET
Set a statistical value.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
const char * service
Name of the subsystem this entry is for, allocated at the end of this struct, do not free()...
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:35
#define GNUNET_MESSAGE_TYPE_STATISTICS_END
Response to a STATISTICS_GET message (end of value stream).
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
static void load()
Load persistent values from disk.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct SubsystemEntry * subsystem
Which subsystem is this client writing to (SET/UPDATE)?
uint64_t value
Our value.
struct StatsEntry * prev
This is a linked list.
#define GNUNET_MESSAGE_TYPE_STATISTICS_WATCH
Watch changes to a statistical value.
Handle to a service.
Definition: service.c:116
static unsigned int client_count
Number of connected clients.
Statistics message.
Definition: statistics.h:40
static int check_get(void *cls, const struct GNUNET_MessageHeader *message)
Check integrity of GET-message.
uint32_t uid
Unique numerical identifier for the value (will not change during the same client-session).
Definition: statistics.h:53
struct StatsEntry * next
This is a linked list.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1293
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_cls)
A client disconnected.
static void notify_change(struct StatsEntry *se)
Notify all clients listening about a change to a value.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct WatchEntry * we_head
Watch context for changes to this value, or NULL for none.
static void shutdown_task(void *cls)
Task run during shutdown.
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
Callback called when a client connects to the service.
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
Definition: gnunet_mq_lib.h:67
static struct Experiment * e
int GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition: disk.c:833
#define GNUNET_NO
Definition: gnunet_common.h:81
Message to set a statistic.
Definition: statistics.h:92
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#define GNUNET_MESSAGE_TYPE_STATISTICS_VALUE
Response to a STATISTICS_GET message (with value).
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
uint32_t flags
0 for absolute value, 1 for relative value; 2 to make persistent (see GNUNET_STATISTICS_SETFLAG_*).
Definition: statistics.h:128
#define GNUNET_new(type)
Allocate a struct or union of the given type.
uint32_t reserved
Reserved (always 0).
Definition: statistics.h:141
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
static void save()
Write persistent statistics to disk.
#define GNUNET_STATISTICS_SETFLAG_RELATIVE
The value being set is a relative change.
Definition: statistics.h:76
struct WatchEntry * prev
Watch entries are kept in a linked list.
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition: nc.c:164
struct GNUNET_SERVICE_Client * client
Handle identifying the client.
int GNUNET_BIO_read_close(struct GNUNET_BIO_ReadHandle *h, char **emsg)
Close an open file.
Definition: bio.c:119
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define UNLINK(f)
Definition: plibc.h:666
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
Handle to a client that is connected to a service.
Definition: service.c:249
static int in_shutdown
Set to GNUNET_YES if we are shutting down as soon as possible.
struct GNUNET_BIO_ReadHandle * GNUNET_BIO_read_open(const char *fn)
Open a file for reading.
Definition: bio.c:94
struct SubsystemEntry * next
Subsystems are kept in a DLL.
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:99
int GNUNET_BIO_read(struct GNUNET_BIO_ReadHandle *h, const char *what, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: bio.c:145
unsigned int GNUNET_STRINGS_buffer_tokenize(const char *buffer, size_t size, unsigned int count,...)
Given a buffer of a given size, find "count" 0-terminated strings in the buffer and assign the count ...
Definition: strings.c:136
Message transmitted if a watched value changes.
Definition: statistics.h:117
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct...
Definition: gnunet_mq_lib.h:52
struct WatchEntry * we_tail
Watch context for changes to this value, or NULL for none.
static int inject_message(void *cls, const struct GNUNET_MessageHeader *message)
We&#39;ve read a struct GNUNET_STATISTICS_SetMessage * from disk.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
We keep the statistics organized by subsystem for faster lookup during SET operations.
#define GNUNET_MESSAGE_TYPE_STATISTICS_GET
Get a statistical value(s).
#define GNUNET_memcpy(dst, src, n)
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
uint32_t wid
Unique watch number for this client and this watched value.
static char * value
Value of the record to add/remove.
#define GNUNET_MESSAGE_TYPE_STATISTICS_DISCONNECT_CONFIRM
Service confirms disconnect and that it is done processing all requests from the client.
Information about one of our clients.
int last_value_set
Is last_value valid GNUNET_NO : last_value is n/a, GNUNET_YES: last_value is valid.
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:413
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
static struct SubsystemEntry * sub_tail
Tail of linked list of subsystems with active statistics.
static char * fn
Filename of the unique file.
Trigger a SOFT server shutdown on signals, allowing active non-monitor clients to complete their tran...
#define GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE
Changes to a watched value.
Handle to a message stream tokenizer.
Definition: mst.c:43
static char buf[2048]
static void disconnect(struct GNUNET_PEERSTORE_Handle *h)
Disconnect from the peerstore service.
static int check_set(void *cls, const struct GNUNET_STATISTICS_SetMessage *msg)
Check format of SET-message.
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:87
static void do_shutdown()
Actually perform the shutdown.
size_t GNUNET_STRINGS_buffer_fill(char *buffer, size_t size, unsigned int count,...)
Fill a buffer of the given size with count 0-terminated strings (given as varargs).
Definition: strings.c:64
int persistent
Is this value persistent?
int GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition: mst.c:116
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the &#39;monitor&#39; flag on this client.
Definition: service.c:2704
Handle for buffered writing.
Definition: bio.c:399
GNUNET_SERVICE_MAIN("statistics", GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_var_size(set, GNUNET_MESSAGE_TYPE_STATISTICS_SET, struct GNUNET_STATISTICS_SetMessage, NULL), GNUNET_MQ_hd_var_size(get, GNUNET_MESSAGE_TYPE_STATISTICS_GET, struct GNUNET_MessageHeader, NULL), GNUNET_MQ_hd_var_size(watch, GNUNET_MESSAGE_TYPE_STATISTICS_WATCH, struct GNUNET_MessageHeader, NULL), GNUNET_MQ_hd_fixed_size(disconnect, GNUNET_MESSAGE_TYPE_STATISTICS_DISCONNECT, struct GNUNET_MessageHeader, NULL), GNUNET_MQ_handler_end())
Define "main" method using service macro.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2618
static void transmit(struct ClientEntry *ce, const struct StatsEntry *e)
Transmit the given stats value.
static void handle_disconnect(void *cls, const struct GNUNET_MessageHeader *message)
Handle DISCONNECT-message.
uint32_t wid
Unique watch identification number (watch requests are enumerated in the order they are received...
Definition: statistics.h:136
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:35
uint64_t last_value
Last value we communicated to the client for this watch entry.
#define GNUNET_MESSAGE_TYPE_STATISTICS_DISCONNECT
Client is done sending service requests and will now disconnect.
static int watch
Watch value continuously.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static unsigned int size
Size of the "table".
Definition: peer.c:67
struct GNUNET_MQ_Handle * mq
Queue for transmissions to client.
static void handle_set(void *cls, const struct GNUNET_STATISTICS_SetMessage *msg)
Handle SET-message.
static uint32_t uidgen
Counter used to generate unique values.
const char * name
Entry in the statistics list.
#define GNUNET_STATISTICS_PERSIST_BIT
Flag for the struct GNUNET_STATISTICS_ReplyMessage UID only.
Definition: statistics.h:66
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
struct ClientEntry * ce
For which client is this watch entry?
static struct GNUNET_TESTBED_BarrierWaitHandle * wh
Our barrier wait handle.
static struct SubsystemEntry * sub_head
Head of linked list of subsystems with active statistics.
int GNUNET_BIO_write_close(struct GNUNET_BIO_WriteHandle *h)
Close an open file for writing.
Definition: bio.c:457
const char * name
Name for the value stored by this entry, allocated at the end of this struct.
int set
Is this value set? GNUNET_NO: value is n/a, GNUNET_YES: value is valid.
int GNUNET_DISK_file_size(const char *filename, uint64_t *size, int include_symbolic_links, int single_file_mode)
Get the size of the file (or directory) of the given file (in bytes).
Definition: disk.c:289
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message...
static struct GNUNET_NotificationContext * nc
Our notification context.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition: nc.c:125
Handle to a message queue.
Definition: mq.c:85
enum RadiotapType __attribute__
struct StatsEntry * stat_tail
Tail of list of values kept for this subsystem.
static int check_watch(void *cls, const struct GNUNET_MessageHeader *message)
Check integrity of WATCH-message.
configuration data
Definition: configuration.c:85
struct GNUNET_BIO_WriteHandle * GNUNET_BIO_write_open(const char *fn)
Open a file for writing.
Definition: bio.c:430
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_STATISTICS_SET.
Definition: statistics.h:97
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
#define GNUNET_log(kind,...)
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Process statistics requests.
static struct StatsEntry * find_stat_entry(struct SubsystemEntry *se, const char *name)
Find the statistics entry of the given subsystem.
int GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
struct SubsystemEntry * prev
Subsystems are kept in a DLL.
Header for all communications.
#define GNUNET_YES
Definition: gnunet_common.h:80
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition: nc.c:141
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:353
int GNUNET_BIO_write(struct GNUNET_BIO_WriteHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: bio.c:505
uint32_t uid
Unique ID.
struct SubsystemEntry * subsystem
Subsystem this entry belongs to.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
struct WatchEntry * next
Watch entries are kept in a linked list.
uint64_t value
The value.
Definition: statistics.h:58
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2533
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
uint32_t max_wid
Maximum watch ID used by this client so far.
static void handle_watch(void *cls, const struct GNUNET_MessageHeader *message)
Handle WATCH-message.
#define GNUNET_malloc(size)
Wrapper around malloc.
Handle for buffered reading.
Definition: bio.c:53
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
Definition: common_endian.c:48
#define GNUNET_STATISTICS_SETFLAG_PERSISTENT
The value being set is to be persistent (note that this bit can be combined with GNUNET_STATISTICS_SE...
Definition: statistics.h:84
#define GNUNET_free(ptr)
Wrapper around free.
static struct SubsystemEntry * find_subsystem_entry(struct ClientEntry *ce, const char *service)
Find the subsystem entry of the given name for the specified client.