summaryrefslogtreecommitdiff
path: root/src/hostlist
diff options
context:
space:
mode:
authorBertrand Marc <beberking@gmail.com>2012-05-02 21:43:37 +0200
committerBertrand Marc <beberking@gmail.com>2012-05-02 21:43:37 +0200
commit2b81464a43485fcc8ce079fafdee7b7a171835f4 (patch)
tree394774c0f735199b57d51a2d3840356317853fe1 /src/hostlist
Imported Upstream version 0.9.2upstream/0.9.2
Diffstat (limited to 'src/hostlist')
-rw-r--r--src/hostlist/Makefile.am81
-rw-r--r--src/hostlist/Makefile.in949
-rw-r--r--src/hostlist/gnunet-daemon-hostlist.c347
-rw-r--r--src/hostlist/gnunet-daemon-hostlist.h47
-rw-r--r--src/hostlist/hostlist-client.c1568
-rw-r--r--src/hostlist/hostlist-client.h108
-rw-r--r--src/hostlist/hostlist-server.c700
-rw-r--r--src/hostlist/hostlist-server.h58
-rw-r--r--src/hostlist/hostlist.conf14
-rw-r--r--src/hostlist/learning_data.conf14
-rw-r--r--src/hostlist/test_gnunet_daemon_hostlist.c255
-rw-r--r--src/hostlist/test_gnunet_daemon_hostlist_data.conf29
-rw-r--r--src/hostlist/test_gnunet_daemon_hostlist_learning.c533
-rw-r--r--src/hostlist/test_gnunet_daemon_hostlist_peer1.conf43
-rw-r--r--src/hostlist/test_gnunet_daemon_hostlist_peer2.conf43
-rw-r--r--src/hostlist/test_gnunet_daemon_hostlist_reconnect.c266
-rw-r--r--src/hostlist/test_hostlist_defaults.conf62
-rw-r--r--src/hostlist/test_learning_adv_peer.conf47
-rw-r--r--src/hostlist/test_learning_learn_peer.conf46
-rw-r--r--src/hostlist/test_learning_learn_peer2.conf39
20 files changed, 5249 insertions, 0 deletions
diff --git a/src/hostlist/Makefile.am b/src/hostlist/Makefile.am
new file mode 100644
index 0000000..f764f2f
--- /dev/null
+++ b/src/hostlist/Makefile.am
@@ -0,0 +1,81 @@
+INCLUDES = -I$(top_srcdir)/src/include
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+dist_pkgcfg_DATA = \
+ hostlist.conf
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+endif
+
+if HAVE_MHD
+ HOSTLIST_SERVER_SOURCES = hostlist-server.c hostlist-server.h
+ GN_LIBMHD = -lmicrohttpd
+endif
+
+bin_PROGRAMS = \
+ gnunet-daemon-hostlist
+
+gnunet_daemon_hostlist_SOURCES = \
+ gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \
+ hostlist-client.c hostlist-client.h \
+ $(HOSTLIST_SERVER_SOURCES)
+
+gnunet_daemon_hostlist_LDADD = \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBMHD) \
+ @LIBCURL@ \
+ $(GN_LIBINTL)
+
+gnunet_daemon_hostlist_CPPFLAGS = \
+ @LIBCURL_CPPFLAGS@
+
+check_PROGRAMS = \
+ test_gnunet_daemon_hostlist \
+ test_gnunet_daemon_hostlist_reconnect \
+ test_gnunet_daemon_hostlist_learning
+
+if HAVE_MHD
+if ENABLE_TEST_RUN
+TESTS = \
+ test_gnunet_daemon_hostlist \
+ test_gnunet_daemon_hostlist_reconnect \
+ test_gnunet_daemon_hostlist_learning
+endif
+endif
+
+test_gnunet_daemon_hostlist_SOURCES = \
+ test_gnunet_daemon_hostlist.c
+test_gnunet_daemon_hostlist_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_gnunet_daemon_hostlist_reconnect_SOURCES = \
+ test_gnunet_daemon_hostlist_reconnect.c
+test_gnunet_daemon_hostlist_reconnect_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_gnunet_daemon_hostlist_learning_SOURCES = \
+ test_gnunet_daemon_hostlist_learning.c
+test_gnunet_daemon_hostlist_learning_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+EXTRA_DIST = \
+ test_hostlist_defaults.conf \
+ test_gnunet_daemon_hostlist_data.conf \
+ test_gnunet_daemon_hostlist_peer1.conf \
+ test_gnunet_daemon_hostlist_peer2.conf \
+ test_learning_adv_peer.conf \
+ test_learning_learn_peer.conf \
+ test_learning_learn_peer2.conf \
+ learning_data.conf
diff --git a/src/hostlist/Makefile.in b/src/hostlist/Makefile.in
new file mode 100644
index 0000000..737e87c
--- /dev/null
+++ b/src/hostlist/Makefile.in
@@ -0,0 +1,949 @@
+# 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-daemon-hostlist$(EXEEXT)
+check_PROGRAMS = test_gnunet_daemon_hostlist$(EXEEXT) \
+ test_gnunet_daemon_hostlist_reconnect$(EXEEXT) \
+ test_gnunet_daemon_hostlist_learning$(EXEEXT)
+@ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@TESTS = test_gnunet_daemon_hostlist$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@ test_gnunet_daemon_hostlist_reconnect$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@ test_gnunet_daemon_hostlist_learning$(EXEEXT)
+subdir = src/hostlist
+DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.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 =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"
+PROGRAMS = $(bin_PROGRAMS)
+am__gnunet_daemon_hostlist_SOURCES_DIST = gnunet-daemon-hostlist.c \
+ gnunet-daemon-hostlist.h hostlist-client.c hostlist-client.h \
+ hostlist-server.c hostlist-server.h
+@HAVE_MHD_TRUE@am__objects_1 = gnunet_daemon_hostlist-hostlist-server.$(OBJEXT)
+am_gnunet_daemon_hostlist_OBJECTS = \
+ gnunet_daemon_hostlist-gnunet-daemon-hostlist.$(OBJEXT) \
+ gnunet_daemon_hostlist-hostlist-client.$(OBJEXT) \
+ $(am__objects_1)
+gnunet_daemon_hostlist_OBJECTS = $(am_gnunet_daemon_hostlist_OBJECTS)
+am__DEPENDENCIES_1 =
+gnunet_daemon_hostlist_DEPENDENCIES = \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+am_test_gnunet_daemon_hostlist_OBJECTS = \
+ test_gnunet_daemon_hostlist.$(OBJEXT)
+test_gnunet_daemon_hostlist_OBJECTS = \
+ $(am_test_gnunet_daemon_hostlist_OBJECTS)
+test_gnunet_daemon_hostlist_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_test_gnunet_daemon_hostlist_learning_OBJECTS = \
+ test_gnunet_daemon_hostlist_learning.$(OBJEXT)
+test_gnunet_daemon_hostlist_learning_OBJECTS = \
+ $(am_test_gnunet_daemon_hostlist_learning_OBJECTS)
+test_gnunet_daemon_hostlist_learning_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_test_gnunet_daemon_hostlist_reconnect_OBJECTS = \
+ test_gnunet_daemon_hostlist_reconnect.$(OBJEXT)
+test_gnunet_daemon_hostlist_reconnect_OBJECTS = \
+ $(am_test_gnunet_daemon_hostlist_reconnect_OBJECTS)
+test_gnunet_daemon_hostlist_reconnect_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.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 = $(gnunet_daemon_hostlist_SOURCES) \
+ $(test_gnunet_daemon_hostlist_SOURCES) \
+ $(test_gnunet_daemon_hostlist_learning_SOURCES) \
+ $(test_gnunet_daemon_hostlist_reconnect_SOURCES)
+DIST_SOURCES = $(am__gnunet_daemon_hostlist_SOURCES_DIST) \
+ $(test_gnunet_daemon_hostlist_SOURCES) \
+ $(test_gnunet_daemon_hostlist_learning_SOURCES) \
+ $(test_gnunet_daemon_hostlist_reconnect_SOURCES)
+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'
+DATA = $(dist_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
+pkgcfgdir = $(pkgdatadir)/config.d/
+dist_pkgcfg_DATA = \
+ hostlist.conf
+
+@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0
+@HAVE_MHD_TRUE@HOSTLIST_SERVER_SOURCES = hostlist-server.c hostlist-server.h
+@HAVE_MHD_TRUE@GN_LIBMHD = -lmicrohttpd
+gnunet_daemon_hostlist_SOURCES = \
+ gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \
+ hostlist-client.c hostlist-client.h \
+ $(HOSTLIST_SERVER_SOURCES)
+
+gnunet_daemon_hostlist_LDADD = \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBMHD) \
+ @LIBCURL@ \
+ $(GN_LIBINTL)
+
+gnunet_daemon_hostlist_CPPFLAGS = \
+ @LIBCURL_CPPFLAGS@
+
+test_gnunet_daemon_hostlist_SOURCES = \
+ test_gnunet_daemon_hostlist.c
+
+test_gnunet_daemon_hostlist_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_gnunet_daemon_hostlist_reconnect_SOURCES = \
+ test_gnunet_daemon_hostlist_reconnect.c
+
+test_gnunet_daemon_hostlist_reconnect_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+test_gnunet_daemon_hostlist_learning_SOURCES = \
+ test_gnunet_daemon_hostlist_learning.c
+
+test_gnunet_daemon_hostlist_learning_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+EXTRA_DIST = \
+ test_hostlist_defaults.conf \
+ test_gnunet_daemon_hostlist_data.conf \
+ test_gnunet_daemon_hostlist_peer1.conf \
+ test_gnunet_daemon_hostlist_peer2.conf \
+ test_learning_adv_peer.conf \
+ test_learning_learn_peer.conf \
+ test_learning_learn_peer2.conf \
+ learning_data.conf
+
+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/hostlist/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/hostlist/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):
+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-daemon-hostlist$(EXEEXT): $(gnunet_daemon_hostlist_OBJECTS) $(gnunet_daemon_hostlist_DEPENDENCIES)
+ @rm -f gnunet-daemon-hostlist$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_daemon_hostlist_OBJECTS) $(gnunet_daemon_hostlist_LDADD) $(LIBS)
+test_gnunet_daemon_hostlist$(EXEEXT): $(test_gnunet_daemon_hostlist_OBJECTS) $(test_gnunet_daemon_hostlist_DEPENDENCIES)
+ @rm -f test_gnunet_daemon_hostlist$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_OBJECTS) $(test_gnunet_daemon_hostlist_LDADD) $(LIBS)
+test_gnunet_daemon_hostlist_learning$(EXEEXT): $(test_gnunet_daemon_hostlist_learning_OBJECTS) $(test_gnunet_daemon_hostlist_learning_DEPENDENCIES)
+ @rm -f test_gnunet_daemon_hostlist_learning$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_learning_OBJECTS) $(test_gnunet_daemon_hostlist_learning_LDADD) $(LIBS)
+test_gnunet_daemon_hostlist_reconnect$(EXEEXT): $(test_gnunet_daemon_hostlist_reconnect_OBJECTS) $(test_gnunet_daemon_hostlist_reconnect_DEPENDENCIES)
+ @rm -f test_gnunet_daemon_hostlist_reconnect$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_reconnect_OBJECTS) $(test_gnunet_daemon_hostlist_reconnect_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist_learning.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist_reconnect.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 $@ $<
+
+gnunet_daemon_hostlist-gnunet-daemon-hostlist.o: gnunet-daemon-hostlist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-gnunet-daemon-hostlist.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.o `test -f 'gnunet-daemon-hostlist.c' || echo '$(srcdir)/'`gnunet-daemon-hostlist.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-daemon-hostlist.c' object='gnunet_daemon_hostlist-gnunet-daemon-hostlist.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.o `test -f 'gnunet-daemon-hostlist.c' || echo '$(srcdir)/'`gnunet-daemon-hostlist.c
+
+gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj: gnunet-daemon-hostlist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj `if test -f 'gnunet-daemon-hostlist.c'; then $(CYGPATH_W) 'gnunet-daemon-hostlist.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-daemon-hostlist.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-daemon-hostlist.c' object='gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj `if test -f 'gnunet-daemon-hostlist.c'; then $(CYGPATH_W) 'gnunet-daemon-hostlist.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-daemon-hostlist.c'; fi`
+
+gnunet_daemon_hostlist-hostlist-client.o: hostlist-client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-client.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo -c -o gnunet_daemon_hostlist-hostlist-client.o `test -f 'hostlist-client.c' || echo '$(srcdir)/'`hostlist-client.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-client.c' object='gnunet_daemon_hostlist-hostlist-client.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-client.o `test -f 'hostlist-client.c' || echo '$(srcdir)/'`hostlist-client.c
+
+gnunet_daemon_hostlist-hostlist-client.obj: hostlist-client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-client.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo -c -o gnunet_daemon_hostlist-hostlist-client.obj `if test -f 'hostlist-client.c'; then $(CYGPATH_W) 'hostlist-client.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-client.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-client.c' object='gnunet_daemon_hostlist-hostlist-client.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-client.obj `if test -f 'hostlist-client.c'; then $(CYGPATH_W) 'hostlist-client.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-client.c'; fi`
+
+gnunet_daemon_hostlist-hostlist-server.o: hostlist-server.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-server.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo -c -o gnunet_daemon_hostlist-hostlist-server.o `test -f 'hostlist-server.c' || echo '$(srcdir)/'`hostlist-server.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-server.c' object='gnunet_daemon_hostlist-hostlist-server.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-server.o `test -f 'hostlist-server.c' || echo '$(srcdir)/'`hostlist-server.c
+
+gnunet_daemon_hostlist-hostlist-server.obj: hostlist-server.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-server.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo -c -o gnunet_daemon_hostlist-hostlist-server.obj `if test -f 'hostlist-server.c'; then $(CYGPATH_W) 'hostlist-server.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-server.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-server.c' object='gnunet_daemon_hostlist-hostlist-server.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-server.obj `if test -f 'hostlist-server.c'; then $(CYGPATH_W) 'hostlist-server.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-server.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)"
+ @list='$(dist_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-dist_pkgcfgDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_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)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(PROGRAMS) $(DATA)
+installdirs:
+ for dir in "$(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-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-dist_pkgcfgDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+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-dist_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-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-dist_pkgcfgDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am 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-dist_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/hostlist/gnunet-daemon-hostlist.c b/src/hostlist/gnunet-daemon-hostlist.c
new file mode 100644
index 0000000..0eedb56
--- /dev/null
+++ b/src/hostlist/gnunet-daemon-hostlist.c
@@ -0,0 +1,347 @@
+/*
+ This file is part of GNUnet.
+ (C) 2007, 2008, 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 hostlist/gnunet-daemon-hostlist.c
+ * @brief code for bootstrapping via hostlist servers
+ * @author Christian Grothoff
+ */
+
+#include <stdlib.h>
+#include "platform.h"
+#include "hostlist-client.h"
+#include "gnunet_core_service.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_strings_lib.h"
+#include "gnunet_time_lib.h"
+#include "gnunet_util_lib.h"
+
+#if HAVE_MHD
+
+#include "hostlist-server.h"
+
+/**
+ * Set if we are allowed to advertise our hostlist to others.
+ */
+static int advertising;
+
+/**
+ * Set if the user wants us to run a hostlist server.
+ */
+static int provide_hostlist;
+
+/**
+ * Handle to hostlist server's connect handler
+ */
+static GNUNET_CORE_ConnectEventHandler server_ch;
+
+/**
+ * Handle to hostlist server's disconnect handler
+ */
+static GNUNET_CORE_DisconnectEventHandler server_dh;
+
+#endif
+
+/**
+ * Set if we are allowed to learn about peers by accessing
+ * hostlist servers.
+ */
+static int bootstrapping;
+
+/**
+ * Set if the user allows us to learn about new hostlists
+ * from the network.
+ */
+static int learning;
+
+/**
+ * Statistics handle.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to the core service (NULL until we've connected to it).
+ */
+static struct GNUNET_CORE_Handle *core;
+
+/**
+ * Handle to the hostlist client's advertisement handler
+ */
+static GNUNET_CORE_MessageCallback client_adv_handler;
+
+/**
+ * Handle to hostlist client's connect handler
+ */
+static GNUNET_CORE_ConnectEventHandler client_ch;
+
+/**
+ * Handle to hostlist client's disconnect handler
+ */
+static GNUNET_CORE_DisconnectEventHandler client_dh;
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * A HOSTLIST_ADV message is used to exchange information about
+ * hostlist advertisements. This struct is always
+ * followed by the actual url under which the hostlist can be obtained:
+ *
+ * 1) transport-name (0-terminated)
+ * 2) address-length (uint32_t, network byte order; possibly
+ * unaligned!)
+ * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
+ * unaligned!)
+ * 4) address (address-length bytes; possibly unaligned!)
+ */
+struct GNUNET_HOSTLIST_ADV_Message
+{
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Always zero (for alignment).
+ */
+ uint32_t reserved GNUNET_PACKED;
+};
+GNUNET_NETWORK_STRUCT_END
+
+static struct GNUNET_PeerIdentity me;
+
+static void
+core_init (void *cls, struct GNUNET_CORE_Handle *server,
+ const struct GNUNET_PeerIdentity *my_identity)
+{
+ me = *my_identity;
+}
+
+/**
+ * Core handler for p2p hostlist advertisements
+ *
+ * @param cls closure
+ * @param peer identity of the sender
+ * @param message advertisement message we got
+ * @param atsi performance information
+ * @param atsi_count number of records in 'atsi'
+ * @return GNUNET_OK on success
+ */
+static int
+advertisement_handler (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ GNUNET_assert (NULL != client_adv_handler);
+ return (*client_adv_handler) (cls, peer, message, atsi, atsi_count);
+}
+
+
+/**
+ * Method called whenever a given peer connects. Wrapper to call both client's and server's functions
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ * @param atsi performance data
+ * @param atsi_count number of records in 'atsi'
+ */
+static void
+connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity)))
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "A new peer connected, notifying client and server\n");
+ if (NULL != client_ch)
+ (*client_ch) (cls, peer, atsi, atsi_count);
+#if HAVE_MHD
+ if (NULL != server_ch)
+ (*server_ch) (cls, peer, atsi, atsi_count);
+#endif
+}
+
+/**
+ * Method called whenever a given peer disconnects. Wrapper to call both client's and server's functions
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity)))
+ return;
+ /* call hostlist client disconnect handler */
+ if (NULL != client_dh)
+ (*client_dh) (cls, peer);
+#if HAVE_MHD
+ /* call hostlist server disconnect handler */
+ if (NULL != server_dh)
+ (*server_dh) (cls, peer);
+#endif
+}
+
+/**
+ * Last task run during shutdown. Disconnects us from
+ * the other services.
+ */
+static void
+cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist daemon is shutting down\n");
+ if (core != NULL)
+ {
+ GNUNET_CORE_disconnect (core);
+ core = NULL;
+ }
+ if (bootstrapping)
+ {
+ GNUNET_HOSTLIST_client_stop ();
+ }
+#if HAVE_MHD
+ if (provide_hostlist)
+ {
+ GNUNET_HOSTLIST_server_stop ();
+ }
+#endif
+ if (stats != NULL)
+ {
+ GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
+ stats = NULL;
+ }
+}
+
+
+/**
+ * Main function that will be run.
+ *
+ * @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)
+{
+ static const struct GNUNET_CORE_MessageHandler learn_handlers[] = {
+ {&advertisement_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0},
+ {NULL, 0, 0}
+ };
+ static const struct GNUNET_CORE_MessageHandler no_learn_handlers[] = {
+ {NULL, 0, 0}
+ };
+ if ((!bootstrapping) && (!learning)
+#if HAVE_MHD
+ && (!provide_hostlist)
+#endif
+ )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("None of the functions for the hostlist daemon were enabled. I have no reason to run!\n"));
+ return;
+ }
+
+
+
+ stats = GNUNET_STATISTICS_create ("hostlist", cfg);
+
+ core =
+ GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_handler,
+ &disconnect_handler, NULL, GNUNET_NO, NULL,
+ GNUNET_NO,
+ learning ? learn_handlers : no_learn_handlers);
+
+ if (bootstrapping)
+ {
+ GNUNET_HOSTLIST_client_start (cfg, stats, &client_ch, &client_dh,
+ &client_adv_handler, learning);
+ }
+
+#if HAVE_MHD
+ if (provide_hostlist)
+ {
+ GNUNET_HOSTLIST_server_start (cfg, stats, core, &server_ch, &server_dh,
+ advertising);
+ }
+#endif
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task,
+ NULL);
+
+ if (NULL == core)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to connect to `%s' service.\n"), "core");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+}
+
+
+/**
+ * The main function for the hostlist daemon.
+ *
+ * @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[] = {
+#if HAVE_MHD
+ {'a', "advertise", NULL,
+ gettext_noop ("advertise our hostlist to other peers"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising},
+#endif
+ {'b', "bootstrap", NULL,
+ gettext_noop
+ ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping},
+ {'e', "enable-learning", NULL,
+ gettext_noop ("enable learning about hostlist servers from other peers"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &learning},
+#if HAVE_MHD
+ {'p', "provide-hostlist", NULL,
+ gettext_noop ("provide a hostlist server"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist},
+#endif
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ int ret;
+
+ GNUNET_log_setup ("hostlist", "WARNING", NULL);
+ ret =
+ (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc, argv, "hostlist",
+ _("GNUnet hostlist server and client"), options,
+ &run, NULL)) ? 0 : 1;
+
+ return ret;
+}
+
+/* end of gnunet-daemon-hostlist.c */
diff --git a/src/hostlist/gnunet-daemon-hostlist.h b/src/hostlist/gnunet-daemon-hostlist.h
new file mode 100644
index 0000000..8c9824e
--- /dev/null
+++ b/src/hostlist/gnunet-daemon-hostlist.h
@@ -0,0 +1,47 @@
+/*
+ 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 hostlist/gnunet-daemon-hostlist.h
+ * @brief common internal definitions for hostlist daemon
+ * @author Matthias Wachs
+ */
+#include <stdlib.h>
+#include "platform.h"
+#include "hostlist-client.h"
+#include "hostlist-server.h"
+#include "gnunet_core_service.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_strings_lib.h"
+#include "gnunet_time_lib.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * General hostlist daemon debugging.
+ */
+#define DEBUG_HOSTLIST GNUNET_EXTRA_LOGGING
+
+#define MAX_URL_LEN 1000
+#define MAX_BYTES_PER_HOSTLISTS 500000
+
+/* end of gnunet-daemon-hostlist.h */
diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c
new file mode 100644
index 0000000..350a0ba
--- /dev/null
+++ b/src/hostlist/hostlist-client.c
@@ -0,0 +1,1568 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 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 hostlist/hostlist-client.c
+ * @brief hostlist support. Downloads HELLOs via HTTP.
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+ */
+
+#include "platform.h"
+#include "hostlist-client.h"
+#include "gnunet_core_service.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet-daemon-hostlist.h"
+#include <curl/curl.h>
+#include "gnunet_common.h"
+#include "gnunet_bio_lib.h"
+
+#define DEBUG_HOSTLIST_CLIENT GNUNET_EXTRA_LOGGING
+
+
+/**
+ * Number of connections that we must have to NOT download
+ * hostlists anymore.
+ */
+#define MIN_CONNECTIONS 4
+
+/**
+ * Interval between two advertised hostlist tests
+ */
+#define TESTING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+/**
+ * A single hostlist obtained by hostlist advertisements
+ */
+struct Hostlist
+{
+ /**
+ * previous entry, used to manage entries in a double linked list
+ */
+ struct Hostlist *prev;
+
+ /**
+ * next entry, used to manage entries in a double linked list
+ */
+ struct Hostlist *next;
+
+ /**
+ * URI where hostlist can be obtained
+ */
+ const char *hostlist_uri;
+
+ /**
+ * Value describing the quality of the hostlist, the bigger the better but (should) never < 0
+ * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached
+ * intial value = HOSTLIST_INITIAL
+ * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD
+ * increased every successful download by number of obtained HELLO messages
+ * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD
+ */
+ uint64_t quality;
+
+ /**
+ * Time the hostlist advertisement was recieved and the entry was created
+ */
+ struct GNUNET_TIME_Absolute time_creation;
+
+ /**
+ * Last time the hostlist was obtained
+ */
+ struct GNUNET_TIME_Absolute time_last_usage;
+
+ /**
+ * Number of HELLO messages obtained during last download
+ */
+ uint32_t hello_count;
+
+ /**
+ * Number of times the hostlist was successfully obtained
+ */
+ uint32_t times_used;
+
+};
+
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Statistics handle.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Transport handle.
+ */
+static struct GNUNET_TRANSPORT_Handle *transport;
+
+/**
+ * Proxy that we are using (can be NULL).
+ */
+static char *proxy;
+
+/**
+ * Number of bytes valid in 'download_buffer'.
+ */
+static size_t download_pos;
+
+/**
+ * Current URL that we are using.
+ */
+static char *current_url;
+
+/**
+ * Current CURL handle.
+ */
+static CURL *curl;
+
+/**
+ * Current multi-CURL handle.
+ */
+static CURLM *multi;
+
+/**
+ * How many bytes did we download from the current hostlist URL?
+ */
+static uint32_t stat_bytes_downloaded;
+
+/**
+ * Amount of time we wait between hostlist downloads.
+ */
+static struct GNUNET_TIME_Relative hostlist_delay;
+
+/**
+ * ID of the task, checking if hostlist download should take plate
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ti_check_download;
+
+/**
+ * ID of the task downloading the hostlist
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ti_download;
+
+/**
+ * ID of the task saving the hostlsit in a regular intervall
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ti_saving_task;
+
+/**
+ * ID of the task called to initiate a download
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ti_download_dispatcher_task;
+
+/**
+ * ID of the task controlling the locking between two hostlist tests
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ti_testing_intervall_task;
+
+/**
+ * At what time MUST the current hostlist request be done?
+ */
+static struct GNUNET_TIME_Absolute end_time;
+
+/**
+ * Head of the linked list used to store hostlists
+ */
+static struct Hostlist *linked_list_head;
+
+/**
+ * Tail of the linked list used to store hostlists
+ */
+static struct Hostlist *linked_list_tail;
+
+/**
+ * Current hostlist used for downloading
+ */
+static struct Hostlist *current_hostlist;
+
+/**
+ * Size of the linke list used to store hostlists
+ */
+static unsigned int linked_list_size;
+
+/**
+ * Head of the linked list used to store hostlists
+ */
+static struct Hostlist *hostlist_to_test;
+
+/**
+ * Set to GNUNET_YES if the current URL had some problems.
+ */
+static int stat_bogus_url;
+
+/**
+ * Value controlling if a hostlist is tested at the moment
+ */
+static int stat_testing_hostlist;
+
+/**
+ * Value controlling if a hostlist testing is allowed at the moment
+ */
+static int stat_testing_allowed;
+
+/**
+ * Value controlling if a hostlist download is running at the moment
+ */
+static int stat_download_in_progress;
+
+/**
+ * Value saying if a preconfigured bootstrap server is used
+ */
+static unsigned int stat_use_bootstrap;
+
+/**
+ * Set if we are allowed to learn new hostlists and use them
+ */
+static int stat_learning;
+
+/**
+ * Value saying if hostlist download was successful
+ */
+static unsigned int stat_download_successful;
+
+/**
+ * Value saying how many valid HELLO messages were obtained during download
+ */
+static unsigned int stat_hellos_obtained;
+
+/**
+ * Number of active connections (according to core service).
+ */
+static unsigned int stat_connection_count;
+
+
+/**
+ * Process downloaded bits by calling callback on each HELLO.
+ *
+ * @param ptr buffer with downloaded data
+ * @param size size of a record
+ * @param nmemb number of records downloaded
+ * @param ctx unused
+ * @return number of bytes that were processed (always size*nmemb)
+ */
+static size_t
+callback_download (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ const char *cbuf = ptr;
+ const struct GNUNET_MessageHeader *msg;
+ size_t total;
+ size_t cpy;
+ size_t left;
+ uint16_t msize;
+
+ total = size * nmemb;
+ stat_bytes_downloaded += total;
+ if ((total == 0) || (stat_bogus_url))
+ {
+ return total; /* ok, no data or bogus data */
+ }
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# bytes downloaded from hostlist servers"),
+ (int64_t) total, GNUNET_NO);
+ left = total;
+ while ((left > 0) || (download_pos > 0))
+ {
+ cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos);
+ memcpy (&download_buffer[download_pos], cbuf, cpy);
+ cbuf += cpy;
+ download_pos += cpy;
+ left -= cpy;
+ if (download_pos < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_assert (left == 0);
+ break;
+ }
+ msg = (const struct GNUNET_MessageHeader *) download_buffer;
+ msize = ntohs (msg->size);
+ if (msize < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# invalid HELLOs downloaded from hostlist servers"),
+ 1, GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Invalid `%s' message received from hostlist at `%s'\n"),
+ "HELLO", current_url);
+ stat_hellos_obtained++;
+ stat_bogus_url = 1;
+ return total;
+ }
+ if (download_pos < msize)
+ {
+ GNUNET_assert (left == 0);
+ break;
+ }
+ if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) msg) == msize)
+ {
+#if DEBUG_HOSTLIST_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received valid `%s' message from hostlist server.\n",
+ "HELLO");
+#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# valid HELLOs downloaded from hostlist servers"),
+ 1, GNUNET_NO);
+ stat_hellos_obtained++;
+ GNUNET_TRANSPORT_offer_hello (transport, msg, NULL, NULL);
+ }
+ else
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# invalid HELLOs downloaded from hostlist servers"),
+ 1, GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Invalid `%s' message received from hostlist at `%s'\n"),
+ "HELLO", current_url);
+ stat_bogus_url = GNUNET_YES;
+ stat_hellos_obtained++;
+ return total;
+ }
+ memmove (download_buffer, &download_buffer[msize], download_pos - msize);
+ download_pos -= msize;
+ }
+ return total;
+}
+
+
+/**
+ * Obtain a hostlist URL that we should use.
+ *
+ * @return NULL if there is no URL available
+ */
+static char *
+get_bootstrap_server ()
+{
+ char *servers;
+ char *ret;
+ size_t urls;
+ size_t pos;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "SERVERS",
+ &servers))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
+ "SERVERS", "HOSTLIST");
+ return NULL;
+ }
+
+ urls = 0;
+ if (strlen (servers) > 0)
+ {
+ urls++;
+ pos = strlen (servers) - 1;
+ while (pos > 0)
+ {
+ if (servers[pos] == ' ')
+ urls++;
+ pos--;
+ }
+ }
+ if (urls == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
+ "SERVERS", "HOSTLIST");
+ GNUNET_free (servers);
+ return NULL;
+ }
+
+ urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1;
+ pos = strlen (servers) - 1;
+ while (pos > 0)
+ {
+ if (servers[pos] == ' ')
+ {
+ urls--;
+ servers[pos] = '\0';
+ }
+ if (urls == 0)
+ {
+ pos++;
+ break;
+ }
+ pos--;
+ }
+ ret = GNUNET_strdup (&servers[pos]);
+ GNUNET_free (servers);
+ return ret;
+}
+
+/**
+ * Method deciding if a preconfigured or advertisied hostlist is used on a 50:50 ratio
+ * @return uri to use, NULL if there is no URL available
+ */
+static char *
+download_get_url ()
+{
+ uint32_t index;
+ unsigned int counter;
+ struct Hostlist *pos;
+
+ if (GNUNET_NO == stat_learning)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Using preconfigured bootstrap server\n");
+ current_hostlist = NULL;
+ return get_bootstrap_server ();
+ }
+
+ if ((GNUNET_YES == stat_testing_hostlist) && (NULL != hostlist_to_test))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Testing new advertised hostlist if it is obtainable\n");
+ current_hostlist = hostlist_to_test;
+ return GNUNET_strdup (hostlist_to_test->hostlist_uri);
+ }
+
+ if ((GNUNET_YES == stat_use_bootstrap) || (linked_list_size == 0))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Using preconfigured bootstrap server\n");
+ current_hostlist = NULL;
+ return get_bootstrap_server ();
+ }
+ index =
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size);
+ counter = 0;
+ pos = linked_list_head;
+ while (counter < index)
+ {
+ pos = pos->next;
+ counter++;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using learned hostlist `%s'\n",
+ pos->hostlist_uri);
+ current_hostlist = pos;
+ return GNUNET_strdup (pos->hostlist_uri);
+}
+
+
+#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0)
+
+
+/**
+ * Method to save hostlist to a file during hostlist client shutdown
+ * @param shutdown set if called because of shutdown, entries in linked list will be destroyed
+ */
+static void
+save_hostlist_file (int shutdown);
+
+
+/**
+ * add val2 to val1 with overflow check
+ * @param val1 value 1
+ * @param val2 value 2
+ * @return result
+ */
+static uint64_t
+checked_add (uint64_t val1, uint64_t val2)
+{
+ static uint64_t temp;
+ static uint64_t maxv;
+
+ maxv = 0;
+ maxv--;
+
+ temp = val1 + val2;
+ if (temp < val1)
+ return maxv;
+ else
+ return temp;
+}
+
+/**
+ * Subtract val2 from val1 with underflow check
+ * @param val1 value 1
+ * @param val2 value 2
+ * @return result
+ */
+static uint64_t
+checked_sub (uint64_t val1, uint64_t val2)
+{
+ if (val1 <= val2)
+ return 0;
+ else
+ return (val1 - val2);
+}
+
+/**
+ * Method to check if a URI is in hostlist linked list
+ * @param uri uri to check
+ * @return GNUNET_YES if existing in linked list, GNUNET_NO if not
+ */
+static int
+linked_list_contains (const char *uri)
+{
+ struct Hostlist *pos;
+
+ pos = linked_list_head;
+ while (pos != NULL)
+ {
+ if (0 == strcmp (pos->hostlist_uri, uri))
+ return GNUNET_YES;
+ pos = pos->next;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Method returning the hostlist element with the lowest quality in the datastore
+ * @return hostlist with lowest quality
+ */
+static struct Hostlist *
+linked_list_get_lowest_quality ()
+{
+ struct Hostlist *pos;
+ struct Hostlist *lowest;
+
+ if (linked_list_size == 0)
+ return NULL;
+ lowest = linked_list_head;
+ pos = linked_list_head->next;
+ while (pos != NULL)
+ {
+ if (pos->quality < lowest->quality)
+ lowest = pos;
+ pos = pos->next;
+ }
+ return lowest;
+}
+
+
+/**
+ * Method to insert a hostlist into the datastore. If datastore
+ * contains maximum number of elements, the elements with lowest
+ * quality is dismissed
+ */
+static void
+insert_hostlist ()
+{
+ struct Hostlist *lowest_quality;
+
+ if (MAX_NUMBER_HOSTLISTS <= linked_list_size)
+ {
+ /* No free entries available, replace existing entry */
+ lowest_quality = linked_list_get_lowest_quality ();
+ GNUNET_assert (lowest_quality != NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing hostlist with URI `%s' which has the worst quality of all (%llu)\n",
+ lowest_quality->hostlist_uri,
+ (unsigned long long) lowest_quality->quality);
+ GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail,
+ lowest_quality);
+ linked_list_size--;
+ GNUNET_free (lowest_quality);
+ }
+ GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail,
+ hostlist_to_test);
+ linked_list_size++;
+ GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"),
+ linked_list_size, GNUNET_NO);
+ stat_testing_hostlist = GNUNET_NO;
+}
+
+
+/**
+ * Method updating hostlist statistics
+ */
+static void
+update_hostlist ()
+{
+ char *stat;
+
+ if (((stat_use_bootstrap == GNUNET_NO) && (NULL != current_hostlist)) ||
+ ((stat_testing_hostlist == GNUNET_YES) && (NULL != current_hostlist)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Updating hostlist statics for URI `%s'\n",
+ current_hostlist->hostlist_uri);
+ current_hostlist->hello_count = stat_hellos_obtained;
+ current_hostlist->time_last_usage = GNUNET_TIME_absolute_get ();
+ current_hostlist->quality =
+ checked_add (current_hostlist->quality,
+ (stat_hellos_obtained * HOSTLIST_SUCCESSFUL_HELLO));
+ if (GNUNET_YES == stat_download_successful)
+ {
+ current_hostlist->times_used++;
+ current_hostlist->quality =
+ checked_add (current_hostlist->quality, HOSTLIST_SUCCESSFUL_DOWNLOAD);
+ GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"),
+ current_hostlist->hostlist_uri);
+
+ GNUNET_STATISTICS_update (stats, stat, 1, GNUNET_YES);
+ GNUNET_free (stat);
+ }
+ else
+ current_hostlist->quality =
+ checked_sub (current_hostlist->quality, HOSTLIST_FAILED_DOWNLOAD);
+ }
+ current_hostlist = NULL;
+ /* Alternating the usage of preconfigured and learned hostlists */
+
+ if (stat_testing_hostlist == GNUNET_YES)
+ return;
+
+ if (GNUNET_YES == stat_learning)
+ {
+ if (stat_use_bootstrap == GNUNET_YES)
+ stat_use_bootstrap = GNUNET_NO;
+ else
+ stat_use_bootstrap = GNUNET_YES;
+ }
+ else
+ stat_use_bootstrap = GNUNET_YES;
+}
+
+/**
+ * Clean up the state from the task that downloaded the
+ * hostlist and schedule the next task.
+ */
+static void
+clean_up ()
+{
+ CURLMcode mret;
+
+ if ((stat_testing_hostlist == GNUNET_YES) &&
+ (GNUNET_NO == stat_download_successful) && (NULL != hostlist_to_test))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Advertised hostlist with URI `%s' could not be downloaded. Advertised URI gets dismissed.\n"),
+ hostlist_to_test->hostlist_uri);
+ }
+
+ if (stat_testing_hostlist == GNUNET_YES)
+ {
+ stat_testing_hostlist = GNUNET_NO;
+ }
+ if (NULL != hostlist_to_test)
+ {
+ GNUNET_free (hostlist_to_test);
+ hostlist_to_test = NULL;
+ }
+
+ if (multi != NULL)
+ {
+ mret = curl_multi_remove_handle (multi, curl);
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_remove_handle", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ }
+ mret = curl_multi_cleanup (multi);
+ if (mret != CURLM_OK)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_cleanup", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ multi = NULL;
+ }
+ if (curl != NULL)
+ {
+ curl_easy_cleanup (curl);
+ curl = NULL;
+ }
+ GNUNET_free_non_null (current_url);
+ current_url = NULL;
+ stat_bytes_downloaded = 0;
+ stat_download_in_progress = GNUNET_NO;
+}
+
+
+/**
+ * Task that is run when we are ready to receive more data from the hostlist
+ * server.
+ *
+ * @param cls closure, unused
+ * @param tc task context, unused
+ */
+static void
+task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Ask CURL for the select set and then schedule the
+ * receiving task with the scheduler.
+ */
+static void
+download_prepare ()
+{
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ int max;
+ struct GNUNET_NETWORK_FDSet *grs;
+ struct GNUNET_NETWORK_FDSet *gws;
+ long timeout;
+ struct GNUNET_TIME_Relative rtime;
+
+ max = -1;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_fdset", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ clean_up ();
+ return;
+ }
+ mret = curl_multi_timeout (multi, &timeout);
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_timeout", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ clean_up ();
+ return;
+ }
+ rtime =
+ GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time),
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MILLISECONDS, timeout));
+ grs = GNUNET_NETWORK_fdset_create ();
+ gws = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
+#if DEBUG_HOSTLIST_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Scheduling task for hostlist download using cURL\n");
+#endif
+ ti_download =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK, rtime, grs, gws,
+ &task_download, multi);
+ GNUNET_NETWORK_fdset_destroy (gws);
+ GNUNET_NETWORK_fdset_destroy (grs);
+}
+
+
+/**
+ * Task that is run when we are ready to receive more data from the hostlist
+ * server.
+ *
+ * @param cls closure, unused
+ * @param tc task context, unused
+ */
+static void
+task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ int running;
+ struct CURLMsg *msg;
+ CURLMcode mret;
+
+ ti_download = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ {
+#if DEBUG_HOSTLIST_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Shutdown requested while trying to download hostlist from `%s'\n",
+ current_url);
+#endif
+ update_hostlist ();
+ clean_up ();
+ return;
+ }
+ if (GNUNET_TIME_absolute_get_remaining (end_time).rel_value == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Timeout trying to download hostlist from `%s'\n"),
+ current_url);
+ update_hostlist ();
+ clean_up ();
+ return;
+ }
+#if DEBUG_HOSTLIST_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Ready for processing hostlist client request\n");
+#endif
+
+ do
+ {
+ running = 0;
+ if (stat_bytes_downloaded > MAX_BYTES_PER_HOSTLISTS)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Download limit of %u bytes exceeded, stopping download\n"),
+ MAX_BYTES_PER_HOSTLISTS);
+ clean_up ();
+ return;
+ }
+ mret = curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ do
+ {
+ msg = curl_multi_info_read (multi, &running);
+ GNUNET_break (msg != NULL);
+ if (msg == NULL)
+ break;
+ switch (msg->msg)
+ {
+ case CURLMSG_DONE:
+ if ((msg->data.result != CURLE_OK) &&
+ (msg->data.result != CURLE_GOT_NOTHING))
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("%s failed for `%s' at %s:%d: `%s'\n"),
+ "curl_multi_perform", current_url, __FILE__, __LINE__,
+ curl_easy_strerror (msg->data.result));
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Download of hostlist `%s' completed.\n"),
+ current_url);
+ stat_download_successful = GNUNET_YES;
+ update_hostlist ();
+ if (GNUNET_YES == stat_testing_hostlist)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Adding successfully tested hostlist `%s' datastore.\n"),
+ current_url);
+ insert_hostlist ();
+ hostlist_to_test = NULL;
+ stat_testing_hostlist = GNUNET_NO;
+ }
+ }
+ clean_up ();
+ return;
+ default:
+ break;
+ }
+
+ }
+ while ((running > 0));
+ }
+ }
+ while (mret == CURLM_CALL_MULTI_PERFORM);
+
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_perform", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ clean_up ();
+ }
+ download_prepare ();
+}
+
+
+/**
+ * Main function that will download a hostlist and process its
+ * data.
+ */
+static void
+download_hostlist ()
+{
+ CURLcode ret;
+ CURLMcode mret;
+
+
+ current_url = download_get_url ();
+ if (current_url == NULL)
+ return;
+ curl = curl_easy_init ();
+ multi = NULL;
+ if (curl == NULL)
+ {
+ GNUNET_break (0);
+ clean_up ();
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+ _("Bootstrapping using hostlist at `%s'.\n"), current_url);
+
+ stat_download_in_progress = GNUNET_YES;
+ stat_download_successful = GNUNET_NO;
+ stat_hellos_obtained = 0;
+ stat_bytes_downloaded = 0;
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# hostlist downloads initiated"), 1,
+ GNUNET_NO);
+ if (proxy != NULL)
+ CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy);
+ download_pos = 0;
+ stat_bogus_url = 0;
+ CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &callback_download);
+ if (ret != CURLE_OK)
+ {
+ clean_up ();
+ return;
+ }
+ CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, NULL);
+ if (ret != CURLE_OK)
+ {
+ clean_up ();
+ return;
+ }
+ CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1);
+ CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4);
+ /* no need to abort if the above failed */
+ CURL_EASY_SETOPT (curl, CURLOPT_URL, current_url);
+ if (ret != CURLE_OK)
+ {
+ clean_up ();
+ return;
+ }
+ CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1);
+#if 0
+ CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1);
+#endif
+ CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ if (0 == strncmp (current_url, "http", 4))
+ CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
+ CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L);
+ CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 60L);
+#if 0
+ /* this should no longer be needed; we're now single-threaded! */
+ CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1);
+#endif
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ GNUNET_break (0);
+ /* clean_up (); */
+ return;
+ }
+ mret = curl_multi_add_handle (multi, curl);
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_add_handle", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ mret = curl_multi_cleanup (multi);
+ if (mret != CURLM_OK)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_cleanup", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ multi = NULL;
+ clean_up ();
+ return;
+ }
+ end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
+ download_prepare ();
+}
+
+
+static void
+task_download_dispatcher (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download is initiated...\n");
+ if (GNUNET_NO == stat_download_in_progress)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download can start immediately...\n");
+ download_hostlist ();
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Download in progess, have to wait...\n");
+ ti_download_dispatcher_task =
+ GNUNET_SCHEDULER_add_delayed (WAITING_INTERVALL,
+ &task_download_dispatcher, NULL);
+ }
+}
+
+/**
+ * Task that checks if we should try to download a hostlist.
+ * If so, we initiate the download, otherwise we schedule
+ * this task again for a later time.
+ */
+static void
+task_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ static int once;
+ struct GNUNET_TIME_Relative delay;
+
+ ti_check_download = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ if (stat_connection_count < MIN_CONNECTIONS)
+ {
+ ti_download_dispatcher_task =
+ GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL);
+ }
+
+ if (stats == NULL)
+ {
+ curl_global_cleanup ();
+ return; /* in shutdown */
+ }
+ delay = hostlist_delay;
+ if (hostlist_delay.rel_value == 0)
+ hostlist_delay = GNUNET_TIME_UNIT_SECONDS;
+ else
+ hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2);
+ if (hostlist_delay.rel_value >
+ GNUNET_TIME_UNIT_HOURS.rel_value * (1 + stat_connection_count))
+ hostlist_delay =
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
+ (1 + stat_connection_count));
+ GNUNET_STATISTICS_set (stats,
+ gettext_noop
+ ("# milliseconds between hostlist downloads"),
+ hostlist_delay.rel_value, GNUNET_YES);
+ if (0 == once)
+ {
+ delay = GNUNET_TIME_UNIT_ZERO;
+ once = 1;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Have %u/%u connections. Will consider downloading hostlist in %llums\n"),
+ stat_connection_count, MIN_CONNECTIONS,
+ (unsigned long long) delay.rel_value);
+ ti_check_download = GNUNET_SCHEDULER_add_delayed (delay, &task_check, NULL);
+}
+
+
+/**
+ * This tasks sets hostlist testing to allowed after intervall between to testings is reached
+ *
+ * @param cls closure
+ * @param tc TaskContext
+ */
+static void
+task_testing_intervall_reset (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ stat_testing_allowed = GNUNET_OK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Testing new hostlist advertisements is allowed again\n");
+}
+
+
+/**
+ * Task that writes hostlist entries to a file on a regular base
+ *
+ * @param cls closure
+ * @param tc TaskContext
+ */
+static void
+task_hostlist_saving (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ ti_saving_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Scheduled saving of hostlists\n"));
+ save_hostlist_file (GNUNET_NO);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Hostlists will be saved to file again in %llums\n"),
+ (unsigned long long) SAVING_INTERVALL.rel_value);
+ ti_saving_task =
+ GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving,
+ NULL);
+}
+
+
+/**
+ * Method called whenever a given peer connects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ * @param atsi performance data
+ * @param atsi_count number of records in 'atsi'
+ */
+static void
+handler_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ GNUNET_assert (stat_connection_count < UINT_MAX);
+ stat_connection_count++;
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), 1,
+ GNUNET_NO);
+}
+
+
+/**
+ * Method called whenever a given peer disconnects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+handler_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_assert (stat_connection_count > 0);
+ stat_connection_count--;
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), -1,
+ GNUNET_NO);
+}
+
+
+/**
+ * Method called whenever an advertisement message arrives.
+ *
+ * @param cls closure (always NULL)
+ * @param peer the peer sending the message
+ * @param message the actual message
+ * @param atsi performance data
+ * @param atsi_count number of records in 'atsi'
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handler_advertisement (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ size_t size;
+ size_t uri_size;
+ const struct GNUNET_MessageHeader *incoming;
+ const char *uri;
+ struct Hostlist *hostlist;
+
+ GNUNET_assert (ntohs (message->type) ==
+ GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
+ size = ntohs (message->size);
+ if (size <= sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ incoming = (const struct GNUNET_MessageHeader *) message;
+ uri = (const char *) &incoming[1];
+ uri_size = size - sizeof (struct GNUNET_MessageHeader);
+ if (uri[uri_size - 1] != '\0')
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Hostlist client recieved advertisement from `%s' containing URI `%s'\n",
+ GNUNET_i2s (peer), uri);
+ if (GNUNET_NO != linked_list_contains (uri))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URI `%s' is already known\n", uri);
+ return GNUNET_OK;
+ }
+
+ if (GNUNET_NO == stat_testing_allowed)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Currently not accepting new advertisements: interval between to advertisements is not reached\n");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_YES == stat_testing_hostlist)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Currently not accepting new advertisements: we are already testing a hostlist\n");
+ return GNUNET_SYSERR;
+ }
+
+ hostlist = GNUNET_malloc (sizeof (struct Hostlist) + uri_size);
+ hostlist->hostlist_uri = (const char *) &hostlist[1];
+ memcpy (&hostlist[1], uri, uri_size);
+ hostlist->time_creation = GNUNET_TIME_absolute_get ();
+ hostlist->time_last_usage = GNUNET_TIME_absolute_get_zero ();
+ hostlist->quality = HOSTLIST_INITIAL;
+ hostlist_to_test = hostlist;
+
+ stat_testing_hostlist = GNUNET_YES;
+ stat_testing_allowed = GNUNET_NO;
+ ti_testing_intervall_task =
+ GNUNET_SCHEDULER_add_delayed (TESTING_INTERVAL,
+ &task_testing_intervall_reset, NULL);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Testing new hostlist advertisements is locked for the next %u ms\n",
+ TESTING_INTERVAL.rel_value);
+
+ ti_download_dispatcher_task =
+ GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL);
+
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Continuation called by the statistics code once
+ * we go the stat. Initiates hostlist download scheduling.
+ *
+ * @param cls closure
+ * @param success GNUNET_OK if statistics were
+ * successfully obtained, GNUNET_SYSERR if not.
+ */
+static void
+primary_task (void *cls, int success)
+{
+ if (stats == NULL)
+ return; /* in shutdown */
+#if DEBUG_HOSTLIST_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Statistics request done, scheduling hostlist download\n");
+#endif
+ ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL);
+}
+
+
+static int
+process_stat (void *cls, const char *subsystem, const char *name,
+ uint64_t value, int is_persistent)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Initial time between hostlist downloads is %llums\n"),
+ (unsigned long long) value);
+ hostlist_delay.rel_value = value;
+ return GNUNET_OK;
+}
+
+/**
+ * Method to load persistent hostlist file during hostlist client startup
+ */
+static void
+load_hostlist_file ()
+{
+ char *filename;
+ char *uri;
+ char *emsg;
+ struct Hostlist *hostlist;
+
+ uri = NULL;
+ uint32_t times_used;
+ uint32_t hellos_returned;
+ uint64_t quality;
+ uint64_t last_used;
+ uint64_t created;
+ uint32_t counter;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE",
+ &filename))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("No `%s' specified in `%s' configuration, cannot load hostlists from file.\n"),
+ "HOSTLISTFILE", "HOSTLIST");
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Loading saved hostlist entries from file `%s' \n"), filename);
+ if (GNUNET_NO == GNUNET_DISK_file_test (filename))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Hostlist file `%s' is not existing\n"), filename);
+ GNUNET_free (filename);
+ return;
+ }
+
+ struct GNUNET_BIO_ReadHandle *rh = GNUNET_BIO_read_open (filename);
+
+ if (NULL == rh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Could not open file `%s' for reading to load hostlists: %s\n"),
+ filename, STRERROR (errno));
+ GNUNET_free (filename);
+ return;
+ }
+
+ counter = 0;
+ while ((GNUNET_OK == GNUNET_BIO_read_string (rh, "url", &uri, MAX_URL_LEN)) &&
+ (NULL != uri) && (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &times_used))
+ && (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) &&
+ (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &last_used)) &&
+ (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &created)) &&
+ (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &hellos_returned)))
+ {
+ hostlist = GNUNET_malloc (sizeof (struct Hostlist) + strlen (uri) + 1);
+ hostlist->hello_count = hellos_returned;
+ hostlist->hostlist_uri = (const char *) &hostlist[1];
+ memcpy (&hostlist[1], uri, strlen (uri) + 1);
+ hostlist->quality = quality;
+ hostlist->time_creation.abs_value = created;
+ hostlist->time_last_usage.abs_value = last_used;
+ GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, hostlist);
+ linked_list_size++;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Added hostlist entry eith URI `%s' \n",
+ hostlist->hostlist_uri);
+ GNUNET_free (uri);
+ uri = NULL;
+ counter++;
+ if (counter >= MAX_NUMBER_HOSTLISTS)
+ break;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%u hostlist URIs loaded from file\n"),
+ counter);
+ GNUNET_STATISTICS_set (stats, gettext_noop ("# hostlist URIs read from file"),
+ counter, GNUNET_YES);
+ GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"),
+ linked_list_size, GNUNET_NO);
+
+ GNUNET_free_non_null (uri);
+ emsg = NULL;
+ GNUNET_BIO_read_close (rh, &emsg);
+ if (emsg != NULL)
+ GNUNET_free (emsg);
+ GNUNET_free (filename);
+}
+
+
+/**
+ * Method to save persistent hostlist file during hostlist client shutdown
+ * @param shutdown set if called because of shutdown, entries in linked list will be destroyed
+ */
+static void
+save_hostlist_file (int shutdown)
+{
+ char *filename;
+ struct Hostlist *pos;
+ struct GNUNET_BIO_WriteHandle *wh;
+ int ok;
+ uint32_t counter;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE",
+ &filename))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("No `%s' specified in `%s' configuration, cannot save hostlists to file.\n"),
+ "HOSTLISTFILE", "HOSTLIST");
+ return;
+ }
+ if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
+ {
+ GNUNET_free (filename);
+ return;
+ }
+ wh = GNUNET_BIO_write_open (filename);
+ if (NULL == wh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Could not open file `%s' for writing to save hostlists: %s\n"),
+ filename, STRERROR (errno));
+ GNUNET_free (filename);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Writing %u hostlist URIs to `%s'\n"),
+ linked_list_size, filename);
+ /* add code to write hostlists to file using bio */
+ ok = GNUNET_YES;
+ counter = 0;
+ while (NULL != (pos = linked_list_head))
+ {
+ if (GNUNET_YES == shutdown)
+ {
+ GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, pos);
+ linked_list_size--;
+ }
+ if (GNUNET_YES == ok)
+ {
+ if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pos->hostlist_uri)) ||
+ (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->times_used)) ||
+ (GNUNET_OK != GNUNET_BIO_write_int64 (wh, pos->quality)) ||
+ (GNUNET_OK !=
+ GNUNET_BIO_write_int64 (wh, pos->time_last_usage.abs_value)) ||
+ (GNUNET_OK !=
+ GNUNET_BIO_write_int64 (wh, pos->time_creation.abs_value)) ||
+ (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->hello_count)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Error writing hostlist URIs to file `%s'\n"), filename);
+ ok = GNUNET_NO;
+ }
+ }
+
+ if (GNUNET_YES == shutdown)
+ GNUNET_free (pos);
+ counter++;
+ if (counter >= MAX_NUMBER_HOSTLISTS)
+ break;
+ }
+ GNUNET_STATISTICS_set (stats,
+ gettext_noop ("# hostlist URIs written to file"),
+ counter, GNUNET_YES);
+
+ if (GNUNET_OK != GNUNET_BIO_write_close (wh))
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Error writing hostlist URIs to file `%s'\n"), filename);
+ GNUNET_free (filename);
+}
+
+/**
+ * Start downloading hostlists from hostlist servers as necessary.
+ */
+int
+GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_STATISTICS_Handle *st,
+ GNUNET_CORE_ConnectEventHandler *ch,
+ GNUNET_CORE_DisconnectEventHandler *dh,
+ GNUNET_CORE_MessageCallback *msgh, int learn)
+{
+ char *filename;
+ int result;
+
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ transport = GNUNET_TRANSPORT_connect (c, NULL, NULL, NULL, NULL, NULL);
+ if (NULL == transport)
+ {
+ curl_global_cleanup ();
+ return GNUNET_SYSERR;
+ }
+ cfg = c;
+ stats = st;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "HTTP-PROXY",
+ &proxy))
+ proxy = NULL;
+ stat_learning = learn;
+ *ch = &handler_connect;
+ *dh = &handler_disconnect;
+ linked_list_head = NULL;
+ linked_list_tail = NULL;
+ stat_use_bootstrap = GNUNET_YES;
+ stat_testing_hostlist = GNUNET_NO;
+ stat_testing_allowed = GNUNET_YES;
+
+ if (GNUNET_YES == stat_learning)
+ {
+ *msgh = &handler_advertisement;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Learning is enabled on this peer\n"));
+ load_hostlist_file ();
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Hostlists will be saved to file again in %llums\n"),
+ (unsigned long long) SAVING_INTERVALL.rel_value);
+ ti_saving_task =
+ GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving,
+ NULL);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Learning is not enabled on this peer\n"));
+ *msgh = NULL;
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST",
+ "HOSTLISTFILE", &filename))
+ {
+ if (GNUNET_YES == GNUNET_DISK_file_test (filename))
+ {
+ result = remove (filename);
+ if (result == 0)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Since learning is not enabled on this peer, hostlist file `%s' was removed\n"),
+ filename);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Hostlist file `%s' could not be removed\n"), filename);
+ }
+ }
+ GNUNET_free (filename);
+ }
+ GNUNET_STATISTICS_get (stats, "hostlist",
+ gettext_noop
+ ("# milliseconds between hostlist downloads"),
+ GNUNET_TIME_UNIT_MINUTES, &primary_task, &process_stat,
+ NULL);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Stop downloading hostlists from hostlist servers as necessary.
+ */
+void
+GNUNET_HOSTLIST_client_stop ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n");
+#if DEBUG_HOSTLIST_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n");
+#endif
+ if (GNUNET_YES == stat_learning)
+ save_hostlist_file (GNUNET_YES);
+
+ if (ti_saving_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_saving_task);
+ }
+
+ if (ti_download_dispatcher_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_download_dispatcher_task);
+ }
+ if (ti_testing_intervall_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_testing_intervall_task);
+ }
+ if (ti_download != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_download);
+ }
+ if (ti_check_download != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_check_download);
+ curl_global_cleanup ();
+ }
+ if (transport != NULL)
+ {
+ GNUNET_TRANSPORT_disconnect (transport);
+ transport = NULL;
+ }
+ GNUNET_assert (NULL == transport);
+ GNUNET_free_non_null (proxy);
+ proxy = NULL;
+ cfg = NULL;
+}
+
+/* end of hostlist-client.c */
diff --git a/src/hostlist/hostlist-client.h b/src/hostlist/hostlist-client.h
new file mode 100644
index 0000000..3def865
--- /dev/null
+++ b/src/hostlist/hostlist-client.h
@@ -0,0 +1,108 @@
+/*
+ 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 hostlist/hostlist-client.h
+ * @brief hostlist support. Downloads HELLOs via HTTP.
+ * @author Christian Grothoff
+ */
+
+#ifndef HOSTLIST_CLIENT_H
+#define HOSTLIST_CLIENT_H
+
+#include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_time_lib.h"
+
+/**
+ * Maximum number of hostlist that are saved
+ */
+#define MAX_NUMBER_HOSTLISTS 30
+
+/**
+ * Time intervall hostlists are saved to disk
+ */
+#define SAVING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
+
+/**
+ * Time interval between two hostlist tests
+ */
+#define TESTING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
+
+/**
+ * Time interval for download dispatcher before a download is re-scheduled
+ */
+#define WAITING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+/**
+ * Defines concerning the hostlist quality metric
+ */
+
+/**
+ * Initial quality of a new created hostlist
+ */
+#define HOSTLIST_INITIAL 10000
+
+/**
+ * Value subtracted each time a hostlist download fails
+ */
+#define HOSTLIST_FAILED_DOWNLOAD 100
+
+/**
+ * Value added each time a hostlist download is successful
+ */
+#define HOSTLIST_SUCCESSFUL_DOWNLOAD 100
+
+/**
+ * Value added for each valid HELLO recived during a hostlist download
+ */
+#define HOSTLIST_SUCCESSFUL_HELLO 1
+
+
+
+/**
+ * Start downloading hostlists from hostlist servers as necessary.
+ *
+ * @param c the configuration to use
+ * @param st hande for publishing statistics
+ * @param ch set to handler for connect notifications
+ * @param dh set to handler for disconnect notifications
+ * @param msgh set to handler for message handler notifications
+ * @param learn set if client is learning new hostlists
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_STATISTICS_Handle *st,
+ GNUNET_CORE_ConnectEventHandler *ch,
+ GNUNET_CORE_DisconnectEventHandler *dh,
+ GNUNET_CORE_MessageCallback *msgh, int learn);
+
+
+/**
+ * Stop downloading hostlists from hostlist servers as necessary.
+ */
+void
+GNUNET_HOSTLIST_client_stop (void);
+
+
+#endif
+/* end of hostlist-client.h */
diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c
new file mode 100644
index 0000000..8e79ace
--- /dev/null
+++ b/src/hostlist/hostlist-server.c
@@ -0,0 +1,700 @@
+/*
+ This file is part of GNUnet.
+ (C) 2008, 2009, 2010 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 hostlist/hostlist-server.c
+ * @author Christian Grothoff, Matthias Wachs
+ * @brief application to provide an integrated hostlist HTTP server
+ */
+
+#include "platform.h"
+#include <microhttpd.h>
+#include "hostlist-server.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet-daemon-hostlist.h"
+#include "gnunet_resolver_service.h"
+
+#define DEBUG_HOSTLIST_SERVER GNUNET_EXTRA_LOGGING
+
+/**
+ * Handle to the HTTP server as provided by libmicrohttpd for IPv6.
+ */
+static struct MHD_Daemon *daemon_handle_v6;
+
+/**
+ * Handle to the HTTP server as provided by libmicrohttpd for IPv4.
+ */
+static struct MHD_Daemon *daemon_handle_v4;
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * For keeping statistics.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to the core service (NULL until we've connected to it).
+ */
+static struct GNUNET_CORE_Handle *core;
+
+/**
+ * Handle to the peerinfo notify service (NULL until we've connected to it).
+ */
+static struct GNUNET_PEERINFO_NotifyContext *notify;
+
+/**
+ * Our primary task for IPv4.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4;
+
+/**
+ * Our primary task for IPv6.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6;
+
+/**
+ * Our canonical response.
+ */
+static struct MHD_Response *response;
+
+/**
+ * NULL if we are not currenlty iterating over peer information.
+ */
+static struct GNUNET_PEERINFO_IteratorContext *pitr;
+
+/**
+ * Handle for accessing peerinfo service.
+ */
+static struct GNUNET_PEERINFO_Handle *peerinfo;
+
+/**
+ * Context for host processor.
+ */
+struct HostSet
+{
+ unsigned int size;
+
+ char *data;
+};
+
+/**
+ * Set if we are allowed to advertise our hostlist to others.
+ */
+static int advertising;
+
+/**
+ * Buffer for the hostlist address
+ */
+static char *hostlist_uri;
+
+
+/**
+ * Function that assembles our response.
+ */
+static void
+finish_response (struct HostSet *results)
+{
+ if (response != NULL)
+ MHD_destroy_response (response);
+#if DEBUG_HOSTLIST_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating hostlist response with %u bytes\n",
+ (unsigned int) results->size);
+#endif
+ response =
+ MHD_create_response_from_data (results->size, results->data, MHD_YES,
+ MHD_NO);
+ if ((daemon_handle_v4 == NULL) && (daemon_handle_v6 == NULL))
+ {
+ MHD_destroy_response (response);
+ response = NULL;
+ }
+ GNUNET_STATISTICS_set (stats, gettext_noop ("bytes in hostlist"),
+ results->size, GNUNET_YES);
+ GNUNET_free (results);
+}
+
+
+/**
+ * Set 'cls' to GNUNET_YES (we have an address!).
+ *
+ * @param cls closure, an 'int*'
+ * @param address the address (ignored)
+ * @param expiration expiration time (call is ignored if this is in the past)
+ * @return GNUNET_SYSERR to stop iterating (unless expiration has occured)
+ */
+static int
+check_has_addr (void *cls, const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
+{
+ int *arg = cls;
+
+ if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("expired addresses encountered"), 1,
+ GNUNET_YES);
+ return GNUNET_YES; /* ignore this address */
+ }
+ *arg = GNUNET_YES;
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Callback that processes each of the known HELLOs for the
+ * hostlist response construction.
+ */
+static void
+host_processor (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Message *hello, const char *err_msg)
+{
+ struct HostSet *results = cls;
+ size_t old;
+ size_t s;
+ int has_addr;
+
+ if (err_msg != NULL)
+ {
+ GNUNET_assert (NULL == peer);
+ pitr = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Error in communication with PEERINFO service: %s\n"),
+ err_msg);
+ return;
+ }
+ if (peer == NULL)
+ {
+ pitr = NULL;
+ finish_response (results);
+ return;
+ }
+ if (hello == NULL)
+ return;
+ has_addr = GNUNET_NO;
+ GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_has_addr, &has_addr);
+ if (GNUNET_NO == has_addr)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "HELLO for peer `%4s' has no address, not suitable for hostlist!\n",
+ GNUNET_i2s (peer));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("HELLOs without addresses encountered (ignored)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ old = results->size;
+ s = GNUNET_HELLO_size (hello);
+#if DEBUG_HOSTLIST_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u bytes of `%s' from peer `%s' for hostlist.\n",
+ (unsigned int) s, "HELLO", GNUNET_i2s (peer));
+#endif
+ if ((old + s >= GNUNET_MAX_MALLOC_CHECKED) ||
+ (old + s >= MAX_BYTES_PER_HOSTLISTS))
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("bytes not included in hostlist (size limit)"),
+ s, GNUNET_NO);
+ return; /* too large, skip! */
+ }
+#if DEBUG_HOSTLIST_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Adding peer `%s' to hostlist (%u bytes)\n", GNUNET_i2s (peer),
+ (unsigned int) s);
+#endif
+ GNUNET_array_grow (results->data, results->size, old + s);
+ memcpy (&results->data[old], hello, s);
+}
+
+
+
+/**
+ * Hostlist access policy (very permissive, allows everything).
+ */
+static int
+accept_policy_callback (void *cls, const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ if (NULL == response)
+ {
+#if DEBUG_HOSTLIST_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received request for hostlist, but I am not yet ready; rejecting!\n");
+#endif
+ return MHD_NO;
+ }
+ return MHD_YES; /* accept all */
+}
+
+
+/**
+ * Main request handler.
+ */
+static int
+access_handler_callback (void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method,
+ const char *version, const char *upload_data,
+ size_t * upload_data_size, void **con_cls)
+{
+ static int dummy;
+
+ if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Refusing `%s' request to hostlist server\n"), method);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("hostlist requests refused (not HTTP GET)"), 1,
+ GNUNET_YES);
+ return MHD_NO;
+ }
+ if (NULL == *con_cls)
+ {
+ (*con_cls) = &dummy;
+#if DEBUG_HOSTLIST_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Sending 100 CONTINUE reply\n"));
+#endif
+ return MHD_YES; /* send 100 continue */
+ }
+ if (*upload_data_size != 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Refusing `%s' request with %llu bytes of upload data\n"),
+ method, (unsigned long long) *upload_data_size);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("hostlist requests refused (upload data)"), 1,
+ GNUNET_YES);
+ return MHD_NO; /* do not support upload data */
+ }
+ if (response == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Could not handle hostlist request since I do not have a response yet\n"));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("hostlist requests refused (not ready)"), 1,
+ GNUNET_YES);
+ return MHD_NO; /* internal error, no response yet */
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received request for our hostlist\n"));
+ GNUNET_STATISTICS_update (stats, gettext_noop ("hostlist requests processed"),
+ 1, GNUNET_YES);
+ return MHD_queue_response (connection, MHD_HTTP_OK, response);
+}
+
+
+/**
+ * Handler called by core when core is ready to transmit message
+ * @param cls closure
+ * @param size size of buffer to copy message to
+ * @param buf buffer to copy message to
+ */
+static size_t
+adv_transmit_ready (void *cls, size_t size, void *buf)
+{
+ static uint64_t hostlist_adv_count;
+
+ size_t transmission_size;
+ size_t uri_size; /* Including \0 termination! */
+ struct GNUNET_MessageHeader header;
+ char *cbuf;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission failed, buffer invalid!\n");
+ return 0;
+ }
+ uri_size = strlen (hostlist_uri) + 1;
+ transmission_size = sizeof (struct GNUNET_MessageHeader) + uri_size;
+ header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
+ header.size = htons (transmission_size);
+ GNUNET_assert (size >= transmission_size);
+ memcpy (buf, &header, sizeof (struct GNUNET_MessageHeader));
+ cbuf = buf;
+ memcpy (&cbuf[sizeof (struct GNUNET_MessageHeader)], hostlist_uri, uri_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sent advertisement message: Copied %u bytes into buffer!\n",
+ (unsigned int) transmission_size);
+ hostlist_adv_count++;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " # Sent advertisement message: %u\n",
+ hostlist_adv_count);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# hostlist advertisements send"), 1,
+ GNUNET_NO);
+ return transmission_size;
+}
+
+
+/**
+ * Method called whenever a given peer connects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ * @param atsi performance data
+ * @param atsi_count number of records in 'atsi'
+ */
+static void
+connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ size_t size;
+
+ if (!advertising)
+ return;
+ if (hostlist_uri == NULL)
+ return;
+ size = strlen (hostlist_uri) + 1;
+ if (size + sizeof (struct GNUNET_MessageHeader) >=
+ GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ size += sizeof (struct GNUNET_MessageHeader);
+ if (NULL == core)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Asked core to transmit advertisement message with a size of %u bytes to peer `%s'\n",
+ size, GNUNET_i2s (peer));
+ if (NULL ==
+ GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 0,
+ GNUNET_ADV_TIMEOUT, peer, size,
+ &adv_transmit_ready, NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Advertisement message could not be queued by core\n"));
+ }
+}
+
+
+/**
+ * Method called whenever a given peer disconnects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ /* nothing to do */
+}
+
+/**
+ * PEERINFO calls this function to let us know about a possible peer
+ * that we might want to connect to.
+ *
+ * @param cls closure (not used)
+ * @param peer potential peer to connect to
+ * @param hello HELLO for this peer (or NULL)
+ * @param err_msg NULL if successful, otherwise contains error message
+ */
+static void
+process_notify (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Message *hello, const char *err_msg)
+{
+ struct HostSet *results;
+
+#if DEBUG_HOSTLIST_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peerinfo is notifying us to rebuild our hostlist\n");
+#endif
+ if (err_msg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Error in communication with PEERINFO service\n"));
+ /* return; */
+ }
+ results = GNUNET_malloc (sizeof (struct HostSet));
+ GNUNET_assert (peerinfo != NULL);
+ pitr =
+ GNUNET_PEERINFO_iterate (peerinfo, NULL, GNUNET_TIME_UNIT_MINUTES,
+ &host_processor, results);
+}
+
+/**
+ * Function that queries MHD's select sets and
+ * starts the task waiting for them.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier
+prepare_daemon (struct MHD_Daemon *daemon_handle);
+
+
+/**
+ * Call MHD to process pending requests and then go back
+ * and schedule the next run.
+ */
+static void
+run_daemon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct MHD_Daemon *daemon_handle = cls;
+
+ if (daemon_handle == daemon_handle_v4)
+ hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK;
+ else
+ hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
+ if (daemon_handle == daemon_handle_v4)
+ hostlist_task_v4 = prepare_daemon (daemon_handle);
+ else
+ hostlist_task_v6 = prepare_daemon (daemon_handle);
+}
+
+
+/**
+ * Function that queries MHD's select sets and
+ * starts the task waiting for them.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier
+prepare_daemon (struct MHD_Daemon *daemon_handle)
+{
+ GNUNET_SCHEDULER_TaskIdentifier ret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ struct GNUNET_NETWORK_FDSet *wrs;
+ struct GNUNET_NETWORK_FDSet *wws;
+ struct GNUNET_NETWORK_FDSet *wes;
+ int max;
+ unsigned long long timeout;
+ int haveto;
+ struct GNUNET_TIME_Relative tv;
+
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ wrs = GNUNET_NETWORK_fdset_create ();
+ wes = GNUNET_NETWORK_fdset_create ();
+ wws = GNUNET_NETWORK_fdset_create ();
+ max = -1;
+ GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
+ haveto = MHD_get_timeout (daemon_handle, &timeout);
+ if (haveto == MHD_YES)
+ tv.rel_value = (uint64_t) timeout;
+ else
+ tv = GNUNET_TIME_UNIT_FOREVER_REL;
+ GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
+ ret =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
+ GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws,
+ &run_daemon, daemon_handle);
+ GNUNET_NETWORK_fdset_destroy (wrs);
+ GNUNET_NETWORK_fdset_destroy (wws);
+ GNUNET_NETWORK_fdset_destroy (wes);
+ return ret;
+}
+
+
+
+/**
+ * Start server offering our hostlist.
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_STATISTICS_Handle *st,
+ struct GNUNET_CORE_Handle *co,
+ GNUNET_CORE_ConnectEventHandler *server_ch,
+ GNUNET_CORE_DisconnectEventHandler *server_dh,
+ int advertise)
+{
+ unsigned long long port;
+ char *hostname;
+ size_t size;
+
+ advertising = advertise;
+ if (!advertising)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Advertising not enabled on this hostlist server\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Advertising enabled on this hostlist server\n");
+ cfg = c;
+ stats = st;
+ peerinfo = GNUNET_PEERINFO_connect (cfg);
+ if (peerinfo == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not access PEERINFO service. Exiting.\n"));
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, "HOSTLIST", "HTTPPORT",
+ &port))
+ return GNUNET_SYSERR;
+ if ((port == 0) || (port > UINT16_MAX))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Invalid port number %llu. Exiting.\n"), port);
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST",
+ "EXTERNAL_DNS_NAME", &hostname))
+ hostname = GNUNET_RESOLVER_local_fqdn_get ();
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlist service starts on %s:%llu\n"),
+ hostname, port);
+ if (NULL != hostname)
+ {
+ size = strlen (hostname);
+ if (size + 15 > MAX_URL_LEN)
+ {
+ GNUNET_break (0);
+ }
+ else
+ {
+ GNUNET_asprintf (&hostlist_uri, "http://%s:%u/", hostname,
+ (unsigned int) port);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Address to obtain hostlist: `%s'\n"), hostlist_uri);
+ }
+ GNUNET_free (hostname);
+ }
+ daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6
+#if DEBUG_HOSTLIST_SERVER
+ | MHD_USE_DEBUG
+#endif
+ , (unsigned short) port,
+ &accept_policy_callback, NULL,
+ &access_handler_callback, NULL,
+ MHD_OPTION_CONNECTION_LIMIT,
+ (unsigned int) 16,
+ MHD_OPTION_PER_IP_CONNECTION_LIMIT,
+ (unsigned int) 1,
+ MHD_OPTION_CONNECTION_TIMEOUT,
+ (unsigned int) 16,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+ (size_t) (16 * 1024), MHD_OPTION_END);
+ daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG
+#if DEBUG_HOSTLIST_SERVER
+ | MHD_USE_DEBUG
+#endif
+ , (unsigned short) port,
+ &accept_policy_callback, NULL,
+ &access_handler_callback, NULL,
+ MHD_OPTION_CONNECTION_LIMIT,
+ (unsigned int) 16,
+ MHD_OPTION_PER_IP_CONNECTION_LIMIT,
+ (unsigned int) 1,
+ MHD_OPTION_CONNECTION_TIMEOUT,
+ (unsigned int) 16,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+ (size_t) (16 * 1024), MHD_OPTION_END);
+
+ if ((daemon_handle_v6 == NULL) && (daemon_handle_v4 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not start hostlist HTTP server on port %u\n"),
+ (unsigned short) port);
+ return GNUNET_SYSERR;
+ }
+
+ core = co;
+
+ *server_ch = &connect_handler;
+ *server_dh = &disconnect_handler;
+
+ if (daemon_handle_v4 != NULL)
+ hostlist_task_v4 = prepare_daemon (daemon_handle_v4);
+ if (daemon_handle_v6 != NULL)
+ hostlist_task_v6 = prepare_daemon (daemon_handle_v6);
+
+ notify = GNUNET_PEERINFO_notify (cfg, process_notify, NULL);
+
+ return GNUNET_OK;
+}
+
+/**
+ * Stop server offering our hostlist.
+ */
+void
+GNUNET_HOSTLIST_server_stop ()
+{
+#if DEBUG_HOSTLIST_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n");
+#endif
+ if (NULL != notify)
+ {
+ GNUNET_PEERINFO_notify_cancel (notify);
+ notify = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6)
+ {
+ GNUNET_SCHEDULER_cancel (hostlist_task_v6);
+ hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4)
+ {
+ GNUNET_SCHEDULER_cancel (hostlist_task_v4);
+ hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (pitr != NULL)
+ {
+ GNUNET_PEERINFO_iterate_cancel (pitr);
+ pitr = NULL;
+ }
+ if (NULL != daemon_handle_v4)
+ {
+ MHD_stop_daemon (daemon_handle_v4);
+ daemon_handle_v4 = NULL;
+ }
+ if (NULL != daemon_handle_v6)
+ {
+ MHD_stop_daemon (daemon_handle_v6);
+ daemon_handle_v6 = NULL;
+ }
+ if (response != NULL)
+ {
+ MHD_destroy_response (response);
+ response = NULL;
+ }
+ if (peerinfo != NULL)
+ {
+ GNUNET_PEERINFO_disconnect (peerinfo);
+ peerinfo = NULL;
+ }
+ cfg = NULL;
+ stats = NULL;
+ core = NULL;
+}
+
+/* end of hostlist-server.c */
diff --git a/src/hostlist/hostlist-server.h b/src/hostlist/hostlist-server.h
new file mode 100644
index 0000000..e0f8eb4
--- /dev/null
+++ b/src/hostlist/hostlist-server.h
@@ -0,0 +1,58 @@
+/*
+ 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 hostlist/hostlist-server.h
+ * @brief hostlist support. Downloads HELLOs via HTTP.
+ * @author Christian Grothoff
+ */
+
+#ifndef HOSTLIST_SERVER_H
+#define HOSTLIST_SERVER_H
+
+#include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_util_lib.h"
+
+#define GNUNET_ADV_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
+
+/**
+ * Start server offering our hostlist.
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_STATISTICS_Handle *st,
+ struct GNUNET_CORE_Handle *core,
+ GNUNET_CORE_ConnectEventHandler *server_ch,
+ GNUNET_CORE_DisconnectEventHandler *server_dh,
+ int advertise);
+
+
+/**
+ * Stop server offering our hostlist.
+ */
+void
+GNUNET_HOSTLIST_server_stop (void);
+
+
+#endif
+/* end of hostlist-server.h */
diff --git a/src/hostlist/hostlist.conf b/src/hostlist/hostlist.conf
new file mode 100644
index 0000000..b13e1e5
--- /dev/null
+++ b/src/hostlist/hostlist.conf
@@ -0,0 +1,14 @@
+[hostlist]
+# port for hostlist http server
+HTTPPORT = 8080
+HOME = $SERVICEHOME
+HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data
+CONFIG = $DEFAULTCONFIG
+BINARY = gnunet-daemon-hostlist
+# consider having "-e" as default as well once implemented
+OPTIONS = -b
+SERVERS = http://v9.gnunet.org:58080/ http://ioerror.gnunet.org:65535/
+# proxy for downloading hostlists
+HTTP-PROXY =
+
+
diff --git a/src/hostlist/learning_data.conf b/src/hostlist/learning_data.conf
new file mode 100644
index 0000000..e3a3897
--- /dev/null
+++ b/src/hostlist/learning_data.conf
@@ -0,0 +1,14 @@
+@INLINE@ test_hostlist_defaults.conf
+[hostlist]
+HTTPPORT = 28080
+OPTIONS = -b -e
+SERVERS = http://gnunet.org:8080/
+PORT = 23354
+HOSTNAME = localhost
+
+[datastore]
+AUTOSTART = YES
+
+[fs]
+AUTOSTART = YES
+
diff --git a/src/hostlist/test_gnunet_daemon_hostlist.c b/src/hostlist/test_gnunet_daemon_hostlist.c
new file mode 100644
index 0000000..da3ab8b
--- /dev/null
+++ b/src/hostlist/test_gnunet_daemon_hostlist.c
@@ -0,0 +1,255 @@
+/*
+ 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 hostlist/test_gnunet_daemon_hostlist.c
+ * @brief test for gnunet_daemon_hostslist.c
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_transport_service.h"
+
+#define VERBOSE GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150)
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+struct PeerContext
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_TRANSPORT_Handle *th;
+ struct GNUNET_MessageHeader *hello;
+ struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
+#if START_ARM
+ struct GNUNET_OS_Process *arm_proc;
+#endif
+};
+
+static struct PeerContext p1;
+
+static struct PeerContext p2;
+
+
+static void
+clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (p1.th != NULL)
+ {
+ if (p1.ghh != NULL)
+ {
+ GNUNET_TRANSPORT_get_hello_cancel (p1.ghh);
+ p1.ghh = NULL;
+ }
+ GNUNET_TRANSPORT_disconnect (p1.th);
+ p1.th = NULL;
+ }
+ if (p2.th != NULL)
+ {
+ if (p2.ghh != NULL)
+ {
+ GNUNET_TRANSPORT_get_hello_cancel (p2.ghh);
+ p2.ghh = NULL;
+ }
+ GNUNET_TRANSPORT_disconnect (p2.th);
+ p2.th = NULL;
+ }
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Timeout, give up.
+ */
+static void
+timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout trying to connect peers, test failed.\n");
+ clean_up (NULL, tc);
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param peer the peer that connected
+ * @param latency current latency of the connection
+ * @param distance in overlay hops, as given by transport plugin
+ */
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ if (peer == NULL)
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n");
+ ok = 0;
+ if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (timeout_task);
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_SCHEDULER_add_now (&clean_up, NULL);
+}
+
+
+static void
+process_hello (void *cls, const struct GNUNET_MessageHeader *message)
+{
+ struct PeerContext *p = cls;
+
+ GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
+ p->ghh = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received HELLO, starting hostlist service.\n");
+}
+
+
+static void
+setup_peer (struct PeerContext *p, const char *cfgname)
+{
+ p->cfg = GNUNET_CONFIGURATION_create ();
+#if START_ARM
+ p->arm_proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
+ "gnunet-service-arm",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ "-c", cfgname, NULL);
+#endif
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+ p->th =
+ GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, &notify_connect, NULL);
+ GNUNET_assert (p->th != NULL);
+ p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p);
+}
+
+
+static void
+waitpid_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PeerContext *p = cls;
+
+#if START_ARM
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n");
+ if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n",
+ GNUNET_OS_process_get_pid (p->arm_proc));
+ GNUNET_OS_process_close (p->arm_proc);
+ p->arm_proc = NULL;
+#endif
+ GNUNET_CONFIGURATION_destroy (p->cfg);
+}
+
+
+static void
+stop_arm (struct PeerContext *p)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n");
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p);
+}
+
+
+/**
+ * Try again to connect to transport service.
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ stop_arm (&p1);
+ stop_arm (&p2);
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ GNUNET_assert (ok == 1);
+ ok++;
+ timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+ NULL);
+ setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf");
+ setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf");
+}
+
+
+static int
+check ()
+{
+ char *const argv[] = { "test-gnunet-daemon-hostlist",
+ "-c", "test_gnunet_daemon_hostlist_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
+ "test-gnunet-daemon-hostlist", "nohelp", options, &run,
+ &ok);
+ return ok;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+
+ int ret;
+
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist");
+ GNUNET_log_setup ("test-gnunet-daemon-hostlist",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist");
+ return ret;
+}
+
+/* end of test_gnunet_daemon_hostlist.c */
diff --git a/src/hostlist/test_gnunet_daemon_hostlist_data.conf b/src/hostlist/test_gnunet_daemon_hostlist_data.conf
new file mode 100644
index 0000000..74d16be
--- /dev/null
+++ b/src/hostlist/test_gnunet_daemon_hostlist_data.conf
@@ -0,0 +1,29 @@
+@INLINE@ test_hostlist_defaults.conf
+[transport-tcp]
+PORT = 12968
+
+[arm]
+PORT = 12966
+DEFAULTSERVICES = hostlist topology
+
+[statistics]
+PORT = 12967
+
+[resolver]
+PORT = 12964
+
+[peerinfo]
+PORT = 12969
+
+[transport]
+PORT = 12965
+
+[core]
+PORT = 12970
+
+[hostlist]
+HTTPPORT = 28080
+SERVERS = http://gnunet.org:8080/
+PORT = 23354
+HOSTNAME = localhost
+
diff --git a/src/hostlist/test_gnunet_daemon_hostlist_learning.c b/src/hostlist/test_gnunet_daemon_hostlist_learning.c
new file mode 100644
index 0000000..9ef8812
--- /dev/null
+++ b/src/hostlist/test_gnunet_daemon_hostlist_learning.c
@@ -0,0 +1,533 @@
+/*
+ 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 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 hostlist/test_gnunet_daemon_hostlist.c
+ * @brief test for gnunet_daemon_hostslist.c
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_core_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_statistics_service.h"
+
+#define VERBOSE GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+#define MAX_URL_LEN 1000
+
+/**
+ * How long until wait until testcases fails
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180)
+
+#define CHECK_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+
+struct PeerContext
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_TRANSPORT_Handle *th;
+ struct GNUNET_MessageHeader *hello;
+ struct GNUNET_CORE_Handle *core;
+ struct GNUNET_STATISTICS_Handle *stats;
+#if START_ARM
+ struct GNUNET_OS_Process *arm_proc;
+#endif
+};
+
+static int timeout;
+
+static int adv_sent;
+
+static int adv_arrived;
+
+static int learned_hostlist_saved;
+
+static int learned_hostlist_downloaded;
+
+static char *current_adv_uri;
+
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier check_task;
+
+static struct PeerContext adv_peer;
+
+static struct PeerContext learn_peer;
+
+static struct GNUNET_STATISTICS_GetHandle *download_stats;
+
+static struct GNUNET_STATISTICS_GetHandle *urisrecv_stat;
+
+static struct GNUNET_STATISTICS_GetHandle *advsent_stat;
+
+
+static void
+shutdown_testcase ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown testcase....\n");
+ if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (timeout_task);
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != download_stats)
+ {
+ GNUNET_STATISTICS_get_cancel (download_stats);
+ download_stats = NULL;
+ }
+ if (NULL != urisrecv_stat)
+ {
+ GNUNET_STATISTICS_get_cancel (urisrecv_stat);
+ urisrecv_stat = NULL;
+ }
+ if (NULL != advsent_stat)
+ {
+ GNUNET_STATISTICS_get_cancel (advsent_stat);
+ advsent_stat = NULL;
+ }
+ if (check_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (check_task);
+ check_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != current_adv_uri)
+ {
+ GNUNET_free (current_adv_uri);
+ current_adv_uri = NULL;
+ }
+ if (adv_peer.th != NULL)
+ {
+ GNUNET_TRANSPORT_disconnect (adv_peer.th);
+ adv_peer.th = NULL;
+ }
+ if (learn_peer.th != NULL)
+ {
+ GNUNET_TRANSPORT_disconnect (learn_peer.th);
+ learn_peer.th = NULL;
+ }
+ if (adv_peer.core != NULL)
+ {
+ GNUNET_CORE_disconnect (adv_peer.core);
+ adv_peer.core = NULL;
+ }
+ if (learn_peer.core != NULL)
+ {
+ GNUNET_CORE_disconnect (learn_peer.core);
+ learn_peer.core = NULL;
+ }
+#if START_ARM
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Killing hostlist server ARM process.\n");
+ if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ if (GNUNET_OS_process_wait (adv_peer.arm_proc) != GNUNET_OK)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+ GNUNET_OS_process_close (adv_peer.arm_proc);
+ adv_peer.arm_proc = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Killing hostlist client ARM process.\n");
+ if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ if (GNUNET_OS_process_wait (learn_peer.arm_proc) != GNUNET_OK)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+ GNUNET_OS_process_close (learn_peer.arm_proc);
+ learn_peer.arm_proc = NULL;
+#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown complete....\n");
+}
+
+/**
+ * Timeout, give up.
+ */
+static void
+timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout while executing testcase, test failed.\n");
+ timeout = GNUNET_YES;
+ shutdown_testcase ();
+}
+
+
+static void
+process_downloads_done (void *cls, int success)
+{
+ download_stats = NULL;
+}
+
+
+static int
+process_downloads (void *cls, const char *subsystem, const char *name,
+ uint64_t value, int is_persistent)
+{
+ if ((value >= 2) && (learned_hostlist_downloaded == GNUNET_NO))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Peer has successfully downloaded advertised URI\n");
+ learned_hostlist_downloaded = GNUNET_YES;
+ if ((learned_hostlist_saved == GNUNET_YES) && (adv_sent == GNUNET_YES))
+ shutdown_testcase ();
+ }
+ return GNUNET_OK;
+}
+
+
+static void
+process_uris_recv_done (void *cls, int success)
+{
+ urisrecv_stat = NULL;
+}
+
+
+static int
+process_uris_recv (void *cls, const char *subsystem, const char *name,
+ uint64_t value, int is_persistent)
+{
+ if (((struct PeerContext *) cls == &learn_peer) && (value == 1) &&
+ (learned_hostlist_saved == GNUNET_NO))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Peer has successfully saved advertised URI\n");
+ learned_hostlist_saved = GNUNET_YES;
+ if ((learned_hostlist_downloaded == GNUNET_YES) && (adv_sent == GNUNET_YES))
+ shutdown_testcase ();
+ }
+ return GNUNET_OK;
+}
+
+
+static void
+process_adv_sent_done (void *cls, int success)
+{
+ advsent_stat = NULL;
+}
+
+
+static int
+process_adv_sent (void *cls, const char *subsystem, const char *name,
+ uint64_t value, int is_persistent)
+{
+ if ((value >= 1) && (adv_sent == GNUNET_NO))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Server has successfully sent advertisement\n");
+ adv_sent = GNUNET_YES;
+ if ((learned_hostlist_downloaded == GNUNET_YES) &&
+ (learned_hostlist_saved == GNUNET_YES))
+ shutdown_testcase ();
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Check the server statistics regularly
+ */
+static void
+check_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ char *stat;
+
+ check_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"),
+ current_adv_uri);
+ if (NULL != learn_peer.stats)
+ {
+ if (NULL != download_stats)
+ GNUNET_STATISTICS_get_cancel (download_stats);
+ download_stats =
+ GNUNET_STATISTICS_get (learn_peer.stats, "hostlist", stat,
+ GNUNET_TIME_UNIT_MINUTES,
+ &process_downloads_done, &process_downloads,
+ &learn_peer);
+ if (NULL != urisrecv_stat)
+ GNUNET_STATISTICS_get_cancel (urisrecv_stat);
+ urisrecv_stat =
+ GNUNET_STATISTICS_get (learn_peer.stats, "hostlist",
+ gettext_noop ("# advertised hostlist URIs"),
+ GNUNET_TIME_UNIT_MINUTES,
+ &process_uris_recv_done, &process_uris_recv,
+ &learn_peer);
+ }
+ GNUNET_free (stat);
+ if (NULL != adv_peer.stats)
+ {
+ if (NULL != advsent_stat)
+ GNUNET_STATISTICS_get_cancel (advsent_stat);
+ advsent_stat =
+ GNUNET_STATISTICS_get (adv_peer.stats, "hostlist",
+ gettext_noop ("# hostlist advertisements send"),
+ GNUNET_TIME_UNIT_MINUTES, &process_adv_sent_done,
+ &process_adv_sent, NULL);
+ }
+ check_task =
+ GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL);
+}
+
+
+/**
+ * Core handler for p2p hostlist advertisements
+ */
+static int
+ad_arrive_handler (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ char *hostname;
+ char *expected_uri;
+ unsigned long long port;
+ const struct GNUNET_MessageHeader *incoming;
+ const char *end;
+
+ if (-1 ==
+ GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg, "HOSTLIST",
+ "HTTPPORT", &port))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not read advertising server's configuration\n");
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_string (adv_peer.cfg, "HOSTLIST",
+ "EXTERNAL_DNS_NAME", &hostname))
+ hostname = GNUNET_RESOLVER_local_fqdn_get ();
+ GNUNET_asprintf (&expected_uri, "http://%s:%u/",
+ hostname != NULL ? hostname : "localhost",
+ (unsigned int) port);
+ incoming = (const struct GNUNET_MessageHeader *) message;
+ end = (const char *) &incoming[1];
+ if ('\0' !=
+ end[ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - 1])
+ {
+ GNUNET_break (0);
+ GNUNET_free (expected_uri);
+ GNUNET_free_non_null (hostname);
+ return GNUNET_SYSERR;
+ }
+ current_adv_uri = GNUNET_strdup (end);
+ if (0 == strcmp (expected_uri, current_adv_uri))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received hostlist advertisement with URI `%s' as expected\n",
+ current_adv_uri);
+ adv_arrived = GNUNET_YES;
+ adv_sent = GNUNET_YES;
+ }
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected URI `%s' and recieved URI `%s' differ\n",
+ expected_uri, current_adv_uri);
+ GNUNET_free (expected_uri);
+ GNUNET_free_non_null (hostname);
+ return GNUNET_OK;
+}
+
+
+/**
+ * List of handlers if we are learning.
+ */
+static struct GNUNET_CORE_MessageHandler learn_handlers[] = {
+ {&ad_arrive_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0},
+ {NULL, 0, 0}
+};
+
+
+static void
+setup_learn_peer (struct PeerContext *p, const char *cfgname)
+{
+ char *filename;
+ unsigned int result;
+
+ p->cfg = GNUNET_CONFIGURATION_create ();
+#if START_ARM
+ p->arm_proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
+ "gnunet-service-arm",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ "-c", cfgname, NULL);
+#endif
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (p->cfg, "HOSTLIST", "HOSTLISTFILE",
+ &filename))
+ {
+ if (GNUNET_YES == GNUNET_DISK_file_test (filename))
+ {
+ result = UNLINK (filename);
+ if (result == 0)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Hostlist file `%s' was removed\n"), filename);
+ }
+ GNUNET_free (filename);
+ }
+ p->core =
+ GNUNET_CORE_connect (p->cfg, 1, NULL, NULL, NULL, NULL, NULL, GNUNET_NO,
+ NULL, GNUNET_NO, learn_handlers);
+ GNUNET_assert (NULL != p->core);
+ p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
+ GNUNET_assert (NULL != p->stats);
+}
+
+
+static void
+setup_adv_peer (struct PeerContext *p, const char *cfgname)
+{
+ p->cfg = GNUNET_CONFIGURATION_create ();
+#if START_ARM
+ p->arm_proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
+ "gnunet-service-arm",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ "-c", cfgname, NULL);
+#endif
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+ p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
+ GNUNET_assert (NULL != p->stats);
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ timeout = GNUNET_NO;
+ adv_sent = GNUNET_NO;
+
+ adv_arrived = 0;
+ learned_hostlist_saved = GNUNET_NO;
+ learned_hostlist_downloaded = GNUNET_NO;
+
+ cfg = c;
+
+ setup_adv_peer (&adv_peer, "test_learning_adv_peer.conf");
+ setup_learn_peer (&learn_peer, "test_learning_learn_peer.conf");
+ timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL);
+
+ check_task =
+ GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL);
+}
+
+
+static int
+check ()
+{
+ unsigned int failed;
+
+ char *const argv[] = {
+ "test-gnunet-daemon-hostlist-learning",
+ "-c", "learning_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
+ "test-gnunet-daemon-hostlist-learning", "nohelp", options,
+ &run, NULL);
+ failed = GNUNET_NO;
+ if (timeout == GNUNET_YES)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase timeout\n");
+ failed = GNUNET_YES;
+ }
+ if (adv_arrived != GNUNET_YES)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Learning peer did not receive advertisement from server\n");
+ failed = GNUNET_YES;
+ }
+ if (learned_hostlist_saved == GNUNET_NO)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Advertised hostlist was not saved in datastore\n");
+ failed = GNUNET_YES;
+ }
+ if (learned_hostlist_downloaded == GNUNET_NO)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Advertised hostlist could not be downloaded from server\n");
+ failed = GNUNET_YES;
+ }
+ if (adv_sent == GNUNET_NO)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Advertised was not sent from server to client\n");
+ failed = GNUNET_YES;
+ }
+ if (GNUNET_YES == failed)
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
+ GNUNET_log_setup ("test-gnunet-daemon-hostlist",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+#if !WINDOWS
+ system ("gnunet-peerinfo -s -c test_learning_adv_peer.conf > /dev/null");
+ system ("gnunet-peerinfo -s -c test_learning_learn_peer.conf > /dev/null");
+#else
+ system ("gnunet-peerinfo -s -c test_learning_adv_peer.conf > NUL");
+ system ("gnunet-peerinfo -s -c test_learning_learn_peer.conf > NUL");
+#endif
+ ret = check ();
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
+ if (GNUNET_YES == GNUNET_DISK_file_test ("hostlists_learn_peer.file"))
+ {
+ if (0 == UNLINK ("hostlists_learn_peer.file"))
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Hostlist file hostlists_learn_peer.file was removed\n");
+ }
+ return ret;
+}
+
+/* end of test_gnunet_daemon_hostlist.c */
diff --git a/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf b/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf
new file mode 100644
index 0000000..535b60e
--- /dev/null
+++ b/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf
@@ -0,0 +1,43 @@
+@INLINE@ test_hostlist_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-hostlist-peer-1/
+DEFAULTCONFIG = test_gnunet_daemon_hostlist_peer1.conf
+
+[transport-tcp]
+PORT = 12968
+
+[arm]
+PORT = 12966
+DEFAULTSERVICES = hostlist topology
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12967
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12964
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12969
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12965
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+DEBUG = NO
+
+[core]
+PORT = 12970
+UNIXPATH = /tmp/gnunet-p1-service-core.sock
+
+[hostlist]
+HTTPPORT = 12980
+HOSTLISTFILE = hostlists_peer1.file
+OPTIONS = -b -p
+SERVERS = http://localhost:12981/
+
+PORT = 12971
+UNIXPATH = /tmp/gnunet-p1-service-ats.sock
+
diff --git a/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf b/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf
new file mode 100644
index 0000000..41862da
--- /dev/null
+++ b/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf
@@ -0,0 +1,43 @@
+@INLINE@ test_hostlist_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-hostlist-peer-2/
+DEFAULTCONFIG = test_gnunet_daemon_hostlist_peer2.conf
+
+[transport-tcp]
+PORT = 22968
+
+[arm]
+PORT = 22966
+DEFAULTSERVICES = hostlist topology
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 22967
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 22964
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 22969
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 22965
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+[core]
+PORT = 22970
+UNIXPATH = /tmp/gnunet-p2-service-core.sock
+
+[hostlist]
+HTTPPORT = 12981
+HOSTLISTFILE = hostlists_peer2.file
+OPTIONS = -b -p
+SERVERS = http://localhost:12980/
+
+[ats]
+PORT = 22971
+UNIXPATH = /tmp/gnunet-p2-service-ats.sock
+
diff --git a/src/hostlist/test_gnunet_daemon_hostlist_reconnect.c b/src/hostlist/test_gnunet_daemon_hostlist_reconnect.c
new file mode 100644
index 0000000..a991557
--- /dev/null
+++ b/src/hostlist/test_gnunet_daemon_hostlist_reconnect.c
@@ -0,0 +1,266 @@
+/*
+ This file is part of GNUnet
+ (C) 2010 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 hostlist/test_gnunet_daemon_hostlist_reconnect.c
+ * @brief test for gnunet_daemon_hostslist.c; tries to re-start the peers
+ * and connect a second time
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_transport_service.h"
+
+#define VERBOSE GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150)
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+struct PeerContext
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_TRANSPORT_Handle *th;
+ struct GNUNET_MessageHeader *hello;
+ struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
+#if START_ARM
+ struct GNUNET_OS_Process *arm_proc;
+#endif
+};
+
+static struct PeerContext p1;
+
+static struct PeerContext p2;
+
+
+static void
+clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (NULL != p1.ghh)
+ {
+ GNUNET_TRANSPORT_get_hello_cancel (p1.ghh);
+ p1.ghh = NULL;
+ }
+ if (p1.th != NULL)
+ {
+ GNUNET_TRANSPORT_disconnect (p1.th);
+ p1.th = NULL;
+ }
+ if (NULL != p2.ghh)
+ {
+ GNUNET_TRANSPORT_get_hello_cancel (p2.ghh);
+ p2.ghh = NULL;
+ }
+ if (p2.th != NULL)
+ {
+ GNUNET_TRANSPORT_disconnect (p2.th);
+ p2.th = NULL;
+ }
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Timeout, give up.
+ */
+static void
+timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout trying to connect peers, test failed.\n");
+ clean_up (NULL, tc);
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param peer the peer that connected
+ * @param latency current latency of the connection
+ * @param distance in overlay hops, as given by transport plugin
+ */
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ if (peer == NULL)
+ return;
+#if VERBOSE
+ FPRINTF (stderr, "Peer %s connected\n", GNUNET_i2s (peer));
+#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n");
+ ok = 0;
+ if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (timeout_task);
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_SCHEDULER_add_now (&clean_up, NULL);
+}
+
+
+static void
+process_hello (void *cls, const struct GNUNET_MessageHeader *message)
+{
+ struct PeerContext *p = cls;
+
+ GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
+ p->ghh = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received HELLO, starting hostlist service.\n");
+}
+
+
+static void
+setup_peer (struct PeerContext *p, const char *cfgname)
+{
+ p->cfg = GNUNET_CONFIGURATION_create ();
+#if START_ARM
+ p->arm_proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
+ "gnunet-service-arm",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ "-c", cfgname, NULL);
+#endif
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+ p->th =
+ GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, &notify_connect, NULL);
+ GNUNET_assert (p->th != NULL);
+ p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p);
+}
+
+
+static void
+waitpid_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PeerContext *p = cls;
+
+#if START_ARM
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n");
+ if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n",
+ GNUNET_OS_process_get_pid (p->arm_proc));
+ GNUNET_OS_process_close (p->arm_proc);
+ p->arm_proc = NULL;
+#endif
+ GNUNET_CONFIGURATION_destroy (p->cfg);
+}
+
+
+static void
+stop_arm (struct PeerContext *p)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n");
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p);
+}
+
+
+/**
+ * Try again to connect to transport service.
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ stop_arm (&p1);
+ stop_arm (&p2);
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ GNUNET_assert (ok == 1);
+ ok++;
+ timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+ NULL);
+ setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf");
+ setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf");
+}
+
+
+static int
+check ()
+{
+ char *const argv[] = { "test-gnunet-daemon-hostlist",
+ "-c", "test_gnunet_daemon_hostlist_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
+ "test-gnunet-daemon-hostlist", "nohelp", options, &run,
+ &ok);
+ return ok;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+
+ int ret;
+
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-3");
+ GNUNET_log_setup ("test-gnunet-daemon-hostlist",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+ if (ret == 0)
+ {
+ FPRINTF (stderr, "%s", ".");
+ /* now do it again */
+ ret = check ();
+ FPRINTF (stderr, "%s", ".\n");
+ }
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
+ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-3");
+ return ret;
+}
+
+/* end of test_gnunet_daemon_hostlist_reconnect.c */
diff --git a/src/hostlist/test_hostlist_defaults.conf b/src/hostlist/test_hostlist_defaults.conf
new file mode 100644
index 0000000..5772250
--- /dev/null
+++ b/src/hostlist/test_hostlist_defaults.conf
@@ -0,0 +1,62 @@
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-hostlist/
+DEFAULTCONFIG = test_hostlist_default.conf
+
+[resolver]
+PORT = 12464
+
+[transport]
+PORT = 12465
+PLUGINS = tcp
+
+[arm]
+PORT = 12466
+DEFAULTSERVICES = hostlist
+
+[statistics]
+PORT = 12467
+
+[tcp]
+PORT = 12468
+
+[peerinfo]
+PORT = 12469
+
+[core]
+PORT = 12470
+
+[testing]
+WEAKRANDOM = YES
+
+[hostlist]
+HTTP-PROXY =
+
+[mesh]
+AUTOSTART = NO
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[fs]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[dv]
+AUTOSTART = NO
+
+[chat]
+AUTOSTART = NO
+
+[gns]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
diff --git a/src/hostlist/test_learning_adv_peer.conf b/src/hostlist/test_learning_adv_peer.conf
new file mode 100644
index 0000000..fe50bd5
--- /dev/null
+++ b/src/hostlist/test_learning_adv_peer.conf
@@ -0,0 +1,47 @@
+@INLINE@ test_hostlist_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-hostlist-peer-1/
+DEFAULTCONFIG = test_learning_adv_peer.conf
+
+[transport-tcp]
+PORT = 22968
+
+[arm]
+PORT = 22966
+DEFAULTSERVICES = topology hostlist
+UNIXPATH = /tmp/gnunet-hostlist-p2-service-arm.sock
+
+[statistics]
+PORT = 22967
+UNIXPATH = /tmp/gnunet-hostlist-p2-service-statistics.sock
+
+[resolver]
+PORT = 22964
+UNIXPATH = /tmp/gnunet-hostlist-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 22969
+UNIXPATH = /tmp/gnunet-hostlist-p2-service-peerinfo.sock
+
+[transport]
+PORT = 22965
+UNIXPATH = /tmp/gnunet-hostlist-p2-service-transport.sock
+
+[core]
+PORT = 22970
+UNIXPATH = /tmp/gnunet-hostlist-p2-service-core.sock
+
+[hostlist]
+HTTPPORT = 12981
+HOSTLISTFILE = hostlists_adv_peer.file
+OPTIONS = -p -a
+SERVERS = http://localhost:12981/
+EXTERNAL_DNS_NAME = localhost
+
+[dht]
+AUTOSTART = NO
+
+
+[ats]
+PORT = 22971
+UNIXPATH = /tmp/gnunet-ats-p2-service-core.sock
diff --git a/src/hostlist/test_learning_learn_peer.conf b/src/hostlist/test_learning_learn_peer.conf
new file mode 100644
index 0000000..0136d77
--- /dev/null
+++ b/src/hostlist/test_learning_learn_peer.conf
@@ -0,0 +1,46 @@
+@INLINE@ test_hostlist_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-hostlist-peer-2/
+DEFAULTCONFIG = test_learning_learn_peer.conf
+
+[transport-tcp]
+PORT = 12968
+
+[arm]
+PORT = 12966
+DEFAULTSERVICES = topology hostlist
+UNIXPATH = /tmp/gnunet-hostlist-p1-service-arm.sock
+
+[statistics]
+PORT = 12967
+UNIXPATH = /tmp/gnunet-hostlist-p1-service-statistics.sock
+
+[resolver]
+PORT = 12964
+UNIXPATH = /tmp/gnunet-hostlist-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12969
+UNIXPATH = /tmp/gnunet-hostlist-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12965
+UNIXPATH = /tmp/gnunet-hostlist-p1-service-transport.sock
+
+[core]
+PORT = 12970
+UNIXPATH = /tmp/gnunet-hostlist-p1-service-core.sock
+
+[hostlist]
+HTTPPORT = 12980
+HOSTLISTFILE = hostlists_learn_peer.file
+OPTIONS = -b -e
+SERVERS = http://localhost:12981/
+
+[dht]
+AUTOSTART = NO
+
+
+[ats]
+PORT = 12971
+UNIXPATH = /tmp/gnunet-ats-p1-service-core.sock
diff --git a/src/hostlist/test_learning_learn_peer2.conf b/src/hostlist/test_learning_learn_peer2.conf
new file mode 100644
index 0000000..4fd54bb
--- /dev/null
+++ b/src/hostlist/test_learning_learn_peer2.conf
@@ -0,0 +1,39 @@
+@INLINE@ test_hostlist_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-hostlist-peer-3/
+DEFAULTCONFIG = test_learning_learn_peer2.conf
+
+[transport-tcp]
+PORT = 32968
+
+[arm]
+PORT = 32966
+DEFAULTSERVICES = topology hostlist
+UNIXPATH = /tmp/gnunet-p3-service-arm.sock
+
+[statistics]
+PORT = 32967
+UNIXPATH = /tmp/gnunet-p3-service-statistics.sock
+
+[resolver]
+PORT = 32964
+UNIXPATH = /tmp/gnunet-p3-service-resolver.sock
+
+[peerinfo]
+PORT = 32969
+UNIXPATH = /tmp/gnunet-p3-service-peerinfo.sock
+
+[transport]
+PORT = 32965
+UNIXPATH = /tmp/gnunet-p3-service-transport.sock
+
+[core]
+PORT = 32970
+UNIXPATH = /tmp/gnunet-p3-service-core.sock
+
+[hostlist]
+HTTPPORT = 32980
+HOSTLISTFILE = hostlists_learn_peer2.file
+OPTIONS = -b -e
+SERVERS = http://localhost:12981/
+