aboutsummaryrefslogtreecommitdiff
path: root/src/statistics
diff options
context:
space:
mode:
Diffstat (limited to 'src/statistics')
-rw-r--r--src/statistics/Makefile.am85
-rw-r--r--src/statistics/Makefile.in951
-rw-r--r--src/statistics/gnunet-service-statistics.c737
-rw-r--r--src/statistics/gnunet-statistics.c184
-rw-r--r--src/statistics/statistics.conf.in22
-rw-r--r--src/statistics/statistics.h135
-rw-r--r--src/statistics/statistics_api.c1277
-rwxr-xr-xsrc/statistics/test_gnunet_statistics.sh199
-rw-r--r--src/statistics/test_statistics_api.c212
-rw-r--r--src/statistics/test_statistics_api_data.conf43
-rw-r--r--src/statistics/test_statistics_api_loop.c133
-rw-r--r--src/statistics/test_statistics_api_watch.c164
12 files changed, 4142 insertions, 0 deletions
diff --git a/src/statistics/Makefile.am b/src/statistics/Makefile.am
new file mode 100644
index 0000000..2d1daf8
--- /dev/null
+++ b/src/statistics/Makefile.am
@@ -0,0 +1,85 @@
+INCLUDES = -I$(top_srcdir)/src/include
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+pkgcfg_DATA = \
+ statistics.conf
+
+lib_LTLIBRARIES = libgnunetstatistics.la
+
+libgnunetstatistics_la_SOURCES = \
+ statistics_api.c statistics.h
+libgnunetstatistics_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL) $(XLIB)
+libgnunetstatistics_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+ -version-info 1:0:1
+
+
+bin_PROGRAMS = \
+ gnunet-statistics \
+ gnunet-service-statistics
+
+gnunet_statistics_SOURCES = \
+ gnunet-statistics.c
+gnunet_statistics_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+gnunet_statistics_DEPENDENCIES = \
+ libgnunetstatistics.la
+
+gnunet_service_statistics_SOURCES = \
+ gnunet-service-statistics.c
+gnunet_service_statistics_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+gnunet_service_statistics_DEPENDENCIES = \
+ libgnunetstatistics.la
+
+check_PROGRAMS = \
+ test_statistics_api \
+ test_statistics_api_loop \
+ test_statistics_api_watch
+
+if ENABLE_TEST_RUN
+TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
+endif
+
+test_statistics_api_SOURCES = \
+ test_statistics_api.c
+test_statistics_api_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_statistics_api_loop_SOURCES = \
+ test_statistics_api_loop.c
+test_statistics_api_loop_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_statistics_api_watch_SOURCES = \
+ test_statistics_api_watch.c
+test_statistics_api_watch_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+check_SCRIPTS = \
+ test_gnunet_statistics.sh
+
+EXTRA_DIST = \
+ test_statistics_api_data.conf \
+ $(check_SCRIPTS)
+
+
diff --git a/src/statistics/Makefile.in b/src/statistics/Makefile.in
new file mode 100644
index 0000000..1930c3a
--- /dev/null
+++ b/src/statistics/Makefile.in
@@ -0,0 +1,951 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+bin_PROGRAMS = gnunet-statistics$(EXEEXT) \
+ gnunet-service-statistics$(EXEEXT)
+check_PROGRAMS = test_statistics_api$(EXEEXT) \
+ test_statistics_api_loop$(EXEEXT) \
+ test_statistics_api_watch$(EXEEXT)
+subdir = src/statistics
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/statistics.conf.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \
+ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \
+ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/gnunet_config.h
+CONFIG_CLEAN_FILES = statistics.conf
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(pkgcfgdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgnunetstatistics_la_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgnunetstatistics_la_OBJECTS = statistics_api.lo
+libgnunetstatistics_la_OBJECTS = $(am_libgnunetstatistics_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libgnunetstatistics_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libgnunetstatistics_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+PROGRAMS = $(bin_PROGRAMS)
+am_gnunet_service_statistics_OBJECTS = \
+ gnunet-service-statistics.$(OBJEXT)
+gnunet_service_statistics_OBJECTS = \
+ $(am_gnunet_service_statistics_OBJECTS)
+am_gnunet_statistics_OBJECTS = gnunet-statistics.$(OBJEXT)
+gnunet_statistics_OBJECTS = $(am_gnunet_statistics_OBJECTS)
+am_test_statistics_api_OBJECTS = test_statistics_api.$(OBJEXT)
+test_statistics_api_OBJECTS = $(am_test_statistics_api_OBJECTS)
+test_statistics_api_DEPENDENCIES = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_test_statistics_api_loop_OBJECTS = \
+ test_statistics_api_loop.$(OBJEXT)
+test_statistics_api_loop_OBJECTS = \
+ $(am_test_statistics_api_loop_OBJECTS)
+test_statistics_api_loop_DEPENDENCIES = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_test_statistics_api_watch_OBJECTS = \
+ test_statistics_api_watch.$(OBJEXT)
+test_statistics_api_watch_OBJECTS = \
+ $(am_test_statistics_api_watch_OBJECTS)
+test_statistics_api_watch_DEPENDENCIES = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgnunetstatistics_la_SOURCES) \
+ $(gnunet_service_statistics_SOURCES) \
+ $(gnunet_statistics_SOURCES) $(test_statistics_api_SOURCES) \
+ $(test_statistics_api_loop_SOURCES) \
+ $(test_statistics_api_watch_SOURCES)
+DIST_SOURCES = $(libgnunetstatistics_la_SOURCES) \
+ $(gnunet_service_statistics_SOURCES) \
+ $(gnunet_statistics_SOURCES) $(test_statistics_api_SOURCES) \
+ $(test_statistics_api_loop_SOURCES) \
+ $(test_statistics_api_watch_SOURCES)
+DATA = $(pkgcfg_DATA)
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ARGZ_H = @ARGZ_H@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_INTERFACE = @DEFAULT_INTERFACE@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLDIR = @DLLDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXT_LIBS = @EXT_LIBS@
+EXT_LIB_PATH = @EXT_LIB_PATH@
+FGREP = @FGREP@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUNETDNS_GROUP = @GNUNETDNS_GROUP@
+GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@
+GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@
+GN_INTLINCL = @GN_INTLINCL@
+GN_LIBINTL = @GN_LIBINTL@
+GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@
+GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@
+GN_USER_HOME_DIR = @GN_USER_HOME_DIR@
+GREP = @GREP@
+HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@
+INCLTDL = @INCLTDL@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBADD_DL = @LIBADD_DL@
+LIBADD_DLD_LINK = @LIBADD_DLD_LINK@
+LIBADD_DLOPEN = @LIBADD_DLOPEN@
+LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBLTDL = @LIBLTDL@
+LIBOBJS = @LIBOBJS@
+LIBPREFIX = @LIBPREFIX@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNISTRING = @LIBUNISTRING@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTDLDEPS = @LTDLDEPS@
+LTDLINCL = @LTDLINCL@
+LTDLOPEN = @LTDLOPEN@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBUNISTRING = @LTLIBUNISTRING@
+LT_CONFIG_H = @LT_CONFIG_H@
+LT_DLLOADERS = @LT_DLLOADERS@
+LT_DLPREOPEN = @LT_DLPREOPEN@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJCFLAGS = @OBJCFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@
+POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@
+POSUB = @POSUB@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@
+SQLITE_LDFLAGS = @SQLITE_LDFLAGS@
+STRIP = @STRIP@
+SUDO_BINARY = @SUDO_BINARY@
+UNIXONLY = @UNIXONLY@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+ltdl_LIBOBJS = @ltdl_LIBOBJS@
+ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sys_symbol_underscore = @sys_symbol_underscore@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(top_srcdir)/src/include
+@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0
+@USE_COVERAGE_TRUE@XLIB = -lgcov
+pkgcfgdir = $(pkgdatadir)/config.d/
+pkgcfg_DATA = \
+ statistics.conf
+
+lib_LTLIBRARIES = libgnunetstatistics.la
+libgnunetstatistics_la_SOURCES = \
+ statistics_api.c statistics.h
+
+libgnunetstatistics_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL) $(XLIB)
+
+libgnunetstatistics_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+ -version-info 1:0:1
+
+gnunet_statistics_SOURCES = \
+ gnunet-statistics.c
+
+gnunet_statistics_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+
+gnunet_statistics_DEPENDENCIES = \
+ libgnunetstatistics.la
+
+gnunet_service_statistics_SOURCES = \
+ gnunet-service-statistics.c
+
+gnunet_service_statistics_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+
+gnunet_service_statistics_DEPENDENCIES = \
+ libgnunetstatistics.la
+
+@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
+test_statistics_api_SOURCES = \
+ test_statistics_api.c
+
+test_statistics_api_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_statistics_api_loop_SOURCES = \
+ test_statistics_api_loop.c
+
+test_statistics_api_loop_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_statistics_api_watch_SOURCES = \
+ test_statistics_api_watch.c
+
+test_statistics_api_watch_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+check_SCRIPTS = \
+ test_gnunet_statistics.sh
+
+EXTRA_DIST = \
+ test_statistics_api_data.conf \
+ $(check_SCRIPTS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/statistics/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/statistics/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+statistics.conf: $(top_builddir)/config.status $(srcdir)/statistics.conf.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgnunetstatistics.la: $(libgnunetstatistics_la_OBJECTS) $(libgnunetstatistics_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunetstatistics_la_LINK) -rpath $(libdir) $(libgnunetstatistics_la_OBJECTS) $(libgnunetstatistics_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+gnunet-service-statistics$(EXEEXT): $(gnunet_service_statistics_OBJECTS) $(gnunet_service_statistics_DEPENDENCIES)
+ @rm -f gnunet-service-statistics$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_service_statistics_OBJECTS) $(gnunet_service_statistics_LDADD) $(LIBS)
+gnunet-statistics$(EXEEXT): $(gnunet_statistics_OBJECTS) $(gnunet_statistics_DEPENDENCIES)
+ @rm -f gnunet-statistics$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_statistics_OBJECTS) $(gnunet_statistics_LDADD) $(LIBS)
+test_statistics_api$(EXEEXT): $(test_statistics_api_OBJECTS) $(test_statistics_api_DEPENDENCIES)
+ @rm -f test_statistics_api$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_statistics_api_OBJECTS) $(test_statistics_api_LDADD) $(LIBS)
+test_statistics_api_loop$(EXEEXT): $(test_statistics_api_loop_OBJECTS) $(test_statistics_api_loop_DEPENDENCIES)
+ @rm -f test_statistics_api_loop$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_statistics_api_loop_OBJECTS) $(test_statistics_api_loop_LDADD) $(LIBS)
+test_statistics_api_watch$(EXEEXT): $(test_statistics_api_watch_OBJECTS) $(test_statistics_api_watch_DEPENDENCIES)
+ @rm -f test_statistics_api_watch$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_statistics_api_watch_OBJECTS) $(test_statistics_api_watch_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-statistics.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-statistics.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statistics_api.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api_loop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api_watch.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgcfgDATA: $(pkgcfg_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)"
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \
+ done
+
+uninstall-pkgcfgDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ echo "$$grn$$dashes"; \
+ else \
+ echo "$$red$$dashes"; \
+ fi; \
+ echo "$$banner"; \
+ test -z "$$skipped" || echo "$$skipped"; \
+ test -z "$$report" || echo "$$report"; \
+ echo "$$dashes$$std"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgcfgDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-pkgcfgDATA
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-pkgcfgDATA
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c
new file mode 100644
index 0000000..a890d6d
--- /dev/null
+++ b/src/statistics/gnunet-service-statistics.c
@@ -0,0 +1,737 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file statistics/gnunet-service-statistics.c
+ * @brief program that tracks statistics
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_bio_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_disk_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_service_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_strings_lib.h"
+#include "gnunet_time_lib.h"
+#include "statistics.h"
+
+/**
+ * Watch entry.
+ */
+struct WatchEntry
+{
+
+ struct WatchEntry *next;
+
+ struct WatchEntry *prev;
+
+ struct GNUNET_SERVER_Client *client;
+
+ uint64_t last_value;
+
+ uint32_t wid;
+
+};
+
+
+/**
+ * Client entry.
+ */
+struct ClientEntry
+{
+
+ struct ClientEntry *next;
+
+ struct ClientEntry *prev;
+
+ struct GNUNET_SERVER_Client *client;
+
+ uint32_t max_wid;
+
+};
+
+/**
+ * Entry in the statistics list.
+ */
+struct StatsEntry
+{
+ /**
+ * This is a linked list.
+ */
+ struct StatsEntry *next;
+
+ /**
+ * Name of the service, points into the
+ * middle of msg.
+ */
+ const char *service;
+
+ /**
+ * Name for the value, points into
+ * the middle of msg.
+ */
+ const char *name;
+
+ /**
+ * Message that can be used to set this value,
+ * stored at the end of the memory used by
+ * this struct.
+ */
+ struct GNUNET_STATISTICS_SetMessage *msg;
+
+ /**
+ * Watch context for changes to this
+ * value, or NULL for none.
+ */
+ struct WatchEntry *we_head;
+
+ /**
+ * Watch context for changes to this
+ * value, or NULL for none.
+ */
+ struct WatchEntry *we_tail;
+
+ /**
+ * Our value.
+ */
+ uint64_t value;
+
+ /**
+ * Unique ID.
+ */
+ uint32_t uid;
+
+ /**
+ * Is this value persistent?
+ */
+ int persistent;
+
+};
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Linked list of our active statistics.
+ */
+static struct StatsEntry *start;
+
+static struct ClientEntry *client_head;
+
+static struct ClientEntry *client_tail;
+
+/**
+ * Our notification context.
+ */
+static struct GNUNET_SERVER_NotificationContext *nc;
+
+/**
+ * Counter used to generate unique values.
+ */
+static uint32_t uidgen;
+
+
+static void
+inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_SERVER_Handle *server = cls;
+
+ GNUNET_break (GNUNET_OK == GNUNET_SERVER_inject (server, NULL, msg));
+}
+
+
+/**
+ * Load persistent values from disk. Disk format is
+ * exactly the same format that we also use for
+ * setting the values over the network.
+ *
+ * @param server handle to the server context
+ */
+static void
+load (struct GNUNET_SERVER_Handle *server)
+{
+ char *fn;
+ struct GNUNET_BIO_ReadHandle *rh;
+ struct stat sb;
+ char *buf;
+ struct GNUNET_SERVER_MessageStreamTokenizer *mst;
+ char *emsg;
+
+ fn = GNUNET_DISK_get_home_filename (cfg, "statistics", "statistics.data",
+ NULL);
+ if (fn == NULL)
+ return;
+ if ((0 != stat (fn, &sb)) || (sb.st_size == 0))
+ {
+ GNUNET_free (fn);
+ return;
+ }
+ buf = GNUNET_malloc (sb.st_size);
+ rh = GNUNET_BIO_read_open (fn);
+ if (!rh)
+ {
+ GNUNET_free (buf);
+ GNUNET_free (fn);
+ return;
+ }
+ if (GNUNET_OK != GNUNET_BIO_read (rh, fn, buf, sb.st_size))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", fn);
+ GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg));
+ GNUNET_free (buf);
+ GNUNET_free_non_null (emsg);
+ GNUNET_free (fn);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Loading %llu bytes of statistics from `%s'\n"),
+ (unsigned long long) sb.st_size, fn);
+ mst = GNUNET_SERVER_mst_create (&inject_message, server);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_SERVER_mst_receive (mst, NULL, buf, sb.st_size,
+ GNUNET_YES, GNUNET_NO));
+ GNUNET_SERVER_mst_destroy (mst);
+ GNUNET_free (buf);
+ GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg));
+ GNUNET_free_non_null (emsg);
+ GNUNET_free (fn);
+}
+
+/**
+ * Write persistent statistics to disk.
+ */
+static void
+save ()
+{
+ struct StatsEntry *pos;
+ char *fn;
+ struct GNUNET_BIO_WriteHandle *wh;
+
+ uint16_t size;
+ unsigned long long total;
+
+ wh = NULL;
+ fn = GNUNET_DISK_get_home_filename (cfg, "statistics", "statistics.data",
+ NULL);
+ if (fn != NULL)
+ wh = GNUNET_BIO_write_open (fn);
+ total = 0;
+ while (NULL != (pos = start))
+ {
+ start = pos->next;
+ if ((pos->persistent) && (NULL != wh))
+ {
+ size = htons (pos->msg->header.size);
+ if (GNUNET_OK != GNUNET_BIO_write (wh, pos->msg, size))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);
+ if (GNUNET_OK != GNUNET_BIO_write_close (wh))
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn);
+ wh = NULL;
+ }
+ else
+ total += size;
+ }
+ GNUNET_free (pos);
+ }
+ if (NULL != wh)
+ {
+ if (GNUNET_OK != GNUNET_BIO_write_close (wh))
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn);
+ if (total == 0)
+ GNUNET_break (0 == UNLINK (fn));
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Wrote %llu bytes of statistics to `%s'\n"), total, fn);
+ }
+ GNUNET_free_non_null (fn);
+}
+
+
+/**
+ * Transmit the given stats value.
+ */
+static void
+transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e)
+{
+ struct GNUNET_STATISTICS_ReplyMessage *m;
+ size_t size;
+
+ size =
+ sizeof (struct GNUNET_STATISTICS_ReplyMessage) + strlen (e->service) + 1 +
+ strlen (e->name) + 1;
+ GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ m = GNUNET_malloc (size);
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_VALUE);
+ m->header.size = htons (size);
+ m->uid = htonl (e->uid);
+ if (e->persistent)
+ m->uid |= htonl (GNUNET_STATISTICS_PERSIST_BIT);
+ m->value = GNUNET_htonll (e->value);
+ size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage);
+ GNUNET_assert (size ==
+ GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2,
+ e->service, e->name));
+#if DEBUG_STATISTICS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting value for `%s:%s' (%d): %llu\n", e->service,
+ e->name, e->persistent, e->value);
+#endif
+ GNUNET_SERVER_notification_context_unicast (nc, client, &m->header,
+ GNUNET_NO);
+ GNUNET_free (m);
+}
+
+
+/**
+ * Does this entry match the request?
+ */
+static int
+matches (const struct StatsEntry *e, const char *service, const char *name)
+{
+ return ((0 == strlen (service)) || (0 == strcmp (service, e->service))) &&
+ ((0 == strlen (name)) || (0 == strcmp (name, e->name)));
+}
+
+
+static struct ClientEntry *
+make_client_entry (struct GNUNET_SERVER_Client *client)
+{
+ struct ClientEntry *ce;
+
+ GNUNET_assert (client != NULL);
+ ce = client_head;
+ while (ce != NULL)
+ {
+ if (ce->client == client)
+ return ce;
+ ce = ce->next;
+ }
+ ce = GNUNET_malloc (sizeof (struct ClientEntry));
+ ce->client = client;
+ GNUNET_SERVER_client_keep (client);
+ GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ce);
+ GNUNET_SERVER_notification_context_add (nc, client);
+ return ce;
+}
+
+
+/**
+ * Handle GET-message.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static void
+handle_get (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_MessageHeader end;
+ char *service;
+ char *name;
+ struct StatsEntry *pos;
+ size_t size;
+
+ if (client != NULL)
+ make_client_entry (client);
+ size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
+ if (size !=
+ GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2,
+ &service, &name))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+#if DEBUG_STATISTICS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received request for statistics on `%s:%s'\n",
+ strlen (service) ? service : "*", strlen (name) ? name : "*");
+#endif
+ pos = start;
+ while (pos != NULL)
+ {
+ if (matches (pos, service, name))
+ transmit (client, pos);
+ pos = pos->next;
+ }
+ end.size = htons (sizeof (struct GNUNET_MessageHeader));
+ end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END);
+ GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+static void
+notify_change (struct StatsEntry *se)
+{
+ struct GNUNET_STATISTICS_WatchValueMessage wvm;
+ struct WatchEntry *pos;
+
+ pos = se->we_head;
+ while (pos != NULL)
+ {
+ if (pos->last_value != se->value)
+ {
+ wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE);
+ wvm.header.size =
+ htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage));
+ wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0);
+ wvm.wid = htonl (pos->wid);
+ wvm.reserved = htonl (0);
+ wvm.value = GNUNET_htonll (se->value);
+ GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header,
+ GNUNET_NO);
+ pos->last_value = se->value;
+ }
+ pos = pos->next;
+ }
+}
+
+/**
+ * Handle SET-message.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_set (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ char *service;
+ char *name;
+ uint16_t msize;
+ uint16_t size;
+ const struct GNUNET_STATISTICS_SetMessage *msg;
+ struct StatsEntry *pos;
+ struct StatsEntry *prev;
+ uint32_t flags;
+ uint64_t value;
+ int64_t delta;
+ int changed;
+
+ if (client != NULL)
+ make_client_entry (client);
+ msize = ntohs (message->size);
+ if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage);
+ msg = (const struct GNUNET_STATISTICS_SetMessage *) message;
+
+ if (size !=
+ GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], size, 2, &service,
+ &name))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ flags = ntohl (msg->flags);
+ value = GNUNET_ntohll (msg->value);
+#if DEBUG_STATISTICS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received request to update statistic on `%s:%s' (%u) to/by %llu\n",
+ service, name, (unsigned int) flags, (unsigned long long) value);
+#endif
+ pos = start;
+ prev = NULL;
+ while (pos != NULL)
+ {
+ if (matches (pos, service, name))
+ {
+ if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0)
+ {
+ changed = (pos->value != value);
+ pos->value = value;
+ }
+ else
+ {
+ delta = (int64_t) value;
+ if ((delta < 0) && (pos->value < -delta))
+ {
+ changed = (pos->value != 0);
+ pos->value = 0;
+ }
+ else
+ {
+ changed = (delta != 0);
+ GNUNET_break ((delta <= 0) || (pos->value + delta > pos->value));
+ pos->value += delta;
+ }
+ }
+ pos->msg->value = GNUNET_htonll (pos->value);
+ pos->msg->flags = msg->flags;
+ pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT));
+ if (prev != NULL)
+ {
+ /* move to front for faster setting next time! */
+ prev->next = pos->next;
+ pos->next = start;
+ start = pos;
+ }
+#if DEBUG_STATISTICS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Statistic `%s:%s' updated to value %llu.\n", service, name,
+ pos->value);
+#endif
+ if (changed)
+ notify_change (pos);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ prev = pos;
+ pos = pos->next;
+ }
+ pos = GNUNET_malloc (sizeof (struct StatsEntry) + msize);
+ pos->next = start;
+ if (((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) ||
+ (0 < (int64_t) GNUNET_ntohll (msg->value)))
+ pos->value = GNUNET_ntohll (msg->value);
+ pos->uid = uidgen++;
+ pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT));
+ pos->msg = (void *) &pos[1];
+ memcpy (pos->msg, message, ntohs (message->size));
+ pos->service = (const char *) &pos->msg[1];
+ pos->name = &pos->service[strlen (pos->service) + 1];
+
+ start = pos;
+#if DEBUG_STATISTICS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "New statistic on `%s:%s' with value %llu created.\n", service,
+ name, pos->value);
+#endif
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle WATCH-message.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_watch (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ char *service;
+ char *name;
+ uint16_t msize;
+ uint16_t size;
+ struct StatsEntry *pos;
+ struct ClientEntry *ce;
+ struct WatchEntry *we;
+ size_t slen;
+
+ ce = make_client_entry (client);
+ msize = ntohs (message->size);
+ if (msize < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ size = msize - sizeof (struct GNUNET_MessageHeader);
+ if (size !=
+ GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2,
+ &service, &name))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+#if DEBUG_STATISTICS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received request to watch statistic on `%s:%s'\n", service,
+ name);
+#endif
+ pos = start;
+ while (pos != NULL)
+ {
+ if (matches (pos, service, name))
+ break;
+ pos = pos->next;
+ }
+ if (pos == NULL)
+ {
+ pos =
+ GNUNET_malloc (sizeof (struct StatsEntry) +
+ sizeof (struct GNUNET_STATISTICS_SetMessage) + size);
+ pos->next = start;
+ pos->uid = uidgen++;
+ pos->msg = (void *) &pos[1];
+ pos->msg->header.size =
+ htons (sizeof (struct GNUNET_STATISTICS_SetMessage) + size);
+ pos->msg->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET);
+ pos->service = (const char *) &pos->msg[1];
+ slen = strlen (service) + 1;
+ memcpy ((void *) pos->service, service, slen);
+ pos->name = &pos->service[slen];
+ memcpy ((void *) pos->name, name, strlen (name) + 1);
+ start = pos;
+ }
+ we = GNUNET_malloc (sizeof (struct WatchEntry));
+ we->client = client;
+ GNUNET_SERVER_client_keep (client);
+ we->wid = ce->max_wid++;
+ GNUNET_CONTAINER_DLL_insert (pos->we_head, pos->we_tail, we);
+ if (pos->value != 0)
+ notify_change (pos);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ClientEntry *ce;
+ struct WatchEntry *we;
+ struct StatsEntry *se;
+
+ save ();
+ GNUNET_SERVER_notification_context_destroy (nc);
+ nc = NULL;
+ while (NULL != (ce = client_head))
+ {
+ GNUNET_SERVER_client_drop (ce->client);
+ GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce);
+ GNUNET_free (ce);
+ }
+ while (NULL != (se = start))
+ {
+ start = se->next;
+ while (NULL != (we = se->we_head))
+ {
+ GNUNET_SERVER_client_drop (we->client);
+ GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we);
+ GNUNET_free (we);
+ }
+ GNUNET_free (se);
+ }
+}
+
+
+/**
+ * A client disconnected. Remove all of its data structure entries.
+ *
+ * @param cls closure, NULL
+ * @param client identification of the client
+ */
+static void
+handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct ClientEntry *ce;
+ struct WatchEntry *we;
+ struct WatchEntry *wen;
+ struct StatsEntry *se;
+
+ ce = client_head;
+ while (NULL != ce)
+ {
+ if (ce->client == client)
+ {
+ GNUNET_SERVER_client_drop (ce->client);
+ GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce);
+ GNUNET_free (ce);
+ break;
+ }
+ ce = ce->next;
+ }
+ se = start;
+ while (NULL != se)
+ {
+ wen = se->we_head;
+ while (NULL != (we = wen))
+ {
+ wen = we->next;
+ if (we->client != client)
+ continue;
+ GNUNET_SERVER_client_drop (we->client);
+ GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we);
+ GNUNET_free (we);
+ }
+ se = se->next;
+ }
+}
+
+
+/**
+ * Process statistics requests.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+ {&handle_set, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_SET, 0},
+ {&handle_get, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_GET, 0},
+ {&handle_watch, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_WATCH, 0},
+ {NULL, NULL, 0, 0}
+ };
+ cfg = c;
+ GNUNET_SERVER_add_handlers (server, handlers);
+ nc = GNUNET_SERVER_notification_context_create (server, 16);
+ GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
+ load (server);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+ NULL);
+}
+
+
+/**
+ * The main function for the statistics service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ return (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc, argv, "statistics",
+ GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-statistics.c */
diff --git a/src/statistics/gnunet-statistics.c b/src/statistics/gnunet-statistics.c
new file mode 100644
index 0000000..ce91572
--- /dev/null
+++ b/src/statistics/gnunet-statistics.c
@@ -0,0 +1,184 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file statistics/gnunet-statistics.c
+ * @brief tool to obtain statistics
+ * @author Christian Grothoff
+ * @author Igor Wronsky
+ */
+#include "platform.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_statistics_service.h"
+#include "statistics.h"
+
+#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+/**
+ * Final status code.
+ */
+static int ret;
+
+/**
+ * Set to subsystem that we're going to get stats for (or NULL for all).
+ */
+static char *subsystem;
+
+/**
+ * Set to the specific stat value that we are after (or NULL for all).
+ */
+static char *name;
+
+/**
+ * Make the value that is being set persistent.
+ */
+static int persistent;
+
+/**
+ * Quiet mode
+ */
+static int quiet;
+
+/**
+ * Callback function to process statistic values.
+ *
+ * @param cls closure
+ * @param subsystem name of subsystem that created the statistic
+ * @param name the name of the datum
+ * @param value the current value
+ * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
+ * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
+ */
+static int
+printer (void *cls, const char *subsystem, const char *name, uint64_t value,
+ int is_persistent)
+{
+ if (quiet == GNUNET_NO)
+ FPRINTF (stdout, "%s%-12s %-50s: %16llu\n", is_persistent ? "!" : " ",
+ subsystem, _(name), (unsigned long long) value);
+ else
+ FPRINTF (stdout, "%llu\n", (unsigned long long) value);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called last by the statistics code.
+ *
+ * @param cls closure
+ * @param success GNUNET_OK if statistics were
+ * successfully obtained, GNUNET_SYSERR if not.
+ */
+static void
+cleanup (void *cls, int success)
+{
+ struct GNUNET_STATISTICS_Handle *h = cls;
+
+ if (success != GNUNET_OK)
+ {
+ FPRINTF (stderr, "%s", _("Failed to obtain statistics.\n"));
+ ret = 1;
+ }
+ if (h != NULL)
+ GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct GNUNET_STATISTICS_Handle *h;
+ unsigned long long val;
+
+ if (args[0] != NULL)
+ {
+ if ((1 != SSCANF (args[0], "%llu", &val)) || (subsystem == NULL) ||
+ (name == NULL))
+ {
+ FPRINTF (stderr, _("Invalid argument `%s'\n"), args[0]);
+ ret = 1;
+ return;
+ }
+ h = GNUNET_STATISTICS_create (subsystem, cfg);
+ if (h == NULL)
+ {
+ ret = 1;
+ return;
+ }
+ GNUNET_STATISTICS_set (h, name, (uint64_t) val, persistent);
+ GNUNET_STATISTICS_destroy (h, GNUNET_YES);
+ return;
+ }
+ h = GNUNET_STATISTICS_create ("gnunet-statistics", cfg);
+ if (h == NULL)
+ {
+ ret = 1;
+ return;
+ }
+ if (NULL ==
+ GNUNET_STATISTICS_get (h, subsystem, name, GET_TIMEOUT, &cleanup,
+ &printer, h))
+ cleanup (h, GNUNET_SYSERR);
+}
+
+/**
+ * The main function to obtain statistics in GNUnet.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'n', "name", "NAME",
+ gettext_noop ("limit output to statistics for the given NAME"), 1,
+ &GNUNET_GETOPT_set_string, &name},
+ {'p', "persistent", NULL,
+ gettext_noop ("make the value being set persistent"), 0,
+ &GNUNET_GETOPT_set_one, &persistent},
+ {'s', "subsystem", "SUBSYSTEM",
+ gettext_noop ("limit output to the given SUBSYSTEM"), 1,
+ &GNUNET_GETOPT_set_string, &subsystem},
+ {'q', "quiet", NULL,
+ gettext_noop ("just print the statistics value"), 0,
+ &GNUNET_GETOPT_set_one, &quiet},
+ GNUNET_GETOPT_OPTION_END
+ };
+ return (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc, argv, "gnunet-statistics [options [value]]",
+ gettext_noop
+ ("Print statistics about GNUnet operations."),
+ options, &run, NULL)) ? ret : 1;
+}
+
+/* end of gnunet-statistics.c */
diff --git a/src/statistics/statistics.conf.in b/src/statistics/statistics.conf.in
new file mode 100644
index 0000000..4482b0f
--- /dev/null
+++ b/src/statistics/statistics.conf.in
@@ -0,0 +1,22 @@
+[statistics]
+AUTOSTART = YES
+@UNIXONLY@ PORT = 2088
+HOSTNAME = localhost
+HOME = $SERVICEHOME
+CONFIG = $DEFAULTCONFIG
+BINARY = gnunet-service-statistics
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+UNIXPATH = /tmp/gnunet-service-statistics.sock
+UNIX_MATCH_UID = NO
+UNIX_MATCH_GID = YES
+# DISABLE_SOCKET_FORWARDING = NO
+# USERNAME =
+# MAXBUF =
+# TIMEOUT =
+# DISABLEV6 =
+# BINDTO =
+# REJECT_FROM =
+# REJECT_FROM6 =
+# PREFIX =
+
diff --git a/src/statistics/statistics.h b/src/statistics/statistics.h
new file mode 100644
index 0000000..3fcac27
--- /dev/null
+++ b/src/statistics/statistics.h
@@ -0,0 +1,135 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @author Christian Grothoff
+ * @file statistics/statistics.h
+ */
+#ifndef STATISTICS_H
+#define STATISTICS_H
+
+#include "gnunet_common.h"
+
+#define DEBUG_STATISTICS GNUNET_EXTRA_LOGGING
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Statistics message. Contains how long the system is up
+ * and one value.
+ *
+ * The struct is be followed by the service name and
+ * name of the statistic, both 0-terminated.
+ */
+struct GNUNET_STATISTICS_ReplyMessage
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_STATISTICS_VALUE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique numerical identifier for the value (will
+ * not change during the same client-session). Highest
+ * bit will be set for persistent values.
+ */
+ uint32_t uid GNUNET_PACKED;
+
+ /**
+ * The value.
+ */
+ uint64_t value GNUNET_PACKED;
+
+};
+
+#define GNUNET_STATISTICS_PERSIST_BIT (1<<31)
+
+#define GNUNET_STATISTICS_SETFLAG_ABSOLUTE 0
+
+#define GNUNET_STATISTICS_SETFLAG_RELATIVE 1
+
+#define GNUNET_STATISTICS_SETFLAG_PERSISTENT 2
+
+/**
+ * Message to set a statistic. Followed
+ * by the subsystem name and the name of
+ * the statistic (each 0-terminated).
+ */
+struct GNUNET_STATISTICS_SetMessage
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_STATISTICS_SET
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * 0 for absolute value, 1 for relative value; 2 to make persistent
+ * (see GNUNET_STATISTICS_SETFLAG_*).
+ */
+ uint32_t flags GNUNET_PACKED;
+
+ /**
+ * Value. Note that if this is a relative value, it will
+ * be signed even though the type given here is unsigned.
+ */
+ uint64_t value GNUNET_PACKED;
+
+};
+
+
+/**
+ * Message transmitted if a watched value changes.
+ */
+struct GNUNET_STATISTICS_WatchValueMessage
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * 0 for absolute value, 1 for relative value; 2 to make persistent
+ * (see GNUNET_STATISTICS_SETFLAG_*).
+ */
+ uint32_t flags GNUNET_PACKED;
+
+ /**
+ * Unique watch identification number (watch
+ * requests are enumerated in the order they
+ * are received, the first request having
+ * a wid of zero).
+ */
+ uint32_t wid GNUNET_PACKED;
+
+ /**
+ * Reserved (always 0).
+ */
+ uint32_t reserved GNUNET_PACKED;
+
+ /**
+ * Value. Note that if this is a relative value, it will
+ * be signed even though the type given here is unsigned.
+ */
+ uint64_t value GNUNET_PACKED;
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+#endif
diff --git a/src/statistics/statistics_api.c b/src/statistics/statistics_api.c
new file mode 100644
index 0000000..2838b70
--- /dev/null
+++ b/src/statistics/statistics_api.c
@@ -0,0 +1,1277 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file statistics/statistics_api.c
+ * @brief API of the statistics service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_strings_lib.h"
+#include "statistics.h"
+
+/**
+ * How long do we wait until a statistics request for setting
+ * a value times out? (The update will be lost if the
+ * service does not react within this timeframe).
+ */
+#define SET_TRANSMIT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
+
+#define LOG(kind,...) GNUNET_log_from (kind, "statistics-api",__VA_ARGS__)
+
+/**
+ * Types of actions.
+ */
+enum ActionType
+{
+ /**
+ * Get a value.
+ */
+ ACTION_GET,
+
+ /**
+ * Set a value.
+ */
+ ACTION_SET,
+
+ /**
+ * Update a value.
+ */
+ ACTION_UPDATE,
+
+ /**
+ * Watch a value.
+ */
+ ACTION_WATCH
+};
+
+
+/**
+ * Entry kept for each value we are watching.
+ */
+struct GNUNET_STATISTICS_WatchEntry
+{
+
+ /**
+ * What subsystem is this action about? (never NULL)
+ */
+ char *subsystem;
+
+ /**
+ * What value is this action about? (never NULL)
+ */
+ char *name;
+
+ /**
+ * Function to call
+ */
+ GNUNET_STATISTICS_Iterator proc;
+
+ /**
+ * Closure for proc
+ */
+ void *proc_cls;
+
+};
+
+
+/**
+ * Linked list of things we still need to do.
+ */
+struct GNUNET_STATISTICS_GetHandle
+{
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct GNUNET_STATISTICS_GetHandle *next;
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct GNUNET_STATISTICS_GetHandle *prev;
+
+ /**
+ * Main statistics handle.
+ */
+ struct GNUNET_STATISTICS_Handle *sh;
+
+ /**
+ * What subsystem is this action about? (can be NULL)
+ */
+ char *subsystem;
+
+ /**
+ * What value is this action about? (can be NULL)
+ */
+ char *name;
+
+ /**
+ * Continuation to call once action is complete.
+ */
+ GNUNET_STATISTICS_Callback cont;
+
+ /**
+ * Function to call (for GET actions only).
+ */
+ GNUNET_STATISTICS_Iterator proc;
+
+ /**
+ * Closure for proc and cont.
+ */
+ void *cls;
+
+ /**
+ * Timeout for this action.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Associated value.
+ */
+ uint64_t value;
+
+ /**
+ * Flag for SET/UPDATE actions.
+ */
+ int make_persistent;
+
+ /**
+ * Has the current iteration been aborted; for GET actions.
+ */
+ int aborted;
+
+ /**
+ * Is this a GET, SET, UPDATE or WATCH?
+ */
+ enum ActionType type;
+
+ /**
+ * Size of the message that we will be transmitting.
+ */
+ uint16_t msize;
+
+};
+
+
+/**
+ * Handle for the service.
+ */
+struct GNUNET_STATISTICS_Handle
+{
+ /**
+ * Name of our subsystem.
+ */
+ char *subsystem;
+
+ /**
+ * Configuration to use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Socket (if available).
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Currently pending transmission request.
+ */
+ struct GNUNET_CLIENT_TransmitHandle *th;
+
+ /**
+ * Head of the linked list of pending actions (first action
+ * to be performed).
+ */
+ struct GNUNET_STATISTICS_GetHandle *action_head;
+
+ /**
+ * Tail of the linked list of actions (for fast append).
+ */
+ struct GNUNET_STATISTICS_GetHandle *action_tail;
+
+ /**
+ * Action we are currently busy with (action request has been
+ * transmitted, we're now receiving the response from the
+ * service).
+ */
+ struct GNUNET_STATISTICS_GetHandle *current;
+
+ /**
+ * Array of watch entries.
+ */
+ struct GNUNET_STATISTICS_WatchEntry **watches;
+
+ /**
+ * Task doing exponential back-off trying to reconnect.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier backoff_task;
+
+ /**
+ * Time for next connect retry.
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Size of the 'watches' array.
+ */
+ unsigned int watches_size;
+
+ /**
+ * Should this handle auto-destruct once all actions have
+ * been processed?
+ */
+ int do_destroy;
+
+ /**
+ * Are we currently receiving from the service?
+ */
+ int receiving;
+
+};
+
+
+/**
+ * Schedule the next action to be performed.
+ *
+ * @param h statistics handle to reconnect
+ */
+static void
+schedule_action (struct GNUNET_STATISTICS_Handle *h);
+
+
+/**
+ * Transmit request to service that we want to watch
+ * the development of a particular value.
+ *
+ * @param h statistics handle
+ * @param watch watch entry of the value to watch
+ */
+static void
+schedule_watch_request (struct GNUNET_STATISTICS_Handle *h,
+ struct GNUNET_STATISTICS_WatchEntry *watch)
+{
+
+ struct GNUNET_STATISTICS_GetHandle *ai;
+ size_t slen;
+ size_t nlen;
+ size_t nsize;
+
+ GNUNET_assert (h != NULL);
+ slen = strlen (watch->subsystem) + 1;
+ nlen = strlen (watch->name) + 1;
+ nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen;
+ if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
+ ai->sh = h;
+ ai->subsystem = GNUNET_strdup (watch->subsystem);
+ ai->name = GNUNET_strdup (watch->name);
+ ai->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
+ ai->msize = nsize;
+ ai->type = ACTION_WATCH;
+ ai->proc = watch->proc;
+ ai->cls = watch->proc_cls;
+ GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail,
+ ai);
+ schedule_action (h);
+}
+
+
+/**
+ * Free memory associated with the given action item.
+ *
+ * @param gh action item to free
+ */
+static void
+free_action_item (struct GNUNET_STATISTICS_GetHandle *gh)
+{
+ GNUNET_free_non_null (gh->subsystem);
+ GNUNET_free_non_null (gh->name);
+ GNUNET_free (gh);
+}
+
+
+/**
+ * Disconnect from the statistics service.
+ *
+ * @param h statistics handle to disconnect from
+ */
+static void
+do_disconnect (struct GNUNET_STATISTICS_Handle *h)
+{
+ struct GNUNET_STATISTICS_GetHandle *c;
+
+ if (NULL != h->th)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
+ h->th = NULL;
+ }
+ if (NULL != h->client)
+ {
+ GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
+ h->client = NULL;
+ }
+ h->receiving = GNUNET_NO;
+ if (NULL != (c = h->current))
+ {
+ h->current = NULL;
+ if (c->cont != NULL)
+ c->cont (c->cls, GNUNET_SYSERR);
+ free_action_item (c);
+ }
+}
+
+
+/**
+ * Try to (re)connect to the statistics service.
+ *
+ * @param h statistics handle to reconnect
+ * @return GNUNET_YES on success, GNUNET_NO on failure.
+ */
+static int
+try_connect (struct GNUNET_STATISTICS_Handle *h)
+{
+ struct GNUNET_STATISTICS_GetHandle *gh;
+ struct GNUNET_STATISTICS_GetHandle *gn;
+ unsigned int i;
+
+ if (h->backoff_task != GNUNET_SCHEDULER_NO_TASK)
+ return GNUNET_NO;
+ if (h->client != NULL)
+ return GNUNET_YES;
+ h->client = GNUNET_CLIENT_connect ("statistics", h->cfg);
+ if (h->client != NULL)
+ {
+ gn = h->action_head;
+ while (NULL != (gh = gn))
+ {
+ gn = gh->next;
+ if (gh->type == ACTION_WATCH)
+ {
+ GNUNET_CONTAINER_DLL_remove (h->action_head,
+ h->action_tail,
+ gh);
+ free_action_item (gh);
+ }
+ }
+ for (i = 0; i < h->watches_size; i++)
+ schedule_watch_request (h, h->watches[i]);
+ return GNUNET_YES;
+ }
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ _("Failed to connect to statistics service!\n"));
+#endif
+ return GNUNET_NO;
+}
+
+
+/**
+ * We've waited long enough, reconnect now.
+ *
+ * @param cls the 'struct GNUNET_STATISTICS_Handle' to reconnect
+ * @param tc scheduler context (unused)
+ */
+static void
+reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_STATISTICS_Handle *h = cls;
+
+ h->backoff_task = GNUNET_SCHEDULER_NO_TASK;
+ schedule_action (h);
+}
+
+
+/**
+ * Reconnect at a later time, respecting back-off.
+ *
+ * @param h statistics handle
+ */
+static void
+reconnect_later (struct GNUNET_STATISTICS_Handle *h)
+{
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->backoff_task);
+ h->backoff_task =
+ GNUNET_SCHEDULER_add_delayed (h->backoff, &reconnect_task, h);
+ h->backoff = GNUNET_TIME_relative_multiply (h->backoff, 2);
+ h->backoff =
+ GNUNET_TIME_relative_min (h->backoff, GNUNET_CONSTANTS_SERVICE_TIMEOUT);
+}
+
+
+/**
+ * Process a 'GNUNET_MESSAGE_TYPE_STATISTICS_VALUE' message.
+ *
+ * @param h statistics handle
+ * @param msg message received from the service, never NULL
+ * @return GNUNET_OK if the message was well-formed
+ */
+static int
+process_statistics_value_message (struct GNUNET_STATISTICS_Handle *h,
+ const struct GNUNET_MessageHeader *msg)
+{
+ char *service;
+ char *name;
+ const struct GNUNET_STATISTICS_ReplyMessage *smsg;
+ uint16_t size;
+
+ if (h->current->aborted)
+ {
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Iteration was aborted, ignoring VALUE\n");
+#endif
+ return GNUNET_OK; /* don't bother */
+ }
+ size = ntohs (msg->size);
+ if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ smsg = (const struct GNUNET_STATISTICS_ReplyMessage *) msg;
+ size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage);
+ if (size !=
+ GNUNET_STRINGS_buffer_tokenize ((const char *) &smsg[1], size, 2,
+ &service, &name))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received valid statistic on `%s:%s': %llu\n",
+ service, name, GNUNET_ntohll (smsg->value));
+#endif
+ if (GNUNET_OK !=
+ h->current->proc (h->current->cls, service, name,
+ GNUNET_ntohll (smsg->value),
+ 0 !=
+ (ntohl (smsg->uid) & GNUNET_STATISTICS_PERSIST_BIT)))
+ {
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Processing of remaining statistics aborted by client.\n");
+#endif
+ h->current->aborted = GNUNET_YES;
+ }
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "VALUE processed successfully\n");
+#endif
+ return GNUNET_OK;
+}
+
+
+/**
+ * We have received a watch value from the service. Process it.
+ *
+ * @param h statistics handle
+ * @param msg the watch value message
+ * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not,
+ * GNUNET_NO if this watch has been cancelled
+ */
+static int
+process_watch_value (struct GNUNET_STATISTICS_Handle *h,
+ const struct GNUNET_MessageHeader *msg)
+{
+ const struct GNUNET_STATISTICS_WatchValueMessage *wvm;
+ struct GNUNET_STATISTICS_WatchEntry *w;
+ uint32_t wid;
+
+ if (sizeof (struct GNUNET_STATISTICS_WatchValueMessage) != ntohs (msg->size))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ wvm = (const struct GNUNET_STATISTICS_WatchValueMessage *) msg;
+ GNUNET_break (0 == ntohl (wvm->reserved));
+ wid = ntohl (wvm->wid);
+ if (wid >= h->watches_size)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ w = h->watches[wid];
+ if (NULL == w)
+ return GNUNET_NO;
+ (void) w->proc (w->proc_cls, w->subsystem, w->name,
+ GNUNET_ntohll (wvm->value),
+ 0 != (ntohl (wvm->flags) & GNUNET_STATISTICS_PERSIST_BIT));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called with messages from stats service.
+ *
+ * @param cls closure
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_STATISTICS_Handle *h = cls;
+ struct GNUNET_STATISTICS_GetHandle *c;
+ int ret;
+
+ if (msg == NULL)
+ {
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Error receiving statistics from service, is the service running?\n");
+#endif
+ do_disconnect (h);
+ reconnect_later (h);
+ return;
+ }
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_STATISTICS_END:
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of statistics marker\n");
+#endif
+ if (NULL == (c = h->current))
+ {
+ GNUNET_break (0);
+ do_disconnect (h);
+ reconnect_later (h);
+ return;
+ }
+ h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+ if (h->watches_size > 0)
+ {
+ GNUNET_CLIENT_receive (h->client, &receive_stats, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ else
+ {
+ h->receiving = GNUNET_NO;
+ }
+ h->current = NULL;
+ schedule_action (h);
+ if (c->cont != NULL)
+ c->cont (c->cls, GNUNET_OK);
+ free_action_item (c);
+ return;
+ case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE:
+ if (GNUNET_OK != process_statistics_value_message (h, msg))
+ {
+ do_disconnect (h);
+ reconnect_later (h);
+ return;
+ }
+ /* finally, look for more! */
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Processing VALUE done, now reading more\n");
+#endif
+ GNUNET_CLIENT_receive (h->client, &receive_stats, h,
+ GNUNET_TIME_absolute_get_remaining (h->
+ current->timeout));
+ h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+ return;
+ case GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE:
+ if (GNUNET_OK !=
+ (ret = process_watch_value (h, msg)))
+ {
+ do_disconnect (h);
+ if (GNUNET_NO == ret)
+ h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+ reconnect_later (h);
+ return;
+ }
+ h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+ GNUNET_assert (h->watches_size > 0);
+ GNUNET_CLIENT_receive (h->client, &receive_stats, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ return;
+ default:
+ GNUNET_break (0);
+ do_disconnect (h);
+ reconnect_later (h);
+ return;
+ }
+}
+
+
+/**
+ * Transmit a GET request (and if successful, start to receive
+ * the response).
+ *
+ * @param handle statistics handle
+ * @param size how many bytes can we write to buf
+ * @param buf where to write requests to the service
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
+{
+ struct GNUNET_STATISTICS_GetHandle *c;
+ struct GNUNET_MessageHeader *hdr;
+ size_t slen1;
+ size_t slen2;
+ uint16_t msize;
+
+ GNUNET_assert (NULL != (c = handle->current));
+ if (buf == NULL)
+ {
+ /* timeout / error */
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission of request for statistics failed!\n");
+#endif
+ do_disconnect (handle);
+ reconnect_later (handle);
+ return 0;
+ }
+ slen1 = strlen (c->subsystem) + 1;
+ slen2 = strlen (c->name) + 1;
+ msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader);
+ GNUNET_assert (msize <= size);
+ hdr = (struct GNUNET_MessageHeader *) buf;
+ hdr->size = htons (msize);
+ hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_GET);
+ GNUNET_assert (slen1 + slen2 ==
+ GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2,
+ c->subsystem,
+ c->name));
+ if (GNUNET_YES != handle->receiving)
+ {
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission of GET done, now reading response\n");
+#endif
+ handle->receiving = GNUNET_YES;
+ GNUNET_CLIENT_receive (handle->client, &receive_stats, handle,
+ GNUNET_TIME_absolute_get_remaining (c->timeout));
+ }
+ return msize;
+}
+
+
+/**
+ * Transmit a WATCH request (and if successful, start to receive
+ * the response).
+ *
+ * @param handle statistics handle
+ * @param size how many bytes can we write to buf
+ * @param buf where to write requests to the service
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_watch (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *hdr;
+ size_t slen1;
+ size_t slen2;
+ uint16_t msize;
+
+ if (buf == NULL)
+ {
+ /* timeout / error */
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission of request for statistics failed!\n");
+#endif
+ do_disconnect (handle);
+ reconnect_later (handle);
+ return 0;
+ }
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting watch request for `%s'\n",
+ handle->current->name);
+#endif
+ slen1 = strlen (handle->current->subsystem) + 1;
+ slen2 = strlen (handle->current->name) + 1;
+ msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader);
+ GNUNET_assert (msize <= size);
+ hdr = (struct GNUNET_MessageHeader *) buf;
+ hdr->size = htons (msize);
+ hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH);
+ GNUNET_assert (slen1 + slen2 ==
+ GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2,
+ handle->current->subsystem,
+ handle->current->name));
+ if (GNUNET_YES != handle->receiving)
+ {
+ handle->receiving = GNUNET_YES;
+ GNUNET_CLIENT_receive (handle->client, &receive_stats, handle,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ GNUNET_assert (NULL == handle->current->cont);
+ free_action_item (handle->current);
+ handle->current = NULL;
+ return msize;
+}
+
+
+/**
+ * Transmit a SET/UPDATE request.
+ *
+ * @param handle statistics handle
+ * @param size how many bytes can we write to buf
+ * @param buf where to write requests to the service
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_set (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
+{
+ struct GNUNET_STATISTICS_SetMessage *r;
+ size_t slen;
+ size_t nlen;
+ size_t nsize;
+
+ if (NULL == buf)
+ {
+ do_disconnect (handle);
+ reconnect_later (handle);
+ return 0;
+ }
+ slen = strlen (handle->current->subsystem) + 1;
+ nlen = strlen (handle->current->name) + 1;
+ nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
+ if (size < nsize)
+ {
+ GNUNET_break (0);
+ do_disconnect (handle);
+ reconnect_later (handle);
+ return 0;
+ }
+ r = buf;
+ r->header.size = htons (nsize);
+ r->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET);
+ r->flags = 0;
+ r->value = GNUNET_htonll (handle->current->value);
+ if (handle->current->make_persistent)
+ r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_PERSISTENT);
+ if (handle->current->type == ACTION_UPDATE)
+ r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_RELATIVE);
+ GNUNET_assert (slen + nlen ==
+ GNUNET_STRINGS_buffer_fill ((char *) &r[1], slen + nlen, 2,
+ handle->current->subsystem,
+ handle->current->name));
+ GNUNET_assert (NULL == handle->current->cont);
+ free_action_item (handle->current);
+ handle->current = NULL;
+ return nsize;
+}
+
+
+/**
+ * Function called when we are ready to transmit a request to the service.
+ *
+ * @param cls the 'struct GNUNET_STATISTICS_Handle'
+ * @param size how many bytes can we write to buf
+ * @param buf where to write requests to the service
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_action (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_STATISTICS_Handle *h = cls;
+ size_t ret;
+
+ h->th = NULL;
+ ret = 0;
+ if (NULL != h->current)
+ switch (h->current->type)
+ {
+ case ACTION_GET:
+ ret = transmit_get (h, size, buf);
+ break;
+ case ACTION_SET:
+ case ACTION_UPDATE:
+ ret = transmit_set (h, size, buf);
+ break;
+ case ACTION_WATCH:
+ ret = transmit_watch (h, size, buf);
+ break;
+ default:
+ GNUNET_assert (0);
+ break;
+ }
+ schedule_action (h);
+ return ret;
+}
+
+
+/**
+ * Get handle for the statistics service.
+ *
+ * @param subsystem name of subsystem using the service
+ * @param cfg services configuration in use
+ * @return handle to use
+ */
+struct GNUNET_STATISTICS_Handle *
+GNUNET_STATISTICS_create (const char *subsystem,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct GNUNET_STATISTICS_Handle *ret;
+
+ GNUNET_assert (subsystem != NULL);
+ GNUNET_assert (cfg != NULL);
+ ret = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_Handle));
+ ret->cfg = cfg;
+ ret->subsystem = GNUNET_strdup (subsystem);
+ ret->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+ return ret;
+}
+
+
+/**
+ * Destroy a handle (free all state associated with
+ * it).
+ *
+ * @param h statistics handle to destroy
+ * @param sync_first set to GNUNET_YES if pending SET requests should
+ * be completed
+ */
+void
+GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
+{
+ struct GNUNET_STATISTICS_GetHandle *pos;
+ struct GNUNET_STATISTICS_GetHandle *next;
+ struct GNUNET_TIME_Relative timeout;
+ int i;
+
+ if (h == NULL)
+ return;
+ if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->backoff_task);
+ h->backoff_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (sync_first)
+ {
+ if (h->current != NULL)
+ {
+ if (h->current->type == ACTION_GET)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
+ h->th = NULL;
+ free_action_item (h->current);
+ h->current = NULL;
+ }
+ }
+ next = h->action_head;
+ while (NULL != (pos = next))
+ {
+ next = pos->next;
+ if (pos->type == ACTION_GET)
+ {
+ GNUNET_CONTAINER_DLL_remove (h->action_head,
+ h->action_tail,
+ pos);
+ free_action_item (pos);
+ }
+ }
+ if ( (NULL == h->current) &&
+ (NULL != (h->current = h->action_head)) )
+ GNUNET_CONTAINER_DLL_remove (h->action_head,
+ h->action_tail,
+ h->current);
+ h->do_destroy = GNUNET_YES;
+ if ((h->current != NULL) && (h->th == NULL))
+ {
+ if (NULL == h->client)
+ {
+ /* instant-connect (regardless of back-off) to submit final value */
+ h->client = GNUNET_CLIENT_connect ("statistics", h->cfg);
+ }
+ if (NULL != h->client)
+ {
+ timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout);
+ h->th =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize,
+ timeout, GNUNET_YES,
+ &transmit_action, h);
+ GNUNET_assert (NULL != h->th);
+ }
+ }
+ if (h->th != NULL)
+ return; /* do not finish destruction just yet */
+ }
+ while (NULL != (pos = h->action_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->action_head,
+ h->action_tail,
+ pos);
+ free_action_item (pos);
+ }
+ do_disconnect (h);
+ for (i = 0; i < h->watches_size; i++)
+ {
+ if (NULL == h->watches[i])
+ continue;
+ GNUNET_free (h->watches[i]->subsystem);
+ GNUNET_free (h->watches[i]->name);
+ GNUNET_free (h->watches[i]);
+ }
+ GNUNET_array_grow (h->watches, h->watches_size, 0);
+ GNUNET_free (h->subsystem);
+ GNUNET_free (h);
+}
+
+
+/**
+ * Schedule the next action to be performed.
+ *
+ * @param h statistics handle
+ */
+static void
+schedule_action (struct GNUNET_STATISTICS_Handle *h)
+{
+ struct GNUNET_TIME_Relative timeout;
+
+ if ( (h->th != NULL) ||
+ (h->backoff_task != GNUNET_SCHEDULER_NO_TASK) )
+ return; /* action already pending */
+ if (GNUNET_YES != try_connect (h))
+ {
+ reconnect_later (h);
+ return;
+ }
+ if (NULL != h->current)
+ return; /* action already pending */
+ /* schedule next action */
+ h->current = h->action_head;
+ if (NULL == h->current)
+ {
+ if (h->do_destroy)
+ {
+ h->do_destroy = GNUNET_NO;
+ GNUNET_STATISTICS_destroy (h, GNUNET_YES);
+ }
+ return;
+ }
+ GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, h->current);
+ timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout);
+ if (NULL ==
+ (h->th =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize,
+ timeout, GNUNET_YES,
+ &transmit_action, h)))
+ {
+#if DEBUG_STATISTICS
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to transmit request to statistics service.\n");
+#endif
+ do_disconnect (h);
+ reconnect_later (h);
+ }
+}
+
+
+/**
+ * Get statistic from the peer.
+ *
+ * @param handle identification of the statistics service
+ * @param subsystem limit to the specified subsystem, NULL for our subsystem
+ * @param name name of the statistic value, NULL for all values
+ * @param timeout after how long should we give up (and call
+ * cont with an error code)?
+ * @param cont continuation to call when done (can be NULL)
+ * @param proc function to call on each value
+ * @param cls closure for cont and proc
+ * @return NULL on error
+ */
+struct GNUNET_STATISTICS_GetHandle *
+GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle,
+ const char *subsystem, const char *name,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_STATISTICS_Callback cont,
+ GNUNET_STATISTICS_Iterator proc, void *cls)
+{
+ size_t slen1;
+ size_t slen2;
+ struct GNUNET_STATISTICS_GetHandle *ai;
+
+ if (NULL == handle)
+ return NULL;
+ GNUNET_assert (proc != NULL);
+ GNUNET_assert (GNUNET_NO == handle->do_destroy);
+ if (subsystem == NULL)
+ subsystem = "";
+ if (name == NULL)
+ name = "";
+ slen1 = strlen (subsystem) + 1;
+ slen2 = strlen (name) + 1;
+ GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) <
+ GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
+ ai->sh = handle;
+ ai->subsystem = GNUNET_strdup (subsystem);
+ ai->name = GNUNET_strdup (name);
+ ai->cont = cont;
+ ai->proc = proc;
+ ai->cls = cls;
+ ai->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ ai->type = ACTION_GET;
+ ai->msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader);
+ GNUNET_CONTAINER_DLL_insert_tail (handle->action_head, handle->action_tail,
+ ai);
+ schedule_action (handle);
+ return ai;
+}
+
+
+/**
+ * Cancel a 'get' request. Must be called before the 'cont'
+ * function is called.
+ *
+ * @param gh handle of the request to cancel
+ */
+void
+GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh)
+{
+ if (NULL == gh)
+ return;
+ if (gh->sh->current == gh)
+ {
+ gh->aborted = GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_CONTAINER_DLL_remove (gh->sh->action_head, gh->sh->action_tail, gh);
+ GNUNET_free (gh->name);
+ GNUNET_free (gh->subsystem);
+ GNUNET_free (gh);
+ }
+}
+
+
+/**
+ * Watch statistics from the peer (be notified whenever they change).
+ *
+ * @param handle identification of the statistics service
+ * @param subsystem limit to the specified subsystem, never NULL
+ * @param name name of the statistic value, never NULL
+ * @param proc function to call on each value
+ * @param proc_cls closure for proc
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle,
+ const char *subsystem, const char *name,
+ GNUNET_STATISTICS_Iterator proc, void *proc_cls)
+{
+ struct GNUNET_STATISTICS_WatchEntry *w;
+
+ if (handle == NULL)
+ return GNUNET_SYSERR;
+ w = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_WatchEntry));
+ w->subsystem = GNUNET_strdup (subsystem);
+ w->name = GNUNET_strdup (name);
+ w->proc = proc;
+ w->proc_cls = proc_cls;
+ GNUNET_array_append (handle->watches, handle->watches_size, w);
+ schedule_watch_request (handle, w);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Stop watching statistics from the peer.
+ *
+ * @param handle identification of the statistics service
+ * @param subsystem limit to the specified subsystem, never NULL
+ * @param name name of the statistic value, never NULL
+ * @param proc function to call on each value
+ * @param proc_cls closure for proc
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error (no such watch)
+ */
+int
+GNUNET_STATISTICS_watch_cancel (struct GNUNET_STATISTICS_Handle *handle,
+ const char *subsystem, const char *name,
+ GNUNET_STATISTICS_Iterator proc, void *proc_cls)
+{
+ struct GNUNET_STATISTICS_WatchEntry *w;
+ unsigned int i;
+
+ if (handle == NULL)
+ return GNUNET_SYSERR;
+ for (i=0;i<handle->watches_size;i++)
+ {
+ w = handle->watches[i];
+ if ( (w->proc == proc) &&
+ (w->proc_cls == proc_cls) &&
+ (0 == strcmp (w->name, name)) &&
+ (0 == strcmp (w->subsystem, subsystem)) )
+ {
+ GNUNET_free (w->name);
+ GNUNET_free (w->subsystem);
+ GNUNET_free (w);
+ handle->watches[i] = NULL;
+ return GNUNET_OK;
+ }
+ }
+ return GNUNET_SYSERR;
+}
+
+
+
+/**
+ * Queue a request to change a statistic.
+ *
+ * @param h statistics handle
+ * @param name name of the value
+ * @param make_persistent should the value be kept across restarts?
+ * @param value new value or change
+ * @param type type of the action (ACTION_SET or ACTION_UPDATE)
+ */
+static void
+add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name,
+ int make_persistent, uint64_t value, enum ActionType type)
+{
+ struct GNUNET_STATISTICS_GetHandle *ai;
+ size_t slen;
+ size_t nlen;
+ size_t nsize;
+ int64_t delta;
+
+ GNUNET_assert (h != NULL);
+ GNUNET_assert (name != NULL);
+ slen = strlen (h->subsystem) + 1;
+ nlen = strlen (name) + 1;
+ nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
+ if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ for (ai = h->action_head; ai != NULL; ai = ai->next)
+ {
+ if (! ( (0 == strcmp (ai->subsystem, h->subsystem)) &&
+ (0 == strcmp (ai->name, name)) &&
+ ( (ai->type == ACTION_UPDATE) ||
+ (ai->type == ACTION_SET) ) ) )
+ continue;
+ if (ai->type == ACTION_SET)
+ {
+ if (type == ACTION_UPDATE)
+ {
+ delta = (int64_t) value;
+ if (delta > 0)
+ {
+ /* update old set by new delta */
+ ai->value += delta;
+ }
+ else
+ {
+ /* update old set by new delta, but never go negative */
+ if (ai->value < -delta)
+ ai->value = 0;
+ else
+ ai->value += delta;
+ }
+ }
+ else
+ {
+ /* new set overrides old set */
+ ai->value = value;
+ }
+ }
+ else
+ {
+ if (type == ACTION_UPDATE)
+ {
+ /* make delta cummulative */
+ delta = (int64_t) value;
+ ai->value += delta;
+ }
+ else
+ {
+ /* drop old 'update', use new 'set' instead */
+ ai->value = value;
+ ai->type = type;
+ }
+ }
+ ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT);
+ ai->make_persistent = make_persistent;
+ return;
+ }
+ /* no existing entry matches, create a fresh one */
+ ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
+ ai->sh = h;
+ ai->subsystem = GNUNET_strdup (h->subsystem);
+ ai->name = GNUNET_strdup (name);
+ ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT);
+ ai->make_persistent = make_persistent;
+ ai->msize = nsize;
+ ai->value = value;
+ ai->type = type;
+ GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail,
+ ai);
+ schedule_action (h);
+}
+
+
+/**
+ * Set statistic value for the peer. Will always use our
+ * subsystem (the argument used when "handle" was created).
+ *
+ * @param handle identification of the statistics service
+ * @param name name of the statistic value
+ * @param value new value to set
+ * @param make_persistent should the value be kept across restarts?
+ */
+void
+GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle,
+ const char *name, uint64_t value, int make_persistent)
+{
+ if (handle == NULL)
+ return;
+ GNUNET_assert (GNUNET_NO == handle->do_destroy);
+ add_setter_action (handle, name, make_persistent, value, ACTION_SET);
+}
+
+
+/**
+ * Set statistic value for the peer. Will always use our
+ * subsystem (the argument used when "handle" was created).
+ *
+ * @param handle identification of the statistics service
+ * @param name name of the statistic value
+ * @param delta change in value (added to existing value)
+ * @param make_persistent should the value be kept across restarts?
+ */
+void
+GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle,
+ const char *name, int64_t delta, int make_persistent)
+{
+ if (handle == NULL)
+ return;
+ if (delta == 0)
+ return;
+ GNUNET_assert (GNUNET_NO == handle->do_destroy);
+ add_setter_action (handle, name, make_persistent, (uint64_t) delta,
+ ACTION_UPDATE);
+}
+
+
+/* end of statistics_api.c */
diff --git a/src/statistics/test_gnunet_statistics.sh b/src/statistics/test_gnunet_statistics.sh
new file mode 100755
index 0000000..eb2d618
--- /dev/null
+++ b/src/statistics/test_gnunet_statistics.sh
@@ -0,0 +1,199 @@
+#!/bin/sh
+
+rm -rf /tmp/test-gnunetd-statistics/
+exe="./gnunet-statistics -c test_statistics_api_data.conf"
+out=`mktemp /tmp/test-gnunet-statistics-logXXXXXXXX`
+arm="gnunet-arm -c test_statistics_api_data.conf $DEBUG"
+#DEBUG="-L DEBUG"
+# -----------------------------------
+echo -n "Preparing: Starting service..."
+
+$arm -s > /dev/null
+sleep 1
+$arm -i statistics > /dev/null
+sleep 1
+echo "DONE"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: Bad argument checking..."
+
+if $exe -x 2> /dev/null; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: Set value..."
+
+if ! $exe $DEBUG -n test -s subsystem 42 ; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: Set another value..."
+
+if ! $exe $DEBUG -n other -s osystem 43 ; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: viewing all stats..."
+
+if ! $exe $DEBUG > $out; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+LINES=`cat $out | wc -l`
+if test $LINES -ne 2; then
+ echo "FAIL: unexpected output"
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: viewing stats by name..."
+
+if ! $exe $DEBUG -n other > $out; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+LINES=`cat $out | grep 43 | wc -l`
+if test $LINES -ne 1; then
+ echo "FAIL: unexpected output"
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: viewing stats by subsystem..."
+
+if ! $exe $DEBUG -s subsystem > $out; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+LINES=`cat $out | grep 42 | wc -l`
+if test $LINES -ne 1; then
+ echo "FAIL: unexpected output"
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: Set persistent value..."
+
+if ! $exe $DEBUG -n lasting -s subsystem 40 -p; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+if ! $exe $DEBUG > $out; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+LINES=`cat $out | grep 40 | wc -l`
+if test $LINES -ne 1; then
+ echo "FAIL: unexpected output"
+ cat $out
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+# -----------------------------------
+echo -n "Restarting service..."
+$arm -k statistics > /dev/null
+sleep 1
+$arm -i statistics > /dev/null
+sleep 1
+echo "DONE"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: checking persistence..."
+
+if ! $exe $DEBUG > $out; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+LINES=`cat $out | grep 40 | wc -l`
+if test $LINES -ne 1; then
+ echo "FAIL: unexpected output"
+ cat $out
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: Removing persistence..."
+
+if ! $exe $DEBUG -n lasting -s subsystem 40; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+if ! $exe $DEBUG > $out; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+LINES=`cat $out | grep \! | wc -l`
+if test $LINES -ne 0; then
+ echo "FAIL: unexpected output"
+ cat $out
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+
+# -----------------------------------
+echo -n "Restarting service..."
+$arm -k statistics > /dev/null
+sleep 1
+$arm -i statistics > /dev/null
+sleep 1
+echo "DONE"
+
+# ----------------------------------------------------------------------------------
+echo -n "TEST: checking removed persistence..."
+
+if ! $exe $DEBUG > $out; then
+ echo "FAIL: error running $exe"
+ $arm -e
+ exit 1
+fi
+LINES=`cat $out | grep 40 | wc -l`
+if test $LINES -ne 0; then
+ echo "FAIL: unexpected output"
+ cat $out
+ $arm -e
+ exit 1
+fi
+echo "PASS"
+
+# -----------------------------------
+echo -n "Stopping service..."
+$arm -e > /dev/null
+sleep 1
+echo "DONE"
+rm -f $out
+rm -rf /tmp/test-gnunetd-statistics/
diff --git a/src/statistics/test_statistics_api.c b/src/statistics/test_statistics_api.c
new file mode 100644
index 0000000..0647a49
--- /dev/null
+++ b/src/statistics/test_statistics_api.c
@@ -0,0 +1,212 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file statistics/test_statistics_api.c
+ * @brief testcase for statistics_api.c
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_statistics_service.h"
+
+#define DEBUG_STATISTICS GNUNET_EXTRA_LOGGING
+
+#define START_SERVICE GNUNET_YES
+
+static int
+check_1 (void *cls, const char *subsystem, const char *name, uint64_t value,
+ int is_persistent)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n",
+ (unsigned long long) value, subsystem, name);
+ GNUNET_assert (0 == strcmp (name, "test-1"));
+ GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api"));
+ GNUNET_assert (value == 1);
+ GNUNET_assert (is_persistent == GNUNET_NO);
+ return GNUNET_OK;
+}
+
+static int
+check_2 (void *cls, const char *subsystem, const char *name, uint64_t value,
+ int is_persistent)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n",
+ (unsigned long long) value, subsystem, name);
+ GNUNET_assert (0 == strcmp (name, "test-2"));
+ GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api"));
+ GNUNET_assert (value == 2);
+ GNUNET_assert (is_persistent == GNUNET_NO);
+ return GNUNET_OK;
+}
+
+static int
+check_3 (void *cls, const char *subsystem, const char *name, uint64_t value,
+ int is_persistent)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n",
+ (unsigned long long) value, subsystem, name);
+ GNUNET_assert (0 == strcmp (name, "test-3"));
+ GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api"));
+ GNUNET_assert (value == 3);
+ GNUNET_assert (is_persistent == GNUNET_YES);
+ return GNUNET_OK;
+}
+
+static struct GNUNET_STATISTICS_Handle *h;
+
+static void
+next_fin (void *cls, int success)
+{
+ int *ok = cls;
+
+ GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+ GNUNET_assert (success == GNUNET_OK);
+ *ok = 0;
+}
+
+static void
+next (void *cls, int success)
+{
+ GNUNET_assert (success == GNUNET_OK);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing GET request\n");
+ GNUNET_break (NULL !=
+ GNUNET_STATISTICS_get (h, NULL, "test-2",
+ GNUNET_TIME_UNIT_SECONDS, &next_fin,
+ &check_2, cls));
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ h = GNUNET_STATISTICS_create ("test-statistics-api", cfg);
+ GNUNET_STATISTICS_set (h, "test-1", 1, GNUNET_NO);
+ GNUNET_STATISTICS_set (h, "test-2", 2, GNUNET_NO);
+ GNUNET_STATISTICS_set (h, "test-3", 2, GNUNET_NO);
+ GNUNET_STATISTICS_update (h, "test-3", 1, GNUNET_YES);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing GET request\n");
+ GNUNET_break (NULL !=
+ GNUNET_STATISTICS_get (h, NULL, "test-1",
+ GNUNET_TIME_UNIT_SECONDS, &next,
+ &check_1, cls));
+}
+
+static void
+run_more (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ h = GNUNET_STATISTICS_create ("test-statistics-api", cfg);
+ GNUNET_break (NULL !=
+ GNUNET_STATISTICS_get (h, NULL, "test-3",
+ GNUNET_TIME_UNIT_SECONDS, &next_fin,
+ &check_3, cls));
+}
+
+static int
+check ()
+{
+ int ok = 1;
+
+ char *const argv[] = { "test-statistics-api",
+ "-c",
+ "test_statistics_api_data.conf",
+#if DEBUG_STATISTICS
+ "-L", "DEBUG",
+#else
+ "-L", "WARNING",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+#if START_SERVICE
+ struct GNUNET_OS_Process *proc;
+
+ proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics",
+ "gnunet-service-statistics",
+#if DEBUG_STATISTICS
+ "-L", "DEBUG",
+#endif
+ "-c", "test_statistics_api_data.conf", NULL);
+#endif
+ GNUNET_assert (NULL != proc);
+ GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", options, &run,
+ &ok);
+#if START_SERVICE
+ if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ ok = 1;
+ }
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_close (proc);
+ proc = NULL;
+#endif
+ if (ok != 0)
+ return ok;
+ ok = 1;
+#if START_SERVICE
+ /* restart to check persistence! */
+ proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics",
+ "gnunet-service-statistics",
+#if DEBUG_STATISTICS
+ "-L", "DEBUG",
+#endif
+ "-c", "test_statistics_api_data.conf", NULL);
+#endif
+ GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", options,
+ &run_more, &ok);
+#if START_SERVICE
+ if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ ok = 1;
+ }
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_close (proc);
+ proc = NULL;
+#endif
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_log_setup ("test_statistics_api",
+#if DEBUG_STATISTICS
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+
+ return ret;
+}
+
+/* end of test_statistics_api.c */
diff --git a/src/statistics/test_statistics_api_data.conf b/src/statistics/test_statistics_api_data.conf
new file mode 100644
index 0000000..9ccb770
--- /dev/null
+++ b/src/statistics/test_statistics_api_data.conf
@@ -0,0 +1,43 @@
+[PATHS]
+SERVICEHOME = /tmp/test-gnunetd-statistics/
+DEFAULTCONFIG = test_statistics_api_data.conf
+
+[statistics]
+PORT = 22353
+UNIXPATH = /tmp/test-statistics-service-statistics.unix
+#DEBUG = YES
+
+[arm]
+PORT = 22354
+DEFAULTSERVICES =
+UNIXPATH = /tmp/test-statistics-service-arm.unix
+# DEBUG = YES
+
+[fs]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[transport]
+AUTOSTART = NO
+
+[core]
+AUTOSTART = NO
+
+[peerinfo]
+AUTOSTART = NO
+
+
+[dns]
+AUTOSTART = NO
+
+
+
+[nse]
+AUTOSTART = NO
+
+
diff --git a/src/statistics/test_statistics_api_loop.c b/src/statistics/test_statistics_api_loop.c
new file mode 100644
index 0000000..32b176c
--- /dev/null
+++ b/src/statistics/test_statistics_api_loop.c
@@ -0,0 +1,133 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file statistics/test_statistics_api_loop.c
+ * @brief testcase for statistics_api.c
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_statistics_service.h"
+
+#define VERBOSE GNUNET_NO
+
+#define START_SERVICE GNUNET_YES
+
+#define ROUNDS (1024 * 1024)
+
+static int
+check_1 (void *cls, const char *subsystem, const char *name, uint64_t value,
+ int is_persistent)
+{
+ GNUNET_assert (0 == strcmp (name, "test-0"));
+ GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api-loop"));
+ GNUNET_assert (is_persistent == GNUNET_NO);
+ return GNUNET_OK;
+}
+
+static struct GNUNET_STATISTICS_Handle *h;
+
+static void
+next (void *cls, int success)
+{
+ int *ok = cls;
+
+ GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+ GNUNET_assert (success == GNUNET_OK);
+ *ok = 0;
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ int i;
+ char name[128];
+
+ h = GNUNET_STATISTICS_create ("test-statistics-api-loop", cfg);
+ for (i = 0; i < ROUNDS; i++)
+ {
+ GNUNET_snprintf (name, sizeof (name), "test-%d", i % 256);
+ GNUNET_STATISTICS_set (h, name, i, GNUNET_NO);
+ GNUNET_snprintf (name, sizeof (name), "test-%d", i % 128);
+ GNUNET_STATISTICS_update (h, name, 1, GNUNET_NO);
+ }
+ i = 0;
+ GNUNET_break (NULL !=
+ GNUNET_STATISTICS_get (h, NULL, "test-0",
+ GNUNET_TIME_UNIT_MINUTES, &next,
+ &check_1, cls));
+}
+
+
+static int
+check ()
+{
+ int ok = 1;
+
+ char *const argv[] = { "test-statistics-api",
+ "-c",
+ "test_statistics_api_data.conf",
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+#if START_SERVICE
+ struct GNUNET_OS_Process *proc;
+
+ proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics",
+ "gnunet-service-statistics",
+#if DEBUG_STATISTICS
+ "-L", "DEBUG",
+#endif
+ "-c", "test_statistics_api_data.conf", NULL);
+#endif
+ GNUNET_assert (NULL != proc);
+ GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", options, &run,
+ &ok);
+#if START_SERVICE
+ if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ ok = 1;
+ }
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_close (proc);
+ proc = NULL;
+#endif
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ ret = check ();
+
+ return ret;
+}
+
+/* end of test_statistics_api_loop.c */
diff --git a/src/statistics/test_statistics_api_watch.c b/src/statistics/test_statistics_api_watch.c
new file mode 100644
index 0000000..979b561
--- /dev/null
+++ b/src/statistics/test_statistics_api_watch.c
@@ -0,0 +1,164 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file statistics/test_statistics_api_watch.c
+ * @brief testcase for statistics_api.c watch functions
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_statistics_service.h"
+
+#define VERBOSE GNUNET_NO
+
+#define START_SERVICE GNUNET_YES
+
+static int ok;
+
+static struct GNUNET_STATISTICS_Handle *h;
+
+static struct GNUNET_STATISTICS_Handle *h2;
+
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+
+static void
+force_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ fprintf (stderr, "Timeout, failed to receive notifications: %d\n", ok);
+ GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+ GNUNET_STATISTICS_destroy (h2, GNUNET_NO);
+ ok = 7;
+}
+
+
+static void
+normal_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+ GNUNET_STATISTICS_destroy (h2, GNUNET_NO);
+}
+
+
+static int
+watch_1 (void *cls, const char *subsystem, const char *name, uint64_t value,
+ int is_persistent)
+{
+ GNUNET_assert (value == 42);
+ GNUNET_assert (0 == strcmp (name, "test-1"));
+ ok &= ~1;
+ if (0 == ok)
+ {
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL);
+ }
+ return GNUNET_OK;
+}
+
+
+static int
+watch_2 (void *cls, const char *subsystem, const char *name, uint64_t value,
+ int is_persistent)
+{
+ GNUNET_assert (value == 43);
+ GNUNET_assert (0 == strcmp (name, "test-2"));
+ ok &= ~2;
+ if (0 == ok)
+ {
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL);
+ }
+ return GNUNET_OK;
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ h = GNUNET_STATISTICS_create ("dummy", cfg);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_STATISTICS_watch (h, "test-statistics-api-watch",
+ "test-1", &watch_1, NULL));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_STATISTICS_watch (h, "test-statistics-api-watch",
+ "test-2", &watch_2, NULL));
+ h2 = GNUNET_STATISTICS_create ("test-statistics-api-watch", cfg);
+ GNUNET_STATISTICS_set (h2, "test-1", 42, GNUNET_NO);
+ GNUNET_STATISTICS_set (h2, "test-2", 43, GNUNET_NO);
+ shutdown_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &force_shutdown,
+ NULL);
+}
+
+
+static int
+check ()
+{
+ char *const argv[] = { "test-statistics-api",
+ "-c",
+ "test_statistics_api_data.conf",
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+#if START_SERVICE
+ struct GNUNET_OS_Process *proc;
+
+ proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics",
+ "gnunet-service-statistics",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ "-c", "test_statistics_api_data.conf", NULL);
+#endif
+ GNUNET_assert (NULL != proc);
+ ok = 3;
+ GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", options, &run,
+ NULL);
+#if START_SERVICE
+ if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ ok = 1;
+ }
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_close (proc);
+ proc = NULL;
+#endif
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ ret = check ();
+
+ return ret;
+}
+
+/* end of test_statistics_api_watch.c */