aboutsummaryrefslogtreecommitdiff
path: root/src/ats
diff options
context:
space:
mode:
Diffstat (limited to 'src/ats')
-rw-r--r--src/ats/Makefile.am121
-rw-r--r--src/ats/Makefile.in1015
-rw-r--r--src/ats/ats.conf.in24
-rw-r--r--src/ats/ats.h243
-rw-r--r--src/ats/ats_api_performance.c645
-rw-r--r--src/ats/ats_api_scheduling.c1177
-rw-r--r--src/ats/gnunet-service-ats.c182
-rw-r--r--src/ats/gnunet-service-ats.h38
-rw-r--r--src/ats/gnunet-service-ats_addresses.c805
-rw-r--r--src/ats/gnunet-service-ats_addresses.h151
-rw-r--r--src/ats/gnunet-service-ats_addresses_mlp.c1736
-rw-r--r--src/ats/gnunet-service-ats_addresses_mlp.h394
-rw-r--r--src/ats/gnunet-service-ats_performance.c316
-rw-r--r--src/ats/gnunet-service-ats_performance.h123
-rw-r--r--src/ats/gnunet-service-ats_reservations.c157
-rw-r--r--src/ats/gnunet-service-ats_reservations.h75
-rw-r--r--src/ats/gnunet-service-ats_scheduling.c409
-rw-r--r--src/ats/gnunet-service-ats_scheduling.h158
-rw-r--r--src/ats/perf_ats_mlp.c138
-rw-r--r--src/ats/test_ats_api.conf24
-rw-r--r--src/ats/test_ats_api_scheduling.c264
-rw-r--r--src/ats/test_ats_mlp.c199
-rw-r--r--src/ats/test_ats_mlp_averaging.c182
23 files changed, 8576 insertions, 0 deletions
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am
new file mode 100644
index 0000000..f4056fa
--- /dev/null
+++ b/src/ats/Makefile.am
@@ -0,0 +1,121 @@
+INCLUDES = -I$(top_srcdir)/src/include
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+pkgcfg_DATA = \
+ ats.conf
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS = -fprofile-arcs -ftest-coverage
+endif
+
+if HAVE_LIBGLPK
+ GN_LIBGLPK = -lglpk
+ GN_MLP_SRC = gnunet-service-ats_addresses_mlp.c gnunet-service-ats_addresses_mlp.h
+ GN_MLP_TEST = test_ats_mlp
+ GN_MLP_TEST_AVG = test_ats_mlp_averaging
+ GN_MLP_PERF = perf_ats_mlp
+endif
+
+lib_LTLIBRARIES = libgnunetats.la
+
+libgnunetats_la_SOURCES = \
+ ats_api_scheduling.c \
+ ats_api_performance.c
+
+libgnunetats_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunetats_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) \
+ -version-info 1:0:1
+
+
+bin_PROGRAMS = \
+ gnunet-service-ats
+
+gnunet_service_ats_SOURCES = \
+ gnunet-service-ats.c gnunet-service-ats.h\
+ gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \
+ $(GN_MLP_SRC) \
+ gnunet-service-ats_performance.c gnunet-service-ats_performance.h \
+ gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \
+ gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h
+gnunet_service_ats_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBGLPK) \
+ $(GN_LIBINTL)
+
+
+check_PROGRAMS = \
+ test_ats_api_scheduling \
+ $(GN_MLP_TEST) \
+ $(GN_MLP_TEST_AVG) \
+ $(GN_MLP_PERF)
+# test_ats_api_scheduling_get_type
+# test_ats_api_bandwidth_consumption
+
+if ENABLE_TEST_RUN
+TESTS = $(check_PROGRAMS)
+endif
+
+if HAVE_LIBGLPK
+test_ats_mlp_SOURCES = \
+ $(GN_MLP_SRC) \
+ test_ats_mlp.c
+test_ats_mlp_LDADD = \
+ $(GN_LIBGLPK) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
+test_ats_mlp_averaging_SOURCES = \
+ $(GN_MLP_SRC) \
+ test_ats_mlp_averaging.c
+test_ats_mlp_averaging_LDADD = \
+ $(GN_LIBGLPK) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
+perf_ats_mlp_SOURCES = \
+ $(GN_MLP_SRC) \
+ perf_ats_mlp.c
+perf_ats_mlp_LDADD = \
+ $(GN_LIBGLPK) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la
+endif
+
+test_ats_api_scheduling_SOURCES = \
+ test_ats_api_scheduling.c
+test_ats_api_scheduling_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/ats/libgnunetats.la
+
+#test_ats_api_scheduling_get_type_SOURCES = \
+# test_ats_api_scheduling_get_type.c
+#test_ats_api_scheduling_get_type_LDADD = \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/ats/libgnunetats.la
+
+#test_ats_api_bandwidth_consumption_SOURCES = \
+# test_ats_api_bandwidth_consumption.c
+#test_ats_api_bandwidth_consumption_LDADD = \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/ats/libgnunetats.la
+
+#test_ats_api_update_address_SOURCES = \
+# test_ats_api_update_address.c
+#test_ats_api_update_address_LDADD = \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/ats/libgnunetats.la
+
+
+EXTRA_DIST = \
+ ats.h \
+ test_ats_api.conf
+
diff --git a/src/ats/Makefile.in b/src/ats/Makefile.in
new file mode 100644
index 0000000..26610e1
--- /dev/null
+++ b/src/ats/Makefile.in
@@ -0,0 +1,1015 @@
+# 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-service-ats$(EXEEXT)
+check_PROGRAMS = test_ats_api_scheduling$(EXEEXT) $(am__EXEEXT_1) \
+ $(am__EXEEXT_2) $(am__EXEEXT_3)
+subdir = src/ats
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/ats.conf.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \
+ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \
+ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/gnunet_config.h
+CONFIG_CLEAN_FILES = ats.conf
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(pkgcfgdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libgnunetats_la_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunetats_la_OBJECTS = ats_api_scheduling.lo \
+ ats_api_performance.lo
+libgnunetats_la_OBJECTS = $(am_libgnunetats_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libgnunetats_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libgnunetats_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@HAVE_LIBGLPK_TRUE@am__EXEEXT_1 = test_ats_mlp$(EXEEXT)
+@HAVE_LIBGLPK_TRUE@am__EXEEXT_2 = test_ats_mlp_averaging$(EXEEXT)
+@HAVE_LIBGLPK_TRUE@am__EXEEXT_3 = perf_ats_mlp$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+am__gnunet_service_ats_SOURCES_DIST = gnunet-service-ats.c \
+ gnunet-service-ats.h gnunet-service-ats_addresses.c \
+ gnunet-service-ats_addresses.h \
+ gnunet-service-ats_addresses_mlp.c \
+ gnunet-service-ats_addresses_mlp.h \
+ gnunet-service-ats_performance.c \
+ gnunet-service-ats_performance.h \
+ gnunet-service-ats_scheduling.c \
+ gnunet-service-ats_scheduling.h \
+ gnunet-service-ats_reservations.c \
+ gnunet-service-ats_reservations.h
+@HAVE_LIBGLPK_TRUE@am__objects_1 = \
+@HAVE_LIBGLPK_TRUE@ gnunet-service-ats_addresses_mlp.$(OBJEXT)
+am_gnunet_service_ats_OBJECTS = gnunet-service-ats.$(OBJEXT) \
+ gnunet-service-ats_addresses.$(OBJEXT) $(am__objects_1) \
+ gnunet-service-ats_performance.$(OBJEXT) \
+ gnunet-service-ats_scheduling.$(OBJEXT) \
+ gnunet-service-ats_reservations.$(OBJEXT)
+gnunet_service_ats_OBJECTS = $(am_gnunet_service_ats_OBJECTS)
+am__DEPENDENCIES_1 =
+gnunet_service_ats_DEPENDENCIES = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__perf_ats_mlp_SOURCES_DIST = gnunet-service-ats_addresses_mlp.c \
+ gnunet-service-ats_addresses_mlp.h perf_ats_mlp.c
+@HAVE_LIBGLPK_TRUE@am_perf_ats_mlp_OBJECTS = $(am__objects_1) \
+@HAVE_LIBGLPK_TRUE@ perf_ats_mlp.$(OBJEXT)
+perf_ats_mlp_OBJECTS = $(am_perf_ats_mlp_OBJECTS)
+@HAVE_LIBGLPK_TRUE@perf_ats_mlp_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la
+am_test_ats_api_scheduling_OBJECTS = \
+ test_ats_api_scheduling.$(OBJEXT)
+test_ats_api_scheduling_OBJECTS = \
+ $(am_test_ats_api_scheduling_OBJECTS)
+test_ats_api_scheduling_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/ats/libgnunetats.la
+am__test_ats_mlp_SOURCES_DIST = gnunet-service-ats_addresses_mlp.c \
+ gnunet-service-ats_addresses_mlp.h test_ats_mlp.c
+@HAVE_LIBGLPK_TRUE@am_test_ats_mlp_OBJECTS = $(am__objects_1) \
+@HAVE_LIBGLPK_TRUE@ test_ats_mlp.$(OBJEXT)
+test_ats_mlp_OBJECTS = $(am_test_ats_mlp_OBJECTS)
+@HAVE_LIBGLPK_TRUE@test_ats_mlp_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la
+am__test_ats_mlp_averaging_SOURCES_DIST = \
+ gnunet-service-ats_addresses_mlp.c \
+ gnunet-service-ats_addresses_mlp.h test_ats_mlp_averaging.c
+@HAVE_LIBGLPK_TRUE@am_test_ats_mlp_averaging_OBJECTS = \
+@HAVE_LIBGLPK_TRUE@ $(am__objects_1) \
+@HAVE_LIBGLPK_TRUE@ test_ats_mlp_averaging.$(OBJEXT)
+test_ats_mlp_averaging_OBJECTS = $(am_test_ats_mlp_averaging_OBJECTS)
+@HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_DEPENDENCIES = \
+@HAVE_LIBGLPK_TRUE@ $(am__DEPENDENCIES_1) \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.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 = $(libgnunetats_la_SOURCES) $(gnunet_service_ats_SOURCES) \
+ $(perf_ats_mlp_SOURCES) $(test_ats_api_scheduling_SOURCES) \
+ $(test_ats_mlp_SOURCES) $(test_ats_mlp_averaging_SOURCES)
+DIST_SOURCES = $(libgnunetats_la_SOURCES) \
+ $(am__gnunet_service_ats_SOURCES_DIST) \
+ $(am__perf_ats_mlp_SOURCES_DIST) \
+ $(test_ats_api_scheduling_SOURCES) \
+ $(am__test_ats_mlp_SOURCES_DIST) \
+ $(am__test_ats_mlp_averaging_SOURCES_DIST)
+DATA = $(pkgcfg_DATA)
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ARGZ_H = @ARGZ_H@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_INTERFACE = @DEFAULT_INTERFACE@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLDIR = @DLLDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXT_LIBS = @EXT_LIBS@
+EXT_LIB_PATH = @EXT_LIB_PATH@
+FGREP = @FGREP@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUNETDNS_GROUP = @GNUNETDNS_GROUP@
+GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@
+GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@
+GN_INTLINCL = @GN_INTLINCL@
+GN_LIBINTL = @GN_LIBINTL@
+GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@
+GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@
+GN_USER_HOME_DIR = @GN_USER_HOME_DIR@
+GREP = @GREP@
+HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@
+INCLTDL = @INCLTDL@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBADD_DL = @LIBADD_DL@
+LIBADD_DLD_LINK = @LIBADD_DLD_LINK@
+LIBADD_DLOPEN = @LIBADD_DLOPEN@
+LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBLTDL = @LIBLTDL@
+LIBOBJS = @LIBOBJS@
+LIBPREFIX = @LIBPREFIX@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNISTRING = @LIBUNISTRING@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTDLDEPS = @LTDLDEPS@
+LTDLINCL = @LTDLINCL@
+LTDLOPEN = @LTDLOPEN@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBUNISTRING = @LTLIBUNISTRING@
+LT_CONFIG_H = @LT_CONFIG_H@
+LT_DLLOADERS = @LT_DLLOADERS@
+LT_DLPREOPEN = @LT_DLPREOPEN@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJCFLAGS = @OBJCFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@
+POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@
+POSUB = @POSUB@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@
+SQLITE_LDFLAGS = @SQLITE_LDFLAGS@
+STRIP = @STRIP@
+SUDO_BINARY = @SUDO_BINARY@
+UNIXONLY = @UNIXONLY@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+ltdl_LIBOBJS = @ltdl_LIBOBJS@
+ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sys_symbol_underscore = @sys_symbol_underscore@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(top_srcdir)/src/include
+pkgcfgdir = $(pkgdatadir)/config.d/
+pkgcfg_DATA = \
+ ats.conf
+
+@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage
+@HAVE_LIBGLPK_TRUE@GN_LIBGLPK = -lglpk
+@HAVE_LIBGLPK_TRUE@GN_MLP_SRC = gnunet-service-ats_addresses_mlp.c gnunet-service-ats_addresses_mlp.h
+@HAVE_LIBGLPK_TRUE@GN_MLP_TEST = test_ats_mlp
+@HAVE_LIBGLPK_TRUE@GN_MLP_TEST_AVG = test_ats_mlp_averaging
+@HAVE_LIBGLPK_TRUE@GN_MLP_PERF = perf_ats_mlp
+lib_LTLIBRARIES = libgnunetats.la
+libgnunetats_la_SOURCES = \
+ ats_api_scheduling.c \
+ ats_api_performance.c
+
+libgnunetats_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunetats_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) \
+ -version-info 1:0:1
+
+gnunet_service_ats_SOURCES = \
+ gnunet-service-ats.c gnunet-service-ats.h\
+ gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \
+ $(GN_MLP_SRC) \
+ gnunet-service-ats_performance.c gnunet-service-ats_performance.h \
+ gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \
+ gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h
+
+gnunet_service_ats_LDADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBGLPK) \
+ $(GN_LIBINTL)
+
+# test_ats_api_scheduling_get_type
+# test_ats_api_bandwidth_consumption
+@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS)
+@HAVE_LIBGLPK_TRUE@test_ats_mlp_SOURCES = \
+@HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \
+@HAVE_LIBGLPK_TRUE@ test_ats_mlp.c
+
+@HAVE_LIBGLPK_TRUE@test_ats_mlp_LDADD = \
+@HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
+@HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_SOURCES = \
+@HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \
+@HAVE_LIBGLPK_TRUE@ test_ats_mlp_averaging.c
+
+@HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_LDADD = \
+@HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
+@HAVE_LIBGLPK_TRUE@perf_ats_mlp_SOURCES = \
+@HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \
+@HAVE_LIBGLPK_TRUE@ perf_ats_mlp.c
+
+@HAVE_LIBGLPK_TRUE@perf_ats_mlp_LDADD = \
+@HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
+test_ats_api_scheduling_SOURCES = \
+ test_ats_api_scheduling.c
+
+test_ats_api_scheduling_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/ats/libgnunetats.la
+
+
+#test_ats_api_scheduling_get_type_SOURCES = \
+# test_ats_api_scheduling_get_type.c
+#test_ats_api_scheduling_get_type_LDADD = \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/ats/libgnunetats.la
+
+#test_ats_api_bandwidth_consumption_SOURCES = \
+# test_ats_api_bandwidth_consumption.c
+#test_ats_api_bandwidth_consumption_LDADD = \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/ats/libgnunetats.la
+
+#test_ats_api_update_address_SOURCES = \
+# test_ats_api_update_address.c
+#test_ats_api_update_address_LDADD = \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/ats/libgnunetats.la
+EXTRA_DIST = \
+ ats.h \
+ test_ats_api.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/ats/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/ats/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):
+ats.conf: $(top_builddir)/config.status $(srcdir)/ats.conf.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgnunetats.la: $(libgnunetats_la_OBJECTS) $(libgnunetats_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunetats_la_LINK) -rpath $(libdir) $(libgnunetats_la_OBJECTS) $(libgnunetats_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+gnunet-service-ats$(EXEEXT): $(gnunet_service_ats_OBJECTS) $(gnunet_service_ats_DEPENDENCIES)
+ @rm -f gnunet-service-ats$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_service_ats_OBJECTS) $(gnunet_service_ats_LDADD) $(LIBS)
+perf_ats_mlp$(EXEEXT): $(perf_ats_mlp_OBJECTS) $(perf_ats_mlp_DEPENDENCIES)
+ @rm -f perf_ats_mlp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(perf_ats_mlp_OBJECTS) $(perf_ats_mlp_LDADD) $(LIBS)
+test_ats_api_scheduling$(EXEEXT): $(test_ats_api_scheduling_OBJECTS) $(test_ats_api_scheduling_DEPENDENCIES)
+ @rm -f test_ats_api_scheduling$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_ats_api_scheduling_OBJECTS) $(test_ats_api_scheduling_LDADD) $(LIBS)
+test_ats_mlp$(EXEEXT): $(test_ats_mlp_OBJECTS) $(test_ats_mlp_DEPENDENCIES)
+ @rm -f test_ats_mlp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_ats_mlp_OBJECTS) $(test_ats_mlp_LDADD) $(LIBS)
+test_ats_mlp_averaging$(EXEEXT): $(test_ats_mlp_averaging_OBJECTS) $(test_ats_mlp_averaging_DEPENDENCIES)
+ @rm -f test_ats_mlp_averaging$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_ats_mlp_averaging_OBJECTS) $(test_ats_mlp_averaging_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ats_api_performance.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ats_api_scheduling.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_addresses.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_addresses_mlp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_performance.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_reservations.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_scheduling.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_ats_mlp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_api_scheduling.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_mlp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_mlp_averaging.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgcfgDATA: $(pkgcfg_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)"
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \
+ done
+
+uninstall-pkgcfgDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ echo "$$grn$$dashes"; \
+ else \
+ echo "$$red$$dashes"; \
+ fi; \
+ echo "$$banner"; \
+ test -z "$$skipped" || echo "$$skipped"; \
+ test -z "$$report" || echo "$$report"; \
+ echo "$$dashes$$std"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgcfgDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-pkgcfgDATA
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-pkgcfgDATA
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/ats/ats.conf.in b/src/ats/ats.conf.in
new file mode 100644
index 0000000..6ea0d41
--- /dev/null
+++ b/src/ats/ats.conf.in
@@ -0,0 +1,24 @@
+[ats]
+AUTOSTART = YES
+@UNIXONLY@ PORT = 2098
+HOSTNAME = localhost
+HOME = $SERVICEHOME
+CONFIG = $DEFAULTCONFIG
+BINARY = gnunet-service-ats
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+UNIXPATH = /tmp/gnunet-service-ats.sock
+UNIX_MATCH_UID = YES
+UNIX_MATCH_GID = YES
+MLP = NO
+WAN_QUOTA_IN = 65536
+WAN_QUOTA_OUT = 65536
+# ATS options
+DUMP_MLP = NO
+DUMP_SOLUTION = NO
+DUMP_OVERWRITE = NO
+DUMP_MIN_PEERS = 0
+DUMP_MIN_ADDRS = 0
+DUMP_OVERWRITE = NO
+ATS_MIN_INTERVAL = 15000
+ATS_EXEC_INTERVAL = 30000
diff --git a/src/ats/ats.h b/src/ats/ats.h
new file mode 100644
index 0000000..30ca295
--- /dev/null
+++ b/src/ats/ats.h
@@ -0,0 +1,243 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/ats.h
+ * @brief automatic transport selection messages
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+ */
+#ifndef ATS_H
+#define ATS_H
+
+#include "gnunet_util_lib.h"
+
+
+enum StartFlag
+{
+
+ START_FLAG_SCHEDULING = 0,
+
+ START_FLAG_PERFORMANCE_WITH_PIC = 1,
+
+ START_FLAG_PERFORMANCE_NO_PIC = 2
+};
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct ClientStartMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * NBO value of an 'enum StartFlag'.
+ */
+ uint32_t start_flag GNUNET_PACKED;
+};
+
+
+struct RequestAddressMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ uint32_t reserved GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+};
+
+
+struct AddressUpdateMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ uint32_t ats_count GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+
+ uint16_t address_length GNUNET_PACKED;
+
+ uint16_t plugin_name_length GNUNET_PACKED;
+
+ uint32_t session_id GNUNET_PACKED;
+
+ /* followed by:
+ * - struct GNUNET_ATS_Information [ats_count];
+ * - char address[address_length]
+ * - char plugin_name[plugin_name_length] (including '\0'-termination).
+ */
+
+};
+
+struct AddressUseMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ struct GNUNET_PeerIdentity peer;
+
+ uint16_t in_use GNUNET_PACKED;
+
+ uint16_t address_length GNUNET_PACKED;
+
+ uint16_t plugin_name_length GNUNET_PACKED;
+
+ uint32_t session_id GNUNET_PACKED;
+
+ /* followed by:
+ * - char address[address_length]
+ * - char plugin_name[plugin_name_length] (including '\0'-termination).
+ */
+
+};
+
+
+struct AddressDestroyedMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ uint32_t reserved GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+
+ uint16_t address_length GNUNET_PACKED;
+
+ uint16_t plugin_name_length GNUNET_PACKED;
+
+ uint32_t session_id GNUNET_PACKED;
+
+ /* followed by:
+ * - char address[address_length]
+ * - char plugin_name[plugin_name_length] (including '\0'-termination).
+ */
+
+};
+
+
+struct AddressSuggestionMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ uint32_t ats_count GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+
+ uint16_t address_length GNUNET_PACKED;
+
+ uint16_t plugin_name_length GNUNET_PACKED;
+
+ uint32_t session_id GNUNET_PACKED;
+
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
+
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
+
+ /* followed by:
+ * - struct GNUNET_ATS_Information [ats_count];
+ * - char address[address_length]
+ * - char plugin_name[plugin_name_length] (including '\0'-termination).
+ */
+
+};
+
+
+struct PeerInformationMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ uint32_t ats_count GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+
+ uint16_t address_length GNUNET_PACKED;
+
+ uint16_t plugin_name_length GNUNET_PACKED;
+
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
+
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
+
+ /* followed by:
+ * - struct GNUNET_ATS_Information [ats_count];
+ * - char address[address_length]
+ * - char plugin_name[plugin_name_length] (including '\0'-termination).
+ */
+
+};
+
+
+struct ReservationRequestMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ int32_t amount GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+};
+
+
+/**
+ * Message sent by ATS service to client to confirm that it is done
+ * using the given session ID.
+ */
+struct SessionReleaseMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ uint32_t session_id GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+};
+
+
+struct ReservationResultMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ int32_t amount GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+
+ struct GNUNET_TIME_RelativeNBO res_delay;
+};
+
+struct PreferenceInformation
+{
+
+ uint32_t preference_kind GNUNET_PACKED;
+
+ float preference_value GNUNET_PACKED;
+
+};
+
+
+struct ChangePreferenceMessage
+{
+ struct GNUNET_MessageHeader header;
+
+ uint32_t num_preferences GNUNET_PACKED;
+
+ struct GNUNET_PeerIdentity peer;
+
+ /* followed by 'num_preferences'
+ * struct PreferenceInformation values */
+};
+GNUNET_NETWORK_STRUCT_END
+
+
+
+#endif
diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c
new file mode 100644
index 0000000..848c7ec
--- /dev/null
+++ b/src/ats/ats_api_performance.c
@@ -0,0 +1,645 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/ats_api_performance.c
+ * @brief automatic transport selection and outbound bandwidth determination
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+ */
+#include "platform.h"
+#include "gnunet_ats_service.h"
+#include "ats.h"
+
+
+/**
+ * Message in linked list we should send to the ATS service. The
+ * actual binary message follows this struct.
+ */
+struct PendingMessage
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct PendingMessage *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct PendingMessage *prev;
+
+ /**
+ * Size of the message.
+ */
+ size_t size;
+
+ /**
+ * Is this the 'ATS_START' message?
+ */
+ int is_init;
+};
+
+
+/**
+ * Linked list of pending reservations.
+ */
+struct GNUNET_ATS_ReservationContext
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct GNUNET_ATS_ReservationContext *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct GNUNET_ATS_ReservationContext *prev;
+
+ /**
+ * Target peer.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * Desired reservation
+ */
+ int32_t size;
+
+ /**
+ * Function to call on result.
+ */
+ GNUNET_ATS_ReservationCallback rcb;
+
+ /**
+ * Closure for 'rcb'
+ */
+ void *rcb_cls;
+
+ /**
+ * Do we need to undo this reservation if it succeeded? Set to
+ * GNUNET_YES if a reservation is cancelled. (at that point, 'info'
+ * is also set to NULL; however, info will ALSO be NULL for the
+ * reservation context that is created to undo the original request,
+ * so 'info' being NULL cannot be used to check if undo is
+ * required).
+ */
+ int undo;
+};
+
+
+/**
+ * ATS Handle to obtain and/or modify performance information.
+ */
+struct GNUNET_ATS_PerformanceHandle
+{
+
+ /**
+ * Our configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Callback to invoke on performance changes.
+ */
+ GNUNET_ATS_PeerInformationCallback infocb;
+
+ /**
+ * Closure for 'infocb'.
+ */
+ void *infocb_cls;
+
+ /**
+ * Connection to ATS service.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Head of list of messages for the ATS service.
+ */
+ struct PendingMessage *pending_head;
+
+ /**
+ * Tail of list of messages for the ATS service
+ */
+ struct PendingMessage *pending_tail;
+
+ /**
+ * Head of linked list of pending reservation requests.
+ */
+ struct GNUNET_ATS_ReservationContext *reservation_head;
+
+ /**
+ * Tail of linked list of pending reservation requests.
+ */
+ struct GNUNET_ATS_ReservationContext *reservation_tail;
+
+ /**
+ * Current request for transmission to ATS.
+ */
+ struct GNUNET_CLIENT_TransmitHandle *th;
+
+ /**
+ * Task to trigger reconnect.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier task;
+
+};
+
+
+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param ph handle to use to re-connect.
+ */
+static void
+reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
+
+
+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param cls handle to use to re-connect.
+ * @param tc scheduler context
+ */
+static void
+reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_ATS_PerformanceHandle *ph = cls;
+
+ ph->task = GNUNET_SCHEDULER_NO_TASK;
+ reconnect (ph);
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param ph handle to use
+ */
+static void
+do_transmit (struct GNUNET_ATS_PerformanceHandle *ph);
+
+
+/**
+ * We can now transmit a message to ATS. Do it.
+ *
+ * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
+ * @param size number of bytes we can transmit to ATS
+ * @param buf where to copy the messages
+ * @return number of bytes copied into buf
+ */
+static size_t
+transmit_message_to_ats (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_ATS_PerformanceHandle *ph = cls;
+ struct PendingMessage *p;
+ size_t ret;
+ char *cbuf;
+
+ ph->th = NULL;
+ ret = 0;
+ cbuf = buf;
+ while ((NULL != (p = ph->pending_head)) && (p->size <= size))
+ {
+ memcpy (&cbuf[ret], &p[1], p->size);
+ ret += p->size;
+ size -= p->size;
+ GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p);
+ GNUNET_free (p);
+ }
+ do_transmit (ph);
+ return ret;
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param ph handle to use
+ */
+static void
+do_transmit (struct GNUNET_ATS_PerformanceHandle *ph)
+{
+ struct PendingMessage *p;
+
+ if (NULL != ph->th)
+ return;
+ if (NULL == (p = ph->pending_head))
+ return;
+ if (NULL == ph->client)
+ return; /* currently reconnecting */
+ ph->th =
+ GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &transmit_message_to_ats,
+ ph);
+}
+
+
+/**
+ * We received a peer information message. Validate and process it.
+ *
+ * @param ph our context with the callback
+ * @param msg the message
+ * @return GNUNET_OK if the message was well-formed
+ */
+static int
+process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph,
+ const struct GNUNET_MessageHeader *msg)
+{
+ const struct PeerInformationMessage *pi;
+ const struct GNUNET_ATS_Information *atsi;
+ const char *plugin_address;
+ const char *plugin_name;
+ struct GNUNET_HELLO_Address address;
+ uint16_t plugin_address_length;
+ uint16_t plugin_name_length;
+ uint32_t ats_count;
+
+ if (ph->infocb == NULL)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (ntohs (msg->size) < sizeof (struct PeerInformationMessage))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ pi = (const struct PeerInformationMessage *) msg;
+ ats_count = ntohl (pi->ats_count);
+ plugin_address_length = ntohs (pi->address_length);
+ plugin_name_length = ntohs (pi->plugin_name_length);
+ atsi = (const struct GNUNET_ATS_Information *) &pi[1];
+ plugin_address = (const char *) &atsi[ats_count];
+ plugin_name = &plugin_address[plugin_address_length];
+ if ((plugin_address_length + plugin_name_length +
+ ats_count * sizeof (struct GNUNET_ATS_Information) +
+ sizeof (struct PeerInformationMessage) != ntohs (msg->size)) ||
+ (ats_count >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
+ || (plugin_name[plugin_name_length - 1] != '\0'))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ address.peer = pi->peer;
+ address.address = plugin_address;
+ address.address_length = plugin_address_length;
+ address.transport_name = plugin_name;
+ ph->infocb (ph->infocb_cls, &address, pi->bandwidth_out, pi->bandwidth_in,
+ atsi, ats_count);
+ return GNUNET_OK;
+}
+
+
+/**
+ * We received a reservation result message. Validate and process it.
+ *
+ * @param ph our context with the callback
+ * @param msg the message
+ * @return GNUNET_OK if the message was well-formed
+ */
+static int
+process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph,
+ const struct GNUNET_MessageHeader *msg)
+{
+ const struct ReservationResultMessage *rr;
+ struct GNUNET_ATS_ReservationContext *rc;
+ int32_t amount;
+
+ if (ntohs (msg->size) < sizeof (struct ReservationResultMessage))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ rr = (const struct ReservationResultMessage *) msg;
+ amount = ntohl (rr->amount);
+ rc = ph->reservation_head;
+ if (0 != memcmp (&rr->peer, &rc->peer, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail, rc);
+ if ((amount == 0) || (rc->rcb != NULL))
+ {
+ /* tell client if not cancelled */
+ if (rc->rcb != NULL)
+ rc->rcb (rc->rcb_cls, &rr->peer, amount,
+ GNUNET_TIME_relative_ntoh (rr->res_delay));
+ GNUNET_free (rc);
+ return GNUNET_OK;
+ }
+ /* amount non-zero, but client cancelled, consider undo! */
+ if (GNUNET_YES != rc->undo)
+ {
+ GNUNET_free (rc);
+ return GNUNET_OK; /* do not try to undo failed undos or negative amounts */
+ }
+ GNUNET_free (rc);
+ (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Type of a function to call when we receive a message
+ * from the service.
+ *
+ * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_ATS_PerformanceHandle *ph = cls;
+
+ if (NULL == msg)
+ goto reconnect;
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION:
+ if (GNUNET_OK != process_pi_message (ph, msg))
+ goto reconnect;
+ break;
+ case GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT:
+ if (GNUNET_OK != process_rr_message (ph, msg))
+ goto reconnect;
+ break;
+ default:
+ GNUNET_break (0);
+ goto reconnect;
+ }
+ GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ return;
+reconnect:
+ GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO);
+ ph->client = NULL;
+ ph->task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
+ ph);
+}
+
+
+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param ph handle to use to re-connect.
+ */
+static void
+reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
+{
+ struct PendingMessage *p;
+ struct ClientStartMessage *init;
+
+ GNUNET_assert (NULL == ph->client);
+ ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg);
+ GNUNET_assert (NULL != ph->client);
+ GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init))
+ {
+ p = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct ClientStartMessage));
+ p->size = sizeof (struct ClientStartMessage);
+ p->is_init = GNUNET_YES;
+ init = (struct ClientStartMessage *) &p[1];
+ init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
+ init->header.size = htons (sizeof (struct ClientStartMessage));
+ init->start_flag =
+ htonl ((ph->infocb ==
+ NULL) ? START_FLAG_PERFORMANCE_NO_PIC :
+ START_FLAG_PERFORMANCE_WITH_PIC);
+ GNUNET_CONTAINER_DLL_insert (ph->pending_head, ph->pending_tail, p);
+ }
+ do_transmit (ph);
+}
+
+
+
+/**
+ * Get handle to access performance API of the ATS subsystem.
+ *
+ * @param cfg configuration to use
+ * @param infocb function to call on allocation changes, can be NULL
+ * @param infocb_cls closure for infocb
+ * @return ats performance context
+ */
+struct GNUNET_ATS_PerformanceHandle *
+GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_ATS_PeerInformationCallback infocb,
+ void *infocb_cls)
+{
+ struct GNUNET_ATS_PerformanceHandle *ph;
+
+ ph = GNUNET_malloc (sizeof (struct GNUNET_ATS_PerformanceHandle));
+ ph->cfg = cfg;
+ ph->infocb = infocb;
+ ph->infocb_cls = infocb_cls;
+ reconnect (ph);
+ return ph;
+}
+
+
+/**
+ * Client is done using the ATS performance subsystem, release resources.
+ *
+ * @param ph handle
+ */
+void
+GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph)
+{
+ struct PendingMessage *p;
+ struct GNUNET_ATS_ReservationContext *rc;
+
+ while (NULL != (p = ph->pending_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p);
+ GNUNET_free (p);
+ }
+ while (NULL != (rc = ph->reservation_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail,
+ rc);
+ GNUNET_break (NULL == rc->rcb);
+ GNUNET_free (rc);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != ph->task)
+ {
+ GNUNET_SCHEDULER_cancel (ph->task);
+ ph->task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != ph->client)
+ {
+ GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO);
+ ph->client = NULL;
+ }
+ GNUNET_free (ph);
+}
+
+
+/**
+ * Reserve inbound bandwidth from the given peer. ATS will look at
+ * the current amount of traffic we receive from the peer and ensure
+ * that the peer could add 'amount' of data to its stream.
+ *
+ * @param ph performance handle
+ * @param peer identifies the peer
+ * @param amount reserve N bytes for receiving, negative
+ * amounts can be used to undo a (recent) reservation;
+ * @param rcb function to call with the resulting reservation information
+ * @param rcb_cls closure for info
+ * @return NULL on error
+ * @deprecated will be replaced soon
+ */
+struct GNUNET_ATS_ReservationContext *
+GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph,
+ const struct GNUNET_PeerIdentity *peer,
+ int32_t amount,
+ GNUNET_ATS_ReservationCallback rcb, void *rcb_cls)
+{
+ struct GNUNET_ATS_ReservationContext *rc;
+ struct PendingMessage *p;
+ struct ReservationRequestMessage *m;
+
+ rc = GNUNET_malloc (sizeof (struct GNUNET_ATS_ReservationContext));
+ rc->size = amount;
+ rc->peer = *peer;
+ rc->rcb = rcb;
+ rc->rcb_cls = rcb_cls;
+ if ((rcb != NULL) && (amount > 0))
+ rc->undo = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head, ph->reservation_tail,
+ rc);
+
+ p = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct ReservationRequestMessage));
+ p->size = sizeof (struct ReservationRequestMessage);
+ p->is_init = GNUNET_NO;
+ m = (struct ReservationRequestMessage *) &p[1];
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST);
+ m->header.size = htons (sizeof (struct ReservationRequestMessage));
+ m->amount = htonl (amount);
+ m->peer = *peer;
+ GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
+ do_transmit (ph);
+ return rc;
+}
+
+
+/**
+ * Cancel request for reserving bandwidth.
+ *
+ * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call
+ */
+void
+GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc)
+{
+ rc->rcb = NULL;
+}
+
+
+/**
+ * Change preferences for the given peer. Preference changes are forgotten if peers
+ * disconnect.
+ *
+ * @param ph performance handle
+ * @param peer identifies the peer
+ * @param ... 0-terminated specification of the desired changes
+ */
+void
+GNUNET_ATS_change_preference (struct GNUNET_ATS_PerformanceHandle *ph,
+ const struct GNUNET_PeerIdentity *peer, ...)
+{
+ struct PendingMessage *p;
+ struct ChangePreferenceMessage *m;
+ size_t msize;
+ uint32_t count;
+ struct PreferenceInformation *pi;
+ va_list ap;
+ enum GNUNET_ATS_PreferenceKind kind;
+
+ count = 0;
+ va_start (ap, peer);
+ while (GNUNET_ATS_PREFERENCE_END !=
+ (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
+ {
+ switch (kind)
+ {
+ case GNUNET_ATS_PREFERENCE_BANDWIDTH:
+ count++;
+ (void) va_arg (ap, double);
+
+ break;
+ case GNUNET_ATS_PREFERENCE_LATENCY:
+ count++;
+ (void) va_arg (ap, double);
+
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ }
+ va_end (ap);
+ msize =
+ count * sizeof (struct PreferenceInformation) +
+ sizeof (struct ChangePreferenceMessage);
+ p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
+ p->size = msize;
+ p->is_init = GNUNET_NO;
+ m = (struct ChangePreferenceMessage *) &p[1];
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE);
+ m->header.size = htons (msize);
+ m->num_preferences = htonl (count);
+ m->peer = *peer;
+ pi = (struct PreferenceInformation *) &m[1];
+ count = 0;
+ va_start (ap, peer);
+ while (GNUNET_ATS_PREFERENCE_END !=
+ (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
+ {
+ pi[count].preference_kind = htonl (kind);
+ switch (kind)
+ {
+ case GNUNET_ATS_PREFERENCE_BANDWIDTH:
+ pi[count].preference_value = (float) va_arg (ap, double);
+
+ count++;
+ break;
+ case GNUNET_ATS_PREFERENCE_LATENCY:
+ pi[count].preference_value = (float) va_arg (ap, double);
+
+ count++;
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ }
+ va_end (ap);
+ GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
+ do_transmit (ph);
+}
+
+/* end of ats_api_performance.c */
diff --git a/src/ats/ats_api_scheduling.c b/src/ats/ats_api_scheduling.c
new file mode 100644
index 0000000..78e8d61
--- /dev/null
+++ b/src/ats/ats_api_scheduling.c
@@ -0,0 +1,1177 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/ats_api_scheduling.c
+ * @brief automatic transport selection and outbound bandwidth determination
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+ */
+#include "platform.h"
+#include "gnunet_ats_service.h"
+#include "ats.h"
+
+#define DEBUG_ATS GNUNET_EXTRA_LOGGING
+
+#define INTERFACE_PROCESSING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+/**
+ * Message in linked list we should send to the ATS service. The
+ * actual binary message follows this struct.
+ */
+struct PendingMessage
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct PendingMessage *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct PendingMessage *prev;
+
+ /**
+ * Size of the message.
+ */
+ size_t size;
+
+ /**
+ * Is this the 'ATS_START' message?
+ */
+ int is_init;
+};
+
+
+/**
+ * Information we track per session.
+ */
+struct SessionRecord
+{
+ /**
+ * Identity of the peer (just needed for error checking).
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * Session handle.
+ */
+ struct Session *session;
+
+ /**
+ * Set to GNUNET_YES if the slot is used.
+ */
+ int slot_used;
+};
+
+
+struct ATS_Network
+{
+ struct ATS_Network * next;
+
+ struct ATS_Network * prev;
+
+ struct sockaddr *network;
+ struct sockaddr *netmask;
+ socklen_t length;
+};
+
+
+
+/**
+ * Handle to the ATS subsystem for bandwidth/transport scheduling information.
+ */
+struct GNUNET_ATS_SchedulingHandle
+{
+
+ /**
+ * Our configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Callback to invoke on suggestions.
+ */
+ GNUNET_ATS_AddressSuggestionCallback suggest_cb;
+
+ /**
+ * Closure for 'suggest_cb'.
+ */
+ void *suggest_cb_cls;
+
+ /**
+ * Connection to ATS service.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Head of list of messages for the ATS service.
+ */
+ struct PendingMessage *pending_head;
+
+ /**
+ * Tail of list of messages for the ATS service
+ */
+ struct PendingMessage *pending_tail;
+
+ /**
+ * Current request for transmission to ATS.
+ */
+ struct GNUNET_CLIENT_TransmitHandle *th;
+
+ /**
+ * Head of network list
+ */
+ struct ATS_Network * net_head;
+
+ /**
+ * Tail of network list
+ */
+ struct ATS_Network * net_tail;
+
+
+ /**
+ * Array of session objects (we need to translate them to numbers and back
+ * for the protocol; the offset in the array is the session number on the
+ * network). Index 0 is always NULL and reserved to represent the NULL pointer.
+ * Unused entries are also NULL.
+ */
+ struct SessionRecord *session_array;
+
+ /**
+ * Task to trigger reconnect.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier task;
+
+ /**
+ * Task retrieving interfaces from the system
+ */
+
+ GNUNET_SCHEDULER_TaskIdentifier interface_task;
+
+
+ /**
+ * Size of the session array.
+ */
+ unsigned int session_array_size;
+
+ /**
+ * Should we reconnect to ATS due to some serious error?
+ */
+ int reconnect;
+};
+
+
+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param sh handle to use to re-connect.
+ */
+static void
+reconnect (struct GNUNET_ATS_SchedulingHandle *sh);
+
+
+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param cls handle to use to re-connect.
+ * @param tc scheduler context
+ */
+static void
+reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_ATS_SchedulingHandle *sh = cls;
+
+ sh->task = GNUNET_SCHEDULER_NO_TASK;
+ reconnect (sh);
+}
+
+
+/**
+ * Disconnect from ATS and then reconnect.
+ *
+ * @param sh our handle
+ */
+static void
+force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
+{
+ sh->reconnect = GNUNET_NO;
+ GNUNET_CLIENT_disconnect (sh->client, GNUNET_NO);
+ sh->client = NULL;
+ sh->task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
+ sh);
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param sh handle to use
+ */
+static void
+do_transmit (struct GNUNET_ATS_SchedulingHandle *sh);
+
+
+/**
+ * Type of a function to call when we receive a message
+ * from the service.
+ *
+ * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * We can now transmit a message to ATS. Do it.
+ *
+ * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
+ * @param size number of bytes we can transmit to ATS
+ * @param buf where to copy the messages
+ * @return number of bytes copied into buf
+ */
+static size_t
+transmit_message_to_ats (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_ATS_SchedulingHandle *sh = cls;
+ struct PendingMessage *p;
+ size_t ret;
+ char *cbuf;
+
+ sh->th = NULL;
+ if ((size == 0) || (buf == NULL))
+ {
+ force_reconnect (sh);
+ return 0;
+ }
+ ret = 0;
+ cbuf = buf;
+ while ((NULL != (p = sh->pending_head)) && (p->size <= size))
+ {
+ memcpy (&cbuf[ret], &p[1], p->size);
+ ret += p->size;
+ size -= p->size;
+ GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p);
+ if (GNUNET_YES == p->is_init)
+ GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ GNUNET_free (p);
+ }
+ do_transmit (sh);
+ return ret;
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param sh handle to use
+ */
+static void
+do_transmit (struct GNUNET_ATS_SchedulingHandle *sh)
+{
+ struct PendingMessage *p;
+
+ if (NULL != sh->th)
+ return;
+ if (NULL == (p = sh->pending_head))
+ return;
+ if (NULL == sh->client)
+ return; /* currently reconnecting */
+ sh->th =
+ GNUNET_CLIENT_notify_transmit_ready (sh->client, p->size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_NO, &transmit_message_to_ats,
+ sh);
+}
+
+
+/**
+ * Find the session object corresponding to the given session ID.
+ *
+ * @param sh our handle
+ * @param session_id current session ID
+ * @param peer peer the session belongs to
+ * @return the session object (or NULL)
+ */
+static struct Session *
+find_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
+ const struct GNUNET_PeerIdentity *peer)
+{
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Find session %u from peer %s in %p\n",
+ (unsigned int) session_id, GNUNET_i2s (peer), sh);
+#endif
+ if (session_id >= sh->session_array_size)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (0 == session_id)
+ return NULL;
+ if (sh->session_array[session_id].session == NULL)
+ {
+ GNUNET_break (0 ==
+ memcmp (peer, &sh->session_array[session_id].peer,
+ sizeof (struct GNUNET_PeerIdentity)));
+ return NULL;
+ }
+
+ if (0 !=
+ memcmp (peer, &sh->session_array[session_id].peer,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break (0);
+ sh->reconnect = GNUNET_YES;
+ return NULL;
+ }
+ return sh->session_array[session_id].session;
+}
+
+
+/**
+ * Get the ID for the given session object. If we do not have an ID for
+ * the given session object, allocate one.
+ *
+ * @param sh our handle
+ * @param session session object
+ * @param peer peer the session belongs to
+ * @return the session id
+ */
+static uint32_t
+get_session_id (struct GNUNET_ATS_SchedulingHandle *sh, struct Session *session,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ unsigned int i;
+ unsigned int f;
+
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Get session ID for session %p from peer %s in %p\n", session,
+ GNUNET_i2s (peer), sh);
+#endif
+ if (NULL == session)
+ return 0;
+ f = 0;
+ for (i = 1; i < sh->session_array_size; i++)
+ {
+ if (session == sh->session_array[i].session)
+ {
+ GNUNET_assert (0 ==
+ memcmp (peer, &sh->session_array[i].peer,
+ sizeof (struct GNUNET_PeerIdentity)));
+ return i;
+ }
+ if ((f == 0) && (sh->session_array[i].slot_used == GNUNET_NO))
+ f = i;
+ }
+ if (f == 0)
+ {
+ f = sh->session_array_size;
+ GNUNET_array_grow (sh->session_array, sh->session_array_size,
+ sh->session_array_size * 2);
+ }
+ GNUNET_assert (f > 0);
+ sh->session_array[f].session = session;
+ sh->session_array[f].peer = *peer;
+ sh->session_array[f].slot_used = GNUNET_YES;
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Assigning session ID %u for session %p of peer %s in %p\n", f,
+ session, GNUNET_i2s (peer), sh);
+#endif
+ return f;
+}
+
+
+/**
+ * Remove the session of the given session ID from the session
+ * table (it is no longer valid).
+ *
+ * @param sh our handle
+ * @param session_id identifies session that is no longer valid
+ * @param peer peer the session belongs to
+ */
+static void
+remove_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
+ const struct GNUNET_PeerIdentity *peer)
+{
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Remove sessionID %u from peer %s in %p\n",
+ (unsigned int) session_id, GNUNET_i2s (peer), sh);
+#endif
+ if (0 == session_id)
+ return;
+ GNUNET_assert (session_id < sh->session_array_size);
+ GNUNET_assert (GNUNET_YES == sh->session_array[session_id].slot_used);
+ GNUNET_assert (0 ==
+ memcmp (peer, &sh->session_array[session_id].peer,
+ sizeof (struct GNUNET_PeerIdentity)));
+ sh->session_array[session_id].session = NULL;
+}
+
+
+/**
+ * Release the session slot from the session table (ATS service is
+ * also done using it).
+ *
+ * @param sh our handle
+ * @param session_id identifies session that is no longer valid
+ * @param peer peer the session belongs to
+ */
+static void
+release_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
+ const struct GNUNET_PeerIdentity *peer)
+{
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Release sessionID %u from peer %s in %p\n",
+ (unsigned int) session_id, GNUNET_i2s (peer), sh);
+#endif
+ if (session_id >= sh->session_array_size)
+ {
+ GNUNET_break (0);
+ sh->reconnect = GNUNET_YES;
+ return;
+ }
+
+ /* this slot should have been removed from remove_session before */
+ GNUNET_assert (sh->session_array[session_id].session == NULL);
+
+ if (0 !=
+ memcmp (peer, &sh->session_array[session_id].peer,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break (0);
+ sh->reconnect = GNUNET_YES;
+ return;
+ }
+ sh->session_array[session_id].slot_used = GNUNET_NO;
+ memset (&sh->session_array[session_id].peer, 0,
+ sizeof (struct GNUNET_PeerIdentity));
+}
+
+
+static void
+process_release_message (struct GNUNET_ATS_SchedulingHandle *sh,
+ const struct SessionReleaseMessage *srm)
+{
+ release_session (sh, ntohl (srm->session_id), &srm->peer);
+}
+
+
+/**
+ * Type of a function to call when we receive a message
+ * from the service.
+ *
+ * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_ATS_SchedulingHandle *sh = cls;
+ const struct AddressSuggestionMessage *m;
+ const struct GNUNET_ATS_Information *atsi;
+ const char *plugin_address;
+ const char *plugin_name;
+ uint16_t plugin_address_length;
+ uint16_t plugin_name_length;
+ uint32_t ats_count;
+ struct GNUNET_HELLO_Address address;
+ struct Session *s;
+
+ if (NULL == msg)
+ {
+ force_reconnect (sh);
+ return;
+ }
+ if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE) &&
+ (ntohs (msg->size) == sizeof (struct SessionReleaseMessage)))
+ {
+ process_release_message (sh, (const struct SessionReleaseMessage *) msg);
+ GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ if (GNUNET_YES == sh->reconnect)
+ force_reconnect (sh);
+ return;
+ }
+ if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION) ||
+ (ntohs (msg->size) <= sizeof (struct AddressSuggestionMessage)))
+ {
+ GNUNET_break (0);
+ force_reconnect (sh);
+ return;
+ }
+ m = (const struct AddressSuggestionMessage *) msg;
+ ats_count = ntohl (m->ats_count);
+ plugin_address_length = ntohs (m->address_length);
+ atsi = (const struct GNUNET_ATS_Information *) &m[1];
+ plugin_address = (const char *) &atsi[ats_count];
+ plugin_name = &plugin_address[plugin_address_length];
+ plugin_name_length = ntohs (m->plugin_name_length);
+ if ((plugin_address_length + plugin_name_length +
+ ats_count * sizeof (struct GNUNET_ATS_Information) +
+ sizeof (struct AddressSuggestionMessage) != ntohs (msg->size)) ||
+ (ats_count >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
+ || (plugin_name[plugin_name_length - 1] != '\0'))
+ {
+ GNUNET_break (0);
+ force_reconnect (sh);
+ return;
+ }
+ uint32_t session_id = ntohl (m->session_id);
+
+ if (session_id == 0)
+ s = NULL;
+ else
+ {
+ s = find_session (sh, session_id, &m->peer);
+ if (s == NULL)
+ {
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "ATS tries to use outdated session `%s'\n",
+ GNUNET_i2s (&m->peer));
+#endif
+ GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ return;
+ }
+ }
+ address.peer = m->peer;
+ address.address = plugin_address;
+ address.address_length = plugin_address_length;
+ address.transport_name = plugin_name;
+
+ if ((s == NULL) && (0 == address.address_length))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "ATS returned invalid address for peer `%s' transport `%s' address length %i, session_id %i\n",
+ GNUNET_i2s (&address.peer), address.transport_name,
+ plugin_address_length, session_id);
+ GNUNET_break_op (0);
+ GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ return;
+ }
+
+ sh->suggest_cb (sh->suggest_cb_cls, &address, s, m->bandwidth_out,
+ m->bandwidth_in, atsi, ats_count);
+
+ GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ if (GNUNET_YES == sh->reconnect)
+ force_reconnect (sh);
+}
+
+
+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param sh handle to use to re-connect.
+ */
+static void
+reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
+{
+ struct PendingMessage *p;
+ struct ClientStartMessage *init;
+
+ GNUNET_assert (NULL == sh->client);
+ sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg);
+ GNUNET_assert (NULL != sh->client);
+ if ((NULL == (p = sh->pending_head)) || (GNUNET_YES != p->is_init))
+ {
+ p = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct ClientStartMessage));
+ p->size = sizeof (struct ClientStartMessage);
+ p->is_init = GNUNET_YES;
+ init = (struct ClientStartMessage *) &p[1];
+ init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
+ init->header.size = htons (sizeof (struct ClientStartMessage));
+ init->start_flag = htonl (START_FLAG_SCHEDULING);
+ GNUNET_CONTAINER_DLL_insert (sh->pending_head, sh->pending_tail, p);
+ }
+ do_transmit (sh);
+}
+
+/**
+ * delete the current network list
+ */
+
+static void
+delete_networks (struct GNUNET_ATS_SchedulingHandle *sh)
+{
+ struct ATS_Network * cur = sh->net_head;
+ while (cur != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove(sh->net_head, sh->net_tail, cur);
+ GNUNET_free (cur);
+ cur = sh->net_head;
+ }
+}
+
+
+static int
+interface_proc (void *cls, const char *name,
+ int isDefault,
+ const struct sockaddr *
+ addr,
+ const struct sockaddr *
+ broadcast_addr,
+ const struct sockaddr *
+ netmask, socklen_t addrlen)
+{
+ struct GNUNET_ATS_SchedulingHandle * sh = cls;
+ /* Calculate network */
+ struct ATS_Network *net = NULL;
+
+ /* Skipping IPv4 loopback addresses since we have special check */
+ if (addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
+
+ if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
+ return GNUNET_OK;
+ }
+ /* Skipping IPv6 loopback addresses since we have special check */
+ if (addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
+ if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
+ return GNUNET_OK;
+ }
+
+ if (addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
+ struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask;
+ struct sockaddr_in *tmp = NULL;
+ struct sockaddr_in network4;
+
+ net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in));
+ tmp = (struct sockaddr_in *) &net[1];
+ net->network = (struct sockaddr *) &tmp[0];
+ net->netmask = (struct sockaddr *) &tmp[1];
+ net->length = addrlen;
+
+ memset (&network4, 0, sizeof (network4));
+ network4.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ network4.sin_len = sizeof (network4);
+#endif
+ network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr);
+
+ memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in));
+ memcpy (net->network, &network4, sizeof (struct sockaddr_in));
+ }
+
+ if (addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
+ struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask;
+ struct sockaddr_in6 * tmp = NULL;
+ struct sockaddr_in6 network6;
+
+ net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6));
+ tmp = (struct sockaddr_in6 *) &net[1];
+ net->network = (struct sockaddr *) &tmp[0];
+ net->netmask = (struct sockaddr *) &tmp[1];
+ net->length = addrlen;
+
+ memset (&network6, 0, sizeof (network6));
+ network6.sin6_family = AF_INET6;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ network6.sin6_len = sizeof (network6);
+#endif
+ int c = 0;
+ uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr;
+ uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr;
+ uint32_t *net_elem = (uint32_t *) &network6.sin6_addr;
+ for (c = 0; c < 4; c++)
+ net_elem[c] = addr_elem[c] & mask_elem[c];
+
+ memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6));
+ memcpy (net->network, &network6, sizeof (struct sockaddr_in6));
+ }
+
+ /* Store in list */
+ if (net != NULL)
+ {
+#if VERBOSE_ATS
+ char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n",
+ GNUNET_a2s((struct sockaddr *) net->network, addrlen),
+ netmask);
+ GNUNET_free (netmask);
+# endif
+ GNUNET_CONTAINER_DLL_insert(sh->net_head, sh->net_tail, net);
+ }
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Periodically get list of addresses
+ * @param cls closure
+ * @param tc Task context
+ */
+static void
+get_addresses (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_ATS_SchedulingHandle * sh = cls;
+ sh->interface_task = GNUNET_SCHEDULER_NO_TASK;
+ delete_networks (sh);
+ GNUNET_OS_network_interfaces_list(interface_proc, sh);
+ sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL,
+ get_addresses,
+ sh);
+}
+
+/**
+ * Returns where the address is located: LAN or WAN or ...
+ * @param sh the scheduling handle
+ * @param addr address
+ * @param addrlen address length
+ * @return location as GNUNET_ATS_Information
+ */
+
+const struct GNUNET_ATS_Information
+GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle * sh, const struct sockaddr * addr, socklen_t addrlen)
+{
+ GNUNET_assert (sh != NULL);
+ struct GNUNET_ATS_Information ats;
+ struct ATS_Network * cur = sh->net_head;
+ int type = GNUNET_ATS_NET_UNSPECIFIED;
+
+ if (addr->sa_family == AF_UNIX)
+ {
+ type = GNUNET_ATS_NET_LOOPBACK;
+ }
+
+ /* IPv4 loopback check */
+ if (addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
+
+ if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
+ type = GNUNET_ATS_NET_LOOPBACK;
+ }
+ /* IPv6 loopback check */
+ if (addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
+ if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
+ type = GNUNET_ATS_NET_LOOPBACK;
+ }
+
+ /* Check local networks */
+ while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED))
+ {
+ if (addrlen != cur->length)
+ {
+ cur = cur->next;
+ continue;
+ }
+
+ if (addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
+ struct sockaddr_in * net4 = (struct sockaddr_in *) cur->network;
+ struct sockaddr_in * mask4 = (struct sockaddr_in *) cur->netmask;
+
+ if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr)
+ {
+ char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n",
+ GNUNET_a2s ((const struct sockaddr *)a4, addrlen),
+ net);
+ GNUNET_free (net);
+ type = GNUNET_ATS_NET_LAN;
+ }
+ }
+ if (addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
+ struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network;
+ struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask;
+
+ int res = GNUNET_YES;
+ int c = 0;
+ uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr;
+ uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr;
+ uint32_t *net_elem = (uint32_t *) &net6->sin6_addr;
+ for (c = 0; c < 4; c++)
+ if ((addr_elem[c] & mask_elem[c]) != net_elem[c])
+ res = GNUNET_NO;
+
+ if (res == GNUNET_YES)
+ {
+ char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net6, addrlen));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n",
+ GNUNET_a2s ((const struct sockaddr *) a6, addrlen),
+ net);
+ GNUNET_free (net);
+ type = GNUNET_ATS_NET_LAN;
+ }
+ }
+ cur = cur->next;
+ }
+
+ /* no local network found for this address, default: WAN */
+ if (type == GNUNET_ATS_NET_UNSPECIFIED)
+ type = GNUNET_ATS_NET_WAN;
+
+#if VERBOSE
+ const char * range;
+ switch (type) {
+ case GNUNET_ATS_NET_WAN:
+ range = "WAN";
+ break;
+ case GNUNET_ATS_NET_LAN:
+ range = "LAN";
+ break;
+ case GNUNET_ATS_NET_LOOPBACK:
+ range = "LOOPBACK";
+ break;
+ default:
+
+ break;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "`%s' is in network `%s'\n",
+ GNUNET_a2s ((const struct sockaddr *) addr, addrlen),
+ range);
+#endif
+
+ ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
+ ats.value = htonl (type);
+ return (const struct GNUNET_ATS_Information) ats;
+}
+
+/**
+ * Initialize the ATS subsystem.
+ *
+ * @param cfg configuration to use
+ * @param suggest_cb notification to call whenever the suggestation changed
+ * @param suggest_cb_cls closure for 'suggest_cb'
+ * @return ats context
+ */
+struct GNUNET_ATS_SchedulingHandle *
+GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_ATS_AddressSuggestionCallback suggest_cb,
+ void *suggest_cb_cls)
+{
+ struct GNUNET_ATS_SchedulingHandle *sh;
+
+ sh = GNUNET_malloc (sizeof (struct GNUNET_ATS_SchedulingHandle));
+ sh->cfg = cfg;
+ sh->suggest_cb = suggest_cb;
+ sh->suggest_cb_cls = suggest_cb_cls;
+ GNUNET_array_grow (sh->session_array, sh->session_array_size, 4);
+ GNUNET_OS_network_interfaces_list(interface_proc, sh);
+ sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL,
+ get_addresses,
+ sh);
+ reconnect (sh);
+ return sh;
+}
+
+
+/**
+ * Client is done with ATS scheduling, release resources.
+ *
+ * @param sh handle to release
+ */
+void
+GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh)
+{
+ struct PendingMessage *p;
+
+ while (NULL != (p = sh->pending_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p);
+ GNUNET_free (p);
+ }
+ if (NULL != sh->client)
+ {
+ GNUNET_CLIENT_disconnect (sh->client, GNUNET_NO);
+ sh->client = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != sh->task)
+ {
+ GNUNET_SCHEDULER_cancel (sh->task);
+ sh->task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ delete_networks (sh);
+ if (sh->interface_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(sh->interface_task);
+ sh->interface_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_array_grow (sh->session_array, sh->session_array_size, 0);
+ GNUNET_free (sh);
+ sh = NULL;
+}
+
+
+/**
+ * We would like to establish a new connection with a peer. ATS
+ * should suggest a good address to begin with.
+ *
+ * @param sh handle
+ * @param peer identity of the peer we need an address for
+ */
+void
+GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct PendingMessage *p;
+ struct RequestAddressMessage *m;
+
+ p = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct RequestAddressMessage));
+ p->size = sizeof (struct RequestAddressMessage);
+ p->is_init = GNUNET_NO;
+ m = (struct RequestAddressMessage *) &p[1];
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS);
+ m->header.size = htons (sizeof (struct RequestAddressMessage));
+ m->reserved = htonl (0);
+ m->peer = *peer;
+ GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
+ do_transmit (sh);
+}
+
+
+/**
+ * We would like to stop receiving address updates for this peer
+ *
+ * @param sh handle
+ * @param peer identity of the peer
+ */
+void
+GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct PendingMessage *p;
+ struct RequestAddressMessage *m;
+
+ p = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct RequestAddressMessage));
+ p->size = sizeof (struct RequestAddressMessage);
+ p->is_init = GNUNET_NO;
+ m = (struct RequestAddressMessage *) &p[1];
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL);
+ m->header.size = htons (sizeof (struct RequestAddressMessage));
+ m->reserved = htonl (0);
+ m->peer = *peer;
+ GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
+ do_transmit (sh);
+}
+
+/**
+ * We have updated performance statistics for a given address. Note
+ * that this function can be called for addresses that are currently
+ * in use as well as addresses that are valid but not actively in use.
+ * Furthermore, the peer may not even be connected to us right now (in
+ * which case the call may be ignored or the information may be stored
+ * for later use). Update bandwidth assignments.
+ *
+ * @param sh handle
+ * @param address the address
+ * @param session session handle (if available)
+ * @param ats performance data for the address
+ * @param ats_count number of performance records in 'ats'
+ */
+void
+GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ struct PendingMessage *p;
+ struct AddressUpdateMessage *m;
+ struct GNUNET_ATS_Information *am;
+ char *pm;
+ size_t namelen;
+ size_t msize;
+
+ if (address == NULL)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if ((address == NULL) && (session == NULL))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ namelen =
+ (address->transport_name ==
+ NULL) ? 0 : strlen (address->transport_name) + 1;
+ msize =
+ sizeof (struct AddressUpdateMessage) + address->address_length +
+ ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
+ if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+ (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+ (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+ (ats_count >=
+ GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
+ p->size = msize;
+ p->is_init = GNUNET_NO;
+ m = (struct AddressUpdateMessage *) &p[1];
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE);
+ m->header.size = htons (msize);
+ m->ats_count = htonl (ats_count);
+ m->peer = address->peer;
+ m->address_length = htons (address->address_length);
+ m->plugin_name_length = htons (namelen);
+ m->session_id = htonl (get_session_id (sh, session, &address->peer));
+ am = (struct GNUNET_ATS_Information *) &m[1];
+ memcpy (am, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
+ pm = (char *) &am[ats_count];
+ memcpy (pm, address->address, address->address_length);
+ memcpy (&pm[address->address_length], address->transport_name, namelen);
+ GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
+ do_transmit (sh);
+}
+
+
+/**
+ * An address is now in use or not used any more.
+ *
+ * @param sh handle
+ * @param address the address
+ * @param session session handle
+ * @param in_use GNUNET_YES if this address is now used, GNUNET_NO
+ * if address is not used any more
+ */
+void
+GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session, int in_use)
+{
+ struct PendingMessage *p;
+ struct AddressUseMessage *m;
+ char *pm;
+ size_t namelen;
+ size_t msize;
+
+ GNUNET_assert (NULL != address);
+ namelen =
+ (address->transport_name ==
+ NULL) ? 0 : strlen (address->transport_name) + 1;
+ msize = sizeof (struct AddressUseMessage) + address->address_length + namelen;
+ if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+ (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+ (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
+ p->size = msize;
+ p->is_init = GNUNET_NO;
+ m = (struct AddressUseMessage *) &p[1];
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE);
+ m->header.size = htons (msize);
+ m->peer = address->peer;
+ m->in_use = htons (in_use);
+ m->address_length = htons (address->address_length);
+ m->plugin_name_length = htons (namelen);
+ m->session_id = htonl (get_session_id (sh, session, &address->peer));
+ pm = (char *) &m[1];
+ memcpy (pm, address->address, address->address_length);
+ memcpy (&pm[address->address_length], address->transport_name, namelen);
+ GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
+
+ do_transmit (sh);
+}
+
+/**
+ * A session got destroyed, stop including it as a valid address.
+ *
+ * @param sh handle
+ * @param address the address
+ * @param session session handle that is no longer valid
+ */
+void
+GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session)
+{
+ struct PendingMessage *p;
+ struct AddressDestroyedMessage *m;
+ char *pm;
+ size_t namelen;
+ size_t msize;
+ uint32_t session_id;
+
+ GNUNET_assert (address->transport_name != NULL);
+ namelen = strlen (address->transport_name) + 1;
+ GNUNET_assert (namelen > 1);
+ msize =
+ sizeof (struct AddressDestroyedMessage) + address->address_length +
+ namelen;
+ if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+ (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+ (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
+ p->size = msize;
+ p->is_init = GNUNET_NO;
+ m = (struct AddressDestroyedMessage *) &p[1];
+ m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);
+ m->header.size = htons (msize);
+ m->reserved = htonl (0);
+ m->peer = address->peer;
+ m->address_length = htons (address->address_length);
+ m->plugin_name_length = htons (namelen);
+ session_id = get_session_id (sh, session, &address->peer);
+ m->session_id = htonl (session_id);
+ pm = (char *) &m[1];
+ memcpy (pm, address->address, address->address_length);
+ memcpy (&pm[address->address_length], address->transport_name, namelen);
+ GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
+ do_transmit (sh);
+ remove_session (sh, session_id, &address->peer);
+}
+
+/* end of ats_api_scheduling.c */
diff --git a/src/ats/gnunet-service-ats.c b/src/ats/gnunet-service-ats.c
new file mode 100644
index 0000000..7deca0b
--- /dev/null
+++ b/src/ats/gnunet-service-ats.c
@@ -0,0 +1,182 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats.c
+ * @brief ats service
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_ats_service.h"
+#include "gnunet-service-ats.h"
+#include "gnunet-service-ats_addresses.h"
+#include "gnunet-service-ats_performance.h"
+#include "gnunet-service-ats_scheduling.h"
+#include "gnunet-service-ats_reservations.h"
+#include "ats.h"
+
+/**
+ * Handle for statistics.
+ */
+struct GNUNET_STATISTICS_Handle *GSA_stats;
+
+/**
+ * We have received a 'ClientStartMessage' from a client. Find out which
+ * type of client it is and notify the respective subsystem.
+ *
+ * @param cls closure, unused
+ * @param client handle to the client
+ * @param message the start message
+ */
+static void
+handle_ats_start (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct ClientStartMessage *msg =
+ (const struct ClientStartMessage *) message;
+ enum StartFlag flag;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ATS_START");
+ flag = ntohl (msg->start_flag);
+ switch (flag)
+ {
+ case START_FLAG_SCHEDULING:
+ if (GNUNET_OK != GAS_scheduling_add_client (client))
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ break;
+ case START_FLAG_PERFORMANCE_WITH_PIC:
+ GAS_performance_add_client (client, flag);
+ break;
+ case START_FLAG_PERFORMANCE_NO_PIC:
+ GAS_performance_add_client (client, flag);
+ break;
+ default:
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * A client disconnected from us. Tear down the local client
+ * record.
+ *
+ * @param cls unused
+ * @param client handle of the client
+ */
+static void
+client_disconnect_handler (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ if (NULL == client)
+ return;
+ GAS_scheduling_remove_client (client);
+ GAS_performance_remove_client (client);
+}
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GAS_addresses_done ();
+ GAS_scheduling_done ();
+ GAS_performance_done ();
+ GAS_reservations_done ();
+ if (NULL != GSA_stats)
+ {
+ GNUNET_STATISTICS_destroy (GSA_stats, GNUNET_NO);
+ GSA_stats = NULL;
+ }
+}
+
+
+/**
+ * Process template requests.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+ {&handle_ats_start, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_START, sizeof (struct ClientStartMessage)},
+ {&GAS_handle_request_address, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS,
+ sizeof (struct RequestAddressMessage)},
+ {&GAS_handle_request_address_cancel, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL,
+ sizeof (struct RequestAddressMessage)},
+ {&GAS_handle_address_update, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE, 0},
+ {&GAS_handle_address_in_use, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE, 0},
+ {&GAS_handle_address_destroyed, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED, 0},
+ {&GAS_handle_reservation_request, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST,
+ sizeof (struct ReservationRequestMessage)},
+ {&GAS_handle_preference_change, NULL,
+ GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE, 0},
+ {NULL, NULL, 0, 0}
+ };
+ GSA_stats = GNUNET_STATISTICS_create ("ats", cfg);
+ GAS_reservations_init ();
+ GAS_performance_init (server);
+ GAS_scheduling_init (server);
+ GAS_addresses_init (cfg, GSA_stats);
+ GNUNET_SERVER_disconnect_notify (server, &client_disconnect_handler, NULL);
+ GNUNET_SERVER_add_handlers (server, handlers);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
+ NULL);
+}
+
+
+/**
+ * The main function for the ats service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ return (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc, argv, "ats", GNUNET_SERVICE_OPTION_NONE,
+ &run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-ats.c */
diff --git a/src/ats/gnunet-service-ats.h b/src/ats/gnunet-service-ats.h
new file mode 100644
index 0000000..b60332d
--- /dev/null
+++ b/src/ats/gnunet-service-ats.h
@@ -0,0 +1,38 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats.h
+ * @brief ats service
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_ATS_H
+#define GNUNET_SERVICE_ATS_H
+
+#include "gnunet_statistics_service.h"
+
+/**
+ * Handle for statistics.
+ */
+extern struct GNUNET_STATISTICS_Handle *GSA_stats;
+
+
+#endif
diff --git a/src/ats/gnunet-service-ats_addresses.c b/src/ats/gnunet-service-ats_addresses.c
new file mode 100644
index 0000000..fb9bad0
--- /dev/null
+++ b/src/ats/gnunet-service-ats_addresses.c
@@ -0,0 +1,805 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_addresses.c
+ * @brief ats service address management
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_ats_service.h"
+#include "gnunet-service-ats.h"
+#include "gnunet-service-ats_addresses.h"
+#include "gnunet-service-ats_performance.h"
+#include "gnunet-service-ats_scheduling.h"
+#include "gnunet-service-ats_reservations.h"
+#if HAVE_LIBGLPK
+#include "gnunet-service-ats_addresses_mlp.h"
+#endif
+
+#define VERBOSE GNUNET_NO
+
+enum ATS_Mode
+{
+ /*
+ * Assign each peer an equal amount of bandwidth (bw)
+ *
+ * bw_per_peer = bw_total / #active addresses
+ */
+ SIMPLE,
+
+ /*
+ * Use MLP solver to assign bandwidth
+ */
+ MLP
+};
+
+static struct GNUNET_CONTAINER_MultiHashMap *addresses;
+
+#if HAVE_LIBGLPK
+static struct GAS_MLP_Handle *mlp;
+#endif
+
+static unsigned long long wan_quota_in;
+
+static unsigned long long wan_quota_out;
+
+static unsigned int active_addr_count;
+
+static int ats_mode;
+
+
+/**
+ * Update a bandwidth assignment for a peer. This trivial method currently
+ * simply assigns the same share to all active connections.
+ *
+ * @param cls unused
+ * @param key unused
+ * @param value the 'struct ATS_Address'
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+update_bw_simple_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct ATS_Address *aa = value;
+
+ if (GNUNET_YES != aa->active)
+ return GNUNET_OK;
+ GNUNET_assert (active_addr_count > 0);
+
+
+ /* Simple method */
+ aa->assigned_bw_in.value__ = htonl (wan_quota_in / active_addr_count);
+ aa->assigned_bw_out.value__ = htonl (wan_quota_out / active_addr_count);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n",
+ GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__),
+ ntohl (aa->assigned_bw_out.value__));
+ GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr,
+ aa->addr_len, aa->session_id,
+ aa->ats, aa->ats_count,
+ aa->assigned_bw_out,
+ aa->assigned_bw_in);
+ GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in);
+ GAS_performance_notify_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len,
+ aa->ats, aa->ats_count, aa->assigned_bw_out,
+ aa->assigned_bw_in);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Some (significant) input changed, recalculate bandwidth assignment
+ * for all peers.
+ */
+static void
+recalculate_assigned_bw ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Recalculating bandwidth for all active connections\n");
+ GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed",
+ 1, GNUNET_NO);
+ GNUNET_STATISTICS_set (GSA_stats, "# active addresses", active_addr_count,
+ GNUNET_NO);
+
+ GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, NULL);
+}
+
+/**
+ * Free the given address
+ * @param addr address to destroy
+ */
+static void
+free_address (struct ATS_Address *addr)
+{
+ GNUNET_free_non_null (addr->ats);
+ GNUNET_free (addr->plugin);
+ GNUNET_free (addr);
+}
+
+/**
+ * Create a ATS_address with the given information
+ * @param peer peer
+ * @param plugin_name plugin
+ * @param plugin_addr address
+ * @param plugin_addr_len address length
+ * @param session_id session
+ * @return the ATS_Address
+ */
+static struct ATS_Address *
+create_address (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name,
+ const void *plugin_addr, size_t plugin_addr_len,
+ uint32_t session_id)
+{
+ struct ATS_Address *aa = NULL;
+
+ aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
+ aa->peer = *peer;
+ aa->addr_len = plugin_addr_len;
+ aa->addr = &aa[1];
+ memcpy (&aa[1], plugin_addr, plugin_addr_len);
+ aa->plugin = GNUNET_strdup (plugin_name);
+ aa->session_id = session_id;
+ aa->mlp_information = NULL;
+ aa->next = NULL;
+ aa->prev = NULL;
+ return aa;
+}
+
+
+/**
+ * Destroy the given address.
+ *
+ * @param addr address to destroy
+ * @return GNUNET_YES if bandwidth allocations should be recalcualted
+ */
+static int
+destroy_address (struct ATS_Address *addr)
+{
+ int ret;
+
+ ret = GNUNET_NO;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (addresses,
+ &addr->peer.hashPubKey,
+ addr));
+
+#if HAVE_LIBGLPK
+ if (ats_mode == MLP)
+ GAS_mlp_address_delete (mlp, addresses, addr);
+#endif
+
+ if (GNUNET_YES == addr->active)
+ {
+ active_addr_count--;
+ addr->active = GNUNET_NO;
+ ret = GNUNET_YES;
+ }
+ free_address (addr);
+ return ret;
+}
+
+
+struct CompareAddressContext
+{
+ const struct ATS_Address *search;
+
+ /* exact_address != NULL if address and session is equal */
+ struct ATS_Address *exact_address;
+ /* exact_address != NULL if address and session is 0 */
+ struct ATS_Address *base_address;
+};
+
+
+static int
+compare_address_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct CompareAddressContext *cac = cls;
+ struct ATS_Address *aa = value;
+/*
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Comparing to: %s %s %u session %u\n",
+ GNUNET_i2s (&aa->peer), aa->plugin, aa->addr_len, aa->session_id);
+
+*/
+ /* find an exact matching address: aa->addr == cac->search->addr && aa->session == cac->search->session */
+ if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
+ {
+ if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
+ {
+ cac->exact_address = aa;
+ }
+ }
+
+ /* find an matching address: aa->addr == cac->search->addr && aa->session == 0 */
+ /* this address can be used to be updated */
+ if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
+ {
+ if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0))
+ {
+ cac->base_address = aa;
+ }
+ }
+
+ if (cac->exact_address == NULL)
+ return GNUNET_YES;
+ else
+ return GNUNET_NO;
+}
+
+
+/**
+ * Find an existing equivalent address record.
+ * Compares by peer identity and network address OR by session ID
+ * (one of the two must match).
+ *
+ * @param peer peer to lookup addresses for
+ * @param addr existing address record
+ * @return existing address record, NULL for none
+ */
+struct ATS_Address *
+find_address (const struct GNUNET_PeerIdentity *peer,
+ const struct ATS_Address *addr)
+{
+ struct CompareAddressContext cac;
+
+ cac.exact_address = NULL;
+ cac.base_address = NULL;
+ cac.search = addr;
+ GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
+ &compare_address_it, &cac);
+
+/*
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "exact address: %s base address: %s\n",
+ (cac.exact_address != NULL) ? "YES" : "NO",
+ (cac.base_address != NULL) ? "YES" : "NO");
+*/
+ if (cac.exact_address == NULL)
+ return cac.base_address;
+ return cac.exact_address;
+}
+
+
+static int
+compare_address_session_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct CompareAddressContext *cac = cls;
+ struct ATS_Address *aa = value;
+
+ if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
+ {
+ if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
+ {
+ cac->exact_address = aa;
+ return GNUNET_NO;
+ }
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Find an existing equivalent address record.
+ * Compares by peer identity and network address AND by session ID
+ * (one of the two must match).
+ *
+ * @param peer peer to lookup addresses for
+ * @param addr existing address record
+ * @return existing address record, NULL for none
+ */
+struct ATS_Address *
+find_exact_address (const struct GNUNET_PeerIdentity *peer,
+ const struct ATS_Address *addr)
+{
+ struct CompareAddressContext cac;
+
+ cac.exact_address = NULL;
+ cac.search = addr;
+ GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
+ &compare_address_session_it, &cac);
+ return cac.exact_address;
+}
+
+
+void
+GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name, const void *plugin_addr,
+ size_t plugin_addr_len, uint32_t session_id,
+ const struct GNUNET_ATS_Information *atsi,
+ uint32_t atsi_count)
+{
+ struct ATS_Address *aa;
+ struct ATS_Address *old;
+ uint32_t i;
+
+ aa = create_address (peer,
+ plugin_name,
+ plugin_addr, plugin_addr_len,
+ session_id);
+
+ aa->mlp_information = NULL;
+ aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
+ aa->ats_count = atsi_count;
+ memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
+
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' %u\n",
+ GNUNET_i2s (peer),
+ session_id);
+#endif
+ /* Get existing address or address with session == 0 */
+ old = find_address (peer, aa);
+ if (old == NULL)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (addresses,
+ &peer->hashPubKey, aa,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' %X\n",
+ GNUNET_i2s (peer), aa);
+#endif
+ old = aa;
+ }
+ else
+ {
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Updated existing address for peer `%s' %p old session %u new session %u\n",
+ GNUNET_i2s (peer), old,
+ old->session_id, session_id);
+#endif
+ GNUNET_free_non_null (old->ats);
+ old->session_id = session_id;
+ old->ats = NULL;
+ old->ats_count = 0;
+ old->ats = aa->ats;
+ old->ats_count = aa->ats_count;
+ GNUNET_free (aa->plugin);
+ GNUNET_free (aa);
+ }
+ for (i = 0; i < atsi_count; i++)
+ switch (ntohl (atsi[i].type))
+ {
+ case GNUNET_ATS_UTILIZATION_UP:
+ old->atsp_utilization_out.value__ = atsi[i].value;
+ break;
+ case GNUNET_ATS_UTILIZATION_DOWN:
+ old->atsp_utilization_in.value__ = atsi[i].value;
+ break;
+ case GNUNET_ATS_QUALITY_NET_DELAY:
+ old->atsp_latency.rel_value = ntohl (atsi[i].value);
+ break;
+ case GNUNET_ATS_QUALITY_NET_DISTANCE:
+ old->atsp_distance = ntohl (atsi[i].value);
+ break;
+ case GNUNET_ATS_COST_WAN:
+ old->atsp_cost_wan = ntohl (atsi[i].value);
+ break;
+ case GNUNET_ATS_COST_LAN:
+ old->atsp_cost_lan = ntohl (atsi[i].value);
+ break;
+ case GNUNET_ATS_COST_WLAN:
+ old->atsp_cost_wlan = ntohl (atsi[i].value);
+ break;
+ case GNUNET_ATS_NETWORK_TYPE:
+ old->atsp_network_type = ntohl (atsi[i].value);
+ break;
+
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Received unsupported ATS type %u\n", ntohl (atsi[i].type));
+ GNUNET_break (0);
+ break;
+ }
+#if HAVE_LIBGLPK
+ if (ats_mode == MLP)
+ GAS_mlp_address_update (mlp, addresses, old);
+#endif
+}
+
+
+/**
+ * Delete an address
+ *
+ * If session != 0, just the session is deleted, the address itself still exists
+ * If session == 0, remove full address
+ * If session == 0 and addrlen == 0, destroy inbound address
+ *
+ * @param cls unused
+ * @param key unused
+ * @param value the 'struct ATS_Address'
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+destroy_by_session_id (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ const struct ATS_Address *info = cls;
+ struct ATS_Address *aa = value;
+
+ GNUNET_assert (0 ==
+ memcmp (&aa->peer, &info->peer,
+ sizeof (struct GNUNET_PeerIdentity)));
+ /* session == 0, remove full address */
+ if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) &&
+ (aa->addr_len == info->addr_len) &&
+ (0 == memcmp (info->addr, aa->addr, aa->addr_len)))
+ {
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Deleting address for peer `%s': `%s' %u\n",
+ GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
+#endif
+ if (GNUNET_YES == destroy_address (aa))
+ recalculate_assigned_bw ();
+ return GNUNET_OK;
+ }
+ /* session != 0, just remove session */
+ if (aa->session_id != info->session_id)
+ return GNUNET_OK; /* irrelevant */
+ if (aa->session_id != 0)
+ GNUNET_break (0 == strcmp (info->plugin, aa->plugin));
+ /* session died */
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Deleting session for peer `%s': `%s' %u\n",
+ GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
+#endif
+ aa->session_id = 0;
+
+ if (GNUNET_YES == aa->active)
+ {
+ aa->active = GNUNET_NO;
+ active_addr_count--;
+ recalculate_assigned_bw ();
+ }
+
+ /* session == 0 and addrlen == 0 : destroy address */
+ if (aa->addr_len == 0)
+ {
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Deleting session and address for peer `%s': `%s' %u\n",
+ GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
+#endif
+ (void) destroy_address (aa);
+ }
+ else
+ {
+ /* session was set to 0, update address */
+#if HAVE_LIBGLPK
+ if (ats_mode == MLP)
+ GAS_mlp_address_update (mlp, addresses, aa);
+#endif
+ }
+
+ return GNUNET_OK;
+}
+
+void
+GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name, const void *plugin_addr,
+ size_t plugin_addr_len, uint32_t session_id)
+{
+ struct ATS_Address *aa;
+
+ GNUNET_break (0 < strlen (plugin_name));
+ aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
+
+ GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
+ &destroy_by_session_id, aa);
+
+ free_address (aa);
+}
+
+
+/**
+ * Find a "good" address to use for a peer. If we already have an existing
+ * address, we stick to it. Otherwise, we pick by lowest distance and then
+ * by lowest latency.
+ *
+ * @param cls the 'struct ATS_Address**' where we store the result
+ * @param key unused
+ * @param value another 'struct ATS_Address*' to consider using
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+find_address_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct ATS_Address **ap = cls;
+ struct ATS_Address *aa = (struct ATS_Address *) value;
+ struct ATS_Address *ab = *ap;
+
+ if (NULL == ab)
+ {
+ *ap = aa;
+ return GNUNET_OK;
+ }
+ if ((ntohl (ab->assigned_bw_in.value__) == 0) &&
+ (ntohl (aa->assigned_bw_in.value__) > 0))
+ {
+ /* stick to existing connection */
+ *ap = aa;
+ return GNUNET_OK;
+ }
+ if (ab->atsp_distance > aa->atsp_distance)
+ {
+ /* user shorter distance */
+ *ap = aa;
+ return GNUNET_OK;
+ }
+ if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value)
+ {
+ /* user lower latency */
+ *ap = aa;
+ return GNUNET_OK;
+ }
+ /* don't care */
+ return GNUNET_OK;
+}
+
+
+void
+GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name, const void *plugin_addr,
+ size_t plugin_addr_len, uint32_t session_id, int in_use)
+{
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE",
+ GNUNET_i2s (peer), in_use);
+#endif
+
+ struct ATS_Address *aa;
+ struct ATS_Address *old;
+
+
+ aa = create_address(peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
+ old = find_exact_address (peer, aa);
+ free_address (aa);
+
+ GNUNET_assert (old != NULL);
+ GNUNET_assert (old->used != in_use);
+ old->used = in_use;
+
+#if HAVE_LIBGLPK
+ if (ats_mode == MLP)
+ GAS_mlp_address_update (mlp, addresses, old);
+#endif
+}
+
+
+void request_address_mlp (const struct GNUNET_PeerIdentity *peer)
+{
+ struct ATS_Address *aa;
+ aa = NULL;
+
+#if HAVE_GLPK
+ /* Get preferred address from MLP */
+ struct ATS_PreferedAddress * paddr = NULL;
+ paddr = GAS_mlp_get_preferred_address (mlp, addresses, peer);
+ aa = paddr->address;
+ aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(paddr->bandwidth_out);
+ /* FIXME use bw in value */
+ paddr->bandwidth_in = paddr->bandwidth_out;
+ aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (paddr->bandwidth_in);
+ GNUNET_free (paddr);
+#endif
+
+ if (aa == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
+ return;
+ }
+ if (aa->active == GNUNET_NO)
+ {
+ aa->active = GNUNET_YES;
+ active_addr_count++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n",
+ GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__),
+ ntohl (aa->assigned_bw_out.value__));
+ GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr,
+ aa->addr_len, aa->session_id,
+ aa->ats, aa->ats_count,
+ aa->assigned_bw_out,
+ aa->assigned_bw_in);
+ GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in);
+ GAS_performance_notify_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len,
+ aa->ats, aa->ats_count, aa->assigned_bw_out,
+ aa->assigned_bw_in);
+ }
+ else
+ {
+ /* just to be sure... */
+ GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
+ aa->addr_len, aa->session_id,
+ aa->ats, aa->ats_count,
+ aa->assigned_bw_out,
+ aa->assigned_bw_in);
+ }
+
+}
+
+void request_address_simple (const struct GNUNET_PeerIdentity *peer)
+{
+ struct ATS_Address *aa;
+ aa = NULL;
+
+ /* Get address with: stick to current address, lower distance, lower latency */
+ GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
+ &find_address_it, &aa);
+ if (aa == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
+ return;
+ }
+
+ if (aa->active == GNUNET_NO)
+ {
+ aa->active = GNUNET_YES;
+ active_addr_count++;
+ if (ats_mode == SIMPLE)
+ {
+ recalculate_assigned_bw ();
+ }
+ }
+ else
+ {
+ /* just to be sure... */
+ GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
+ aa->addr_len, aa->session_id,
+ aa->ats, aa->ats_count,
+ aa->assigned_bw_out,
+ aa->assigned_bw_in);
+ }
+}
+
+
+void
+GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
+{
+ if (ats_mode == SIMPLE)
+ {
+ request_address_simple (peer);
+ }
+ if (ats_mode == MLP)
+ {
+ request_address_mlp(peer);
+ }
+}
+
+
+// FIXME: this function should likely end up in the LP-subsystem and
+// not with 'addresses' in the future...
+void
+GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
+ enum GNUNET_ATS_PreferenceKind kind,
+ float score)
+{
+#if HAVE_LIBGLPK
+ if (ats_mode == MLP)
+ GAS_mlp_address_change_preference (mlp, peer, kind, score);
+#endif
+}
+
+
+
+/**
+ * Initialize address subsystem.
+ *
+ * @param cfg configuration to use
+ * @param stats the statistics handle to use
+ */
+void
+GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_STATISTICS_Handle *stats)
+{
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "WAN_QUOTA_IN",
+ &wan_quota_in));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "WAN_QUOTA_OUT",
+ &wan_quota_out));
+
+ switch (GNUNET_CONFIGURATION_get_value_yesno (cfg, "ats", "MLP"))
+ {
+ /* MLP = YES */
+ case GNUNET_YES:
+#if HAVE_LIBGLPK
+ ats_mode = MLP;
+ /* Init the MLP solver with default values */
+ mlp = GAS_mlp_init (cfg, stats, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS);
+ break;
+#else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode");
+ ats_mode = SIMPLE;
+ break;
+#endif
+ /* MLP = NO */
+ case GNUNET_NO:
+ ats_mode = SIMPLE;
+ break;
+ /* No configuration value */
+ case GNUNET_SYSERR:
+ ats_mode = SIMPLE;
+ break;
+ default:
+ break;
+ }
+
+ addresses = GNUNET_CONTAINER_multihashmap_create (128);
+}
+
+
+/**
+ * Free memory of address.
+ *
+ * @param cls NULL
+ * @param key peer identity (unused)
+ * @param value the 'struct ATS_Address' to free
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+free_address_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct ATS_Address *aa = value;
+
+ destroy_address (aa);
+ return GNUNET_OK;
+}
+
+
+void
+GAS_addresses_destroy_all ()
+{
+ if (addresses != NULL)
+ GNUNET_CONTAINER_multihashmap_iterate (addresses, &free_address_it, NULL);
+ GNUNET_assert (active_addr_count == 0);
+}
+
+
+/**
+ * Shutdown address subsystem.
+ */
+void
+GAS_addresses_done ()
+{
+ GAS_addresses_destroy_all ();
+ GNUNET_CONTAINER_multihashmap_destroy (addresses);
+ addresses = NULL;
+#if HAVE_LIBGLPK
+ if (ats_mode == MLP)
+ {
+ GAS_mlp_done (mlp);
+ }
+#endif
+
+}
+
+
+/* end of gnunet-service-ats_addresses.c */
diff --git a/src/ats/gnunet-service-ats_addresses.h b/src/ats/gnunet-service-ats_addresses.h
new file mode 100644
index 0000000..33ff586
--- /dev/null
+++ b/src/ats/gnunet-service-ats_addresses.h
@@ -0,0 +1,151 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_addresses.h
+ * @brief ats service address management
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_ATS_ADDRESSES_H
+#define GNUNET_SERVICE_ATS_ADDRESSES_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet_ats_service.h"
+#include "gnunet_statistics_service.h"
+#include "ats.h"
+
+struct ATS_Address
+{
+ struct ATS_Address *next;
+
+ struct ATS_Address *prev;
+
+ struct GNUNET_PeerIdentity peer;
+
+ size_t addr_len;
+
+ uint32_t session_id;
+
+ uint32_t ats_count;
+
+ const void *addr;
+
+ char *plugin;
+
+ void *mlp_information;
+
+ struct GNUNET_ATS_Information *ats;
+
+ struct GNUNET_TIME_Relative atsp_latency;
+
+ struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in;
+
+ struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out;
+
+ uint32_t atsp_distance;
+
+ uint32_t atsp_cost_wan;
+
+ uint32_t atsp_cost_lan;
+
+ uint32_t atsp_cost_wlan;
+
+ uint32_t atsp_network_type;
+
+ struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_in;
+
+ struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out;
+
+ /**
+ * Is this the active address for this peer?
+ */
+ int active;
+
+ /**
+ * Is this the address for this peer in use?
+ */
+ int used;
+};
+
+/**
+ * Initialize address subsystem.
+ *
+ * @param cfg configuration to use
+ * @param stats the statistics handle to use
+ */
+void
+GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_STATISTICS_Handle *stats);
+
+
+/**
+ * Shutdown address subsystem.
+ */
+void
+GAS_addresses_done (void);
+
+/**
+ * This address is now used or not used anymore
+ */
+void
+GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name, const void *plugin_addr,
+ size_t plugin_addr_len, uint32_t session_id, int in_use);
+
+void
+GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name, const void *plugin_addr,
+ size_t plugin_addr_len, uint32_t session_id,
+ const struct GNUNET_ATS_Information *atsi,
+ uint32_t atsi_count);
+
+
+void
+GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name, const void *plugin_addr,
+ size_t plugin_addr_len, uint32_t session_id);
+
+
+void
+GAS_addresses_destroy_all (void);
+
+
+// FIXME: this function should likely end up in the LP-subsystem and
+// not with 'addresses' in the future...
+// Note: this call should trigger an address suggestion
+// (GAS_scheduling_transmit_address_suggestion)
+void
+GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer);
+
+
+// FIXME: this function should likely end up in the LP-subsystem and
+// not with 'addresses' in the future...
+void
+GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
+ enum GNUNET_ATS_PreferenceKind kind,
+ float score);
+
+
+/* FIXME: add performance request API */
+
+#endif
+
+/* end of gnunet-service-ats_addresses.h */
diff --git a/src/ats/gnunet-service-ats_addresses_mlp.c b/src/ats/gnunet-service-ats_addresses_mlp.c
new file mode 100644
index 0000000..61aa733
--- /dev/null
+++ b/src/ats/gnunet-service-ats_addresses_mlp.c
@@ -0,0 +1,1736 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_addresses_mlp.c
+ * @brief ats mlp problem solver
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet-service-ats_addresses.h"
+#include "gnunet-service-ats_addresses_mlp.h"
+#include "gnunet_statistics_service.h"
+#include "glpk.h"
+
+#define WRITE_MLP GNUNET_NO
+#define DEBUG_ATS GNUNET_NO
+#define VERBOSE_GLPK GNUNET_NO
+
+#define ENABLE_C8 GNUNET_YES
+#define ENABLE_C9 GNUNET_YES
+/**
+ * Translate glpk solver error codes to text
+ * @param retcode return code
+ * @return string with result
+ */
+const char *
+mlp_solve_to_string (int retcode)
+{
+ switch (retcode) {
+ case 0:
+ return "ok";
+ break;
+ case GLP_EBADB:
+ return "invalid basis";
+ break;
+ case GLP_ESING:
+ return "singular matrix";
+ break;
+ case GLP_ECOND:
+ return "ill-conditioned matrix";
+ break;
+ case GLP_EBOUND:
+ return "invalid bounds";
+ break;
+ case GLP_EFAIL:
+ return "solver failed";
+ break;
+ case GLP_EOBJLL:
+ return "objective lower limit reached";
+ break;
+ case GLP_EOBJUL:
+ return "objective upper limit reached";
+ break;
+ case GLP_EITLIM:
+ return "iteration limit exceeded";
+ break;
+ case GLP_ETMLIM:
+ return "time limit exceeded";
+ break;
+ case GLP_ENOPFS:
+ return "no primal feasible solution";
+ break;
+ case GLP_EROOT:
+ return "root LP optimum not provided";
+ break;
+ case GLP_ESTOP:
+ return "search terminated by application";
+ break;
+ case GLP_EMIPGAP:
+ return "relative mip gap tolerance reached";
+ break;
+ case GLP_ENOFEAS:
+ return "no dual feasible solution";
+ break;
+ case GLP_ENOCVG:
+ return "no convergence";
+ break;
+ case GLP_EINSTAB:
+ return "numerical instability";
+ break;
+ case GLP_EDATA:
+ return "invalid data";
+ break;
+ case GLP_ERANGE:
+ return "result out of range";
+ break;
+ default:
+ GNUNET_break (0);
+ return "unknown error";
+ break;
+ }
+ GNUNET_break (0);
+ return "unknown error";
+}
+
+
+/**
+ * Translate glpk status error codes to text
+ * @param retcode return code
+ * @return string with result
+ */
+const char *
+mlp_status_to_string (int retcode)
+{
+ switch (retcode) {
+ case GLP_UNDEF:
+ return "solution is undefined";
+ break;
+ case GLP_FEAS:
+ return "solution is feasible";
+ break;
+ case GLP_INFEAS:
+ return "solution is infeasible";
+ break;
+ case GLP_NOFEAS:
+ return "no feasible solution exists";
+ break;
+ case GLP_OPT:
+ return "solution is optimal";
+ break;
+ case GLP_UNBND:
+ return "solution is unbounded";
+ break;
+ default:
+ GNUNET_break (0);
+ return "unknown error";
+ break;
+ }
+ GNUNET_break (0);
+ return "unknown error";
+}
+
+/**
+ * Translate ATS properties to text
+ * Just intended for debugging
+ *
+ * @param ats_index the ATS index
+ * @return string with result
+ */
+const char *
+mlp_ats_to_string (int ats_index)
+{
+ switch (ats_index) {
+ case GNUNET_ATS_ARRAY_TERMINATOR:
+ return "GNUNET_ATS_ARRAY_TERMINATOR";
+ break;
+ case GNUNET_ATS_UTILIZATION_UP:
+ return "GNUNET_ATS_UTILIZATION_UP";
+ break;
+ case GNUNET_ATS_UTILIZATION_DOWN:
+ return "GNUNET_ATS_UTILIZATION_DOWN";
+ break;
+ case GNUNET_ATS_COST_LAN:
+ return "GNUNET_ATS_COST_LAN";
+ break;
+ case GNUNET_ATS_COST_WAN:
+ return "GNUNET_ATS_COST_LAN";
+ break;
+ case GNUNET_ATS_COST_WLAN:
+ return "GNUNET_ATS_COST_WLAN";
+ break;
+ case GNUNET_ATS_NETWORK_TYPE:
+ return "GNUNET_ATS_NETWORK_TYPE";
+ break;
+ case GNUNET_ATS_QUALITY_NET_DELAY:
+ return "GNUNET_ATS_QUALITY_NET_DELAY";
+ break;
+ case GNUNET_ATS_QUALITY_NET_DISTANCE:
+ return "GNUNET_ATS_QUALITY_NET_DISTANCE";
+ break;
+ default:
+ return "unknown";
+ break;
+ }
+ GNUNET_break (0);
+ return "unknown error";
+}
+
+/**
+ * Find a peer in the DLL
+ *
+ * @param mlp the mlp handle
+ * @param peer the peer to find
+ * @return the peer struct
+ */
+static struct ATS_Peer *
+mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer)
+{
+ struct ATS_Peer *res = mlp->peer_head;
+ while (res != NULL)
+ {
+ if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity)))
+ break;
+ res = res->next;
+ }
+ return res;
+}
+
+/**
+ * Intercept GLPK terminal output
+ * @param info the mlp handle
+ * @param s the string to print
+ * @return 0: glpk prints output on terminal, 0 != surpress output
+ */
+static int
+mlp_term_hook (void *info, const char *s)
+{
+ /* Not needed atm struct MLP_information *mlp = info; */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s", s);
+ return 1;
+}
+
+/**
+ * Delete the MLP problem and free the constrain matrix
+ *
+ * @param mlp the MLP handle
+ */
+static void
+mlp_delete_problem (struct GAS_MLP_Handle *mlp)
+{
+ if (mlp != NULL)
+ {
+ if (mlp->prob != NULL)
+ glp_delete_prob(mlp->prob);
+
+ /* delete row index */
+ if (mlp->ia != NULL)
+ {
+ GNUNET_free (mlp->ia);
+ mlp->ia = NULL;
+ }
+
+ /* delete column index */
+ if (mlp->ja != NULL)
+ {
+ GNUNET_free (mlp->ja);
+ mlp->ja = NULL;
+ }
+
+ /* delete coefficients */
+ if (mlp->ar != NULL)
+ {
+ GNUNET_free (mlp->ar);
+ mlp->ar = NULL;
+ }
+ mlp->ci = 0;
+ mlp->prob = NULL;
+ }
+}
+
+/**
+ * Add constraints that are iterating over "forall addresses"
+ * and collects all existing peers for "forall peers" constraints
+ *
+ * @param cls GAS_MLP_Handle
+ * @param key Hashcode
+ * @param value ATS_Address
+ *
+ * @return GNUNET_OK to continue
+ */
+static int
+create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct GAS_MLP_Handle *mlp = cls;
+ struct ATS_Address *address = value;
+ struct MLP_information *mlpi;
+ unsigned int row_index;
+ char *name;
+
+ GNUNET_assert (address->mlp_information != NULL);
+ mlpi = (struct MLP_information *) address->mlp_information;
+
+ /* c 1) bandwidth capping
+ * b_t + (-M) * n_t <= 0
+ */
+ row_index = glp_add_rows (mlp->prob, 1);
+ mlpi->r_c1 = row_index;
+ /* set row name */
+ GNUNET_asprintf(&name, "c1_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
+ glp_set_row_name (mlp->prob, row_index, name);
+ GNUNET_free (name);
+ /* set row bounds: <= 0 */
+ glp_set_row_bnds (mlp->prob, row_index, GLP_UP, 0.0, 0.0);
+ mlp->ia[mlp->ci] = row_index;
+ mlp->ja[mlp->ci] = mlpi->c_b;
+ mlp->ar[mlp->ci] = 1;
+ mlp->ci++;
+
+ mlp->ia[mlp->ci] = row_index;
+ mlp->ja[mlp->ci] = mlpi->c_n;
+ mlp->ar[mlp->ci] = -mlp->BIG_M;
+ mlp->ci++;
+
+ /* c 3) minimum bandwidth
+ * b_t + (-n_t * b_min) >= 0
+ */
+
+ row_index = glp_add_rows (mlp->prob, 1);
+ /* set row name */
+ GNUNET_asprintf(&name, "c3_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
+ glp_set_row_name (mlp->prob, row_index, name);
+ GNUNET_free (name);
+ mlpi->r_c3 = row_index;
+ /* set row bounds: >= 0 */
+ glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0);
+
+ mlp->ia[mlp->ci] = row_index;
+ mlp->ja[mlp->ci] = mlpi->c_b;
+ mlp->ar[mlp->ci] = 1;
+ mlp->ci++;
+
+ mlp->ia[mlp->ci] = row_index;
+ mlp->ja[mlp->ci] = mlpi->c_n;
+ mlp->ar[mlp->ci] = - (double) mlp->b_min;
+ mlp->ci++;
+
+ /* c 4) minimum connections
+ * (1)*n_1 + ... + (1)*n_m >= n_min
+ */
+ mlp->ia[mlp->ci] = mlp->r_c4;
+ mlp->ja[mlp->ci] = mlpi->c_n;
+ mlp->ar[mlp->ci] = 1;
+ mlp->ci++;
+
+ /* c 6) maximize diversity
+ * (1)*n_1 + ... + (1)*n_m - d == 0
+ */
+ mlp->ia[mlp->ci] = mlp->r_c6;
+ mlp->ja[mlp->ci] = mlpi->c_n;
+ mlp->ar[mlp->ci] = 1;
+ mlp->ci++;
+
+ /* c 10) obey network specific quotas
+ * (1)*b_1 + ... + (1)*b_m <= quota_n
+ */
+
+ int cur_row = 0;
+ int c;
+ for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
+ {
+ if (mlp->quota_index[c] == address->atsp_network_type)
+ {
+ cur_row = mlp->r_quota[c];
+ break;
+ }
+ }
+
+ if (cur_row != 0)
+ {
+ mlp->ia[mlp->ci] = cur_row;
+ mlp->ja[mlp->ci] = mlpi->c_b;
+ mlp->ar[mlp->ci] = 1;
+ mlp->ci++;
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+
+ return GNUNET_OK;
+}
+
+/**
+ * Find the required ATS information for an address
+ *
+ * @param addr the address
+ * @param ats_index the desired ATS index
+ *
+ * @return the index on success, otherwise GNUNET_SYSERR
+ */
+
+static int
+mlp_lookup_ats (struct ATS_Address *addr, int ats_index)
+{
+ struct GNUNET_ATS_Information * ats = addr->ats;
+ int c = 0;
+ int found = GNUNET_NO;
+ for (c = 0; c < addr->ats_count; c++)
+ {
+ if (ats[c].type == ats_index)
+ {
+ found = GNUNET_YES;
+ break;
+ }
+ }
+ if (found == GNUNET_YES)
+ return c;
+ else
+ return GNUNET_SYSERR;
+}
+
+/**
+ * Adds the problem constraints for all addresses
+ * Required for problem recreation after address deletion
+ *
+ * @param mlp the mlp handle
+ * @param addresses all addresses
+ */
+
+static void
+mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
+{
+ unsigned int n_addresses;
+ int c;
+ char *name;
+
+ /* Problem matrix*/
+ n_addresses = GNUNET_CONTAINER_multihashmap_size(addresses);
+
+ /* Required indices in the constrain matrix
+ *
+ * feasibility constraints:
+ *
+ * c 1) bandwidth capping
+ * #rows: |n_addresses|
+ * #indices: 2 * |n_addresses|
+ *
+ * c 2) one active address per peer
+ * #rows: |peers|
+ * #indices: |n_addresses|
+ *
+ * c 3) minium bandwidth assigned
+ * #rows: |n_addresses|
+ * #indices: 2 * |n_addresses|
+ *
+ * c 4) minimum number of active connections
+ * #rows: 1
+ * #indices: |n_addresses|
+ *
+ * c 5) maximum ressource consumption
+ * #rows: |ressources|
+ * #indices: |n_addresses|
+ *
+ * c 10) obey network specific quota
+ * #rows: |network types
+ * #indices: |n_addresses|
+ *
+ * Sum for feasibility constraints:
+ * #rows: 3 * |n_addresses| + |ressources| + |peers| + 1
+ * #indices: 7 * |n_addresses|
+ *
+ * optimality constraints:
+ *
+ * c 6) diversity
+ * #rows: 1
+ * #indices: |n_addresses| + 1
+ *
+ * c 7) quality
+ * #rows: |quality properties|
+ * #indices: |n_addresses| + |quality properties|
+ *
+ * c 8) utilization
+ * #rows: 1
+ * #indices: |n_addresses| + 1
+ *
+ * c 9) relativity
+ * #rows: |peers|
+ * #indices: |n_addresses| + |peers|
+ * */
+
+ /* last +1 caused by glpk index starting with one: [1..pi]*/
+ int pi = ((7 * n_addresses) + (5 * n_addresses + mlp->m_q + mlp->c_p + 2) + 1);
+ mlp->cm_size = pi;
+ mlp->ci = 1;
+
+ /* row index */
+ int *ia = GNUNET_malloc (pi * sizeof (int));
+ mlp->ia = ia;
+
+ /* column index */
+ int *ja = GNUNET_malloc (pi * sizeof (int));
+ mlp->ja = ja;
+
+ /* coefficient */
+ double *ar= GNUNET_malloc (pi * sizeof (double));
+ mlp->ar = ar;
+
+ /* Adding constraint rows
+ * This constraints are kind of "for all addresses"
+ * Feasibility constraints:
+ *
+ * c 1) bandwidth capping
+ * c 3) minimum bandwidth
+ * c 4) minimum number of connections
+ * c 6) maximize diversity
+ * c 10) obey network specific quota
+ */
+
+ int min = mlp->n_min;
+ if (mlp->n_min > mlp->c_p)
+ min = mlp->c_p;
+
+ mlp->r_c4 = glp_add_rows (mlp->prob, 1);
+ glp_set_row_name (mlp->prob, mlp->r_c4, "c4");
+ glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, min, min);
+
+ /* Add row for c6) */
+
+ mlp->r_c6 = glp_add_rows (mlp->prob, 1);
+ /* Set type type to fix */
+ glp_set_row_bnds (mlp->prob, mlp->r_c6, GLP_FX, 0.0, 0.0);
+ /* Setting -D */
+ ia[mlp->ci] = mlp->r_c6 ;
+ ja[mlp->ci] = mlp->c_d;
+ ar[mlp->ci] = -1;
+ mlp->ci++;
+
+ /* Add rows for c 10) */
+ for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
+ {
+ mlp->r_quota[c] = glp_add_rows (mlp->prob, 1);
+ char * text;
+ GNUNET_asprintf(&text, "quota_ats_%i", mlp->quota_index[c]);
+ glp_set_row_name (mlp->prob, mlp->r_quota[c], text);
+ GNUNET_free (text);
+ /* Set bounds to 0 <= x <= quota_out */
+ glp_set_row_bnds (mlp->prob, mlp->r_quota[c], GLP_UP, 0.0, mlp->quota_out[c]);
+ }
+
+ GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp);
+
+ /* Adding constraint rows
+ * This constraints are kind of "for all peers"
+ * Feasibility constraints:
+ *
+ * c 2) 1 address per peer
+ * sum (n_p1_1 + ... + n_p1_n) = 1
+ *
+ * c 8) utilization
+ * sum (f_p * b_p1_1 + ... + f_p * b_p1_n) - u = 0
+ *
+ * c 9) relativity
+ * V p : sum (bt_1 + ... +bt_n) - f_p * r = 0
+ * */
+
+ /* Adding rows for c 8) */
+ mlp->r_c8 = glp_add_rows (mlp->prob, mlp->c_p);
+ glp_set_row_name (mlp->prob, mlp->r_c8, "c8");
+ /* Set row bound == 0 */
+ glp_set_row_bnds (mlp->prob, mlp->r_c8, GLP_FX, 0.0, 0.0);
+ /* -u */
+
+ ia[mlp->ci] = mlp->r_c8;
+ ja[mlp->ci] = mlp->c_u;
+ ar[mlp->ci] = -1;
+ mlp->ci++;
+
+ struct ATS_Peer * peer = mlp->peer_head;
+ while (peer != NULL)
+ {
+ struct ATS_Address *addr = peer->head;
+ struct MLP_information *mlpi = NULL;
+
+ /* Adding rows for c 2) */
+ peer->r_c2 = glp_add_rows (mlp->prob, 1);
+ GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&peer->id));
+ glp_set_row_name (mlp->prob, peer->r_c2, name);
+ GNUNET_free (name);
+ /* Set row bound == 1 */
+ glp_set_row_bnds (mlp->prob, peer->r_c2, GLP_FX, 1.0, 1.0);
+
+ /* Adding rows for c 9) */
+#if ENABLE_C9
+ peer->r_c9 = glp_add_rows (mlp->prob, 1);
+ GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&peer->id));
+ glp_set_row_name (mlp->prob, peer->r_c9, name);
+ GNUNET_free (name);
+ /* Set row bound == 0 */
+ glp_set_row_bnds (mlp->prob, peer->r_c9, GLP_LO, 0.0, 0.0);
+
+ /* Set -r */
+ ia[mlp->ci] = peer->r_c9;
+ ja[mlp->ci] = mlp->c_r;
+ ar[mlp->ci] = -1;
+ mlp->ci++;
+#endif
+
+ while (addr != NULL)
+ {
+ mlpi = (struct MLP_information *) addr->mlp_information;
+
+ /* coefficient for c 2) */
+
+ ia[mlp->ci] = peer->r_c2;
+ ja[mlp->ci] = mlpi->c_n;
+ ar[mlp->ci] = 1;
+ mlp->ci++;
+
+ /* coefficient for c 8) */
+ ia[mlp->ci] = mlp->r_c8;
+ ja[mlp->ci] = mlpi->c_b;
+ ar[mlp->ci] = peer->f;
+ mlp->ci++;
+
+#if ENABLE_C9
+ /* coefficient for c 9) */
+ ia[mlp->ci] = peer->r_c9;
+ ja[mlp->ci] = mlpi->c_b;
+ ar[mlp->ci] = 1;
+ mlp->ci++;
+#endif
+
+ addr = addr->next;
+ }
+ peer = peer->next;
+ }
+
+ /* c 7) For all quality metrics */
+
+
+ for (c = 0; c < mlp->m_q; c++)
+ {
+ struct ATS_Peer *tp;
+ struct ATS_Address *ta;
+ struct MLP_information * mlpi;
+ double value = 1.0;
+
+ /* Adding rows for c 7) */
+ mlp->r_q[c] = glp_add_rows (mlp->prob, 1);
+ GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->q[c]));
+ glp_set_row_name (mlp->prob, mlp->r_q[c], name);
+ GNUNET_free (name);
+ /* Set row bound == 0 */
+ glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_LO, 0.0, 0.0);
+
+ ia[mlp->ci] = mlp->r_q[c];
+ ja[mlp->ci] = mlp->c_q[c];
+ ar[mlp->ci] = -1;
+ mlp->ci++;
+
+ for (tp = mlp->peer_head; tp != NULL; tp = tp->next)
+ for (ta = tp->head; ta != NULL; ta = ta->next)
+ {
+ mlpi = ta->mlp_information;
+ value = mlpi->q_averaged[c];
+
+ mlpi->r_q[c] = mlp->r_q[c];
+
+ ia[mlp->ci] = mlp->r_q[c];
+ ja[mlp->ci] = mlpi->c_b;
+ ar[mlp->ci] = tp->f * value;
+ mlp->ci++;
+ }
+ }
+}
+
+
+/**
+ * Add columns for all addresses
+ *
+ * @param cls GAS_MLP_Handle
+ * @param key Hashcode
+ * @param value ATS_Address
+ *
+ * @return GNUNET_OK to continue
+ */
+static int
+create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct GAS_MLP_Handle *mlp = cls;
+ struct ATS_Address *address = value;
+ struct MLP_information *mlpi;
+ unsigned int col;
+ char *name;
+
+ GNUNET_assert (address->mlp_information != NULL);
+ mlpi = address->mlp_information;
+
+ /* Add bandwidth column */
+ col = glp_add_cols (mlp->prob, 2);
+ mlpi->c_b = col;
+ mlpi->c_n = col + 1;
+
+
+ GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
+ glp_set_col_name (mlp->prob, mlpi->c_b , name);
+ GNUNET_free (name);
+ /* Lower bound == 0 */
+ glp_set_col_bnds (mlp->prob, mlpi->c_b , GLP_LO, 0.0, 0.0);
+ /* Continuous value*/
+ glp_set_col_kind (mlp->prob, mlpi->c_b , GLP_CV);
+ /* Objective function coefficient == 0 */
+ glp_set_obj_coef (mlp->prob, mlpi->c_b , 0);
+
+
+ /* Add usage column */
+ GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
+ glp_set_col_name (mlp->prob, mlpi->c_n, name);
+ GNUNET_free (name);
+ /* Limit value : 0 <= value <= 1 */
+ glp_set_col_bnds (mlp->prob, mlpi->c_n, GLP_DB, 0.0, 1.0);
+ /* Integer value*/
+ glp_set_col_kind (mlp->prob, mlpi->c_n, GLP_IV);
+ /* Objective function coefficient == 0 */
+ glp_set_obj_coef (mlp->prob, mlpi->c_n, 0);
+
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Create the MLP problem
+ *
+ * @param mlp the MLP handle
+ * @param addresses the hashmap containing all adresses
+ * @return GNUNET_OK or GNUNET_SYSERR
+ */
+static int
+mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
+{
+ int res = GNUNET_OK;
+ int col;
+ int c;
+ char *name;
+
+ GNUNET_assert (mlp->prob == NULL);
+
+ /* create the glpk problem */
+ mlp->prob = glp_create_prob ();
+
+ /* Set a problem name */
+ glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution");
+
+ /* Set optimization direction to maximize */
+ glp_set_obj_dir (mlp->prob, GLP_MAX);
+
+ /* Adding invariant columns */
+
+ /* Diversity d column */
+
+ col = glp_add_cols (mlp->prob, 1);
+ mlp->c_d = col;
+ /* Column name */
+ glp_set_col_name (mlp->prob, col, "d");
+ /* Column objective function coefficient */
+ glp_set_obj_coef (mlp->prob, col, mlp->co_D);
+ /* Column lower bound = 0.0 */
+ glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
+
+ /* Utilization u column */
+
+ col = glp_add_cols (mlp->prob, 1);
+ mlp->c_u = col;
+ /* Column name */
+ glp_set_col_name (mlp->prob, col, "u");
+ /* Column objective function coefficient */
+ glp_set_obj_coef (mlp->prob, col, mlp->co_U);
+ /* Column lower bound = 0.0 */
+ glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
+
+#if ENABLE_C9
+ /* Relativity r column */
+ col = glp_add_cols (mlp->prob, 1);
+ mlp->c_r = col;
+ /* Column name */
+ glp_set_col_name (mlp->prob, col, "r");
+ /* Column objective function coefficient */
+ glp_set_obj_coef (mlp->prob, col, mlp->co_R);
+ /* Column lower bound = 0.0 */
+ glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
+#endif
+
+ /* Quality metric columns */
+ col = glp_add_cols(mlp->prob, mlp->m_q);
+ for (c = 0; c < mlp->m_q; c++)
+ {
+ mlp->c_q[c] = col + c;
+ GNUNET_asprintf (&name, "q_%u", mlp->q[c]);
+ glp_set_col_name (mlp->prob, col + c, name);
+ /* Column lower bound = 0.0 */
+ glp_set_col_bnds (mlp->prob, col + c, GLP_LO, 0.0, 0.0);
+ GNUNET_free (name);
+ /* Coefficient == Qm */
+ glp_set_obj_coef (mlp->prob, col + c, mlp->co_Q[c]);
+ }
+
+ /* Add columns for addresses */
+ GNUNET_CONTAINER_multihashmap_iterate (addresses, create_columns_it, mlp);
+
+ /* Add constraints */
+ mlp_add_constraints_all_addresses (mlp, addresses);
+
+ /* Load the matrix */
+ glp_load_matrix(mlp->prob, (mlp->ci-1), mlp->ia, mlp->ja, mlp->ar);
+
+ return res;
+}
+
+/**
+ * Solves the LP problem
+ *
+ * @param mlp the MLP Handle
+ * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
+ */
+static int
+mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
+{
+ int res;
+ struct GNUNET_TIME_Relative duration;
+ struct GNUNET_TIME_Absolute end;
+ struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
+
+ /* LP presolver?
+ * Presolver is required if the problem was modified and an existing
+ * valid basis is now invalid */
+ if (mlp->presolver_required == GNUNET_YES)
+ mlp->control_param_lp.presolve = GLP_ON;
+ else
+ mlp->control_param_lp.presolve = GLP_OFF;
+
+ /* Solve LP problem to have initial valid solution */
+lp_solv:
+ res = glp_simplex(mlp->prob, &mlp->control_param_lp);
+ if (res == 0)
+ {
+ /* The LP problem instance has been successfully solved. */
+ }
+ else if (res == GLP_EITLIM)
+ {
+ /* simplex iteration limit has been exceeded. */
+ // TODO Increase iteration limit?
+ }
+ else if (res == GLP_ETMLIM)
+ {
+ /* Time limit has been exceeded. */
+ // TODO Increase time limit?
+ }
+ else
+ {
+ /* Problem was ill-defined, retry with presolver */
+ if (mlp->presolver_required == GNUNET_NO)
+ {
+ mlp->presolver_required = GNUNET_YES;
+ goto lp_solv;
+ }
+ else
+ {
+ /* Problem was ill-defined, no way to handle that */
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "ats-mlp",
+ "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res));
+ return GNUNET_SYSERR;
+ }
+ }
+
+ end = GNUNET_TIME_absolute_get ();
+ duration = GNUNET_TIME_absolute_get_difference (start, end);
+ mlp->lp_solved++;
+ mlp->lp_total_duration =+ duration.rel_value;
+
+ GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
+ GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO);
+ GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average",
+ mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO);
+
+
+ /* Analyze problem status */
+ res = glp_get_status (mlp->prob);
+ switch (res) {
+ /* solution is optimal */
+ case GLP_OPT:
+ /* solution is feasible */
+ case GLP_FEAS:
+ break;
+
+ /* Problem was ill-defined, no way to handle that */
+ default:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "ats-mlp",
+ "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res));
+ return GNUNET_SYSERR;
+ break;
+ }
+
+ /* solved sucessfully, no presolver required next time */
+ mlp->presolver_required = GNUNET_NO;
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Solves the MLP problem
+ *
+ * @param mlp the MLP Handle
+ * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
+ */
+int
+mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
+{
+ int res;
+ struct GNUNET_TIME_Relative duration;
+ struct GNUNET_TIME_Absolute end;
+ struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
+
+ /* solve MLP problem */
+ res = glp_intopt(mlp->prob, &mlp->control_param_mlp);
+
+ if (res == 0)
+ {
+ /* The MLP problem instance has been successfully solved. */
+ }
+ else if (res == GLP_EITLIM)
+ {
+ /* simplex iteration limit has been exceeded. */
+ // TODO Increase iteration limit?
+ }
+ else if (res == GLP_ETMLIM)
+ {
+ /* Time limit has been exceeded. */
+ // TODO Increase time limit?
+ }
+ else
+ {
+ /* Problem was ill-defined, no way to handle that */
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "ats-mlp",
+ "Solving MLP problem failed: %s\n", mlp_solve_to_string(res));
+ return GNUNET_SYSERR;
+ }
+
+ end = GNUNET_TIME_absolute_get ();
+ duration = GNUNET_TIME_absolute_get_difference (start, end);
+ mlp->mlp_solved++;
+ mlp->mlp_total_duration =+ duration.rel_value;
+
+ GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
+ GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO);
+ GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average",
+ mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO);
+
+ /* Analyze problem status */
+ res = glp_mip_status(mlp->prob);
+ switch (res) {
+ /* solution is optimal */
+ case GLP_OPT:
+ /* solution is feasible */
+ case GLP_FEAS:
+ break;
+
+ /* Problem was ill-defined, no way to handle that */
+ default:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "ats-mlp",
+ "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res));
+ return GNUNET_SYSERR;
+ break;
+ }
+
+ return GNUNET_OK;
+}
+
+int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp);
+
+static void
+mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GAS_MLP_Handle *mlp = cls;
+
+ mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
+
+ if (mlp->addr_in_problem != 0)
+ GAS_mlp_solve_problem(mlp);
+}
+
+
+/**
+ * Solves the MLP problem
+ *
+ * @param mlp the MLP Handle
+ * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
+ */
+int
+GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
+{
+ int res;
+ mlp->last_execution = GNUNET_TIME_absolute_get ();
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n");
+
+
+#if WRITE_MLP
+ char * name;
+ static int i;
+ i++;
+ GNUNET_asprintf(&name, "problem_%i", i);
+ glp_write_lp (mlp->prob, 0, name);
+ GNUNET_free (name);
+# endif
+
+ res = mlp_solve_lp_problem (mlp);
+
+#if WRITE_MLP
+ GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
+ glp_print_sol (mlp->prob, name);
+ GNUNET_free (name);
+# endif
+
+ if (res != GNUNET_OK)
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
+
+ return GNUNET_SYSERR;
+ }
+
+ res = mlp_solve_mlp_problem (mlp);
+
+#if WRITE_MLP
+ GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
+ glp_print_mip (mlp->prob, name);
+ GNUNET_free (name);
+# endif
+ if (res != GNUNET_OK)
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n");
+
+ return GNUNET_SYSERR;
+ }
+
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved\n");
+ /* Process result */
+ struct ATS_Peer *p = NULL;
+ struct ATS_Address *a = NULL;
+ struct MLP_information *mlpi = NULL;
+
+ for (p = mlp->peer_head; p != NULL; p = p->next)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s'\n", GNUNET_i2s (&p->id));
+ for (a = p->head; a != NULL; a = a->next)
+ {
+ double b = 0.0;
+ double n = 0.0;
+
+ mlpi = a->mlp_information;
+
+ b = glp_mip_col_val(mlp->prob, mlpi->c_b);
+ mlpi->b = b;
+
+ n = glp_mip_col_val(mlp->prob, mlpi->c_n);
+ if (n == 1.0)
+ mlpi->n = GNUNET_YES;
+ else
+ mlpi->n = GNUNET_NO;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tAddress %s %f\n",
+ (n == 1.0) ? "[x]" : "[ ]", b);
+ }
+ }
+
+ if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(mlp->mlp_task);
+ mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
+ return res;
+}
+
+/**
+ * Init the MLP problem solving component
+ *
+ * @param cfg the GNUNET_CONFIGURATION_Handle handle
+ * @param stats the GNUNET_STATISTICS handle
+ * @param max_duration maximum numbers of iterations for the LP/MLP Solver
+ * @param max_iterations maximum time limit for the LP/MLP Solver
+ * @return struct GAS_MLP_Handle * on success, NULL on fail
+ */
+struct GAS_MLP_Handle *
+GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_STATISTICS_Handle *stats,
+ struct GNUNET_TIME_Relative max_duration,
+ unsigned int max_iterations)
+{
+ struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
+
+ double D;
+ double R;
+ double U;
+ long long unsigned int tmp;
+ unsigned int b_min;
+ unsigned int n_min;
+ struct GNUNET_TIME_Relative i_exec;
+ int c;
+
+ /* Init GLPK environment */
+ GNUNET_assert (glp_init_env() == 0);
+
+ /* Create initial MLP problem */
+ mlp->prob = glp_create_prob();
+ GNUNET_assert (mlp->prob != NULL);
+
+ mlp->BIG_M = (double) (UINT32_MAX) /10;
+
+ /* Get diversity coefficient from configuration */
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "COEFFICIENT_D",
+ &tmp))
+ D = (double) tmp / 100;
+ else
+ D = 1.0;
+
+ /* Get proportionality coefficient from configuration */
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "COEFFICIENT_R",
+ &tmp))
+ R = (double) tmp / 100;
+ else
+ R = 1.0;
+
+ /* Get utilization coefficient from configuration */
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "COEFFICIENT_U",
+ &tmp))
+ U = (double) tmp / 100;
+ else
+ U = 1.0;
+
+ /* Get quality metric coefficients from configuration */
+ int i_delay = -1;
+ int i_distance = -1;
+ int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
+ for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+ {
+ /* initialize quality coefficients with default value 1.0 */
+ mlp->co_Q[c] = 1.0;
+
+ mlp->q[c] = q[c];
+ if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
+ i_delay = c;
+ if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
+ i_distance = c;
+ }
+
+ if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "COEFFICIENT_QUALITY_DELAY",
+ &tmp)))
+
+ mlp->co_Q[i_delay] = (double) tmp / 100;
+ else
+ mlp->co_Q[i_delay] = 1.0;
+
+ if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "COEFFICIENT_QUALITY_DISTANCE",
+ &tmp)))
+ mlp->co_Q[i_distance] = (double) tmp / 100;
+ else
+ mlp->co_Q[i_distance] = 1.0;
+
+ /* Get minimum bandwidth per used address from configuration */
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "MIN_BANDWIDTH",
+ &tmp))
+ b_min = tmp;
+ else
+ {
+ b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+ }
+
+ /* Get minimum number of connections from configuration */
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+ "MIN_CONNECTIONS",
+ &tmp))
+ n_min = tmp;
+ else
+ n_min = 4;
+
+ /* Init network quotas */
+ int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
+ for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
+ {
+ mlp->quota_index[c] = quotas[c];
+ static char * entry_in = NULL;
+ static char * entry_out = NULL;
+ unsigned long long quota_in = 0;
+ unsigned long long quota_out = 0;
+
+ switch (quotas[c]) {
+ case GNUNET_ATS_NET_UNSPECIFIED:
+ entry_out = "UNSPECIFIED_QUOTA_OUT";
+ entry_in = "UNSPECIFIED_QUOTA_IN";
+ break;
+ case GNUNET_ATS_NET_LOOPBACK:
+ entry_out = "LOOPBACK_QUOTA_OUT";
+ entry_in = "LOOPBACK_QUOTA_IN";
+ break;
+ case GNUNET_ATS_NET_LAN:
+ entry_out = "LAN_QUOTA_OUT";
+ entry_in = "LAN_QUOTA_IN";
+ break;
+ case GNUNET_ATS_NET_WAN:
+ entry_out = "WAN_QUOTA_OUT";
+ entry_in = "WAN_QUOTA_IN";
+ break;
+ case GNUNET_ATS_NET_WLAN:
+ entry_out = "WLAN_QUOTA_OUT";
+ entry_in = "WLAN_QUOTA_IN";
+ break;
+ default:
+ break;
+ }
+
+ if ((entry_in == NULL) || (entry_out == NULL))
+ continue;
+
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_out, &quota_out))
+ {
+ quota_out = mlp->BIG_M;
+ }
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_in, &quota_in))
+ {
+ quota_in = mlp->BIG_M;
+ }
+ /* Check if defined quota could make problem unsolvable */
+ if ((n_min * b_min) > quota_out)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent quota configuration value `%s': " \
+ "outbound quota (%u Bps) too small for combination of minimum connections and minimum bandwidth per peer (%u * %u Bps = %u)\n", entry_out, quota_out, n_min, b_min, n_min * b_min);
+ unsigned int default_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+ if ((quota_out / n_min) > default_min)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reducing minimum bandwidth per peer to %u Bps\n",
+ (quota_out / n_min));
+ b_min = (quota_out / n_min);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reducing minimum bandwidth per peer to %u Bps and minimum connections to %u \n",
+ default_min, (quota_out / default_min));
+ b_min = default_min;
+ n_min = (quota_out / default_min);
+ }
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n",
+ entry_out, quota_out, entry_in, quota_in);
+ mlp->quota_out[c] = quota_out;
+ mlp->quota_in[c] = quota_in;
+ }
+
+ /* Get minimum number of connections from configuration */
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats",
+ "ATS_EXEC_INTERVAL",
+ &i_exec))
+ mlp->exec_interval = i_exec;
+ else
+ mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);
+
+ mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
+ mlp->max_iterations = max_iterations;
+ mlp->max_exec_duration = max_duration;
+ mlp->auto_solve = GNUNET_YES;
+
+ /* Redirect GLPK output to GNUnet logging */
+ glp_error_hook((void *) mlp, &mlp_term_hook);
+
+ /* Init LP solving parameters */
+ glp_init_smcp(&mlp->control_param_lp);
+
+ mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
+#if VERBOSE_GLPK
+ mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
+#endif
+
+ mlp->control_param_lp.it_lim = max_iterations;
+ mlp->control_param_lp.tm_lim = max_duration.rel_value;
+
+ /* Init MLP solving parameters */
+ glp_init_iocp(&mlp->control_param_mlp);
+
+ mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
+#if VERBOSE_GLPK
+ mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
+#endif
+ mlp->control_param_mlp.tm_lim = max_duration.rel_value;
+
+ mlp->last_execution = GNUNET_TIME_absolute_get_forever();
+
+ mlp->co_D = D;
+ mlp->co_R = R;
+ mlp->co_U = U;
+ mlp->b_min = b_min;
+ mlp->n_min = n_min;
+ mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
+
+ return mlp;
+}
+
+static void
+update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality metrics for peer `%s'\n",
+ GNUNET_i2s (&address->peer));
+
+ struct MLP_information *mlpi = address->mlp_information;
+ struct GNUNET_ATS_Information *ats = address->ats;
+ GNUNET_assert (mlpi != NULL);
+
+ int c;
+
+ for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+ {
+ int index = mlp_lookup_ats(address, mlp->q[c]);
+
+ if (index == GNUNET_SYSERR)
+ continue;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' value `%s': %f\n",
+ GNUNET_i2s (&address->peer),
+ mlp_ats_to_string(mlp->q[c]),
+ (double) ats[index].value);
+
+ int i = mlpi->q_avg_i[c];
+ double * qp = mlpi->q[c];
+ qp[i] = (double) ats[index].value;
+
+ int t;
+ for (t = 0; t < MLP_AVERAGING_QUEUE_LENGTH; t++)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' queue[%u]: %f\n",
+ GNUNET_i2s (&address->peer),
+ mlp_ats_to_string(mlp->q[c]),
+ t,
+ qp[t]);
+ }
+
+ if (mlpi->q_avg_i[c] + 1 < (MLP_AVERAGING_QUEUE_LENGTH))
+ mlpi->q_avg_i[c] ++;
+ else
+ mlpi->q_avg_i[c] = 0;
+
+
+ int c2;
+ int c3;
+ double avg = 0.0;
+ switch (mlp->q[c])
+ {
+ case GNUNET_ATS_QUALITY_NET_DELAY:
+ c3 = 0;
+ for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
+ {
+ if (mlpi->q[c][c2] != -1)
+ {
+ double * t2 = mlpi->q[c] ;
+ avg += t2[c2];
+ c3 ++;
+ }
+ }
+ if (c3 > 0)
+ /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
+ mlpi->q_averaged[c] = (double) c3 / avg;
+ else
+ mlpi->q_averaged[c] = 0.0;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n",
+ GNUNET_i2s (&address->peer),
+ mlp_ats_to_string(mlp->q[c]),
+ avg,
+ avg / (double) c3,
+ mlpi->q_averaged[c]);
+
+ break;
+ case GNUNET_ATS_QUALITY_NET_DISTANCE:
+ c3 = 0;
+ for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
+ {
+ if (mlpi->q[c][c2] != -1)
+ {
+ double * t2 = mlpi->q[c] ;
+ avg += t2[c2];
+ c3 ++;
+ }
+ }
+ if (c3 > 0)
+ /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
+ mlpi->q_averaged[c] = (double) c3 / avg;
+ else
+ mlpi->q_averaged[c] = 0.0;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n",
+ GNUNET_i2s (&address->peer),
+ mlp_ats_to_string(mlp->q[c]),
+ avg,
+ avg / (double) c3,
+ mlpi->q_averaged[c]);
+
+ break;
+ default:
+ break;
+ }
+
+ if ((mlpi->c_b != 0) && (mlpi->r_q[c] != 0))
+ {
+
+ /* Get current number of columns */
+ int found = GNUNET_NO;
+ int cols = glp_get_num_cols(mlp->prob);
+ int *ind = GNUNET_malloc (cols * sizeof (int) + 1);
+ double *val = GNUNET_malloc (cols * sizeof (double) + 1);
+
+ /* Get the matrix row of quality */
+ int length = glp_get_mat_row(mlp->prob, mlp->r_q[c], ind, val);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "cols %i, length %i c_b %i\n", cols, length, mlpi->c_b);
+ int c4;
+ /* Get the index if matrix row of quality */
+ for (c4 = 1; c4 <= length; c4++ )
+ {
+ if (mlpi->c_b == ind[c4])
+ {
+ /* Update the value */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality `%s' column `%s' row `%s' : %f -> %f\n",
+ mlp_ats_to_string(mlp->q[c]),
+ glp_get_col_name (mlp->prob, ind[c4]),
+ glp_get_row_name (mlp->prob, mlp->r_q[c]),
+ val[c4],
+ mlpi->q_averaged[c]);
+ val[c4] = mlpi->q_averaged[c];
+ found = GNUNET_YES;
+ break;
+ }
+ }
+
+ if (found == GNUNET_NO)
+ {
+
+ ind[length+1] = mlpi->c_b;
+ val[length+1] = mlpi->q_averaged[c];
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%i ind[%i] val[%i]: %i %f\n", length+1, length+1, length+1, mlpi->c_b, mlpi->q_averaged[c]);
+ glp_set_mat_row (mlp->prob, mlpi->r_q[c], length+1, ind, val);
+ }
+ else
+ {
+ /* Get the index if matrix row of quality */
+ glp_set_mat_row (mlp->prob, mlpi->r_q[c], length, ind, val);
+ }
+
+ GNUNET_free (ind);
+ GNUNET_free (val);
+ }
+ }
+}
+
+/**
+ * Updates a single address in the MLP problem
+ *
+ * If the address did not exist before in the problem:
+ * The MLP problem has to be recreated and the problem has to be resolved
+ *
+ * Otherwise the addresses' values can be updated and the existing base can
+ * be reused
+ *
+ * @param mlp the MLP Handle
+ * @param addresses the address hashmap
+ * the address has to be already removed from the hashmap
+ * @param address the address to update
+ */
+void
+GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+{
+ int new;
+ struct MLP_information *mlpi;
+
+ GNUNET_STATISTICS_update (mlp->stats,"# LP address updates", 1, GNUNET_NO);
+
+ /* We add a new address */
+ if (address->mlp_information == NULL)
+ new = GNUNET_YES;
+ else
+ new = GNUNET_NO;
+
+ /* Do the update */
+ if (new == GNUNET_YES)
+ {
+ mlpi = GNUNET_malloc (sizeof (struct MLP_information));
+
+ int c;
+ for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+ {
+ int c2;
+ mlpi->r_q[c] = 0;
+ for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
+ mlpi->q[c][c2] = -1.0; /* -1.0: invalid value */
+ mlpi->q_avg_i[c] = 0;
+ mlpi->q_averaged[c] = 0.0;
+ }
+
+ address->mlp_information = mlpi;
+ mlp->addr_in_problem ++;
+
+ /* Check for and add peer */
+ struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
+ if (peer == NULL)
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer `%s'\n",
+ GNUNET_i2s (&address->peer));
+
+ peer = GNUNET_malloc (sizeof (struct ATS_Peer));
+ peer->head = NULL;
+ peer->tail = NULL;
+
+ int c;
+ for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+ {
+ peer->f_q[c] = 1.0;
+ }
+ peer->f = 1.0;
+
+ memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity));
+ GNUNET_assert(address->prev == NULL);
+ GNUNET_assert(address->next == NULL);
+ GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
+ GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer);
+ mlp->c_p ++;
+ }
+ else
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding address to peer `%s'\n",
+ GNUNET_i2s (&address->peer));
+
+ GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
+ }
+
+ update_quality (mlp, address);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating existing address to peer `%s'\n",
+ GNUNET_i2s (&address->peer));
+
+ update_quality (mlp, address);
+ }
+
+ /* Recalculate */
+ if (new == GNUNET_YES)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n");
+
+ mlp_delete_problem (mlp);
+ mlp_create_problem (mlp, addresses);
+ mlp->presolver_required = GNUNET_YES;
+ }
+ if (mlp->auto_solve == GNUNET_YES)
+ GAS_mlp_solve_problem (mlp);
+}
+
+/**
+ * Deletes a single address in the MLP problem
+ *
+ * The MLP problem has to be recreated and the problem has to be resolved
+ *
+ * @param mlp the MLP Handle
+ * @param addresses the address hashmap
+ * the address has to be already removed from the hashmap
+ * @param address the address to delete
+ */
+void
+GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+{
+ GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
+
+ /* Free resources */
+ if (address->mlp_information != NULL)
+ {
+ GNUNET_free (address->mlp_information);
+ address->mlp_information = NULL;
+
+ mlp->addr_in_problem --;
+ }
+
+ /* Remove from peer list */
+ struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer);
+ GNUNET_assert (head != NULL);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer));
+
+ GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address);
+ if ((head->head == NULL) && (head->tail == NULL))
+ {
+ /* No address for peer left, remove peer */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer));
+
+ GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head);
+ GNUNET_free (head);
+ mlp->c_p --;
+ }
+
+ /* Update problem */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n");
+
+ mlp_delete_problem (mlp);
+ if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0))
+ {
+ mlp_create_problem (mlp, addresses);
+
+ /* Recalculate */
+ mlp->presolver_required = GNUNET_YES;
+ if (mlp->auto_solve == GNUNET_YES)
+ GAS_mlp_solve_problem (mlp);
+ }
+}
+
+static int
+mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+
+ struct ATS_PreferedAddress *aa = (struct ATS_PreferedAddress *) cls;
+ struct ATS_Address *addr = value;
+ struct MLP_information *mlpi = addr->mlp_information;
+ if (mlpi == NULL)
+ return GNUNET_YES;
+ if (mlpi->n == GNUNET_YES)
+ {
+ aa->address = addr;
+ if (mlpi->b > (double) UINT32_MAX)
+ aa->bandwidth_out = UINT32_MAX;
+ else
+ aa->bandwidth_out = (uint32_t) mlpi->b;
+ aa->bandwidth_in = 0;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Get the preferred address for a specific peer
+ *
+ * @param mlp the MLP Handle
+ * @param addresses address hashmap
+ * @param peer the peer
+ * @return suggested address
+ */
+struct ATS_PreferedAddress *
+GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp,
+ struct GNUNET_CONTAINER_MultiHashMap * addresses,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct ATS_PreferedAddress * aa = GNUNET_malloc (sizeof (struct ATS_PreferedAddress));
+ aa->address = NULL;
+ aa->bandwidth_in = 0;
+ aa->bandwidth_out = 0;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n", GNUNET_i2s (peer));
+ GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, mlp_get_preferred_address_it, aa);
+ return aa;
+}
+
+
+/**
+ * Changes the preferences for a peer in the MLP problem
+ *
+ * @param mlp the MLP Handle
+ * @param peer the peer
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
+ const struct GNUNET_PeerIdentity *peer,
+ enum GNUNET_ATS_PreferenceKind kind,
+ float score)
+{
+ GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
+
+ struct ATS_Peer *p = mlp_find_peer (mlp, peer);
+ p = p;
+ /* Here we have to do the matching */
+}
+
+/**
+ * Shutdown the MLP problem solving component
+ * @param mlp the MLP handle
+ */
+void
+GAS_mlp_done (struct GAS_MLP_Handle *mlp)
+{
+ struct ATS_Peer * peer;
+ struct ATS_Peer * tmp;
+
+ GNUNET_assert (mlp != NULL);
+
+ if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(mlp->mlp_task);
+ mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ /* clean up peer list */
+ peer = mlp->peer_head;
+ while (peer != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
+ tmp = peer->next;
+ GNUNET_free (peer);
+ peer = tmp;
+ }
+ mlp_delete_problem (mlp);
+
+ /* Clean up GLPK environment */
+ glp_free_env();
+
+ GNUNET_free (mlp);
+}
+
+
+/* end of gnunet-service-ats_addresses_mlp.c */
diff --git a/src/ats/gnunet-service-ats_addresses_mlp.h b/src/ats/gnunet-service-ats_addresses_mlp.h
new file mode 100644
index 0000000..8f60a85
--- /dev/null
+++ b/src/ats/gnunet-service-ats_addresses_mlp.h
@@ -0,0 +1,394 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_addresses_mlp.h
+ * @brief ats mlp problem solver
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-ats_addresses.h"
+#if HAVE_LIBGLPK
+#include "glpk.h"
+#endif
+
+#ifndef GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
+#define GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
+
+#define DEBUG_MLP GNUNET_EXTRA_LOGGING
+
+#define MLP_AVERAGING_QUEUE_LENGTH 3
+
+#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3)
+#define MLP_MAX_ITERATIONS INT_MAX
+
+struct ATS_Peer
+{
+ struct ATS_Peer *next;
+ struct ATS_Peer *prev;
+
+ struct GNUNET_PeerIdentity id;
+
+ /* Array of quality preferences */
+ double f_q[GNUNET_ATS_QualityPropertiesCount];
+ /* Legacy preference value */
+ double f;
+
+ /* constraint 2: 1 address per peer*/
+ unsigned int r_c2;
+
+ /* constraint 9: relativity */
+ unsigned int r_c9;
+
+ struct ATS_Address *head;
+ struct ATS_Address *tail;
+};
+
+struct ATS_PreferedAddress
+{
+ uint32_t bandwidth_out;
+ uint32_t bandwidth_in;
+ struct ATS_Address *address;
+};
+
+/**
+ * MLP Handle
+ */
+struct GAS_MLP_Handle
+{
+ /**
+ * Statistics handle
+ */
+ struct GNUNET_STATISTICS_Handle *stats;
+
+ /**
+ * GLPK (MLP) problem object
+ */
+#if HAVE_LIBGLPK
+ glp_prob *prob;
+#else
+ void *prob;
+#endif
+
+ double BIG_M;
+
+ /**
+ * GLPK LP control parameter
+ */
+ glp_smcp control_param_lp;
+
+ /**
+ * GLPK LP control parameter
+ */
+ glp_iocp control_param_mlp;
+
+ /**
+ * Solves the task in an regular interval
+ */
+ GNUNET_SCHEDULER_TaskIdentifier mlp_task;
+
+ /**
+ * Interval between scheduled problem solving
+ */
+ struct GNUNET_TIME_Relative exec_interval;
+
+ /**
+ * Maximum execution time per problem solving
+ */
+ struct GNUNET_TIME_Relative max_exec_duration;
+
+ /**
+ * Maximum number of LP iterations per problem solving
+ */
+ unsigned int max_iterations;
+
+ /**
+ * Solve the problem automatically when updates occur?
+ * Default: GNUNET_YES
+ * Can be disabled for test and measurements
+ */
+ int auto_solve;
+
+ /* state information */
+
+ /**
+ * Do we need to use the LP presolver?
+ *
+ * If the problem addresses were added or removed and the last basis was we
+ * need to use the presolver.
+ * presolver_required == GNUNET_YES
+ *
+ * If values were modified, we can reuse a valid basis
+ * presolver_required == GNUNET_NO
+ */
+ int presolver_required;
+
+ /* statistics */
+
+ /**
+ * Time of last execution
+ */
+ struct GNUNET_TIME_Absolute last_execution;
+
+
+ /**
+ * How often was the LP problem solved
+ */
+ unsigned int lp_solved;
+
+ /**
+ * total duration of all lp solver executions
+ */
+ uint64_t lp_total_duration;
+
+ /**
+ * How often was the MLP problem solved
+ */
+ unsigned int mlp_solved;
+
+ /**
+ * total duration of all mlp solver executions
+ */
+ uint64_t mlp_total_duration;
+
+ unsigned int addr_in_problem;
+
+ /* Information about the problem */
+
+ struct ATS_Peer *peer_head;
+ struct ATS_Peer *peer_tail;
+
+ /* Number of peers */
+ unsigned int c_p;
+
+ /* current problem matrix */
+ /* row index array */
+ int *ia;
+ /* column index array */
+ int *ja;
+ /* column index array */
+ double *ar;
+ /* current size of the constraint matrix |indices| */
+ unsigned int cm_size;
+ unsigned int ci;
+
+ /* Row index constraint 2: */
+ unsigned int r_c2;
+ /* Row index constraint 4: minimum connections */
+ unsigned int r_c4;
+ /* Row index constraint 6: maximize diversity */
+ unsigned int r_c6;
+ /* Row index constraint 8: utilization*/
+ unsigned int r_c8;
+ /* Row index constraint 9: relativity*/
+ unsigned int r_c9;
+
+ /* column index Diversity (D) column */
+ int c_d;
+ double co_D;
+
+ /* column index Utilization (U) column */
+ int c_u;
+ double co_U;
+
+ /* column index Proportionality (R) column */
+ int c_r;
+ double co_R;
+
+ /* ATS Quality metrics
+ *
+ * array with GNUNET_ATS_QualityPropertiesCount elements
+ * contains mapping to GNUNET_ATS_Property*/
+ int q[GNUNET_ATS_QualityPropertiesCount];
+
+ /* column index quality metrics */
+ int c_q[GNUNET_ATS_QualityPropertiesCount];
+
+ /* column index quality metrics */
+ int r_q[GNUNET_ATS_QualityPropertiesCount];
+
+ /* quality metric coefficients*/
+ double co_Q[GNUNET_ATS_QualityPropertiesCount];
+
+ /* number of quality metrics */
+ int m_q;
+
+ /* ATS network quotas */
+ int c_quota[GNUNET_ATS_NetworkTypeCount];
+ int r_quota[GNUNET_ATS_NetworkTypeCount];
+ int quota_index [GNUNET_ATS_NetworkTypeCount];
+ unsigned long long quota_out[GNUNET_ATS_NetworkTypeCount];
+ unsigned long long quota_in[GNUNET_ATS_NetworkTypeCount];
+
+ /* ATS ressource costs
+ *
+ * array with GNUNET_ATS_QualityPropertiesCount elements
+ * contains mapping to GNUNET_ATS_Property*/
+ int rc[GNUNET_ATS_QualityPropertiesCount];
+
+ /* column index ressource costs */
+ int c_rc[GNUNET_ATS_QualityPropertiesCount];
+
+ /* ressource costs coefficients*/
+ double co_RC[GNUNET_ATS_QualityPropertiesCount];
+
+ /* number of quality metrics */
+ int m_rc;
+
+ /* minimum bandwidth assigned to an address */
+ unsigned int b_min;
+
+ /* minimum number of addresses with bandwidth assigned */
+ unsigned int n_min;
+};
+
+
+/**
+ * Address specific MLP information
+ */
+struct MLP_information
+{
+ double b;
+
+ int n;
+
+ /* bandwidth column index */
+ signed int c_b;
+
+ /* address usage column */
+ signed int c_n;
+
+ /* row indexes */
+
+ /* constraint 1: bandwidth capping */
+ unsigned int r_c1;
+
+ /* constraint 3: minimum bandwidth */
+ unsigned int r_c3;
+
+ /* Quality information row indices */
+ unsigned int r_q[GNUNET_ATS_QualityPropertiesCount];
+
+ /* Quality information */
+ double q[GNUNET_ATS_QualityPropertiesCount][MLP_AVERAGING_QUEUE_LENGTH];
+
+ /* Quality information averaged */
+ double q_averaged[GNUNET_ATS_QualityPropertiesCount];
+
+ /* Averaging index */
+ int q_avg_i[GNUNET_ATS_QualityPropertiesCount];
+};
+
+
+/**
+ * Init the MLP problem solving component
+ *
+ * @param cfg configuration handle
+ * @param stats the GNUNET_STATISTICS handle
+ * @param max_duration maximum numbers of iterations for the LP/MLP Solver
+ * @param max_iterations maximum time limit for the LP/MLP Solver
+ * @return struct GAS_MLP_Handle * on success, NULL on fail
+ */
+struct GAS_MLP_Handle *
+GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_STATISTICS_Handle *stats,
+ struct GNUNET_TIME_Relative max_duration,
+ unsigned int max_iterations);
+
+/**
+ * Solves the MLP problem on demand
+ *
+ * @param mlp the MLP Handle
+ * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
+ */
+int
+GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp);
+
+
+/**
+ * Updates a single address in the MLP problem
+ *
+ * If the address did not exist before in the problem:
+ * The MLP problem has to be recreated and the problem has to be resolved
+ *
+ * Otherwise the addresses' values can be updated and the existing base can
+ * be reused
+ *
+ * @param mlp the MLP Handle
+ * @param addresses the address hashmap
+ * the address has to be already added from the hashmap
+ * @param address the address to update
+ */
+void
+GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address);
+
+
+/**
+ * Deletes a single address in the MLP problem
+ *
+ * The MLP problem has to be recreated and the problem has to be resolved
+ *
+ * @param mlp the MLP Handle
+ * @param addresses the address hashmap
+ * the address has to be already removed from the hashmap
+ * @param address the address to delete
+ */
+void
+GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address);
+
+
+/**
+ * Changes the preferences for a peer in the MLP problem
+ *
+ * @param mlp the MLP Handle
+ * @param peer the peer
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
+ const struct GNUNET_PeerIdentity *peer,
+ enum GNUNET_ATS_PreferenceKind kind,
+ float score);
+
+
+/**
+ * Get the preferred address for a specific peer
+ *
+ * @param mlp the MLP Handle
+ * @param addresses address hashmap
+ * @param peer the peer
+ * @return suggested address
+ */
+struct ATS_PreferedAddress *
+GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp,
+ struct GNUNET_CONTAINER_MultiHashMap * addresses,
+ const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Shutdown the MLP problem solving component
+ */
+void
+GAS_mlp_done ();
+
+#endif
+/* end of gnunet-service-ats_addresses_mlp.h */
diff --git a/src/ats/gnunet-service-ats_performance.c b/src/ats/gnunet-service-ats_performance.c
new file mode 100644
index 0000000..b127656
--- /dev/null
+++ b/src/ats/gnunet-service-ats_performance.c
@@ -0,0 +1,316 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_performance.c
+ * @brief ats service, interaction with 'performance' API
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-ats.h"
+#include "gnunet-service-ats_addresses.h"
+#include "gnunet-service-ats_performance.h"
+#include "gnunet-service-ats_reservations.h"
+#include "ats.h"
+
+
+/**
+ * We keep clients that are interested in performance in a linked list.
+ */
+struct PerformanceClient
+{
+ /**
+ * Next in doubly-linked list.
+ */
+ struct PerformanceClient *next;
+
+ /**
+ * Previous in doubly-linked list.
+ */
+ struct PerformanceClient *prev;
+
+ /**
+ * Actual handle to the client.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Options for the client.
+ */
+ enum StartFlag flag;
+
+};
+
+
+/**
+ * Head of linked list of all clients to this service.
+ */
+static struct PerformanceClient *pc_head;
+
+/**
+ * Tail of linked list of all clients to this service.
+ */
+static struct PerformanceClient *pc_tail;
+
+/**
+ * Context for sending messages to performance clients.
+ */
+static struct GNUNET_SERVER_NotificationContext *nc;
+
+
+/**
+ * Find the performance client associated with the given handle.
+ *
+ * @param client server handle
+ * @return internal handle
+ */
+static struct PerformanceClient *
+find_client (struct GNUNET_SERVER_Client *client)
+{
+ struct PerformanceClient *pc;
+
+ for (pc = pc_head; pc != NULL; pc = pc->next)
+ if (pc->client == client)
+ return pc;
+ return NULL;
+}
+
+
+/**
+ * Register a new performance client.
+ *
+ * @param client handle of the new client
+ * @param flag flag specifying the type of the client
+ */
+void
+GAS_performance_add_client (struct GNUNET_SERVER_Client *client,
+ enum StartFlag flag)
+{
+ struct PerformanceClient *pc;
+
+ GNUNET_break (NULL == find_client (client));
+ pc = GNUNET_malloc (sizeof (struct PerformanceClient));
+ pc->client = client;
+ pc->flag = flag;
+ GNUNET_SERVER_notification_context_add (nc, client);
+ GNUNET_SERVER_client_keep (client);
+ GNUNET_CONTAINER_DLL_insert (pc_head, pc_tail, pc);
+}
+
+
+/**
+ * Unregister a client (which may have been a performance client,
+ * but this is not assured).
+ *
+ * @param client handle of the (now dead) client
+ */
+void
+GAS_performance_remove_client (struct GNUNET_SERVER_Client *client)
+{
+ struct PerformanceClient *pc;
+
+ pc = find_client (client);
+ if (NULL == pc)
+ return;
+ GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc);
+ GNUNET_SERVER_client_drop (client);
+ GNUNET_free (pc);
+}
+
+
+/**
+ * Transmit the given performance information to all performance
+ * clients.
+ *
+ * @param peer peer for which this is an address suggestion
+ * @param plugin_name 0-termintated string specifying the transport plugin
+ * @param plugin_addr binary address for the plugin to use
+ * @param plugin_addr_len number of bytes in plugin_addr
+ * @param atsi performance data for the address
+ * @param atsi_count number of performance records in 'ats'
+ * @param bandwidth_out assigned outbound bandwidth
+ * @param bandwidth_in assigned inbound bandwidth
+ */
+void
+GAS_performance_notify_clients (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name,
+ const void *plugin_addr, size_t plugin_addr_len,
+ const struct GNUNET_ATS_Information *atsi,
+ uint32_t atsi_count,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_out,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
+{
+ struct PerformanceClient *pc;
+ struct PeerInformationMessage *msg;
+ size_t plugin_name_length = strlen (plugin_name) + 1;
+ size_t msize =
+ sizeof (struct PeerInformationMessage) +
+ atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len +
+ plugin_name_length;
+ char buf[msize];
+ struct GNUNET_ATS_Information *atsp;
+ char *addrp;
+
+ GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ GNUNET_assert (atsi_count <
+ GNUNET_SERVER_MAX_MESSAGE_SIZE /
+ sizeof (struct GNUNET_ATS_Information));
+ msg = (struct PeerInformationMessage *) buf;
+ msg->header.size = htons (msize);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION);
+ msg->ats_count = htonl (atsi_count);
+ msg->peer = *peer;
+ msg->address_length = htons (plugin_addr_len);
+ msg->plugin_name_length = htons (plugin_name_length);
+ msg->bandwidth_out = bandwidth_out;
+ msg->bandwidth_in = bandwidth_in;
+ atsp = (struct GNUNET_ATS_Information *) &msg[1];
+ memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
+ addrp = (char *) &atsp[atsi_count];
+ memcpy (addrp, plugin_addr, plugin_addr_len);
+ strcpy (&addrp[plugin_addr_len], plugin_name);
+ for (pc = pc_head; pc != NULL; pc = pc->next)
+ if (pc->flag == START_FLAG_PERFORMANCE_WITH_PIC)
+ {
+ GNUNET_SERVER_notification_context_unicast (nc, pc->client, &msg->header,
+ GNUNET_YES);
+ GNUNET_STATISTICS_update (GSA_stats,
+ "# performance updates given to clients", 1,
+ GNUNET_NO);
+ }
+}
+
+
+/**
+ * Handle 'reservation request' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_reservation_request (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct ReservationRequestMessage *msg =
+ (const struct ReservationRequestMessage *) message;
+ struct ReservationResultMessage result;
+ int32_t amount;
+ struct GNUNET_TIME_Relative res_delay;
+
+ if (NULL == find_client (client))
+ {
+ /* missing start message! */
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
+ "RESERVATION_REQUEST");
+ amount = (int32_t) ntohl (msg->amount);
+ res_delay = GAS_reservations_reserve (&msg->peer, amount);
+ if (res_delay.rel_value > 0)
+ amount = 0;
+ result.header.size = htons (sizeof (struct ReservationResultMessage));
+ result.header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT);
+ result.amount = htonl (amount);
+ result.peer = msg->peer;
+ result.res_delay = GNUNET_TIME_relative_hton (res_delay);
+ GNUNET_STATISTICS_update (GSA_stats, "# reservation requests processed", 1,
+ GNUNET_NO);
+ GNUNET_SERVER_notification_context_unicast (nc, client, &result.header,
+ GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle 'preference change' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_preference_change (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct ChangePreferenceMessage *msg;
+ const struct PreferenceInformation *pi;
+ uint16_t msize;
+ uint32_t nump;
+ uint32_t i;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
+ "PREFERENCE_CHANGE");
+ msize = ntohs (message->size);
+ if (msize < sizeof (struct ChangePreferenceMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msg = (const struct ChangePreferenceMessage *) message;
+ nump = ntohl (msg->num_preferences);
+ if (msize !=
+ sizeof (struct ChangePreferenceMessage) +
+ nump * sizeof (struct PreferenceInformation))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_STATISTICS_update (GSA_stats, "# preference change requests processed",
+ 1, GNUNET_NO);
+ pi = (const struct PreferenceInformation *) &msg[1];
+ for (i = 0; i < nump; i++)
+ GAS_addresses_change_preference (&msg->peer,
+ (enum GNUNET_ATS_PreferenceKind)
+ ntohl (pi[i].preference_kind),
+ pi[i].preference_value);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Initialize performance subsystem.
+ *
+ * @param server handle to our server
+ */
+void
+GAS_performance_init (struct GNUNET_SERVER_Handle *server)
+{
+ nc = GNUNET_SERVER_notification_context_create (server, 128);
+}
+
+
+/**
+ * Shutdown performance subsystem.
+ */
+void
+GAS_performance_done ()
+{
+ GNUNET_SERVER_notification_context_destroy (nc);
+ nc = NULL;
+}
+
+/* end of gnunet-service-ats_performance.c */
diff --git a/src/ats/gnunet-service-ats_performance.h b/src/ats/gnunet-service-ats_performance.h
new file mode 100644
index 0000000..75d555a
--- /dev/null
+++ b/src/ats/gnunet-service-ats_performance.h
@@ -0,0 +1,123 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_performance.h
+ * @brief ats service, interaction with 'performance' API
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_ATS_PERFORMANCE_H
+#define GNUNET_SERVICE_ATS_PERFORMANCE_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet_ats_service.h"
+#include "ats.h"
+
+/**
+ * Register a new performance client.
+ *
+ * @param client handle of the new client
+ * @param flag flag specifying the type of the client
+ */
+void
+GAS_performance_add_client (struct GNUNET_SERVER_Client *client,
+ enum StartFlag flag);
+
+
+/**
+ * Unregister a client (which may have been a performance client,
+ * but this is not assured).
+ *
+ * @param client handle of the (now dead) client
+ */
+void
+GAS_performance_remove_client (struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Transmit the given performance information to all performance
+ * clients.
+ *
+ * @param peer peer for which this is an address suggestion
+ * @param plugin_name 0-termintated string specifying the transport plugin
+ * @param plugin_addr binary address for the plugin to use
+ * @param plugin_addr_len number of bytes in plugin_addr
+ * @param atsi performance data for the address
+ * @param atsi_count number of performance records in 'ats'
+ * @param bandwidth_out assigned outbound bandwidth
+ * @param bandwidth_in assigned inbound bandwidth
+ */
+void
+GAS_performance_notify_clients (const struct GNUNET_PeerIdentity *peer,
+ const char *plugin_name,
+ const void *plugin_addr, size_t plugin_addr_len,
+ const struct GNUNET_ATS_Information *atsi,
+ uint32_t atsi_count,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_out,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_in);
+
+
+/**
+ * Handle 'reservation request' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_reservation_request (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Handle 'preference change' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_preference_change (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Initialize performance subsystem.
+ *
+ * @param server handle to our server
+ */
+void
+GAS_performance_init (struct GNUNET_SERVER_Handle *server);
+
+
+/**
+ * Shutdown performance subsystem.
+ */
+void
+GAS_performance_done (void);
+
+
+/* FIXME: add API to broadcast performance updates! */
+
+#endif
+/* end of gnunet-service-ats_performance.h */
diff --git a/src/ats/gnunet-service-ats_reservations.c b/src/ats/gnunet-service-ats_reservations.c
new file mode 100644
index 0000000..d1212dd
--- /dev/null
+++ b/src/ats/gnunet-service-ats_reservations.c
@@ -0,0 +1,157 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_reservations.c
+ * @brief ats service, inbound bandwidth reservation management
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-ats_reservations.h"
+
+/**
+ * Number of seconds that available bandwidth carries over
+ * (can accumulate).
+ */
+#define MAX_BANDWIDTH_CARRY_S 5
+
+
+/**
+ * Map of peer identities to 'struct GNUNET_BANDWIDTH_Tracker *'s
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *trackers;
+
+
+/**
+ * Reserve the given amount of incoming bandwidth (in bytes) from the
+ * given peer. If a reservation is not possible right now, return how
+ * long the client should wait before trying again.
+ *
+ * @param peer peer to reserve bandwidth from
+ * @param amount number of bytes to reserve
+ * @return 0 if the reservation was successful, FOREVER if the
+ * peer is not connected, otherwise the time to wait
+ * until the reservation might succeed
+ */
+struct GNUNET_TIME_Relative
+GAS_reservations_reserve (const struct GNUNET_PeerIdentity *peer,
+ int32_t amount)
+{
+ struct GNUNET_BANDWIDTH_Tracker *tracker;
+ struct GNUNET_TIME_Relative ret;
+
+ tracker = GNUNET_CONTAINER_multihashmap_get (trackers, &peer->hashPubKey);
+ if (NULL == tracker)
+ return GNUNET_TIME_UNIT_ZERO; /* not connected, satisfy now */
+ if (amount >= 0)
+ {
+ ret = GNUNET_BANDWIDTH_tracker_get_delay (tracker, amount);
+ if (ret.rel_value > 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Delay to satisfy reservation for %d bytes is %llu ms\n",
+ (int) amount, (unsigned long long) ret.rel_value);
+ return ret;
+ }
+ }
+ (void) GNUNET_BANDWIDTH_tracker_consume (tracker, amount);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reserved %d bytes\n", (int) amount);
+ return GNUNET_TIME_UNIT_ZERO;
+}
+
+
+/**
+ * Set the amount of bandwidth the other peer could currently transmit
+ * to us (as far as we know) to the given value.
+ *
+ * @param peer identity of the peer
+ * @param bandwidth_in currently available bandwidth from that peer to
+ * this peer (estimate)
+ */
+void
+GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
+{
+ struct GNUNET_BANDWIDTH_Tracker *tracker;
+
+ tracker = GNUNET_CONTAINER_multihashmap_get (trackers, &peer->hashPubKey);
+ if (0 == ntohl (bandwidth_in.value__))
+ {
+ if (NULL == tracker)
+ return;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (trackers,
+ &peer->hashPubKey,
+ tracker));
+ GNUNET_free (tracker);
+ return;
+ }
+ if (NULL == tracker)
+ {
+ tracker = GNUNET_malloc (sizeof (struct GNUNET_BANDWIDTH_Tracker));
+ GNUNET_BANDWIDTH_tracker_init (tracker, bandwidth_in,
+ MAX_BANDWIDTH_CARRY_S);
+ GNUNET_CONTAINER_multihashmap_put (trackers, &peer->hashPubKey, tracker,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ return;
+ }
+ GNUNET_BANDWIDTH_tracker_update_quota (tracker, bandwidth_in);
+}
+
+
+/**
+ * Initialize reservations subsystem.
+ */
+void
+GAS_reservations_init ()
+{
+ trackers = GNUNET_CONTAINER_multihashmap_create (128);
+}
+
+
+/**
+ * Free memory of bandwidth tracker.
+ *
+ * @param cls NULL
+ * @param key peer identity (unused)
+ * @param value the 'struct GNUNET_BANDWIDTH_Tracker' to free
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+free_tracker (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct GNUNET_BANDWIDTH_Tracker *tracker = value;
+
+ GNUNET_free (tracker);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown reservations subsystem.
+ */
+void
+GAS_reservations_done ()
+{
+ GNUNET_CONTAINER_multihashmap_iterate (trackers, &free_tracker, NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (trackers);
+}
+
+/* end of gnunet-service-ats_reservations.c */
diff --git a/src/ats/gnunet-service-ats_reservations.h b/src/ats/gnunet-service-ats_reservations.h
new file mode 100644
index 0000000..5ddec9b
--- /dev/null
+++ b/src/ats/gnunet-service-ats_reservations.h
@@ -0,0 +1,75 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_reservations.h
+ * @brief ats service, inbound bandwidth reservation management
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_ATS_RESERVATIONS_H
+#define GNUNET_SERVICE_ATS_RESERVATIONS_H
+
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Set the amount of bandwidth the other peer could currently transmit
+ * to us (as far as we know) to the given value.
+ *
+ * @param peer identity of the peer
+ * @param bandwidth_in currently available bandwidth from that peer to
+ * this peer (estimate)
+ */
+void
+GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_in);
+
+
+/**
+ * Reserve the given amount of incoming bandwidth (in bytes) from the
+ * given peer. If a reservation is not possible right now, return how
+ * long the client should wait before trying again.
+ *
+ * @param peer peer to reserve bandwidth from
+ * @param amount number of bytes to reserve
+ * @return 0 if the reservation was successful, FOREVER if the
+ * peer is not connected, otherwise the time to wait
+ * until the reservation might succeed
+ */
+struct GNUNET_TIME_Relative
+GAS_reservations_reserve (const struct GNUNET_PeerIdentity *peer,
+ int32_t amount);
+
+
+/**
+ * Initialize reservations subsystem.
+ */
+void
+GAS_reservations_init (void);
+
+
+/**
+ * Shutdown reservations subsystem.
+ */
+void
+GAS_reservations_done (void);
+
+#endif
diff --git a/src/ats/gnunet-service-ats_scheduling.c b/src/ats/gnunet-service-ats_scheduling.c
new file mode 100644
index 0000000..72b72cd
--- /dev/null
+++ b/src/ats/gnunet-service-ats_scheduling.c
@@ -0,0 +1,409 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_scheduling.c
+ * @brief ats service, interaction with 'scheduling' API
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-ats.h"
+#include "gnunet-service-ats_addresses.h"
+#include "gnunet-service-ats_scheduling.h"
+#include "ats.h"
+
+
+/**
+ * Context for sending messages to clients.
+ */
+static struct GNUNET_SERVER_NotificationContext *nc;
+
+/**
+ * Actual handle to the client.
+ */
+static struct GNUNET_SERVER_Client *my_client;
+
+
+/**
+ * Register a new scheduling client.
+ *
+ * @param client handle of the new client
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GAS_scheduling_add_client (struct GNUNET_SERVER_Client *client)
+{
+ if (my_client != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "This ATS already has a scheduling client, refusing new scheduling client for now.\n");
+ return GNUNET_SYSERR;
+ }
+ my_client = client;
+ GNUNET_SERVER_notification_context_add (nc, client);
+ GNUNET_SERVER_client_keep (client);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Unregister a client (which may have been a scheduling client,
+ * but this is not assured).
+ *
+ * @param client handle of the (now dead) client
+ */
+void
+GAS_scheduling_remove_client (struct GNUNET_SERVER_Client *client)
+{
+ if (my_client != client)
+ return;
+ GAS_addresses_destroy_all ();
+ GNUNET_SERVER_client_drop (client);
+ my_client = NULL;
+}
+
+
+/**
+ * Transmit the given address suggestion and bandwidth update to all scheduling
+ * clients.
+ *
+ * @param peer peer for which this is an address suggestion
+ * @param plugin_name 0-termintated string specifying the transport plugin
+ * @param plugin_addr binary address for the plugin to use
+ * @param plugin_addr_len number of bytes in plugin_addr
+ * @param session_id session ID to use for the given client (other clients will see 0)
+ * @param atsi performance data for the address
+ * @param atsi_count number of performance records in 'ats'
+ * @param bandwidth_out assigned outbound bandwidth
+ * @param bandwidth_in assigned inbound bandwidth
+ */
+void
+GAS_scheduling_transmit_address_suggestion (const struct GNUNET_PeerIdentity
+ *peer, const char *plugin_name,
+ const void *plugin_addr,
+ size_t plugin_addr_len,
+ uint32_t session_id,
+ const struct GNUNET_ATS_Information
+ *atsi, uint32_t atsi_count,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_out,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_in)
+{
+ struct AddressSuggestionMessage *msg;
+ size_t plugin_name_length = strlen (plugin_name) + 1;
+ size_t msize =
+ sizeof (struct AddressSuggestionMessage) +
+ atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len +
+ plugin_name_length;
+ char buf[msize];
+ struct GNUNET_ATS_Information *atsp;
+ char *addrp;
+
+ if (my_client == NULL)
+ return;
+ GNUNET_STATISTICS_update (GSA_stats, "# address suggestions made", 1,
+ GNUNET_NO);
+ GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ GNUNET_assert (atsi_count <
+ GNUNET_SERVER_MAX_MESSAGE_SIZE /
+ sizeof (struct GNUNET_ATS_Information));
+ msg = (struct AddressSuggestionMessage *) buf;
+ msg->header.size = htons (msize);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION);
+ msg->ats_count = htonl (atsi_count);
+ msg->peer = *peer;
+ msg->address_length = htons (plugin_addr_len);
+ msg->plugin_name_length = htons (plugin_name_length);
+ msg->session_id = htonl (session_id);
+ msg->bandwidth_out = bandwidth_out;
+ msg->bandwidth_in = bandwidth_in;
+ atsp = (struct GNUNET_ATS_Information *) &msg[1];
+ memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
+ addrp = (char *) &atsp[atsi_count];
+ memcpy (addrp, plugin_addr, plugin_addr_len);
+ strcpy (&addrp[plugin_addr_len], plugin_name);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "ATS sends quota for peer `%s': (in/out) %u/%u\n",
+ GNUNET_i2s (peer), ntohl (bandwidth_in.value__),
+ ntohl (bandwidth_out.value__));
+
+ GNUNET_SERVER_notification_context_unicast (nc, my_client, &msg->header,
+ GNUNET_YES);
+}
+
+
+/**
+ * Handle 'request address' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_request_address (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct RequestAddressMessage *msg =
+ (const struct RequestAddressMessage *) message;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
+ "REQUEST_ADDRESS");
+ GNUNET_STATISTICS_update (GSA_stats, "# address requests received", 1,
+ GNUNET_NO);
+ GNUNET_break (0 == ntohl (msg->reserved));
+ GAS_addresses_request_address (&msg->peer);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle 'request address' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_request_address_cancel (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct RequestAddressMessage *msg =
+ (const struct RequestAddressMessage *) message;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
+ "REQUEST_ADDRESS_CANCEL");
+ GNUNET_break (0 == ntohl (msg->reserved));
+
+ /* TODO */
+
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle 'address update' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_address_update (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct AddressUpdateMessage *m;
+ const struct GNUNET_ATS_Information *atsi;
+ const char *address;
+ const char *plugin_name;
+ uint16_t address_length;
+ uint16_t plugin_name_length;
+ uint32_t ats_count;
+ uint16_t size;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
+ "ADDRESS_UPDATE");
+ size = ntohs (message->size);
+ if (size < sizeof (struct AddressUpdateMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ m = (const struct AddressUpdateMessage *) message;
+ ats_count = ntohl (m->ats_count);
+ address_length = ntohs (m->address_length);
+ plugin_name_length = ntohs (m->plugin_name_length);
+ atsi = (const struct GNUNET_ATS_Information *) &m[1];
+ address = (const char *) &atsi[ats_count];
+ if (plugin_name_length != 0)
+ plugin_name = &address[address_length];
+ else
+ plugin_name = "";
+
+ if ((address_length + plugin_name_length +
+ ats_count * sizeof (struct GNUNET_ATS_Information) +
+ sizeof (struct AddressUpdateMessage) != ntohs (message->size)) ||
+ (ats_count >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) ||
+ ((plugin_name_length > 0) && (plugin_name[plugin_name_length - 1] != '\0')))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_STATISTICS_update (GSA_stats, "# address updates received", 1,
+ GNUNET_NO);
+ GAS_addresses_update (&m->peer, plugin_name, address, address_length,
+ ntohl (m->session_id), atsi, ats_count);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle 'address in use' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_address_in_use (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct AddressUseMessage *m;
+ const char *address;
+ const char *plugin_name;
+ uint16_t address_length;
+ uint16_t plugin_name_length;
+
+ uint16_t size;
+ uint16_t in_use;
+
+ size = ntohs (message->size);
+ if (size < sizeof (struct AddressUseMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ m = (const struct AddressUseMessage *) message;
+
+ address_length = ntohs (m->address_length);
+ plugin_name_length = ntohs (m->plugin_name_length);
+
+ address = (const char *) &m[1];
+ if (plugin_name_length != 0)
+ plugin_name = &address[address_length];
+ else
+ plugin_name = "";
+
+ if ((address_length + plugin_name_length +
+ sizeof (struct AddressUseMessage) != ntohs (message->size)) ||
+ ((plugin_name_length > 0) &&
+ (plugin_name[plugin_name_length - 1] != '\0')))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ in_use = ntohs (m->in_use);
+ GAS_addresses_in_use (&m->peer, plugin_name, address, address_length,
+ ntohl (m->session_id), in_use);
+
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+/**
+ * Handle 'address destroyed' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_address_destroyed (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct AddressDestroyedMessage *m;
+ struct SessionReleaseMessage srm;
+ const char *address;
+ const char *plugin_name;
+ uint16_t address_length;
+ uint16_t plugin_name_length;
+ uint16_t size;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message of size %u %u\n",
+ "ADDRESS_DESTROYED", ntohs (message->size),
+ sizeof (struct AddressDestroyedMessage));
+ size = ntohs (message->size);
+ if ((size < sizeof (struct AddressDestroyedMessage)) || (client != my_client))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ m = (const struct AddressDestroyedMessage *) message;
+ GNUNET_break (0 == ntohl (m->reserved));
+ address_length = ntohs (m->address_length);
+ plugin_name_length = ntohs (m->plugin_name_length);
+ address = (const char *) &m[1];
+ if (plugin_name_length != 0)
+ plugin_name = &address[address_length];
+ else
+ plugin_name = "";
+ if ((address_length + plugin_name_length +
+ sizeof (struct AddressDestroyedMessage) != ntohs (message->size)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if ((plugin_name_length == 0) ||
+ (plugin_name[plugin_name_length - 1] != '\0'))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_STATISTICS_update (GSA_stats, "# addresses destroyed", 1, GNUNET_NO);
+ GAS_addresses_destroy (&m->peer, plugin_name, address, address_length,
+ ntohl (m->session_id));
+ if (0 != ntohl (m->session_id))
+ {
+ srm.header.type = ntohs (GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE);
+ srm.header.size = ntohs (sizeof (struct SessionReleaseMessage));
+ srm.session_id = m->session_id;
+ srm.peer = m->peer;
+ GNUNET_SERVER_notification_context_unicast (nc, client, &srm.header,
+ GNUNET_NO);
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Initialize scheduling subsystem.
+ *
+ * @param server handle to our server
+ */
+void
+GAS_scheduling_init (struct GNUNET_SERVER_Handle *server)
+{
+ nc = GNUNET_SERVER_notification_context_create (server, 128);
+}
+
+
+/**
+ * Shutdown scheduling subsystem.
+ */
+void
+GAS_scheduling_done ()
+{
+ GNUNET_SERVER_notification_context_destroy (nc);
+ nc = NULL;
+}
+
+
+/* end of gnunet-service-ats_scheduling.c */
diff --git a/src/ats/gnunet-service-ats_scheduling.h b/src/ats/gnunet-service-ats_scheduling.h
new file mode 100644
index 0000000..45fca2f
--- /dev/null
+++ b/src/ats/gnunet-service-ats_scheduling.h
@@ -0,0 +1,158 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/gnunet-service-ats_scheduling.h
+ * @brief ats service, interaction with 'scheduling' API
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_ATS_SCHEDULING_H
+#define GNUNET_SERVICE_ATS_SCHEDULING_H
+
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Register a new scheduling client.
+ *
+ * @param client handle of the new client
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+int
+GAS_scheduling_add_client (struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Unregister a client (which may have been a scheduling client,
+ * but this is not assured).
+ *
+ * @param client handle of the (now dead) client
+ */
+void
+GAS_scheduling_remove_client (struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Transmit the given address suggestion and bandwidth update to all scheduling
+ * clients.
+ *
+ * @param peer peer for which this is an address suggestion
+ * @param plugin_name 0-termintated string specifying the transport plugin
+ * @param plugin_addr binary address for the plugin to use
+ * @param plugin_addr_len number of bytes in plugin_addr
+ * @param session_id session ID to use
+ * @param atsi performance data for the address
+ * @param atsi_count number of performance records in 'ats'
+ * @param bandwidth_out assigned outbound bandwidth
+ * @param bandwidth_in assigned inbound bandwidth
+ */
+void
+GAS_scheduling_transmit_address_suggestion (const struct GNUNET_PeerIdentity
+ *peer, const char *plugin_name,
+ const void *plugin_addr,
+ size_t plugin_addr_len,
+ uint32_t session_id,
+ const struct GNUNET_ATS_Information
+ *atsi, uint32_t atsi_count,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_out,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_in);
+
+
+/**
+ * Handle 'request address' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_request_address (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Cancel 'request address' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_request_address_cancel (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Handle 'address update' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_address_update (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Handle 'address in use' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_address_in_use (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Handle 'address destroyed' messages from clients.
+ *
+ * @param cls unused, NULL
+ * @param client client that sent the request
+ * @param message the request message
+ */
+void
+GAS_handle_address_destroyed (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Initialize scheduling subsystem.
+ *
+ * @param server handle to our server
+ */
+void
+GAS_scheduling_init (struct GNUNET_SERVER_Handle *server);
+
+
+/**
+ * Shutdown scheduling subsystem.
+ */
+void
+GAS_scheduling_done (void);
+
+
+#endif
+/* end of gnunet-service-ats_scheduling.h */
diff --git a/src/ats/perf_ats_mlp.c b/src/ats/perf_ats_mlp.c
new file mode 100644
index 0000000..a15e4b4
--- /dev/null
+++ b/src/ats/perf_ats_mlp.c
@@ -0,0 +1,138 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/test_ats_mlp.c
+ * @brief test for the MLP solver
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-ats_addresses_mlp.h"
+
+#define VERBOSE GNUNET_YES
+#define VERBOSE_ARM GNUNET_NO
+
+#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3)
+#define MLP_MAX_ITERATIONS INT_MAX
+
+
+static int ret;
+
+struct GNUNET_STATISTICS_Handle * stats;
+
+struct GNUNET_CONTAINER_MultiHashMap * addresses;
+
+struct GAS_MLP_Handle *mlp;
+
+static void
+check (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+#if !HAVE_LIBGLPK
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!");
+ ret = 1;
+ return;
+#endif
+ struct ATS_Address addr[10];
+
+ stats = GNUNET_STATISTICS_create("ats", cfg);
+
+ addresses = GNUNET_CONTAINER_multihashmap_create (10);
+
+ GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &addr[0].peer.hashPubKey);
+ addr[0].mlp_information = NULL;
+ addr[0].next = NULL;
+ addr[0].prev = NULL;
+ addr[0].plugin = strdup ("dummy");
+
+ addr[1].peer = addr[0].peer;
+ addr[1].mlp_information = NULL;
+ addr[1].next = NULL;
+ addr[1].prev = NULL;
+ addr[1].plugin = strdup ("dummy2");
+
+ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+
+ mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS);
+
+ /* Add a new address */
+#if 0
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+
+ GNUNET_assert (mlp != NULL);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+ /* Update an new address */
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+ /* Add a second address for same peer */
+ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[1], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GAS_mlp_address_update (mlp, addresses, &addr[1]);
+ GNUNET_assert (mlp->addr_in_problem == 2);
+
+ /* Delete an address */
+ GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]);
+ GAS_mlp_address_delete (mlp, addresses, &addr[0]);
+ GAS_mlp_address_delete (mlp, addresses, &addr[1]);
+#endif
+ GAS_mlp_done (mlp);
+
+ GNUNET_free (addr[0].plugin);
+ GNUNET_free (addr[1].plugin);
+ GNUNET_CONTAINER_multihashmap_destroy (addresses);
+ GNUNET_STATISTICS_destroy(stats, GNUNET_NO);
+
+ ret = 0;
+ return;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+
+ static char *const argv2[] = { "test_ats_mlp",
+ "-c",
+ "test_ats_api.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#else
+ "-L", "WARNING",
+#endif
+ NULL
+ };
+
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_ats_mlp", "nohelp", options,
+ &check, NULL);
+
+
+ return ret;
+}
+
+/* end of file test_ats_api_bandwidth_consumption.c */
diff --git a/src/ats/test_ats_api.conf b/src/ats/test_ats_api.conf
new file mode 100644
index 0000000..fa379c9
--- /dev/null
+++ b/src/ats/test_ats_api.conf
@@ -0,0 +1,24 @@
+[PATHS]
+SERVICEHOME = /tmp/test-ats-api-scheduling/
+
+[arm]
+PORT = 12001
+DEFAULTSERVICES = ats
+UNIXPATH = /tmp/test-ats-scheduling-arm.sock
+
+[ats]
+#DEBUG = YES
+#PREFIX = valgrind --leak-check=full
+#WAN_QUOTA_OUT = 4294967295
+#WAN_QUOTA_IN = 4294967295
+AUTOSTART = YES
+PORT = 12002
+HOSTNAME = localhost
+HOME = $SERVICEHOME
+CONFIG = $DEFAULTCONFIG
+BINARY = gnunet-service-ats
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+UNIXPATH = /tmp/test-ats-scheduling-ats.sock
+UNIX_MATCH_UID = YES
+UNIX_MATCH_GID = YES \ No newline at end of file
diff --git a/src/ats/test_ats_api_scheduling.c b/src/ats/test_ats_api_scheduling.c
new file mode 100644
index 0000000..892186c
--- /dev/null
+++ b/src/ats/test_ats_api_scheduling.c
@@ -0,0 +1,264 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/test_ats_api_scheduling.c
+ * @brief test automatic transport selection scheduling API
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+ *
+ * TODO:
+ * - write test case
+ * - extend API to get performance data
+ * - implement simplistic strategy based on say 'lowest latency' or strict ordering
+ * - extend API to get peer preferences, implement proportional bandwidth assignment
+ * - re-implement API against a real ATS service (!)
+ */
+#include "platform.h"
+#include "gnunet_ats_service.h"
+#include "ats.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static struct GNUNET_ATS_SchedulingHandle *ats;
+
+struct GNUNET_OS_Process *arm_proc;
+
+
+
+static int ret;
+
+struct Address
+{
+ char *plugin;
+ size_t plugin_len;
+
+ void *addr;
+ size_t addr_len;
+
+ struct GNUNET_ATS_Information *ats;
+ int ats_count;
+
+ void *session;
+};
+
+struct PeerContext
+{
+ struct GNUNET_PeerIdentity id;
+
+ struct Address *addr;
+};
+
+struct Address addr[2];
+struct PeerContext p[2];
+struct GNUNET_ATS_Information atsi[2];
+
+static void
+stop_arm ()
+{
+ if (0 != GNUNET_OS_process_kill (arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ GNUNET_OS_process_wait (arm_proc);
+ GNUNET_OS_process_close (arm_proc);
+ arm_proc = NULL;
+}
+
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ if (ats != NULL)
+ GNUNET_ATS_scheduling_done (ats);
+
+ ret = GNUNET_SYSERR;
+
+ stop_arm ();
+}
+
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_ATS_scheduling_done (ats);
+
+ ret = 0;
+
+ stop_arm ();
+}
+
+
+static void
+address_suggest_cb (void *cls, const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS suggests address `%s'\n",
+ GNUNET_i2s (&address->peer));
+
+ GNUNET_assert (0 ==
+ memcmp (&address->peer, &p[0].id,
+ sizeof (struct GNUNET_PeerIdentity)));
+ GNUNET_assert (0 == strcmp (address->transport_name, addr[0].plugin));
+ GNUNET_assert (address->address_length == addr[0].addr_len);
+ GNUNET_assert (0 ==
+ memcmp (address->address, addr[0].plugin,
+ address->address_length));
+ GNUNET_assert (addr[0].session == session);
+
+
+ /* TODO ats merge
+ * GNUNET_assert (ats_count == 2);
+ * GNUNET_assert (atsi[0].type == htons (1));
+ * GNUNET_assert (atsi[0].type == htons (2));
+ * GNUNET_assert (atsi[1].type == htons (2));
+ * GNUNET_assert (atsi[1].type == htons (2));
+ */
+
+ ret = 0;
+
+ GNUNET_SCHEDULER_add_now (&end, NULL);
+}
+
+void
+start_arm (const char *cfgname)
+{
+ arm_proc =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
+ "gnunet-service-arm",
+#if VERBOSE_ARM
+ "-L", "DEBUG",
+#endif
+ "-c", cfgname, NULL);
+}
+
+static void
+check (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct GNUNET_HELLO_Address address0;
+
+ ret = GNUNET_SYSERR;
+
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ start_arm (cfgfile);
+
+ ats = GNUNET_ATS_scheduling_init (cfg, &address_suggest_cb, NULL);
+
+ if (ats == NULL)
+ {
+ ret = GNUNET_SYSERR;
+ end ();
+ return;
+ }
+
+ /* set up peer */
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &p[0].id.hashPubKey);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n",
+ GNUNET_i2s (&p[0].id));
+
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &p[1].id.hashPubKey);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n",
+ GNUNET_i2s (&p[1].id));
+
+ addr[0].plugin = "test";
+ addr[0].session = NULL;
+ addr[0].addr = GNUNET_strdup ("test");
+ addr[0].addr_len = 4;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing address creation\n");
+
+ address0.peer = p[0].id;
+ address0.transport_name = addr[0].plugin;
+ address0.address = addr[0].addr;
+ address0.address_length = addr[0].addr_len;
+ GNUNET_ATS_address_update (ats, &address0, addr[0].session, NULL, 0);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing ATS info creation\n");
+
+ atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_UP);
+ atsi[0].value = htonl (1024);
+
+ GNUNET_ATS_address_update (ats, &address0, addr[0].session, atsi, 1);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing ATS info update\n");
+
+ atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_UP);
+ atsi[0].value = htonl (2048);
+
+ atsi[1].type = htonl (GNUNET_ATS_UTILIZATION_DOWN);
+ atsi[1].value = htonl (1024);
+
+ GNUNET_ATS_address_update (ats, &address0, addr[0].session, atsi, 2);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing manual address deletion \n");
+ address0.peer = p[1].id; // FIXME: why? typo in old code?
+ GNUNET_ATS_address_update (ats, &address0, addr[0].session, NULL, 0);
+ GNUNET_ATS_address_destroyed (ats, &address0, addr[0].session);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting peer `%s'\n",
+ GNUNET_i2s (&p[0].id));
+ GNUNET_ATS_suggest_address (ats, &p[0].id);
+}
+
+int
+main (int argc, char *argv[])
+{
+ static char *const argv2[] = { "test_ats_api_scheduling",
+ "-c",
+ "test_ats_api.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#else
+ "-L", "WARNING",
+#endif
+ NULL
+ };
+
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_ats_api_scheduling", "nohelp", options, &check,
+ NULL);
+
+
+ return ret;
+}
+
+/* end of file test_ats_api_scheduling.c */
diff --git a/src/ats/test_ats_mlp.c b/src/ats/test_ats_mlp.c
new file mode 100644
index 0000000..14df2d0
--- /dev/null
+++ b/src/ats/test_ats_mlp.c
@@ -0,0 +1,199 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/test_ats_mlp.c
+ * @brief test for the MLP solver
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_ats_service.h"
+#include "gnunet-service-ats_addresses_mlp.h"
+
+#define VERBOSE GNUNET_YES
+#define VERBOSE_ARM GNUNET_NO
+
+#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3)
+#define MLP_MAX_ITERATIONS INT_MAX
+
+
+static int ret;
+
+struct GNUNET_STATISTICS_Handle * stats;
+
+struct GNUNET_CONTAINER_MultiHashMap * addresses;
+
+struct GAS_MLP_Handle *mlp;
+
+
+static void
+create_address (struct ATS_Address *addr, char * plugin, int ats_count, struct GNUNET_ATS_Information *ats)
+{
+ addr->mlp_information = NULL;
+ addr->next = NULL;
+ addr->prev = NULL;
+ addr->plugin = strdup (plugin);
+ addr->ats_count = ats_count;
+ addr->ats = ats;
+}
+
+static void
+set_ats (struct GNUNET_ATS_Information *ats, uint32_t type, uint32_t value)
+{
+ ats->type = type;
+ ats->value = value;
+}
+
+static void
+check (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+#if !HAVE_LIBGLPK
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!");
+ ret = 1;
+ return;
+#endif
+ struct ATS_Address addr[10];
+ struct ATS_PreferedAddress *res[10];
+
+ stats = GNUNET_STATISTICS_create("ats", cfg);
+
+ addresses = GNUNET_CONTAINER_multihashmap_create (10);
+
+ mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS);
+ mlp->auto_solve = GNUNET_NO;
+
+ struct GNUNET_PeerIdentity p[10];
+
+ /* Creating peer 1 */
+ GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[0].hashPubKey);
+ /* Creating peer 2 */
+ GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[1].hashPubKey);
+
+ /* Creating peer 1 address 1 */
+ addr[0].peer.hashPubKey = p[0].hashPubKey;
+ struct GNUNET_ATS_Information a1_ats[3];
+ set_ats (&a1_ats[0], GNUNET_ATS_QUALITY_NET_DISTANCE, 1);
+ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 1);
+ set_ats (&a1_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0);
+ create_address (&addr[0], "dummy", 3, &a1_ats[0]);
+ addr[0].atsp_network_type = GNUNET_ATS_NET_WAN;
+
+ /* Creating peer 1 address 2 */
+ addr[1].peer.hashPubKey = p[0].hashPubKey;
+ struct GNUNET_ATS_Information a2_ats[3];
+ set_ats (&a2_ats[1], GNUNET_ATS_QUALITY_NET_DISTANCE, 1);
+ set_ats (&a2_ats[0], GNUNET_ATS_QUALITY_NET_DELAY, 1);
+ set_ats (&a2_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0);
+ create_address (&addr[1], "dummy2", 3, &a2_ats[0]);
+ addr[1].atsp_network_type = GNUNET_ATS_NET_LAN;
+
+ /* Creating peer 2 address 1 */
+ addr[2].peer.hashPubKey = p[1].hashPubKey;
+ struct GNUNET_ATS_Information a3_ats[3];
+ set_ats (&a3_ats[1], GNUNET_ATS_QUALITY_NET_DISTANCE, 1);
+ set_ats (&a3_ats[0], GNUNET_ATS_QUALITY_NET_DELAY, 1);
+ set_ats (&a3_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0);
+ create_address (&addr[2], "dummy3", 3, &a3_ats[0]);
+ addr[2].atsp_network_type = GNUNET_ATS_NET_LAN;
+
+ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+
+ /* Add peer 1 address 1 */
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+
+ GNUNET_assert (mlp != NULL);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+ /* Update an peer 1 address 1 */
+ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 1);
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+ /* Add peer 1 address 2 */
+ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[1], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GAS_mlp_address_update (mlp, addresses, &addr[1]);
+ GNUNET_assert (mlp->addr_in_problem == 2);
+
+ /* Add peer 2 address 1 */
+ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[2].peer.hashPubKey, &addr[2], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GAS_mlp_address_update (mlp, addresses, &addr[2]);
+ GNUNET_assert (mlp->addr_in_problem == 3);
+
+ GNUNET_assert (GNUNET_OK == GAS_mlp_solve_problem(mlp));
+
+ res[0] = GAS_mlp_get_preferred_address(mlp, addresses, &p[0]);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[0]->address->plugin, res[0]->bandwidth_out);
+ res[1] = GAS_mlp_get_preferred_address(mlp, addresses, &p[1]);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[1]->address->plugin, res[1]->bandwidth_out);
+
+ /* Delete an address */
+ GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]);
+ GAS_mlp_address_delete (mlp, addresses, &addr[0]);
+ GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[1].peer.hashPubKey, &addr[1]);
+ GAS_mlp_address_delete (mlp, addresses, &addr[1]);
+ GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[2].peer.hashPubKey, &addr[2]);
+ GAS_mlp_address_delete (mlp, addresses, &addr[2]);
+
+ GNUNET_assert (mlp->addr_in_problem == 0);
+
+ GAS_mlp_done (mlp);
+
+ GNUNET_free (addr[0].plugin);
+ GNUNET_free (addr[1].plugin);
+ GNUNET_CONTAINER_multihashmap_destroy (addresses);
+ GNUNET_STATISTICS_destroy(stats, GNUNET_NO);
+
+ ret = 0;
+ return;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+
+ static char *const argv2[] = { "test_ats_mlp",
+ "-c",
+ "test_ats_api.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#else
+ "-L", "WARNING",
+#endif
+ NULL
+ };
+
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_ats_mlp", "nohelp", options,
+ &check, NULL);
+
+
+ return ret;
+}
+
+/* end of file test_ats_api_bandwidth_consumption.c */
diff --git a/src/ats/test_ats_mlp_averaging.c b/src/ats/test_ats_mlp_averaging.c
new file mode 100644
index 0000000..f7b7b1d
--- /dev/null
+++ b/src/ats/test_ats_mlp_averaging.c
@@ -0,0 +1,182 @@
+/*
+ This file is part of GNUnet.
+ (C) 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 ats/test_ats_mlp.c
+ * @brief test for the MLP solver
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_ats_service.h"
+#include "gnunet-service-ats_addresses_mlp.h"
+
+#define VERBOSE GNUNET_YES
+#define VERBOSE_ARM GNUNET_NO
+
+#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3)
+#define MLP_MAX_ITERATIONS INT_MAX
+
+
+static int ret;
+
+struct GNUNET_STATISTICS_Handle * stats;
+
+struct GNUNET_CONTAINER_MultiHashMap * addresses;
+
+struct GAS_MLP_Handle *mlp;
+
+
+static void
+create_address (struct ATS_Address *addr, char * plugin, int ats_count, struct GNUNET_ATS_Information *ats)
+{
+ addr->mlp_information = NULL;
+ addr->next = NULL;
+ addr->prev = NULL;
+ addr->plugin = strdup (plugin);
+ addr->ats_count = ats_count;
+ addr->ats = ats;
+}
+
+static void
+set_ats (struct GNUNET_ATS_Information *ats, uint32_t type, uint32_t value)
+{
+ ats->type = type;
+ ats->value = value;
+}
+
+static void
+check (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+#if !HAVE_LIBGLPK
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!");
+ ret = 1;
+ return;
+#endif
+ struct ATS_Address addr[10];
+ struct ATS_PreferedAddress *res[10];
+ struct MLP_information *mlpi;
+
+ stats = GNUNET_STATISTICS_create("ats", cfg);
+
+ addresses = GNUNET_CONTAINER_multihashmap_create (10);
+
+ mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS);
+ mlp->auto_solve = GNUNET_NO;
+
+ struct GNUNET_PeerIdentity p[10];
+
+ /* Creating peer 1 */
+ GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[0].hashPubKey);
+
+ /* Creating peer 1 address 1 */
+ addr[0].peer.hashPubKey = p[0].hashPubKey;
+ struct GNUNET_ATS_Information a1_ats[3];
+ set_ats (&a1_ats[0], GNUNET_ATS_QUALITY_NET_DISTANCE, 1);
+ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 0);
+ set_ats (&a1_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0);
+ create_address (&addr[0], "dummy", 3, &a1_ats[0]);
+ addr[0].atsp_network_type = GNUNET_ATS_NET_LAN;
+
+ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+
+ /* Add peer 1 address 1 */
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+ mlpi = addr[0].mlp_information;
+
+ GNUNET_assert (mlp != NULL);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+ /* Update an peer 1 address 1 */
+ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 20);
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+
+ /* Update an peer 1 address 1 */
+ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 10);
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+ /* Update an peer 1 address 1 */
+ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 10);
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+ /* Update an peer 1 address 1 */
+ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 30);
+ GAS_mlp_address_update (mlp, addresses, &addr[0]);
+ GNUNET_assert (mlp->addr_in_problem == 1);
+
+
+ GNUNET_assert (GNUNET_OK == GAS_mlp_solve_problem(mlp));
+
+ res[0] = GAS_mlp_get_preferred_address(mlp, addresses, &p[0]);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[0]->address->plugin, res[0]->bandwidth_out);
+ GNUNET_free (res[0]);
+
+ /* Delete an address */
+ GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]);
+ GAS_mlp_address_delete (mlp, addresses, &addr[0]);
+
+ GNUNET_assert (mlp->addr_in_problem == 0);
+
+ GAS_mlp_done (mlp);
+
+ GNUNET_free (addr[0].plugin);
+ GNUNET_CONTAINER_multihashmap_destroy (addresses);
+ GNUNET_STATISTICS_destroy(stats, GNUNET_NO);
+
+ ret = 0;
+ return;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+
+ static char *const argv2[] = { "test_ats_mlp",
+ "-c",
+ "test_ats_api.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#else
+ "-L", "WARNING",
+#endif
+ NULL
+ };
+
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_ats_mlp", "nohelp", options,
+ &check, NULL);
+
+
+ return ret;
+}
+
+/* end of file test_ats_api_bandwidth_consumption.c */