diff options
author | Bertrand Marc <beberking@gmail.com> | 2012-05-02 21:43:37 +0200 |
---|---|---|
committer | Bertrand Marc <beberking@gmail.com> | 2012-05-02 21:43:37 +0200 |
commit | 2b81464a43485fcc8ce079fafdee7b7a171835f4 (patch) | |
tree | 394774c0f735199b57d51a2d3840356317853fe1 /src/ats |
Imported Upstream version 0.9.2upstream/0.9.2
Diffstat (limited to 'src/ats')
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, "a_out)) + { + quota_out = mlp->BIG_M; + } + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_in, "a_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 */ |