GNUnet  0.11.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 {
46  struct WatchEntry *next;
47 
51  struct WatchEntry *prev;
52 
56  struct ClientEntry *ce;
57 
61  uint64_t last_value;
62 
66  uint32_t wid;
67 
73 };
74 
75 
80 struct SubsystemEntry;
81 
82 
86 struct StatsEntry
87 {
91  struct StatsEntry *next;
92 
96  struct StatsEntry *prev;
97 
102 
107  const char *name;
108 
113 
118 
122  uint64_t value;
123 
127  uint32_t uid;
128 
133 
138  int set;
139 };
140 
141 
147 {
152 
157 
162 
167 
172  const char *service;
173 };
174 
175 
179 struct ClientEntry
180 {
184  struct GNUNET_SERVICE_Client *client;
185 
189  struct GNUNET_MQ_Handle *mq;
190 
195 
199  uint32_t max_wid;
200 };
201 
202 
206 static const struct GNUNET_CONFIGURATION_Handle *cfg;
207 
211 static struct SubsystemEntry *sub_head;
212 
216 static struct SubsystemEntry *sub_tail;
217 
221 static unsigned int client_count;
222 
227 
231 static uint32_t uidgen;
232 
236 static int in_shutdown;
237 
238 
242 static void
244 {
245  struct SubsystemEntry *se;
246  struct StatsEntry *pos;
247  char *fn;
248  struct GNUNET_BIO_WriteHandle *wh;
249  uint16_t size;
250  unsigned long long total;
251  size_t nlen;
252  size_t slen;
254 
256  "STATISTICS",
257  "DATABASE",
258  &fn))
259  {
261  "STATISTICS",
262  "DATABASE");
263  return;
264  }
266  wh = GNUNET_BIO_write_open_file (fn);
267  total = 0;
268  while (NULL != (se = sub_head))
269  {
270  GNUNET_CONTAINER_DLL_remove (sub_head, sub_tail, se);
271  slen = strlen (se->service) + 1;
272  while (NULL != (pos = se->stat_head))
273  {
275  if ((pos->persistent) && (NULL != wh))
276  {
277  nlen = strlen (pos->name) + 1;
278  size = sizeof(struct GNUNET_STATISTICS_SetMessage) + nlen + slen;
279  GNUNET_assert (size < UINT16_MAX);
280  msg = GNUNET_malloc (size);
281 
282  msg->header.size = htons ((uint16_t) size);
284  GNUNET_assert (nlen + slen ==
285  GNUNET_STRINGS_buffer_fill ((char *) &msg[1],
286  nlen + slen,
287  2,
288  se->service,
289  pos->name));
290  msg->flags =
292  msg->value = GNUNET_htonll (pos->value);
293  if (GNUNET_OK != GNUNET_BIO_write (wh, "statistics-save-msg", msg,
294  size))
295  {
297  if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
299  wh = NULL;
300  }
301  else
302  {
303  total += size;
304  }
305  GNUNET_free (msg);
306  }
307  GNUNET_free (pos);
308  }
309  GNUNET_free (se);
310  }
311  if (NULL != wh)
312  {
313  if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
315  if (0 == total)
316  GNUNET_break (0 == unlink (fn));
317  else
319  _ ("Wrote %llu bytes of statistics to `%s'\n"),
320  total,
321  fn);
322  }
323  GNUNET_free (fn);
324 }
325 
326 
333 static void
334 transmit (struct ClientEntry *ce, const struct StatsEntry *e)
335 {
336  struct GNUNET_MQ_Envelope *env;
338  size_t size;
339 
340  size = strlen (e->subsystem->service) + 1 + strlen (e->name) + 1;
343  m->uid = htonl (e->uid);
344  if (e->persistent)
345  m->uid |= htonl (GNUNET_STATISTICS_PERSIST_BIT);
346  m->value = GNUNET_htonll (e->value);
347  GNUNET_assert (size == GNUNET_STRINGS_buffer_fill ((char *) &m[1],
348  size,
349  2,
350  e->subsystem->service,
351  e->name));
353  "Transmitting value for `%s:%s' (%d): %llu\n",
354  e->subsystem->service,
355  e->name,
356  e->persistent,
357  (unsigned long long) e->value);
358  GNUNET_MQ_send (ce->mq, env);
359 }
360 
361 
370 static void *
371 client_connect_cb (void *cls,
372  struct GNUNET_SERVICE_Client *c,
373  struct GNUNET_MQ_Handle *mq)
374 {
375  struct ClientEntry *ce;
376 
377  ce = GNUNET_new (struct ClientEntry);
378  ce->client = c;
379  ce->mq = mq;
380  client_count++;
382  return ce;
383 }
384 
385 
393 static int
394 check_get (void *cls, const struct GNUNET_MessageHeader *message)
395 {
396  const char *service;
397  const char *name;
398  size_t size;
399 
400  size = ntohs (message->size) - sizeof(struct GNUNET_MessageHeader);
401  if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
402  size,
403  2,
404  &service,
405  &name))
406  {
407  GNUNET_break (0);
408  return GNUNET_SYSERR;
409  }
410  return GNUNET_OK;
411 }
412 
413 
420 static void
421 handle_get (void *cls, const struct GNUNET_MessageHeader *message)
422 {
423  struct ClientEntry *ce = cls;
424  struct GNUNET_MQ_Envelope *env;
425  struct GNUNET_MessageHeader *end;
426  const char *service;
427  const char *name;
428  size_t slen;
429  size_t nlen;
430  struct SubsystemEntry *se;
431  struct StatsEntry *pos;
432  size_t size;
433 
434  size = ntohs (message->size) - sizeof(struct GNUNET_MessageHeader);
435  GNUNET_assert (size ==
436  GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
437  size,
438  2,
439  &service,
440  &name));
441  slen = strlen (service);
442  nlen = strlen (name);
444  "Received request for statistics on `%s:%s'\n",
445  slen ? service : "*",
446  nlen ? name : "*");
447  for (se = sub_head; NULL != se; se = se->next)
448  {
449  if (! ((0 == slen) || (0 == strcmp (service, se->service))))
450  continue;
451  for (pos = se->stat_head; NULL != pos; pos = pos->next)
452  {
453  if (! ((0 == nlen) || (0 == strcmp (name, pos->name))))
454  continue;
455  transmit (ce, pos);
456  }
457  }
459  GNUNET_MQ_send (ce->mq, env);
461 }
462 
463 
469 static void
471 {
472  struct GNUNET_MQ_Envelope *env;
474  struct WatchEntry *pos;
475 
476  for (pos = se->we_head; NULL != pos; pos = pos->next)
477  {
478  if (GNUNET_YES == pos->last_value_set)
479  {
480  if (pos->last_value == se->value)
481  continue;
482  }
483  else
484  {
485  pos->last_value_set = GNUNET_YES;
486  }
488  wvm->flags =
490  wvm->wid = htonl (pos->wid);
491  wvm->reserved = htonl (0);
492  wvm->value = GNUNET_htonll (se->value);
493  GNUNET_MQ_send (pos->ce->mq, env);
494  pos->last_value = se->value;
495  }
496 }
497 
498 
507 static struct SubsystemEntry *
509 {
510  size_t slen;
511  struct SubsystemEntry *se;
512 
513  if (NULL != ce)
514  se = ce->subsystem;
515  else
516  se = NULL;
517  if ((NULL == se) || (0 != strcmp (service, se->service)))
518  {
519  for (se = sub_head; NULL != se; se = se->next)
520  if (0 == strcmp (service, se->service))
521  break;
522  if (NULL != ce)
523  ce->subsystem = se;
524  }
525  if (NULL != se)
526  return se;
528  "Allocating new subsystem entry `%s'\n",
529  service);
530  slen = strlen (service) + 1;
531  se = GNUNET_malloc (sizeof(struct SubsystemEntry) + slen);
532  GNUNET_memcpy (&se[1], service, slen);
533  se->service = (const char *) &se[1];
534  GNUNET_CONTAINER_DLL_insert (sub_head, sub_tail, se);
535  if (NULL != ce)
536  ce->subsystem = se;
537  return se;
538 }
539 
540 
548 static struct StatsEntry *
549 find_stat_entry (struct SubsystemEntry *se, const char *name)
550 {
551  struct StatsEntry *pos;
552 
553  for (pos = se->stat_head; NULL != pos; pos = pos->next)
554  if (0 == strcmp (name, pos->name))
555  return pos;
556  return NULL;
557 }
558 
559 
567 static int
568 check_set (void *cls, const struct GNUNET_STATISTICS_SetMessage *msg)
569 {
570  const char *service;
571  const char *name;
572  size_t msize;
573 
574  msize = ntohs (msg->header.size) - sizeof(*msg);
575  if (msize != GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1],
576  msize,
577  2,
578  &service,
579  &name))
580  {
581  GNUNET_break (0);
582  return GNUNET_SYSERR;
583  }
584  return GNUNET_OK;
585 }
586 
587 
594 static void
595 handle_set (void *cls, const struct GNUNET_STATISTICS_SetMessage *msg)
596 {
597  struct ClientEntry *ce = cls;
598  const char *service;
599  const char *name;
600  size_t nlen;
601  uint16_t msize;
602  uint16_t size;
603  struct SubsystemEntry *se;
604  struct StatsEntry *pos;
605  uint32_t flags;
606  uint64_t value;
607  int64_t delta;
608  int changed;
609  int initial_set;
610 
611  msize = ntohs (msg->header.size);
612  size = msize - sizeof(struct GNUNET_STATISTICS_SetMessage);
613  GNUNET_assert (size == GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1],
614  size,
615  2,
616  &service,
617  &name));
618  se = find_subsystem_entry (ce, service);
619  flags = ntohl (msg->flags);
620  value = GNUNET_ntohll (msg->value);
622  "Received request to update statistic on `%s:%s' (%u) to/by %llu\n",
623  service,
624  name,
625  (unsigned int) flags,
626  (unsigned long long) value);
627  pos = find_stat_entry (se, name);
628  if (NULL != pos)
629  {
630  initial_set = 0;
631  if (0 == (flags & GNUNET_STATISTICS_SETFLAG_RELATIVE))
632  {
633  changed = (pos->value != value);
634  pos->value = value;
635  }
636  else
637  {
638  delta = (int64_t) value;
639  if ((delta < 0) && (pos->value < -delta))
640  {
641  changed = (0 != pos->value);
642  pos->value = 0;
643  }
644  else
645  {
646  changed = (0 != delta);
647  GNUNET_break ((delta <= 0) || (pos->value + delta > pos->value));
648  pos->value += delta;
649  }
650  }
651  if (GNUNET_NO == pos->set)
652  {
653  pos->set = GNUNET_YES;
654  initial_set = 1;
655  }
656  pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT));
657  if (pos != se->stat_head)
658  {
659  /* move to front for faster setting next time! */
662  }
664  "Statistic `%s:%s' updated to value %llu (%d).\n",
665  service,
666  name,
667  (unsigned long long) pos->value,
668  pos->persistent);
669  if ((changed) || (1 == initial_set))
670  notify_change (pos);
672  return;
673  }
674  /* not found, create a new entry */
675  nlen = strlen (name) + 1;
676  pos = GNUNET_malloc (sizeof(struct StatsEntry) + nlen);
677  GNUNET_memcpy (&pos[1], name, nlen);
678  pos->name = (const char *) &pos[1];
679  pos->subsystem = se;
680  if ((0 == (flags & GNUNET_STATISTICS_SETFLAG_RELATIVE)) ||
681  (0 < (int64_t) GNUNET_ntohll (msg->value)))
682  {
683  pos->value = GNUNET_ntohll (msg->value);
684  pos->set = GNUNET_YES;
685  }
686  else
687  {
688  pos->set = GNUNET_NO;
689  }
690  pos->uid = uidgen++;
691  pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT));
694  "New statistic on `%s:%s' with value %llu created.\n",
695  service,
696  name,
697  (unsigned long long) pos->value);
698  if (NULL != ce)
700 }
701 
702 
710 static int
711 check_watch (void *cls, const struct GNUNET_MessageHeader *message)
712 {
713  size_t size;
714  const char *service;
715  const char *name;
716 
717  size = ntohs (message->size) - sizeof(struct GNUNET_MessageHeader);
718  if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
719  size,
720  2,
721  &service,
722  &name))
723  {
724  GNUNET_break (0);
725  return GNUNET_SYSERR;
726  }
727  return GNUNET_OK;
728 }
729 
730 
737 static void
738 handle_watch (void *cls, const struct GNUNET_MessageHeader *message)
739 {
740  struct ClientEntry *ce = cls;
741  const char *service;
742  const char *name;
743  uint16_t msize;
744  uint16_t size;
745  struct SubsystemEntry *se;
746  struct StatsEntry *pos;
747  struct WatchEntry *we;
748  size_t nlen;
749 
750  if (NULL == nc)
751  {
753  return;
754  }
756  msize = ntohs (message->size);
757  size = msize - sizeof(struct GNUNET_MessageHeader);
758  GNUNET_assert (size ==
759  GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
760  size,
761  2,
762  &service,
763  &name));
765  "Received request to watch statistic on `%s:%s'\n",
766  service,
767  name);
768  se = find_subsystem_entry (ce, service);
769  pos = find_stat_entry (se, name);
770  if (NULL == pos)
771  {
772  nlen = strlen (name) + 1;
773  pos = GNUNET_malloc (sizeof(struct StatsEntry) + nlen);
774  GNUNET_memcpy (&pos[1], name, nlen);
775  pos->name = (const char *) &pos[1];
776  pos->subsystem = se;
778  pos->uid = uidgen++;
779  pos->set = GNUNET_NO;
781  "New statistic on `%s:%s' with value %llu created.\n",
782  service,
783  name,
784  (unsigned long long) pos->value);
785  }
786  we = GNUNET_new (struct WatchEntry);
787  we->ce = ce;
789  we->wid = ce->max_wid++;
791  if (0 != pos->value)
792  notify_change (pos);
794 }
795 
796 
805 static void
806 handle_disconnect (void *cls, const struct GNUNET_MessageHeader *message)
807 {
808  struct ClientEntry *ce = cls;
809  struct GNUNET_MQ_Envelope *env;
810  struct GNUNET_MessageHeader *msg;
811 
813  GNUNET_MQ_send (ce->mq, env);
815 }
816 
817 
821 static void
823 {
824  struct WatchEntry *we;
825  struct StatsEntry *pos;
826  struct SubsystemEntry *se;
827 
828  if (NULL == nc)
829  return;
830  save ();
832  nc = NULL;
834  while (NULL != (se = sub_head))
835  {
836  GNUNET_CONTAINER_DLL_remove (sub_head, sub_tail, se);
837  while (NULL != (pos = se->stat_head))
838  {
840  while (NULL != (we = pos->we_head))
841  {
842  GNUNET_break (0);
844  GNUNET_free (we);
845  }
846  GNUNET_free (pos);
847  }
848  GNUNET_free (se);
849  }
850 }
851 
852 
858 static void
859 shutdown_task (void *cls)
860 {
862  if (0 != client_count)
863  return;
864  do_shutdown ();
865 }
866 
867 
875 static void
877  struct GNUNET_SERVICE_Client *client,
878  void *app_cls)
879 {
880  struct ClientEntry *ce = app_cls;
881  struct WatchEntry *we;
882  struct WatchEntry *wen;
883  struct StatsEntry *pos;
884  struct SubsystemEntry *se;
885 
886  client_count--;
887  for (se = sub_head; NULL != se; se = se->next)
888  {
889  for (pos = se->stat_head; NULL != pos; pos = pos->next)
890  {
891  wen = pos->we_head;
892  while (NULL != (we = wen))
893  {
894  wen = we->next;
895  if (we->ce != ce)
896  continue;
898  GNUNET_free (we);
899  }
900  }
901  }
902  GNUNET_free (ce);
903  if ((0 == client_count) && (GNUNET_YES == in_shutdown))
904  do_shutdown ();
905 }
906 
907 
919 static int
920 inject_message (void *cls, const struct GNUNET_MessageHeader *message)
921 {
922  uint16_t msize = ntohs (message->size);
923  const struct GNUNET_STATISTICS_SetMessage *sm;
924 
925  sm = (const struct GNUNET_STATISTICS_SetMessage *) message;
926  if ((sizeof(struct GNUNET_STATISTICS_SetMessage) > msize) ||
927  (GNUNET_OK != check_set (NULL, sm)))
928  {
929  GNUNET_break (0);
930  return GNUNET_SYSERR;
931  }
932  handle_set (NULL, sm);
933  return GNUNET_OK;
934 }
935 
936 
941 static void
943 {
944  char *fn;
945  struct GNUNET_BIO_ReadHandle *rh;
946  uint64_t fsize;
947  char *buf;
948  struct GNUNET_MessageStreamTokenizer *mst;
949 
951  "STATISTICS",
952  "DATABASE",
953  &fn))
954  {
956  "STATISTICS",
957  "DATABASE");
958  return;
959  }
960  if ((GNUNET_OK !=
961  GNUNET_DISK_file_size (fn, &fsize, GNUNET_NO, GNUNET_YES)) ||
962  (0 == fsize))
963  {
964  GNUNET_free (fn);
965  return;
966  }
967  buf = GNUNET_malloc (fsize);
968  rh = GNUNET_BIO_read_open_file (fn);
969  if (! rh)
970  {
971  GNUNET_free (buf);
972  GNUNET_free (fn);
973  return;
974  }
975  if (GNUNET_OK != GNUNET_BIO_read (rh, fn, buf, fsize))
976  {
979  GNUNET_free (buf);
980  GNUNET_free (fn);
981  return;
982  }
984  _ ("Loading %llu bytes of statistics from `%s'\n"),
985  (unsigned long long) fsize,
986  fn);
987  mst = GNUNET_MST_create (&inject_message, NULL);
988  GNUNET_break (
989  GNUNET_OK ==
990  GNUNET_MST_from_buffer (mst, buf, (size_t) fsize, GNUNET_YES, GNUNET_NO));
991  GNUNET_MST_destroy (mst);
992  GNUNET_free (buf);
994  GNUNET_free (fn);
995 }
996 
997 
1005 static void
1006 run (void *cls,
1007  const struct GNUNET_CONFIGURATION_Handle *c,
1009 {
1010  cfg = c;
1012  load ();
1014 }
1015 
1016 
1021  "statistics",
1023  &run,
1026  NULL,
1027  GNUNET_MQ_hd_var_size (set,
1030  NULL),
1031  GNUNET_MQ_hd_var_size (get,
1033  struct GNUNET_MessageHeader,
1034  NULL),
1037  struct GNUNET_MessageHeader,
1038  NULL),
1041  struct GNUNET_MessageHeader,
1042  NULL),
1044 
1045 
1046 #if defined(__linux__) && defined(__GLIBC__)
1047 #include <malloc.h>
1048 
1052 void __attribute__ ((constructor))
1053 GNUNET_STATISTICS_memory_init ()
1054 {
1055  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1056  mallopt (M_TOP_PAD, 1 * 1024);
1057  malloc_trim (0);
1058 }
1059 
1060 
1061 #endif
1062 
1063 
1064 /* 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:75
#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_BIO_ReadHandle * GNUNET_BIO_read_open_file(const char *fn)
Open a file for reading.
Definition: bio.c:119
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:1331
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_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#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:684
Message to set a statistic.
Definition: statistics.h:91
#define GNUNET_MESSAGE_TYPE_STATISTICS_VALUE
Response to a STATISTICS_GET message (with value).
uint32_t flags
0 for absolute value, 1 for relative value; 2 to make persistent (see GNUNET_STATISTICS_SETFLAG_*).
Definition: statistics.h:126
#define GNUNET_new(type)
Allocate a struct or union of the given type.
uint32_t reserved
Reserved (always 0).
Definition: statistics.h:139
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:75
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:160
struct GNUNET_SERVICE_Client * client
Handle identifying the client.
int GNUNET_BIO_read_close(struct GNUNET_BIO_ReadHandle *h, char **emsg)
Close an open handle.
Definition: bio.c:166
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define _(String)
GNU gettext support macro.
Definition: platform.h:184
Handle to a client that is connected to a service.
Definition: service.c:250
static int in_shutdown
Set to GNUNET_YES if we are shutting down as soon as possible.
struct SubsystemEntry * next
Subsystems are kept in a DLL.
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:104
int GNUNET_BIO_read(struct GNUNET_BIO_ReadHandle *h, const char *what, void *result, size_t len)
Read some contents into a buffer.
Definition: bio.c:287
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:137
Message transmitted if a watched value changes.
Definition: statistics.h:115
#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).
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:411
#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:85
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:66
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:114
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the &#39;monitor&#39; flag on this client.
Definition: service.c:2406
Handle for buffered writing.
Definition: bio.c:516
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:2323
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:134
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:36
struct GNUNET_BIO_WriteHandle * GNUNET_BIO_write_open_file(const char *fn)
Open a file for writing.
Definition: bio.c:559
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.
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.
Entry in the statistics list.
#define GNUNET_STATISTICS_PERSIST_BIT
Flag for the struct GNUNET_STATISTICS_ReplyMessage UID only.
Definition: statistics.h:65
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
int GNUNET_BIO_write_close(struct GNUNET_BIO_WriteHandle *h, char **emsg)
Close an IO handle.
Definition: bio.c:608
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.
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:257
#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:121
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:84
const char * name
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_STATISTICS_SET.
Definition: statistics.h:96
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.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition: nc.c:137
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:355
uint32_t uid
Unique ID.
struct SubsystemEntry * subsystem
Subsystem this entry belongs to.
int GNUNET_BIO_write(struct GNUNET_BIO_WriteHandle *h, const char *what, const void *buffer, size_t n)
Write a buffer to a handle.
Definition: bio.c:795
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:2242
#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:73
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
Definition: common_endian.c:53
#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:83
#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.