gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r31244 - gnunet/src/ats


From: gnunet
Subject: [GNUnet-SVN] r31244 - gnunet/src/ats
Date: Tue, 10 Dec 2013 08:58:08 +0100

Author: wachs
Date: 2013-12-10 08:58:08 +0100 (Tue, 10 Dec 2013)
New Revision: 31244

Added:
   gnunet/src/ats/plugin_ats_mlp.c
   gnunet/src/ats/plugin_ats_mlp.h
   gnunet/src/ats/plugin_ats_proportional.c
   gnunet/src/ats/plugin_ats_proportional.h
   gnunet/src/ats/plugin_ats_ril.c
   gnunet/src/ats/plugin_ats_ril.h
Removed:
   gnunet/src/ats/libgnunet_plugin_ats_mlp.c
   gnunet/src/ats/libgnunet_plugin_ats_mlp.h
   gnunet/src/ats/libgnunet_plugin_ats_proportional.c
   gnunet/src/ats/libgnunet_plugin_ats_proportional.h
   gnunet/src/ats/libgnunet_plugin_ats_ril.c
   gnunet/src/ats/libgnunet_plugin_ats_ril.h
Modified:
   gnunet/src/ats/Makefile.am
Log:
renaming according to naming conventions


Modified: gnunet/src/ats/Makefile.am
===================================================================
--- gnunet/src/ats/Makefile.am  2013-12-09 23:22:55 UTC (rev 31243)
+++ gnunet/src/ats/Makefile.am  2013-12-10 07:58:08 UTC (rev 31244)
@@ -48,7 +48,7 @@
   -version-info 4:0:0
 
 libgnunet_plugin_ats_proportional_la_SOURCES = \
-  libgnunet_plugin_ats_proportional.c
+  plugin_ats_proportional.c
 libgnunet_plugin_ats_proportional_la_LIBADD = \
        libgnunetats.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
@@ -62,7 +62,7 @@
 
 if HAVE_LIBGLPK
 libgnunet_plugin_ats_mlp_la_SOURCES = \
-  libgnunet_plugin_ats_mlp.c
+  plugin_ats_mlp.c
 libgnunet_plugin_ats_mlp_la_LIBADD = \
        libgnunetats.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
@@ -74,7 +74,7 @@
 endif
 
 libgnunet_plugin_ats_ril_la_SOURCES = \
-  libgnunet_plugin_ats_ril.c
+  plugin_ats_ril.c
 libgnunet_plugin_ats_ril_la_LIBADD = \
   libgnunetats.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \

Deleted: gnunet/src/ats/libgnunet_plugin_ats_mlp.c
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_mlp.c   2013-12-09 23:22:55 UTC (rev 
31243)
+++ gnunet/src/ats/libgnunet_plugin_ats_mlp.c   2013-12-10 07:58:08 UTC (rev 
31244)
@@ -1,2167 +0,0 @@
-/*
-     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/libgnunet_plugin_ats_mlp.c
- * @brief ats mlp problem solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-
-#include "libgnunet_plugin_ats_mlp.h"
-
-
-/**
- *
- * NOTE: Do not modify this documentation. This documentation is based on
- * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
- * use build_txt.sh to generate plaintext output
- *
- *    The MLP solver (mlp) tries to finds an optimal bandwidth assignmentby
- *    optimizing an mixed integer programming problem. The MLP solver uses a
- *    number of constraints to find the best adddress for a peer and an optimal
- *    bandwidth assignment. mlp uses the GNU Linear Programming Kit to solve 
the
- *    MLP problem.
- *
- *    We defined a constraint system to find an optimal bandwidth assignment.
- *    This constraint system uses as an input data addresses, bandwidth quotas,
- *    preferences and quality values. This constraint system is stored in an
- *    matrix based equotation system.
- *
- *   5 Using GLPK
- *
- *    A (M)LP problem consists of a target function to optimizes, constraints
- *    and rows and columns. FIXME GLP uses three arrays to index the matrix: 
two
- *    integer arrays storing the row and column indices in the matrix and an
- *    float array to store the coeeficient.
- *
- *    To solve the problem we first find an initial solution for the LP problem
- *    using the LP solver and then find an MLP solution based on this solution
- *    using the MLP solver.
- *
- *    Solving (M)LP problems has the property that finding an initial solution
- *    for the LP problem is computationally expensive and finding the MLP
- *    solution is cheaper. This is especially interesting an existing LP
- *    solution can be reused if only coefficients in the matrix have changed
- *    (addresses updated). Only when the problem size changes (addresses added
- *    or deleted) a new LP solution has to be found.
- *
- *    Intended usage
- *    The mlp solver solves the bandwidth assignment problem only on demand 
when
- *    an address suggestion is requested. When an address is requested mlp the
- *    solves the mlp problem and if the active address or the bandwidth 
assigned
- *    changes it calls the callback to addresses. The mlp solver gets notified
- *    about new addresses (adding sessions), removed addresses (address
- *    deletions) and address updates. To benefit from the mlp properties
- *    mentioned in section 5 the solver rembers if since the last solution
- *    addresses were added or deleted (problem size changed, problem has to be
- *    rebuild and solved from sratch) or if addresses were updated and the
- *    existing solution can be reused.
- *
- *     5.1 Input data
- *
- *    The quotas for each network segment are passed by addresses. MLP can be
- *    adapted using configuration settings and uses the following parameters:
- *      * MLP_MAX_DURATION:
- *        Maximum duration for a MLP solution procees (default: 3 sec.)
- *      * MLP_MAX_DURATION:
- *        Maximum number of iterations for a MLP solution process (default:
- *        1024)
- *      * MLP_MIN_CONNECTIONS:
- *        Minimum number of desired connections (default: 4)
- *      * MLP_MIN_BANDWIDTH:
- *        Minimum amount of bandwidth assigned to an address (default: 1024)
- *      * MLP_COEFFICIENT_D:
- *        Diversity coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_R:
- *        Relativity coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_U:
- *        Utilization coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_D:
- *        Diversity coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_QUALITY_DELAY:
- *        Quality delay coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
- *        Quality distance coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
- *        Quality distance coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
- *        Quality distance coefficient (default: 1.0)
- *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
- *        Quality distance coefficient (default: 1.0)
- *
- *     5.2 Data structures used
- *
- *    mlp has for each known peer a struct ATS_Peer containing information 
about
- *    a specific peer. The address field solver_information contains 
information
- *    about the mlp properties of this address.
- *
- *     5.3 Initializing
- *
- *    During initialization mlp initializes the GLPK libray used to solve the
- *    MLP problem: it initializes the glpk environment and creates an initial 
LP
- *    problem. Next it loads the configuration values from the configuration or
- *    uses the default values configured in -addresses_mlp.h. The quotas used
- *    are given by addresses but may have to be adjusted. mlp uses a upper 
limit
- *    for the bandwidth assigned called BIG M and a minimum amount of bandwidth
- *    an address gets assigned as well as a minium desired number of
- *    connections. If the configured quota is bigger than BIG M, it is reduced
- *    to BIG M. If the configured quota is smaller than MLP_MIN_CONNECTIONS
- *    *MLP_MIN_BANDWIDTH it is increased to this value.
- *
- *     5.4 Shutdown
-
- */
-
-#define LOG(kind,...) GNUNET_log_from (kind, "ats-mlp",__VA_ARGS__)
-
-/**
- * Print debug output for mlp problem creation
- */
-#define DEBUG_MLP_PROBLEM_CREATION GNUNET_NO
-
-/**
- * Enable GLPK verbose output
- */
-#define VERBOSE_GLPK GNUNET_NO
-
-/**
- * Maximize bandwidth assigned
- *
- * This option can be used to test if problem can be solved at all without
- * optimizing for utility, diversity or relativity
- *
- */
-#define MAXIMIZE_FOR_BANDWIDTH_ASSIGNED GNUNET_NO
-
-/**
- * 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; */
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "%s", s);
-  return 1;
-}
-
-
-/**
- * Reset peers for next problem creation
- *
- * @param cls not used
- * @param key the key
- * @param value ATS_Peer
- * @return GNUNET_OK
- */
-static int
-reset_peers (void *cls,
-            const struct GNUNET_PeerIdentity *key,
-            void *value)
- {
-   struct ATS_Peer *peer = value;
-   peer->processed = GNUNET_NO;
-   return GNUNET_OK;
- }
-
-/**
- * Delete the MLP problem and free the constrain matrix
- *
- * @param mlp the MLP handle
- */
-static void
-mlp_delete_problem (struct GAS_MLP_Handle *mlp)
-{
-  int c;
-  if (mlp == NULL)
-    return;
-  if (mlp->p.prob != NULL)
-  {
-    glp_delete_prob(mlp->p.prob);
-    mlp->p.prob = NULL;
-  }
-
-  /* delete row index */
-  if (mlp->p.ia != NULL)
-  {
-    GNUNET_free (mlp->p.ia);
-    mlp->p.ia = NULL;
-  }
-
-  /* delete column index */
-  if (mlp->p.ja != NULL)
-  {
-    GNUNET_free (mlp->p.ja);
-    mlp->p.ja = NULL;
-  }
-
-  /* delete coefficients */
-  if (mlp->p.ar != NULL)
-  {
-    GNUNET_free (mlp->p.ar);
-    mlp->p.ar = NULL;
-  }
-  mlp->p.ci = 0;
-  mlp->p.prob = NULL;
-
-  mlp->p.c_d = MLP_UNDEFINED;
-  mlp->p.c_r = MLP_UNDEFINED;
-  mlp->p.r_c2 = MLP_UNDEFINED;
-  mlp->p.r_c4 = MLP_UNDEFINED;
-  mlp->p.r_c6 = MLP_UNDEFINED;
-  mlp->p.r_c9 = MLP_UNDEFINED;
-  for (c = 0; c < mlp->pv.m_q ; c ++)
-    mlp->p.r_q[c] = MLP_UNDEFINED;
-  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c ++)
-    mlp->p.r_quota[c] = MLP_UNDEFINED;
-  mlp->p.ci = MLP_UNDEFINED;
-
-
-  GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
-                                        &reset_peers, NULL);
-}
-
-
-/**
- * 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";
-    case GNUNET_ATS_UTILIZATION_OUT:
-      return "GNUNET_ATS_UTILIZATION_OUT";
-    case GNUNET_ATS_UTILIZATION_IN:
-      return "GNUNET_ATS_UTILIZATION_IN";
-    case GNUNET_ATS_UTILIZATION_PAYLOAD_OUT:
-      return "GNUNET_ATS_UTILIZATION_PAYLOAD_OUT";
-    case GNUNET_ATS_UTILIZATION_PAYLOAD_IN:
-      return "GNUNET_ATS_UTILIZATION_PAYLOAD_IN";
-    case GNUNET_ATS_COST_LAN:
-      return "GNUNET_ATS_COST_LAN";
-    case GNUNET_ATS_COST_WAN:
-      return "GNUNET_ATS_COST_LAN";
-    case GNUNET_ATS_COST_WLAN:
-      return "GNUNET_ATS_COST_WLAN";
-    case GNUNET_ATS_NETWORK_TYPE:
-      return "GNUNET_ATS_NETWORK_TYPE";
-    case GNUNET_ATS_QUALITY_NET_DELAY:
-      return "GNUNET_ATS_QUALITY_NET_DELAY";
-    case GNUNET_ATS_QUALITY_NET_DISTANCE:
-      return "GNUNET_ATS_QUALITY_NET_DISTANCE";
-    default:
-      GNUNET_break (0);
-      return "unknown";
-  }
-}
-
-/**
- * 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";
-    case GLP_FEAS:
-      return "solution is feasible";
-    case GLP_INFEAS:
-      return "solution is infeasible";
-    case GLP_NOFEAS:
-      return "no feasible solution exists";
-    case GLP_OPT:
-      return "solution is optimal";
-    case GLP_UNBND:
-      return "solution is unbounded";
-    default:
-      GNUNET_break (0);
-      return "unknown error";
-  }
-}
-
-/**
- * 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";
-    case GLP_EBADB:
-      return "invalid basis";
-    case GLP_ESING:
-      return "singular matrix";
-    case GLP_ECOND:
-      return "ill-conditioned matrix";
-    case GLP_EBOUND:
-      return "invalid bounds";
-    case GLP_EFAIL:
-      return "solver failed";
-    case GLP_EOBJLL:
-      return "objective lower limit reached";
-    case GLP_EOBJUL:
-      return "objective upper limit reached";
-    case GLP_EITLIM:
-      return "iteration limit exceeded";
-    case GLP_ETMLIM:
-      return "time limit exceeded";
-    case GLP_ENOPFS:
-      return "no primal feasible solution";
-    case GLP_ENODFS:
-      return "no dual feasible solution";
-    case GLP_EROOT:
-      return "root LP optimum not provided";
-    case GLP_ESTOP:
-      return "search terminated by application";
-    case GLP_EMIPGAP:
-      return "relative mip gap tolerance reached";
-    case GLP_ENOFEAS:
-      return "no dual feasible solution";
-    case GLP_ENOCVG:
-      return "no convergence";
-    case GLP_EINSTAB:
-      return "numerical instability";
-    case GLP_EDATA:
-      return "invalid data";
-    case GLP_ERANGE:
-      return "result out of range";
-    default:
-      GNUNET_break (0);
-      return "unknown error";
-  }
-}
-
-/**
- * Extract an ATS performance info from an address
- *
- * @param address the address
- * @param type the type to extract in HBO
- * @return the value in HBO or GNUNET_ATS_VALUE_UNDEFINED in HBO if value does 
not exist
- */
-static int
-get_performance_info (struct ATS_Address *address, uint32_t type)
-{
-  int c1;
-  GNUNET_assert (NULL != address);
-
-  if ((NULL == address->atsi) || (0 == address->atsi_count))
-      return GNUNET_ATS_VALUE_UNDEFINED;
-
-  for (c1 = 0; c1 < address->atsi_count; c1++)
-  {
-      if (ntohl(address->atsi[c1].type) == type)
-        return ntohl(address->atsi[c1].value);
-  }
-  return GNUNET_ATS_VALUE_UNDEFINED;
-}
-
-
-struct CountContext
-{
-  const struct GNUNET_CONTAINER_MultiPeerMap *peers;
-  int result;
-};
-
-static int
-mlp_create_problem_count_addresses_it (void *cls,
-                                      const struct GNUNET_PeerIdentity *key,
-                                      void *value)
-{
-  struct CountContext *cctx = cls;
-
-  /* Check if we have to add this peer due to a pending request */
-  if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->peers, key))
-    cctx->result++;
-  return GNUNET_OK;
-}
-
-
-static int
-mlp_create_problem_count_addresses (const struct GNUNET_CONTAINER_MultiPeerMap 
*peers,
-                                   const struct GNUNET_CONTAINER_MultiPeerMap 
*addresses)
-{
-  struct CountContext cctx;
-
-  cctx.peers = peers;
-  cctx.result = 0;
-  GNUNET_CONTAINER_multipeermap_iterate (addresses,
-                                        
&mlp_create_problem_count_addresses_it, &cctx);
-  return cctx.result;
-}
-
-
-/**
- * Updates an existing value in the matrix
- *
- * Extract the row, updates the value and updates the row in the problem
- *
- * @param p the mlp problem
- * @param row the row to create the value in
- * @param col the column to create the value in
- * @param val the value to set
- * @param line calling line for debbuging
- * @return GNUNET_YES value changed, GNUNET_NO value did not change, 
GNUNET_SYSERR
- * on error
- */
-static int
-mlp_create_problem_update_value (struct MLP_Problem *p,
-                              int row, int col, double val,
-                              int line)
-{
-  int c_cols;
-  int c_elems;
-  int c1;
-  int res;
-  int found;
-  double *val_array;
-  int *ind_array;
-
-  GNUNET_assert (NULL != p);
-  GNUNET_assert (NULL != p->prob);
-
-  /* Get number of columns and prepare data structure */
-  c_cols = glp_get_num_cols(p->prob);
-  if (0 >= c_cols)
-    return GNUNET_SYSERR;
-
-  val_array = GNUNET_malloc ((c_cols +1)* sizeof (double));
-  GNUNET_assert (NULL != val_array);
-  ind_array = GNUNET_malloc ((c_cols+1) * sizeof (int));
-  GNUNET_assert (NULL != ind_array);
-  /* Extract the row */
-
-  /* Update the value */
-  c_elems = glp_get_mat_row (p->prob, row, ind_array, val_array);
-  found = GNUNET_NO;
-  for (c1 = 1; c1 < (c_elems+1); c1++)
-  {
-    if (ind_array[c1] == col)
-    {
-      found = GNUNET_YES;
-      break;
-    }
-  }
-  if (GNUNET_NO == found)
-  {
-    ind_array[c_elems+1] = col;
-    val_array[c_elems+1] = val;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Setting value in [%s : %s] to `%.2f'\n",
-        glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
-        val);
-    glp_set_mat_row (p->prob, row, c_elems+1, ind_array, val_array);
-    GNUNET_free (ind_array);
-    GNUNET_free (val_array);
-    return GNUNET_YES;
-  }
-  else
-  {
-    /* Update value */
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Updating value in [%s : %s] from `%.2f' 
to `%.2f'\n",
-        glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
-        val_array[c1], val);
-    if (val != val_array[c1])
-      res = GNUNET_YES;
-    else
-      res = GNUNET_NO;
-    val_array[c1] = val;
-    /* Update the row in the matrix */
-    glp_set_mat_row (p->prob, row, c_elems, ind_array, val_array);
-  }
-
-  GNUNET_free (ind_array);
-  GNUNET_free (val_array);
-  return res;
-}
-
-/**
- * Creates a new value in the matrix
- *
- * Sets the row and column index in the problem array and increments the
- * position field
- *
- * @param p the mlp problem
- * @param row the row to create the value in
- * @param col the column to create the value in
- * @param val the value to set
- * @param line calling line for debbuging
- */
-static void
-mlp_create_problem_set_value (struct MLP_Problem *p,
-                              int row, int col, double val,
-                              int line)
-{
-  if ((p->ci) >= p->num_elements)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Request for index %u bigger 
than array size of %u\n",
-        line, p->ci + 1, p->num_elements);
-    GNUNET_break (0);
-    return;
-  }
-  if ((0 == row) || (0 == col))
-    GNUNET_break (0);
-  p->ia[p->ci] = row ;
-  p->ja[p->ci] = col;
-  p->ar[p->ci] = val;
-#if  DEBUG_MLP_PROBLEM_CREATION
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Set value [%u,%u] in index %u 
==  %.2f\n",
-      line, p->ia[p->ci], p->ja[p->ci], p->ci, p->ar[p->ci]);
-#endif
-  p->ci++;
-}
-
-static int
-mlp_create_problem_create_column (struct MLP_Problem *p, char *name,
-    unsigned int type, unsigned int bound, double lb, double ub,
-    double coef)
-{
-  int col = glp_add_cols (p->prob, 1);
-  glp_set_col_name (p->prob, col, name);
-  glp_set_col_bnds (p->prob, col, bound, lb, ub);
-  glp_set_col_kind (p->prob, col, type);
-  glp_set_obj_coef (p->prob, col, coef);
-#if  DEBUG_MLP_PROBLEM_CREATION
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added column [%u] `%s': %.2f\n",
-      col, name, coef);
-#endif
-  return col;
-}
-
-static int
-mlp_create_problem_create_constraint (struct MLP_Problem *p, char *name,
-    unsigned int bound, double lb, double ub)
-{
-  char * op;
-  int row = glp_add_rows (p->prob, 1);
-  /* set row name */
-  glp_set_row_name (p->prob, row, name);
-  /* set row bounds: <= 0 */
-  glp_set_row_bnds (p->prob, row, bound, lb, ub);
-  switch (bound)
-  {
-    case GLP_UP:
-            GNUNET_asprintf(&op, "-inf <= x <= %.2f", ub);
-            break;
-    case GLP_DB:
-            GNUNET_asprintf(&op, "%.2f <= x <= %.2f", lb, ub);
-            break;
-    case GLP_FX:
-            GNUNET_asprintf(&op, "%.2f == x == %.2f", lb, ub);
-            break;
-    case GLP_LO:
-            GNUNET_asprintf(&op, "%.2f <= x <= inf", lb);
-            break;
-    default:
-            GNUNET_asprintf(&op, "ERROR");
-            break;
-  }
-#if  DEBUG_MLP_PROBLEM_CREATION
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added row [%u] `%s': %s\n",
-        row, name, op);
-#endif
-  GNUNET_free (op);
-  return row;
-}
-
-/**
- * Create the
- * - address columns b and n
- * - address dependent constraint rows c1, c3
- * - peer dependent rows c2 and c9
- * - Set address dependent entries in problem matrix as well
- */
-static int
-mlp_create_problem_add_address_information (void *cls,
-                                           const struct GNUNET_PeerIdentity 
*key,
-                                           void *value)
-{
-  struct GAS_MLP_Handle *mlp = cls;
-  struct MLP_Problem *p = &mlp->p;
-  struct ATS_Address *address = value;
-  struct ATS_Peer *peer;
-  struct MLP_information *mlpi;
-  char *name;
-  const double *props;
-  uint32_t addr_net;
-  int c;
-
-  /* Check if we have to add this peer due to a pending request */
-  if (GNUNET_NO == 
GNUNET_CONTAINER_multipeermap_contains(mlp->requested_peers, key))
-    return GNUNET_OK;
-
-  mlpi = address->solver_information;
-  if (NULL == mlpi)
-  {
-      fprintf (stderr, "%s %p\n",GNUNET_i2s (&address->peer), address);
-      GNUNET_break (0);
-      return GNUNET_OK;
-  }
-
-  /* Get peer */
-  peer = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, key);
-  if (peer->processed == GNUNET_NO)
-  {
-      /* Add peer dependent constraints */
-      /* Add constraint c2 */
-      GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&address->peer));
-      peer->r_c2 = mlp_create_problem_create_constraint (p, name, GLP_FX, 1.0, 
1.0);
-      GNUNET_free (name);
-      /* Add constraint c9 */
-      GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&address->peer));
-      peer->r_c9 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 
0.0);
-      GNUNET_free (name);
-      /* c 9) set coefficient */
-      mlp_create_problem_set_value (p, peer->r_c9, p->c_r, -peer->f, __LINE__);
-      peer->processed = GNUNET_YES;
-  }
-
-  /* Reset addresses' solver information */
-  mlpi->c_b = 0;
-  mlpi->c_n = 0;
-  mlpi->n = 0;
-  mlpi->r_c1 = 0;
-  mlpi->r_c3 = 0;
-
-  /* Add bandwidth column */
-  GNUNET_asprintf (&name, "b_%s_%s_%p", GNUNET_i2s (&address->peer), 
address->plugin, address);
-#if TEST_MAX_BW_ASSIGNMENT
-  mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 
0.0, 1.0);
-#else
-  mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 
0.0, 0.0);
-#endif
-
-  GNUNET_free (name);
-
-  /* Add usage column */
-  GNUNET_asprintf (&name, "n_%s_%s_%p", GNUNET_i2s (&address->peer), 
address->plugin, address);
-  mlpi->c_n = mlp_create_problem_create_column (p, name, GLP_IV, GLP_DB, 0.0, 
1.0, 0.0);
-  GNUNET_free (name);
-
-  /* Add address dependent constraints */
-  /* Add constraint c1) bandwidth capping
-   * b_t  + (-M) * n_t <= 0
-   * */
-  GNUNET_asprintf(&name, "c1_%s_%s_%p", GNUNET_i2s(&address->peer), 
address->plugin, address);
-  mlpi->r_c1 = mlp_create_problem_create_constraint (p, name, GLP_UP, 0.0, 
0.0);
-  GNUNET_free (name);
-
-  /*  c1) set b = 1 coefficient */
-  mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_b, 1, __LINE__);
-  /*  c1) set n = -M coefficient */
-  mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_n, -mlp->pv.BIG_M, 
__LINE__);
-
-  /* Add constraint c 3) minimum bandwidth
-   * b_t + (-n_t * b_min) >= 0
-   * */
-  GNUNET_asprintf(&name, "c3_%s_%s_%p", GNUNET_i2s(&address->peer), 
address->plugin, address);
-  mlpi->r_c3 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 
0.0);
-  GNUNET_free (name);
-
-  /*  c3) set b = 1 coefficient */
-  mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_b, 1, __LINE__);
-  /*  c3) set n = -b_min coefficient */
-  mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_n, - ((double 
)mlp->pv.b_min), __LINE__);
-
-
-  /* Set coefficient entries in invariant rows */
-  /* c 4) minimum connections */
-  mlp_create_problem_set_value (p, p->r_c4, mlpi->c_n, 1, __LINE__);
-  /* c 6) maximize diversity */
-  mlp_create_problem_set_value (p, p->r_c6, mlpi->c_n, 1, __LINE__);
-  /* c 2) 1 address peer peer */
-  mlp_create_problem_set_value (p, peer->r_c2, mlpi->c_n, 1, __LINE__);
-  /* c 9) relativity */
-  mlp_create_problem_set_value (p, peer->r_c9, mlpi->c_b, 1, __LINE__);
-  /* c 8) utility */
-  mlp_create_problem_set_value (p, p->r_c8, mlpi->c_b, 1, __LINE__);
-
-  /* c 10) obey network specific quotas
-   * (1)*b_1 + ... + (1)*b_m <= quota_n
-   */
-  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
-  {
-    addr_net = get_performance_info (address, GNUNET_ATS_NETWORK_TYPE);
-    if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
-            addr_net = GNUNET_ATS_NET_UNSPECIFIED;
-
-    if (mlp->pv.quota_index[c] == addr_net)
-    {
-      mlp_create_problem_set_value (p, p->r_quota[c], mlpi->c_b, 1, __LINE__);
-      break;
-    }
-  }
-
-  /* c 7) Optimize quality */
-  /* For all quality metrics, set quality of this address */
-  props = mlp->get_properties (mlp->get_properties_cls, address);
-  for (c = 0; c < mlp->pv.m_q; c++)
-    mlp_create_problem_set_value (p, p->r_q[c], mlpi->c_b, props[c], __LINE__);
-
-  return GNUNET_OK;
-}
-
-/**
- * Create the invariant columns c4, c6, c10, c8, c7
- */
-static void
-mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct 
MLP_Problem *p)
-{
-  char *name;
-  int c;
-
-  /* Row for c4) minimum connection */
-  /* Number of minimum connections is min(|Peers|, n_min) */
-  p->r_c4 = mlp_create_problem_create_constraint (p, "c4", GLP_LO, 
(mlp->pv.n_min > p->num_peers) ? p->num_peers : mlp->pv.n_min, 0.0);
-
-  /* Add row for c6) */
-  p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0, 0.0);
-  /* c6 )Setting -D */
-  mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__);
-
-  /* Add rows for c 10) */
-  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
-  {
-    char * text;
-    GNUNET_asprintf(&text, "c10_quota_ats_%s",
-        GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]));
-    p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 
0.0, mlp->pv.quota_out[c]);
-    GNUNET_free (text);
-  }
-
-  /* Adding rows for c 8) */
-  p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0, 0.0);
-  /* -u */
-  mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__);
-
-  /* c 7) For all quality metrics */
-  for (c = 0; c < mlp->pv.m_q; c++)
-  {
-    GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->pv.q[c]));
-    p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0, 
0.0);
-    GNUNET_free (name);
-    mlp_create_problem_set_value (p, p->r_q[c], p->c_q[c], -1, __LINE__);
-  }
-}
-
-
-/**
- * Create the invariant columns d, u, r, q0 ... qm
- */
-static void
-mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct 
MLP_Problem *p)
-{
-  char *name;
-  int c;
-
-#if TEST_MAX_BW_ASSIGNMENT
-  mlp->pv.co_D = 0.0;
-  mlp->pv.co_U = 0.0;
-
-#endif
-  //mlp->pv.co_R = 0.0;
-
-  /* Diversity d column  */
-  p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0, 0.0, 
mlp->pv.co_D);
-
-  /* Utilization u column  */
-  p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, 0.0, 
mlp->pv.co_U);
-
-  /* Relativity r column  */
-  p->c_r = mlp_create_problem_create_column (p, "r", GLP_CV, GLP_LO, 0.0, 0.0, 
mlp->pv.co_R);
-
-  /* Quality metric columns */
-  for (c = 0; c < mlp->pv.m_q; c++)
-  {
-    GNUNET_asprintf (&name, "q_%u", mlp->pv.q[c]);
-#if TEST_MAX_BW_ASSIGNMENT
-    p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 
0.0, 0.0, 0.0);
-#else
-    p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 
0.0, 0.0, mlp->pv.co_Q[c]);
-#endif
-    GNUNET_free (name);
-  }
-}
-
-
-/**
- * Create the MLP problem
- *
- * @param mlp the MLP handle
- * @return GNUNET_OK or GNUNET_SYSERR
- */
-static int
-mlp_create_problem (struct GAS_MLP_Handle *mlp)
-{
-  struct MLP_Problem *p = &mlp->p;
-  int res = GNUNET_OK;
-
-  GNUNET_assert (p->prob == NULL);
-  GNUNET_assert (p->ia == NULL);
-  GNUNET_assert (p->ja == NULL);
-  GNUNET_assert (p->ar == NULL);
-  /* Reset MLP problem struct */
-
-  /* create the glpk problem */
-  p->prob = glp_create_prob ();
-  GNUNET_assert (NULL != p->prob);
-  p->num_peers = GNUNET_CONTAINER_multipeermap_size (mlp->requested_peers);
-  p->num_addresses = mlp_create_problem_count_addresses (mlp->requested_peers, 
mlp->addresses);
-
-  /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 
2 + 1 */
-  p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses +
-      mlp->pv.m_q + p->num_peers + 2 + 1);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality 
metrics == %u elements\n",
-       p->num_peers,
-       p->num_addresses,
-       mlp->pv.m_q,
-       p->num_elements);
-
-  /* Set a problem name */
-  glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution");
-  /* Set optimization direction to maximize */
-  glp_set_obj_dir (p->prob, GLP_MAX);
-
-  /* Create problem matrix */
-  /* last +1 caused by glpk index starting with one: [1..elements]*/
-  p->ci = 1;
-  /* row index */
-  p->ia = GNUNET_malloc (p->num_elements * sizeof (int));
-  /* column index */
-  p->ja = GNUNET_malloc (p->num_elements * sizeof (int));
-  /* coefficient */
-  p->ar = GNUNET_malloc (p->num_elements * sizeof (double));
-
-  if ((NULL == p->ia) || (NULL == p->ja) || (NULL == p->ar))
-  {
-      LOG (GNUNET_ERROR_TYPE_ERROR, _("Problem size too large, cannot allocate 
memory!\n"));
-      return GNUNET_SYSERR;
-  }
-
-  /* Adding invariant columns */
-  mlp_create_problem_add_invariant_columns (mlp, p);
-
-  /* Adding address independent constraint rows */
-  mlp_create_problem_add_invariant_rows (mlp, p);
-
-  /* Adding address dependent columns constraint rows */
-  GNUNET_CONTAINER_multipeermap_iterate (mlp->addresses,
-                                        
&mlp_create_problem_add_address_information,
-                                        mlp);
-
-  /* Load the matrix */
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n");
-  glp_load_matrix(p->prob, (p->ci)-1, p->ia, p->ja, p->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 = 0;
-
-  res = glp_simplex(mlp->p.prob, &mlp->control_param_lp);
-  if (0 == res)
-          LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n", 
res, mlp_solve_to_string(res));
-  else
-          LOG (GNUNET_ERROR_TYPE_WARNING, "Solving LP problem failed: 0x%02X 
%s\n", res, mlp_solve_to_string(res));
-
-  /* Analyze problem status  */
-  res = glp_get_status (mlp->p.prob);
-  switch (res) {
-    /* solution is optimal */
-    case GLP_OPT:
-    /* solution is feasible */
-    case GLP_FEAS:
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n",
-          res, mlp_status_to_string(res));
-      return GNUNET_OK;
-    /* Problem was ill-defined, no way to handle that */
-    default:
-      LOG (GNUNET_ERROR_TYPE_WARNING, "Solving LP problem failed, no solution: 
0x%02X %s\n",
-          res, mlp_status_to_string(res));
-      return GNUNET_SYSERR;
-  }
-}
-
-
-/**
- * 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 = 0;
-  res = glp_intopt(mlp->p.prob, &mlp->control_param_mlp);
-  if (0 == res)
-          LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem: 0x%02X %s\n", 
res, mlp_solve_to_string(res));
-  else
-          LOG (GNUNET_ERROR_TYPE_WARNING, "Solving MLP problem failed: 0x%02X 
%s\n", res, mlp_solve_to_string(res));
-  /* Analyze problem status  */
-  res = glp_mip_status(mlp->p.prob);
-  switch (res) {
-    /* solution is optimal */
-    case GLP_OPT:
-    /* solution is feasible */
-    case GLP_FEAS:
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem: 0x%02X %s\n", res, 
mlp_status_to_string(res));
-      return GNUNET_OK;
-    /* Problem was ill-defined, no way to handle that */
-    default:
-      LOG (GNUNET_ERROR_TYPE_WARNING,"Solving MLP problem failed, 0x%02X 
%s\n\n", res, mlp_status_to_string(res));
-      return GNUNET_SYSERR;
-  }
-}
-
-/**
- * Propagates the results when MLP problem was solved
- *
- * @param cls the MLP handle
- * @param key the peer identity
- * @param value the address
- * @return #GNUNET_OK to continue
- */
-int
-mlp_propagate_results (void *cls,
-                      const struct GNUNET_PeerIdentity *key,
-                      void *value)
-{
-  struct GAS_MLP_Handle *mlp = cls;
-  struct ATS_Address *address;
-  struct MLP_information *mlpi;
-  double mlp_bw_in = MLP_NaN;
-  double mlp_bw_out = MLP_NaN;
-  double mlp_use = MLP_NaN;
-
-  /* Check if we have to add this peer due to a pending request */
-  if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains 
(mlp->requested_peers,
-                                                          key))
-  {
-    return GNUNET_OK;
-  }
-  address = value;
-  GNUNET_assert (address->solver_information != NULL);
-  mlpi = address->solver_information;
-
-  mlp_bw_in = glp_mip_col_val(mlp->p.prob, mlpi->c_b);/* FIXME */
-  if (mlp_bw_in > (double) UINT32_MAX)
-  {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing 
...\n" );
-      mlp_bw_in = (double) UINT32_MAX;
-  }
-  mlp_bw_out = glp_mip_col_val(mlp->p.prob, mlpi->c_b);
-  if (mlp_bw_out > (double) UINT32_MAX)
-  {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing 
...\n" );
-      mlp_bw_out = (double) UINT32_MAX;
-  }
-  mlp_use = glp_mip_col_val(mlp->p.prob, mlpi->c_n);
-
-  /*
-   * Debug: solution
-   * LOG (GNUNET_ERROR_TYPE_INFO, "MLP result address: `%s' `%s' length %u 
session %u, mlp use %f\n",
-   *    GNUNET_i2s(&address->peer), address->plugin,
-   *    address->addr_len, address->session_id);
-   */
-
-  if (GLP_YES == mlp_use)
-  {
-    /* This address was selected by the solver to be used */
-    mlpi->n = GNUNET_YES;
-    if (GNUNET_NO == address->active)
-    {
-            /* Address was not used before, enabling address */
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : enabling address\n",
-          (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
-      address->active = GNUNET_YES;
-      address->assigned_bw_in.value__ = htonl (mlp_bw_in);
-      mlpi->b_in.value__ = htonl(mlp_bw_in);
-      address->assigned_bw_out.value__ = htonl (mlp_bw_out);
-      mlpi->b_out.value__ = htonl(mlp_bw_out);
-      if ((NULL == mlp->exclude_peer) || (0 != memcmp (&address->peer, 
mlp->exclude_peer, sizeof (address->peer))))
-        mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
-      return GNUNET_OK;
-    }
-    else if (GNUNET_YES == address->active)
-    {
-      /* Address was used before, check for bandwidth change */
-      if ((mlp_bw_out != ntohl(address->assigned_bw_out.value__)) ||
-              (mlp_bw_in != ntohl(address->assigned_bw_in.value__)))
-      {
-          LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : bandwidth changed\n",
-              (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
-          address->assigned_bw_in.value__ = htonl (mlp_bw_in);
-          mlpi->b_in.value__ = htonl(mlp_bw_in);
-          address->assigned_bw_out.value__ = htonl (mlp_bw_out);
-          mlpi->b_out.value__ = htonl(mlp_bw_out);
-          if ((NULL == mlp->exclude_peer) || (0 != memcmp (&address->peer, 
mlp->exclude_peer, sizeof (address->peer))))
-            mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
-          return GNUNET_OK;
-      }
-    }
-    else
-      GNUNET_break (0);
-  }
-  else if (GLP_NO == mlp_use)
-  {
-    /* This address was selected by the solver to be not used */
-    mlpi->n = GNUNET_NO;
-    if (GNUNET_NO == address->active)
-    {
-      /* Address was not used before, nothing to do */
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : no change\n",
-          (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
-      return GNUNET_OK;
-    }
-    else if (GNUNET_YES == address->active)
-    {
-    /* Address was used before, disabling address */
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : disabling address\n",
-        (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
-      address->active = GNUNET_NO;
-      /* Set bandwidth to 0 */
-      address->assigned_bw_in = BANDWIDTH_ZERO;
-      mlpi->b_in.value__ = htonl(mlp_bw_in);
-      address->assigned_bw_out = BANDWIDTH_ZERO;
-      mlpi->b_out.value__ = htonl(mlp_bw_out);
-      //mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
-      return GNUNET_OK;
-    }
-    else
-      GNUNET_break (0);
-  }
-  else
-    GNUNET_break (0);
-
-  return GNUNET_OK;
-}
-
-static void notify (struct GAS_MLP_Handle *mlp,
-    enum GAS_Solver_Operation op,
-    enum GAS_Solver_Status stat,
-    enum GAS_Solver_Additional_Information add)
-{
-  if (NULL != mlp->env->info_cb)
-    mlp->env->info_cb (mlp->env->info_cb_cls, op, stat, add);
-}
-/**
- * Solves the MLP problem
- *
- * @param solver the MLP Handle
- * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
- */
-int
-GAS_mlp_solve_problem (void *solver)
-{
-  struct GAS_MLP_Handle *mlp = solver;
-  char *filename;
-  int res_lp = 0;
-  int res_mip = 0;
-
-  struct GNUNET_TIME_Absolute start;
-  struct GNUNET_TIME_Relative dur_total;
-  struct GNUNET_TIME_Relative dur_setup;
-  struct GNUNET_TIME_Relative dur_lp;
-  struct GNUNET_TIME_Relative dur_mlp;
-
-  GNUNET_assert(NULL != solver);
-
-  if (GNUNET_YES == mlp->bulk_lock)
-    {
-      mlp->bulk_request++;
-      return GNUNET_NO;
-    }
-  notify(mlp, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS,
-      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
-  start = GNUNET_TIME_absolute_get();
-
-  if (0 == GNUNET_CONTAINER_multipeermap_size(mlp->requested_peers))
-    {
-      notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
-      return GNUNET_OK; /* No pending requests */
-    }
-  if (0 == GNUNET_CONTAINER_multipeermap_size(mlp->addresses))
-    {
-      notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
-      return GNUNET_OK; /* No addresses available */
-    }
-
-  if ((GNUNET_NO == mlp->mlp_prob_changed)
-      && (GNUNET_NO == mlp->mlp_prob_updated))
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n");
-      notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
-      return GNUNET_OK;
-    }
-  if (GNUNET_YES == mlp->mlp_prob_changed)
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
-      notify(mlp, GAS_OP_SOLVE_SETUP_START, GAS_STAT_SUCCESS, GAS_INFO_FULL);
-      mlp_delete_problem(mlp);
-      if (GNUNET_SYSERR == mlp_create_problem(mlp))
-        {
-          notify(mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_FAIL, GAS_INFO_FULL);
-          return GNUNET_SYSERR;
-        }
-      notify(mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_SUCCESS, GAS_INFO_FULL);
-      mlp->control_param_lp.presolve = GLP_YES;
-      mlp->control_param_mlp.presolve = GNUNET_NO; /* No presolver, we have LP 
solution */
-    }
-  else
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n");
-    }
-
-  dur_setup = GNUNET_TIME_absolute_get_duration (start);
-  mlp->control_param_lp.presolve = GLP_YES;
-  /* Run LP solver */
-
-  notify(mlp, GAS_OP_SOLVE_MLP_LP_START, GAS_STAT_SUCCESS,
-      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Running LP solver %s\n",
-      (GLP_YES == mlp->control_param_lp.presolve)? "with presolver": "without 
presolver");
-  res_lp = mlp_solve_lp_problem(mlp);
-  notify(mlp, GAS_OP_SOLVE_MLP_LP_STOP,
-      (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
-      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
-
-  dur_lp = GNUNET_TIME_absolute_get_duration (start);
-  dur_lp = GNUNET_TIME_relative_subtract(dur_lp, dur_setup);
-
-  /* Run MLP solver */
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
-  notify(mlp, GAS_OP_SOLVE_MLP_MLP_START, GAS_STAT_SUCCESS,
-      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
-  res_mip = mlp_solve_mlp_problem(mlp);
-  notify(mlp, GAS_OP_SOLVE_MLP_MLP_STOP,
-      (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
-      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
-  notify(mlp, GAS_OP_SOLVE_STOP,
-      (GNUNET_OK == res_mip) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
-      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
-
-  dur_mlp = GNUNET_TIME_absolute_get_duration (start);
-  dur_mlp = GNUNET_TIME_relative_subtract(dur_mlp, dur_setup);
-  dur_mlp = GNUNET_TIME_relative_subtract(dur_mlp, dur_lp);
-  dur_total = GNUNET_TIME_absolute_get_duration (start);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-      "Execution time for %s solve: (total/setup/lp/mlp) : %llu %llu %llu 
%llu\n",
-      (GNUNET_YES == mlp->mlp_prob_changed) ? "full" : "updated",
-      (unsigned long long) dur_total.rel_value_us,
-      (unsigned long long) dur_setup.rel_value_us,
-      (unsigned long long) dur_lp.rel_value_us,
-      (unsigned long long) dur_mlp.rel_value_us);
-
-  /* Save stats */
-  mlp->ps.lp_res = res_lp;
-  mlp->ps.mip_res = res_mip;
-  mlp->ps.lp_presolv = mlp->control_param_lp.presolve;
-  mlp->ps.mip_presolv = mlp->control_param_mlp.presolve;
-  mlp->ps.p_cols = glp_get_num_cols(mlp->p.prob);
-  mlp->ps.p_rows = glp_get_num_rows(mlp->p.prob);
-  mlp->ps.p_elements = mlp->p.num_elements;
-
-  /* Propagate result*/
-  notify(mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
-      (GNUNET_OK == res_lp) && (GNUNET_OK == res_mip) ? GAS_STAT_SUCCESS : 
GAS_STAT_FAIL,
-      GAS_INFO_NONE);
-  if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
-    {
-      GNUNET_CONTAINER_multipeermap_iterate(mlp->addresses,
-          &mlp_propagate_results, mlp);
-    }
-  notify(mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
-      (GNUNET_OK == res_lp) && (GNUNET_OK == res_mip) ? GAS_STAT_SUCCESS : 
GAS_STAT_FAIL,
-      GAS_INFO_NONE);
-
-  struct GNUNET_TIME_Absolute time = GNUNET_TIME_absolute_get();
-  if (GNUNET_YES == mlp->write_mip_mps)
-    {
-      /* Write problem to disk */
-      GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.mps", mlp->p.num_peers,
-          mlp->p.num_addresses, time.abs_value_us);
-      LOG(GNUNET_ERROR_TYPE_ERROR, "DUMP: %s \n", filename);
-      glp_write_lp(mlp->p.prob, NULL, filename);
-      GNUNET_free(filename);
-    }
-  if (GNUNET_YES == mlp->write_mip_sol)
-    {
-      /* Write solution to disk */
-      GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.sol", mlp->p.num_peers,
-          mlp->p.num_addresses, time.abs_value_us);
-      glp_print_mip(mlp->p.prob, filename);
-      LOG(GNUNET_ERROR_TYPE_ERROR, "DUMP: %s \n", filename);
-      GNUNET_free(filename);
-    }
-
-  /* Reset change and update marker */
-  mlp->control_param_lp.presolve = GLP_NO;
-  mlp->mlp_prob_updated = GNUNET_NO;
-  mlp->mlp_prob_changed = GNUNET_NO;
-
-  if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
-    return GNUNET_OK;
-  else
-    return GNUNET_SYSERR;
-}
-
-/**
- * Add a single address to the solve
- *
- * @param solver the solver Handle
- * @param address the address to add
- * @param network network type of this address
- */
-void
-GAS_mlp_address_add (void *solver,
-                    struct ATS_Address *address,
-                    uint32_t network)
-{
-  struct GAS_MLP_Handle *mlp = solver;
-  struct ATS_Peer *p;
-
-  GNUNET_assert (NULL != solver);
-  GNUNET_assert (NULL != address);
-
-  if (GNUNET_ATS_NetworkTypeCount <= network)
-  {
-   GNUNET_break (0);
-   return;
-  }
-
-  if (NULL == address->solver_information)
-  {
-      address->solver_information = GNUNET_new (struct MLP_information);
-  }
-  else
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-          _("Adding address for peer `%s' multiple times\n"),
-          GNUNET_i2s(&address->peer));
-
-  /* Is this peer included in the problem? */
-  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
-                                                     &address->peer)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' without 
address request \n", GNUNET_i2s(&address->peer));
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' with address 
request \n", GNUNET_i2s(&address->peer));
-  /* Problem size changed: new address for peer with pending request */
-  mlp->mlp_prob_changed = GNUNET_YES;
-  if (GNUNET_YES == mlp->mlp_auto_solve)
-    GAS_mlp_solve_problem (solver);
-}
-
-
-/**
- * Transport properties for this address have changed
- *
- * @param solver solver handle
- * @param address the address
- * @param type the ATSI type in HBO
- * @param abs_value the absolute value of the property
- * @param rel_value the normalized value
- */
-void
-GAS_mlp_address_property_changed (void *solver,
-                                  struct ATS_Address *address,
-                                  uint32_t type,
-                                  uint32_t abs_value,
-                                  double rel_value)
-{
-  struct MLP_information *mlpi = address->solver_information;
-  struct GAS_MLP_Handle *mlp = solver;
-  struct ATS_Peer *p;
-  int c1;
-  int type_index;
-
-  GNUNET_assert (NULL != solver);
-  GNUNET_assert (NULL != address);
-
-  if (NULL == mlpi)
-  {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-          _("Updating address property `%s' for peer `%s' %p not added 
before\n"),
-          GNUNET_ATS_print_property_type (type),
-          GNUNET_i2s(&address->peer),
-          address);
-      GNUNET_break (0);
-      return;
-  }
-
-  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
-                                                     &address->peer)))
-  {
-    /* Peer is not requested, so no need to update problem */
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating property `%s' address for peer 
`%s'\n",
-      GNUNET_ATS_print_property_type (type),
-      GNUNET_i2s(&address->peer));
-
-  /* Find row index */
-  type_index = -1;
-  for (c1 = 0; c1 < mlp->pv.m_q; c1++)
-  {
-    if (type == mlp->pv.q[c1])
-    {
-      type_index = c1;
-      break;
-    }
-  }
-  if (-1 == type_index)
-  {
-    GNUNET_break (0);
-    return; /* quality index not found */
-  }
-
-  /* Update c7) [r_q[index]][c_b] = f_q * q_averaged[type_index] */
-  if (GNUNET_YES == mlp_create_problem_update_value (&mlp->p,
-      mlp->p.r_q[type_index], mlpi->c_b, rel_value, __LINE__))
-  {
-    mlp->mlp_prob_updated = GNUNET_YES;
-    if (GNUNET_YES == mlp->mlp_auto_solve)
-      GAS_mlp_solve_problem (solver);
-  }
-}
-
-
-/**
- * Transport session for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param cur_session the current session
- * @param new_session the new session
- */
-void
-GAS_mlp_address_session_changed (void *solver,
-                                  struct ATS_Address *address,
-                                  uint32_t cur_session,
-                                  uint32_t new_session)
-{
-  /* Nothing to do here */
-  return;
-}
-
-
-/**
- * Transport session for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param in_use usage state
- */
-void
-GAS_mlp_address_inuse_changed (void *solver,
-                               struct ATS_Address *address,
-                               int in_use)
-{
-  /* Nothing to do here */
-  return;
-}
-
-
-/**
- * Network scope for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param current_network the current network
- * @param new_network the new network
- */
-void
-GAS_mlp_address_change_network (void *solver,
-                               struct ATS_Address *address,
-                               uint32_t current_network,
-                               uint32_t new_network)
-{
-  struct MLP_information *mlpi = address->solver_information;
-  struct GAS_MLP_Handle *mlp = solver;
-  struct ATS_Peer *p;
-  int nets_avail[] = GNUNET_ATS_NetworkType;
-  int c1;
-
-  GNUNET_assert (NULL != solver);
-  GNUNET_assert (NULL != address);
-
-  if (GNUNET_ATS_NetworkTypeCount <= new_network)
-  {
-   GNUNET_break (0);
-   return;
-  }
-
-  if (NULL == mlpi)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  if (mlpi->c_b == MLP_UNDEFINED)
-    return; /* This address is not yet in the matrix*/
-
-  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
-                                                     &address->peer)))
-  {
-    /* Peer is not requested, so no need to update problem */
-    GNUNET_break (0);
-    return;
-  }
-
-  if (current_network == new_network)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  for (c1 = 0; c1 < GNUNET_ATS_NetworkTypeCount ; c1 ++)
-  {
-    if (nets_avail[c1] == new_network)
-      break;
-  }
-
-  if (GNUNET_ATS_NetworkTypeCount == c1)
-  {
-    /* Invalid network */
-    GNUNET_break (0);
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating network for peer `%s' from `%s' to 
`%s'\n",
-      GNUNET_i2s (&address->peer),
-      GNUNET_ATS_print_network_type(current_network),
-      GNUNET_ATS_print_network_type(new_network));
-
-  for (c1 = 0; c1 < GNUNET_ATS_NetworkTypeCount; c1++)
-  {
-    if (mlp->pv.quota_index[c1] == current_network)
-    {
-      /* Remove from old network */
-      mlp_create_problem_update_value (&mlp->p,
-          mlp->p.r_quota[c1],
-          mlpi->c_b, 0.0, __LINE__);
-      break;
-    }
-  }
-
-  for (c1 = 0; c1 < GNUNET_ATS_NetworkTypeCount; c1++)
-  {
-    if (mlp->pv.quota_index[c1] == new_network)
-    {
-      /* Remove from old network */
-      if (GNUNET_SYSERR == mlp_create_problem_update_value (&mlp->p,
-          mlp->p.r_quota[c1],
-          mlpi->c_b, 1.0, __LINE__))
-      {
-        /* This quota did not exist in the problem, recreate */
-        GNUNET_break (0);
-      }
-      break;
-    }
-  }
-
-  mlp->mlp_prob_changed = GNUNET_YES;
-}
-
-
-/**
- * Deletes a single address in the MLP problem
- *
- * The MLP problem has to be recreated and the problem has to be resolved
- *
- * @param solver the MLP Handle
- * @param address the address to delete
- * @param session_only delete only session not whole address
- */
-void
-GAS_mlp_address_delete (void *solver,
-    struct ATS_Address *address,
-    int session_only)
-{
-  struct ATS_Peer *p;
-  struct GAS_MLP_Handle *mlp = solver;
-  struct MLP_information *mlpi;
-  int was_active;
-
-  GNUNET_assert (NULL != solver);
-  GNUNET_assert (NULL != address);
-
-  mlpi = address->solver_information;
-  if ((GNUNET_NO == session_only) && (NULL != mlpi))
-  {
-    /* Remove full address */
-    GNUNET_free (mlpi);
-    address->solver_information = NULL;
-  }
-  was_active = address->active;
-  address->active = GNUNET_NO;
-  address->assigned_bw_in = BANDWIDTH_ZERO;
-  address->assigned_bw_out = BANDWIDTH_ZERO;
-
-  /* Is this peer included in the problem? */
-  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
-                                                     &address->peer)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s for peer `%s' without address 
request \n",
-        (session_only == GNUNET_YES) ? "session" : "address",
-        GNUNET_i2s(&address->peer));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_INFO, "Deleting %s for peer `%s' with address request 
\n",
-      (session_only == GNUNET_YES) ? "session" : "address",
-      GNUNET_i2s(&address->peer));
-
-  /* Problem size changed: new address for peer with pending request */
-  mlp->mlp_prob_changed = GNUNET_YES;
-  if (GNUNET_YES == mlp->mlp_auto_solve)
-  {
-    GAS_mlp_solve_problem (solver);
-  }
-  if (GNUNET_YES == was_active)
-  {
-    if (NULL == GAS_mlp_get_preferred_address (solver, &address->peer))
-    {
-      /* No alternative address, disconnecting peer */
-      mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
-    }
-  }
-
-  return;
-}
-
-
-/**
- * Find the active address in the set of addresses of a peer
- * @param cls destination
- * @param key peer id
- * @param value address
- * @return GNUNET_OK
- */
-static int
-mlp_get_preferred_address_it (void *cls,
-                             const struct GNUNET_PeerIdentity *key,
-                             void *value)
-{
-  static int counter = 0;
-  struct ATS_Address **aa = cls;
-  struct ATS_Address *addr = value;
-  struct MLP_information *mlpi = addr->solver_information;
-
-  if (mlpi == NULL)
-    return GNUNET_YES;
-
-  /*
-   * Debug output
-   * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-   *           "MLP [%u] Peer `%s' %s length %u session %u active %s mlp 
active %s\n",
-   *           counter, GNUNET_i2s (&addr->peer), addr->plugin, 
addr->addr_len, addr->session_id,
-   *           (GNUNET_YES == addr->active) ? "active" : "inactive",
-   *           (GNUNET_YES == mlpi->n) ? "active" : "inactive");
-   */
-
-  if (GNUNET_YES == mlpi->n)
-  {
-
-    (*aa) = addr;
-    (*aa)->assigned_bw_in = mlpi->b_in;
-    (*aa)->assigned_bw_out = mlpi->b_out;
-    return GNUNET_NO;
-  }
-  counter ++;
-  return GNUNET_YES;
-}
-
-
-static double
-get_peer_pref_value (struct GAS_MLP_Handle *mlp, const struct 
GNUNET_PeerIdentity *peer)
-{
-  double res;
-  const double *preferences = NULL;
-  int c;
-  preferences = mlp->get_preferences (mlp->get_preferences_cls, peer);
-
-  res = 0.0;
-  for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
-  {
-    if (c != GNUNET_ATS_PREFERENCE_END)
-    {
-      //fprintf (stderr, "VALUE[%u] %s %.3f \n", c, GNUNET_i2s 
(&cur->addr->peer), t[c]);
-      res += preferences[c];
-    }
-  }
-  res /= (GNUNET_ATS_PreferenceCount -1);
-  return res;
-}
-
-
-/**
- * Get the preferred address for a specific peer
- *
- * @param solver the MLP Handle
- * @param peer the peer
- * @return suggested address
- */
-const struct ATS_Address *
-GAS_mlp_get_preferred_address (void *solver,
-                               const struct GNUNET_PeerIdentity *peer)
-{
-  struct GAS_MLP_Handle *mlp = solver;
-  struct ATS_Peer *p;
-  struct ATS_Address *res;
-
-  GNUNET_assert (NULL != solver);
-  GNUNET_assert (NULL != peer);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n",
-      GNUNET_i2s (peer));
-
-  /* Is this peer included in the problem? */
-  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
-                                                     peer)))
-    {
-      LOG (GNUNET_ERROR_TYPE_INFO, "Adding peer `%s' to list of 
requested_peers with requests\n",
-          GNUNET_i2s (peer));
-
-      p = GNUNET_malloc (sizeof (struct ATS_Peer));
-      p->id = (*peer);
-      p->f = get_peer_pref_value (mlp, peer);
-      GNUNET_CONTAINER_multipeermap_put (mlp->requested_peers,
-                                        peer, p,
-                                        
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
-
-      /* Added new peer, we have to rebuild problem before solving */
-      mlp->mlp_prob_changed = GNUNET_YES;
-
-      if ((GNUNET_YES == mlp->mlp_auto_solve)&&
-          (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains(mlp->addresses,
-                                                               peer)))
-      {
-        mlp->exclude_peer = peer;
-        GAS_mlp_solve_problem (mlp);
-        mlp->exclude_peer = NULL;
-      }
-  }
-  /* Get prefered address */
-  res = NULL;
-  GNUNET_CONTAINER_multipeermap_get_multiple (mlp->addresses, peer,
-                                              mlp_get_preferred_address_it, 
&res);
-  return res;
-}
-
-
-/**
- * Start a bulk operation
- *
- * @param solver the solver
- */
-void
-GAS_mlp_bulk_start (void *solver)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Locking solver for bulk operation ...\n");
-  struct GAS_MLP_Handle *s = (struct GAS_MLP_Handle *) solver;
-
-  GNUNET_assert (NULL != solver);
-
-  s->bulk_lock ++;
-}
-
-void
-GAS_mlp_bulk_stop (void *solver)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Unlocking solver from bulk operation ...\n");
-
-  struct GAS_MLP_Handle *s = (struct GAS_MLP_Handle *) solver;
-  GNUNET_assert (NULL != solver);
-
-  if (s->bulk_lock < 1)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  s->bulk_lock --;
-
-  if (0 < s->bulk_request)
-  {
-    GAS_mlp_solve_problem (solver);
-    s->bulk_request= 0;
-  }
-}
-
-
-
-/**
- * Stop notifying about address and bandwidth changes for this peer
- *
- * @param solver the MLP handle
- * @param peer the peer
- */
-void
-GAS_mlp_stop_get_preferred_address (void *solver,
-                                     const struct GNUNET_PeerIdentity *peer)
-{
-  struct GAS_MLP_Handle *mlp = solver;
-  struct ATS_Peer *p = NULL;
-
-  GNUNET_assert (NULL != solver);
-  GNUNET_assert (NULL != peer);
-  if (NULL != (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, 
peer)))
-  {
-    GNUNET_CONTAINER_multipeermap_remove (mlp->requested_peers, peer, p);
-    GNUNET_free (p);
-
-    mlp->mlp_prob_changed = GNUNET_YES;
-    if (GNUNET_YES == mlp->mlp_auto_solve)
-    {
-      GAS_mlp_solve_problem (solver);
-    }
-  }
-}
-
-
-/**
- * Changes the preferences for a peer in the MLP problem
- *
- * @param solver the MLP Handle
- * @param peer the peer
- * @param kind the kind to change the preference
- * @param pref_rel the relative score
- */
-void
-GAS_mlp_address_change_preference (void *solver,
-                   const struct GNUNET_PeerIdentity *peer,
-                   enum GNUNET_ATS_PreferenceKind kind,
-                   double pref_rel)
-{
-  struct GAS_MLP_Handle *mlp = solver;
-  struct ATS_Peer *p = NULL;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Changing preference for address for peer `%s' 
to %.2f\n",
-      GNUNET_i2s(peer), pref_rel);
-
-  GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, 
GNUNET_NO);
-  /* Update the constraints with changed preferences */
-
-  /* Update quality constraint c7 */
-
-  /* Update relativity constraint c9 */
-  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, 
peer)))
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR, "Updating preference for unknown peer 
`%s'\n", GNUNET_i2s(peer));
-    return;
-  }
-  p->f = get_peer_pref_value (mlp, peer);
-  /*
-  LOG (GNUNET_ERROR_TYPE_ERROR, "PEER PREF: %s %.2f\n",
-      GNUNET_i2s(peer), p->f);*/
-  mlp_create_problem_update_value (&mlp->p, p->r_c9, mlp->p.c_r, -p->f, 
__LINE__);
-
-  /* Problem size changed: new address for peer with pending request */
-  mlp->mlp_prob_updated = GNUNET_YES;
-  if (GNUNET_YES == mlp->mlp_auto_solve)
-    GAS_mlp_solve_problem (solver);
-  return;
-}
-
-
-/**
- * Get application feedback for a peer
- *
- * @param solver the solver handle
- * @param application the application
- * @param peer the peer to change the preference for
- * @param scope the time interval for this feedback: [now - scope .. now]
- * @param kind the kind to change the preference
- * @param score the score
- */
-void
-GAS_mlp_address_preference_feedback (void *solver,
-                                    void *application,
-                                    const struct GNUNET_PeerIdentity *peer,
-                                    const struct GNUNET_TIME_Relative scope,
-                                    enum GNUNET_ATS_PreferenceKind kind,
-                                    double score)
-{
-  struct GAS_PROPORTIONAL_Handle *s = solver;
-  GNUNET_assert (NULL != solver);
-  GNUNET_assert (NULL != peer);
-
-  GNUNET_assert (NULL != s);
-}
-
-
-static int
-mlp_free_peers (void *cls,
-               const struct GNUNET_PeerIdentity *key, void *value)
-{
-  struct GNUNET_CONTAINER_MultiPeerMap *map = cls;
-  struct ATS_Peer *p = value;
-
-  GNUNET_CONTAINER_multipeermap_remove (map, key, value);
-  GNUNET_free (p);
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Shutdown the MLP problem solving component
- *
- * @param cls the solver handle
- * @return NULL
- */
-void *
-libgnunet_plugin_ats_mlp_done (void *cls)
-{
-  struct GAS_MLP_Handle *mlp = cls;
-  GNUNET_assert (mlp != NULL);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down mlp solver\n");
-  mlp_delete_problem (mlp);
-
-  GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
-                                        &mlp_free_peers,
-                                        mlp->requested_peers);
-  GNUNET_CONTAINER_multipeermap_destroy (mlp->requested_peers);
-  mlp->requested_peers = NULL;
-
-  /* Clean up GLPK environment */
-  glp_free_env();
-  GNUNET_free (mlp);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown down of mlp solver complete\n");
-  return NULL;
-}
-
-
-void *
-libgnunet_plugin_ats_mlp_init (void *cls)
-{
-  struct GNUNET_ATS_PluginEnvironment *env = cls;
-  struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
-
-  double D;
-  double R;
-  double U;
-  unsigned long long tmp;
-  unsigned int b_min;
-  unsigned int n_min;
-  int c;
-  int c2;
-  int found;
-
-  struct GNUNET_TIME_Relative max_duration;
-  long long unsigned int max_iterations;
-
-  GNUNET_assert (NULL != env->cfg);
-  GNUNET_assert (NULL != env->stats);
-  GNUNET_assert (NULL != env->addresses);
-  GNUNET_assert (NULL != env->bandwidth_changed_cb);
-  GNUNET_assert (NULL != env->get_preferences);
-  GNUNET_assert (NULL != env->get_property);
-
-  /* Init GLPK environment */
-  int res = glp_init_env();
-  switch (res) {
-    case 0:
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
-          "initialization successful");
-      break;
-    case 1:
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
-          "environment is already initialized");
-      break;
-    case 2:
-      LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
-          "initialization failed (insufficient memory)");
-      GNUNET_free(mlp);
-      return NULL;
-      break;
-    case 3:
-      LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
-          "initialization failed (unsupported programming model)");
-      GNUNET_free(mlp);
-      return NULL;
-      break;
-    default:
-      break;
-  }
-
-   mlp->write_mip_mps = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "ats",
-          "DUMP_MLP");
-   if (GNUNET_SYSERR == mlp->write_mip_mps)
-     mlp->write_mip_mps = GNUNET_NO;
-   mlp->write_mip_sol = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "ats",
-          "DUMP_SOLUTION");
-   if (GNUNET_SYSERR == mlp->write_mip_sol)
-     mlp->write_mip_sol = GNUNET_NO;
-
-  mlp->pv.BIG_M = (double) BIG_M_VALUE;
-
-  /* Get timeout for iterations */
-  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(env->cfg, "ats", 
"MLP_MAX_DURATION", &max_duration))
-  {
-    max_duration = MLP_MAX_EXEC_DURATION;
-  }
-
-  /* Get maximum number of iterations */
-  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(env->cfg, "ats", 
"MLP_MAX_ITERATIONS", &max_iterations))
-  {
-    max_iterations = MLP_MAX_ITERATIONS;
-  }
-
-  /* Get diversity coefficient from configuration */
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
-                                                      "MLP_COEFFICIENT_D",
-                                                      &tmp))
-    D = (double) tmp / 100;
-  else
-    D = DEFAULT_D;
-
-  /* Get proportionality coefficient from configuration */
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
-                                                      "MLP_COEFFICIENT_R",
-                                                      &tmp))
-    R = (double) tmp / 100;
-  else
-    R = DEFAULT_R;
-
-  /* Get utilization coefficient from configuration */
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
-                                                      "MLP_COEFFICIENT_U",
-                                                      &tmp))
-    U = (double) tmp / 100;
-  else
-    U = DEFAULT_U;
-
-  /* Get quality metric coefficients from configuration */
-  int i_delay = MLP_NaN;
-  int i_distance = MLP_NaN;
-  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->pv.co_Q[c] = DEFAULT_QUALITY;
-
-    mlp->pv.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 != MLP_NaN) && (GNUNET_OK == 
GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
-                                                      
"MLP_COEFFICIENT_QUALITY_DELAY",
-                                                      &tmp)))
-
-    mlp->pv.co_Q[i_delay] = (double) tmp / 100;
-  else
-    mlp->pv.co_Q[i_delay] = DEFAULT_QUALITY;
-
-  if ((i_distance != MLP_NaN) && (GNUNET_OK == 
GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
-                                                      
"MLP_COEFFICIENT_QUALITY_DISTANCE",
-                                                      &tmp)))
-    mlp->pv.co_Q[i_distance] = (double) tmp / 100;
-  else
-    mlp->pv.co_Q[i_distance] = DEFAULT_QUALITY;
-
-  /* Get minimum bandwidth per used address from configuration */
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
-                                                      "MLP_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 (env->cfg, "ats",
-                                                      "MLP_MIN_CONNECTIONS",
-                                                      &tmp))
-    n_min = tmp;
-  else
-    n_min = DEFAULT_MIN_CONNECTIONS;
-
-  /* Init network quotas */
-  int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
-  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
-  {
-      found = GNUNET_NO;
-      for (c2 = 0; c2 < env->network_count; c2++)
-      {
-          if (quotas[c] == env->networks[c2])
-          {
-              mlp->pv.quota_index[c] = env->networks[c2];
-              mlp->pv.quota_out[c] = env->out_quota[c2];
-              mlp->pv.quota_in[c] = env->in_quota[c2];
-              found = GNUNET_YES;
-              LOG (GNUNET_ERROR_TYPE_DEBUG, "Quota for network `%s' (in/out) 
%llu/%llu\n",
-                          
GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
-                          mlp->pv.quota_out[c],
-                          mlp->pv.quota_in[c]);
-              break;
-          }
-      }
-
-      /* Check if defined quota could make problem unsolvable */
-      if ((n_min * b_min) > mlp->pv.quota_out[c])
-      {
-        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent outbound quota 
configuration for network `%s', is %llu must be at least %llu\n"),
-            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
-            mlp->pv.quota_out[c],
-            (n_min * b_min));
-        mlp->pv.quota_out[c] = (n_min * b_min);
-      }
-      if ((n_min * b_min) > mlp->pv.quota_in[c])
-      {
-        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent inbound quota 
configuration for network `%s', is %llu must be at least %llu\n"),
-            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
-            mlp->pv.quota_in[c],
-            (n_min * b_min));
-        mlp->pv.quota_in[c] = (n_min * b_min);
-      }
-
-      /* Check if bandwidth is too big to make problem solvable */
-      if (mlp->pv.BIG_M < mlp->pv.quota_out[c])
-      {
-        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting outbound quota configuration 
for network `%s'from %llu to %.0f\n"),
-            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
-            mlp->pv.quota_out[c],
-            mlp->pv.BIG_M);
-        mlp->pv.quota_out[c] = mlp->pv.BIG_M ;
-      }
-      if (mlp->pv.BIG_M < mlp->pv.quota_in[c])
-      {
-        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inbound quota configuration 
for network `%s' from %llu to %.0f\n"),
-            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
-            mlp->pv.quota_in[c],
-            mlp->pv.BIG_M);
-        mlp->pv.quota_in[c] = mlp->pv.BIG_M ;
-      }
-
-      if (GNUNET_NO == found)
-      {
-        mlp->pv.quota_in[c] = 
ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
-        mlp->pv.quota_out[c] = 
ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
-        LOG (GNUNET_ERROR_TYPE_INFO, _("Using default quota configuration for 
network `%s' (in/out) %llu/%llu\n"),
-            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
-            mlp->pv.quota_in[c],
-            mlp->pv.quota_out[c]);
-      }
-  }
-  mlp->env = env;
-  env->sf.s_add = &GAS_mlp_address_add;
-  env->sf.s_address_update_property = &GAS_mlp_address_property_changed;
-  env->sf.s_address_update_session = &GAS_mlp_address_session_changed;
-  env->sf.s_address_update_inuse = &GAS_mlp_address_inuse_changed;
-  env->sf.s_address_update_network = &GAS_mlp_address_change_network;
-  env->sf.s_get = &GAS_mlp_get_preferred_address;
-  env->sf.s_get_stop = &GAS_mlp_stop_get_preferred_address;
-  env->sf.s_pref = &GAS_mlp_address_change_preference;
-  env->sf.s_feedback = &GAS_mlp_address_preference_feedback;
-  env->sf.s_del = &GAS_mlp_address_delete;
-  env->sf.s_bulk_start = &GAS_mlp_bulk_start;
-  env->sf.s_bulk_stop = &GAS_mlp_bulk_stop;
-
-
-  /* Assign options to handle */
-  mlp->stats = (struct GNUNET_STATISTICS_Handle *) env->stats;
-  mlp->addresses = env->addresses;
-  mlp->bw_changed_cb = env->bandwidth_changed_cb;
-  mlp->bw_changed_cb_cls = env->bw_changed_cb_cls;
-  mlp->get_preferences =  env->get_preferences;
-  mlp->get_preferences_cls = env->get_preference_cls;
-  mlp->get_properties = env->get_property;
-  mlp->get_properties_cls = env->get_property_cls;
-  /* Setting MLP Input variables */
-
-  mlp->pv.co_D = D;
-  mlp->pv.co_R = R;
-  mlp->pv.co_U = U;
-  mlp->pv.b_min = b_min;
-  mlp->pv.n_min = n_min;
-  mlp->pv.m_q = GNUNET_ATS_QualityPropertiesCount;
-  mlp->mlp_prob_changed = GNUNET_NO;
-  mlp->mlp_prob_updated = GNUNET_NO;
-  mlp->mlp_auto_solve = GNUNET_YES;
-  mlp->requested_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
-  mlp->bulk_request = 0;
-  mlp->bulk_lock = 0;
-
-  /* Setup GLPK */
-  /* Redirect GLPK output to GNUnet logging */
-  glp_term_hook (&mlp_term_hook, (void *) mlp);
-
-  /* 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_us / 1000LL;
-
-  /* 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_us / 1000LL;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
-
-  return mlp;
-}
-
-/* end of gnunet-service-ats_addresses_mlp.c */

Deleted: gnunet/src/ats/libgnunet_plugin_ats_mlp.h
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_mlp.h   2013-12-09 23:22:55 UTC (rev 
31243)
+++ gnunet/src/ats/libgnunet_plugin_ats_mlp.h   2013-12-10 07:58:08 UTC (rev 
31244)
@@ -1,559 +0,0 @@
-/*
- (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/libgnunet_plugin_ats_mlp.h
- * @brief ats MLP problem solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_ats_service.h"
-#include "gnunet_ats_plugin.h"
-#include "gnunet-service-ats_addresses.h"
-#include "gnunet_statistics_service.h"
-#if HAVE_LIBGLPK
-#include "glpk.h"
-#endif
-
-#ifndef GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
-#define GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
-
-#define BIG_M_VALUE (UINT32_MAX) /10
-#define BIG_M_STRING "unlimited"
-
-#define MLP_AVERAGING_QUEUE_LENGTH 3
-
-#define MLP_MAX_EXEC_DURATION   
GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
-#define MLP_MAX_ITERATIONS      4096
-
-#define DEFAULT_D 1.0
-#define DEFAULT_R 1.0
-#define DEFAULT_U 1.0
-#define DEFAULT_QUALITY 1.0
-#define DEFAULT_MIN_CONNECTIONS 4
-#define DEFAULT_PEER_PREFERENCE 1.0
-
-#define MLP_NaN -1
-#define MLP_UNDEFINED 0
-#define GLP_YES 1.0
-#define GLP_NO  0.0
-
-struct MLP_Solution
-{
-  int lp_res;
-  int lp_presolv;
-  int mip_res;
-  int mip_presolv;
-
-  int p_elements;
-  int p_cols;
-  int p_rows;
-
-  int n_peers;
-  int n_addresses;
-
-};
-
-struct ATS_Peer
-{
-  struct GNUNET_PeerIdentity id;
-
-  /* Was this peer already added to the current problem? */
-  int processed;
-
-  /* constraint 2: 1 address per peer*/
-  unsigned int r_c2;
-
-  /* constraint 9: relativity */
-  unsigned int r_c9;
-
-  /* Legacy preference value */
-  double f;
-};
-
-struct MLP_Problem
-{
-  /**
-   * GLPK (MLP) problem object
-   */
-#if HAVE_LIBGLPK
-  glp_prob *prob;
-#else
-  void *prob;
-#endif
-
-  /* Number of addresses in problem */
-  unsigned int num_addresses;
-  /* Number of peers in problem */
-  unsigned int num_peers;
-  /* Number of elements in problem matrix */
-  unsigned int num_elements;
-
-  /* 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;
-  /* Row indices quality metrics  */
-  int r_q[GNUNET_ATS_QualityPropertiesCount];
-  /* Row indices ATS network quotas */
-  int r_quota[GNUNET_ATS_NetworkTypeCount];
-
-  /* Column index Diversity (D) column */
-  int c_d;
-  /* Column index Utilization (U) column */
-  int c_u;
-  /* Column index Proportionality (R) column */
-  int c_r;
-  /* Column index quality metrics  */
-  int c_q[GNUNET_ATS_QualityPropertiesCount];
-
-  /* Problem matrix */
-  /* Current index */
-  unsigned int ci;
-  /* Row index array */
-  int *ia;
-  /* Column index array */
-  int *ja;
-  /* Column index value */
-  double *ar;
-
-};
-
-struct MLP_Variables
-{
-  /* Big M value for bandwidth capping */
-  double BIG_M;
-
-  /* ATS Quality metrics
-   *
-   * Array with GNUNET_ATS_QualityPropertiesCount elements
-   * contains mapping to GNUNET_ATS_Property*/
-  int q[GNUNET_ATS_QualityPropertiesCount];
-
-  /* Number of quality metrics */
-  int m_q;
-
-  /* Number of quality metrics */
-  int m_rc;
-
-  /* Quality metric coefficients*/
-  double co_Q[GNUNET_ATS_QualityPropertiesCount];
-
-  /* Ressource costs coefficients*/
-  double co_RC[GNUNET_ATS_QualityPropertiesCount];
-
-  /* Diversity coefficient */
-  double co_D;
-
-  /* Utility coefficient */
-  double co_U;
-
-  /* Relativity coefficient */
-  double co_R;
-
-  /* Minimum bandwidth assigned to an address */
-  unsigned int b_min;
-
-  /* Minimum number of addresses with bandwidth assigned */
-  unsigned int n_min;
-
-  /* Quotas */
-  /* Array mapping array index to ATS network */
-  int quota_index[GNUNET_ATS_NetworkTypeCount];
-  /* Outbound quotas */
-  unsigned long long quota_out[GNUNET_ATS_NetworkTypeCount];
-  /* Inbound quotas */
-
-  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];
-
-};
-
-/**
- * MLP Handle
- */
-struct GAS_MLP_Handle
-{
-  struct GNUNET_ATS_PluginEnvironment *env;
-
-  /**
-   * Statistics handle
-   */
-  struct GNUNET_STATISTICS_Handle *stats;
-
-  /**
-   * Address hashmap for lookups
-   */
-  const struct GNUNET_CONTAINER_MultiPeerMap *addresses;
-
-  /**
-   * Addresses' bandwidth changed callback
-   */
-  GAS_bandwidth_changed_cb bw_changed_cb;
-
-  /**
-   * Addresses' bandwidth changed callback closure
-   */
-  void *bw_changed_cb_cls;
-
-  /**
-   * ATS function to get preferences
-   */
-  GAS_get_preferences get_preferences;
-
-  /**
-   * Closure for ATS function to get preferences
-   */
-  void *get_preferences_cls;
-
-  /**
-   * ATS function to get properties
-   */
-  GAS_get_properties get_properties;
-
-  /**
-   * Closure for ATS function to get properties
-   */
-  void *get_properties_cls;
-
-  /**
-   * Exclude peer from next result propagation
-   */
-  const struct GNUNET_PeerIdentity *exclude_peer;
-
-  /**
-   * Encapsulation for the MLP problem
-   */
-  struct MLP_Problem p;
-
-  /**
-   * Encapsulation for the MLP problem variables
-   */
-  struct MLP_Variables pv;
-
-  /**
-   * Encapsulation for the MLP solution
-   */
-  struct MLP_Solution ps;
-
-  /**
-   * Bulk lock
-   */
-
-  int bulk_lock;
-
-  /**
-   * Number of changes while solver was locked
-   */
-  int bulk_request;
-
-  /**
-   * GLPK LP control parameter
-   */
-#if HAVE_LIBGLPK
-  glp_smcp control_param_lp;
-#else
-  void *control_param_lp;
-#endif
-
-  /**
-   * GLPK LP control parameter
-   */
-#if HAVE_LIBGLPK
-  glp_iocp control_param_mlp;
-#else
-  void *control_param_mlp;
-#endif
-
-  /**
-   * Peers with pending address requests
-   */
-  struct GNUNET_CONTAINER_MultiPeerMap *requested_peers;
-
-  /**
-   * Was the problem updated since last solution
-   */
-  int mlp_prob_updated;
-
-  /**
-   * Has the problem size changed since last solution
-   */
-  int mlp_prob_changed;
-
-  /**
-   * Solve the problem automatically when updates occur?
-   * Default: GNUNET_YES
-   * Can be disabled for test and measurements
-   */
-  int mlp_auto_solve;
-
-  /**
-   * Write MILP problem to a MPS file
-   */
-  int write_mip_mps;
-
-  /**
-   * Write MILP problem to a MPS file
-   */
-  int write_mip_sol;
-
-};
-
-/**
- * Address specific MLP information
- */
-struct MLP_information
-{
-
-  /* Bandwidth assigned */
-  struct GNUNET_BANDWIDTH_Value32NBO b_out;
-  struct GNUNET_BANDWIDTH_Value32NBO b_in;
-
-  /* Address selected */
-  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;
-};
-
-
-/**
- * Solves the MLP problem
- *
- * @param solver the MLP Handle
- * @return #GNUNET_OK if could be solved, GNUNET_SYSERR on failure
- */
-int
-GAS_mlp_solve_problem (void *solver);
-
-
-/**
- * Init the MLP problem solving component
- *
- * @param cfg the GNUNET_CONFIGURATION_Handle handle
- * @param stats the GNUNET_STATISTICS handle
- * @param addresses Hashmap containing addresses
- * @param network array of GNUNET_ATS_NetworkType with length dest_length
- * @param out_dest array of outbound quotas
- * @param in_dest array of outbound quota
- * @param dest_length array length for quota arrays
- * @param bw_changed_cb callback for changed bandwidth amounts
- * @param bw_changed_cb_cls cls for callback
- * @param get_preference callback to get relative preferences for a peer
- * @param get_preference_cls cls for callback to get relative preferences for 
a peer
- * @param get_properties callback to get relative properties
- * @param get_properties_cls cls for callback to get relative properties
- * @return struct GAS_MLP_Handle on success, NULL on fail
- */
-void *
-GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
-             const struct GNUNET_STATISTICS_Handle *stats,
-              const struct GNUNET_CONTAINER_MultiPeerMap *addresses,
-              int *network,
-              unsigned long long *out_dest,
-              unsigned long long *in_dest,
-              int dest_length,
-              GAS_bandwidth_changed_cb bw_changed_cb,
-              void *bw_changed_cb_cls,
-              GAS_get_preferences get_preference,
-              void *get_preference_cls,
-              GAS_get_properties get_properties,
-              void *get_properties_cls);
-
-
-/**
- * Add a single address within a network to the solver
- *
- * @param solver the solver Handle
- * @param address the address to add
- * @param network network type of this address
- */
-void
-GAS_mlp_address_add (void *solver, struct ATS_Address *address,
-    uint32_t network);
-
-
-/**
- * Transport properties for this address have changed
- *
- * @param solver solver handle
- * @param address the address
- * @param type the ATSI type in HBO
- * @param abs_value the absolute value of the property
- * @param rel_value the normalized value
- */
-void
-GAS_mlp_address_property_changed (void *solver, struct ATS_Address *address,
-    uint32_t type, uint32_t abs_value, double rel_value);
-
-
-/**
- * Transport session for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param cur_session the current session
- * @param new_session the new session
- */
-void
-GAS_mlp_address_session_changed (void *solver, struct ATS_Address *address,
-                                uint32_t cur_session, uint32_t new_session);
-
-
-/**
- * Usage for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param in_use usage state
- */
-void
-GAS_mlp_address_inuse_changed (void *solver, struct ATS_Address *address,
-    int in_use);
-
-/**
- * Network scope for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param current_network the current network
- * @param new_network the new network
- */
-void
-GAS_mlp_address_change_network (void *solver, struct ATS_Address *address,
-    uint32_t current_network, uint32_t new_network);
-
-/**
- * Deletes a single address in the MLP problem
- *
- * The MLP problem has to be recreated and the problem has to be resolved
- *
- * @param solver the MLP Handle
- * @param address the address to delete
- * @param session_only delete only session not whole address
- */
-void
-GAS_mlp_address_delete (void *solver, struct ATS_Address *address,
-    int session_only);
-
-/**
- * Changes the preferences for a peer in the MLP problem
- *
- * @param solver the MLP Handle
- * @param peer the peer
- * @param kind the kind to change the preference
- * @param pref_rel the relative score
- */
-void
-GAS_mlp_address_change_preference (void *solver,
-    const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind 
kind,
-    double pref_rel);
-
-/**
- * Get application feedback for a peer
- *
- * @param solver the solver handle
- * @param application the application
- * @param peer the peer to change the preference for
- * @param scope the time interval for this feedback: [now - scope .. now]
- * @param kind the kind to change the preference
- * @param score the score
- */
-void
-GAS_mlp_address_preference_feedback (void *solver, void *application,
-    const struct GNUNET_PeerIdentity *peer,
-    const struct GNUNET_TIME_Relative scope,
-    enum GNUNET_ATS_PreferenceKind kind, double score);
-
-/**
- * Start a bulk operation
- *
- * @param solver the solver
- */
-void
-GAS_mlp_bulk_start (void *solver);
-
-/**
- * Bulk operation done
- */
-void
-GAS_mlp_bulk_stop (void *solver);
-
-/**
- * Get the preferred address for a specific peer until
- * GAS_mlp_stop_get_preferred_address is called
- *
- * @param solver the MLP Handle
- * @param peer the peer
- * @return suggested address
- */
-const struct ATS_Address *
-GAS_mlp_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Stop notifying about address and bandwidth changes for this peer
- *
- * @param solver the MLP handle
- * @param peer the peer
- */
-void
-GAS_mlp_stop_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Shutdown the MLP problem solving component
- *
- * @param solver the solver handle
- */
-void
-GAS_mlp_done (void *solver);
-
-#endif
-/* end of gnunet-service-ats_addresses_mlp.h */

Deleted: gnunet/src/ats/libgnunet_plugin_ats_proportional.c
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_proportional.c  2013-12-09 23:22:55 UTC 
(rev 31243)
+++ gnunet/src/ats/libgnunet_plugin_ats_proportional.c  2013-12-10 07:58:08 UTC 
(rev 31244)
@@ -1,1604 +0,0 @@
-/*
- 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/libgnunet_plugin_ats_proportional.c
- * @brief ATS proportional solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-#include "libgnunet_plugin_ats_proportional.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "ats-proportional",__VA_ARGS__)
-
-
-/**
- *
- * NOTE: Do not change this documentation. This documentation is based
- * on gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
- * use build_txt.sh to generate plaintext output
- *
- * ATS addresses : proportional solver
- *
- *    The proportional solver ("proportional") distributes the available
- *    bandwidth fair over all the addresses influenced by the
- *    preference values. For each available network type an in- and
- *    outbound quota is configured and the bandwidth available in
- *    these networks is distributed over the addresses.  The solver
- *    first assigns every addresses the minimum amount of bandwidth
- *    GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT and then distributes the
- *    remaining bandwidth available according to the preference
- *    values. For each peer only a single address gets bandwidth
- *    assigned and only one address marked as active.  The most
- *    important functionality for the solver is implemented in: *
- *    find_address_it is an hashmap iterator returning the prefered
- *    address for an peer * update_quota_per_network distributes
- *    available bandwidth for a network over active addresses
- *
- *    Changes to addresses automatically have an impact on the the
- *    bandwidth assigned to other addresses in the same network since
- *    the solver distributes the remaining bandwidth over the
- *    addresses in the network.  When changes to the addresses occur,
- *    the solver first performs the changes, like adding or deleting
- *    addresses, and then updates bandwidth assignment for the
- *    affected network. Bandwidth assignment is only recalculated on
- *    demand when an address is requested by a client for a peer or
- *    when the addresses available have changed or an address changed
- *    the network it is located in. When the bandwidth assignment has
- *    changed the callback is called with the new bandwidth
- *    assignments. The bandwidth distribution for a network is
- *    recalculated due to: * address suggestion requests * address
- *    deletions * address switching networks during address update *
- *    preference changes
- *
- *     3.1 Data structures used
- *
- *    For each ATS network (e.g. WAN, LAN, loopback) a struct Network
- *    is used to specify network related information as total adresses
- *    and active addresses in this network and the configured in- and
- *    outbound quota. Each network also contains a list of addresses
- *    added to the solver located in this network. The proportional
- *    solver uses the addresses' solver_information field to store the
- *    proportional network it belongs to for each address.
- *
- *     3.2 Initializing
- *
- *    When the proportional solver is initialized the solver creates a
- *    new solver handle and initializes the network structures with
- *    the quotas passed from addresses and returns the handle solver.
- *
- *     3.3 Adding an address
- *
- *    When a new address is added to the solver using s_add, a lookup
- *    for the network for this address is done and the address is
- *    enqueued in in the linked list of the network.
- *
- *     3.4 Updating an address
- *
- *    The main purpose of address updates is to update the ATS
- *    information for addresse selection. Important for the proportional
- *    solver is when an address switches network it is located
- *    in. This is common because addresses added by transport's
- *    validation mechanism are commonly located in
- *    GNUNET_ATS_NET_UNSPECIFIED. Addresses in validation are located
- *    in this network type and only if a connection is successful on
- *    return of payload data transport switches to the real network
- *    the address is located in.  When an address changes networks it
- *    is first of all removed from the old network using the solver
- *    API function GAS_proportional_address_delete and the network in
- *    the address struct is updated. A lookup for the respective new
- *    proportional network is done and stored in the addresse's
- *    solver_information field. Next the address is re-added to the
- *    solver using the solver API function
- *    GAS_proportional_address_add. If the address was marked as in
- *    active, the solver checks if bandwidth is available in the
- *    network and if yes sets the address to active and updates the
- *    bandwidth distribution in this network. If no bandwidth is
- *    available it sets the bandwidth for this address to 0 and tries
- *    to suggest an alternative address. If an alternative address was
- *    found, addresses' callback is called for this address.
- *
- *     3.5 Deleting an address
- *
- *    When an address is removed from the solver, it removes the
- *    respective address from the network and if the address was
- *    marked as active, it updates the bandwidth distribution for this
- *    network.
- *
- *     3.6 Requesting addresses
- *
- *    When an address is requested for a peer the solver performs a
- *    lookup for the peer entry in addresses address hashmap and
- *    selects the best address.  The selection of the most suitable
- *    address is done in the find_address_it hashmap iterator
- *    described in detail in section 3.7. If no address is returned,
- *    no address can be suggested at the moment. If the address
- *    returned is marked as active, the solver can return this
- *    address. If the address is not marked as active, the solver
- *    checks if another address belongign to this peer is marked as
- *    active and marks the address as inactive, updates the bandwidth
- *    for this address to 0, call the bandwidth changed callback for
- *    this address due to the change and updates quota assignment for
- *    the addresse's network. the now in-active address is belonging
- *    to. The solver marks the new address as active and updates the
- *    bandwidth assignment for this network.
- *
- *     3.7 Choosing addresses
- *
- *    Choosing the best possible address for suggestion is done by
- *    iterating over all addresses of a peer stored in addresses'
- *    hashmap and using the hashmap iterator find_address_it to select
- *    the best available address.  Several checks are done when an
- *    address is selected. First if this address is currently blocked
- *    by addresses from being suggested. An address is blocked for the
- *    duration of ATS_BLOCKING_DELTA when it is suggested to
- *    transport. Next it is checked if at least
- *    GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT bytes bandwidth is available
- *    in the addresse's network, because suggesting an address without
- *    bandwidth does not make sense. This also ensures that all active
- *    addresses in this network get at least the minimum amount of
- *    bandwidth assigned. In the next step the solver ensures that for
- *    tcp connections inbound connections are prefered over outbound
- *    connections. In the next stet the solver ensures that
- *    connections are prefered in the following order: * connections
- *    are already established and have bandwidth assigned *
- *    connections with a shorter distance * connectes have a shorter
- *    latency
- *
- *     3.8 Changing preferences
- *
- *     3.9 Shutdown
- *
- *    During shutdown all network entries and aging processes are
- *    destroyed and freed.
- *
- *
- * OLD DOCUMENTATION
- *
- * This solver assigns in and outbound bandwidth equally for all
- * addresses in specific network type (WAN, LAN) based on configured
- * in and outbound quota for this network.
- *
- * The solver is notified by addresses about changes to the addresses
- * and recalculates the bandwith assigned if required. The solver
- * notifies addresses by calling the GAS_bandwidth_changed_cb
- * callback.
- *
- * - Initialization
- *
- *
- *
- *
- * For each peer only a single is selected and marked as "active" in the 
address
- * struct.
- *
- * E.g.:
- *
- * You have the networks WAN and LAN and quotas
- * WAN_TOTAL_IN, WAN_TOTAL_OUT
- * LAN_TOTAL_IN, LAN_TOTAL_OUT
- *
- * If you have x addresses in the network segment LAN, the quotas are
- * QUOTA_PER_ADDRESS = LAN_TOTAL_OUT / x
- *
- * Quotas are automatically recalculated and reported back when addresses are
- * - requested
- *
- */
-
-#define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10)
-#define PREF_AGING_FACTOR 0.95
-
-#define DEFAULT_REL_PREFERENCE 1.0
-#define DEFAULT_ABS_PREFERENCE 0.0
-#define MIN_UPDATE_INTERVAL GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10)
-
-/**
- * A handle for the proportional solver
- */
-struct GAS_PROPORTIONAL_Handle
-{
-   struct GNUNET_ATS_PluginEnvironment *env;
-
-  /**
-   * Statistics handle
-   */
-  struct GNUNET_STATISTICS_Handle *stats;
-
-  /**
-   * Hashmap containing all valid addresses
-   */
-  const struct GNUNET_CONTAINER_MultiPeerMap *addresses;
-
-  /**
-   * Pending address requests
-   */
-  struct GNUNET_CONTAINER_MultiPeerMap *requests;
-
-  /**
-   * Bandwidth changed callback
-   */
-  GAS_bandwidth_changed_cb bw_changed;
-
-  /**
-   * Bandwidth changed callback cls
-   */
-  void *bw_changed_cls;
-
-  /**
-   * ATS function to get preferences
-   */
-  GAS_get_preferences get_preferences;
-
-  /**
-   * Closure for ATS function to get preferences
-   */
-  void *get_preferences_cls;
-
-  /**
-   * ATS function to get properties
-   */
-  GAS_get_properties get_properties;
-
-  /**
-   * Closure for ATS function to get properties
-   */
-  void *get_properties_cls;
-
-  /**
-   * Bulk lock
-   */
-  int bulk_lock;
-
-  /**
-   * Number of changes while solver was locked
-   */
-  int bulk_requests;
-
-  /**
-   * Total number of addresses for solver
-   */
-  unsigned int total_addresses;
-
-  /**
-   * Number of active addresses for solver
-   */
-  unsigned int active_addresses;
-
-  /**
-   * Networks array
-   */
-  struct Network *network_entries;
-
-  /**
-   * Number of networks
-   */
-  unsigned int network_count;
-
-};
-
-/**
- * Representation of a network
- */
-struct Network
-{
-  /**
-   * ATS network type
-   */
-  unsigned int type;
-
-  /**
-   * Network description
-   */
-  char *desc;
-
-  /**
-   * Total inbound quota
-   *
-   */
-  unsigned long long total_quota_in;
-
-  /**
-   * Total outbound quota
-   *
-   */
-  unsigned long long total_quota_out;
-
-  /**
-   * Number of active addresses for this network
-   */
-  unsigned int active_addresses;
-
-  /**
-   * Number of total addresses for this network
-   */
-  unsigned int total_addresses;
-
-  /**
-   * String for statistics total addresses
-   */
-  char *stat_total;
-
-  /**
-   * String for statistics active addresses
-   */
-  char *stat_active;
-
-  struct AddressWrapper *head;
-  struct AddressWrapper *tail;
-};
-
-/**
- * Address information stored in the solver
- */
-struct AddressSolverInformation
-{
-  struct Network *network;
-
-  /**
-   * Inbound quota
-   *
-   */
-  unsigned long long calculated_quota_in_NBO;
-
-  /**
-   * Outbound quota
-   *
-   */
-  unsigned long long calculated_quota_out_NBO;
-
-
-};
-
-/**
- * Wrapper for addresses to store them in network's linked list
- */
-struct AddressWrapper
-{
-  /**
-   * Next in DLL
-   */
-  struct AddressWrapper *next;
-
-  /**
-   * Previous in DLL
-   */
-  struct AddressWrapper *prev;
-
-  /**
-   * The address
-   */
-  struct ATS_Address *addr;
-};
-
-/**
- *  Important solver functions
- *  ---------------------------
- */
-
-void *
-libgnunet_plugin_ats_proportional_init (void *cls)
-{
-  struct GNUNET_ATS_PluginEnvironment *env = cls;
-  struct GAS_PROPORTIONAL_Handle *s;
-  struct Network * cur;
-  char * net_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
-  int c;
-
-  GNUNET_assert (NULL != env);
-  GNUNET_assert(NULL != env->cfg);
-  GNUNET_assert(NULL != env->stats);
-  GNUNET_assert(NULL != env->bandwidth_changed_cb);
-  GNUNET_assert(NULL != env->get_preferences);
-  GNUNET_assert(NULL != env->get_property);
-
-  s = GNUNET_malloc (sizeof (struct GAS_PROPORTIONAL_Handle));
-  s->env = env;
-  env->sf.s_add = &GAS_proportional_address_add;
-  env->sf.s_address_update_property = 
&GAS_proportional_address_property_changed;
-  env->sf.s_address_update_session = &GAS_proportional_address_session_changed;
-  env->sf.s_address_update_inuse = &GAS_proportional_address_inuse_changed;
-  env->sf.s_address_update_network = &GAS_proportional_address_change_network;
-  env->sf.s_get = &GAS_proportional_get_preferred_address;
-  env->sf.s_get_stop = &GAS_proportional_stop_get_preferred_address;
-  env->sf.s_pref = &GAS_proportional_address_change_preference;
-  env->sf.s_feedback = &GAS_proportional_address_preference_feedback;
-  env->sf.s_del = &GAS_proportional_address_delete;
-  env->sf.s_bulk_start = &GAS_proportional_bulk_start;
-  env->sf.s_bulk_stop = &GAS_proportional_bulk_stop;
-
-  s->stats = (struct GNUNET_STATISTICS_Handle *) env->stats;
-  s->bw_changed = env->bandwidth_changed_cb;
-  s->bw_changed_cls = env->bw_changed_cb_cls;
-  s->get_preferences = env->get_preferences;
-  s->get_preferences_cls = env->get_preference_cls;
-  s->get_properties = env->get_property;
-  s->get_properties_cls = env->get_property_cls;
-  s->network_count = env->network_count;
-  s->network_entries = GNUNET_malloc (env->network_count * sizeof (struct 
Network));
-
-  /* Init */
-  s->active_addresses = 0;
-  s->total_addresses = 0;
-  s->bulk_lock = GNUNET_NO;
-  s->addresses = env->addresses;
-  s->requests = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
-
-  for (c = 0; c < env->network_count; c++)
-  {
-    cur = &s->network_entries[c];
-    cur->total_addresses = 0;
-    cur->active_addresses = 0;
-    cur->type = env->networks[c];
-    cur->total_quota_in = env->in_quota[c];
-    cur->total_quota_out = env->out_quota[c];
-    cur->desc = net_str[c];
-    GNUNET_asprintf (&cur->stat_total,
-        "# ATS addresses %s total", cur->desc);
-    GNUNET_asprintf (&cur->stat_active,
-        "# ATS active addresses %s total", cur->desc);
-    LOG (GNUNET_ERROR_TYPE_INFO, "Added network %u `%s' %p\n", c, cur->desc, 
s);
-  }
-  return s;
-}
-
-void *
-libgnunet_plugin_ats_proportional_done (void *cls)
-{
-  struct GAS_PROPORTIONAL_Handle *s = cls;
-  struct AddressWrapper *cur;
-  struct AddressWrapper *next;
-  int c;
-  GNUNET_assert(s != NULL);
-  for (c = 0; c < s->network_count; c++)
-  {
-    if (s->network_entries[c].total_addresses > 0)
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG,
-          "Had %u addresses for network `%s' not deleted during shutdown\n",
-          s->network_entries[c].total_addresses, s->network_entries[c].desc);
-      GNUNET_break(0);
-    }
-
-    if (s->network_entries[c].active_addresses > 0)
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG,
-          "Had %u active addresses for network `%s' not deleted during 
shutdown\n",
-          s->network_entries[c].active_addresses, s->network_entries[c].desc);
-      GNUNET_break(0);
-    }
-
-    next = s->network_entries[c].head;
-    while (NULL != (cur = next))
-    {
-      next = cur->next;
-      GNUNET_CONTAINER_DLL_remove(s->network_entries[c].head,
-          s->network_entries[c].tail, cur);
-      GNUNET_free_non_null (cur->addr->solver_information);
-      GNUNET_free(cur);
-    }
-    GNUNET_free(s->network_entries[c].stat_total);
-    GNUNET_free(s->network_entries[c].stat_active);
-  }
-  if (s->total_addresses > 0)
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Had %u addresses not deleted during shutdown\n", s->total_addresses);
-    GNUNET_break(0);
-  }
-  if (s->active_addresses > 0)
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Had %u active addresses not deleted during shutdown\n",
-        s->active_addresses);
-    GNUNET_break (0);
-  }
-  GNUNET_free (s->network_entries);
-  GNUNET_CONTAINER_multipeermap_destroy (s->requests);
-  GNUNET_free (s);
-  return NULL;
-}
-
-
-/**
- * Test if bandwidth is available in this network to add an additional address
- *
- * @param net the network type to update
- * @return GNUNET_YES or GNUNET_NO
- */
-static int
-is_bandwidth_available_in_network (struct Network *net)
-{
-  GNUNET_assert(NULL != net);
-  unsigned int na = net->active_addresses + 1;
-  uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
-  if (((net->total_quota_in / na) > min_bw)
-      && ((net->total_quota_out / na) > min_bw))
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Enough bandwidth available for %u active addresses in network `%s'\n",
-        na, net->desc);
-
-    return GNUNET_YES;
-  }
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Not enough bandwidth available for %u active addresses in network 
`%s'\n",
-      na, net->desc);
-  return GNUNET_NO;
-}
-
-/**
- * Update bandwidth assigned to peers in this network
- *
- * @param s the solver handle
- * @param net the network type to update
- * @param address_except address excluded from notification, since we suggest
- * this address
- */
-static void
-distribute_bandwidth (struct GAS_PROPORTIONAL_Handle *s,
-    struct Network *net, struct ATS_Address *address_except)
-{
-  struct AddressSolverInformation *asi;
-  struct AddressWrapper *cur;
-
-  unsigned long long remaining_quota_in = 0;
-  unsigned long long quota_out_used = 0;
-  unsigned long long remaining_quota_out = 0;
-  unsigned long long quota_in_used = 0;
-  uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
-  double peer_prefs;
-  double total_prefs; /* Important: has to be double not float due to 
precision */
-  double cur_pref; /* Important: has to be double not float due to precision */
-  const double *t = NULL; /* Important: has to be double not float due to 
precision */
-  int c;
-  unsigned long long assigned_quota_in = 0;
-  unsigned long long assigned_quota_out = 0;
-
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Recalculate quota for network type `%s' for %u addresses (in/out): 
%llu/%llu \n",
-      net->desc, net->active_addresses, net->total_quota_in,
-      net->total_quota_in);
-
-  if (net->active_addresses == 0)
-    return; /* no addresses to update */
-
-  /* Idea
-   * Assign every peer in network minimum Bandwidth
-   * Distribute bandwidth left according to preference
-   */
-
-  if ((net->active_addresses * min_bw) > net->total_quota_in)
-  {
-    GNUNET_break(0);
-    return;
-  }
-  if ((net->active_addresses * min_bw) > net->total_quota_out)
-  {
-    GNUNET_break(0);
-    return;
-  }
-
-  remaining_quota_in = net->total_quota_in - (net->active_addresses * min_bw);
-  remaining_quota_out = net->total_quota_out - (net->active_addresses * 
min_bw);
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Remaining bandwidth : (in/out): %llu/%llu \n",
-      remaining_quota_in, remaining_quota_out);
-  total_prefs = 0.0;
-  for (cur = net->head; NULL != cur; cur = cur->next)
-  {
-    if (GNUNET_YES == cur->addr->active)
-    {
-      GNUNET_assert(
-          NULL != (t = s->get_preferences (s->get_preferences_cls, 
&cur->addr->peer)));
-
-      peer_prefs = 0.0;
-      for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
-      {
-        if (c != GNUNET_ATS_PREFERENCE_END)
-        {
-          //fprintf (stderr, "VALUE[%u] %s %.3f \n", c, GNUNET_i2s 
(&cur->addr->peer), t[c]);
-          peer_prefs += t[c];
-        }
-      }
-      total_prefs += (peer_prefs / (GNUNET_ATS_PreferenceCount - 1));
-    }
-  }
-  for (cur = net->head; NULL != cur; cur = cur->next)
-  {
-    if (GNUNET_YES == cur->addr->active)
-    {
-      cur_pref = 0.0;
-      GNUNET_assert(
-          NULL != (t = s->get_preferences (s->get_preferences_cls, 
&cur->addr->peer)));
-
-      for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
-      {
-        if (c != GNUNET_ATS_PREFERENCE_END)
-          cur_pref += t[c];
-      }
-      cur_pref /= 2;
-
-      assigned_quota_in = min_bw
-          + ((cur_pref / total_prefs) * remaining_quota_in);
-      assigned_quota_out = min_bw
-          + ((cur_pref / total_prefs) * remaining_quota_out);
-
-      LOG(GNUNET_ERROR_TYPE_DEBUG,
-          "New quota for peer `%s' with preference (cur/total) %.3f/%.3f 
(in/out): %llu / %llu\n",
-          GNUNET_i2s (&cur->addr->peer), cur_pref, total_prefs,
-          assigned_quota_in, assigned_quota_out);
-    }
-    else
-    {
-      assigned_quota_in = 0;
-      assigned_quota_out = 0;
-    }
-
-    quota_in_used += assigned_quota_in;
-    quota_out_used += assigned_quota_out;
-    /* Prevent overflow due to rounding errors */
-    if (assigned_quota_in > UINT32_MAX)
-      assigned_quota_in = UINT32_MAX;
-    if (assigned_quota_out > UINT32_MAX)
-      assigned_quota_out = UINT32_MAX;
-
-    /* Compare to current bandwidth assigned */
-    asi = cur->addr->solver_information;
-    asi->calculated_quota_in_NBO = htonl (assigned_quota_in);
-    asi->calculated_quota_out_NBO = htonl (assigned_quota_out);
-  }
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Total bandwidth assigned is (in/out): %llu /%llu\n", quota_in_used,
-      quota_out_used);
-  if (quota_out_used > net->total_quota_out + 1) /* +1 is required due to 
rounding errors */
-  {
-    LOG(GNUNET_ERROR_TYPE_ERROR,
-        "Total outbound bandwidth assigned is larger than allowed 
(used/allowed) for %u active addresses: %llu / %llu\n",
-        net->active_addresses, quota_out_used, net->total_quota_out);
-  }
-  if (quota_in_used > net->total_quota_in + 1) /* +1 is required due to 
rounding errors */
-  {
-    LOG(GNUNET_ERROR_TYPE_ERROR,
-        "Total inbound bandwidth assigned is larger than allowed 
(used/allowed) for %u active addresses: %llu / %llu\n",
-        net->active_addresses, quota_in_used, net->total_quota_in);
-  }
-}
-
-struct FindBestAddressCtx
-{
-  struct GAS_PROPORTIONAL_Handle *s;
-  struct ATS_Address *best;
-};
-
-static int
-find_property_index (uint32_t type)
-{
-  int existing_types[] = GNUNET_ATS_QualityProperties;
-  int c;
-  for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
-    if (existing_types[c] == type)
-      return c;
-  return GNUNET_SYSERR;
-}
-
-/**
- * Find a "good" address to use for a peer by iterating over the addresses for 
this 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_best_address_it (void *cls,
-                     const struct GNUNET_PeerIdentity *key,
-                     void *value)
-{
-  struct FindBestAddressCtx *fba_ctx = (struct FindBestAddressCtx *) cls;
-  struct ATS_Address *current = (struct ATS_Address *) value;
-  struct GNUNET_TIME_Absolute now;
-  struct AddressSolverInformation *asi;
-  const double *norm_prop_cur;
-  const double *norm_prop_prev;
-  int index;
-
-  asi = current->solver_information;
-  now = GNUNET_TIME_absolute_get ();
-
-  if (current->blocked_until.abs_value_us
-      == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value_us)
-  {
-    /* This address is blocked for suggestion */
-    LOG(GNUNET_ERROR_TYPE_DEBUG, "Address %p blocked for suggestion for %s \n",
-        current,
-        GNUNET_STRINGS_relative_time_to_string 
(GNUNET_TIME_absolute_get_difference (now, current->blocked_until), 
GNUNET_YES));
-    return GNUNET_OK;
-  }
-  if (GNUNET_NO == is_bandwidth_available_in_network (asi->network))
-    return GNUNET_OK; /* There's no bandwidth available in this network */
-  if (NULL != fba_ctx->best)
-  {
-    GNUNET_assert(NULL != fba_ctx->best->plugin);
-    GNUNET_assert(NULL != current->plugin);
-    if (0 == strcmp (fba_ctx->best->plugin, current->plugin))
-    {
-      if ((0 != fba_ctx->best->addr_len) && (0 == current->addr_len))
-      {
-        /* saved address was an outbound address, but we have an inbound 
address */
-        fba_ctx->best = current;
-        return GNUNET_OK;
-      }
-      if (0 == fba_ctx->best->addr_len)
-      {
-        /* saved address was an inbound address, so do not overwrite */
-        return GNUNET_OK;
-      }
-    }
-  }
-  if (NULL == fba_ctx->best)
-  {
-    fba_ctx->best = current;
-    return GNUNET_OK;
-  }
-  if ((ntohl (fba_ctx->best->assigned_bw_in.value__) == 0)
-      && (ntohl (current->assigned_bw_in.value__) > 0))
-  {
-    /* stick to existing connection */
-    fba_ctx->best = current;
-    return GNUNET_OK;
-  }
-
-  norm_prop_cur = fba_ctx->s->get_properties (fba_ctx->s->get_properties_cls,
-      (const struct ATS_Address *) current);
-  norm_prop_prev = fba_ctx->s->get_properties (fba_ctx->s->get_properties_cls,
-      (const struct ATS_Address *) fba_ctx->best);
-  /*
-   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s previous %.2f current %.2f\n",
-   "DISTANCE", norm_prop_cur[1], norm_prop_cur[1]);
-   */
-  index = find_property_index (GNUNET_ATS_QUALITY_NET_DISTANCE);
-  if (GNUNET_SYSERR == index)
-  {
-    GNUNET_break(0);
-    return GNUNET_OK;
-  }
-  if (norm_prop_cur[index] < norm_prop_prev[index])
-  {
-    /* user shorter distance */
-    fba_ctx->best = current;
-    return GNUNET_OK;
-  }
-  /*
-   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s previous %.2f current %.2f\n",
-   "DELAY", norm_prop_cur[1], norm_prop_cur[1]);
-   */
-  index = find_property_index (GNUNET_ATS_QUALITY_NET_DELAY);
-  if (GNUNET_SYSERR == index)
-  {
-    GNUNET_break(0);
-    return GNUNET_OK;
-  }
-  if (norm_prop_cur[index] < norm_prop_prev[index])
-  {
-    /* user shorter delay */
-    fba_ctx->best = current;
-    return GNUNET_OK;
-  }
-
-  /* don't care */
-  return GNUNET_OK;
-}
-
-/**
- *  Helper functions
- *  ---------------------------
- */
-static void
-propagate_bandwidth (struct GAS_PROPORTIONAL_Handle *s,
-    struct Network *net, struct ATS_Address *address_except)
-{
-  struct AddressWrapper *cur;
-  struct AddressSolverInformation *asi;
-  for (cur = net->head; NULL != cur; cur = cur->next)
-  {
-      asi = cur->addr->solver_information;
-      if ( (cur->addr->assigned_bw_in.value__ != asi->calculated_quota_in_NBO) 
||
-           (cur->addr->assigned_bw_out.value__ != 
asi->calculated_quota_out_NBO) )
-      {
-        cur->addr->assigned_bw_in.value__ = asi->calculated_quota_in_NBO;
-        cur->addr->assigned_bw_out.value__ = asi->calculated_quota_in_NBO;
-        /* Notify on change */
-        if ((GNUNET_YES == cur->addr->active) && (cur->addr != address_except))
-          s->bw_changed (s->bw_changed_cls, cur->addr);
-      }
-  }
-}
-
-/**
- * Distribibute bandwidth
- *
- * @param s the solver handle
- * @param n the network, can be NULL for all network
- * @param address_except do not notify for this address
- */
-static void
-distribute_bandwidth_in_network (struct GAS_PROPORTIONAL_Handle *s,
-    struct Network *n, struct ATS_Address *address_except)
-{
-  if (GNUNET_YES == s->bulk_lock)
-  {
-    s->bulk_requests++;
-    return;
-  }
-
-  if (NULL != n)
-  {
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_START,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
-    distribute_bandwidth(s, n, address_except);
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_STOP,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
-    propagate_bandwidth(s, n, address_except);
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
-  }
-  else
-  {
-    int i;
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_START,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
-    for (i = 0; i < s->network_count; i++)
-      distribute_bandwidth(s, &s->network_entries[i], NULL);
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_STOP,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
-    for (i = 0; i < s->network_count; i++)
-    {
-      propagate_bandwidth(s, &s->network_entries[i], address_except);
-    }
-    if (NULL != s->env->info_cb)
-      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
-          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
-  }
-}
-
-/**
- * Lookup network struct by type
- *
- * @param s the solver handle
- * @param type the network type
- * @return the network struct
- */
-static struct Network *
-get_network (struct GAS_PROPORTIONAL_Handle *s, uint32_t type)
-{
-  int c;
-  for (c = 0; c < s->network_count; c++)
-  {
-    if (s->network_entries[c].type == type)
-      return &s->network_entries[c];
-  }
-  return NULL ;
-}
-
-/**
- * Hashmap Iterator to find current active address for peer
- *
- * @param cls last active address
- * @param key peer's key
- * @param value address to check
- * @return #GNUNET_NO on double active address else #GNUNET_YES;
- */
-static int
-get_active_address_it (void *cls,
-                      const struct GNUNET_PeerIdentity *key,
-                      void *value)
-{
-  struct ATS_Address **dest = cls;
-  struct ATS_Address *aa = (struct ATS_Address *) value;
-
-  if (GNUNET_YES == aa->active)
-  {
-
-    if (NULL != (*dest))
-    {
-      /* should never happen */
-      LOG(GNUNET_ERROR_TYPE_ERROR, "Multiple active addresses for peer `%s'\n",
-          GNUNET_i2s (&aa->peer));
-      GNUNET_break(0);
-      return GNUNET_NO;
-    }
-    (*dest) = aa;
-  }
-  return GNUNET_OK;
-}
-
-/**
- * Find current active address for peer
- *
- * @param solver the solver handle
- * @param addresses the address set
- * @param peer the peer
- * @return active address or NULL
- */
-static struct ATS_Address *
-get_active_address (void *solver,
-                   const struct GNUNET_CONTAINER_MultiPeerMap * addresses,
-                   const struct GNUNET_PeerIdentity *peer)
-{
-  struct ATS_Address * dest = NULL;
-
-  GNUNET_CONTAINER_multipeermap_get_multiple (addresses, peer,
-                                             &get_active_address_it, &dest);
-  return dest;
-}
-
-
-static void
-addresse_increment (struct GAS_PROPORTIONAL_Handle *s, struct Network *net,
-    int total, int active)
-{
-  if (GNUNET_YES == total)
-  {
-    s->total_addresses++;
-    net->total_addresses++;
-    GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", 1, GNUNET_NO);
-    GNUNET_STATISTICS_update (s->stats, net->stat_total, 1, GNUNET_NO);
-  }
-  if (GNUNET_YES == active)
-  {
-    net->active_addresses++;
-    s->active_addresses++;
-    GNUNET_STATISTICS_update (s->stats, "# ATS active addresses total", 1,
-        GNUNET_NO);
-    GNUNET_STATISTICS_update (s->stats, net->stat_active, 1, GNUNET_NO);
-  }
-
-}
-
-
-static int
-addresse_decrement (struct GAS_PROPORTIONAL_Handle *s, struct Network *net,
-    int total, int active)
-{
-  int res = GNUNET_OK;
-  if (GNUNET_YES == total)
-  {
-    if (s->total_addresses < 1)
-    {
-      GNUNET_break(0);
-      res = GNUNET_SYSERR;
-    }
-    else
-    {
-      s->total_addresses--;
-      GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1,
-          GNUNET_NO);
-    }
-    if (net->total_addresses < 1)
-    {
-      GNUNET_break(0);
-      res = GNUNET_SYSERR;
-    }
-    else
-    {
-      net->total_addresses--;
-      GNUNET_STATISTICS_update (s->stats, net->stat_total, -1, GNUNET_NO);
-    }
-  }
-
-  if (GNUNET_YES == active)
-  {
-    if (net->active_addresses < 1)
-    {
-      GNUNET_break(0);
-      res = GNUNET_SYSERR;
-    }
-    else
-    {
-      net->active_addresses--;
-      GNUNET_STATISTICS_update (s->stats, net->stat_active, -1, GNUNET_NO);
-    }
-    if (s->active_addresses < 1)
-    {
-      GNUNET_break(0);
-      res = GNUNET_SYSERR;
-    }
-    else
-    {
-      s->active_addresses--;
-      GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1,
-          GNUNET_NO);
-    }
-  }
-  return res;
-}
-
-/**
- *  Solver API functions
- *  ---------------------------
- */
-
-/**
- * Changes the preferences for a peer in the problem
- *
- * @param solver the solver handle
- * @param peer the peer to change the preference for
- * @param kind the kind to change the preference
- * @param pref_rel the normalized preference value for this kind over all 
clients
- */
-void
-GAS_proportional_address_change_preference (void *solver,
-                                           const struct GNUNET_PeerIdentity 
*peer,
-                                           enum GNUNET_ATS_PreferenceKind kind,
-                                           double pref_rel)
-{
-  struct GAS_PROPORTIONAL_Handle *s = solver;
-  GNUNET_assert(NULL != solver);
-  GNUNET_assert(NULL != peer);
-
-  distribute_bandwidth_in_network (s, NULL, NULL);
-}
-
-
-/**
- * Get application feedback for a peer
- *
- * @param solver the solver handle
- * @param application the application
- * @param peer the peer to change the preference for
- * @param scope the time interval for this feedback: [now - scope .. now]
- * @param kind the kind to change the preference
- * @param score the score
- */
-void
-GAS_proportional_address_preference_feedback (void *solver, void *application,
-    const struct GNUNET_PeerIdentity *peer,
-    const struct GNUNET_TIME_Relative scope,
-    enum GNUNET_ATS_PreferenceKind kind, double score)
-{
-  struct GAS_PROPORTIONAL_Handle *s = solver;
-  GNUNET_assert(NULL != solver);
-  GNUNET_assert(NULL != peer);
-
-  GNUNET_assert(NULL != s);
-  GNUNET_break(0);
-}
-
-/**
- * Get the preferred address for a specific peer
- *
- * @param solver the solver handle
- * @param peer the identity of the peer
- */
-const struct ATS_Address *
-GAS_proportional_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer)
-{
-  struct GAS_PROPORTIONAL_Handle *s = solver;
-  struct Network *net_prev;
-  struct Network *net_cur;
-  struct ATS_Address *prev;
-  struct FindBestAddressCtx fba_ctx;
-  struct AddressSolverInformation *asi;
-  struct AddressSolverInformation *asi_prev;
-
-  GNUNET_assert(s != NULL);
-  GNUNET_assert(peer != NULL);
-
-  /* Add to list of pending requests */
-  if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (s->requests,
-                                                          peer))
-  {
-    GNUNET_assert (GNUNET_OK ==
-                  GNUNET_CONTAINER_multipeermap_put (s->requests,
-                                                     peer, NULL,
-                                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  }
-
-  /* Get address with: stick to current address, lower distance, lower latency 
*/
-  fba_ctx.s = s;
-  fba_ctx.best = NULL;
-
-  GNUNET_CONTAINER_multipeermap_get_multiple (s->addresses, peer,
-                                             &find_best_address_it, &fba_ctx);
-  if (NULL == fba_ctx.best)
-  {
-    LOG(GNUNET_ERROR_TYPE_INFO, "Cannot suggest address for peer `%s'\n",
-        GNUNET_i2s (peer));
-    return NULL ;
-  }
-
-  LOG(GNUNET_ERROR_TYPE_INFO, "Suggesting %s address %p for peer `%s'\n",
-      (GNUNET_NO == fba_ctx.best->active) ? "inactive" : "active", 
fba_ctx.best,
-      GNUNET_i2s (peer));
-  asi = fba_ctx.best->solver_information;
-  net_cur = asi->network ;
-  if (NULL == fba_ctx.best)
-  {
-    LOG(GNUNET_ERROR_TYPE_ERROR,
-        "Trying to suggesting unknown address peer `%s'\n", GNUNET_i2s (peer));
-    GNUNET_break(0);
-    return NULL ;
-  }
-  if (GNUNET_YES == fba_ctx.best->active)
-  {
-    /* This address was selected previously, so no need to update quotas */
-    return fba_ctx.best;
-  }
-
-  /* This address was not active, so we have to:
-   *
-   * - mark previous active address as not active
-   * - update quota for previous address network
-   * - update quota for this address network
-   */
-  prev = get_active_address (s, s->addresses, peer);
-  if (NULL != prev)
-  {
-    asi_prev = prev->solver_information;
-    net_prev = (struct Network *) asi_prev->network;
-    prev->active = GNUNET_NO; /* No active any longer */
-    prev->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
-    prev->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
-    if (GNUNET_SYSERR == addresse_decrement (s, net_prev, GNUNET_NO, 
GNUNET_YES))
-      GNUNET_break(0);
-    distribute_bandwidth_in_network (s, net_prev, NULL);
-  }
-
-  if (GNUNET_NO == (is_bandwidth_available_in_network (net_cur)))
-  {
-    GNUNET_break(0); /* This should never happen*/
-    return NULL ;
-  }
-
-  fba_ctx.best->active = GNUNET_YES;
-  addresse_increment (s, net_cur, GNUNET_NO, GNUNET_YES);
-  distribute_bandwidth_in_network (s, net_cur, fba_ctx.best);
-  return fba_ctx.best;
-}
-
-/**
- * Stop notifying about address and bandwidth changes for this peer
- *
- * @param solver the solver handle
- * @param peer the peer
- */
-void
-GAS_proportional_stop_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer)
-{
-  struct GAS_PROPORTIONAL_Handle *s = solver;
-  struct ATS_Address *cur;
-  struct AddressSolverInformation *asi;
-  struct Network *cur_net;
-
-  if (GNUNET_YES
-      == GNUNET_CONTAINER_multipeermap_contains (s->requests,
-                                                peer))
-    GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove 
(s->requests, peer,
-                                         NULL));
-
-  cur = get_active_address (s,
-                           s->addresses, peer);
-  if (NULL != cur)
-  {
-    /* Disabling current address */
-    asi = cur->solver_information;
-    cur_net = asi->network ;
-    cur->active = GNUNET_NO; /* No active any longer */
-    cur->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
-    cur->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
-    if (GNUNET_SYSERR == addresse_decrement (s, cur_net, GNUNET_NO, 
GNUNET_YES))
-      GNUNET_break(0);
-    distribute_bandwidth_in_network (s, cur_net, NULL );
-  }
-  return;
-}
-
-/**
- * Remove an address from the solver
- *
- * @param solver the solver handle
- * @param address the address to remove
- * @param session_only delete only session not whole address
- */
-void
-GAS_proportional_address_delete (void *solver, struct ATS_Address *address,
-    int session_only)
-{
-  struct GAS_PROPORTIONAL_Handle *s = solver;
-  struct Network *net;
-  struct AddressWrapper *aw;
-  struct AddressSolverInformation *asi;
-  const struct ATS_Address *new_address;
-
-
-  /* Remove an adress completely, we have to:
-   * - Remove from specific network
-   * - Decrease number of total addresses
-   * - If active:
-   *   - decrease number of active addreses
-   *   - update quotas
-   */
-  asi = address->solver_information;
-
-  if (NULL == asi)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  net = asi->network;
-
-  if (GNUNET_NO == session_only)
-  {
-    LOG(GNUNET_ERROR_TYPE_INFO,
-        "Deleting %s address %p for peer `%s' from network `%s' (total: %u/ 
active: %u)\n",
-        (GNUNET_NO == address->active) ? "inactive" : "active", address,
-        GNUNET_i2s (&address->peer), net->desc, net->total_addresses,
-        net->active_addresses);
-
-    /* Remove address */
-    addresse_decrement (s, net, GNUNET_YES, GNUNET_NO);
-    for (aw = net->head; NULL != aw; aw = aw->next)
-    {
-      if (aw->addr == address)
-        break;
-    }
-    if (NULL == aw)
-    {
-      GNUNET_break(0);
-      return;
-    }
-    GNUNET_CONTAINER_DLL_remove(net->head, net->tail, aw);
-    GNUNET_free_non_null (aw->addr->solver_information);
-    GNUNET_free(aw);
-  }
-  else
-  {
-    /* Remove session only: remove if active and update */
-    LOG(GNUNET_ERROR_TYPE_INFO,
-        "Deleting %s session %p for peer `%s' from network `%s' (total: %u/ 
active: %u)\n",
-        (GNUNET_NO == address->active) ? "inactive" : "active", address,
-        GNUNET_i2s (&address->peer), net->desc, net->total_addresses,
-        net->active_addresses);
-  }
-
-  if (GNUNET_YES == address->active)
-  {
-    /* Address was active, remove from network and update quotas*/
-    address->active = GNUNET_NO;
-    address->assigned_bw_in = BANDWIDTH_ZERO;
-    address->assigned_bw_out = BANDWIDTH_ZERO;
-
-    if (GNUNET_SYSERR == addresse_decrement (s, net, GNUNET_NO, GNUNET_YES))
-      GNUNET_break(0);
-    distribute_bandwidth_in_network (s, net, NULL);
-    if (NULL == (new_address = GAS_proportional_get_preferred_address (s, 
&address->peer)))
-    {
-      /* No alternative address found, disconnect peer */
-      s->bw_changed (s->bw_changed_cls, address);
-    }
-    else
-    {
-      s->bw_changed (s->bw_changed_cls, (struct ATS_Address *) new_address);
-    }
-  }
-  LOG(GNUNET_ERROR_TYPE_INFO,
-      "After deleting address now total %u and active %u addresses in network 
`%s'\n",
-      net->total_addresses, net->active_addresses, net->desc);
-
-}
-
-/**
- * Start a bulk operation
- *
- * @param solver the solver
- */
-void
-GAS_proportional_bulk_start (void *solver)
-{
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Locking solver for bulk operation ...\n");
-  struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *) 
solver;
-
-  GNUNET_assert(NULL != solver);
-  s->bulk_lock++;
-}
-
-
-/**
- * Bulk operation done
- */
-void
-GAS_proportional_bulk_stop (void *solver)
-{
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Unlocking solver from bulk operation ...\n");
-
-  struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *) 
solver;
-  GNUNET_assert(NULL != solver);
-
-  if (s->bulk_lock < 1)
-  {
-    GNUNET_break(0);
-    return;
-  }
-  s->bulk_lock--;
-  if ((0 == s->bulk_lock) && (0 < s->bulk_requests))
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG, "No lock pending, recalculating\n");
-    distribute_bandwidth_in_network (s, NULL, NULL);
-    s->bulk_requests = 0;
-  }
-}
-
-
-/**
- * Add a new single address to a network
- *
- * @param solver the solver Handle
- * @param address the address to add
- * @param network network type of this address
- */
-void
-GAS_proportional_address_add (void *solver, struct ATS_Address *address,
-    uint32_t network);
-
-/**
- * Transport properties for this address have changed
- *
- * @param solver solver handle
- * @param address the address
- * @param type the ATSI type in HBO
- * @param abs_value the absolute value of the property
- * @param rel_value the normalized value
- */
-void
-GAS_proportional_address_property_changed (void *solver,
-    struct ATS_Address *address, uint32_t type, uint32_t abs_value,
-    double rel_value)
-{
-  struct GAS_PROPORTIONAL_Handle *s;
-  struct Network *n;
-  struct AddressSolverInformation *asi;
-
-  GNUNET_assert(NULL != solver);
-  GNUNET_assert(NULL != address);
-
-  s = (struct GAS_PROPORTIONAL_Handle *) solver;
-  asi = address->solver_information;
-  n = asi->network;
-
-  if (NULL == n)
-  {
-    GNUNET_break(0);
-    return;
-  }
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Property `%s' for peer `%s' address %p changed to %.2f \n",
-      GNUNET_ATS_print_property_type (type), GNUNET_i2s (&address->peer),
-      address, rel_value);
-  switch (type)
-  {
-  case GNUNET_ATS_UTILIZATION_OUT:
-  case GNUNET_ATS_UTILIZATION_IN:
-  case GNUNET_ATS_UTILIZATION_PAYLOAD_IN:
-  case GNUNET_ATS_UTILIZATION_PAYLOAD_OUT:
-  case GNUNET_ATS_QUALITY_NET_DELAY:
-  case GNUNET_ATS_QUALITY_NET_DISTANCE:
-  case GNUNET_ATS_COST_WAN:
-  case GNUNET_ATS_COST_LAN:
-  case GNUNET_ATS_COST_WLAN:
-    distribute_bandwidth_in_network (s, n, NULL);
-    break;
-  }
-}
-
-/**
- * Transport session for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param cur_session the current session
- * @param new_session the new session
- */
-void
-GAS_proportional_address_session_changed (void *solver,
-    struct ATS_Address *address, uint32_t cur_session, uint32_t new_session)
-{
-  if (cur_session != new_session)
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG, "Session changed from %u to %u\n", 
cur_session,
-        new_session);
-  }
-}
-
-/**
- * Usage for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param in_use usage state
- */
-void
-GAS_proportional_address_inuse_changed (void *solver,
-    struct ATS_Address *address, int in_use)
-{
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Usage changed to %s\n",
-      (GNUNET_YES == in_use) ? "USED" : "UNUSED");
-}
-
-/**
- * Network scope for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param current_network the current network
- * @param new_network the new network
- */
-void
-GAS_proportional_address_change_network (void *solver,
-    struct ATS_Address *address, uint32_t current_network, uint32_t 
new_network)
-{
-  struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *) 
solver;
-  struct AddressSolverInformation *asi;
-  int save_active = GNUNET_NO;
-
-  struct Network *new_net = NULL;
-
-  if (current_network == new_network)
-  {
-    GNUNET_break(0);
-    return;
-  }
-
-  /* Network changed */
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Network type changed, moving %s address from `%s' to `%s'\n",
-      (GNUNET_YES == address->active) ? "active" : "inactive",
-      GNUNET_ATS_print_network_type (current_network),
-      GNUNET_ATS_print_network_type (new_network));
-
-  save_active = address->active;
-
-  /* Disable and assign no bandwidth */
-  address->active = GNUNET_NO;
-  address->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
-  address->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
-
-  /* Remove from old network */
-  GAS_proportional_address_delete (solver, address, GNUNET_NO);
-
-  /* Set new network type */
-  if (NULL == (new_net = get_network (solver, new_network)))
-  {
-    /* Address changed to invalid network... */
-    LOG(GNUNET_ERROR_TYPE_ERROR,
-        _("Invalid network type `%u' `%s': Disconnect!\n"), new_network,
-        GNUNET_ATS_print_network_type (new_network));
-
-    /* Find new address to suggest since no bandwidth in network*/
-    if (NULL == GAS_proportional_get_preferred_address (s, &address->peer))
-    {
-      /* No alternative address found, disconnect peer */
-      s->bw_changed (s->bw_changed_cls, address);
-    }
-    return;
-  }
-
-  /* Add to new network and update*/
-  asi = address->solver_information;
-  asi->network = new_net;
-  GAS_proportional_address_add (solver, address, new_network);
-  if (GNUNET_YES == save_active)
-  {
-    /* check if bandwidth available in new network */
-    if (GNUNET_YES == (is_bandwidth_available_in_network (new_net)))
-    {
-      /* Assign bandwidth to updated address */
-      address->active = GNUNET_YES;
-      addresse_increment (s, new_net, GNUNET_NO, GNUNET_YES);
-      distribute_bandwidth_in_network (solver, new_net, NULL);
-    }
-    else
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG,
-          "Not enough bandwidth in new network, suggesting alternative address 
..\n");
-      /* Find new address to suggest since no bandwidth in network*/
-      if (NULL == GAS_proportional_get_preferred_address (s, &address->peer))
-      {
-        /* No alternative address found, disconnect peer */
-        s->bw_changed (s->bw_changed_cls, address);
-      }
-    }
-  }
-}
-
-/**
- * Add a new single address to a network
- *
- * @param solver the solver Handle
- * @param address the address to add
- * @param network network type of this address
- */
-void
-GAS_proportional_address_add (void *solver, struct ATS_Address *address,
-    uint32_t network)
-{
-  struct GAS_PROPORTIONAL_Handle *s = solver;
-  struct Network *net = NULL;
-  struct AddressWrapper *aw = NULL;
-  struct AddressSolverInformation *asi;
-
-  GNUNET_assert(NULL != s);
-  net = get_network (s, network);
-  if (NULL == net)
-  {
-    GNUNET_break(0);
-    return;
-  }
-
-  aw = GNUNET_malloc (sizeof (struct AddressWrapper));
-  aw->addr = address;
-  GNUNET_CONTAINER_DLL_insert(net->head, net->tail, aw);
-  addresse_increment (s, net, GNUNET_YES, GNUNET_NO);
-
-  asi = GNUNET_malloc (sizeof (struct AddressSolverInformation));
-  asi->network = net;
-  asi->calculated_quota_in_NBO = 0;
-  asi->calculated_quota_out_NBO = 0;
-  aw->addr->solver_information = asi;
-
-  if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (s->requests, 
&address->peer))
-  {
-    if (NULL == get_active_address (s, s->addresses, &address->peer))
-    {
-      if (NULL != GAS_proportional_get_preferred_address (s, &address->peer))
-          s->bw_changed (s->bw_changed_cls, (struct ATS_Address *) address);
-    }
-  }
-
-  LOG(GNUNET_ERROR_TYPE_INFO,
-      "Adding new address %p for peer `%s', now total %u and active %u 
addresses in network `%s'\n",
-      address, GNUNET_i2s(&address->peer), net->total_addresses, 
net->active_addresses, net->desc);
-}
-
-
-/* end of gnunet-service-ats-solver_proportional.c */

Deleted: gnunet/src/ats/libgnunet_plugin_ats_proportional.h
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_proportional.h  2013-12-09 23:22:55 UTC 
(rev 31243)
+++ gnunet/src/ats/libgnunet_plugin_ats_proportional.h  2013-12-10 07:58:08 UTC 
(rev 31244)
@@ -1,186 +0,0 @@
-/*
- 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/libgnunet_plugin_ats_proportional.h
- * @brief ATS proportional solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet_ats_plugin.h"
-#include "gnunet-service-ats_addresses.h"
-
-/**
- * ATS proportional solver
- *
- * General description
- */
-
-/**
- * Changes the preferences for a peer in the problem
- *
- * @param solver the solver handle
- * @param peer the peer to change the preference for
- * @param kind the kind to change the preference
- * @param pref_rel the normalized preference value for this kind over all 
clients
- */
-void
-GAS_proportional_address_change_preference (void *solver,
-    const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind 
kind,
-    double pref_rel);
-
-/**
- * Get application feedback for a peer
- *
- * @param solver the solver handle
- * @param application the application
- * @param peer the peer to change the preference for
- * @param scope the time interval for this feedback: [now - scope .. now]
- * @param kind the kind to change the preference
- * @param score the score
- */
-void
-GAS_proportional_address_preference_feedback (void *solver, void *application,
-    const struct GNUNET_PeerIdentity *peer,
-    const struct GNUNET_TIME_Relative scope,
-    enum GNUNET_ATS_PreferenceKind kind, double score);
-
-/**
- * Shutdown the proportional problem solver
- *
- * @param solver the respective handle to shutdown
- */
-void
-GAS_proportional_done (void * solver);
-
-/**
- * Add a single address within a network to the solver
- *
- * @param solver the solver Handle
- * @param address the address to add
- * @param network network type of this address
- */
-void
-GAS_proportional_address_add (void *solver, struct ATS_Address *address,
-    uint32_t network);
-
-/**
- * Transport properties for this address have changed
- *
- * @param solver solver handle
- * @param address the address
- * @param type the ATSI type in HBO
- * @param abs_value the absolute value of the property
- * @param rel_value the normalized value
- */
-void
-GAS_proportional_address_property_changed (void *solver,
-    struct ATS_Address *address, uint32_t type, uint32_t abs_value,
-    double rel_value);
-
-/**
- * Transport session for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param cur_session the current session
- * @param new_session the new session
- */
-void
-GAS_proportional_address_session_changed (void *solver,
-    struct ATS_Address *address, uint32_t cur_session, uint32_t new_session);
-
-/**
- * Usage for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param in_use usage state
- */
-void
-GAS_proportional_address_inuse_changed (void *solver,
-    struct ATS_Address *address, int in_use);
-
-/**
- * Network scope for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param current_network the current network
- * @param new_network the new network
- */
-void
-GAS_proportional_address_change_network (void *solver,
-    struct ATS_Address *address, uint32_t current_network, uint32_t 
new_network);
-
-/**
- * Remove an address from the solver
- *
- * @param solver the solver handle
- * @param address the address to remove
- * @param session_only delete only session not whole address
- */
-void
-GAS_proportional_address_delete (void *solver, struct ATS_Address *address,
-    int session_only);
-
-/**
- * Start a bulk operation
- *
- * @param solver the solver
- */
-void
-GAS_proportional_bulk_start (void *solver);
-
-/**
- * Bulk operation done
- */
-void
-GAS_proportional_bulk_stop (void *solver);
-
-/**
- * Stop notifying about address and bandwidth changes for this peer
- *
- * @param solver the proportional handle
- * @param peer the peer
- */
-void
-GAS_proportional_stop_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Get the prefered address for a specific peer
- *
- * @param solver the solver handle
- * @param peer the identity of the peer
- */
-const struct ATS_Address *
-GAS_proportional_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer);
-
-/* end of gnunet-service-ats-solver_proportional.c */

Deleted: gnunet/src/ats/libgnunet_plugin_ats_ril.c
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_ril.c   2013-12-09 23:22:55 UTC (rev 
31243)
+++ gnunet/src/ats/libgnunet_plugin_ats_ril.c   2013-12-10 07:58:08 UTC (rev 
31244)
@@ -1,2420 +0,0 @@
-/*
- 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/libgnunet_plugin_ats_ril.c
- * @brief ATS reinforcement learning solver
- * @author Fabian Oehlmann
- * @author Matthias Wachs
- */
-#include "libgnunet_plugin_ats_ril.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "ats-ril",__VA_ARGS__)
-
-#define MIN_BW ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)
-
-#define RIL_ACTION_INVALID -1
-#define RIL_FEATURES_ADDRESS_COUNT (0)// + GNUNET_ATS_QualityPropertiesCount)
-#define RIL_FEATURES_NETWORK_COUNT 2
-#define RIL_INTERVAL_EXPONENT 10
-
-#define RIL_DEFAULT_STEP_TIME_MIN GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MILLISECONDS, 500)
-#define RIL_DEFAULT_STEP_TIME_MAX GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MILLISECONDS, 3000)
-#define RIL_DEFAULT_ALGORITHM RIL_ALGO_SARSA
-#define RIL_DEFAULT_DISCOUNT_BETA 1
-#define RIL_DEFAULT_DISCOUNT_GAMMA 0.5
-#define RIL_DEFAULT_GRADIENT_STEP_SIZE 0.1
-#define RIL_DEFAULT_TRACE_DECAY 0.5
-#define RIL_DEFAULT_EXPLORE_RATIO 0.1
-#define RIL_DEFAULT_GLOBAL_REWARD_SHARE 0.5
-
-#define RIL_INC_DEC_STEP_SIZE 1
-
-/**
- * ATS reinforcement learning solver
- *
- * General description
- */
-
-/**
- * The actions, how an agent can manipulate the current assignment. I.e. how 
the bandwidth can be
- * changed for the currently chosen address. Not depicted in the enum are the 
actions of switching
- * to a particular address. The action of switching to address with index i is 
depicted by the
- * number (RIL_ACTION_TYPE_NUM + i).
- */
-enum RIL_Action_Type
-{
-  RIL_ACTION_NOTHING = -1,
-  RIL_ACTION_BW_IN_DBL = -2, //TODO! put actions back
-  RIL_ACTION_BW_IN_HLV = -3,
-  RIL_ACTION_BW_IN_INC = 0,
-  RIL_ACTION_BW_IN_DEC = 1,
-  RIL_ACTION_BW_OUT_DBL = -4,
-  RIL_ACTION_BW_OUT_HLV = -5,
-  RIL_ACTION_BW_OUT_INC = -6,
-  RIL_ACTION_BW_OUT_DEC = -7,
-  RIL_ACTION_TYPE_NUM = 1
-};
-
-enum RIL_Algorithm
-{
-  RIL_ALGO_SARSA = 0,
-  RIL_ALGO_Q = 1
-};
-
-enum RIL_E_Modification
-{
-  RIL_E_SET,
-  RIL_E_ZERO,
-  RIL_E_ACCUMULATE,
-  RIL_E_REPLACE
-};
-
-/**
- * Global learning parameters
- */
-struct RIL_Learning_Parameters
-{
-  /**
-   * The TD-algorithm to use
-   */
-  enum RIL_Algorithm algorithm;
-
-  /**
-   * Gradient-descent step-size
-   */
-  double alpha;
-
-  /**
-   * Learning discount variable in the TD-update for semi-MDPs
-   */
-  double beta;
-
-  /**
-   * Learning discount factor in the TD-update for MDPs
-   */
-  double gamma;
-
-  /**
-   * Trace-decay factor for eligibility traces
-   */
-  double lambda;
-
-  /**
-   * Ratio, with what probability an agent should explore in the e-greed policy
-   */
-  double explore_ratio;
-
-  /**
-   * How big the share of the global part of the reward signal is
-   */
-  double reward_global_share;
-
-  /**
-   * Minimal interval time between steps in milliseconds
-   */
-  struct GNUNET_TIME_Relative step_time_min;
-
-  /**
-   * Maximum interval time between steps in milliseconds
-   */
-  struct GNUNET_TIME_Relative step_time_max;
-};
-
-/**
- * Wrapper for addresses to store them in agent's linked list
- */
-struct RIL_Address_Wrapped
-{
-  /**
-   * Next in DLL
-   */
-  struct RIL_Address_Wrapped *next;
-
-  /**
-   * Previous in DLL
-   */
-  struct RIL_Address_Wrapped *prev;
-
-  /**
-   * The address
-   */
-  struct ATS_Address *address_naked;
-};
-
-struct RIL_Peer_Agent
-{
-  /**
-   * Next agent in solver's linked list
-   */
-  struct RIL_Peer_Agent *next;
-
-  /**
-   * Previous agent in solver's linked list
-   */
-  struct RIL_Peer_Agent *prev;
-
-  /**
-   * Environment handle
-   */
-  struct GAS_RIL_Handle *envi;
-
-  /**
-   * Peer ID
-   */
-  struct GNUNET_PeerIdentity peer;
-
-  /**
-   * Whether the agent is active or not
-   */
-  int is_active;
-
-  /**
-   * Number of performed time-steps
-   */
-  unsigned long long step_count;
-
-  /**
-   * Experience matrix W
-   */
-  double ** W;
-
-  /**
-   * Number of rows of W / Number of state-vector features
-   */
-  unsigned int m;
-
-  /**
-   * Number of columns of W / Number of actions
-   */
-  unsigned int n;
-
-  /**
-   * Last perceived state feature vector
-   */
-  double * s_old;
-
-  /**
-   * Last chosen action
-   */
-  int a_old;
-
-  /**
-   * Eligibility trace vector
-   */
-  double * e;
-
-  /**
-   * Address in use
-   */
-  struct ATS_Address * address_inuse;
-
-  /**
-   * Head of addresses DLL
-   */
-  struct RIL_Address_Wrapped * addresses_head;
-
-  /**
-   * Tail of addresses DLL
-   */
-  struct RIL_Address_Wrapped * addresses_tail;
-
-  /**
-   * Inbound bandwidth assigned by the agent
-   */
-  unsigned long long bw_in;
-
-  /**
-   * Outbound bandwidth assigned by the agent
-   */
-  unsigned long long bw_out;
-
-  /**
-   * Flag whether a suggestion has to be issued
-   */
-  int suggestion_issue;
-
-  /**
-   * The address which has to be issued
-   */
-  struct ATS_Address * suggestion_address;
-};
-
-struct RIL_Network
-{
-  /**
-   * ATS network type
-   */
-  enum GNUNET_ATS_Network_Type type;
-
-  /**
-   * Total available inbound bandwidth
-   */
-  unsigned long long bw_in_available;
-
-  /**
-   * Bandwidth inbound assigned in network after last step
-   */
-  unsigned long long bw_in_assigned;
-
-  /**
-   * Total available outbound bandwidth
-   */
-  unsigned long long bw_out_available;
-
-  /**
-   * * Bandwidth outbound assigned in network after last step
-   */
-  unsigned long long bw_out_assigned;
-};
-
-/**
- * A handle for the reinforcement learning solver
- */
-struct GAS_RIL_Handle
-{
-  /**
-   * The solver-plugin environment of the solver-plugin API
-   */
-  struct GNUNET_ATS_PluginEnvironment *plugin_envi;
-
-  /**
-   * Statistics handle
-   */
-  struct GNUNET_STATISTICS_Handle *stats;
-
-  /**
-   * Number of performed steps
-   */
-  unsigned long long step_count;
-
-  /**
-   * Timestamp for the last time-step
-   */
-  struct GNUNET_TIME_Absolute step_time_last;
-
-  /**
-   * Task identifier of the next time-step to be executed
-   */
-  GNUNET_SCHEDULER_TaskIdentifier step_next_task_id;
-
-  /**
-   * Variable discount factor, dependent on time between steps
-   */
-  double global_discount_variable;
-
-  /**
-   * Integrated variable discount factor, dependent on time between steps
-   */
-  double global_discount_integrated;
-
-  /**
-   * State vector for networks for the current step
-   */
-  double *global_state_networks;
-
-  /**
-   * Lock for bulk operations
-   */
-  int bulk_lock;
-
-  /**
-   * Number of changes during a lock
-   */
-  int bulk_changes;
-
-  /**
-   * Learning parameters
-   */
-  struct RIL_Learning_Parameters parameters;
-
-  /**
-   * Array of networks with global assignment state
-   */
-  struct RIL_Network * network_entries;
-
-  /**
-   * Networks count
-   */
-  unsigned int networks_count;
-
-  /**
-   * List of active peer-agents
-   */
-  struct RIL_Peer_Agent * agents_head;
-  struct RIL_Peer_Agent * agents_tail;
-
-  /**
-   * Shutdown
-   */
-  int done;
-
-  /**
-   * Simulate steps, i.e. schedule steps immediately
-   */
-  unsigned long long simulate;
-};
-
-/*
- *  Private functions
- *  ---------------------------
- */
-
-static int
-ril_count_agents(struct GAS_RIL_Handle * solver);
-
-/**
- * Estimate the current action-value for state s and action a
- *
- * @param agent agent performing the estimation
- * @param state s
- * @param action a
- * @return estimation value
- */
-static double
-agent_estimate_q (struct RIL_Peer_Agent *agent, double *state, int action)
-{
-  int i;
-  double result = 0;
-
-  for (i = 0; i < agent->m; i++)
-  {
-    result += state[i] * agent->W[action][i];
-  }
-
-  GNUNET_assert(!isnan(result));
-
-  if (isinf(result))
-  {
-    return isinf(result) * UINT32_MAX; //TODO! fix
-  }
-
-  return result;
-}
-
-/**
- * Decide whether to do exploration (i.e. taking a new action) or exploitation 
(i.e. taking the
- * currently estimated best action) in the current step
- *
- * @param agent agent performing the step
- * @return yes, if exploring
- */
-static int
-agent_decide_exploration (struct RIL_Peer_Agent *agent)
-{
-  //TODO? Future Work: Improve exploration/exploitation trade-off by different 
mechanisms than e-greedy
-  double r = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-      UINT32_MAX) / (double) UINT32_MAX;
-
-  if (r < agent->envi->parameters.explore_ratio)
-  {
-    return GNUNET_YES;
-  }
-  return GNUNET_NO;
-}
-
-  /**
-   * Get the index of the address in the agent's list.
-   *
-   * @param agent agent handle
-   * @param address address handle
-   * @return the index, starting with zero
-   */
-static int
-agent_address_get_index (struct RIL_Peer_Agent *agent, struct ATS_Address 
*address)
-{
-  int i;
-  struct RIL_Address_Wrapped *cur;
-
-  i = -1;
-  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
-  {
-    i++;
-    if (cur->address_naked == address)
-    {
-      return i;
-    }
-  }
-
-  return i;
-}
-
-/**
- * Gets the wrapped address from the agent's list
- *
- * @param agent agent handle
- * @param address address handle
- * @return wrapped address
- */
-static struct RIL_Address_Wrapped *
-agent_address_get (struct RIL_Peer_Agent *agent, struct ATS_Address *address)
-{
-  struct RIL_Address_Wrapped *cur;
-
-  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
-  {
-    if (cur->address_naked == address)
-    {
-      return cur;
-    }
-  }
-
-  return NULL ;
-}
-
-/**
- * Gets the action, with the maximal estimated Q-value (i.e. the one currently 
estimated to bring the
- * most reward in the future)
- *
- * @param agent agent performing the calculation
- * @param state the state from which to take the action
- * @return the action promising most future reward
- */
-static int
-agent_get_action_best (struct RIL_Peer_Agent *agent, double *state)
-{
-  int i;
-  int max_i = RIL_ACTION_INVALID;
-  double cur_q;
-  double max_q = -DBL_MAX;
-
-  for (i = 0; i < agent->n; i++)
-  {
-    cur_q = agent_estimate_q (agent, state, i);
-    if (cur_q > max_q)
-    {
-      max_q = cur_q;
-      max_i = i;
-    }
-  }
-
-  GNUNET_assert(RIL_ACTION_INVALID != max_i);
-
-  return max_i;
-}
-
-/**
- * Gets any action, to explore the action space from that state
- *
- * @param agent agent performing the calculation
- * @param state the state from which to take the action
- * @return any action
- */
-static int
-agent_get_action_explore (struct RIL_Peer_Agent *agent, double *state)
-{
-  // TODO?: Future Work: Choose the action for exploration, which has been 
explored the least in this state
-  return GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, agent->n);
-}
-
-/**
- * Updates the weights (i.e. coefficients) of the weight vector in matrix W 
for action a
- *
- * @param agent the agent performing the update
- * @param reward the reward received for the last action
- * @param s_next the new state, the last step got the agent into
- * @param a_prime the new
- */
-static void
-agent_update_weights (struct RIL_Peer_Agent *agent, double reward, double 
*s_next, int a_prime)
-{
-  int i;
-  double delta;
-  double *theta = agent->W[agent->a_old];
-
-  delta = agent->envi->global_discount_integrated * reward; //reward
-  delta += agent->envi->global_discount_variable * agent_estimate_q (agent, 
s_next, a_prime); //discounted future value
-  delta -= agent_estimate_q (agent, agent->s_old, agent->a_old); //one step
-
-  LOG(GNUNET_ERROR_TYPE_INFO, "update()   Step# %llu  Q(s,a): %f  a: %f  r: %f 
 y: %f  Q(s+1,a+1) = %f  delta: %f\n",
-      agent->step_count,
-      agent_estimate_q (agent, agent->s_old, agent->a_old),
-      agent->envi->parameters.alpha,
-      reward,
-      agent->envi->global_discount_variable,
-      agent_estimate_q (agent, s_next, a_prime),
-      delta);
-
-  for (i = 0; i < agent->m; i++)
-  {
-//    LOG(GNUNET_ERROR_TYPE_INFO, "alpha = %f   delta = %f   e[%d] = %f\n",
-//        agent->envi->parameters.alpha,
-//        delta,
-//        i,
-//        agent->e[i]);
-    theta[i] += agent->envi->parameters.alpha * delta * agent->s_old[i];// * 
agent->e[i];
-  }
-}
-
-/**
- * Changes the eligibility trace vector e in various manners:
- * RIL_E_ACCUMULATE - adds 1 to each component as in accumulating eligibility 
traces
- * RIL_E_REPLACE - resets each component to 1 as in replacing traces
- * RIL_E_SET - multiplies e with discount factor and lambda as in the update 
rule
- * RIL_E_ZERO - sets e to 0 as in Watkin's Q-learning algorithm when exploring 
and when initializing
- *
- * @param agent the agent handle
- * @param mod the kind of modification
- */
-static void
-agent_modify_eligibility (struct RIL_Peer_Agent *agent, enum 
RIL_E_Modification mod, double *f)
-{
-  int i;
-  double *e = agent->e;
-
-  for (i = 0; i < agent->m; i++)
-  {
-    switch (mod)
-    {
-    case RIL_E_ACCUMULATE:
-      e[i] += f[i];
-      break;
-    case RIL_E_REPLACE:
-      e[i] = f[i];
-      break;
-    case RIL_E_SET:
-      e[i] *= agent->envi->global_discount_variable * 
agent->envi->parameters.lambda;
-      break;
-    case RIL_E_ZERO:
-      e[i] = 0;
-      break;
-    }
-  }
-}
-
-static void
-ril_inform (struct GAS_RIL_Handle *solver,
-    enum GAS_Solver_Operation op,
-    enum GAS_Solver_Status stat)
-{
-  if (NULL != solver->plugin_envi->info_cb)
-    solver->plugin_envi->info_cb (solver->plugin_envi->info_cb_cls, op, stat, 
GAS_INFO_NONE);
-}
-
-/**
- * Changes the active assignment suggestion of the handler and invokes the 
bw_changed callback to
- * notify ATS of its new decision
- *
- * @param solver solver handle
- * @param agent agent handle
- * @param new_address the address which is to be used
- * @param new_bw_in the new amount of inbound bandwidth set for this address
- * @param new_bw_out the new amount of outbound bandwidth set for this address
- * @param silent disables invocation of the bw_changed callback, if GNUNET_YES
- */
-static void
-envi_set_active_suggestion (struct GAS_RIL_Handle *solver,
-    struct RIL_Peer_Agent *agent,
-    struct ATS_Address *new_address,
-    unsigned long long new_bw_in,
-    unsigned long long new_bw_out,
-    int silent)
-{
-  int notify = GNUNET_NO;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "    set_active_suggestion() for peer '%s'\n", 
GNUNET_i2s (&agent->peer));
-
-  //address change
-  if (agent->address_inuse != new_address)
-  {
-    if (NULL != agent->address_inuse)
-    {
-      agent->address_inuse->active = GNUNET_NO;
-      agent->address_inuse->assigned_bw_in.value__ = htonl (0);
-      agent->address_inuse->assigned_bw_out.value__ = htonl (0);
-    }
-    if (NULL != new_address)
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG, "    set address active: %s\n", 
agent->is_active ? "yes" : "no");
-      new_address->active = agent->is_active;
-      new_address->assigned_bw_in.value__ = htonl (agent->bw_in);
-      new_address->assigned_bw_out.value__ = htonl (agent->bw_out);
-    }
-    notify |= GNUNET_YES;
-  }
-
-  if (new_address)
-  {
-    //activity change
-    if (new_address->active != agent->is_active)
-    {
-      new_address->active = agent->is_active;
-      notify |= GNUNET_YES;
-    }
-
-    //bw change
-    if (agent->bw_in != new_bw_in)
-    {
-      agent->bw_in = new_bw_in;
-      new_address->assigned_bw_in.value__ = htonl (new_bw_in);
-      notify |= GNUNET_YES;
-    }
-    if (agent->bw_out != new_bw_out)
-    {
-      agent->bw_out = new_bw_out;
-      new_address->assigned_bw_out.value__ = htonl (new_bw_out);
-      notify |= GNUNET_YES;
-    }
-  }
-
-  if (notify && agent->is_active && (GNUNET_NO == silent))
-  {
-    if (new_address)
-    {
-      LOG(GNUNET_ERROR_TYPE_DEBUG, "    envi_set_active_suggestion() 
notify\n");
-      agent->suggestion_issue = GNUNET_YES;
-      agent->suggestion_address = new_address;
-    }
-    else if (agent->address_inuse)
-    {
-      //disconnect case, no new address
-      GNUNET_assert(0 == ntohl (agent->address_inuse->assigned_bw_in.value__));
-      GNUNET_assert(0 == ntohl 
(agent->address_inuse->assigned_bw_out.value__));
-      agent->bw_in = 0;
-      agent->bw_out = 0;
-
-      agent->suggestion_issue = GNUNET_YES;
-      agent->suggestion_address = agent->address_inuse;
-    }
-  }
-  agent->address_inuse = new_address;
-}
-
-static unsigned long long
-ril_network_get_assigned (struct GAS_RIL_Handle *solver, enum 
GNUNET_ATS_Network_Type type, int direction_in)
-{
-  struct RIL_Peer_Agent *cur;
-  struct RIL_Network *net;
-  unsigned long long sum = 0;
-
-  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
-  {
-    if (cur->is_active && cur->address_inuse)
-    {
-      net = cur->address_inuse->solver_information;
-      if (net->type == type)
-      {
-        if (direction_in)
-          sum += cur->bw_in;
-        else
-          sum += cur->bw_out;
-      }
-    }
-  }
-
-  return sum;
-}
-
-//static void
-//envi_state_networks (struct GAS_RIL_Handle *solver)
-//{
-//  int i;
-//  struct RIL_Network net;
-//  int overutilized_in;
-//  int overutilized_out;
-//
-//  for (i = 0; i < solver->networks_count; i++)
-//  {
-//    net = solver->network_entries[i];
-//
-//    overutilized_in = net.bw_in_assigned > net.bw_in_available;
-//    overutilized_out = net.bw_out_assigned > net.bw_out_available;
-//
-//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 0] = 
((double) net.bw_in_assigned / (double) net.bw_in_available)*10;
-//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 1] = 
(double) overutilized_in;
-//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 2] = 
((double) net.bw_out_assigned / (double) net.bw_out_available)*10;
-//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 3] = 
(double) overutilized_out;
-//  }
-//}
-
-/**
- * Allocates a state vector and fills it with the features present
- * @param solver the solver handle
- * @param agent the agent handle
- * @return pointer to the state vector
- */
-static double *
-envi_get_state (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
-{
-  int i;
-//  int k;
-  double *state = GNUNET_malloc (sizeof (double) * agent->m);
-  struct RIL_Address_Wrapped *cur_address;
-//  const double *preferences;
-//  const double *properties;
-  struct RIL_Network *net;
-
-  //copy global networks state
-  for (i = 0; i < solver->networks_count * RIL_FEATURES_NETWORK_COUNT; i++)
-  {
-//    state[i] = solver->global_state_networks[i];
-  }
-  net = agent->address_inuse->solver_information;
-
-  state[0] = (double) net->bw_in_assigned / 1024; //(double) 
net->bw_in_available;
-  if (net->bw_in_assigned > net->bw_in_available)
-  {
-    state[1] = 1;// net->bw_in_available;
-  }
-  else
-  {
-    state[1] = 0;
-  }
-  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  state[0] = %f\n", state[0]);
-  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  state[1] = %f\n", state[1]);
-
-  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  W / %08.3f %08.3f \\ \n", 
agent->W[0][0], agent->W[1][0]);
-  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  W \\ %08.3f %08.3f / \n", 
agent->W[0][1], agent->W[1][1]);
-
-
-  //get peer features
-//  preferences = solver->plugin_envi->get_preferences 
(solver->plugin_envi->get_preference_cls,
-//        &agent->peer);
-//  for (k = 0; k < GNUNET_ATS_PreferenceCount; k++)
-//  {
-//    state[i++] = preferences[k];
-//  }
-
-  //get address specific features
-  for (cur_address = agent->addresses_head; NULL != cur_address; cur_address = 
cur_address->next)
-  {
-//    //when changing the number of address specific state features, change 
RIL_FEATURES_ADDRESS_COUNT macro
-//    state[i++] = cur_address->address_naked->active;
-//    state[i++] = cur_address->address_naked->active ? agent->bw_in : 0;
-//    state[i++] = cur_address->address_naked->active ? agent->bw_out : 0;
-//    properties = solver->plugin_envi->get_property 
(solver->plugin_envi->get_property_cls,
-//        cur_address->address_naked);
-//    for (k = 0; k < GNUNET_ATS_QualityPropertiesCount; k++)
-//    {
-//      state[i++] = properties[k];
-//    }
-  }
-
-  return state;
-}
-
-///**
-// * For all networks a peer has an address in, this gets the maximum 
bandwidth which could
-// * theoretically be available in one of the networks. This is used for 
bandwidth normalization.
-// *
-// * @param agent the agent handle
-// * @param direction_in whether the inbound bandwidth should be considered. 
Returns the maximum outbound bandwidth if GNUNET_NO
-// */
-//static unsigned long long
-//ril_get_max_bw (struct RIL_Peer_Agent *agent, int direction_in)
-//{
-//  /*
-//   * get the maximum bandwidth possible for a peer, e.g. among all addresses 
which addresses'
-//   * network could provide the maximum bandwidth if all that bandwidth was 
used on that one peer.
-//   */
-//  unsigned long long max = 0;
-//  struct RIL_Address_Wrapped *cur;
-//  struct RIL_Network *net;
-//
-//  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
-//  {
-//    net = cur->address_naked->solver_information;
-//    if (direction_in)
-//    {
-//      if (net->bw_in_available > max)
-//      {
-//        max = net->bw_in_available;
-//      }
-//    }
-//    else
-//    {
-//      if (net->bw_out_available > max)
-//      {
-//        max = net->bw_out_available;
-//      }
-//    }
-//  }
-//  return max;
-//}
-
-///**
-// * Get the index of the quality-property in question
-// *
-// * @param type the quality property type
-// * @return the index
-// */
-//static int
-//ril_find_property_index (uint32_t type)
-//{
-//  int existing_types[] = GNUNET_ATS_QualityProperties;
-//  int c;
-//  for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
-//    if (existing_types[c] == type)
-//      return c;
-//  return GNUNET_SYSERR;
-//}
-
-//static int
-//ril_get_atsi (struct ATS_Address *address, uint32_t type)
-//{
-//  int c1;
-//  GNUNET_assert(NULL != address);
-//
-//  if ((NULL == address->atsi) || (0 == address->atsi_count))
-//    return 0;
-//
-//  for (c1 = 0; c1 < address->atsi_count; c1++)
-//  {
-//    if (ntohl (address->atsi[c1].type) == type)
-//      return ntohl (address->atsi[c1].value);
-//  }
-//  return 0;
-//}
-
-//static double
-//envi_reward_global (struct GAS_RIL_Handle *solver)
-//{
-//  int i;
-//  struct RIL_Network net;
-//  unsigned int sum_in_available = 0;
-//  unsigned int sum_out_available = 0;
-//  unsigned int sum_in_assigned = 0;
-//  unsigned int sum_out_assigned = 0;
-//  double ratio_in;
-//  double ratio_out;
-//
-//  for (i = 0; i < solver->networks_count; i++)
-//  {
-//    net = solver->network_entries[i];
-//    sum_in_available += net.bw_in_available;
-//    sum_in_assigned += net.bw_in_assigned;
-//    sum_out_available += net.bw_out_available;
-//    sum_out_assigned += net.bw_out_assigned;
-//  }
-//
-//  ratio_in = ((double) sum_in_assigned) / ((double) sum_in_available);
-//  ratio_out = ((double) sum_out_assigned) / ((double) sum_out_available);
-//
-//  // global reward in [1,2]
-//  return ratio_in +1;
-//  return ((ratio_in + ratio_out) / 2) + 1;
-//}
-
-//static double
-//envi_reward_local (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent)
-//{
-//  const double *preferences;
-//  const double *properties;
-//  int prop_index;
-//  double pref_match = 0;
-//  double bw_norm;
-//  double dl_norm;
-//
-//  preferences = solver->plugin_envi->get_preferences 
(solver->plugin_envi->get_preference_cls,
-//      &agent->peer);
-//  properties = solver->plugin_envi->get_property 
(solver->plugin_envi->get_property_cls,
-//      agent->address_inuse);
-//
-//  // delay in [0,1]
-//  prop_index = ril_find_property_index (GNUNET_ATS_QUALITY_NET_DELAY);
-//  dl_norm = 2 - properties[prop_index]; //invert property as we want to 
maximize for lower latencies
-//
-//  // utilization in [0,1]
-//  bw_norm = (((double) ril_get_atsi (agent->address_inuse, 
GNUNET_ATS_UTILIZATION_IN)
-//      / (double) ril_get_max_bw (agent, GNUNET_YES))
-//      + ((double) ril_get_atsi (agent->address_inuse, 
GNUNET_ATS_UTILIZATION_OUT)
-//          / (double) ril_get_max_bw (agent, GNUNET_NO))) / 2;
-//
-//  // preference matching in [0,4]
-//  pref_match += (preferences[GNUNET_ATS_PREFERENCE_LATENCY] * dl_norm);
-//  pref_match += (preferences[GNUNET_ATS_PREFERENCE_BANDWIDTH] * bw_norm);
-//
-//  // local reward in [1,2]
-//  return (pref_match / 4) +1;
-//}
-
-/**
- * Gets the reward for the last performed step, which is calculated in equal
- * parts from the local (the peer specific) and the global (for all peers
- * identical) reward.
- *
- * @param solver the solver handle
- * @param agent the agent handle
- * @return the reward
- */
-static double
-envi_get_reward (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
-{
-  struct RIL_Network *net;
-//  double reward = 0;
-  long long overutilized_in = 0;
-//  long long overutilized_out;
-  long long assigned_in = 0;
-//  long long assigned_out = 0;
-//  long long unused;
-
-  //punish overutilization
-  net = agent->address_inuse->solver_information;
-
-  if (net->bw_in_assigned > net->bw_in_available)
-  {
-    overutilized_in = (net->bw_in_assigned - net->bw_in_available);
-    assigned_in = net->bw_in_available;
-  }
-  else
-  {
-    assigned_in = net->bw_in_assigned;
-  }
-//  if (net->bw_out_assigned > net->bw_out_available)
-//  {
-//    overutilized_out = (net->bw_out_assigned - net->bw_out_available);
-//    assigned_out = net->bw_out_available;
-//  }
-//  else
-//  {
-//    assigned_out = net->bw_out_assigned;
-//  }
-
-//  unused = net->bw_in_available - net->bw_in_assigned;
-//  unused = unused < 0 ? unused : -unused;
-
-  return (double) (assigned_in - overutilized_in) / 1024;
-
-//  reward += envi_reward_global (solver) * 
(solver->parameters.reward_global_share);
-//  reward += envi_reward_local (solver, agent) * (1 - 
solver->parameters.reward_global_share);
-//
-//  return (reward - 1.) * 100;
-}
-
-/**
- * Doubles the bandwidth for the active address
- *
- * @param solver solver handle
- * @param agent agent handle
- * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise the 
outbound bandwidth
- */
-static void
-envi_action_bw_double (struct GAS_RIL_Handle *solver,
-    struct RIL_Peer_Agent *agent,
-    int direction_in)
-{
-  unsigned long long new_bw;
-
-  if (direction_in)
-  {
-    new_bw = agent->bw_in * 2;
-    if (new_bw < agent->bw_in || new_bw > GNUNET_ATS_MaxBandwidth)
-      new_bw = GNUNET_ATS_MaxBandwidth;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
-        agent->bw_out, GNUNET_NO);
-  }
-  else
-  {
-    new_bw = agent->bw_out * 2;
-    if (new_bw < agent->bw_out || new_bw > GNUNET_ATS_MaxBandwidth)
-      new_bw = GNUNET_ATS_MaxBandwidth;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in,
-        new_bw, GNUNET_NO);
-  }
-}
-
-/**
- * Cuts the bandwidth for the active address in half. The least amount of 
bandwidth suggested, is
- * the minimum bandwidth for a peer, in order to not invoke a disconnect.
- *
- * @param solver solver handle
- * @param agent agent handle
- * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise 
change the outbound
- * bandwidth
- */
-static void
-envi_action_bw_halven (struct GAS_RIL_Handle *solver,
-    struct RIL_Peer_Agent *agent,
-    int direction_in)
-{
-  unsigned long long new_bw;
-
-  if (direction_in)
-  {
-    new_bw = agent->bw_in / 2;
-    if (new_bw < MIN_BW || new_bw > agent->bw_in)
-      new_bw = MIN_BW;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, 
agent->bw_out,
-        GNUNET_NO);
-  }
-  else
-  {
-    new_bw = agent->bw_out / 2;
-    if (new_bw < MIN_BW || new_bw > agent->bw_out)
-      new_bw = MIN_BW;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in, new_bw,
-        GNUNET_NO);
-  }
-}
-
-/**
- * Increases the bandwidth by 5 times the minimum bandwidth for the active 
address.
- *
- * @param solver solver handle
- * @param agent agent handle
- * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise 
change the outbound
- * bandwidth
- */
-static void
-envi_action_bw_inc (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent, int direction_in)
-{
-  unsigned long long new_bw;
-
-  if (direction_in)
-  {
-    new_bw = agent->bw_in + (RIL_INC_DEC_STEP_SIZE * MIN_BW);
-    if (new_bw < agent->bw_in || new_bw > GNUNET_ATS_MaxBandwidth)
-      new_bw = GNUNET_ATS_MaxBandwidth;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
-        agent->bw_out, GNUNET_NO);
-  }
-  else
-  {
-    new_bw = agent->bw_out + (RIL_INC_DEC_STEP_SIZE * MIN_BW);
-    if (new_bw < agent->bw_out || new_bw > GNUNET_ATS_MaxBandwidth)
-      new_bw = GNUNET_ATS_MaxBandwidth;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in,
-        new_bw, GNUNET_NO);
-  }
-}
-
-/**
- * Decreases the bandwidth by 5 times the minimum bandwidth for the active 
address. The least amount
- * of bandwidth suggested, is the minimum bandwidth for a peer, in order to 
not invoke a disconnect.
- *
- * @param solver solver handle
- * @param agent agent handle
- * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise 
change the outbound
- * bandwidth
- */
-static void
-envi_action_bw_dec (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent, int direction_in)
-{
-  unsigned long long new_bw;
-
-  if (direction_in)
-  {
-    new_bw = agent->bw_in - (RIL_INC_DEC_STEP_SIZE * MIN_BW);
-    if (new_bw < MIN_BW || new_bw > agent->bw_in)
-      new_bw = MIN_BW;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, 
agent->bw_out,
-        GNUNET_NO);
-  }
-  else
-  {
-    new_bw = agent->bw_out - (RIL_INC_DEC_STEP_SIZE * MIN_BW);
-    if (new_bw < MIN_BW || new_bw > agent->bw_out)
-      new_bw = MIN_BW;
-    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in, new_bw,
-        GNUNET_NO);
-  }
-}
-
-/**
- * Switches to the address given by its index
- *
- * @param solver solver handle
- * @param agent agent handle
- * @param address_index index of the address as it is saved in the agent's 
list, starting with zero
- */
-static void
-envi_action_address_switch (struct GAS_RIL_Handle *solver,
-    struct RIL_Peer_Agent *agent,
-    unsigned int address_index)
-{
-  struct RIL_Address_Wrapped *cur;
-  int i = 0;
-
-  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
-  {
-    if (i == address_index)
-    {
-      envi_set_active_suggestion (solver, agent, cur->address_naked, 
agent->bw_in, agent->bw_out,
-          GNUNET_NO);
-      return;
-    }
-
-    i++;
-  }
-
-  //no address with address_index exists, in this case this action should not 
be callable
-  GNUNET_assert(GNUNET_NO);
-}
-
-/**
- * Puts the action into effect by calling the according function
- *
- * @param solver the solver handle
- * @param agent the action handle
- * @param action the action to perform by the solver
- */
-static void
-envi_do_action (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent, 
int action)
-{
-  int address_index;
-
-  switch (action)
-  {
-  case RIL_ACTION_NOTHING:
-    break;
-  case RIL_ACTION_BW_IN_DBL:
-    envi_action_bw_double (solver, agent, GNUNET_YES);
-    break;
-  case RIL_ACTION_BW_IN_HLV:
-    envi_action_bw_halven (solver, agent, GNUNET_YES);
-    break;
-  case RIL_ACTION_BW_IN_INC:
-    envi_action_bw_inc (solver, agent, GNUNET_YES);
-    break;
-  case RIL_ACTION_BW_IN_DEC:
-    envi_action_bw_dec (solver, agent, GNUNET_YES);
-    break;
-  case RIL_ACTION_BW_OUT_DBL:
-    envi_action_bw_double (solver, agent, GNUNET_NO);
-    break;
-  case RIL_ACTION_BW_OUT_HLV:
-    envi_action_bw_halven (solver, agent, GNUNET_NO);
-    break;
-  case RIL_ACTION_BW_OUT_INC:
-    envi_action_bw_inc (solver, agent, GNUNET_NO);
-    break;
-  case RIL_ACTION_BW_OUT_DEC:
-    envi_action_bw_dec (solver, agent, GNUNET_NO);
-    break;
-  default:
-    if ((action >= RIL_ACTION_TYPE_NUM) && (action < agent->n)) //switch 
address action
-    {
-      address_index = action - RIL_ACTION_TYPE_NUM;
-
-      GNUNET_assert(address_index >= 0);
-      GNUNET_assert(
-          address_index <= agent_address_get_index (agent, 
agent->addresses_tail->address_naked));
-
-      envi_action_address_switch (solver, agent, address_index);
-      break;
-    }
-    // error - action does not exist
-    GNUNET_assert(GNUNET_NO);
-  }
-}
-
-/**
- * Performs one step of the Markov Decision Process. Other than in the 
literature the step starts
- * after having done the last action a_old. It observes the new state s_next 
and the reward
- * received. Then the coefficient update is done according to the SARSA or 
Q-learning method. The
- * next action is put into effect.
- *
- * @param agent the agent performing the step
- */
-static void
-agent_step (struct RIL_Peer_Agent *agent)
-{
-  int a_next = RIL_ACTION_INVALID;
-  int explore;
-  double *s_next;
-  double reward;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "    agent_step() Peer '%s', algorithm %s\n",
-      GNUNET_i2s (&agent->peer),
-      agent->envi->parameters.algorithm ? "Q" : "SARSA");
-
-  s_next = envi_get_state (agent->envi, agent);
-  reward = envi_get_reward (agent->envi, agent);
-  explore = agent_decide_exploration (agent);
-
-  switch (agent->envi->parameters.algorithm)
-  {
-  case RIL_ALGO_SARSA:
-    if (explore)
-    {
-      a_next = agent_get_action_explore (agent, s_next);
-    }
-    else
-    {
-      a_next = agent_get_action_best (agent, s_next);
-    }
-    if (RIL_ACTION_INVALID != agent->a_old)
-    {
-      //updates weights with selected action (on-policy), if not first step
-      agent_update_weights (agent, reward, s_next, a_next);
-      agent_modify_eligibility (agent, RIL_E_SET, s_next);
-    }
-    break;
-
-  case RIL_ALGO_Q:
-    a_next = agent_get_action_best (agent, s_next);
-    if (RIL_ACTION_INVALID != agent->a_old)
-    {
-      //updates weights with best action, disregarding actually selected 
action (off-policy), if not first step
-      agent_update_weights (agent, reward, s_next, a_next);
-    }
-    if (explore)
-    {
-      a_next = agent_get_action_explore (agent, s_next);
-      agent_modify_eligibility (agent, RIL_E_ZERO, NULL);
-    }
-    else
-    {
-      a_next = agent_get_action_best (agent, s_next);
-      agent_modify_eligibility (agent, RIL_E_SET, s_next);
-    }
-    break;
-  }
-
-  GNUNET_assert(RIL_ACTION_INVALID != a_next);
-
-  agent_modify_eligibility (agent, RIL_E_ACCUMULATE, s_next);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "step()  Step# %llu  R: %f  IN %llu  OUT 
%llu  A: %d\n",
-        agent->step_count,
-        reward,
-        agent->bw_in/1024,
-        agent->bw_out/1024,
-        a_next);
-
-  envi_do_action (agent->envi, agent, a_next);
-
-  GNUNET_free(agent->s_old);
-  agent->s_old = s_next;
-  agent->a_old = a_next;
-
-  agent->step_count += 1;
-}
-
-static void
-ril_step (struct GAS_RIL_Handle *solver);
-
-/**
- * Task for the scheduler, which performs one step and lets the solver know 
that
- * no further step is scheduled.
- *
- * @param cls the solver handle
- * @param tc the task context for the scheduler
- */
-static void
-ril_step_scheduler_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext 
*tc)
-{
-  struct GAS_RIL_Handle *solver = cls;
-
-  solver->step_next_task_id = GNUNET_SCHEDULER_NO_TASK;
-  ril_step (solver);
-}
-
-static double
-ril_get_used_resource_ratio (struct GAS_RIL_Handle *solver)
-{
-  int i;
-  struct RIL_Network net;
-  unsigned long long sum_assigned = 0;
-  unsigned long long sum_available = 0;
-  double ratio;
-
-  for (i = 0; i < solver->networks_count; i++)
-  {
-    net = solver->network_entries[i];
-    if (net.bw_in_assigned > 0) //only consider scopes where an address is 
actually active
-    {
-      sum_assigned += net.bw_in_assigned;
-      sum_assigned += net.bw_out_assigned;
-      sum_available += net.bw_in_available;
-      sum_available += net.bw_out_available;
-    }
-  }
-  if (sum_available > 0)
-  {
-    ratio = ((double) sum_assigned) / ((double) sum_available);
-  }
-  else
-  {
-    ratio = 0;
-  }
-
-  return ratio > 1 ? 1 : ratio; //overutilization possible, cap at 1
-}
-
-/**
- * Lookup network struct by type
- *
- * @param s the solver handle
- * @param type the network type
- * @return the network struct
- */
-static struct RIL_Network *
-ril_get_network (struct GAS_RIL_Handle *s, uint32_t type)
-{
-  int i;
-
-  for (i = 0; i < s->networks_count; i++)
-  {
-    if (s->network_entries[i].type == type)
-    {
-      return &s->network_entries[i];
-    }
-  }
-  return NULL ;
-}
-
-static int
-ril_network_is_not_full (struct GAS_RIL_Handle *solver, enum 
GNUNET_ATS_Network_Type network)
-{
-  struct RIL_Network *net;
-  struct RIL_Peer_Agent *agent;
-  unsigned long long address_count = 0;
-
-  for (agent = solver->agents_head; NULL != agent; agent = agent->next)
-  {
-    if (agent->address_inuse && agent->is_active)
-    {
-      net = agent->address_inuse->solver_information;
-      if (net->type == network)
-      {
-        address_count++;
-      }
-    }
-  }
-
-  net = ril_get_network (solver, network);
-  return (net->bw_in_available > MIN_BW * address_count) && 
(net->bw_out_available > MIN_BW * address_count);
-}
-
-static void
-ril_try_unblock_agent (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent, int silent)
-{
-  struct RIL_Address_Wrapped *addr_wrap;
-  struct RIL_Network *net;
-
-  for (addr_wrap = agent->addresses_head; NULL != addr_wrap; addr_wrap = 
addr_wrap->next)
-  {
-    net = addr_wrap->address_naked->solver_information;
-    if (ril_network_is_not_full(solver, net->type))
-    {
-      if (NULL == agent->address_inuse)
-        envi_set_active_suggestion (solver, agent, addr_wrap->address_naked, 
MIN_BW, MIN_BW, silent);
-      return;
-    }
-  }
-  agent->address_inuse = NULL;
-}
-
-static void
-ril_calculate_discount (struct GAS_RIL_Handle *solver)
-{
-  struct GNUNET_TIME_Absolute time_now;
-  struct GNUNET_TIME_Relative time_delta;
-  double tau;
-
-  // MDP case - remove when debugged
-  if (solver->simulate)
-  {
-    solver->global_discount_variable = solver->parameters.gamma;
-    solver->global_discount_integrated = 1;
-    return;
-  }
-
-  // semi-MDP case
-
-  //calculate tau, i.e. how many real valued time units have passed, one time 
unit is one minimum time step
-  time_now = GNUNET_TIME_absolute_get ();
-  time_delta = GNUNET_TIME_absolute_get_difference (solver->step_time_last, 
time_now);
-  solver->step_time_last = time_now;
-  tau = (double) time_delta.rel_value_us
-      / (double) solver->parameters.step_time_min.rel_value_us;
-
-  //calculate reward discounts (once per step for all agents)
-  solver->global_discount_variable = pow (M_E, ((-1.) * ((double) 
solver->parameters.beta) * tau));
-  solver->global_discount_integrated = (1. - solver->global_discount_variable)
-      / (double) solver->parameters.beta;
-}
-
-static void
-ril_calculate_assigned_bwnet (struct GAS_RIL_Handle *solver)
-{
-  int c;
-  struct RIL_Network *net;
-
-  for (c = 0; c < solver->networks_count; c++)
-  {
-    net = &solver->network_entries[c];
-    net->bw_in_assigned = ril_network_get_assigned(solver, net->type, 
GNUNET_YES);
-    net->bw_out_assigned = ril_network_get_assigned(solver, net->type, 
GNUNET_NO);
-  }
-}
-
-/**
- * Schedules the next global step in an adaptive way. The more resources are
- * left, the earlier the next step is scheduled. This serves the reactivity of
- * the solver to changed inputs.
- *
- * @param solver the solver handle
- */
-static void
-ril_step_schedule_next (struct GAS_RIL_Handle *solver)
-{
-  double used_ratio;
-  double factor;
-  double y;
-  double offset;
-  struct GNUNET_TIME_Relative time_next;
-
-  used_ratio = ril_get_used_resource_ratio (solver);
-
-  GNUNET_assert(
-      solver->parameters.step_time_min.rel_value_us
-          <= solver->parameters.step_time_max.rel_value_us);
-
-  factor = (double) GNUNET_TIME_relative_subtract 
(solver->parameters.step_time_max,
-      solver->parameters.step_time_min).rel_value_us;
-  offset = (double) solver->parameters.step_time_min.rel_value_us;
-  y = factor * pow (used_ratio, RIL_INTERVAL_EXPONENT) + offset;
-
-  GNUNET_assert(y <= (double ) solver->parameters.step_time_max.rel_value_us);
-  GNUNET_assert(y >= (double ) solver->parameters.step_time_min.rel_value_us);
-
-  time_next = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, 
(unsigned long long) y);
-
-  if (solver->simulate)
-  {
-    time_next = GNUNET_TIME_UNIT_ZERO;
-  }
-
-  if ((GNUNET_SCHEDULER_NO_TASK == solver->step_next_task_id) && (GNUNET_NO == 
solver->done))
-  {
-    solver->step_next_task_id = GNUNET_SCHEDULER_add_delayed (time_next, 
&ril_step_scheduler_task,
-          solver);
-  }
-}
-
-/**
- * Triggers one step per agent
- * @param solver
- */
-static void
-ril_step (struct GAS_RIL_Handle *solver)
-{
-  struct RIL_Peer_Agent *cur;
-
-  if (GNUNET_YES == solver->bulk_lock)
-  {
-    solver->bulk_changes++;
-    return;
-  }
-
-  ril_inform (solver, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS);
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "    RIL step number %d\n", solver->step_count);
-
-  if (0 == solver->step_count)
-  {
-    solver->step_time_last = GNUNET_TIME_absolute_get ();
-  }
-
-  ril_calculate_discount (solver);
-  ril_calculate_assigned_bwnet (solver);
-
-  //calculate network state vector
-//  envi_state_networks(solver);
-
-  //trigger one step per active, unblocked agent
-  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
-  {
-    if (cur->is_active)
-    {
-      if (NULL == cur->address_inuse)
-      {
-        ril_try_unblock_agent(solver, cur, GNUNET_NO);
-      }
-      if (cur->address_inuse)
-      {
-        agent_step (cur);
-      }
-    }
-  }
-
-  ril_calculate_assigned_bwnet (solver);
-
-  solver->step_count += 1;
-  ril_step_schedule_next (solver);
-
-  ril_inform (solver, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS);
-
-  ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START, 
GAS_STAT_SUCCESS);
-  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
-  {
-    if (cur->suggestion_issue) {
-      
solver->plugin_envi->bandwidth_changed_cb(solver->plugin_envi->bw_changed_cb_cls,
 cur->suggestion_address);
-      cur->suggestion_issue = GNUNET_NO;
-    }
-  }
-  ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP, GAS_STAT_SUCCESS);
-}
-
-static int
-ril_count_agents (struct GAS_RIL_Handle *solver)
-{
-  int c = 0;
-  struct RIL_Peer_Agent *cur_agent;
-
-  for (cur_agent = solver->agents_head; NULL != cur_agent; cur_agent = 
cur_agent->next)
-  {
-    c++;
-  }
-  return c;
-}
-
-static void
-agent_w_start (struct RIL_Peer_Agent *agent)
-{
-  int count;
-  struct RIL_Peer_Agent *other;
-  int i;
-  int k;
-
-  count = ril_count_agents(agent->envi);
-
-  for (i = 0; i < agent->n; i++)
-  {
-    for (k = 0; k < agent->m; k++)
-    {
-      if (0 == count) {
-        agent->W[i][k] = 1;//.1 - ((double) 
GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 
UINT32_MAX/5)/(double)UINT32_MAX);
-      }
-      else {
-        for (other = agent->envi->agents_head; NULL != other; other = 
other->next)
-        {
-          agent->W[i][k] += (other->W[i][k] / (double) count);
-        }
-      }
-
-      GNUNET_assert(!isinf(agent->W[i][k]));
-    }
-  }
-}
-
-/**
- * Initialize an agent without addresses and its knowledge base
- *
- * @param s ril solver
- * @param peer the one in question
- * @return handle to the new agent
- */
-static struct RIL_Peer_Agent *
-agent_init (void *s, const struct GNUNET_PeerIdentity *peer)
-{
-  int i;
-  struct GAS_RIL_Handle * solver = s;
-  struct RIL_Peer_Agent * agent = GNUNET_malloc (sizeof (struct 
RIL_Peer_Agent));
-
-  agent->envi = solver;
-  agent->peer = *peer;
-  agent->step_count = 0;
-  agent->is_active = GNUNET_NO;
-  agent->bw_in = MIN_BW;
-  agent->bw_out = MIN_BW;
-  agent->suggestion_issue = GNUNET_NO;
-  agent->n = RIL_ACTION_TYPE_NUM;
-  agent->m = (RIL_FEATURES_NETWORK_COUNT);// + GNUNET_ATS_PreferenceCount;
-  agent->W = (double **) GNUNET_malloc (sizeof (double *) * agent->n);
-  for (i = 0; i < agent->n; i++)
-  {
-    agent->W[i] = (double *) GNUNET_malloc (sizeof (double) * agent->m);
-  }
-  agent_w_start(agent);
-  agent->a_old = RIL_ACTION_INVALID;
-  agent->s_old = GNUNET_malloc (sizeof (double) * agent->m);
-  agent->e = (double *) GNUNET_malloc (sizeof (double) * agent->m);
-  agent_modify_eligibility (agent, RIL_E_ZERO, NULL);
-
-  return agent;
-}
-
-/**
- * Deallocate agent
- *
- * @param solver the solver handle
- * @param agent the agent to retire
- */
-static void
-agent_die (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
-{
-  int i;
-
-  for (i = 0; i < agent->n; i++)
-  {
-    GNUNET_free(agent->W[i]);
-  }
-  GNUNET_free(agent->W);
-  GNUNET_free(agent->e);
-  GNUNET_free(agent->s_old);
-  GNUNET_free(agent);
-}
-
-/**
- * Returns the agent for a peer
- *
- * @param solver the solver handle
- * @param peer the identity of the peer
- * @param create whether or not to create an agent, if none is allocated yet
- * @return the agent
- */
-static struct RIL_Peer_Agent *
-ril_get_agent (struct GAS_RIL_Handle *solver, const struct GNUNET_PeerIdentity 
*peer, int create)
-{
-  struct RIL_Peer_Agent *cur;
-
-  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
-  {
-    if (0 == memcmp (peer, &cur->peer, sizeof(struct GNUNET_PeerIdentity)))
-    {
-      return cur;
-    }
-  }
-
-  if (create)
-  {
-    cur = agent_init (solver, peer);
-    GNUNET_CONTAINER_DLL_insert_tail(solver->agents_head, solver->agents_tail, 
cur);
-    return cur;
-  }
-  return NULL ;
-}
-
-/**
- * Determine whether at least the minimum bandwidth is set for the network. 
Otherwise the network is
- * considered inactive and not used. Addresses in an inactive network are 
ignored.
- *
- * @param solver solver handle
- * @param network the network type
- * @return whether or not the network is considered active
- */
-static int
-ril_network_is_active (struct GAS_RIL_Handle *solver, enum 
GNUNET_ATS_Network_Type network)
-{
-  struct RIL_Network *net;
-
-  net = ril_get_network (solver, network);
-  return net->bw_out_available >= MIN_BW;
-}
-
-/**
- * Cuts a slice out of a vector of elements. This is used to decrease the size 
of the matrix storing
- * the reward function approximation. It copies the memory, which is not cut, 
to the new vector,
- * frees the memory of the old vector, and redirects the pointer to the new 
one.
- *
- * @param old pointer to the pointer to the first element of the vector
- * @param element_size byte size of the vector elements
- * @param hole_start the first element to cut out
- * @param hole_length the number of elements to cut out
- * @param old_length the length of the old vector
- */
-static void
-ril_cut_from_vector (void **old,
-    size_t element_size,
-    unsigned int hole_start,
-    unsigned int hole_length,
-    unsigned int old_length)
-{
-  char *tmpptr;
-  char *oldptr = (char *) *old;
-  size_t size;
-  unsigned int bytes_before;
-  unsigned int bytes_hole;
-  unsigned int bytes_after;
-
-  GNUNET_assert(old_length > hole_length);
-  GNUNET_assert(old_length >= (hole_start + hole_length));
-
-  size = element_size * (old_length - hole_length);
-
-  bytes_before = element_size * hole_start;
-  bytes_hole = element_size * hole_length;
-  bytes_after = element_size * (old_length - hole_start - hole_length);
-
-  if (0 == size)
-  {
-    tmpptr = NULL;
-  }
-  else
-  {
-    tmpptr = GNUNET_malloc (size);
-    memcpy (tmpptr, oldptr, bytes_before);
-    memcpy (tmpptr + bytes_before, oldptr + (bytes_before + bytes_hole), 
bytes_after);
-  }
-  if (NULL != *old)
-  {
-    GNUNET_free(*old);
-  }
-  *old = (void *) tmpptr;
-}
-
-/*
- *  Solver API functions
- *  ---------------------------
- */
-
-/**
- * Change relative preference for quality in solver
- *
- * @param solver the solver handle
- * @param peer the peer to change the preference for
- * @param kind the kind to change the preference
- * @param pref_rel the normalized preference value for this kind over all 
clients
- */
-void
-GAS_ril_address_change_preference (void *solver,
-    const struct GNUNET_PeerIdentity *peer,
-    enum GNUNET_ATS_PreferenceKind kind,
-    double pref_rel)
-{
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "API_address_change_preference() Preference '%s' for peer '%s' changed 
to %.2f \n",
-      GNUNET_ATS_print_preference_type (kind), GNUNET_i2s (peer), pref_rel);
-
-  ril_step (solver);
-}
-
-/**
- * Entry point for the plugin
- *
- * @param cls pointer to the 'struct GNUNET_ATS_PluginEnvironment'
- */
-void *
-libgnunet_plugin_ats_ril_init (void *cls)
-{
-  struct GNUNET_ATS_PluginEnvironment *env = cls;
-  struct GAS_RIL_Handle *solver = GNUNET_new (struct GAS_RIL_Handle);
-  struct RIL_Network * cur;
-  int c;
-  char *string;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_init() Initializing RIL solver\n");
-
-  GNUNET_assert(NULL != env);
-  GNUNET_assert(NULL != env->cfg);
-  GNUNET_assert(NULL != env->stats);
-  GNUNET_assert(NULL != env->bandwidth_changed_cb);
-  GNUNET_assert(NULL != env->get_preferences);
-  GNUNET_assert(NULL != env->get_property);
-
-  if (GNUNET_OK
-      != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", 
"RIL_STEP_TIME_MIN",
-          &solver->parameters.step_time_min))
-  {
-    solver->parameters.step_time_min = RIL_DEFAULT_STEP_TIME_MIN;
-  }
-  if (GNUNET_OK
-      != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", 
"RIL_STEP_TIME_MAX",
-          &solver->parameters.step_time_max))
-  {
-    solver->parameters.step_time_max = RIL_DEFAULT_STEP_TIME_MAX;
-  }
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_ALGORITHM", &string))
-  {
-    solver->parameters.algorithm = !strcmp (string, "SARSA") ? RIL_ALGO_SARSA 
: RIL_ALGO_Q;
-    GNUNET_free (string);
-  }
-  else
-  {
-    solver->parameters.algorithm = RIL_DEFAULT_ALGORITHM;
-  }
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_DISCOUNT_BETA", &string))
-  {
-    solver->parameters.beta = strtod (string, NULL);
-    GNUNET_free (string);
-  }
-  else
-  {
-    solver->parameters.beta = RIL_DEFAULT_DISCOUNT_BETA;
-  }
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_DISCOUNT_GAMMA", &string))
-  {
-    solver->parameters.gamma = strtod (string, NULL);
-    GNUNET_free (string);
-  }
-  else
-  {
-    solver->parameters.gamma = RIL_DEFAULT_DISCOUNT_GAMMA;
-  }
-  if (GNUNET_OK
-      == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_GRADIENT_STEP_SIZE", &string))
-  {
-    solver->parameters.alpha = strtod (string, NULL);
-    GNUNET_free (string);
-  }
-  else
-  {
-    solver->parameters.alpha = RIL_DEFAULT_GRADIENT_STEP_SIZE;
-  }
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_TRACE_DECAY", &string))
-  {
-    solver->parameters.lambda = strtod (string, NULL);
-    GNUNET_free (string);
-  }
-  else
-  {
-    solver->parameters.lambda = RIL_DEFAULT_TRACE_DECAY;
-  }
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_EXPLORE_RATIO", &string))
-  {
-    solver->parameters.explore_ratio = strtod (string, NULL);
-    GNUNET_free (string);
-  }
-  else
-  {
-    solver->parameters.explore_ratio = RIL_DEFAULT_EXPLORE_RATIO;
-  }
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_GLOBAL_REWARD_SHARE", &string))
-  {
-    solver->parameters.reward_global_share = strtod (string, NULL);
-    GNUNET_free (string);
-  }
-  else
-  {
-    solver->parameters.reward_global_share = RIL_DEFAULT_GLOBAL_REWARD_SHARE;
-  }
-  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "ats", 
"RIL_SIMULATE", &solver->simulate))
-  {
-    solver->simulate = GNUNET_NO;
-  }
-
-  env->sf.s_add = &GAS_ril_address_add;
-  env->sf.s_address_update_property = &GAS_ril_address_property_changed;
-  env->sf.s_address_update_session = &GAS_ril_address_session_changed;
-  env->sf.s_address_update_inuse = &GAS_ril_address_inuse_changed;
-  env->sf.s_address_update_network = &GAS_ril_address_change_network;
-  env->sf.s_get = &GAS_ril_get_preferred_address;
-  env->sf.s_get_stop = &GAS_ril_stop_get_preferred_address;
-  env->sf.s_pref = &GAS_ril_address_change_preference;
-  env->sf.s_feedback = &GAS_ril_address_preference_feedback;
-  env->sf.s_del = &GAS_ril_address_delete;
-  env->sf.s_bulk_start = &GAS_ril_bulk_start;
-  env->sf.s_bulk_stop = &GAS_ril_bulk_stop;
-
-  solver->plugin_envi = env;
-  solver->networks_count = env->network_count;
-  solver->network_entries = GNUNET_malloc (env->network_count * sizeof (struct 
RIL_Network));
-  solver->step_count = 0;
-  solver->global_state_networks = GNUNET_malloc (solver->networks_count * 
RIL_FEATURES_NETWORK_COUNT * sizeof (double));
-  solver->done = GNUNET_NO;
-
-  for (c = 0; c < env->network_count; c++)
-  {
-    cur = &solver->network_entries[c];
-    cur->type = env->networks[c];
-    cur->bw_in_available = env->in_quota[c];
-    cur->bw_out_available = env->out_quota[c];
-    LOG(GNUNET_ERROR_TYPE_INFO, "init()  Quotas for %s network:  IN %llu - OUT 
%llu\n", GNUNET_ATS_print_network_type(cur->type), cur->bw_in_available/1024, 
cur->bw_out_available/1024);
-  }
-
-  LOG(GNUNET_ERROR_TYPE_INFO, "init()  Parameters:\n");
-  LOG(GNUNET_ERROR_TYPE_INFO, "init()  Algorithm = %s, alpha = %f, beta = %f, 
lambda = %f\n",
-      solver->parameters.algorithm ? "Q" : "SARSA",
-      solver->parameters.alpha,
-      solver->parameters.beta,
-      solver->parameters.lambda);
-  LOG(GNUNET_ERROR_TYPE_INFO, "init()  explore = %f, global_share = %f\n",
-      solver->parameters.explore_ratio,
-      solver->parameters.reward_global_share);
-
-  return solver;
-}
-
-/**
- * Exit point for the plugin
- *
- * @param cls the solver handle
- */
-void *
-libgnunet_plugin_ats_ril_done (void *cls)
-{
-  struct GAS_RIL_Handle *s = cls;
-  struct RIL_Peer_Agent *cur_agent;
-  struct RIL_Peer_Agent *next_agent;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_done() Shutting down RIL solver\n");
-
-  s->done = GNUNET_YES;
-
-  cur_agent = s->agents_head;
-  while (NULL != cur_agent)
-  {
-    next_agent = cur_agent->next;
-    GNUNET_CONTAINER_DLL_remove(s->agents_head, s->agents_tail, cur_agent);
-    agent_die (s, cur_agent);
-    cur_agent = next_agent;
-  }
-
-  if (GNUNET_SCHEDULER_NO_TASK != s->step_next_task_id)
-  {
-    GNUNET_SCHEDULER_cancel (s->step_next_task_id);
-  }
-  GNUNET_free(s->network_entries);
-  GNUNET_free(s->global_state_networks);
-  GNUNET_free(s);
-
-  return NULL;
-}
-
-/**
- * Add a new address for a peer to the solver
- *
- * The address is already contained in the addresses hashmap!
- *
- * @param solver the solver Handle
- * @param address the address to add
- * @param network network type of this address
- */
-void
-GAS_ril_address_add (void *solver, struct ATS_Address *address, uint32_t 
network)
-{
-  struct GAS_RIL_Handle *s = solver;
-  struct RIL_Peer_Agent *agent;
-  struct RIL_Address_Wrapped *address_wrapped;
-  struct RIL_Network *net;
-  unsigned int m_new;
-  unsigned int m_old;
-  unsigned int n_new;
-  unsigned int n_old;
-  int i;
-  unsigned int zero;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "API_address_add()\n");
-
-  net = ril_get_network (s, network);
-  address->solver_information = net;
-
-  if (!ril_network_is_active (s, network))
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "API_address_add() Did not add %s address %s for peer '%s', network 
does not have enough bandwidth\n",
-        address->plugin, address->addr, GNUNET_i2s (&address->peer));
-    return;
-  }
-
-  agent = ril_get_agent (s, &address->peer, GNUNET_YES);
-
-  //add address
-  address_wrapped = GNUNET_malloc (sizeof (struct RIL_Address_Wrapped));
-  address_wrapped->address_naked = address;
-  GNUNET_CONTAINER_DLL_insert_tail(agent->addresses_head, 
agent->addresses_tail, address_wrapped);
-
-  //increase size of W
-  m_new = agent->m + RIL_FEATURES_ADDRESS_COUNT;
-  m_old = agent->m;
-  n_new = agent->n + 1;
-  n_old = agent->n;
-
-  GNUNET_array_grow(agent->W, agent->n, n_new);
-  for (i = 0; i < n_new; i++)
-  {
-    if (i < n_old)
-    {
-      agent->m = m_old;
-      GNUNET_array_grow(agent->W[i], agent->m, m_new);
-    }
-    else
-    {
-      zero = 0;
-      GNUNET_array_grow(agent->W[i], zero, m_new);
-    }
-  }
-
-  //increase size of old state vector
-  agent->m = m_old;
-  GNUNET_array_grow(agent->s_old, agent->m, m_new);
-
-  agent->m = m_old;
-  GNUNET_array_grow(agent->e, agent->m, m_new);
-
-  ril_try_unblock_agent(s, agent, GNUNET_NO);
-
-  ril_step (s);
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_add() Added %s %s address %s for 
peer '%s'\n",
-      address->active ? "active" : "inactive", address->plugin, address->addr,
-      GNUNET_i2s (&address->peer));
-}
-
-/**
- * Delete an address in the solver
- *
- * The address is not contained in the address hashmap anymore!
- *
- * @param solver the solver handle
- * @param address the address to remove
- * @param session_only delete only session not whole address
- */
-void
-GAS_ril_address_delete (void *solver, struct ATS_Address *address, int 
session_only)
-{
-  struct GAS_RIL_Handle *s = solver;
-  struct RIL_Peer_Agent *agent;
-  struct RIL_Address_Wrapped *address_wrapped;
-  int address_was_used = address->active;
-  int address_index;
-  unsigned int m_new;
-  unsigned int n_new;
-  int i;
-  struct RIL_Network *net;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_delete() Delete %s%s %s address %s 
for peer '%s'\n",
-      session_only ? "session for " : "", address->active ? "active" : 
"inactive", address->plugin,
-      address->addr, GNUNET_i2s (&address->peer));
-
-  agent = ril_get_agent (s, &address->peer, GNUNET_NO);
-  if (NULL == agent)
-  {
-    net = address->solver_information;
-    GNUNET_assert(!ril_network_is_active (s, net->type));
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "No agent allocated for peer yet, since address was in inactive 
network\n");
-    return;
-  }
-
-  address_index = agent_address_get_index (agent, address);
-  address_wrapped = agent_address_get (agent, address);
-
-  if (NULL == address_wrapped)
-  {
-    net = address->solver_information;
-    GNUNET_assert(!ril_network_is_active (s, net->type));
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Address not considered by agent, address was in inactive network\n");
-    return;
-  }
-
-  GNUNET_CONTAINER_DLL_remove(agent->addresses_head, agent->addresses_tail, 
address_wrapped);
-  GNUNET_free(address_wrapped);
-
-  //decrease W
-  m_new = agent->m - RIL_FEATURES_ADDRESS_COUNT;
-  n_new = agent->n - 1;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "first\n");
-
-  for (i = 0; i < agent->n; i++)
-  {
-    ril_cut_from_vector ((void **) &agent->W[i], sizeof(double),
-        //((s->networks_count * RIL_FEATURES_NETWORK_COUNT)
-        ((RIL_FEATURES_NETWORK_COUNT) //TODO! replace, when adding more 
networks
-            + (address_index * RIL_FEATURES_ADDRESS_COUNT)), 
RIL_FEATURES_ADDRESS_COUNT, agent->m);
-  }
-  GNUNET_free(agent->W[RIL_ACTION_TYPE_NUM + address_index]);
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "second\n");
-  ril_cut_from_vector ((void **) &agent->W, sizeof(double *), 
RIL_ACTION_TYPE_NUM + address_index,
-      1, agent->n);
-  //correct last action
-  if (agent->a_old > (RIL_ACTION_TYPE_NUM + address_index))
-  {
-    agent->a_old -= 1;
-  }
-  else if (agent->a_old == (RIL_ACTION_TYPE_NUM + address_index))
-  {
-    agent->a_old = RIL_ACTION_INVALID;
-  }
-  //decrease old state vector and eligibility vector
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "third\n");
-  ril_cut_from_vector ((void **) &agent->s_old, sizeof(double),
-      //((s->networks_count * RIL_FEATURES_NETWORK_COUNT)
-      ((RIL_FEATURES_NETWORK_COUNT) //TODO! replace when adding more networks
-          + (address_index * RIL_FEATURES_ADDRESS_COUNT)), 
RIL_FEATURES_ADDRESS_COUNT, agent->m);
-  ril_cut_from_vector ((void **) &agent->e, sizeof(double),
-      //((s->networks_count * RIL_FEATURES_NETWORK_COUNT)
-      ((RIL_FEATURES_NETWORK_COUNT) //TODO! replace when adding more networks
-          + (address_index * RIL_FEATURES_ADDRESS_COUNT)), 
RIL_FEATURES_ADDRESS_COUNT, agent->m);
-  agent->m = m_new;
-  agent->n = n_new;
-
-  if (address_was_used)
-  {
-    if (NULL != agent->addresses_head) //if peer has an address left, use it
-    {
-      envi_set_active_suggestion (s, agent, 
agent->addresses_head->address_naked, MIN_BW, MIN_BW,
-          GNUNET_NO);
-    }
-    else
-    {
-      envi_set_active_suggestion (s, agent, NULL, 0, 0, GNUNET_NO);
-    }
-  }
-
-  ril_step (solver);
-}
-
-/**
- * Update the properties of an address in the solver
- *
- * @param solver solver handle
- * @param address the address
- * @param type the ATSI type in HBO
- * @param abs_value the absolute value of the property
- * @param rel_value the normalized value
- */
-void
-GAS_ril_address_property_changed (void *solver,
-    struct ATS_Address *address,
-    uint32_t type,
-    uint32_t abs_value,
-    double rel_value)
-{
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "API_address_property_changed() Property '%s' for peer '%s' address %s 
changed "
-          "to %.2f \n", GNUNET_ATS_print_property_type (type), GNUNET_i2s 
(&address->peer),
-      address->addr, rel_value);
-
-  ril_step (solver);
-}
-
-/**
- * Update the session of an address in the solver
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param cur_session the current session
- * @param new_session the new session
- */
-void
-GAS_ril_address_session_changed (void *solver,
-    struct ATS_Address *address,
-    uint32_t cur_session,
-    uint32_t new_session)
-{
-  /*
-   * TODO? Future Work: Potentially add session activity as a feature in state 
vector
-   */
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_session_changed()\n");
-}
-
-/**
- * Notify the solver that an address is (not) actively used by transport
- * to communicate with a remote peer
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param in_use usage state
- */
-void
-GAS_ril_address_inuse_changed (void *solver, struct ATS_Address *address, int 
in_use)
-{
-  /*
-   * TODO? Future Work: Potentially add usage variable to state vector
-   */
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "API_address_inuse_changed() Usage for %s address of peer '%s' changed 
to %s\n",
-      address->plugin, GNUNET_i2s (&address->peer), (GNUNET_YES == in_use) ? 
"USED" : "UNUSED");
-}
-
-/**
- * Notify solver that the network an address is located in has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param current_network the current network
- * @param new_network the new network
- */
-void
-GAS_ril_address_change_network (void *solver,
-    struct ATS_Address *address,
-    uint32_t current_network,
-    uint32_t new_network)
-{
-  struct GAS_RIL_Handle *s = solver;
-  struct RIL_Peer_Agent *agent;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_change_network() Network type 
changed, moving "
-      "%s address of peer %s from '%s' to '%s'\n",
-      (GNUNET_YES == address->active) ? "active" : "inactive", GNUNET_i2s 
(&address->peer),
-      GNUNET_ATS_print_network_type (current_network), 
GNUNET_ATS_print_network_type (new_network));
-
-  if (address->active && !ril_network_is_active (solver, new_network))
-  {
-    GAS_ril_address_delete (solver, address, GNUNET_NO);
-    return;
-  }
-
-  agent = ril_get_agent (s, &address->peer, GNUNET_NO);
-  if (NULL == agent)
-  {
-    GNUNET_assert(!ril_network_is_active (solver, current_network));
-
-    GAS_ril_address_add (s, address, new_network);
-    return;
-  }
-
-  address->solver_information = ril_get_network(solver, new_network);
-}
-
-/**
- * Give feedback about the current assignment
- *
- * @param solver the solver handle
- * @param application the application
- * @param peer the peer to change the preference for
- * @param scope the time interval for this feedback: [now - scope .. now]
- * @param kind the kind to change the preference
- * @param score the score
- */
-void
-GAS_ril_address_preference_feedback (void *solver,
-    void *application,
-    const struct GNUNET_PeerIdentity *peer,
-    const struct GNUNET_TIME_Relative scope,
-    enum GNUNET_ATS_PreferenceKind kind,
-    double score)
-{
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "API_address_preference_feedback() Peer '%s' got a feedback of %+.3f 
from application %s for "
-          "preference %s for %d seconds\n", GNUNET_i2s (peer), "UNKNOWN",
-      GNUNET_ATS_print_preference_type (kind), scope.rel_value_us / 1000000);
-}
-
-/**
- * Start a bulk operation
- *
- * @param solver the solver
- */
-void
-GAS_ril_bulk_start (void *solver)
-{
-  struct GAS_RIL_Handle *s = solver;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_bulk_start() lock: %d\n", s->bulk_lock+1);
-
-  s->bulk_lock++;
-}
-
-/**
- * Bulk operation done
- *
- * @param solver the solver handle
- */
-void
-GAS_ril_bulk_stop (void *solver)
-{
-  struct GAS_RIL_Handle *s = solver;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_bulk_stop() lock: %d\n", s->bulk_lock-1);
-
-  if (s->bulk_lock < 1)
-  {
-    GNUNET_break(0);
-    return;
-  }
-  s->bulk_lock--;
-
-  if (0 < s->bulk_changes)
-  {
-    ril_step (solver);
-    s->bulk_changes = 0;
-  }
-}
-
-/**
- * Tell solver to notify ATS if the address to use changes for a specific
- * peer using the bandwidth changed callback
- *
- * The solver must only notify about changes for peers with pending address
- * requests!
- *
- * @param solver the solver handle
- * @param peer the identity of the peer
- */
-const struct ATS_Address *
-GAS_ril_get_preferred_address (void *solver, const struct GNUNET_PeerIdentity 
*peer)
-{
-  /*
-   * activate agent, return currently chosen address
-   */
-  struct GAS_RIL_Handle *s = solver;
-  struct RIL_Peer_Agent *agent;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_get_preferred_address()\n");
-
-  agent = ril_get_agent (s, peer, GNUNET_YES);
-
-  agent->is_active = GNUNET_YES;
-  envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in, agent->bw_out, GNUNET_YES);
-
-  ril_try_unblock_agent(solver, agent, GNUNET_YES);
-
-  if (agent->address_inuse)
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "API_get_preferred_address() Activated agent for peer '%s' with %s 
address %s\n",
-        GNUNET_i2s (peer), agent->address_inuse->plugin, 
agent->address_inuse->addr);
-  }
-  else
-  {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "API_get_preferred_address() Activated agent for peer '%s', but no 
address available\n",
-        GNUNET_i2s (peer));
-  }
-
-  return agent->address_inuse;
-}
-
-/**
- * Tell solver stop notifying ATS about changes for this peers
- *
- * The solver must only notify about changes for peers with pending address
- * requests!
- *
- * @param solver the solver handle
- * @param peer the peer
- */
-void
-GAS_ril_stop_get_preferred_address (void *solver, const struct 
GNUNET_PeerIdentity *peer)
-{
-  struct GAS_RIL_Handle *s = solver;
-  struct RIL_Peer_Agent *agent;
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_stop_get_preferred_address()");
-
-  agent = ril_get_agent (s, peer, GNUNET_NO);
-
-  if (NULL == agent)
-  {
-    GNUNET_break(0);
-    return;
-  }
-  if (GNUNET_NO == agent->is_active)
-  {
-    GNUNET_break(0);
-    return;
-  }
-
-  agent->is_active = GNUNET_NO;
-
-  envi_set_active_suggestion (s, agent, agent->address_inuse, agent->bw_in, 
agent->bw_out,
-      GNUNET_YES);
-
-  ril_step (s);
-
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "API_stop_get_preferred_address() Paused agent for peer '%s' with %s 
address\n",
-      GNUNET_i2s (peer), agent->address_inuse->plugin);
-}
-
-/* end of libgnunet_plugin_ats_ril.c */

Deleted: gnunet/src/ats/libgnunet_plugin_ats_ril.h
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_ril.h   2013-12-09 23:22:55 UTC (rev 
31243)
+++ gnunet/src/ats/libgnunet_plugin_ats_ril.h   2013-12-10 07:58:08 UTC (rev 
31244)
@@ -1,191 +0,0 @@
-/*
- 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/libgnunet_plugin_ats_ril.h
- * @brief ATS reinforcement learning solver
- * @author Fabian Oehlmann
- * @author Matthias Wachs
- */
-#include "platform.h"
-#include <float.h>
-#include <math.h>
-#include "gnunet_ats_plugin.h"
-#include "gnunet-service-ats_addresses.h"
-
-/**
- * ATS reinforcement learning solver
- *
- * General description
- */
-
-/**
- * Changes the preferences for a peer in the problem
- *
- * @param solver the solver handle
- * @param peer the peer to change the preference for
- * @param kind the kind to change the preference
- * @param pref_rel the normalized preference value for this kind over all 
clients
- */
-void
-GAS_ril_address_change_preference (void *solver,
-    const struct GNUNET_PeerIdentity *peer,
-    enum GNUNET_ATS_PreferenceKind kind,
-    double pref_rel);
-
-/**
- * Add a single address within a network to the solver
- *
- * @param solver the solver Handle
- * @param address the address to add
- * @param network network type of this address
- */
-void
-GAS_ril_address_add (void *solver,
-    struct ATS_Address *address,
-    uint32_t network);
-
-/**
- * Transport properties for this address have changed
- *
- * @param solver solver handle
- * @param address the address
- * @param type the ATSI type in HBO
- * @param abs_value the absolute value of the property
- * @param rel_value the normalized value
- */
-void
-GAS_ril_address_property_changed (void *solver,
-    struct ATS_Address *address,
-    uint32_t type,
-    uint32_t abs_value,
-    double rel_value);
-
-/**
- * Transport session for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param cur_session the current session
- * @param new_session the new session
- */
-void
-GAS_ril_address_session_changed (void *solver,
-    struct ATS_Address *address,
-    uint32_t cur_session,
-    uint32_t new_session);
-
-/**
- * Usage for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param in_use usage state
- */
-void
-GAS_ril_address_inuse_changed (void *solver,
-    struct ATS_Address *address,
-    int in_use);
-
-/**
- * Network scope for this address has changed
- *
- * NOTE: values in addresses are already updated
- *
- * @param solver solver handle
- * @param address the address
- * @param current_network the current network
- * @param new_network the new network
- */
-void
-GAS_ril_address_change_network (void *solver,
-    struct ATS_Address *address,
-    uint32_t current_network,
-    uint32_t new_network);
-
-/**
- * Remove an address from the solver
- *
- * @param solver the solver handle
- * @param address the address to remove
- * @param session_only delete only session not whole address
- */
-void
-GAS_ril_address_delete (void *solver,
-    struct ATS_Address *address,
-    int session_only);
-
-/**
- * Get application feedback for a peer
- *
- * @param solver the solver handle
- * @param application the application
- * @param peer the peer to change the preference for
- * @param scope the time interval for this feedback: [now - scope .. now]
- * @param kind the kind to change the preference
- * @param score the score
- */
-void
-GAS_ril_address_preference_feedback (void *solver,
-    void *application,
-    const struct GNUNET_PeerIdentity *peer,
-    const struct GNUNET_TIME_Relative scope,
-    enum GNUNET_ATS_PreferenceKind kind,
-    double score);
-
-/**
- * Start a bulk operation
- *
- * @param solver the solver
- */
-void
-GAS_ril_bulk_start (void *solver);
-
-/**
- * Bulk operation done
- */
-void
-GAS_ril_bulk_stop (void *solver);
-
-/**
- * Stop notifying about address and bandwidth changes for this peer
- *
- * @param solver the solver handle
- * @param peer the peer
- */
-void
-GAS_ril_stop_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Get the prefered address for a specific peer
- *
- * @param solver the solver handle
- * @param peer the identity of the peer
- */
-const struct ATS_Address *
-GAS_ril_get_preferred_address (void *solver,
-    const struct GNUNET_PeerIdentity *peer);
-
-/* end of libgnunet_plugin_ats_ril.h */

Copied: gnunet/src/ats/plugin_ats_mlp.c (from rev 31213, 
gnunet/src/ats/libgnunet_plugin_ats_mlp.c)
===================================================================
--- gnunet/src/ats/plugin_ats_mlp.c                             (rev 0)
+++ gnunet/src/ats/plugin_ats_mlp.c     2013-12-10 07:58:08 UTC (rev 31244)
@@ -0,0 +1,2167 @@
+/*
+     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/plugin_ats_mlp.c
+ * @brief ats mlp problem solver
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+
+#include "plugin_ats_mlp.h"
+
+
+/**
+ *
+ * NOTE: Do not modify this documentation. This documentation is based on
+ * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
+ * use build_txt.sh to generate plaintext output
+ *
+ *    The MLP solver (mlp) tries to finds an optimal bandwidth assignmentby
+ *    optimizing an mixed integer programming problem. The MLP solver uses a
+ *    number of constraints to find the best adddress for a peer and an optimal
+ *    bandwidth assignment. mlp uses the GNU Linear Programming Kit to solve 
the
+ *    MLP problem.
+ *
+ *    We defined a constraint system to find an optimal bandwidth assignment.
+ *    This constraint system uses as an input data addresses, bandwidth quotas,
+ *    preferences and quality values. This constraint system is stored in an
+ *    matrix based equotation system.
+ *
+ *   5 Using GLPK
+ *
+ *    A (M)LP problem consists of a target function to optimizes, constraints
+ *    and rows and columns. FIXME GLP uses three arrays to index the matrix: 
two
+ *    integer arrays storing the row and column indices in the matrix and an
+ *    float array to store the coeeficient.
+ *
+ *    To solve the problem we first find an initial solution for the LP problem
+ *    using the LP solver and then find an MLP solution based on this solution
+ *    using the MLP solver.
+ *
+ *    Solving (M)LP problems has the property that finding an initial solution
+ *    for the LP problem is computationally expensive and finding the MLP
+ *    solution is cheaper. This is especially interesting an existing LP
+ *    solution can be reused if only coefficients in the matrix have changed
+ *    (addresses updated). Only when the problem size changes (addresses added
+ *    or deleted) a new LP solution has to be found.
+ *
+ *    Intended usage
+ *    The mlp solver solves the bandwidth assignment problem only on demand 
when
+ *    an address suggestion is requested. When an address is requested mlp the
+ *    solves the mlp problem and if the active address or the bandwidth 
assigned
+ *    changes it calls the callback to addresses. The mlp solver gets notified
+ *    about new addresses (adding sessions), removed addresses (address
+ *    deletions) and address updates. To benefit from the mlp properties
+ *    mentioned in section 5 the solver rembers if since the last solution
+ *    addresses were added or deleted (problem size changed, problem has to be
+ *    rebuild and solved from sratch) or if addresses were updated and the
+ *    existing solution can be reused.
+ *
+ *     5.1 Input data
+ *
+ *    The quotas for each network segment are passed by addresses. MLP can be
+ *    adapted using configuration settings and uses the following parameters:
+ *      * MLP_MAX_DURATION:
+ *        Maximum duration for a MLP solution procees (default: 3 sec.)
+ *      * MLP_MAX_DURATION:
+ *        Maximum number of iterations for a MLP solution process (default:
+ *        1024)
+ *      * MLP_MIN_CONNECTIONS:
+ *        Minimum number of desired connections (default: 4)
+ *      * MLP_MIN_BANDWIDTH:
+ *        Minimum amount of bandwidth assigned to an address (default: 1024)
+ *      * MLP_COEFFICIENT_D:
+ *        Diversity coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_R:
+ *        Relativity coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_U:
+ *        Utilization coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_D:
+ *        Diversity coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_QUALITY_DELAY:
+ *        Quality delay coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
+ *        Quality distance coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
+ *        Quality distance coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
+ *        Quality distance coefficient (default: 1.0)
+ *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
+ *        Quality distance coefficient (default: 1.0)
+ *
+ *     5.2 Data structures used
+ *
+ *    mlp has for each known peer a struct ATS_Peer containing information 
about
+ *    a specific peer. The address field solver_information contains 
information
+ *    about the mlp properties of this address.
+ *
+ *     5.3 Initializing
+ *
+ *    During initialization mlp initializes the GLPK libray used to solve the
+ *    MLP problem: it initializes the glpk environment and creates an initial 
LP
+ *    problem. Next it loads the configuration values from the configuration or
+ *    uses the default values configured in -addresses_mlp.h. The quotas used
+ *    are given by addresses but may have to be adjusted. mlp uses a upper 
limit
+ *    for the bandwidth assigned called BIG M and a minimum amount of bandwidth
+ *    an address gets assigned as well as a minium desired number of
+ *    connections. If the configured quota is bigger than BIG M, it is reduced
+ *    to BIG M. If the configured quota is smaller than MLP_MIN_CONNECTIONS
+ *    *MLP_MIN_BANDWIDTH it is increased to this value.
+ *
+ *     5.4 Shutdown
+
+ */
+
+#define LOG(kind,...) GNUNET_log_from (kind, "ats-mlp",__VA_ARGS__)
+
+/**
+ * Print debug output for mlp problem creation
+ */
+#define DEBUG_MLP_PROBLEM_CREATION GNUNET_NO
+
+/**
+ * Enable GLPK verbose output
+ */
+#define VERBOSE_GLPK GNUNET_NO
+
+/**
+ * Maximize bandwidth assigned
+ *
+ * This option can be used to test if problem can be solved at all without
+ * optimizing for utility, diversity or relativity
+ *
+ */
+#define MAXIMIZE_FOR_BANDWIDTH_ASSIGNED GNUNET_NO
+
+/**
+ * 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; */
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "%s", s);
+  return 1;
+}
+
+
+/**
+ * Reset peers for next problem creation
+ *
+ * @param cls not used
+ * @param key the key
+ * @param value ATS_Peer
+ * @return GNUNET_OK
+ */
+static int
+reset_peers (void *cls,
+            const struct GNUNET_PeerIdentity *key,
+            void *value)
+ {
+   struct ATS_Peer *peer = value;
+   peer->processed = GNUNET_NO;
+   return GNUNET_OK;
+ }
+
+/**
+ * Delete the MLP problem and free the constrain matrix
+ *
+ * @param mlp the MLP handle
+ */
+static void
+mlp_delete_problem (struct GAS_MLP_Handle *mlp)
+{
+  int c;
+  if (mlp == NULL)
+    return;
+  if (mlp->p.prob != NULL)
+  {
+    glp_delete_prob(mlp->p.prob);
+    mlp->p.prob = NULL;
+  }
+
+  /* delete row index */
+  if (mlp->p.ia != NULL)
+  {
+    GNUNET_free (mlp->p.ia);
+    mlp->p.ia = NULL;
+  }
+
+  /* delete column index */
+  if (mlp->p.ja != NULL)
+  {
+    GNUNET_free (mlp->p.ja);
+    mlp->p.ja = NULL;
+  }
+
+  /* delete coefficients */
+  if (mlp->p.ar != NULL)
+  {
+    GNUNET_free (mlp->p.ar);
+    mlp->p.ar = NULL;
+  }
+  mlp->p.ci = 0;
+  mlp->p.prob = NULL;
+
+  mlp->p.c_d = MLP_UNDEFINED;
+  mlp->p.c_r = MLP_UNDEFINED;
+  mlp->p.r_c2 = MLP_UNDEFINED;
+  mlp->p.r_c4 = MLP_UNDEFINED;
+  mlp->p.r_c6 = MLP_UNDEFINED;
+  mlp->p.r_c9 = MLP_UNDEFINED;
+  for (c = 0; c < mlp->pv.m_q ; c ++)
+    mlp->p.r_q[c] = MLP_UNDEFINED;
+  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c ++)
+    mlp->p.r_quota[c] = MLP_UNDEFINED;
+  mlp->p.ci = MLP_UNDEFINED;
+
+
+  GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
+                                        &reset_peers, NULL);
+}
+
+
+/**
+ * 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";
+    case GNUNET_ATS_UTILIZATION_OUT:
+      return "GNUNET_ATS_UTILIZATION_OUT";
+    case GNUNET_ATS_UTILIZATION_IN:
+      return "GNUNET_ATS_UTILIZATION_IN";
+    case GNUNET_ATS_UTILIZATION_PAYLOAD_OUT:
+      return "GNUNET_ATS_UTILIZATION_PAYLOAD_OUT";
+    case GNUNET_ATS_UTILIZATION_PAYLOAD_IN:
+      return "GNUNET_ATS_UTILIZATION_PAYLOAD_IN";
+    case GNUNET_ATS_COST_LAN:
+      return "GNUNET_ATS_COST_LAN";
+    case GNUNET_ATS_COST_WAN:
+      return "GNUNET_ATS_COST_LAN";
+    case GNUNET_ATS_COST_WLAN:
+      return "GNUNET_ATS_COST_WLAN";
+    case GNUNET_ATS_NETWORK_TYPE:
+      return "GNUNET_ATS_NETWORK_TYPE";
+    case GNUNET_ATS_QUALITY_NET_DELAY:
+      return "GNUNET_ATS_QUALITY_NET_DELAY";
+    case GNUNET_ATS_QUALITY_NET_DISTANCE:
+      return "GNUNET_ATS_QUALITY_NET_DISTANCE";
+    default:
+      GNUNET_break (0);
+      return "unknown";
+  }
+}
+
+/**
+ * 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";
+    case GLP_FEAS:
+      return "solution is feasible";
+    case GLP_INFEAS:
+      return "solution is infeasible";
+    case GLP_NOFEAS:
+      return "no feasible solution exists";
+    case GLP_OPT:
+      return "solution is optimal";
+    case GLP_UNBND:
+      return "solution is unbounded";
+    default:
+      GNUNET_break (0);
+      return "unknown error";
+  }
+}
+
+/**
+ * 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";
+    case GLP_EBADB:
+      return "invalid basis";
+    case GLP_ESING:
+      return "singular matrix";
+    case GLP_ECOND:
+      return "ill-conditioned matrix";
+    case GLP_EBOUND:
+      return "invalid bounds";
+    case GLP_EFAIL:
+      return "solver failed";
+    case GLP_EOBJLL:
+      return "objective lower limit reached";
+    case GLP_EOBJUL:
+      return "objective upper limit reached";
+    case GLP_EITLIM:
+      return "iteration limit exceeded";
+    case GLP_ETMLIM:
+      return "time limit exceeded";
+    case GLP_ENOPFS:
+      return "no primal feasible solution";
+    case GLP_ENODFS:
+      return "no dual feasible solution";
+    case GLP_EROOT:
+      return "root LP optimum not provided";
+    case GLP_ESTOP:
+      return "search terminated by application";
+    case GLP_EMIPGAP:
+      return "relative mip gap tolerance reached";
+    case GLP_ENOFEAS:
+      return "no dual feasible solution";
+    case GLP_ENOCVG:
+      return "no convergence";
+    case GLP_EINSTAB:
+      return "numerical instability";
+    case GLP_EDATA:
+      return "invalid data";
+    case GLP_ERANGE:
+      return "result out of range";
+    default:
+      GNUNET_break (0);
+      return "unknown error";
+  }
+}
+
+/**
+ * Extract an ATS performance info from an address
+ *
+ * @param address the address
+ * @param type the type to extract in HBO
+ * @return the value in HBO or GNUNET_ATS_VALUE_UNDEFINED in HBO if value does 
not exist
+ */
+static int
+get_performance_info (struct ATS_Address *address, uint32_t type)
+{
+  int c1;
+  GNUNET_assert (NULL != address);
+
+  if ((NULL == address->atsi) || (0 == address->atsi_count))
+      return GNUNET_ATS_VALUE_UNDEFINED;
+
+  for (c1 = 0; c1 < address->atsi_count; c1++)
+  {
+      if (ntohl(address->atsi[c1].type) == type)
+        return ntohl(address->atsi[c1].value);
+  }
+  return GNUNET_ATS_VALUE_UNDEFINED;
+}
+
+
+struct CountContext
+{
+  const struct GNUNET_CONTAINER_MultiPeerMap *peers;
+  int result;
+};
+
+static int
+mlp_create_problem_count_addresses_it (void *cls,
+                                      const struct GNUNET_PeerIdentity *key,
+                                      void *value)
+{
+  struct CountContext *cctx = cls;
+
+  /* Check if we have to add this peer due to a pending request */
+  if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->peers, key))
+    cctx->result++;
+  return GNUNET_OK;
+}
+
+
+static int
+mlp_create_problem_count_addresses (const struct GNUNET_CONTAINER_MultiPeerMap 
*peers,
+                                   const struct GNUNET_CONTAINER_MultiPeerMap 
*addresses)
+{
+  struct CountContext cctx;
+
+  cctx.peers = peers;
+  cctx.result = 0;
+  GNUNET_CONTAINER_multipeermap_iterate (addresses,
+                                        
&mlp_create_problem_count_addresses_it, &cctx);
+  return cctx.result;
+}
+
+
+/**
+ * Updates an existing value in the matrix
+ *
+ * Extract the row, updates the value and updates the row in the problem
+ *
+ * @param p the mlp problem
+ * @param row the row to create the value in
+ * @param col the column to create the value in
+ * @param val the value to set
+ * @param line calling line for debbuging
+ * @return GNUNET_YES value changed, GNUNET_NO value did not change, 
GNUNET_SYSERR
+ * on error
+ */
+static int
+mlp_create_problem_update_value (struct MLP_Problem *p,
+                              int row, int col, double val,
+                              int line)
+{
+  int c_cols;
+  int c_elems;
+  int c1;
+  int res;
+  int found;
+  double *val_array;
+  int *ind_array;
+
+  GNUNET_assert (NULL != p);
+  GNUNET_assert (NULL != p->prob);
+
+  /* Get number of columns and prepare data structure */
+  c_cols = glp_get_num_cols(p->prob);
+  if (0 >= c_cols)
+    return GNUNET_SYSERR;
+
+  val_array = GNUNET_malloc ((c_cols +1)* sizeof (double));
+  GNUNET_assert (NULL != val_array);
+  ind_array = GNUNET_malloc ((c_cols+1) * sizeof (int));
+  GNUNET_assert (NULL != ind_array);
+  /* Extract the row */
+
+  /* Update the value */
+  c_elems = glp_get_mat_row (p->prob, row, ind_array, val_array);
+  found = GNUNET_NO;
+  for (c1 = 1; c1 < (c_elems+1); c1++)
+  {
+    if (ind_array[c1] == col)
+    {
+      found = GNUNET_YES;
+      break;
+    }
+  }
+  if (GNUNET_NO == found)
+  {
+    ind_array[c_elems+1] = col;
+    val_array[c_elems+1] = val;
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Setting value in [%s : %s] to `%.2f'\n",
+        glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
+        val);
+    glp_set_mat_row (p->prob, row, c_elems+1, ind_array, val_array);
+    GNUNET_free (ind_array);
+    GNUNET_free (val_array);
+    return GNUNET_YES;
+  }
+  else
+  {
+    /* Update value */
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Updating value in [%s : %s] from `%.2f' 
to `%.2f'\n",
+        glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
+        val_array[c1], val);
+    if (val != val_array[c1])
+      res = GNUNET_YES;
+    else
+      res = GNUNET_NO;
+    val_array[c1] = val;
+    /* Update the row in the matrix */
+    glp_set_mat_row (p->prob, row, c_elems, ind_array, val_array);
+  }
+
+  GNUNET_free (ind_array);
+  GNUNET_free (val_array);
+  return res;
+}
+
+/**
+ * Creates a new value in the matrix
+ *
+ * Sets the row and column index in the problem array and increments the
+ * position field
+ *
+ * @param p the mlp problem
+ * @param row the row to create the value in
+ * @param col the column to create the value in
+ * @param val the value to set
+ * @param line calling line for debbuging
+ */
+static void
+mlp_create_problem_set_value (struct MLP_Problem *p,
+                              int row, int col, double val,
+                              int line)
+{
+  if ((p->ci) >= p->num_elements)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Request for index %u bigger 
than array size of %u\n",
+        line, p->ci + 1, p->num_elements);
+    GNUNET_break (0);
+    return;
+  }
+  if ((0 == row) || (0 == col))
+    GNUNET_break (0);
+  p->ia[p->ci] = row ;
+  p->ja[p->ci] = col;
+  p->ar[p->ci] = val;
+#if  DEBUG_MLP_PROBLEM_CREATION
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Set value [%u,%u] in index %u 
==  %.2f\n",
+      line, p->ia[p->ci], p->ja[p->ci], p->ci, p->ar[p->ci]);
+#endif
+  p->ci++;
+}
+
+static int
+mlp_create_problem_create_column (struct MLP_Problem *p, char *name,
+    unsigned int type, unsigned int bound, double lb, double ub,
+    double coef)
+{
+  int col = glp_add_cols (p->prob, 1);
+  glp_set_col_name (p->prob, col, name);
+  glp_set_col_bnds (p->prob, col, bound, lb, ub);
+  glp_set_col_kind (p->prob, col, type);
+  glp_set_obj_coef (p->prob, col, coef);
+#if  DEBUG_MLP_PROBLEM_CREATION
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added column [%u] `%s': %.2f\n",
+      col, name, coef);
+#endif
+  return col;
+}
+
+static int
+mlp_create_problem_create_constraint (struct MLP_Problem *p, char *name,
+    unsigned int bound, double lb, double ub)
+{
+  char * op;
+  int row = glp_add_rows (p->prob, 1);
+  /* set row name */
+  glp_set_row_name (p->prob, row, name);
+  /* set row bounds: <= 0 */
+  glp_set_row_bnds (p->prob, row, bound, lb, ub);
+  switch (bound)
+  {
+    case GLP_UP:
+            GNUNET_asprintf(&op, "-inf <= x <= %.2f", ub);
+            break;
+    case GLP_DB:
+            GNUNET_asprintf(&op, "%.2f <= x <= %.2f", lb, ub);
+            break;
+    case GLP_FX:
+            GNUNET_asprintf(&op, "%.2f == x == %.2f", lb, ub);
+            break;
+    case GLP_LO:
+            GNUNET_asprintf(&op, "%.2f <= x <= inf", lb);
+            break;
+    default:
+            GNUNET_asprintf(&op, "ERROR");
+            break;
+  }
+#if  DEBUG_MLP_PROBLEM_CREATION
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added row [%u] `%s': %s\n",
+        row, name, op);
+#endif
+  GNUNET_free (op);
+  return row;
+}
+
+/**
+ * Create the
+ * - address columns b and n
+ * - address dependent constraint rows c1, c3
+ * - peer dependent rows c2 and c9
+ * - Set address dependent entries in problem matrix as well
+ */
+static int
+mlp_create_problem_add_address_information (void *cls,
+                                           const struct GNUNET_PeerIdentity 
*key,
+                                           void *value)
+{
+  struct GAS_MLP_Handle *mlp = cls;
+  struct MLP_Problem *p = &mlp->p;
+  struct ATS_Address *address = value;
+  struct ATS_Peer *peer;
+  struct MLP_information *mlpi;
+  char *name;
+  const double *props;
+  uint32_t addr_net;
+  int c;
+
+  /* Check if we have to add this peer due to a pending request */
+  if (GNUNET_NO == 
GNUNET_CONTAINER_multipeermap_contains(mlp->requested_peers, key))
+    return GNUNET_OK;
+
+  mlpi = address->solver_information;
+  if (NULL == mlpi)
+  {
+      fprintf (stderr, "%s %p\n",GNUNET_i2s (&address->peer), address);
+      GNUNET_break (0);
+      return GNUNET_OK;
+  }
+
+  /* Get peer */
+  peer = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, key);
+  if (peer->processed == GNUNET_NO)
+  {
+      /* Add peer dependent constraints */
+      /* Add constraint c2 */
+      GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&address->peer));
+      peer->r_c2 = mlp_create_problem_create_constraint (p, name, GLP_FX, 1.0, 
1.0);
+      GNUNET_free (name);
+      /* Add constraint c9 */
+      GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&address->peer));
+      peer->r_c9 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 
0.0);
+      GNUNET_free (name);
+      /* c 9) set coefficient */
+      mlp_create_problem_set_value (p, peer->r_c9, p->c_r, -peer->f, __LINE__);
+      peer->processed = GNUNET_YES;
+  }
+
+  /* Reset addresses' solver information */
+  mlpi->c_b = 0;
+  mlpi->c_n = 0;
+  mlpi->n = 0;
+  mlpi->r_c1 = 0;
+  mlpi->r_c3 = 0;
+
+  /* Add bandwidth column */
+  GNUNET_asprintf (&name, "b_%s_%s_%p", GNUNET_i2s (&address->peer), 
address->plugin, address);
+#if TEST_MAX_BW_ASSIGNMENT
+  mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 
0.0, 1.0);
+#else
+  mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 
0.0, 0.0);
+#endif
+
+  GNUNET_free (name);
+
+  /* Add usage column */
+  GNUNET_asprintf (&name, "n_%s_%s_%p", GNUNET_i2s (&address->peer), 
address->plugin, address);
+  mlpi->c_n = mlp_create_problem_create_column (p, name, GLP_IV, GLP_DB, 0.0, 
1.0, 0.0);
+  GNUNET_free (name);
+
+  /* Add address dependent constraints */
+  /* Add constraint c1) bandwidth capping
+   * b_t  + (-M) * n_t <= 0
+   * */
+  GNUNET_asprintf(&name, "c1_%s_%s_%p", GNUNET_i2s(&address->peer), 
address->plugin, address);
+  mlpi->r_c1 = mlp_create_problem_create_constraint (p, name, GLP_UP, 0.0, 
0.0);
+  GNUNET_free (name);
+
+  /*  c1) set b = 1 coefficient */
+  mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_b, 1, __LINE__);
+  /*  c1) set n = -M coefficient */
+  mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_n, -mlp->pv.BIG_M, 
__LINE__);
+
+  /* Add constraint c 3) minimum bandwidth
+   * b_t + (-n_t * b_min) >= 0
+   * */
+  GNUNET_asprintf(&name, "c3_%s_%s_%p", GNUNET_i2s(&address->peer), 
address->plugin, address);
+  mlpi->r_c3 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 
0.0);
+  GNUNET_free (name);
+
+  /*  c3) set b = 1 coefficient */
+  mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_b, 1, __LINE__);
+  /*  c3) set n = -b_min coefficient */
+  mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_n, - ((double 
)mlp->pv.b_min), __LINE__);
+
+
+  /* Set coefficient entries in invariant rows */
+  /* c 4) minimum connections */
+  mlp_create_problem_set_value (p, p->r_c4, mlpi->c_n, 1, __LINE__);
+  /* c 6) maximize diversity */
+  mlp_create_problem_set_value (p, p->r_c6, mlpi->c_n, 1, __LINE__);
+  /* c 2) 1 address peer peer */
+  mlp_create_problem_set_value (p, peer->r_c2, mlpi->c_n, 1, __LINE__);
+  /* c 9) relativity */
+  mlp_create_problem_set_value (p, peer->r_c9, mlpi->c_b, 1, __LINE__);
+  /* c 8) utility */
+  mlp_create_problem_set_value (p, p->r_c8, mlpi->c_b, 1, __LINE__);
+
+  /* c 10) obey network specific quotas
+   * (1)*b_1 + ... + (1)*b_m <= quota_n
+   */
+  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
+  {
+    addr_net = get_performance_info (address, GNUNET_ATS_NETWORK_TYPE);
+    if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
+            addr_net = GNUNET_ATS_NET_UNSPECIFIED;
+
+    if (mlp->pv.quota_index[c] == addr_net)
+    {
+      mlp_create_problem_set_value (p, p->r_quota[c], mlpi->c_b, 1, __LINE__);
+      break;
+    }
+  }
+
+  /* c 7) Optimize quality */
+  /* For all quality metrics, set quality of this address */
+  props = mlp->get_properties (mlp->get_properties_cls, address);
+  for (c = 0; c < mlp->pv.m_q; c++)
+    mlp_create_problem_set_value (p, p->r_q[c], mlpi->c_b, props[c], __LINE__);
+
+  return GNUNET_OK;
+}
+
+/**
+ * Create the invariant columns c4, c6, c10, c8, c7
+ */
+static void
+mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct 
MLP_Problem *p)
+{
+  char *name;
+  int c;
+
+  /* Row for c4) minimum connection */
+  /* Number of minimum connections is min(|Peers|, n_min) */
+  p->r_c4 = mlp_create_problem_create_constraint (p, "c4", GLP_LO, 
(mlp->pv.n_min > p->num_peers) ? p->num_peers : mlp->pv.n_min, 0.0);
+
+  /* Add row for c6) */
+  p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0, 0.0);
+  /* c6 )Setting -D */
+  mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__);
+
+  /* Add rows for c 10) */
+  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
+  {
+    char * text;
+    GNUNET_asprintf(&text, "c10_quota_ats_%s",
+        GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]));
+    p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 
0.0, mlp->pv.quota_out[c]);
+    GNUNET_free (text);
+  }
+
+  /* Adding rows for c 8) */
+  p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0, 0.0);
+  /* -u */
+  mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__);
+
+  /* c 7) For all quality metrics */
+  for (c = 0; c < mlp->pv.m_q; c++)
+  {
+    GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->pv.q[c]));
+    p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0, 
0.0);
+    GNUNET_free (name);
+    mlp_create_problem_set_value (p, p->r_q[c], p->c_q[c], -1, __LINE__);
+  }
+}
+
+
+/**
+ * Create the invariant columns d, u, r, q0 ... qm
+ */
+static void
+mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct 
MLP_Problem *p)
+{
+  char *name;
+  int c;
+
+#if TEST_MAX_BW_ASSIGNMENT
+  mlp->pv.co_D = 0.0;
+  mlp->pv.co_U = 0.0;
+
+#endif
+  //mlp->pv.co_R = 0.0;
+
+  /* Diversity d column  */
+  p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0, 0.0, 
mlp->pv.co_D);
+
+  /* Utilization u column  */
+  p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, 0.0, 
mlp->pv.co_U);
+
+  /* Relativity r column  */
+  p->c_r = mlp_create_problem_create_column (p, "r", GLP_CV, GLP_LO, 0.0, 0.0, 
mlp->pv.co_R);
+
+  /* Quality metric columns */
+  for (c = 0; c < mlp->pv.m_q; c++)
+  {
+    GNUNET_asprintf (&name, "q_%u", mlp->pv.q[c]);
+#if TEST_MAX_BW_ASSIGNMENT
+    p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 
0.0, 0.0, 0.0);
+#else
+    p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 
0.0, 0.0, mlp->pv.co_Q[c]);
+#endif
+    GNUNET_free (name);
+  }
+}
+
+
+/**
+ * Create the MLP problem
+ *
+ * @param mlp the MLP handle
+ * @return GNUNET_OK or GNUNET_SYSERR
+ */
+static int
+mlp_create_problem (struct GAS_MLP_Handle *mlp)
+{
+  struct MLP_Problem *p = &mlp->p;
+  int res = GNUNET_OK;
+
+  GNUNET_assert (p->prob == NULL);
+  GNUNET_assert (p->ia == NULL);
+  GNUNET_assert (p->ja == NULL);
+  GNUNET_assert (p->ar == NULL);
+  /* Reset MLP problem struct */
+
+  /* create the glpk problem */
+  p->prob = glp_create_prob ();
+  GNUNET_assert (NULL != p->prob);
+  p->num_peers = GNUNET_CONTAINER_multipeermap_size (mlp->requested_peers);
+  p->num_addresses = mlp_create_problem_count_addresses (mlp->requested_peers, 
mlp->addresses);
+
+  /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 
2 + 1 */
+  p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses +
+      mlp->pv.m_q + p->num_peers + 2 + 1);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality 
metrics == %u elements\n",
+       p->num_peers,
+       p->num_addresses,
+       mlp->pv.m_q,
+       p->num_elements);
+
+  /* Set a problem name */
+  glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution");
+  /* Set optimization direction to maximize */
+  glp_set_obj_dir (p->prob, GLP_MAX);
+
+  /* Create problem matrix */
+  /* last +1 caused by glpk index starting with one: [1..elements]*/
+  p->ci = 1;
+  /* row index */
+  p->ia = GNUNET_malloc (p->num_elements * sizeof (int));
+  /* column index */
+  p->ja = GNUNET_malloc (p->num_elements * sizeof (int));
+  /* coefficient */
+  p->ar = GNUNET_malloc (p->num_elements * sizeof (double));
+
+  if ((NULL == p->ia) || (NULL == p->ja) || (NULL == p->ar))
+  {
+      LOG (GNUNET_ERROR_TYPE_ERROR, _("Problem size too large, cannot allocate 
memory!\n"));
+      return GNUNET_SYSERR;
+  }
+
+  /* Adding invariant columns */
+  mlp_create_problem_add_invariant_columns (mlp, p);
+
+  /* Adding address independent constraint rows */
+  mlp_create_problem_add_invariant_rows (mlp, p);
+
+  /* Adding address dependent columns constraint rows */
+  GNUNET_CONTAINER_multipeermap_iterate (mlp->addresses,
+                                        
&mlp_create_problem_add_address_information,
+                                        mlp);
+
+  /* Load the matrix */
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n");
+  glp_load_matrix(p->prob, (p->ci)-1, p->ia, p->ja, p->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 = 0;
+
+  res = glp_simplex(mlp->p.prob, &mlp->control_param_lp);
+  if (0 == res)
+          LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n", 
res, mlp_solve_to_string(res));
+  else
+          LOG (GNUNET_ERROR_TYPE_WARNING, "Solving LP problem failed: 0x%02X 
%s\n", res, mlp_solve_to_string(res));
+
+  /* Analyze problem status  */
+  res = glp_get_status (mlp->p.prob);
+  switch (res) {
+    /* solution is optimal */
+    case GLP_OPT:
+    /* solution is feasible */
+    case GLP_FEAS:
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n",
+          res, mlp_status_to_string(res));
+      return GNUNET_OK;
+    /* Problem was ill-defined, no way to handle that */
+    default:
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Solving LP problem failed, no solution: 
0x%02X %s\n",
+          res, mlp_status_to_string(res));
+      return GNUNET_SYSERR;
+  }
+}
+
+
+/**
+ * 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 = 0;
+  res = glp_intopt(mlp->p.prob, &mlp->control_param_mlp);
+  if (0 == res)
+          LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem: 0x%02X %s\n", 
res, mlp_solve_to_string(res));
+  else
+          LOG (GNUNET_ERROR_TYPE_WARNING, "Solving MLP problem failed: 0x%02X 
%s\n", res, mlp_solve_to_string(res));
+  /* Analyze problem status  */
+  res = glp_mip_status(mlp->p.prob);
+  switch (res) {
+    /* solution is optimal */
+    case GLP_OPT:
+    /* solution is feasible */
+    case GLP_FEAS:
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem: 0x%02X %s\n", res, 
mlp_status_to_string(res));
+      return GNUNET_OK;
+    /* Problem was ill-defined, no way to handle that */
+    default:
+      LOG (GNUNET_ERROR_TYPE_WARNING,"Solving MLP problem failed, 0x%02X 
%s\n\n", res, mlp_status_to_string(res));
+      return GNUNET_SYSERR;
+  }
+}
+
+/**
+ * Propagates the results when MLP problem was solved
+ *
+ * @param cls the MLP handle
+ * @param key the peer identity
+ * @param value the address
+ * @return #GNUNET_OK to continue
+ */
+int
+mlp_propagate_results (void *cls,
+                      const struct GNUNET_PeerIdentity *key,
+                      void *value)
+{
+  struct GAS_MLP_Handle *mlp = cls;
+  struct ATS_Address *address;
+  struct MLP_information *mlpi;
+  double mlp_bw_in = MLP_NaN;
+  double mlp_bw_out = MLP_NaN;
+  double mlp_use = MLP_NaN;
+
+  /* Check if we have to add this peer due to a pending request */
+  if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains 
(mlp->requested_peers,
+                                                          key))
+  {
+    return GNUNET_OK;
+  }
+  address = value;
+  GNUNET_assert (address->solver_information != NULL);
+  mlpi = address->solver_information;
+
+  mlp_bw_in = glp_mip_col_val(mlp->p.prob, mlpi->c_b);/* FIXME */
+  if (mlp_bw_in > (double) UINT32_MAX)
+  {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing 
...\n" );
+      mlp_bw_in = (double) UINT32_MAX;
+  }
+  mlp_bw_out = glp_mip_col_val(mlp->p.prob, mlpi->c_b);
+  if (mlp_bw_out > (double) UINT32_MAX)
+  {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing 
...\n" );
+      mlp_bw_out = (double) UINT32_MAX;
+  }
+  mlp_use = glp_mip_col_val(mlp->p.prob, mlpi->c_n);
+
+  /*
+   * Debug: solution
+   * LOG (GNUNET_ERROR_TYPE_INFO, "MLP result address: `%s' `%s' length %u 
session %u, mlp use %f\n",
+   *    GNUNET_i2s(&address->peer), address->plugin,
+   *    address->addr_len, address->session_id);
+   */
+
+  if (GLP_YES == mlp_use)
+  {
+    /* This address was selected by the solver to be used */
+    mlpi->n = GNUNET_YES;
+    if (GNUNET_NO == address->active)
+    {
+            /* Address was not used before, enabling address */
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : enabling address\n",
+          (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
+      address->active = GNUNET_YES;
+      address->assigned_bw_in.value__ = htonl (mlp_bw_in);
+      mlpi->b_in.value__ = htonl(mlp_bw_in);
+      address->assigned_bw_out.value__ = htonl (mlp_bw_out);
+      mlpi->b_out.value__ = htonl(mlp_bw_out);
+      if ((NULL == mlp->exclude_peer) || (0 != memcmp (&address->peer, 
mlp->exclude_peer, sizeof (address->peer))))
+        mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
+      return GNUNET_OK;
+    }
+    else if (GNUNET_YES == address->active)
+    {
+      /* Address was used before, check for bandwidth change */
+      if ((mlp_bw_out != ntohl(address->assigned_bw_out.value__)) ||
+              (mlp_bw_in != ntohl(address->assigned_bw_in.value__)))
+      {
+          LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : bandwidth changed\n",
+              (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
+          address->assigned_bw_in.value__ = htonl (mlp_bw_in);
+          mlpi->b_in.value__ = htonl(mlp_bw_in);
+          address->assigned_bw_out.value__ = htonl (mlp_bw_out);
+          mlpi->b_out.value__ = htonl(mlp_bw_out);
+          if ((NULL == mlp->exclude_peer) || (0 != memcmp (&address->peer, 
mlp->exclude_peer, sizeof (address->peer))))
+            mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
+          return GNUNET_OK;
+      }
+    }
+    else
+      GNUNET_break (0);
+  }
+  else if (GLP_NO == mlp_use)
+  {
+    /* This address was selected by the solver to be not used */
+    mlpi->n = GNUNET_NO;
+    if (GNUNET_NO == address->active)
+    {
+      /* Address was not used before, nothing to do */
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : no change\n",
+          (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
+      return GNUNET_OK;
+    }
+    else if (GNUNET_YES == address->active)
+    {
+    /* Address was used before, disabling address */
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : disabling address\n",
+        (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
+      address->active = GNUNET_NO;
+      /* Set bandwidth to 0 */
+      address->assigned_bw_in = BANDWIDTH_ZERO;
+      mlpi->b_in.value__ = htonl(mlp_bw_in);
+      address->assigned_bw_out = BANDWIDTH_ZERO;
+      mlpi->b_out.value__ = htonl(mlp_bw_out);
+      //mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
+      return GNUNET_OK;
+    }
+    else
+      GNUNET_break (0);
+  }
+  else
+    GNUNET_break (0);
+
+  return GNUNET_OK;
+}
+
+static void notify (struct GAS_MLP_Handle *mlp,
+    enum GAS_Solver_Operation op,
+    enum GAS_Solver_Status stat,
+    enum GAS_Solver_Additional_Information add)
+{
+  if (NULL != mlp->env->info_cb)
+    mlp->env->info_cb (mlp->env->info_cb_cls, op, stat, add);
+}
+/**
+ * Solves the MLP problem
+ *
+ * @param solver the MLP Handle
+ * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
+ */
+int
+GAS_mlp_solve_problem (void *solver)
+{
+  struct GAS_MLP_Handle *mlp = solver;
+  char *filename;
+  int res_lp = 0;
+  int res_mip = 0;
+
+  struct GNUNET_TIME_Absolute start;
+  struct GNUNET_TIME_Relative dur_total;
+  struct GNUNET_TIME_Relative dur_setup;
+  struct GNUNET_TIME_Relative dur_lp;
+  struct GNUNET_TIME_Relative dur_mlp;
+
+  GNUNET_assert(NULL != solver);
+
+  if (GNUNET_YES == mlp->bulk_lock)
+    {
+      mlp->bulk_request++;
+      return GNUNET_NO;
+    }
+  notify(mlp, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS,
+      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
+  start = GNUNET_TIME_absolute_get();
+
+  if (0 == GNUNET_CONTAINER_multipeermap_size(mlp->requested_peers))
+    {
+      notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
+      return GNUNET_OK; /* No pending requests */
+    }
+  if (0 == GNUNET_CONTAINER_multipeermap_size(mlp->addresses))
+    {
+      notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
+      return GNUNET_OK; /* No addresses available */
+    }
+
+  if ((GNUNET_NO == mlp->mlp_prob_changed)
+      && (GNUNET_NO == mlp->mlp_prob_updated))
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n");
+      notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
+      return GNUNET_OK;
+    }
+  if (GNUNET_YES == mlp->mlp_prob_changed)
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
+      notify(mlp, GAS_OP_SOLVE_SETUP_START, GAS_STAT_SUCCESS, GAS_INFO_FULL);
+      mlp_delete_problem(mlp);
+      if (GNUNET_SYSERR == mlp_create_problem(mlp))
+        {
+          notify(mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_FAIL, GAS_INFO_FULL);
+          return GNUNET_SYSERR;
+        }
+      notify(mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_SUCCESS, GAS_INFO_FULL);
+      mlp->control_param_lp.presolve = GLP_YES;
+      mlp->control_param_mlp.presolve = GNUNET_NO; /* No presolver, we have LP 
solution */
+    }
+  else
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n");
+    }
+
+  dur_setup = GNUNET_TIME_absolute_get_duration (start);
+  mlp->control_param_lp.presolve = GLP_YES;
+  /* Run LP solver */
+
+  notify(mlp, GAS_OP_SOLVE_MLP_LP_START, GAS_STAT_SUCCESS,
+      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "Running LP solver %s\n",
+      (GLP_YES == mlp->control_param_lp.presolve)? "with presolver": "without 
presolver");
+  res_lp = mlp_solve_lp_problem(mlp);
+  notify(mlp, GAS_OP_SOLVE_MLP_LP_STOP,
+      (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
+      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
+
+  dur_lp = GNUNET_TIME_absolute_get_duration (start);
+  dur_lp = GNUNET_TIME_relative_subtract(dur_lp, dur_setup);
+
+  /* Run MLP solver */
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
+  notify(mlp, GAS_OP_SOLVE_MLP_MLP_START, GAS_STAT_SUCCESS,
+      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
+  res_mip = mlp_solve_mlp_problem(mlp);
+  notify(mlp, GAS_OP_SOLVE_MLP_MLP_STOP,
+      (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
+      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
+  notify(mlp, GAS_OP_SOLVE_STOP,
+      (GNUNET_OK == res_mip) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
+      (GNUNET_YES == mlp->mlp_prob_changed) ? GAS_INFO_FULL : 
GAS_INFO_UPDATED);
+
+  dur_mlp = GNUNET_TIME_absolute_get_duration (start);
+  dur_mlp = GNUNET_TIME_relative_subtract(dur_mlp, dur_setup);
+  dur_mlp = GNUNET_TIME_relative_subtract(dur_mlp, dur_lp);
+  dur_total = GNUNET_TIME_absolute_get_duration (start);
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+      "Execution time for %s solve: (total/setup/lp/mlp) : %llu %llu %llu 
%llu\n",
+      (GNUNET_YES == mlp->mlp_prob_changed) ? "full" : "updated",
+      (unsigned long long) dur_total.rel_value_us,
+      (unsigned long long) dur_setup.rel_value_us,
+      (unsigned long long) dur_lp.rel_value_us,
+      (unsigned long long) dur_mlp.rel_value_us);
+
+  /* Save stats */
+  mlp->ps.lp_res = res_lp;
+  mlp->ps.mip_res = res_mip;
+  mlp->ps.lp_presolv = mlp->control_param_lp.presolve;
+  mlp->ps.mip_presolv = mlp->control_param_mlp.presolve;
+  mlp->ps.p_cols = glp_get_num_cols(mlp->p.prob);
+  mlp->ps.p_rows = glp_get_num_rows(mlp->p.prob);
+  mlp->ps.p_elements = mlp->p.num_elements;
+
+  /* Propagate result*/
+  notify(mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
+      (GNUNET_OK == res_lp) && (GNUNET_OK == res_mip) ? GAS_STAT_SUCCESS : 
GAS_STAT_FAIL,
+      GAS_INFO_NONE);
+  if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
+    {
+      GNUNET_CONTAINER_multipeermap_iterate(mlp->addresses,
+          &mlp_propagate_results, mlp);
+    }
+  notify(mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
+      (GNUNET_OK == res_lp) && (GNUNET_OK == res_mip) ? GAS_STAT_SUCCESS : 
GAS_STAT_FAIL,
+      GAS_INFO_NONE);
+
+  struct GNUNET_TIME_Absolute time = GNUNET_TIME_absolute_get();
+  if (GNUNET_YES == mlp->write_mip_mps)
+    {
+      /* Write problem to disk */
+      GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.mps", mlp->p.num_peers,
+          mlp->p.num_addresses, time.abs_value_us);
+      LOG(GNUNET_ERROR_TYPE_ERROR, "DUMP: %s \n", filename);
+      glp_write_lp(mlp->p.prob, NULL, filename);
+      GNUNET_free(filename);
+    }
+  if (GNUNET_YES == mlp->write_mip_sol)
+    {
+      /* Write solution to disk */
+      GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.sol", mlp->p.num_peers,
+          mlp->p.num_addresses, time.abs_value_us);
+      glp_print_mip(mlp->p.prob, filename);
+      LOG(GNUNET_ERROR_TYPE_ERROR, "DUMP: %s \n", filename);
+      GNUNET_free(filename);
+    }
+
+  /* Reset change and update marker */
+  mlp->control_param_lp.presolve = GLP_NO;
+  mlp->mlp_prob_updated = GNUNET_NO;
+  mlp->mlp_prob_changed = GNUNET_NO;
+
+  if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
+    return GNUNET_OK;
+  else
+    return GNUNET_SYSERR;
+}
+
+/**
+ * Add a single address to the solve
+ *
+ * @param solver the solver Handle
+ * @param address the address to add
+ * @param network network type of this address
+ */
+void
+GAS_mlp_address_add (void *solver,
+                    struct ATS_Address *address,
+                    uint32_t network)
+{
+  struct GAS_MLP_Handle *mlp = solver;
+  struct ATS_Peer *p;
+
+  GNUNET_assert (NULL != solver);
+  GNUNET_assert (NULL != address);
+
+  if (GNUNET_ATS_NetworkTypeCount <= network)
+  {
+   GNUNET_break (0);
+   return;
+  }
+
+  if (NULL == address->solver_information)
+  {
+      address->solver_information = GNUNET_new (struct MLP_information);
+  }
+  else
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+          _("Adding address for peer `%s' multiple times\n"),
+          GNUNET_i2s(&address->peer));
+
+  /* Is this peer included in the problem? */
+  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
+                                                     &address->peer)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' without 
address request \n", GNUNET_i2s(&address->peer));
+    return;
+  }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' with address 
request \n", GNUNET_i2s(&address->peer));
+  /* Problem size changed: new address for peer with pending request */
+  mlp->mlp_prob_changed = GNUNET_YES;
+  if (GNUNET_YES == mlp->mlp_auto_solve)
+    GAS_mlp_solve_problem (solver);
+}
+
+
+/**
+ * Transport properties for this address have changed
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param type the ATSI type in HBO
+ * @param abs_value the absolute value of the property
+ * @param rel_value the normalized value
+ */
+void
+GAS_mlp_address_property_changed (void *solver,
+                                  struct ATS_Address *address,
+                                  uint32_t type,
+                                  uint32_t abs_value,
+                                  double rel_value)
+{
+  struct MLP_information *mlpi = address->solver_information;
+  struct GAS_MLP_Handle *mlp = solver;
+  struct ATS_Peer *p;
+  int c1;
+  int type_index;
+
+  GNUNET_assert (NULL != solver);
+  GNUNET_assert (NULL != address);
+
+  if (NULL == mlpi)
+  {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+          _("Updating address property `%s' for peer `%s' %p not added 
before\n"),
+          GNUNET_ATS_print_property_type (type),
+          GNUNET_i2s(&address->peer),
+          address);
+      GNUNET_break (0);
+      return;
+  }
+
+  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
+                                                     &address->peer)))
+  {
+    /* Peer is not requested, so no need to update problem */
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating property `%s' address for peer 
`%s'\n",
+      GNUNET_ATS_print_property_type (type),
+      GNUNET_i2s(&address->peer));
+
+  /* Find row index */
+  type_index = -1;
+  for (c1 = 0; c1 < mlp->pv.m_q; c1++)
+  {
+    if (type == mlp->pv.q[c1])
+    {
+      type_index = c1;
+      break;
+    }
+  }
+  if (-1 == type_index)
+  {
+    GNUNET_break (0);
+    return; /* quality index not found */
+  }
+
+  /* Update c7) [r_q[index]][c_b] = f_q * q_averaged[type_index] */
+  if (GNUNET_YES == mlp_create_problem_update_value (&mlp->p,
+      mlp->p.r_q[type_index], mlpi->c_b, rel_value, __LINE__))
+  {
+    mlp->mlp_prob_updated = GNUNET_YES;
+    if (GNUNET_YES == mlp->mlp_auto_solve)
+      GAS_mlp_solve_problem (solver);
+  }
+}
+
+
+/**
+ * Transport session for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param cur_session the current session
+ * @param new_session the new session
+ */
+void
+GAS_mlp_address_session_changed (void *solver,
+                                  struct ATS_Address *address,
+                                  uint32_t cur_session,
+                                  uint32_t new_session)
+{
+  /* Nothing to do here */
+  return;
+}
+
+
+/**
+ * Transport session for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param in_use usage state
+ */
+void
+GAS_mlp_address_inuse_changed (void *solver,
+                               struct ATS_Address *address,
+                               int in_use)
+{
+  /* Nothing to do here */
+  return;
+}
+
+
+/**
+ * Network scope for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param current_network the current network
+ * @param new_network the new network
+ */
+void
+GAS_mlp_address_change_network (void *solver,
+                               struct ATS_Address *address,
+                               uint32_t current_network,
+                               uint32_t new_network)
+{
+  struct MLP_information *mlpi = address->solver_information;
+  struct GAS_MLP_Handle *mlp = solver;
+  struct ATS_Peer *p;
+  int nets_avail[] = GNUNET_ATS_NetworkType;
+  int c1;
+
+  GNUNET_assert (NULL != solver);
+  GNUNET_assert (NULL != address);
+
+  if (GNUNET_ATS_NetworkTypeCount <= new_network)
+  {
+   GNUNET_break (0);
+   return;
+  }
+
+  if (NULL == mlpi)
+  {
+    GNUNET_break (0);
+    return;
+  }
+
+  if (mlpi->c_b == MLP_UNDEFINED)
+    return; /* This address is not yet in the matrix*/
+
+  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
+                                                     &address->peer)))
+  {
+    /* Peer is not requested, so no need to update problem */
+    GNUNET_break (0);
+    return;
+  }
+
+  if (current_network == new_network)
+  {
+    GNUNET_break (0);
+    return;
+  }
+
+  for (c1 = 0; c1 < GNUNET_ATS_NetworkTypeCount ; c1 ++)
+  {
+    if (nets_avail[c1] == new_network)
+      break;
+  }
+
+  if (GNUNET_ATS_NetworkTypeCount == c1)
+  {
+    /* Invalid network */
+    GNUNET_break (0);
+    return;
+  }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating network for peer `%s' from `%s' to 
`%s'\n",
+      GNUNET_i2s (&address->peer),
+      GNUNET_ATS_print_network_type(current_network),
+      GNUNET_ATS_print_network_type(new_network));
+
+  for (c1 = 0; c1 < GNUNET_ATS_NetworkTypeCount; c1++)
+  {
+    if (mlp->pv.quota_index[c1] == current_network)
+    {
+      /* Remove from old network */
+      mlp_create_problem_update_value (&mlp->p,
+          mlp->p.r_quota[c1],
+          mlpi->c_b, 0.0, __LINE__);
+      break;
+    }
+  }
+
+  for (c1 = 0; c1 < GNUNET_ATS_NetworkTypeCount; c1++)
+  {
+    if (mlp->pv.quota_index[c1] == new_network)
+    {
+      /* Remove from old network */
+      if (GNUNET_SYSERR == mlp_create_problem_update_value (&mlp->p,
+          mlp->p.r_quota[c1],
+          mlpi->c_b, 1.0, __LINE__))
+      {
+        /* This quota did not exist in the problem, recreate */
+        GNUNET_break (0);
+      }
+      break;
+    }
+  }
+
+  mlp->mlp_prob_changed = GNUNET_YES;
+}
+
+
+/**
+ * Deletes a single address in the MLP problem
+ *
+ * The MLP problem has to be recreated and the problem has to be resolved
+ *
+ * @param solver the MLP Handle
+ * @param address the address to delete
+ * @param session_only delete only session not whole address
+ */
+void
+GAS_mlp_address_delete (void *solver,
+    struct ATS_Address *address,
+    int session_only)
+{
+  struct ATS_Peer *p;
+  struct GAS_MLP_Handle *mlp = solver;
+  struct MLP_information *mlpi;
+  int was_active;
+
+  GNUNET_assert (NULL != solver);
+  GNUNET_assert (NULL != address);
+
+  mlpi = address->solver_information;
+  if ((GNUNET_NO == session_only) && (NULL != mlpi))
+  {
+    /* Remove full address */
+    GNUNET_free (mlpi);
+    address->solver_information = NULL;
+  }
+  was_active = address->active;
+  address->active = GNUNET_NO;
+  address->assigned_bw_in = BANDWIDTH_ZERO;
+  address->assigned_bw_out = BANDWIDTH_ZERO;
+
+  /* Is this peer included in the problem? */
+  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
+                                                     &address->peer)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting %s for peer `%s' without address 
request \n",
+        (session_only == GNUNET_YES) ? "session" : "address",
+        GNUNET_i2s(&address->peer));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_INFO, "Deleting %s for peer `%s' with address request 
\n",
+      (session_only == GNUNET_YES) ? "session" : "address",
+      GNUNET_i2s(&address->peer));
+
+  /* Problem size changed: new address for peer with pending request */
+  mlp->mlp_prob_changed = GNUNET_YES;
+  if (GNUNET_YES == mlp->mlp_auto_solve)
+  {
+    GAS_mlp_solve_problem (solver);
+  }
+  if (GNUNET_YES == was_active)
+  {
+    if (NULL == GAS_mlp_get_preferred_address (solver, &address->peer))
+    {
+      /* No alternative address, disconnecting peer */
+      mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
+    }
+  }
+
+  return;
+}
+
+
+/**
+ * Find the active address in the set of addresses of a peer
+ * @param cls destination
+ * @param key peer id
+ * @param value address
+ * @return GNUNET_OK
+ */
+static int
+mlp_get_preferred_address_it (void *cls,
+                             const struct GNUNET_PeerIdentity *key,
+                             void *value)
+{
+  static int counter = 0;
+  struct ATS_Address **aa = cls;
+  struct ATS_Address *addr = value;
+  struct MLP_information *mlpi = addr->solver_information;
+
+  if (mlpi == NULL)
+    return GNUNET_YES;
+
+  /*
+   * Debug output
+   * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+   *           "MLP [%u] Peer `%s' %s length %u session %u active %s mlp 
active %s\n",
+   *           counter, GNUNET_i2s (&addr->peer), addr->plugin, 
addr->addr_len, addr->session_id,
+   *           (GNUNET_YES == addr->active) ? "active" : "inactive",
+   *           (GNUNET_YES == mlpi->n) ? "active" : "inactive");
+   */
+
+  if (GNUNET_YES == mlpi->n)
+  {
+
+    (*aa) = addr;
+    (*aa)->assigned_bw_in = mlpi->b_in;
+    (*aa)->assigned_bw_out = mlpi->b_out;
+    return GNUNET_NO;
+  }
+  counter ++;
+  return GNUNET_YES;
+}
+
+
+static double
+get_peer_pref_value (struct GAS_MLP_Handle *mlp, const struct 
GNUNET_PeerIdentity *peer)
+{
+  double res;
+  const double *preferences = NULL;
+  int c;
+  preferences = mlp->get_preferences (mlp->get_preferences_cls, peer);
+
+  res = 0.0;
+  for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
+  {
+    if (c != GNUNET_ATS_PREFERENCE_END)
+    {
+      //fprintf (stderr, "VALUE[%u] %s %.3f \n", c, GNUNET_i2s 
(&cur->addr->peer), t[c]);
+      res += preferences[c];
+    }
+  }
+  res /= (GNUNET_ATS_PreferenceCount -1);
+  return res;
+}
+
+
+/**
+ * Get the preferred address for a specific peer
+ *
+ * @param solver the MLP Handle
+ * @param peer the peer
+ * @return suggested address
+ */
+const struct ATS_Address *
+GAS_mlp_get_preferred_address (void *solver,
+                               const struct GNUNET_PeerIdentity *peer)
+{
+  struct GAS_MLP_Handle *mlp = solver;
+  struct ATS_Peer *p;
+  struct ATS_Address *res;
+
+  GNUNET_assert (NULL != solver);
+  GNUNET_assert (NULL != peer);
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n",
+      GNUNET_i2s (peer));
+
+  /* Is this peer included in the problem? */
+  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
+                                                     peer)))
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO, "Adding peer `%s' to list of 
requested_peers with requests\n",
+          GNUNET_i2s (peer));
+
+      p = GNUNET_malloc (sizeof (struct ATS_Peer));
+      p->id = (*peer);
+      p->f = get_peer_pref_value (mlp, peer);
+      GNUNET_CONTAINER_multipeermap_put (mlp->requested_peers,
+                                        peer, p,
+                                        
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+
+      /* Added new peer, we have to rebuild problem before solving */
+      mlp->mlp_prob_changed = GNUNET_YES;
+
+      if ((GNUNET_YES == mlp->mlp_auto_solve)&&
+          (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains(mlp->addresses,
+                                                               peer)))
+      {
+        mlp->exclude_peer = peer;
+        GAS_mlp_solve_problem (mlp);
+        mlp->exclude_peer = NULL;
+      }
+  }
+  /* Get prefered address */
+  res = NULL;
+  GNUNET_CONTAINER_multipeermap_get_multiple (mlp->addresses, peer,
+                                              mlp_get_preferred_address_it, 
&res);
+  return res;
+}
+
+
+/**
+ * Start a bulk operation
+ *
+ * @param solver the solver
+ */
+void
+GAS_mlp_bulk_start (void *solver)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Locking solver for bulk operation ...\n");
+  struct GAS_MLP_Handle *s = (struct GAS_MLP_Handle *) solver;
+
+  GNUNET_assert (NULL != solver);
+
+  s->bulk_lock ++;
+}
+
+void
+GAS_mlp_bulk_stop (void *solver)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Unlocking solver from bulk operation ...\n");
+
+  struct GAS_MLP_Handle *s = (struct GAS_MLP_Handle *) solver;
+  GNUNET_assert (NULL != solver);
+
+  if (s->bulk_lock < 1)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  s->bulk_lock --;
+
+  if (0 < s->bulk_request)
+  {
+    GAS_mlp_solve_problem (solver);
+    s->bulk_request= 0;
+  }
+}
+
+
+
+/**
+ * Stop notifying about address and bandwidth changes for this peer
+ *
+ * @param solver the MLP handle
+ * @param peer the peer
+ */
+void
+GAS_mlp_stop_get_preferred_address (void *solver,
+                                     const struct GNUNET_PeerIdentity *peer)
+{
+  struct GAS_MLP_Handle *mlp = solver;
+  struct ATS_Peer *p = NULL;
+
+  GNUNET_assert (NULL != solver);
+  GNUNET_assert (NULL != peer);
+  if (NULL != (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, 
peer)))
+  {
+    GNUNET_CONTAINER_multipeermap_remove (mlp->requested_peers, peer, p);
+    GNUNET_free (p);
+
+    mlp->mlp_prob_changed = GNUNET_YES;
+    if (GNUNET_YES == mlp->mlp_auto_solve)
+    {
+      GAS_mlp_solve_problem (solver);
+    }
+  }
+}
+
+
+/**
+ * Changes the preferences for a peer in the MLP problem
+ *
+ * @param solver the MLP Handle
+ * @param peer the peer
+ * @param kind the kind to change the preference
+ * @param pref_rel the relative score
+ */
+void
+GAS_mlp_address_change_preference (void *solver,
+                   const struct GNUNET_PeerIdentity *peer,
+                   enum GNUNET_ATS_PreferenceKind kind,
+                   double pref_rel)
+{
+  struct GAS_MLP_Handle *mlp = solver;
+  struct ATS_Peer *p = NULL;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Changing preference for address for peer `%s' 
to %.2f\n",
+      GNUNET_i2s(peer), pref_rel);
+
+  GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, 
GNUNET_NO);
+  /* Update the constraints with changed preferences */
+
+  /* Update quality constraint c7 */
+
+  /* Update relativity constraint c9 */
+  if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, 
peer)))
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR, "Updating preference for unknown peer 
`%s'\n", GNUNET_i2s(peer));
+    return;
+  }
+  p->f = get_peer_pref_value (mlp, peer);
+  /*
+  LOG (GNUNET_ERROR_TYPE_ERROR, "PEER PREF: %s %.2f\n",
+      GNUNET_i2s(peer), p->f);*/
+  mlp_create_problem_update_value (&mlp->p, p->r_c9, mlp->p.c_r, -p->f, 
__LINE__);
+
+  /* Problem size changed: new address for peer with pending request */
+  mlp->mlp_prob_updated = GNUNET_YES;
+  if (GNUNET_YES == mlp->mlp_auto_solve)
+    GAS_mlp_solve_problem (solver);
+  return;
+}
+
+
+/**
+ * Get application feedback for a peer
+ *
+ * @param solver the solver handle
+ * @param application the application
+ * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_mlp_address_preference_feedback (void *solver,
+                                    void *application,
+                                    const struct GNUNET_PeerIdentity *peer,
+                                    const struct GNUNET_TIME_Relative scope,
+                                    enum GNUNET_ATS_PreferenceKind kind,
+                                    double score)
+{
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+  GNUNET_assert (NULL != solver);
+  GNUNET_assert (NULL != peer);
+
+  GNUNET_assert (NULL != s);
+}
+
+
+static int
+mlp_free_peers (void *cls,
+               const struct GNUNET_PeerIdentity *key, void *value)
+{
+  struct GNUNET_CONTAINER_MultiPeerMap *map = cls;
+  struct ATS_Peer *p = value;
+
+  GNUNET_CONTAINER_multipeermap_remove (map, key, value);
+  GNUNET_free (p);
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown the MLP problem solving component
+ *
+ * @param cls the solver handle
+ * @return NULL
+ */
+void *
+libgnunet_plugin_ats_mlp_done (void *cls)
+{
+  struct GAS_MLP_Handle *mlp = cls;
+  GNUNET_assert (mlp != NULL);
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down mlp solver\n");
+  mlp_delete_problem (mlp);
+
+  GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
+                                        &mlp_free_peers,
+                                        mlp->requested_peers);
+  GNUNET_CONTAINER_multipeermap_destroy (mlp->requested_peers);
+  mlp->requested_peers = NULL;
+
+  /* Clean up GLPK environment */
+  glp_free_env();
+  GNUNET_free (mlp);
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown down of mlp solver complete\n");
+  return NULL;
+}
+
+
+void *
+libgnunet_plugin_ats_mlp_init (void *cls)
+{
+  struct GNUNET_ATS_PluginEnvironment *env = cls;
+  struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
+
+  double D;
+  double R;
+  double U;
+  unsigned long long tmp;
+  unsigned int b_min;
+  unsigned int n_min;
+  int c;
+  int c2;
+  int found;
+
+  struct GNUNET_TIME_Relative max_duration;
+  long long unsigned int max_iterations;
+
+  GNUNET_assert (NULL != env->cfg);
+  GNUNET_assert (NULL != env->stats);
+  GNUNET_assert (NULL != env->addresses);
+  GNUNET_assert (NULL != env->bandwidth_changed_cb);
+  GNUNET_assert (NULL != env->get_preferences);
+  GNUNET_assert (NULL != env->get_property);
+
+  /* Init GLPK environment */
+  int res = glp_init_env();
+  switch (res) {
+    case 0:
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
+          "initialization successful");
+      break;
+    case 1:
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
+          "environment is already initialized");
+      break;
+    case 2:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
+          "initialization failed (insufficient memory)");
+      GNUNET_free(mlp);
+      return NULL;
+      break;
+    case 3:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
+          "initialization failed (unsupported programming model)");
+      GNUNET_free(mlp);
+      return NULL;
+      break;
+    default:
+      break;
+  }
+
+   mlp->write_mip_mps = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "ats",
+          "DUMP_MLP");
+   if (GNUNET_SYSERR == mlp->write_mip_mps)
+     mlp->write_mip_mps = GNUNET_NO;
+   mlp->write_mip_sol = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "ats",
+          "DUMP_SOLUTION");
+   if (GNUNET_SYSERR == mlp->write_mip_sol)
+     mlp->write_mip_sol = GNUNET_NO;
+
+  mlp->pv.BIG_M = (double) BIG_M_VALUE;
+
+  /* Get timeout for iterations */
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(env->cfg, "ats", 
"MLP_MAX_DURATION", &max_duration))
+  {
+    max_duration = MLP_MAX_EXEC_DURATION;
+  }
+
+  /* Get maximum number of iterations */
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(env->cfg, "ats", 
"MLP_MAX_ITERATIONS", &max_iterations))
+  {
+    max_iterations = MLP_MAX_ITERATIONS;
+  }
+
+  /* Get diversity coefficient from configuration */
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
+                                                      "MLP_COEFFICIENT_D",
+                                                      &tmp))
+    D = (double) tmp / 100;
+  else
+    D = DEFAULT_D;
+
+  /* Get proportionality coefficient from configuration */
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
+                                                      "MLP_COEFFICIENT_R",
+                                                      &tmp))
+    R = (double) tmp / 100;
+  else
+    R = DEFAULT_R;
+
+  /* Get utilization coefficient from configuration */
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
+                                                      "MLP_COEFFICIENT_U",
+                                                      &tmp))
+    U = (double) tmp / 100;
+  else
+    U = DEFAULT_U;
+
+  /* Get quality metric coefficients from configuration */
+  int i_delay = MLP_NaN;
+  int i_distance = MLP_NaN;
+  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->pv.co_Q[c] = DEFAULT_QUALITY;
+
+    mlp->pv.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 != MLP_NaN) && (GNUNET_OK == 
GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
+                                                      
"MLP_COEFFICIENT_QUALITY_DELAY",
+                                                      &tmp)))
+
+    mlp->pv.co_Q[i_delay] = (double) tmp / 100;
+  else
+    mlp->pv.co_Q[i_delay] = DEFAULT_QUALITY;
+
+  if ((i_distance != MLP_NaN) && (GNUNET_OK == 
GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
+                                                      
"MLP_COEFFICIENT_QUALITY_DISTANCE",
+                                                      &tmp)))
+    mlp->pv.co_Q[i_distance] = (double) tmp / 100;
+  else
+    mlp->pv.co_Q[i_distance] = DEFAULT_QUALITY;
+
+  /* Get minimum bandwidth per used address from configuration */
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
+                                                      "MLP_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 (env->cfg, "ats",
+                                                      "MLP_MIN_CONNECTIONS",
+                                                      &tmp))
+    n_min = tmp;
+  else
+    n_min = DEFAULT_MIN_CONNECTIONS;
+
+  /* Init network quotas */
+  int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
+  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
+  {
+      found = GNUNET_NO;
+      for (c2 = 0; c2 < env->network_count; c2++)
+      {
+          if (quotas[c] == env->networks[c2])
+          {
+              mlp->pv.quota_index[c] = env->networks[c2];
+              mlp->pv.quota_out[c] = env->out_quota[c2];
+              mlp->pv.quota_in[c] = env->in_quota[c2];
+              found = GNUNET_YES;
+              LOG (GNUNET_ERROR_TYPE_DEBUG, "Quota for network `%s' (in/out) 
%llu/%llu\n",
+                          
GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
+                          mlp->pv.quota_out[c],
+                          mlp->pv.quota_in[c]);
+              break;
+          }
+      }
+
+      /* Check if defined quota could make problem unsolvable */
+      if ((n_min * b_min) > mlp->pv.quota_out[c])
+      {
+        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent outbound quota 
configuration for network `%s', is %llu must be at least %llu\n"),
+            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
+            mlp->pv.quota_out[c],
+            (n_min * b_min));
+        mlp->pv.quota_out[c] = (n_min * b_min);
+      }
+      if ((n_min * b_min) > mlp->pv.quota_in[c])
+      {
+        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent inbound quota 
configuration for network `%s', is %llu must be at least %llu\n"),
+            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
+            mlp->pv.quota_in[c],
+            (n_min * b_min));
+        mlp->pv.quota_in[c] = (n_min * b_min);
+      }
+
+      /* Check if bandwidth is too big to make problem solvable */
+      if (mlp->pv.BIG_M < mlp->pv.quota_out[c])
+      {
+        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting outbound quota configuration 
for network `%s'from %llu to %.0f\n"),
+            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
+            mlp->pv.quota_out[c],
+            mlp->pv.BIG_M);
+        mlp->pv.quota_out[c] = mlp->pv.BIG_M ;
+      }
+      if (mlp->pv.BIG_M < mlp->pv.quota_in[c])
+      {
+        LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inbound quota configuration 
for network `%s' from %llu to %.0f\n"),
+            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
+            mlp->pv.quota_in[c],
+            mlp->pv.BIG_M);
+        mlp->pv.quota_in[c] = mlp->pv.BIG_M ;
+      }
+
+      if (GNUNET_NO == found)
+      {
+        mlp->pv.quota_in[c] = 
ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+        mlp->pv.quota_out[c] = 
ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+        LOG (GNUNET_ERROR_TYPE_INFO, _("Using default quota configuration for 
network `%s' (in/out) %llu/%llu\n"),
+            GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
+            mlp->pv.quota_in[c],
+            mlp->pv.quota_out[c]);
+      }
+  }
+  mlp->env = env;
+  env->sf.s_add = &GAS_mlp_address_add;
+  env->sf.s_address_update_property = &GAS_mlp_address_property_changed;
+  env->sf.s_address_update_session = &GAS_mlp_address_session_changed;
+  env->sf.s_address_update_inuse = &GAS_mlp_address_inuse_changed;
+  env->sf.s_address_update_network = &GAS_mlp_address_change_network;
+  env->sf.s_get = &GAS_mlp_get_preferred_address;
+  env->sf.s_get_stop = &GAS_mlp_stop_get_preferred_address;
+  env->sf.s_pref = &GAS_mlp_address_change_preference;
+  env->sf.s_feedback = &GAS_mlp_address_preference_feedback;
+  env->sf.s_del = &GAS_mlp_address_delete;
+  env->sf.s_bulk_start = &GAS_mlp_bulk_start;
+  env->sf.s_bulk_stop = &GAS_mlp_bulk_stop;
+
+
+  /* Assign options to handle */
+  mlp->stats = (struct GNUNET_STATISTICS_Handle *) env->stats;
+  mlp->addresses = env->addresses;
+  mlp->bw_changed_cb = env->bandwidth_changed_cb;
+  mlp->bw_changed_cb_cls = env->bw_changed_cb_cls;
+  mlp->get_preferences =  env->get_preferences;
+  mlp->get_preferences_cls = env->get_preference_cls;
+  mlp->get_properties = env->get_property;
+  mlp->get_properties_cls = env->get_property_cls;
+  /* Setting MLP Input variables */
+
+  mlp->pv.co_D = D;
+  mlp->pv.co_R = R;
+  mlp->pv.co_U = U;
+  mlp->pv.b_min = b_min;
+  mlp->pv.n_min = n_min;
+  mlp->pv.m_q = GNUNET_ATS_QualityPropertiesCount;
+  mlp->mlp_prob_changed = GNUNET_NO;
+  mlp->mlp_prob_updated = GNUNET_NO;
+  mlp->mlp_auto_solve = GNUNET_YES;
+  mlp->requested_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
+  mlp->bulk_request = 0;
+  mlp->bulk_lock = 0;
+
+  /* Setup GLPK */
+  /* Redirect GLPK output to GNUnet logging */
+  glp_term_hook (&mlp_term_hook, (void *) mlp);
+
+  /* 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_us / 1000LL;
+
+  /* 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_us / 1000LL;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
+
+  return mlp;
+}
+
+/* end of plugin_ats_mlp.c */

Copied: gnunet/src/ats/plugin_ats_mlp.h (from rev 31213, 
gnunet/src/ats/libgnunet_plugin_ats_mlp.h)
===================================================================
--- gnunet/src/ats/plugin_ats_mlp.h                             (rev 0)
+++ gnunet/src/ats/plugin_ats_mlp.h     2013-12-10 07:58:08 UTC (rev 31244)
@@ -0,0 +1,559 @@
+/*
+ (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/plugin_ats_mlp.h
+ * @brief ats MLP problem solver
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_ats_service.h"
+#include "gnunet_ats_plugin.h"
+#include "gnunet-service-ats_addresses.h"
+#include "gnunet_statistics_service.h"
+#if HAVE_LIBGLPK
+#include "glpk.h"
+#endif
+
+#ifndef GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
+#define GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
+
+#define BIG_M_VALUE (UINT32_MAX) /10
+#define BIG_M_STRING "unlimited"
+
+#define MLP_AVERAGING_QUEUE_LENGTH 3
+
+#define MLP_MAX_EXEC_DURATION   
GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
+#define MLP_MAX_ITERATIONS      4096
+
+#define DEFAULT_D 1.0
+#define DEFAULT_R 1.0
+#define DEFAULT_U 1.0
+#define DEFAULT_QUALITY 1.0
+#define DEFAULT_MIN_CONNECTIONS 4
+#define DEFAULT_PEER_PREFERENCE 1.0
+
+#define MLP_NaN -1
+#define MLP_UNDEFINED 0
+#define GLP_YES 1.0
+#define GLP_NO  0.0
+
+struct MLP_Solution
+{
+  int lp_res;
+  int lp_presolv;
+  int mip_res;
+  int mip_presolv;
+
+  int p_elements;
+  int p_cols;
+  int p_rows;
+
+  int n_peers;
+  int n_addresses;
+
+};
+
+struct ATS_Peer
+{
+  struct GNUNET_PeerIdentity id;
+
+  /* Was this peer already added to the current problem? */
+  int processed;
+
+  /* constraint 2: 1 address per peer*/
+  unsigned int r_c2;
+
+  /* constraint 9: relativity */
+  unsigned int r_c9;
+
+  /* Legacy preference value */
+  double f;
+};
+
+struct MLP_Problem
+{
+  /**
+   * GLPK (MLP) problem object
+   */
+#if HAVE_LIBGLPK
+  glp_prob *prob;
+#else
+  void *prob;
+#endif
+
+  /* Number of addresses in problem */
+  unsigned int num_addresses;
+  /* Number of peers in problem */
+  unsigned int num_peers;
+  /* Number of elements in problem matrix */
+  unsigned int num_elements;
+
+  /* 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;
+  /* Row indices quality metrics  */
+  int r_q[GNUNET_ATS_QualityPropertiesCount];
+  /* Row indices ATS network quotas */
+  int r_quota[GNUNET_ATS_NetworkTypeCount];
+
+  /* Column index Diversity (D) column */
+  int c_d;
+  /* Column index Utilization (U) column */
+  int c_u;
+  /* Column index Proportionality (R) column */
+  int c_r;
+  /* Column index quality metrics  */
+  int c_q[GNUNET_ATS_QualityPropertiesCount];
+
+  /* Problem matrix */
+  /* Current index */
+  unsigned int ci;
+  /* Row index array */
+  int *ia;
+  /* Column index array */
+  int *ja;
+  /* Column index value */
+  double *ar;
+
+};
+
+struct MLP_Variables
+{
+  /* Big M value for bandwidth capping */
+  double BIG_M;
+
+  /* ATS Quality metrics
+   *
+   * Array with GNUNET_ATS_QualityPropertiesCount elements
+   * contains mapping to GNUNET_ATS_Property*/
+  int q[GNUNET_ATS_QualityPropertiesCount];
+
+  /* Number of quality metrics */
+  int m_q;
+
+  /* Number of quality metrics */
+  int m_rc;
+
+  /* Quality metric coefficients*/
+  double co_Q[GNUNET_ATS_QualityPropertiesCount];
+
+  /* Ressource costs coefficients*/
+  double co_RC[GNUNET_ATS_QualityPropertiesCount];
+
+  /* Diversity coefficient */
+  double co_D;
+
+  /* Utility coefficient */
+  double co_U;
+
+  /* Relativity coefficient */
+  double co_R;
+
+  /* Minimum bandwidth assigned to an address */
+  unsigned int b_min;
+
+  /* Minimum number of addresses with bandwidth assigned */
+  unsigned int n_min;
+
+  /* Quotas */
+  /* Array mapping array index to ATS network */
+  int quota_index[GNUNET_ATS_NetworkTypeCount];
+  /* Outbound quotas */
+  unsigned long long quota_out[GNUNET_ATS_NetworkTypeCount];
+  /* Inbound quotas */
+
+  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];
+
+};
+
+/**
+ * MLP Handle
+ */
+struct GAS_MLP_Handle
+{
+  struct GNUNET_ATS_PluginEnvironment *env;
+
+  /**
+   * Statistics handle
+   */
+  struct GNUNET_STATISTICS_Handle *stats;
+
+  /**
+   * Address hashmap for lookups
+   */
+  const struct GNUNET_CONTAINER_MultiPeerMap *addresses;
+
+  /**
+   * Addresses' bandwidth changed callback
+   */
+  GAS_bandwidth_changed_cb bw_changed_cb;
+
+  /**
+   * Addresses' bandwidth changed callback closure
+   */
+  void *bw_changed_cb_cls;
+
+  /**
+   * ATS function to get preferences
+   */
+  GAS_get_preferences get_preferences;
+
+  /**
+   * Closure for ATS function to get preferences
+   */
+  void *get_preferences_cls;
+
+  /**
+   * ATS function to get properties
+   */
+  GAS_get_properties get_properties;
+
+  /**
+   * Closure for ATS function to get properties
+   */
+  void *get_properties_cls;
+
+  /**
+   * Exclude peer from next result propagation
+   */
+  const struct GNUNET_PeerIdentity *exclude_peer;
+
+  /**
+   * Encapsulation for the MLP problem
+   */
+  struct MLP_Problem p;
+
+  /**
+   * Encapsulation for the MLP problem variables
+   */
+  struct MLP_Variables pv;
+
+  /**
+   * Encapsulation for the MLP solution
+   */
+  struct MLP_Solution ps;
+
+  /**
+   * Bulk lock
+   */
+
+  int bulk_lock;
+
+  /**
+   * Number of changes while solver was locked
+   */
+  int bulk_request;
+
+  /**
+   * GLPK LP control parameter
+   */
+#if HAVE_LIBGLPK
+  glp_smcp control_param_lp;
+#else
+  void *control_param_lp;
+#endif
+
+  /**
+   * GLPK LP control parameter
+   */
+#if HAVE_LIBGLPK
+  glp_iocp control_param_mlp;
+#else
+  void *control_param_mlp;
+#endif
+
+  /**
+   * Peers with pending address requests
+   */
+  struct GNUNET_CONTAINER_MultiPeerMap *requested_peers;
+
+  /**
+   * Was the problem updated since last solution
+   */
+  int mlp_prob_updated;
+
+  /**
+   * Has the problem size changed since last solution
+   */
+  int mlp_prob_changed;
+
+  /**
+   * Solve the problem automatically when updates occur?
+   * Default: GNUNET_YES
+   * Can be disabled for test and measurements
+   */
+  int mlp_auto_solve;
+
+  /**
+   * Write MILP problem to a MPS file
+   */
+  int write_mip_mps;
+
+  /**
+   * Write MILP problem to a MPS file
+   */
+  int write_mip_sol;
+
+};
+
+/**
+ * Address specific MLP information
+ */
+struct MLP_information
+{
+
+  /* Bandwidth assigned */
+  struct GNUNET_BANDWIDTH_Value32NBO b_out;
+  struct GNUNET_BANDWIDTH_Value32NBO b_in;
+
+  /* Address selected */
+  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;
+};
+
+
+/**
+ * Solves the MLP problem
+ *
+ * @param solver the MLP Handle
+ * @return #GNUNET_OK if could be solved, GNUNET_SYSERR on failure
+ */
+int
+GAS_mlp_solve_problem (void *solver);
+
+
+/**
+ * Init the MLP problem solving component
+ *
+ * @param cfg the GNUNET_CONFIGURATION_Handle handle
+ * @param stats the GNUNET_STATISTICS handle
+ * @param addresses Hashmap containing addresses
+ * @param network array of GNUNET_ATS_NetworkType with length dest_length
+ * @param out_dest array of outbound quotas
+ * @param in_dest array of outbound quota
+ * @param dest_length array length for quota arrays
+ * @param bw_changed_cb callback for changed bandwidth amounts
+ * @param bw_changed_cb_cls cls for callback
+ * @param get_preference callback to get relative preferences for a peer
+ * @param get_preference_cls cls for callback to get relative preferences for 
a peer
+ * @param get_properties callback to get relative properties
+ * @param get_properties_cls cls for callback to get relative properties
+ * @return struct GAS_MLP_Handle on success, NULL on fail
+ */
+void *
+GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
+             const struct GNUNET_STATISTICS_Handle *stats,
+              const struct GNUNET_CONTAINER_MultiPeerMap *addresses,
+              int *network,
+              unsigned long long *out_dest,
+              unsigned long long *in_dest,
+              int dest_length,
+              GAS_bandwidth_changed_cb bw_changed_cb,
+              void *bw_changed_cb_cls,
+              GAS_get_preferences get_preference,
+              void *get_preference_cls,
+              GAS_get_properties get_properties,
+              void *get_properties_cls);
+
+
+/**
+ * Add a single address within a network to the solver
+ *
+ * @param solver the solver Handle
+ * @param address the address to add
+ * @param network network type of this address
+ */
+void
+GAS_mlp_address_add (void *solver, struct ATS_Address *address,
+    uint32_t network);
+
+
+/**
+ * Transport properties for this address have changed
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param type the ATSI type in HBO
+ * @param abs_value the absolute value of the property
+ * @param rel_value the normalized value
+ */
+void
+GAS_mlp_address_property_changed (void *solver, struct ATS_Address *address,
+    uint32_t type, uint32_t abs_value, double rel_value);
+
+
+/**
+ * Transport session for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param cur_session the current session
+ * @param new_session the new session
+ */
+void
+GAS_mlp_address_session_changed (void *solver, struct ATS_Address *address,
+                                uint32_t cur_session, uint32_t new_session);
+
+
+/**
+ * Usage for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param in_use usage state
+ */
+void
+GAS_mlp_address_inuse_changed (void *solver, struct ATS_Address *address,
+    int in_use);
+
+/**
+ * Network scope for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param current_network the current network
+ * @param new_network the new network
+ */
+void
+GAS_mlp_address_change_network (void *solver, struct ATS_Address *address,
+    uint32_t current_network, uint32_t new_network);
+
+/**
+ * Deletes a single address in the MLP problem
+ *
+ * The MLP problem has to be recreated and the problem has to be resolved
+ *
+ * @param solver the MLP Handle
+ * @param address the address to delete
+ * @param session_only delete only session not whole address
+ */
+void
+GAS_mlp_address_delete (void *solver, struct ATS_Address *address,
+    int session_only);
+
+/**
+ * Changes the preferences for a peer in the MLP problem
+ *
+ * @param solver the MLP Handle
+ * @param peer the peer
+ * @param kind the kind to change the preference
+ * @param pref_rel the relative score
+ */
+void
+GAS_mlp_address_change_preference (void *solver,
+    const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind 
kind,
+    double pref_rel);
+
+/**
+ * Get application feedback for a peer
+ *
+ * @param solver the solver handle
+ * @param application the application
+ * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_mlp_address_preference_feedback (void *solver, void *application,
+    const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_TIME_Relative scope,
+    enum GNUNET_ATS_PreferenceKind kind, double score);
+
+/**
+ * Start a bulk operation
+ *
+ * @param solver the solver
+ */
+void
+GAS_mlp_bulk_start (void *solver);
+
+/**
+ * Bulk operation done
+ */
+void
+GAS_mlp_bulk_stop (void *solver);
+
+/**
+ * Get the preferred address for a specific peer until
+ * GAS_mlp_stop_get_preferred_address is called
+ *
+ * @param solver the MLP Handle
+ * @param peer the peer
+ * @return suggested address
+ */
+const struct ATS_Address *
+GAS_mlp_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Stop notifying about address and bandwidth changes for this peer
+ *
+ * @param solver the MLP handle
+ * @param peer the peer
+ */
+void
+GAS_mlp_stop_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Shutdown the MLP problem solving component
+ *
+ * @param solver the solver handle
+ */
+void
+GAS_mlp_done (void *solver);
+
+#endif
+/* end of plugin_ats_mlp.h */

Copied: gnunet/src/ats/plugin_ats_proportional.c (from rev 31213, 
gnunet/src/ats/libgnunet_plugin_ats_proportional.c)
===================================================================
--- gnunet/src/ats/plugin_ats_proportional.c                            (rev 0)
+++ gnunet/src/ats/plugin_ats_proportional.c    2013-12-10 07:58:08 UTC (rev 
31244)
@@ -0,0 +1,1604 @@
+/*
+ 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/plugin_ats_proportional.c
+ * @brief ATS proportional solver
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "plugin_ats_proportional.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "ats-proportional",__VA_ARGS__)
+
+
+/**
+ *
+ * NOTE: Do not change this documentation. This documentation is based
+ * on gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
+ * use build_txt.sh to generate plaintext output
+ *
+ * ATS addresses : proportional solver
+ *
+ *    The proportional solver ("proportional") distributes the available
+ *    bandwidth fair over all the addresses influenced by the
+ *    preference values. For each available network type an in- and
+ *    outbound quota is configured and the bandwidth available in
+ *    these networks is distributed over the addresses.  The solver
+ *    first assigns every addresses the minimum amount of bandwidth
+ *    GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT and then distributes the
+ *    remaining bandwidth available according to the preference
+ *    values. For each peer only a single address gets bandwidth
+ *    assigned and only one address marked as active.  The most
+ *    important functionality for the solver is implemented in: *
+ *    find_address_it is an hashmap iterator returning the prefered
+ *    address for an peer * update_quota_per_network distributes
+ *    available bandwidth for a network over active addresses
+ *
+ *    Changes to addresses automatically have an impact on the the
+ *    bandwidth assigned to other addresses in the same network since
+ *    the solver distributes the remaining bandwidth over the
+ *    addresses in the network.  When changes to the addresses occur,
+ *    the solver first performs the changes, like adding or deleting
+ *    addresses, and then updates bandwidth assignment for the
+ *    affected network. Bandwidth assignment is only recalculated on
+ *    demand when an address is requested by a client for a peer or
+ *    when the addresses available have changed or an address changed
+ *    the network it is located in. When the bandwidth assignment has
+ *    changed the callback is called with the new bandwidth
+ *    assignments. The bandwidth distribution for a network is
+ *    recalculated due to: * address suggestion requests * address
+ *    deletions * address switching networks during address update *
+ *    preference changes
+ *
+ *     3.1 Data structures used
+ *
+ *    For each ATS network (e.g. WAN, LAN, loopback) a struct Network
+ *    is used to specify network related information as total adresses
+ *    and active addresses in this network and the configured in- and
+ *    outbound quota. Each network also contains a list of addresses
+ *    added to the solver located in this network. The proportional
+ *    solver uses the addresses' solver_information field to store the
+ *    proportional network it belongs to for each address.
+ *
+ *     3.2 Initializing
+ *
+ *    When the proportional solver is initialized the solver creates a
+ *    new solver handle and initializes the network structures with
+ *    the quotas passed from addresses and returns the handle solver.
+ *
+ *     3.3 Adding an address
+ *
+ *    When a new address is added to the solver using s_add, a lookup
+ *    for the network for this address is done and the address is
+ *    enqueued in in the linked list of the network.
+ *
+ *     3.4 Updating an address
+ *
+ *    The main purpose of address updates is to update the ATS
+ *    information for addresse selection. Important for the proportional
+ *    solver is when an address switches network it is located
+ *    in. This is common because addresses added by transport's
+ *    validation mechanism are commonly located in
+ *    GNUNET_ATS_NET_UNSPECIFIED. Addresses in validation are located
+ *    in this network type and only if a connection is successful on
+ *    return of payload data transport switches to the real network
+ *    the address is located in.  When an address changes networks it
+ *    is first of all removed from the old network using the solver
+ *    API function GAS_proportional_address_delete and the network in
+ *    the address struct is updated. A lookup for the respective new
+ *    proportional network is done and stored in the addresse's
+ *    solver_information field. Next the address is re-added to the
+ *    solver using the solver API function
+ *    GAS_proportional_address_add. If the address was marked as in
+ *    active, the solver checks if bandwidth is available in the
+ *    network and if yes sets the address to active and updates the
+ *    bandwidth distribution in this network. If no bandwidth is
+ *    available it sets the bandwidth for this address to 0 and tries
+ *    to suggest an alternative address. If an alternative address was
+ *    found, addresses' callback is called for this address.
+ *
+ *     3.5 Deleting an address
+ *
+ *    When an address is removed from the solver, it removes the
+ *    respective address from the network and if the address was
+ *    marked as active, it updates the bandwidth distribution for this
+ *    network.
+ *
+ *     3.6 Requesting addresses
+ *
+ *    When an address is requested for a peer the solver performs a
+ *    lookup for the peer entry in addresses address hashmap and
+ *    selects the best address.  The selection of the most suitable
+ *    address is done in the find_address_it hashmap iterator
+ *    described in detail in section 3.7. If no address is returned,
+ *    no address can be suggested at the moment. If the address
+ *    returned is marked as active, the solver can return this
+ *    address. If the address is not marked as active, the solver
+ *    checks if another address belongign to this peer is marked as
+ *    active and marks the address as inactive, updates the bandwidth
+ *    for this address to 0, call the bandwidth changed callback for
+ *    this address due to the change and updates quota assignment for
+ *    the addresse's network. the now in-active address is belonging
+ *    to. The solver marks the new address as active and updates the
+ *    bandwidth assignment for this network.
+ *
+ *     3.7 Choosing addresses
+ *
+ *    Choosing the best possible address for suggestion is done by
+ *    iterating over all addresses of a peer stored in addresses'
+ *    hashmap and using the hashmap iterator find_address_it to select
+ *    the best available address.  Several checks are done when an
+ *    address is selected. First if this address is currently blocked
+ *    by addresses from being suggested. An address is blocked for the
+ *    duration of ATS_BLOCKING_DELTA when it is suggested to
+ *    transport. Next it is checked if at least
+ *    GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT bytes bandwidth is available
+ *    in the addresse's network, because suggesting an address without
+ *    bandwidth does not make sense. This also ensures that all active
+ *    addresses in this network get at least the minimum amount of
+ *    bandwidth assigned. In the next step the solver ensures that for
+ *    tcp connections inbound connections are prefered over outbound
+ *    connections. In the next stet the solver ensures that
+ *    connections are prefered in the following order: * connections
+ *    are already established and have bandwidth assigned *
+ *    connections with a shorter distance * connectes have a shorter
+ *    latency
+ *
+ *     3.8 Changing preferences
+ *
+ *     3.9 Shutdown
+ *
+ *    During shutdown all network entries and aging processes are
+ *    destroyed and freed.
+ *
+ *
+ * OLD DOCUMENTATION
+ *
+ * This solver assigns in and outbound bandwidth equally for all
+ * addresses in specific network type (WAN, LAN) based on configured
+ * in and outbound quota for this network.
+ *
+ * The solver is notified by addresses about changes to the addresses
+ * and recalculates the bandwith assigned if required. The solver
+ * notifies addresses by calling the GAS_bandwidth_changed_cb
+ * callback.
+ *
+ * - Initialization
+ *
+ *
+ *
+ *
+ * For each peer only a single is selected and marked as "active" in the 
address
+ * struct.
+ *
+ * E.g.:
+ *
+ * You have the networks WAN and LAN and quotas
+ * WAN_TOTAL_IN, WAN_TOTAL_OUT
+ * LAN_TOTAL_IN, LAN_TOTAL_OUT
+ *
+ * If you have x addresses in the network segment LAN, the quotas are
+ * QUOTA_PER_ADDRESS = LAN_TOTAL_OUT / x
+ *
+ * Quotas are automatically recalculated and reported back when addresses are
+ * - requested
+ *
+ */
+
+#define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10)
+#define PREF_AGING_FACTOR 0.95
+
+#define DEFAULT_REL_PREFERENCE 1.0
+#define DEFAULT_ABS_PREFERENCE 0.0
+#define MIN_UPDATE_INTERVAL GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10)
+
+/**
+ * A handle for the proportional solver
+ */
+struct GAS_PROPORTIONAL_Handle
+{
+   struct GNUNET_ATS_PluginEnvironment *env;
+
+  /**
+   * Statistics handle
+   */
+  struct GNUNET_STATISTICS_Handle *stats;
+
+  /**
+   * Hashmap containing all valid addresses
+   */
+  const struct GNUNET_CONTAINER_MultiPeerMap *addresses;
+
+  /**
+   * Pending address requests
+   */
+  struct GNUNET_CONTAINER_MultiPeerMap *requests;
+
+  /**
+   * Bandwidth changed callback
+   */
+  GAS_bandwidth_changed_cb bw_changed;
+
+  /**
+   * Bandwidth changed callback cls
+   */
+  void *bw_changed_cls;
+
+  /**
+   * ATS function to get preferences
+   */
+  GAS_get_preferences get_preferences;
+
+  /**
+   * Closure for ATS function to get preferences
+   */
+  void *get_preferences_cls;
+
+  /**
+   * ATS function to get properties
+   */
+  GAS_get_properties get_properties;
+
+  /**
+   * Closure for ATS function to get properties
+   */
+  void *get_properties_cls;
+
+  /**
+   * Bulk lock
+   */
+  int bulk_lock;
+
+  /**
+   * Number of changes while solver was locked
+   */
+  int bulk_requests;
+
+  /**
+   * Total number of addresses for solver
+   */
+  unsigned int total_addresses;
+
+  /**
+   * Number of active addresses for solver
+   */
+  unsigned int active_addresses;
+
+  /**
+   * Networks array
+   */
+  struct Network *network_entries;
+
+  /**
+   * Number of networks
+   */
+  unsigned int network_count;
+
+};
+
+/**
+ * Representation of a network
+ */
+struct Network
+{
+  /**
+   * ATS network type
+   */
+  unsigned int type;
+
+  /**
+   * Network description
+   */
+  char *desc;
+
+  /**
+   * Total inbound quota
+   *
+   */
+  unsigned long long total_quota_in;
+
+  /**
+   * Total outbound quota
+   *
+   */
+  unsigned long long total_quota_out;
+
+  /**
+   * Number of active addresses for this network
+   */
+  unsigned int active_addresses;
+
+  /**
+   * Number of total addresses for this network
+   */
+  unsigned int total_addresses;
+
+  /**
+   * String for statistics total addresses
+   */
+  char *stat_total;
+
+  /**
+   * String for statistics active addresses
+   */
+  char *stat_active;
+
+  struct AddressWrapper *head;
+  struct AddressWrapper *tail;
+};
+
+/**
+ * Address information stored in the solver
+ */
+struct AddressSolverInformation
+{
+  struct Network *network;
+
+  /**
+   * Inbound quota
+   *
+   */
+  unsigned long long calculated_quota_in_NBO;
+
+  /**
+   * Outbound quota
+   *
+   */
+  unsigned long long calculated_quota_out_NBO;
+
+
+};
+
+/**
+ * Wrapper for addresses to store them in network's linked list
+ */
+struct AddressWrapper
+{
+  /**
+   * Next in DLL
+   */
+  struct AddressWrapper *next;
+
+  /**
+   * Previous in DLL
+   */
+  struct AddressWrapper *prev;
+
+  /**
+   * The address
+   */
+  struct ATS_Address *addr;
+};
+
+/**
+ *  Important solver functions
+ *  ---------------------------
+ */
+
+void *
+libgnunet_plugin_ats_proportional_init (void *cls)
+{
+  struct GNUNET_ATS_PluginEnvironment *env = cls;
+  struct GAS_PROPORTIONAL_Handle *s;
+  struct Network * cur;
+  char * net_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
+  int c;
+
+  GNUNET_assert (NULL != env);
+  GNUNET_assert(NULL != env->cfg);
+  GNUNET_assert(NULL != env->stats);
+  GNUNET_assert(NULL != env->bandwidth_changed_cb);
+  GNUNET_assert(NULL != env->get_preferences);
+  GNUNET_assert(NULL != env->get_property);
+
+  s = GNUNET_malloc (sizeof (struct GAS_PROPORTIONAL_Handle));
+  s->env = env;
+  env->sf.s_add = &GAS_proportional_address_add;
+  env->sf.s_address_update_property = 
&GAS_proportional_address_property_changed;
+  env->sf.s_address_update_session = &GAS_proportional_address_session_changed;
+  env->sf.s_address_update_inuse = &GAS_proportional_address_inuse_changed;
+  env->sf.s_address_update_network = &GAS_proportional_address_change_network;
+  env->sf.s_get = &GAS_proportional_get_preferred_address;
+  env->sf.s_get_stop = &GAS_proportional_stop_get_preferred_address;
+  env->sf.s_pref = &GAS_proportional_address_change_preference;
+  env->sf.s_feedback = &GAS_proportional_address_preference_feedback;
+  env->sf.s_del = &GAS_proportional_address_delete;
+  env->sf.s_bulk_start = &GAS_proportional_bulk_start;
+  env->sf.s_bulk_stop = &GAS_proportional_bulk_stop;
+
+  s->stats = (struct GNUNET_STATISTICS_Handle *) env->stats;
+  s->bw_changed = env->bandwidth_changed_cb;
+  s->bw_changed_cls = env->bw_changed_cb_cls;
+  s->get_preferences = env->get_preferences;
+  s->get_preferences_cls = env->get_preference_cls;
+  s->get_properties = env->get_property;
+  s->get_properties_cls = env->get_property_cls;
+  s->network_count = env->network_count;
+  s->network_entries = GNUNET_malloc (env->network_count * sizeof (struct 
Network));
+
+  /* Init */
+  s->active_addresses = 0;
+  s->total_addresses = 0;
+  s->bulk_lock = GNUNET_NO;
+  s->addresses = env->addresses;
+  s->requests = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
+
+  for (c = 0; c < env->network_count; c++)
+  {
+    cur = &s->network_entries[c];
+    cur->total_addresses = 0;
+    cur->active_addresses = 0;
+    cur->type = env->networks[c];
+    cur->total_quota_in = env->in_quota[c];
+    cur->total_quota_out = env->out_quota[c];
+    cur->desc = net_str[c];
+    GNUNET_asprintf (&cur->stat_total,
+        "# ATS addresses %s total", cur->desc);
+    GNUNET_asprintf (&cur->stat_active,
+        "# ATS active addresses %s total", cur->desc);
+    LOG (GNUNET_ERROR_TYPE_INFO, "Added network %u `%s' %p\n", c, cur->desc, 
s);
+  }
+  return s;
+}
+
+void *
+libgnunet_plugin_ats_proportional_done (void *cls)
+{
+  struct GAS_PROPORTIONAL_Handle *s = cls;
+  struct AddressWrapper *cur;
+  struct AddressWrapper *next;
+  int c;
+  GNUNET_assert(s != NULL);
+  for (c = 0; c < s->network_count; c++)
+  {
+    if (s->network_entries[c].total_addresses > 0)
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG,
+          "Had %u addresses for network `%s' not deleted during shutdown\n",
+          s->network_entries[c].total_addresses, s->network_entries[c].desc);
+      GNUNET_break(0);
+    }
+
+    if (s->network_entries[c].active_addresses > 0)
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG,
+          "Had %u active addresses for network `%s' not deleted during 
shutdown\n",
+          s->network_entries[c].active_addresses, s->network_entries[c].desc);
+      GNUNET_break(0);
+    }
+
+    next = s->network_entries[c].head;
+    while (NULL != (cur = next))
+    {
+      next = cur->next;
+      GNUNET_CONTAINER_DLL_remove(s->network_entries[c].head,
+          s->network_entries[c].tail, cur);
+      GNUNET_free_non_null (cur->addr->solver_information);
+      GNUNET_free(cur);
+    }
+    GNUNET_free(s->network_entries[c].stat_total);
+    GNUNET_free(s->network_entries[c].stat_active);
+  }
+  if (s->total_addresses > 0)
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "Had %u addresses not deleted during shutdown\n", s->total_addresses);
+    GNUNET_break(0);
+  }
+  if (s->active_addresses > 0)
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "Had %u active addresses not deleted during shutdown\n",
+        s->active_addresses);
+    GNUNET_break (0);
+  }
+  GNUNET_free (s->network_entries);
+  GNUNET_CONTAINER_multipeermap_destroy (s->requests);
+  GNUNET_free (s);
+  return NULL;
+}
+
+
+/**
+ * Test if bandwidth is available in this network to add an additional address
+ *
+ * @param net the network type to update
+ * @return GNUNET_YES or GNUNET_NO
+ */
+static int
+is_bandwidth_available_in_network (struct Network *net)
+{
+  GNUNET_assert(NULL != net);
+  unsigned int na = net->active_addresses + 1;
+  uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+  if (((net->total_quota_in / na) > min_bw)
+      && ((net->total_quota_out / na) > min_bw))
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "Enough bandwidth available for %u active addresses in network `%s'\n",
+        na, net->desc);
+
+    return GNUNET_YES;
+  }
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "Not enough bandwidth available for %u active addresses in network 
`%s'\n",
+      na, net->desc);
+  return GNUNET_NO;
+}
+
+/**
+ * Update bandwidth assigned to peers in this network
+ *
+ * @param s the solver handle
+ * @param net the network type to update
+ * @param address_except address excluded from notification, since we suggest
+ * this address
+ */
+static void
+distribute_bandwidth (struct GAS_PROPORTIONAL_Handle *s,
+    struct Network *net, struct ATS_Address *address_except)
+{
+  struct AddressSolverInformation *asi;
+  struct AddressWrapper *cur;
+
+  unsigned long long remaining_quota_in = 0;
+  unsigned long long quota_out_used = 0;
+  unsigned long long remaining_quota_out = 0;
+  unsigned long long quota_in_used = 0;
+  uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+  double peer_prefs;
+  double total_prefs; /* Important: has to be double not float due to 
precision */
+  double cur_pref; /* Important: has to be double not float due to precision */
+  const double *t = NULL; /* Important: has to be double not float due to 
precision */
+  int c;
+  unsigned long long assigned_quota_in = 0;
+  unsigned long long assigned_quota_out = 0;
+
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "Recalculate quota for network type `%s' for %u addresses (in/out): 
%llu/%llu \n",
+      net->desc, net->active_addresses, net->total_quota_in,
+      net->total_quota_in);
+
+  if (net->active_addresses == 0)
+    return; /* no addresses to update */
+
+  /* Idea
+   * Assign every peer in network minimum Bandwidth
+   * Distribute bandwidth left according to preference
+   */
+
+  if ((net->active_addresses * min_bw) > net->total_quota_in)
+  {
+    GNUNET_break(0);
+    return;
+  }
+  if ((net->active_addresses * min_bw) > net->total_quota_out)
+  {
+    GNUNET_break(0);
+    return;
+  }
+
+  remaining_quota_in = net->total_quota_in - (net->active_addresses * min_bw);
+  remaining_quota_out = net->total_quota_out - (net->active_addresses * 
min_bw);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Remaining bandwidth : (in/out): %llu/%llu \n",
+      remaining_quota_in, remaining_quota_out);
+  total_prefs = 0.0;
+  for (cur = net->head; NULL != cur; cur = cur->next)
+  {
+    if (GNUNET_YES == cur->addr->active)
+    {
+      GNUNET_assert(
+          NULL != (t = s->get_preferences (s->get_preferences_cls, 
&cur->addr->peer)));
+
+      peer_prefs = 0.0;
+      for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
+      {
+        if (c != GNUNET_ATS_PREFERENCE_END)
+        {
+          //fprintf (stderr, "VALUE[%u] %s %.3f \n", c, GNUNET_i2s 
(&cur->addr->peer), t[c]);
+          peer_prefs += t[c];
+        }
+      }
+      total_prefs += (peer_prefs / (GNUNET_ATS_PreferenceCount - 1));
+    }
+  }
+  for (cur = net->head; NULL != cur; cur = cur->next)
+  {
+    if (GNUNET_YES == cur->addr->active)
+    {
+      cur_pref = 0.0;
+      GNUNET_assert(
+          NULL != (t = s->get_preferences (s->get_preferences_cls, 
&cur->addr->peer)));
+
+      for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
+      {
+        if (c != GNUNET_ATS_PREFERENCE_END)
+          cur_pref += t[c];
+      }
+      cur_pref /= 2;
+
+      assigned_quota_in = min_bw
+          + ((cur_pref / total_prefs) * remaining_quota_in);
+      assigned_quota_out = min_bw
+          + ((cur_pref / total_prefs) * remaining_quota_out);
+
+      LOG(GNUNET_ERROR_TYPE_DEBUG,
+          "New quota for peer `%s' with preference (cur/total) %.3f/%.3f 
(in/out): %llu / %llu\n",
+          GNUNET_i2s (&cur->addr->peer), cur_pref, total_prefs,
+          assigned_quota_in, assigned_quota_out);
+    }
+    else
+    {
+      assigned_quota_in = 0;
+      assigned_quota_out = 0;
+    }
+
+    quota_in_used += assigned_quota_in;
+    quota_out_used += assigned_quota_out;
+    /* Prevent overflow due to rounding errors */
+    if (assigned_quota_in > UINT32_MAX)
+      assigned_quota_in = UINT32_MAX;
+    if (assigned_quota_out > UINT32_MAX)
+      assigned_quota_out = UINT32_MAX;
+
+    /* Compare to current bandwidth assigned */
+    asi = cur->addr->solver_information;
+    asi->calculated_quota_in_NBO = htonl (assigned_quota_in);
+    asi->calculated_quota_out_NBO = htonl (assigned_quota_out);
+  }
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "Total bandwidth assigned is (in/out): %llu /%llu\n", quota_in_used,
+      quota_out_used);
+  if (quota_out_used > net->total_quota_out + 1) /* +1 is required due to 
rounding errors */
+  {
+    LOG(GNUNET_ERROR_TYPE_ERROR,
+        "Total outbound bandwidth assigned is larger than allowed 
(used/allowed) for %u active addresses: %llu / %llu\n",
+        net->active_addresses, quota_out_used, net->total_quota_out);
+  }
+  if (quota_in_used > net->total_quota_in + 1) /* +1 is required due to 
rounding errors */
+  {
+    LOG(GNUNET_ERROR_TYPE_ERROR,
+        "Total inbound bandwidth assigned is larger than allowed 
(used/allowed) for %u active addresses: %llu / %llu\n",
+        net->active_addresses, quota_in_used, net->total_quota_in);
+  }
+}
+
+struct FindBestAddressCtx
+{
+  struct GAS_PROPORTIONAL_Handle *s;
+  struct ATS_Address *best;
+};
+
+static int
+find_property_index (uint32_t type)
+{
+  int existing_types[] = GNUNET_ATS_QualityProperties;
+  int c;
+  for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+    if (existing_types[c] == type)
+      return c;
+  return GNUNET_SYSERR;
+}
+
+/**
+ * Find a "good" address to use for a peer by iterating over the addresses for 
this 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_best_address_it (void *cls,
+                     const struct GNUNET_PeerIdentity *key,
+                     void *value)
+{
+  struct FindBestAddressCtx *fba_ctx = (struct FindBestAddressCtx *) cls;
+  struct ATS_Address *current = (struct ATS_Address *) value;
+  struct GNUNET_TIME_Absolute now;
+  struct AddressSolverInformation *asi;
+  const double *norm_prop_cur;
+  const double *norm_prop_prev;
+  int index;
+
+  asi = current->solver_information;
+  now = GNUNET_TIME_absolute_get ();
+
+  if (current->blocked_until.abs_value_us
+      == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value_us)
+  {
+    /* This address is blocked for suggestion */
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Address %p blocked for suggestion for %s \n",
+        current,
+        GNUNET_STRINGS_relative_time_to_string 
(GNUNET_TIME_absolute_get_difference (now, current->blocked_until), 
GNUNET_YES));
+    return GNUNET_OK;
+  }
+  if (GNUNET_NO == is_bandwidth_available_in_network (asi->network))
+    return GNUNET_OK; /* There's no bandwidth available in this network */
+  if (NULL != fba_ctx->best)
+  {
+    GNUNET_assert(NULL != fba_ctx->best->plugin);
+    GNUNET_assert(NULL != current->plugin);
+    if (0 == strcmp (fba_ctx->best->plugin, current->plugin))
+    {
+      if ((0 != fba_ctx->best->addr_len) && (0 == current->addr_len))
+      {
+        /* saved address was an outbound address, but we have an inbound 
address */
+        fba_ctx->best = current;
+        return GNUNET_OK;
+      }
+      if (0 == fba_ctx->best->addr_len)
+      {
+        /* saved address was an inbound address, so do not overwrite */
+        return GNUNET_OK;
+      }
+    }
+  }
+  if (NULL == fba_ctx->best)
+  {
+    fba_ctx->best = current;
+    return GNUNET_OK;
+  }
+  if ((ntohl (fba_ctx->best->assigned_bw_in.value__) == 0)
+      && (ntohl (current->assigned_bw_in.value__) > 0))
+  {
+    /* stick to existing connection */
+    fba_ctx->best = current;
+    return GNUNET_OK;
+  }
+
+  norm_prop_cur = fba_ctx->s->get_properties (fba_ctx->s->get_properties_cls,
+      (const struct ATS_Address *) current);
+  norm_prop_prev = fba_ctx->s->get_properties (fba_ctx->s->get_properties_cls,
+      (const struct ATS_Address *) fba_ctx->best);
+  /*
+   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s previous %.2f current %.2f\n",
+   "DISTANCE", norm_prop_cur[1], norm_prop_cur[1]);
+   */
+  index = find_property_index (GNUNET_ATS_QUALITY_NET_DISTANCE);
+  if (GNUNET_SYSERR == index)
+  {
+    GNUNET_break(0);
+    return GNUNET_OK;
+  }
+  if (norm_prop_cur[index] < norm_prop_prev[index])
+  {
+    /* user shorter distance */
+    fba_ctx->best = current;
+    return GNUNET_OK;
+  }
+  /*
+   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s previous %.2f current %.2f\n",
+   "DELAY", norm_prop_cur[1], norm_prop_cur[1]);
+   */
+  index = find_property_index (GNUNET_ATS_QUALITY_NET_DELAY);
+  if (GNUNET_SYSERR == index)
+  {
+    GNUNET_break(0);
+    return GNUNET_OK;
+  }
+  if (norm_prop_cur[index] < norm_prop_prev[index])
+  {
+    /* user shorter delay */
+    fba_ctx->best = current;
+    return GNUNET_OK;
+  }
+
+  /* don't care */
+  return GNUNET_OK;
+}
+
+/**
+ *  Helper functions
+ *  ---------------------------
+ */
+static void
+propagate_bandwidth (struct GAS_PROPORTIONAL_Handle *s,
+    struct Network *net, struct ATS_Address *address_except)
+{
+  struct AddressWrapper *cur;
+  struct AddressSolverInformation *asi;
+  for (cur = net->head; NULL != cur; cur = cur->next)
+  {
+      asi = cur->addr->solver_information;
+      if ( (cur->addr->assigned_bw_in.value__ != asi->calculated_quota_in_NBO) 
||
+           (cur->addr->assigned_bw_out.value__ != 
asi->calculated_quota_out_NBO) )
+      {
+        cur->addr->assigned_bw_in.value__ = asi->calculated_quota_in_NBO;
+        cur->addr->assigned_bw_out.value__ = asi->calculated_quota_in_NBO;
+        /* Notify on change */
+        if ((GNUNET_YES == cur->addr->active) && (cur->addr != address_except))
+          s->bw_changed (s->bw_changed_cls, cur->addr);
+      }
+  }
+}
+
+/**
+ * Distribibute bandwidth
+ *
+ * @param s the solver handle
+ * @param n the network, can be NULL for all network
+ * @param address_except do not notify for this address
+ */
+static void
+distribute_bandwidth_in_network (struct GAS_PROPORTIONAL_Handle *s,
+    struct Network *n, struct ATS_Address *address_except)
+{
+  if (GNUNET_YES == s->bulk_lock)
+  {
+    s->bulk_requests++;
+    return;
+  }
+
+  if (NULL != n)
+  {
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_START,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
+    distribute_bandwidth(s, n, address_except);
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_STOP,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
+    propagate_bandwidth(s, n, address_except);
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_SINGLE);
+  }
+  else
+  {
+    int i;
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_START,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
+    for (i = 0; i < s->network_count; i++)
+      distribute_bandwidth(s, &s->network_entries[i], NULL);
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, GAS_OP_SOLVE_STOP,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
+    for (i = 0; i < s->network_count; i++)
+    {
+      propagate_bandwidth(s, &s->network_entries[i], address_except);
+    }
+    if (NULL != s->env->info_cb)
+      s->env->info_cb(s->env->info_cb_cls, 
GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
+          GAS_STAT_SUCCESS, GAS_INFO_PROP_ALL);
+  }
+}
+
+/**
+ * Lookup network struct by type
+ *
+ * @param s the solver handle
+ * @param type the network type
+ * @return the network struct
+ */
+static struct Network *
+get_network (struct GAS_PROPORTIONAL_Handle *s, uint32_t type)
+{
+  int c;
+  for (c = 0; c < s->network_count; c++)
+  {
+    if (s->network_entries[c].type == type)
+      return &s->network_entries[c];
+  }
+  return NULL ;
+}
+
+/**
+ * Hashmap Iterator to find current active address for peer
+ *
+ * @param cls last active address
+ * @param key peer's key
+ * @param value address to check
+ * @return #GNUNET_NO on double active address else #GNUNET_YES;
+ */
+static int
+get_active_address_it (void *cls,
+                      const struct GNUNET_PeerIdentity *key,
+                      void *value)
+{
+  struct ATS_Address **dest = cls;
+  struct ATS_Address *aa = (struct ATS_Address *) value;
+
+  if (GNUNET_YES == aa->active)
+  {
+
+    if (NULL != (*dest))
+    {
+      /* should never happen */
+      LOG(GNUNET_ERROR_TYPE_ERROR, "Multiple active addresses for peer `%s'\n",
+          GNUNET_i2s (&aa->peer));
+      GNUNET_break(0);
+      return GNUNET_NO;
+    }
+    (*dest) = aa;
+  }
+  return GNUNET_OK;
+}
+
+/**
+ * Find current active address for peer
+ *
+ * @param solver the solver handle
+ * @param addresses the address set
+ * @param peer the peer
+ * @return active address or NULL
+ */
+static struct ATS_Address *
+get_active_address (void *solver,
+                   const struct GNUNET_CONTAINER_MultiPeerMap * addresses,
+                   const struct GNUNET_PeerIdentity *peer)
+{
+  struct ATS_Address * dest = NULL;
+
+  GNUNET_CONTAINER_multipeermap_get_multiple (addresses, peer,
+                                             &get_active_address_it, &dest);
+  return dest;
+}
+
+
+static void
+addresse_increment (struct GAS_PROPORTIONAL_Handle *s, struct Network *net,
+    int total, int active)
+{
+  if (GNUNET_YES == total)
+  {
+    s->total_addresses++;
+    net->total_addresses++;
+    GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", 1, GNUNET_NO);
+    GNUNET_STATISTICS_update (s->stats, net->stat_total, 1, GNUNET_NO);
+  }
+  if (GNUNET_YES == active)
+  {
+    net->active_addresses++;
+    s->active_addresses++;
+    GNUNET_STATISTICS_update (s->stats, "# ATS active addresses total", 1,
+        GNUNET_NO);
+    GNUNET_STATISTICS_update (s->stats, net->stat_active, 1, GNUNET_NO);
+  }
+
+}
+
+
+static int
+addresse_decrement (struct GAS_PROPORTIONAL_Handle *s, struct Network *net,
+    int total, int active)
+{
+  int res = GNUNET_OK;
+  if (GNUNET_YES == total)
+  {
+    if (s->total_addresses < 1)
+    {
+      GNUNET_break(0);
+      res = GNUNET_SYSERR;
+    }
+    else
+    {
+      s->total_addresses--;
+      GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1,
+          GNUNET_NO);
+    }
+    if (net->total_addresses < 1)
+    {
+      GNUNET_break(0);
+      res = GNUNET_SYSERR;
+    }
+    else
+    {
+      net->total_addresses--;
+      GNUNET_STATISTICS_update (s->stats, net->stat_total, -1, GNUNET_NO);
+    }
+  }
+
+  if (GNUNET_YES == active)
+  {
+    if (net->active_addresses < 1)
+    {
+      GNUNET_break(0);
+      res = GNUNET_SYSERR;
+    }
+    else
+    {
+      net->active_addresses--;
+      GNUNET_STATISTICS_update (s->stats, net->stat_active, -1, GNUNET_NO);
+    }
+    if (s->active_addresses < 1)
+    {
+      GNUNET_break(0);
+      res = GNUNET_SYSERR;
+    }
+    else
+    {
+      s->active_addresses--;
+      GNUNET_STATISTICS_update (s->stats, "# ATS addresses total", -1,
+          GNUNET_NO);
+    }
+  }
+  return res;
+}
+
+/**
+ *  Solver API functions
+ *  ---------------------------
+ */
+
+/**
+ * Changes the preferences for a peer in the problem
+ *
+ * @param solver the solver handle
+ * @param peer the peer to change the preference for
+ * @param kind the kind to change the preference
+ * @param pref_rel the normalized preference value for this kind over all 
clients
+ */
+void
+GAS_proportional_address_change_preference (void *solver,
+                                           const struct GNUNET_PeerIdentity 
*peer,
+                                           enum GNUNET_ATS_PreferenceKind kind,
+                                           double pref_rel)
+{
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+  GNUNET_assert(NULL != solver);
+  GNUNET_assert(NULL != peer);
+
+  distribute_bandwidth_in_network (s, NULL, NULL);
+}
+
+
+/**
+ * Get application feedback for a peer
+ *
+ * @param solver the solver handle
+ * @param application the application
+ * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_proportional_address_preference_feedback (void *solver, void *application,
+    const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_TIME_Relative scope,
+    enum GNUNET_ATS_PreferenceKind kind, double score)
+{
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+  GNUNET_assert(NULL != solver);
+  GNUNET_assert(NULL != peer);
+
+  GNUNET_assert(NULL != s);
+  GNUNET_break(0);
+}
+
+/**
+ * Get the preferred address for a specific peer
+ *
+ * @param solver the solver handle
+ * @param peer the identity of the peer
+ */
+const struct ATS_Address *
+GAS_proportional_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer)
+{
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+  struct Network *net_prev;
+  struct Network *net_cur;
+  struct ATS_Address *prev;
+  struct FindBestAddressCtx fba_ctx;
+  struct AddressSolverInformation *asi;
+  struct AddressSolverInformation *asi_prev;
+
+  GNUNET_assert(s != NULL);
+  GNUNET_assert(peer != NULL);
+
+  /* Add to list of pending requests */
+  if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (s->requests,
+                                                          peer))
+  {
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_CONTAINER_multipeermap_put (s->requests,
+                                                     peer, NULL,
+                                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  }
+
+  /* Get address with: stick to current address, lower distance, lower latency 
*/
+  fba_ctx.s = s;
+  fba_ctx.best = NULL;
+
+  GNUNET_CONTAINER_multipeermap_get_multiple (s->addresses, peer,
+                                             &find_best_address_it, &fba_ctx);
+  if (NULL == fba_ctx.best)
+  {
+    LOG(GNUNET_ERROR_TYPE_INFO, "Cannot suggest address for peer `%s'\n",
+        GNUNET_i2s (peer));
+    return NULL ;
+  }
+
+  LOG(GNUNET_ERROR_TYPE_INFO, "Suggesting %s address %p for peer `%s'\n",
+      (GNUNET_NO == fba_ctx.best->active) ? "inactive" : "active", 
fba_ctx.best,
+      GNUNET_i2s (peer));
+  asi = fba_ctx.best->solver_information;
+  net_cur = asi->network ;
+  if (NULL == fba_ctx.best)
+  {
+    LOG(GNUNET_ERROR_TYPE_ERROR,
+        "Trying to suggesting unknown address peer `%s'\n", GNUNET_i2s (peer));
+    GNUNET_break(0);
+    return NULL ;
+  }
+  if (GNUNET_YES == fba_ctx.best->active)
+  {
+    /* This address was selected previously, so no need to update quotas */
+    return fba_ctx.best;
+  }
+
+  /* This address was not active, so we have to:
+   *
+   * - mark previous active address as not active
+   * - update quota for previous address network
+   * - update quota for this address network
+   */
+  prev = get_active_address (s, s->addresses, peer);
+  if (NULL != prev)
+  {
+    asi_prev = prev->solver_information;
+    net_prev = (struct Network *) asi_prev->network;
+    prev->active = GNUNET_NO; /* No active any longer */
+    prev->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
+    prev->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
+    if (GNUNET_SYSERR == addresse_decrement (s, net_prev, GNUNET_NO, 
GNUNET_YES))
+      GNUNET_break(0);
+    distribute_bandwidth_in_network (s, net_prev, NULL);
+  }
+
+  if (GNUNET_NO == (is_bandwidth_available_in_network (net_cur)))
+  {
+    GNUNET_break(0); /* This should never happen*/
+    return NULL ;
+  }
+
+  fba_ctx.best->active = GNUNET_YES;
+  addresse_increment (s, net_cur, GNUNET_NO, GNUNET_YES);
+  distribute_bandwidth_in_network (s, net_cur, fba_ctx.best);
+  return fba_ctx.best;
+}
+
+/**
+ * Stop notifying about address and bandwidth changes for this peer
+ *
+ * @param solver the solver handle
+ * @param peer the peer
+ */
+void
+GAS_proportional_stop_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer)
+{
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+  struct ATS_Address *cur;
+  struct AddressSolverInformation *asi;
+  struct Network *cur_net;
+
+  if (GNUNET_YES
+      == GNUNET_CONTAINER_multipeermap_contains (s->requests,
+                                                peer))
+    GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove 
(s->requests, peer,
+                                         NULL));
+
+  cur = get_active_address (s,
+                           s->addresses, peer);
+  if (NULL != cur)
+  {
+    /* Disabling current address */
+    asi = cur->solver_information;
+    cur_net = asi->network ;
+    cur->active = GNUNET_NO; /* No active any longer */
+    cur->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
+    cur->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
+    if (GNUNET_SYSERR == addresse_decrement (s, cur_net, GNUNET_NO, 
GNUNET_YES))
+      GNUNET_break(0);
+    distribute_bandwidth_in_network (s, cur_net, NULL );
+  }
+  return;
+}
+
+/**
+ * Remove an address from the solver
+ *
+ * @param solver the solver handle
+ * @param address the address to remove
+ * @param session_only delete only session not whole address
+ */
+void
+GAS_proportional_address_delete (void *solver, struct ATS_Address *address,
+    int session_only)
+{
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+  struct Network *net;
+  struct AddressWrapper *aw;
+  struct AddressSolverInformation *asi;
+  const struct ATS_Address *new_address;
+
+
+  /* Remove an adress completely, we have to:
+   * - Remove from specific network
+   * - Decrease number of total addresses
+   * - If active:
+   *   - decrease number of active addreses
+   *   - update quotas
+   */
+  asi = address->solver_information;
+
+  if (NULL == asi)
+  {
+    GNUNET_break (0);
+    return;
+  }
+
+  net = asi->network;
+
+  if (GNUNET_NO == session_only)
+  {
+    LOG(GNUNET_ERROR_TYPE_INFO,
+        "Deleting %s address %p for peer `%s' from network `%s' (total: %u/ 
active: %u)\n",
+        (GNUNET_NO == address->active) ? "inactive" : "active", address,
+        GNUNET_i2s (&address->peer), net->desc, net->total_addresses,
+        net->active_addresses);
+
+    /* Remove address */
+    addresse_decrement (s, net, GNUNET_YES, GNUNET_NO);
+    for (aw = net->head; NULL != aw; aw = aw->next)
+    {
+      if (aw->addr == address)
+        break;
+    }
+    if (NULL == aw)
+    {
+      GNUNET_break(0);
+      return;
+    }
+    GNUNET_CONTAINER_DLL_remove(net->head, net->tail, aw);
+    GNUNET_free_non_null (aw->addr->solver_information);
+    GNUNET_free(aw);
+  }
+  else
+  {
+    /* Remove session only: remove if active and update */
+    LOG(GNUNET_ERROR_TYPE_INFO,
+        "Deleting %s session %p for peer `%s' from network `%s' (total: %u/ 
active: %u)\n",
+        (GNUNET_NO == address->active) ? "inactive" : "active", address,
+        GNUNET_i2s (&address->peer), net->desc, net->total_addresses,
+        net->active_addresses);
+  }
+
+  if (GNUNET_YES == address->active)
+  {
+    /* Address was active, remove from network and update quotas*/
+    address->active = GNUNET_NO;
+    address->assigned_bw_in = BANDWIDTH_ZERO;
+    address->assigned_bw_out = BANDWIDTH_ZERO;
+
+    if (GNUNET_SYSERR == addresse_decrement (s, net, GNUNET_NO, GNUNET_YES))
+      GNUNET_break(0);
+    distribute_bandwidth_in_network (s, net, NULL);
+    if (NULL == (new_address = GAS_proportional_get_preferred_address (s, 
&address->peer)))
+    {
+      /* No alternative address found, disconnect peer */
+      s->bw_changed (s->bw_changed_cls, address);
+    }
+    else
+    {
+      s->bw_changed (s->bw_changed_cls, (struct ATS_Address *) new_address);
+    }
+  }
+  LOG(GNUNET_ERROR_TYPE_INFO,
+      "After deleting address now total %u and active %u addresses in network 
`%s'\n",
+      net->total_addresses, net->active_addresses, net->desc);
+
+}
+
+/**
+ * Start a bulk operation
+ *
+ * @param solver the solver
+ */
+void
+GAS_proportional_bulk_start (void *solver)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Locking solver for bulk operation ...\n");
+  struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *) 
solver;
+
+  GNUNET_assert(NULL != solver);
+  s->bulk_lock++;
+}
+
+
+/**
+ * Bulk operation done
+ */
+void
+GAS_proportional_bulk_stop (void *solver)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Unlocking solver from bulk operation ...\n");
+
+  struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *) 
solver;
+  GNUNET_assert(NULL != solver);
+
+  if (s->bulk_lock < 1)
+  {
+    GNUNET_break(0);
+    return;
+  }
+  s->bulk_lock--;
+  if ((0 == s->bulk_lock) && (0 < s->bulk_requests))
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "No lock pending, recalculating\n");
+    distribute_bandwidth_in_network (s, NULL, NULL);
+    s->bulk_requests = 0;
+  }
+}
+
+
+/**
+ * Add a new single address to a network
+ *
+ * @param solver the solver Handle
+ * @param address the address to add
+ * @param network network type of this address
+ */
+void
+GAS_proportional_address_add (void *solver, struct ATS_Address *address,
+    uint32_t network);
+
+/**
+ * Transport properties for this address have changed
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param type the ATSI type in HBO
+ * @param abs_value the absolute value of the property
+ * @param rel_value the normalized value
+ */
+void
+GAS_proportional_address_property_changed (void *solver,
+    struct ATS_Address *address, uint32_t type, uint32_t abs_value,
+    double rel_value)
+{
+  struct GAS_PROPORTIONAL_Handle *s;
+  struct Network *n;
+  struct AddressSolverInformation *asi;
+
+  GNUNET_assert(NULL != solver);
+  GNUNET_assert(NULL != address);
+
+  s = (struct GAS_PROPORTIONAL_Handle *) solver;
+  asi = address->solver_information;
+  n = asi->network;
+
+  if (NULL == n)
+  {
+    GNUNET_break(0);
+    return;
+  }
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "Property `%s' for peer `%s' address %p changed to %.2f \n",
+      GNUNET_ATS_print_property_type (type), GNUNET_i2s (&address->peer),
+      address, rel_value);
+  switch (type)
+  {
+  case GNUNET_ATS_UTILIZATION_OUT:
+  case GNUNET_ATS_UTILIZATION_IN:
+  case GNUNET_ATS_UTILIZATION_PAYLOAD_IN:
+  case GNUNET_ATS_UTILIZATION_PAYLOAD_OUT:
+  case GNUNET_ATS_QUALITY_NET_DELAY:
+  case GNUNET_ATS_QUALITY_NET_DISTANCE:
+  case GNUNET_ATS_COST_WAN:
+  case GNUNET_ATS_COST_LAN:
+  case GNUNET_ATS_COST_WLAN:
+    distribute_bandwidth_in_network (s, n, NULL);
+    break;
+  }
+}
+
+/**
+ * Transport session for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param cur_session the current session
+ * @param new_session the new session
+ */
+void
+GAS_proportional_address_session_changed (void *solver,
+    struct ATS_Address *address, uint32_t cur_session, uint32_t new_session)
+{
+  if (cur_session != new_session)
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Session changed from %u to %u\n", 
cur_session,
+        new_session);
+  }
+}
+
+/**
+ * Usage for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param in_use usage state
+ */
+void
+GAS_proportional_address_inuse_changed (void *solver,
+    struct ATS_Address *address, int in_use)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Usage changed to %s\n",
+      (GNUNET_YES == in_use) ? "USED" : "UNUSED");
+}
+
+/**
+ * Network scope for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param current_network the current network
+ * @param new_network the new network
+ */
+void
+GAS_proportional_address_change_network (void *solver,
+    struct ATS_Address *address, uint32_t current_network, uint32_t 
new_network)
+{
+  struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *) 
solver;
+  struct AddressSolverInformation *asi;
+  int save_active = GNUNET_NO;
+
+  struct Network *new_net = NULL;
+
+  if (current_network == new_network)
+  {
+    GNUNET_break(0);
+    return;
+  }
+
+  /* Network changed */
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "Network type changed, moving %s address from `%s' to `%s'\n",
+      (GNUNET_YES == address->active) ? "active" : "inactive",
+      GNUNET_ATS_print_network_type (current_network),
+      GNUNET_ATS_print_network_type (new_network));
+
+  save_active = address->active;
+
+  /* Disable and assign no bandwidth */
+  address->active = GNUNET_NO;
+  address->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
+  address->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
+
+  /* Remove from old network */
+  GAS_proportional_address_delete (solver, address, GNUNET_NO);
+
+  /* Set new network type */
+  if (NULL == (new_net = get_network (solver, new_network)))
+  {
+    /* Address changed to invalid network... */
+    LOG(GNUNET_ERROR_TYPE_ERROR,
+        _("Invalid network type `%u' `%s': Disconnect!\n"), new_network,
+        GNUNET_ATS_print_network_type (new_network));
+
+    /* Find new address to suggest since no bandwidth in network*/
+    if (NULL == GAS_proportional_get_preferred_address (s, &address->peer))
+    {
+      /* No alternative address found, disconnect peer */
+      s->bw_changed (s->bw_changed_cls, address);
+    }
+    return;
+  }
+
+  /* Add to new network and update*/
+  asi = address->solver_information;
+  asi->network = new_net;
+  GAS_proportional_address_add (solver, address, new_network);
+  if (GNUNET_YES == save_active)
+  {
+    /* check if bandwidth available in new network */
+    if (GNUNET_YES == (is_bandwidth_available_in_network (new_net)))
+    {
+      /* Assign bandwidth to updated address */
+      address->active = GNUNET_YES;
+      addresse_increment (s, new_net, GNUNET_NO, GNUNET_YES);
+      distribute_bandwidth_in_network (solver, new_net, NULL);
+    }
+    else
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG,
+          "Not enough bandwidth in new network, suggesting alternative address 
..\n");
+      /* Find new address to suggest since no bandwidth in network*/
+      if (NULL == GAS_proportional_get_preferred_address (s, &address->peer))
+      {
+        /* No alternative address found, disconnect peer */
+        s->bw_changed (s->bw_changed_cls, address);
+      }
+    }
+  }
+}
+
+/**
+ * Add a new single address to a network
+ *
+ * @param solver the solver Handle
+ * @param address the address to add
+ * @param network network type of this address
+ */
+void
+GAS_proportional_address_add (void *solver, struct ATS_Address *address,
+    uint32_t network)
+{
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+  struct Network *net = NULL;
+  struct AddressWrapper *aw = NULL;
+  struct AddressSolverInformation *asi;
+
+  GNUNET_assert(NULL != s);
+  net = get_network (s, network);
+  if (NULL == net)
+  {
+    GNUNET_break(0);
+    return;
+  }
+
+  aw = GNUNET_malloc (sizeof (struct AddressWrapper));
+  aw->addr = address;
+  GNUNET_CONTAINER_DLL_insert(net->head, net->tail, aw);
+  addresse_increment (s, net, GNUNET_YES, GNUNET_NO);
+
+  asi = GNUNET_malloc (sizeof (struct AddressSolverInformation));
+  asi->network = net;
+  asi->calculated_quota_in_NBO = 0;
+  asi->calculated_quota_out_NBO = 0;
+  aw->addr->solver_information = asi;
+
+  if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (s->requests, 
&address->peer))
+  {
+    if (NULL == get_active_address (s, s->addresses, &address->peer))
+    {
+      if (NULL != GAS_proportional_get_preferred_address (s, &address->peer))
+          s->bw_changed (s->bw_changed_cls, (struct ATS_Address *) address);
+    }
+  }
+
+  LOG(GNUNET_ERROR_TYPE_INFO,
+      "Adding new address %p for peer `%s', now total %u and active %u 
addresses in network `%s'\n",
+      address, GNUNET_i2s(&address->peer), net->total_addresses, 
net->active_addresses, net->desc);
+}
+
+
+/* end of plugin_ats_proportional.c */

Copied: gnunet/src/ats/plugin_ats_proportional.h (from rev 31213, 
gnunet/src/ats/libgnunet_plugin_ats_proportional.h)
===================================================================
--- gnunet/src/ats/plugin_ats_proportional.h                            (rev 0)
+++ gnunet/src/ats/plugin_ats_proportional.h    2013-12-10 07:58:08 UTC (rev 
31244)
@@ -0,0 +1,186 @@
+/*
+ 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/plugin_ats_proportional.h
+ * @brief ATS proportional solver
+ * @author Matthias Wachs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_ats_plugin.h"
+#include "gnunet-service-ats_addresses.h"
+
+/**
+ * ATS proportional solver
+ *
+ * General description
+ */
+
+/**
+ * Changes the preferences for a peer in the problem
+ *
+ * @param solver the solver handle
+ * @param peer the peer to change the preference for
+ * @param kind the kind to change the preference
+ * @param pref_rel the normalized preference value for this kind over all 
clients
+ */
+void
+GAS_proportional_address_change_preference (void *solver,
+    const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind 
kind,
+    double pref_rel);
+
+/**
+ * Get application feedback for a peer
+ *
+ * @param solver the solver handle
+ * @param application the application
+ * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_proportional_address_preference_feedback (void *solver, void *application,
+    const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_TIME_Relative scope,
+    enum GNUNET_ATS_PreferenceKind kind, double score);
+
+/**
+ * Shutdown the proportional problem solver
+ *
+ * @param solver the respective handle to shutdown
+ */
+void
+GAS_proportional_done (void * solver);
+
+/**
+ * Add a single address within a network to the solver
+ *
+ * @param solver the solver Handle
+ * @param address the address to add
+ * @param network network type of this address
+ */
+void
+GAS_proportional_address_add (void *solver, struct ATS_Address *address,
+    uint32_t network);
+
+/**
+ * Transport properties for this address have changed
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param type the ATSI type in HBO
+ * @param abs_value the absolute value of the property
+ * @param rel_value the normalized value
+ */
+void
+GAS_proportional_address_property_changed (void *solver,
+    struct ATS_Address *address, uint32_t type, uint32_t abs_value,
+    double rel_value);
+
+/**
+ * Transport session for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param cur_session the current session
+ * @param new_session the new session
+ */
+void
+GAS_proportional_address_session_changed (void *solver,
+    struct ATS_Address *address, uint32_t cur_session, uint32_t new_session);
+
+/**
+ * Usage for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param in_use usage state
+ */
+void
+GAS_proportional_address_inuse_changed (void *solver,
+    struct ATS_Address *address, int in_use);
+
+/**
+ * Network scope for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param current_network the current network
+ * @param new_network the new network
+ */
+void
+GAS_proportional_address_change_network (void *solver,
+    struct ATS_Address *address, uint32_t current_network, uint32_t 
new_network);
+
+/**
+ * Remove an address from the solver
+ *
+ * @param solver the solver handle
+ * @param address the address to remove
+ * @param session_only delete only session not whole address
+ */
+void
+GAS_proportional_address_delete (void *solver, struct ATS_Address *address,
+    int session_only);
+
+/**
+ * Start a bulk operation
+ *
+ * @param solver the solver
+ */
+void
+GAS_proportional_bulk_start (void *solver);
+
+/**
+ * Bulk operation done
+ */
+void
+GAS_proportional_bulk_stop (void *solver);
+
+/**
+ * Stop notifying about address and bandwidth changes for this peer
+ *
+ * @param solver the proportional handle
+ * @param peer the peer
+ */
+void
+GAS_proportional_stop_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Get the prefered address for a specific peer
+ *
+ * @param solver the solver handle
+ * @param peer the identity of the peer
+ */
+const struct ATS_Address *
+GAS_proportional_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer);
+
+/* end of plugin_ats_proportional.h */

Copied: gnunet/src/ats/plugin_ats_ril.c (from rev 31243, 
gnunet/src/ats/libgnunet_plugin_ats_ril.c)
===================================================================
--- gnunet/src/ats/plugin_ats_ril.c                             (rev 0)
+++ gnunet/src/ats/plugin_ats_ril.c     2013-12-10 07:58:08 UTC (rev 31244)
@@ -0,0 +1,2420 @@
+/*
+ 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/plugin_ats_ril.c
+ * @brief ATS reinforcement learning solver
+ * @author Fabian Oehlmann
+ * @author Matthias Wachs
+ */
+#include "plugin_ats_ril.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "ats-ril",__VA_ARGS__)
+
+#define MIN_BW ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)
+
+#define RIL_ACTION_INVALID -1
+#define RIL_FEATURES_ADDRESS_COUNT (0)// + GNUNET_ATS_QualityPropertiesCount)
+#define RIL_FEATURES_NETWORK_COUNT 2
+#define RIL_INTERVAL_EXPONENT 10
+
+#define RIL_DEFAULT_STEP_TIME_MIN GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MILLISECONDS, 500)
+#define RIL_DEFAULT_STEP_TIME_MAX GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MILLISECONDS, 3000)
+#define RIL_DEFAULT_ALGORITHM RIL_ALGO_SARSA
+#define RIL_DEFAULT_DISCOUNT_BETA 1
+#define RIL_DEFAULT_DISCOUNT_GAMMA 0.5
+#define RIL_DEFAULT_GRADIENT_STEP_SIZE 0.1
+#define RIL_DEFAULT_TRACE_DECAY 0.5
+#define RIL_DEFAULT_EXPLORE_RATIO 0.1
+#define RIL_DEFAULT_GLOBAL_REWARD_SHARE 0.5
+
+#define RIL_INC_DEC_STEP_SIZE 1
+
+/**
+ * ATS reinforcement learning solver
+ *
+ * General description
+ */
+
+/**
+ * The actions, how an agent can manipulate the current assignment. I.e. how 
the bandwidth can be
+ * changed for the currently chosen address. Not depicted in the enum are the 
actions of switching
+ * to a particular address. The action of switching to address with index i is 
depicted by the
+ * number (RIL_ACTION_TYPE_NUM + i).
+ */
+enum RIL_Action_Type
+{
+  RIL_ACTION_NOTHING = -1,
+  RIL_ACTION_BW_IN_DBL = -2, //TODO! put actions back
+  RIL_ACTION_BW_IN_HLV = -3,
+  RIL_ACTION_BW_IN_INC = 0,
+  RIL_ACTION_BW_IN_DEC = 1,
+  RIL_ACTION_BW_OUT_DBL = -4,
+  RIL_ACTION_BW_OUT_HLV = -5,
+  RIL_ACTION_BW_OUT_INC = -6,
+  RIL_ACTION_BW_OUT_DEC = -7,
+  RIL_ACTION_TYPE_NUM = 1
+};
+
+enum RIL_Algorithm
+{
+  RIL_ALGO_SARSA = 0,
+  RIL_ALGO_Q = 1
+};
+
+enum RIL_E_Modification
+{
+  RIL_E_SET,
+  RIL_E_ZERO,
+  RIL_E_ACCUMULATE,
+  RIL_E_REPLACE
+};
+
+/**
+ * Global learning parameters
+ */
+struct RIL_Learning_Parameters
+{
+  /**
+   * The TD-algorithm to use
+   */
+  enum RIL_Algorithm algorithm;
+
+  /**
+   * Gradient-descent step-size
+   */
+  double alpha;
+
+  /**
+   * Learning discount variable in the TD-update for semi-MDPs
+   */
+  double beta;
+
+  /**
+   * Learning discount factor in the TD-update for MDPs
+   */
+  double gamma;
+
+  /**
+   * Trace-decay factor for eligibility traces
+   */
+  double lambda;
+
+  /**
+   * Ratio, with what probability an agent should explore in the e-greed policy
+   */
+  double explore_ratio;
+
+  /**
+   * How big the share of the global part of the reward signal is
+   */
+  double reward_global_share;
+
+  /**
+   * Minimal interval time between steps in milliseconds
+   */
+  struct GNUNET_TIME_Relative step_time_min;
+
+  /**
+   * Maximum interval time between steps in milliseconds
+   */
+  struct GNUNET_TIME_Relative step_time_max;
+};
+
+/**
+ * Wrapper for addresses to store them in agent's linked list
+ */
+struct RIL_Address_Wrapped
+{
+  /**
+   * Next in DLL
+   */
+  struct RIL_Address_Wrapped *next;
+
+  /**
+   * Previous in DLL
+   */
+  struct RIL_Address_Wrapped *prev;
+
+  /**
+   * The address
+   */
+  struct ATS_Address *address_naked;
+};
+
+struct RIL_Peer_Agent
+{
+  /**
+   * Next agent in solver's linked list
+   */
+  struct RIL_Peer_Agent *next;
+
+  /**
+   * Previous agent in solver's linked list
+   */
+  struct RIL_Peer_Agent *prev;
+
+  /**
+   * Environment handle
+   */
+  struct GAS_RIL_Handle *envi;
+
+  /**
+   * Peer ID
+   */
+  struct GNUNET_PeerIdentity peer;
+
+  /**
+   * Whether the agent is active or not
+   */
+  int is_active;
+
+  /**
+   * Number of performed time-steps
+   */
+  unsigned long long step_count;
+
+  /**
+   * Experience matrix W
+   */
+  double ** W;
+
+  /**
+   * Number of rows of W / Number of state-vector features
+   */
+  unsigned int m;
+
+  /**
+   * Number of columns of W / Number of actions
+   */
+  unsigned int n;
+
+  /**
+   * Last perceived state feature vector
+   */
+  double * s_old;
+
+  /**
+   * Last chosen action
+   */
+  int a_old;
+
+  /**
+   * Eligibility trace vector
+   */
+  double * e;
+
+  /**
+   * Address in use
+   */
+  struct ATS_Address * address_inuse;
+
+  /**
+   * Head of addresses DLL
+   */
+  struct RIL_Address_Wrapped * addresses_head;
+
+  /**
+   * Tail of addresses DLL
+   */
+  struct RIL_Address_Wrapped * addresses_tail;
+
+  /**
+   * Inbound bandwidth assigned by the agent
+   */
+  unsigned long long bw_in;
+
+  /**
+   * Outbound bandwidth assigned by the agent
+   */
+  unsigned long long bw_out;
+
+  /**
+   * Flag whether a suggestion has to be issued
+   */
+  int suggestion_issue;
+
+  /**
+   * The address which has to be issued
+   */
+  struct ATS_Address * suggestion_address;
+};
+
+struct RIL_Network
+{
+  /**
+   * ATS network type
+   */
+  enum GNUNET_ATS_Network_Type type;
+
+  /**
+   * Total available inbound bandwidth
+   */
+  unsigned long long bw_in_available;
+
+  /**
+   * Bandwidth inbound assigned in network after last step
+   */
+  unsigned long long bw_in_assigned;
+
+  /**
+   * Total available outbound bandwidth
+   */
+  unsigned long long bw_out_available;
+
+  /**
+   * * Bandwidth outbound assigned in network after last step
+   */
+  unsigned long long bw_out_assigned;
+};
+
+/**
+ * A handle for the reinforcement learning solver
+ */
+struct GAS_RIL_Handle
+{
+  /**
+   * The solver-plugin environment of the solver-plugin API
+   */
+  struct GNUNET_ATS_PluginEnvironment *plugin_envi;
+
+  /**
+   * Statistics handle
+   */
+  struct GNUNET_STATISTICS_Handle *stats;
+
+  /**
+   * Number of performed steps
+   */
+  unsigned long long step_count;
+
+  /**
+   * Timestamp for the last time-step
+   */
+  struct GNUNET_TIME_Absolute step_time_last;
+
+  /**
+   * Task identifier of the next time-step to be executed
+   */
+  GNUNET_SCHEDULER_TaskIdentifier step_next_task_id;
+
+  /**
+   * Variable discount factor, dependent on time between steps
+   */
+  double global_discount_variable;
+
+  /**
+   * Integrated variable discount factor, dependent on time between steps
+   */
+  double global_discount_integrated;
+
+  /**
+   * State vector for networks for the current step
+   */
+  double *global_state_networks;
+
+  /**
+   * Lock for bulk operations
+   */
+  int bulk_lock;
+
+  /**
+   * Number of changes during a lock
+   */
+  int bulk_changes;
+
+  /**
+   * Learning parameters
+   */
+  struct RIL_Learning_Parameters parameters;
+
+  /**
+   * Array of networks with global assignment state
+   */
+  struct RIL_Network * network_entries;
+
+  /**
+   * Networks count
+   */
+  unsigned int networks_count;
+
+  /**
+   * List of active peer-agents
+   */
+  struct RIL_Peer_Agent * agents_head;
+  struct RIL_Peer_Agent * agents_tail;
+
+  /**
+   * Shutdown
+   */
+  int done;
+
+  /**
+   * Simulate steps, i.e. schedule steps immediately
+   */
+  unsigned long long simulate;
+};
+
+/*
+ *  Private functions
+ *  ---------------------------
+ */
+
+static int
+ril_count_agents(struct GAS_RIL_Handle * solver);
+
+/**
+ * Estimate the current action-value for state s and action a
+ *
+ * @param agent agent performing the estimation
+ * @param state s
+ * @param action a
+ * @return estimation value
+ */
+static double
+agent_estimate_q (struct RIL_Peer_Agent *agent, double *state, int action)
+{
+  int i;
+  double result = 0;
+
+  for (i = 0; i < agent->m; i++)
+  {
+    result += state[i] * agent->W[action][i];
+  }
+
+  GNUNET_assert(!isnan(result));
+
+  if (isinf(result))
+  {
+    return isinf(result) * UINT32_MAX; //TODO! fix
+  }
+
+  return result;
+}
+
+/**
+ * Decide whether to do exploration (i.e. taking a new action) or exploitation 
(i.e. taking the
+ * currently estimated best action) in the current step
+ *
+ * @param agent agent performing the step
+ * @return yes, if exploring
+ */
+static int
+agent_decide_exploration (struct RIL_Peer_Agent *agent)
+{
+  //TODO? Future Work: Improve exploration/exploitation trade-off by different 
mechanisms than e-greedy
+  double r = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+      UINT32_MAX) / (double) UINT32_MAX;
+
+  if (r < agent->envi->parameters.explore_ratio)
+  {
+    return GNUNET_YES;
+  }
+  return GNUNET_NO;
+}
+
+  /**
+   * Get the index of the address in the agent's list.
+   *
+   * @param agent agent handle
+   * @param address address handle
+   * @return the index, starting with zero
+   */
+static int
+agent_address_get_index (struct RIL_Peer_Agent *agent, struct ATS_Address 
*address)
+{
+  int i;
+  struct RIL_Address_Wrapped *cur;
+
+  i = -1;
+  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
+  {
+    i++;
+    if (cur->address_naked == address)
+    {
+      return i;
+    }
+  }
+
+  return i;
+}
+
+/**
+ * Gets the wrapped address from the agent's list
+ *
+ * @param agent agent handle
+ * @param address address handle
+ * @return wrapped address
+ */
+static struct RIL_Address_Wrapped *
+agent_address_get (struct RIL_Peer_Agent *agent, struct ATS_Address *address)
+{
+  struct RIL_Address_Wrapped *cur;
+
+  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
+  {
+    if (cur->address_naked == address)
+    {
+      return cur;
+    }
+  }
+
+  return NULL ;
+}
+
+/**
+ * Gets the action, with the maximal estimated Q-value (i.e. the one currently 
estimated to bring the
+ * most reward in the future)
+ *
+ * @param agent agent performing the calculation
+ * @param state the state from which to take the action
+ * @return the action promising most future reward
+ */
+static int
+agent_get_action_best (struct RIL_Peer_Agent *agent, double *state)
+{
+  int i;
+  int max_i = RIL_ACTION_INVALID;
+  double cur_q;
+  double max_q = -DBL_MAX;
+
+  for (i = 0; i < agent->n; i++)
+  {
+    cur_q = agent_estimate_q (agent, state, i);
+    if (cur_q > max_q)
+    {
+      max_q = cur_q;
+      max_i = i;
+    }
+  }
+
+  GNUNET_assert(RIL_ACTION_INVALID != max_i);
+
+  return max_i;
+}
+
+/**
+ * Gets any action, to explore the action space from that state
+ *
+ * @param agent agent performing the calculation
+ * @param state the state from which to take the action
+ * @return any action
+ */
+static int
+agent_get_action_explore (struct RIL_Peer_Agent *agent, double *state)
+{
+  // TODO?: Future Work: Choose the action for exploration, which has been 
explored the least in this state
+  return GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, agent->n);
+}
+
+/**
+ * Updates the weights (i.e. coefficients) of the weight vector in matrix W 
for action a
+ *
+ * @param agent the agent performing the update
+ * @param reward the reward received for the last action
+ * @param s_next the new state, the last step got the agent into
+ * @param a_prime the new
+ */
+static void
+agent_update_weights (struct RIL_Peer_Agent *agent, double reward, double 
*s_next, int a_prime)
+{
+  int i;
+  double delta;
+  double *theta = agent->W[agent->a_old];
+
+  delta = agent->envi->global_discount_integrated * reward; //reward
+  delta += agent->envi->global_discount_variable * agent_estimate_q (agent, 
s_next, a_prime); //discounted future value
+  delta -= agent_estimate_q (agent, agent->s_old, agent->a_old); //one step
+
+  LOG(GNUNET_ERROR_TYPE_INFO, "update()   Step# %llu  Q(s,a): %f  a: %f  r: %f 
 y: %f  Q(s+1,a+1) = %f  delta: %f\n",
+      agent->step_count,
+      agent_estimate_q (agent, agent->s_old, agent->a_old),
+      agent->envi->parameters.alpha,
+      reward,
+      agent->envi->global_discount_variable,
+      agent_estimate_q (agent, s_next, a_prime),
+      delta);
+
+  for (i = 0; i < agent->m; i++)
+  {
+//    LOG(GNUNET_ERROR_TYPE_INFO, "alpha = %f   delta = %f   e[%d] = %f\n",
+//        agent->envi->parameters.alpha,
+//        delta,
+//        i,
+//        agent->e[i]);
+    theta[i] += agent->envi->parameters.alpha * delta * agent->s_old[i];// * 
agent->e[i];
+  }
+}
+
+/**
+ * Changes the eligibility trace vector e in various manners:
+ * RIL_E_ACCUMULATE - adds 1 to each component as in accumulating eligibility 
traces
+ * RIL_E_REPLACE - resets each component to 1 as in replacing traces
+ * RIL_E_SET - multiplies e with discount factor and lambda as in the update 
rule
+ * RIL_E_ZERO - sets e to 0 as in Watkin's Q-learning algorithm when exploring 
and when initializing
+ *
+ * @param agent the agent handle
+ * @param mod the kind of modification
+ */
+static void
+agent_modify_eligibility (struct RIL_Peer_Agent *agent, enum 
RIL_E_Modification mod, double *f)
+{
+  int i;
+  double *e = agent->e;
+
+  for (i = 0; i < agent->m; i++)
+  {
+    switch (mod)
+    {
+    case RIL_E_ACCUMULATE:
+      e[i] += f[i];
+      break;
+    case RIL_E_REPLACE:
+      e[i] = f[i];
+      break;
+    case RIL_E_SET:
+      e[i] *= agent->envi->global_discount_variable * 
agent->envi->parameters.lambda;
+      break;
+    case RIL_E_ZERO:
+      e[i] = 0;
+      break;
+    }
+  }
+}
+
+static void
+ril_inform (struct GAS_RIL_Handle *solver,
+    enum GAS_Solver_Operation op,
+    enum GAS_Solver_Status stat)
+{
+  if (NULL != solver->plugin_envi->info_cb)
+    solver->plugin_envi->info_cb (solver->plugin_envi->info_cb_cls, op, stat, 
GAS_INFO_NONE);
+}
+
+/**
+ * Changes the active assignment suggestion of the handler and invokes the 
bw_changed callback to
+ * notify ATS of its new decision
+ *
+ * @param solver solver handle
+ * @param agent agent handle
+ * @param new_address the address which is to be used
+ * @param new_bw_in the new amount of inbound bandwidth set for this address
+ * @param new_bw_out the new amount of outbound bandwidth set for this address
+ * @param silent disables invocation of the bw_changed callback, if GNUNET_YES
+ */
+static void
+envi_set_active_suggestion (struct GAS_RIL_Handle *solver,
+    struct RIL_Peer_Agent *agent,
+    struct ATS_Address *new_address,
+    unsigned long long new_bw_in,
+    unsigned long long new_bw_out,
+    int silent)
+{
+  int notify = GNUNET_NO;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "    set_active_suggestion() for peer '%s'\n", 
GNUNET_i2s (&agent->peer));
+
+  //address change
+  if (agent->address_inuse != new_address)
+  {
+    if (NULL != agent->address_inuse)
+    {
+      agent->address_inuse->active = GNUNET_NO;
+      agent->address_inuse->assigned_bw_in.value__ = htonl (0);
+      agent->address_inuse->assigned_bw_out.value__ = htonl (0);
+    }
+    if (NULL != new_address)
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG, "    set address active: %s\n", 
agent->is_active ? "yes" : "no");
+      new_address->active = agent->is_active;
+      new_address->assigned_bw_in.value__ = htonl (agent->bw_in);
+      new_address->assigned_bw_out.value__ = htonl (agent->bw_out);
+    }
+    notify |= GNUNET_YES;
+  }
+
+  if (new_address)
+  {
+    //activity change
+    if (new_address->active != agent->is_active)
+    {
+      new_address->active = agent->is_active;
+      notify |= GNUNET_YES;
+    }
+
+    //bw change
+    if (agent->bw_in != new_bw_in)
+    {
+      agent->bw_in = new_bw_in;
+      new_address->assigned_bw_in.value__ = htonl (new_bw_in);
+      notify |= GNUNET_YES;
+    }
+    if (agent->bw_out != new_bw_out)
+    {
+      agent->bw_out = new_bw_out;
+      new_address->assigned_bw_out.value__ = htonl (new_bw_out);
+      notify |= GNUNET_YES;
+    }
+  }
+
+  if (notify && agent->is_active && (GNUNET_NO == silent))
+  {
+    if (new_address)
+    {
+      LOG(GNUNET_ERROR_TYPE_DEBUG, "    envi_set_active_suggestion() 
notify\n");
+      agent->suggestion_issue = GNUNET_YES;
+      agent->suggestion_address = new_address;
+    }
+    else if (agent->address_inuse)
+    {
+      //disconnect case, no new address
+      GNUNET_assert(0 == ntohl (agent->address_inuse->assigned_bw_in.value__));
+      GNUNET_assert(0 == ntohl 
(agent->address_inuse->assigned_bw_out.value__));
+      agent->bw_in = 0;
+      agent->bw_out = 0;
+
+      agent->suggestion_issue = GNUNET_YES;
+      agent->suggestion_address = agent->address_inuse;
+    }
+  }
+  agent->address_inuse = new_address;
+}
+
+static unsigned long long
+ril_network_get_assigned (struct GAS_RIL_Handle *solver, enum 
GNUNET_ATS_Network_Type type, int direction_in)
+{
+  struct RIL_Peer_Agent *cur;
+  struct RIL_Network *net;
+  unsigned long long sum = 0;
+
+  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
+  {
+    if (cur->is_active && cur->address_inuse)
+    {
+      net = cur->address_inuse->solver_information;
+      if (net->type == type)
+      {
+        if (direction_in)
+          sum += cur->bw_in;
+        else
+          sum += cur->bw_out;
+      }
+    }
+  }
+
+  return sum;
+}
+
+//static void
+//envi_state_networks (struct GAS_RIL_Handle *solver)
+//{
+//  int i;
+//  struct RIL_Network net;
+//  int overutilized_in;
+//  int overutilized_out;
+//
+//  for (i = 0; i < solver->networks_count; i++)
+//  {
+//    net = solver->network_entries[i];
+//
+//    overutilized_in = net.bw_in_assigned > net.bw_in_available;
+//    overutilized_out = net.bw_out_assigned > net.bw_out_available;
+//
+//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 0] = 
((double) net.bw_in_assigned / (double) net.bw_in_available)*10;
+//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 1] = 
(double) overutilized_in;
+//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 2] = 
((double) net.bw_out_assigned / (double) net.bw_out_available)*10;
+//    solver->global_state_networks[i * RIL_FEATURES_NETWORK_COUNT + 3] = 
(double) overutilized_out;
+//  }
+//}
+
+/**
+ * Allocates a state vector and fills it with the features present
+ * @param solver the solver handle
+ * @param agent the agent handle
+ * @return pointer to the state vector
+ */
+static double *
+envi_get_state (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
+{
+  int i;
+//  int k;
+  double *state = GNUNET_malloc (sizeof (double) * agent->m);
+  struct RIL_Address_Wrapped *cur_address;
+//  const double *preferences;
+//  const double *properties;
+  struct RIL_Network *net;
+
+  //copy global networks state
+  for (i = 0; i < solver->networks_count * RIL_FEATURES_NETWORK_COUNT; i++)
+  {
+//    state[i] = solver->global_state_networks[i];
+  }
+  net = agent->address_inuse->solver_information;
+
+  state[0] = (double) net->bw_in_assigned / 1024; //(double) 
net->bw_in_available;
+  if (net->bw_in_assigned > net->bw_in_available)
+  {
+    state[1] = 1;// net->bw_in_available;
+  }
+  else
+  {
+    state[1] = 0;
+  }
+  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  state[0] = %f\n", state[0]);
+  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  state[1] = %f\n", state[1]);
+
+  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  W / %08.3f %08.3f \\ \n", 
agent->W[0][0], agent->W[1][0]);
+  LOG(GNUNET_ERROR_TYPE_INFO, "get_state()  W \\ %08.3f %08.3f / \n", 
agent->W[0][1], agent->W[1][1]);
+
+
+  //get peer features
+//  preferences = solver->plugin_envi->get_preferences 
(solver->plugin_envi->get_preference_cls,
+//        &agent->peer);
+//  for (k = 0; k < GNUNET_ATS_PreferenceCount; k++)
+//  {
+//    state[i++] = preferences[k];
+//  }
+
+  //get address specific features
+  for (cur_address = agent->addresses_head; NULL != cur_address; cur_address = 
cur_address->next)
+  {
+//    //when changing the number of address specific state features, change 
RIL_FEATURES_ADDRESS_COUNT macro
+//    state[i++] = cur_address->address_naked->active;
+//    state[i++] = cur_address->address_naked->active ? agent->bw_in : 0;
+//    state[i++] = cur_address->address_naked->active ? agent->bw_out : 0;
+//    properties = solver->plugin_envi->get_property 
(solver->plugin_envi->get_property_cls,
+//        cur_address->address_naked);
+//    for (k = 0; k < GNUNET_ATS_QualityPropertiesCount; k++)
+//    {
+//      state[i++] = properties[k];
+//    }
+  }
+
+  return state;
+}
+
+///**
+// * For all networks a peer has an address in, this gets the maximum 
bandwidth which could
+// * theoretically be available in one of the networks. This is used for 
bandwidth normalization.
+// *
+// * @param agent the agent handle
+// * @param direction_in whether the inbound bandwidth should be considered. 
Returns the maximum outbound bandwidth if GNUNET_NO
+// */
+//static unsigned long long
+//ril_get_max_bw (struct RIL_Peer_Agent *agent, int direction_in)
+//{
+//  /*
+//   * get the maximum bandwidth possible for a peer, e.g. among all addresses 
which addresses'
+//   * network could provide the maximum bandwidth if all that bandwidth was 
used on that one peer.
+//   */
+//  unsigned long long max = 0;
+//  struct RIL_Address_Wrapped *cur;
+//  struct RIL_Network *net;
+//
+//  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
+//  {
+//    net = cur->address_naked->solver_information;
+//    if (direction_in)
+//    {
+//      if (net->bw_in_available > max)
+//      {
+//        max = net->bw_in_available;
+//      }
+//    }
+//    else
+//    {
+//      if (net->bw_out_available > max)
+//      {
+//        max = net->bw_out_available;
+//      }
+//    }
+//  }
+//  return max;
+//}
+
+///**
+// * Get the index of the quality-property in question
+// *
+// * @param type the quality property type
+// * @return the index
+// */
+//static int
+//ril_find_property_index (uint32_t type)
+//{
+//  int existing_types[] = GNUNET_ATS_QualityProperties;
+//  int c;
+//  for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+//    if (existing_types[c] == type)
+//      return c;
+//  return GNUNET_SYSERR;
+//}
+
+//static int
+//ril_get_atsi (struct ATS_Address *address, uint32_t type)
+//{
+//  int c1;
+//  GNUNET_assert(NULL != address);
+//
+//  if ((NULL == address->atsi) || (0 == address->atsi_count))
+//    return 0;
+//
+//  for (c1 = 0; c1 < address->atsi_count; c1++)
+//  {
+//    if (ntohl (address->atsi[c1].type) == type)
+//      return ntohl (address->atsi[c1].value);
+//  }
+//  return 0;
+//}
+
+//static double
+//envi_reward_global (struct GAS_RIL_Handle *solver)
+//{
+//  int i;
+//  struct RIL_Network net;
+//  unsigned int sum_in_available = 0;
+//  unsigned int sum_out_available = 0;
+//  unsigned int sum_in_assigned = 0;
+//  unsigned int sum_out_assigned = 0;
+//  double ratio_in;
+//  double ratio_out;
+//
+//  for (i = 0; i < solver->networks_count; i++)
+//  {
+//    net = solver->network_entries[i];
+//    sum_in_available += net.bw_in_available;
+//    sum_in_assigned += net.bw_in_assigned;
+//    sum_out_available += net.bw_out_available;
+//    sum_out_assigned += net.bw_out_assigned;
+//  }
+//
+//  ratio_in = ((double) sum_in_assigned) / ((double) sum_in_available);
+//  ratio_out = ((double) sum_out_assigned) / ((double) sum_out_available);
+//
+//  // global reward in [1,2]
+//  return ratio_in +1;
+//  return ((ratio_in + ratio_out) / 2) + 1;
+//}
+
+//static double
+//envi_reward_local (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent)
+//{
+//  const double *preferences;
+//  const double *properties;
+//  int prop_index;
+//  double pref_match = 0;
+//  double bw_norm;
+//  double dl_norm;
+//
+//  preferences = solver->plugin_envi->get_preferences 
(solver->plugin_envi->get_preference_cls,
+//      &agent->peer);
+//  properties = solver->plugin_envi->get_property 
(solver->plugin_envi->get_property_cls,
+//      agent->address_inuse);
+//
+//  // delay in [0,1]
+//  prop_index = ril_find_property_index (GNUNET_ATS_QUALITY_NET_DELAY);
+//  dl_norm = 2 - properties[prop_index]; //invert property as we want to 
maximize for lower latencies
+//
+//  // utilization in [0,1]
+//  bw_norm = (((double) ril_get_atsi (agent->address_inuse, 
GNUNET_ATS_UTILIZATION_IN)
+//      / (double) ril_get_max_bw (agent, GNUNET_YES))
+//      + ((double) ril_get_atsi (agent->address_inuse, 
GNUNET_ATS_UTILIZATION_OUT)
+//          / (double) ril_get_max_bw (agent, GNUNET_NO))) / 2;
+//
+//  // preference matching in [0,4]
+//  pref_match += (preferences[GNUNET_ATS_PREFERENCE_LATENCY] * dl_norm);
+//  pref_match += (preferences[GNUNET_ATS_PREFERENCE_BANDWIDTH] * bw_norm);
+//
+//  // local reward in [1,2]
+//  return (pref_match / 4) +1;
+//}
+
+/**
+ * Gets the reward for the last performed step, which is calculated in equal
+ * parts from the local (the peer specific) and the global (for all peers
+ * identical) reward.
+ *
+ * @param solver the solver handle
+ * @param agent the agent handle
+ * @return the reward
+ */
+static double
+envi_get_reward (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
+{
+  struct RIL_Network *net;
+//  double reward = 0;
+  long long overutilized_in = 0;
+//  long long overutilized_out;
+  long long assigned_in = 0;
+//  long long assigned_out = 0;
+//  long long unused;
+
+  //punish overutilization
+  net = agent->address_inuse->solver_information;
+
+  if (net->bw_in_assigned > net->bw_in_available)
+  {
+    overutilized_in = (net->bw_in_assigned - net->bw_in_available);
+    assigned_in = net->bw_in_available;
+  }
+  else
+  {
+    assigned_in = net->bw_in_assigned;
+  }
+//  if (net->bw_out_assigned > net->bw_out_available)
+//  {
+//    overutilized_out = (net->bw_out_assigned - net->bw_out_available);
+//    assigned_out = net->bw_out_available;
+//  }
+//  else
+//  {
+//    assigned_out = net->bw_out_assigned;
+//  }
+
+//  unused = net->bw_in_available - net->bw_in_assigned;
+//  unused = unused < 0 ? unused : -unused;
+
+  return (double) (assigned_in - overutilized_in) / 1024;
+
+//  reward += envi_reward_global (solver) * 
(solver->parameters.reward_global_share);
+//  reward += envi_reward_local (solver, agent) * (1 - 
solver->parameters.reward_global_share);
+//
+//  return (reward - 1.) * 100;
+}
+
+/**
+ * Doubles the bandwidth for the active address
+ *
+ * @param solver solver handle
+ * @param agent agent handle
+ * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise the 
outbound bandwidth
+ */
+static void
+envi_action_bw_double (struct GAS_RIL_Handle *solver,
+    struct RIL_Peer_Agent *agent,
+    int direction_in)
+{
+  unsigned long long new_bw;
+
+  if (direction_in)
+  {
+    new_bw = agent->bw_in * 2;
+    if (new_bw < agent->bw_in || new_bw > GNUNET_ATS_MaxBandwidth)
+      new_bw = GNUNET_ATS_MaxBandwidth;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
+        agent->bw_out, GNUNET_NO);
+  }
+  else
+  {
+    new_bw = agent->bw_out * 2;
+    if (new_bw < agent->bw_out || new_bw > GNUNET_ATS_MaxBandwidth)
+      new_bw = GNUNET_ATS_MaxBandwidth;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in,
+        new_bw, GNUNET_NO);
+  }
+}
+
+/**
+ * Cuts the bandwidth for the active address in half. The least amount of 
bandwidth suggested, is
+ * the minimum bandwidth for a peer, in order to not invoke a disconnect.
+ *
+ * @param solver solver handle
+ * @param agent agent handle
+ * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise 
change the outbound
+ * bandwidth
+ */
+static void
+envi_action_bw_halven (struct GAS_RIL_Handle *solver,
+    struct RIL_Peer_Agent *agent,
+    int direction_in)
+{
+  unsigned long long new_bw;
+
+  if (direction_in)
+  {
+    new_bw = agent->bw_in / 2;
+    if (new_bw < MIN_BW || new_bw > agent->bw_in)
+      new_bw = MIN_BW;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, 
agent->bw_out,
+        GNUNET_NO);
+  }
+  else
+  {
+    new_bw = agent->bw_out / 2;
+    if (new_bw < MIN_BW || new_bw > agent->bw_out)
+      new_bw = MIN_BW;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in, new_bw,
+        GNUNET_NO);
+  }
+}
+
+/**
+ * Increases the bandwidth by 5 times the minimum bandwidth for the active 
address.
+ *
+ * @param solver solver handle
+ * @param agent agent handle
+ * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise 
change the outbound
+ * bandwidth
+ */
+static void
+envi_action_bw_inc (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent, int direction_in)
+{
+  unsigned long long new_bw;
+
+  if (direction_in)
+  {
+    new_bw = agent->bw_in + (RIL_INC_DEC_STEP_SIZE * MIN_BW);
+    if (new_bw < agent->bw_in || new_bw > GNUNET_ATS_MaxBandwidth)
+      new_bw = GNUNET_ATS_MaxBandwidth;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
+        agent->bw_out, GNUNET_NO);
+  }
+  else
+  {
+    new_bw = agent->bw_out + (RIL_INC_DEC_STEP_SIZE * MIN_BW);
+    if (new_bw < agent->bw_out || new_bw > GNUNET_ATS_MaxBandwidth)
+      new_bw = GNUNET_ATS_MaxBandwidth;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in,
+        new_bw, GNUNET_NO);
+  }
+}
+
+/**
+ * Decreases the bandwidth by 5 times the minimum bandwidth for the active 
address. The least amount
+ * of bandwidth suggested, is the minimum bandwidth for a peer, in order to 
not invoke a disconnect.
+ *
+ * @param solver solver handle
+ * @param agent agent handle
+ * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise 
change the outbound
+ * bandwidth
+ */
+static void
+envi_action_bw_dec (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent, int direction_in)
+{
+  unsigned long long new_bw;
+
+  if (direction_in)
+  {
+    new_bw = agent->bw_in - (RIL_INC_DEC_STEP_SIZE * MIN_BW);
+    if (new_bw < MIN_BW || new_bw > agent->bw_in)
+      new_bw = MIN_BW;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw, 
agent->bw_out,
+        GNUNET_NO);
+  }
+  else
+  {
+    new_bw = agent->bw_out - (RIL_INC_DEC_STEP_SIZE * MIN_BW);
+    if (new_bw < MIN_BW || new_bw > agent->bw_out)
+      new_bw = MIN_BW;
+    envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in, new_bw,
+        GNUNET_NO);
+  }
+}
+
+/**
+ * Switches to the address given by its index
+ *
+ * @param solver solver handle
+ * @param agent agent handle
+ * @param address_index index of the address as it is saved in the agent's 
list, starting with zero
+ */
+static void
+envi_action_address_switch (struct GAS_RIL_Handle *solver,
+    struct RIL_Peer_Agent *agent,
+    unsigned int address_index)
+{
+  struct RIL_Address_Wrapped *cur;
+  int i = 0;
+
+  for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
+  {
+    if (i == address_index)
+    {
+      envi_set_active_suggestion (solver, agent, cur->address_naked, 
agent->bw_in, agent->bw_out,
+          GNUNET_NO);
+      return;
+    }
+
+    i++;
+  }
+
+  //no address with address_index exists, in this case this action should not 
be callable
+  GNUNET_assert(GNUNET_NO);
+}
+
+/**
+ * Puts the action into effect by calling the according function
+ *
+ * @param solver the solver handle
+ * @param agent the action handle
+ * @param action the action to perform by the solver
+ */
+static void
+envi_do_action (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent, 
int action)
+{
+  int address_index;
+
+  switch (action)
+  {
+  case RIL_ACTION_NOTHING:
+    break;
+  case RIL_ACTION_BW_IN_DBL:
+    envi_action_bw_double (solver, agent, GNUNET_YES);
+    break;
+  case RIL_ACTION_BW_IN_HLV:
+    envi_action_bw_halven (solver, agent, GNUNET_YES);
+    break;
+  case RIL_ACTION_BW_IN_INC:
+    envi_action_bw_inc (solver, agent, GNUNET_YES);
+    break;
+  case RIL_ACTION_BW_IN_DEC:
+    envi_action_bw_dec (solver, agent, GNUNET_YES);
+    break;
+  case RIL_ACTION_BW_OUT_DBL:
+    envi_action_bw_double (solver, agent, GNUNET_NO);
+    break;
+  case RIL_ACTION_BW_OUT_HLV:
+    envi_action_bw_halven (solver, agent, GNUNET_NO);
+    break;
+  case RIL_ACTION_BW_OUT_INC:
+    envi_action_bw_inc (solver, agent, GNUNET_NO);
+    break;
+  case RIL_ACTION_BW_OUT_DEC:
+    envi_action_bw_dec (solver, agent, GNUNET_NO);
+    break;
+  default:
+    if ((action >= RIL_ACTION_TYPE_NUM) && (action < agent->n)) //switch 
address action
+    {
+      address_index = action - RIL_ACTION_TYPE_NUM;
+
+      GNUNET_assert(address_index >= 0);
+      GNUNET_assert(
+          address_index <= agent_address_get_index (agent, 
agent->addresses_tail->address_naked));
+
+      envi_action_address_switch (solver, agent, address_index);
+      break;
+    }
+    // error - action does not exist
+    GNUNET_assert(GNUNET_NO);
+  }
+}
+
+/**
+ * Performs one step of the Markov Decision Process. Other than in the 
literature the step starts
+ * after having done the last action a_old. It observes the new state s_next 
and the reward
+ * received. Then the coefficient update is done according to the SARSA or 
Q-learning method. The
+ * next action is put into effect.
+ *
+ * @param agent the agent performing the step
+ */
+static void
+agent_step (struct RIL_Peer_Agent *agent)
+{
+  int a_next = RIL_ACTION_INVALID;
+  int explore;
+  double *s_next;
+  double reward;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "    agent_step() Peer '%s', algorithm %s\n",
+      GNUNET_i2s (&agent->peer),
+      agent->envi->parameters.algorithm ? "Q" : "SARSA");
+
+  s_next = envi_get_state (agent->envi, agent);
+  reward = envi_get_reward (agent->envi, agent);
+  explore = agent_decide_exploration (agent);
+
+  switch (agent->envi->parameters.algorithm)
+  {
+  case RIL_ALGO_SARSA:
+    if (explore)
+    {
+      a_next = agent_get_action_explore (agent, s_next);
+    }
+    else
+    {
+      a_next = agent_get_action_best (agent, s_next);
+    }
+    if (RIL_ACTION_INVALID != agent->a_old)
+    {
+      //updates weights with selected action (on-policy), if not first step
+      agent_update_weights (agent, reward, s_next, a_next);
+      agent_modify_eligibility (agent, RIL_E_SET, s_next);
+    }
+    break;
+
+  case RIL_ALGO_Q:
+    a_next = agent_get_action_best (agent, s_next);
+    if (RIL_ACTION_INVALID != agent->a_old)
+    {
+      //updates weights with best action, disregarding actually selected 
action (off-policy), if not first step
+      agent_update_weights (agent, reward, s_next, a_next);
+    }
+    if (explore)
+    {
+      a_next = agent_get_action_explore (agent, s_next);
+      agent_modify_eligibility (agent, RIL_E_ZERO, NULL);
+    }
+    else
+    {
+      a_next = agent_get_action_best (agent, s_next);
+      agent_modify_eligibility (agent, RIL_E_SET, s_next);
+    }
+    break;
+  }
+
+  GNUNET_assert(RIL_ACTION_INVALID != a_next);
+
+  agent_modify_eligibility (agent, RIL_E_ACCUMULATE, s_next);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "step()  Step# %llu  R: %f  IN %llu  OUT 
%llu  A: %d\n",
+        agent->step_count,
+        reward,
+        agent->bw_in/1024,
+        agent->bw_out/1024,
+        a_next);
+
+  envi_do_action (agent->envi, agent, a_next);
+
+  GNUNET_free(agent->s_old);
+  agent->s_old = s_next;
+  agent->a_old = a_next;
+
+  agent->step_count += 1;
+}
+
+static void
+ril_step (struct GAS_RIL_Handle *solver);
+
+/**
+ * Task for the scheduler, which performs one step and lets the solver know 
that
+ * no further step is scheduled.
+ *
+ * @param cls the solver handle
+ * @param tc the task context for the scheduler
+ */
+static void
+ril_step_scheduler_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext 
*tc)
+{
+  struct GAS_RIL_Handle *solver = cls;
+
+  solver->step_next_task_id = GNUNET_SCHEDULER_NO_TASK;
+  ril_step (solver);
+}
+
+static double
+ril_get_used_resource_ratio (struct GAS_RIL_Handle *solver)
+{
+  int i;
+  struct RIL_Network net;
+  unsigned long long sum_assigned = 0;
+  unsigned long long sum_available = 0;
+  double ratio;
+
+  for (i = 0; i < solver->networks_count; i++)
+  {
+    net = solver->network_entries[i];
+    if (net.bw_in_assigned > 0) //only consider scopes where an address is 
actually active
+    {
+      sum_assigned += net.bw_in_assigned;
+      sum_assigned += net.bw_out_assigned;
+      sum_available += net.bw_in_available;
+      sum_available += net.bw_out_available;
+    }
+  }
+  if (sum_available > 0)
+  {
+    ratio = ((double) sum_assigned) / ((double) sum_available);
+  }
+  else
+  {
+    ratio = 0;
+  }
+
+  return ratio > 1 ? 1 : ratio; //overutilization possible, cap at 1
+}
+
+/**
+ * Lookup network struct by type
+ *
+ * @param s the solver handle
+ * @param type the network type
+ * @return the network struct
+ */
+static struct RIL_Network *
+ril_get_network (struct GAS_RIL_Handle *s, uint32_t type)
+{
+  int i;
+
+  for (i = 0; i < s->networks_count; i++)
+  {
+    if (s->network_entries[i].type == type)
+    {
+      return &s->network_entries[i];
+    }
+  }
+  return NULL ;
+}
+
+static int
+ril_network_is_not_full (struct GAS_RIL_Handle *solver, enum 
GNUNET_ATS_Network_Type network)
+{
+  struct RIL_Network *net;
+  struct RIL_Peer_Agent *agent;
+  unsigned long long address_count = 0;
+
+  for (agent = solver->agents_head; NULL != agent; agent = agent->next)
+  {
+    if (agent->address_inuse && agent->is_active)
+    {
+      net = agent->address_inuse->solver_information;
+      if (net->type == network)
+      {
+        address_count++;
+      }
+    }
+  }
+
+  net = ril_get_network (solver, network);
+  return (net->bw_in_available > MIN_BW * address_count) && 
(net->bw_out_available > MIN_BW * address_count);
+}
+
+static void
+ril_try_unblock_agent (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent 
*agent, int silent)
+{
+  struct RIL_Address_Wrapped *addr_wrap;
+  struct RIL_Network *net;
+
+  for (addr_wrap = agent->addresses_head; NULL != addr_wrap; addr_wrap = 
addr_wrap->next)
+  {
+    net = addr_wrap->address_naked->solver_information;
+    if (ril_network_is_not_full(solver, net->type))
+    {
+      if (NULL == agent->address_inuse)
+        envi_set_active_suggestion (solver, agent, addr_wrap->address_naked, 
MIN_BW, MIN_BW, silent);
+      return;
+    }
+  }
+  agent->address_inuse = NULL;
+}
+
+static void
+ril_calculate_discount (struct GAS_RIL_Handle *solver)
+{
+  struct GNUNET_TIME_Absolute time_now;
+  struct GNUNET_TIME_Relative time_delta;
+  double tau;
+
+  // MDP case - remove when debugged
+  if (solver->simulate)
+  {
+    solver->global_discount_variable = solver->parameters.gamma;
+    solver->global_discount_integrated = 1;
+    return;
+  }
+
+  // semi-MDP case
+
+  //calculate tau, i.e. how many real valued time units have passed, one time 
unit is one minimum time step
+  time_now = GNUNET_TIME_absolute_get ();
+  time_delta = GNUNET_TIME_absolute_get_difference (solver->step_time_last, 
time_now);
+  solver->step_time_last = time_now;
+  tau = (double) time_delta.rel_value_us
+      / (double) solver->parameters.step_time_min.rel_value_us;
+
+  //calculate reward discounts (once per step for all agents)
+  solver->global_discount_variable = pow (M_E, ((-1.) * ((double) 
solver->parameters.beta) * tau));
+  solver->global_discount_integrated = (1. - solver->global_discount_variable)
+      / (double) solver->parameters.beta;
+}
+
+static void
+ril_calculate_assigned_bwnet (struct GAS_RIL_Handle *solver)
+{
+  int c;
+  struct RIL_Network *net;
+
+  for (c = 0; c < solver->networks_count; c++)
+  {
+    net = &solver->network_entries[c];
+    net->bw_in_assigned = ril_network_get_assigned(solver, net->type, 
GNUNET_YES);
+    net->bw_out_assigned = ril_network_get_assigned(solver, net->type, 
GNUNET_NO);
+  }
+}
+
+/**
+ * Schedules the next global step in an adaptive way. The more resources are
+ * left, the earlier the next step is scheduled. This serves the reactivity of
+ * the solver to changed inputs.
+ *
+ * @param solver the solver handle
+ */
+static void
+ril_step_schedule_next (struct GAS_RIL_Handle *solver)
+{
+  double used_ratio;
+  double factor;
+  double y;
+  double offset;
+  struct GNUNET_TIME_Relative time_next;
+
+  used_ratio = ril_get_used_resource_ratio (solver);
+
+  GNUNET_assert(
+      solver->parameters.step_time_min.rel_value_us
+          <= solver->parameters.step_time_max.rel_value_us);
+
+  factor = (double) GNUNET_TIME_relative_subtract 
(solver->parameters.step_time_max,
+      solver->parameters.step_time_min).rel_value_us;
+  offset = (double) solver->parameters.step_time_min.rel_value_us;
+  y = factor * pow (used_ratio, RIL_INTERVAL_EXPONENT) + offset;
+
+  GNUNET_assert(y <= (double ) solver->parameters.step_time_max.rel_value_us);
+  GNUNET_assert(y >= (double ) solver->parameters.step_time_min.rel_value_us);
+
+  time_next = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, 
(unsigned long long) y);
+
+  if (solver->simulate)
+  {
+    time_next = GNUNET_TIME_UNIT_ZERO;
+  }
+
+  if ((GNUNET_SCHEDULER_NO_TASK == solver->step_next_task_id) && (GNUNET_NO == 
solver->done))
+  {
+    solver->step_next_task_id = GNUNET_SCHEDULER_add_delayed (time_next, 
&ril_step_scheduler_task,
+          solver);
+  }
+}
+
+/**
+ * Triggers one step per agent
+ * @param solver
+ */
+static void
+ril_step (struct GAS_RIL_Handle *solver)
+{
+  struct RIL_Peer_Agent *cur;
+
+  if (GNUNET_YES == solver->bulk_lock)
+  {
+    solver->bulk_changes++;
+    return;
+  }
+
+  ril_inform (solver, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS);
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "    RIL step number %d\n", solver->step_count);
+
+  if (0 == solver->step_count)
+  {
+    solver->step_time_last = GNUNET_TIME_absolute_get ();
+  }
+
+  ril_calculate_discount (solver);
+  ril_calculate_assigned_bwnet (solver);
+
+  //calculate network state vector
+//  envi_state_networks(solver);
+
+  //trigger one step per active, unblocked agent
+  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
+  {
+    if (cur->is_active)
+    {
+      if (NULL == cur->address_inuse)
+      {
+        ril_try_unblock_agent(solver, cur, GNUNET_NO);
+      }
+      if (cur->address_inuse)
+      {
+        agent_step (cur);
+      }
+    }
+  }
+
+  ril_calculate_assigned_bwnet (solver);
+
+  solver->step_count += 1;
+  ril_step_schedule_next (solver);
+
+  ril_inform (solver, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS);
+
+  ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START, 
GAS_STAT_SUCCESS);
+  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
+  {
+    if (cur->suggestion_issue) {
+      
solver->plugin_envi->bandwidth_changed_cb(solver->plugin_envi->bw_changed_cb_cls,
 cur->suggestion_address);
+      cur->suggestion_issue = GNUNET_NO;
+    }
+  }
+  ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP, GAS_STAT_SUCCESS);
+}
+
+static int
+ril_count_agents (struct GAS_RIL_Handle *solver)
+{
+  int c = 0;
+  struct RIL_Peer_Agent *cur_agent;
+
+  for (cur_agent = solver->agents_head; NULL != cur_agent; cur_agent = 
cur_agent->next)
+  {
+    c++;
+  }
+  return c;
+}
+
+static void
+agent_w_start (struct RIL_Peer_Agent *agent)
+{
+  int count;
+  struct RIL_Peer_Agent *other;
+  int i;
+  int k;
+
+  count = ril_count_agents(agent->envi);
+
+  for (i = 0; i < agent->n; i++)
+  {
+    for (k = 0; k < agent->m; k++)
+    {
+      if (0 == count) {
+        agent->W[i][k] = 1;//.1 - ((double) 
GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 
UINT32_MAX/5)/(double)UINT32_MAX);
+      }
+      else {
+        for (other = agent->envi->agents_head; NULL != other; other = 
other->next)
+        {
+          agent->W[i][k] += (other->W[i][k] / (double) count);
+        }
+      }
+
+      GNUNET_assert(!isinf(agent->W[i][k]));
+    }
+  }
+}
+
+/**
+ * Initialize an agent without addresses and its knowledge base
+ *
+ * @param s ril solver
+ * @param peer the one in question
+ * @return handle to the new agent
+ */
+static struct RIL_Peer_Agent *
+agent_init (void *s, const struct GNUNET_PeerIdentity *peer)
+{
+  int i;
+  struct GAS_RIL_Handle * solver = s;
+  struct RIL_Peer_Agent * agent = GNUNET_malloc (sizeof (struct 
RIL_Peer_Agent));
+
+  agent->envi = solver;
+  agent->peer = *peer;
+  agent->step_count = 0;
+  agent->is_active = GNUNET_NO;
+  agent->bw_in = MIN_BW;
+  agent->bw_out = MIN_BW;
+  agent->suggestion_issue = GNUNET_NO;
+  agent->n = RIL_ACTION_TYPE_NUM;
+  agent->m = (RIL_FEATURES_NETWORK_COUNT);// + GNUNET_ATS_PreferenceCount;
+  agent->W = (double **) GNUNET_malloc (sizeof (double *) * agent->n);
+  for (i = 0; i < agent->n; i++)
+  {
+    agent->W[i] = (double *) GNUNET_malloc (sizeof (double) * agent->m);
+  }
+  agent_w_start(agent);
+  agent->a_old = RIL_ACTION_INVALID;
+  agent->s_old = GNUNET_malloc (sizeof (double) * agent->m);
+  agent->e = (double *) GNUNET_malloc (sizeof (double) * agent->m);
+  agent_modify_eligibility (agent, RIL_E_ZERO, NULL);
+
+  return agent;
+}
+
+/**
+ * Deallocate agent
+ *
+ * @param solver the solver handle
+ * @param agent the agent to retire
+ */
+static void
+agent_die (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
+{
+  int i;
+
+  for (i = 0; i < agent->n; i++)
+  {
+    GNUNET_free(agent->W[i]);
+  }
+  GNUNET_free(agent->W);
+  GNUNET_free(agent->e);
+  GNUNET_free(agent->s_old);
+  GNUNET_free(agent);
+}
+
+/**
+ * Returns the agent for a peer
+ *
+ * @param solver the solver handle
+ * @param peer the identity of the peer
+ * @param create whether or not to create an agent, if none is allocated yet
+ * @return the agent
+ */
+static struct RIL_Peer_Agent *
+ril_get_agent (struct GAS_RIL_Handle *solver, const struct GNUNET_PeerIdentity 
*peer, int create)
+{
+  struct RIL_Peer_Agent *cur;
+
+  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
+  {
+    if (0 == memcmp (peer, &cur->peer, sizeof(struct GNUNET_PeerIdentity)))
+    {
+      return cur;
+    }
+  }
+
+  if (create)
+  {
+    cur = agent_init (solver, peer);
+    GNUNET_CONTAINER_DLL_insert_tail(solver->agents_head, solver->agents_tail, 
cur);
+    return cur;
+  }
+  return NULL ;
+}
+
+/**
+ * Determine whether at least the minimum bandwidth is set for the network. 
Otherwise the network is
+ * considered inactive and not used. Addresses in an inactive network are 
ignored.
+ *
+ * @param solver solver handle
+ * @param network the network type
+ * @return whether or not the network is considered active
+ */
+static int
+ril_network_is_active (struct GAS_RIL_Handle *solver, enum 
GNUNET_ATS_Network_Type network)
+{
+  struct RIL_Network *net;
+
+  net = ril_get_network (solver, network);
+  return net->bw_out_available >= MIN_BW;
+}
+
+/**
+ * Cuts a slice out of a vector of elements. This is used to decrease the size 
of the matrix storing
+ * the reward function approximation. It copies the memory, which is not cut, 
to the new vector,
+ * frees the memory of the old vector, and redirects the pointer to the new 
one.
+ *
+ * @param old pointer to the pointer to the first element of the vector
+ * @param element_size byte size of the vector elements
+ * @param hole_start the first element to cut out
+ * @param hole_length the number of elements to cut out
+ * @param old_length the length of the old vector
+ */
+static void
+ril_cut_from_vector (void **old,
+    size_t element_size,
+    unsigned int hole_start,
+    unsigned int hole_length,
+    unsigned int old_length)
+{
+  char *tmpptr;
+  char *oldptr = (char *) *old;
+  size_t size;
+  unsigned int bytes_before;
+  unsigned int bytes_hole;
+  unsigned int bytes_after;
+
+  GNUNET_assert(old_length > hole_length);
+  GNUNET_assert(old_length >= (hole_start + hole_length));
+
+  size = element_size * (old_length - hole_length);
+
+  bytes_before = element_size * hole_start;
+  bytes_hole = element_size * hole_length;
+  bytes_after = element_size * (old_length - hole_start - hole_length);
+
+  if (0 == size)
+  {
+    tmpptr = NULL;
+  }
+  else
+  {
+    tmpptr = GNUNET_malloc (size);
+    memcpy (tmpptr, oldptr, bytes_before);
+    memcpy (tmpptr + bytes_before, oldptr + (bytes_before + bytes_hole), 
bytes_after);
+  }
+  if (NULL != *old)
+  {
+    GNUNET_free(*old);
+  }
+  *old = (void *) tmpptr;
+}
+
+/*
+ *  Solver API functions
+ *  ---------------------------
+ */
+
+/**
+ * Change relative preference for quality in solver
+ *
+ * @param solver the solver handle
+ * @param peer the peer to change the preference for
+ * @param kind the kind to change the preference
+ * @param pref_rel the normalized preference value for this kind over all 
clients
+ */
+void
+GAS_ril_address_change_preference (void *solver,
+    const struct GNUNET_PeerIdentity *peer,
+    enum GNUNET_ATS_PreferenceKind kind,
+    double pref_rel)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_change_preference() Preference '%s' for peer '%s' changed 
to %.2f \n",
+      GNUNET_ATS_print_preference_type (kind), GNUNET_i2s (peer), pref_rel);
+
+  ril_step (solver);
+}
+
+/**
+ * Entry point for the plugin
+ *
+ * @param cls pointer to the 'struct GNUNET_ATS_PluginEnvironment'
+ */
+void *
+libgnunet_plugin_ats_ril_init (void *cls)
+{
+  struct GNUNET_ATS_PluginEnvironment *env = cls;
+  struct GAS_RIL_Handle *solver = GNUNET_new (struct GAS_RIL_Handle);
+  struct RIL_Network * cur;
+  int c;
+  char *string;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_init() Initializing RIL solver\n");
+
+  GNUNET_assert(NULL != env);
+  GNUNET_assert(NULL != env->cfg);
+  GNUNET_assert(NULL != env->stats);
+  GNUNET_assert(NULL != env->bandwidth_changed_cb);
+  GNUNET_assert(NULL != env->get_preferences);
+  GNUNET_assert(NULL != env->get_property);
+
+  if (GNUNET_OK
+      != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", 
"RIL_STEP_TIME_MIN",
+          &solver->parameters.step_time_min))
+  {
+    solver->parameters.step_time_min = RIL_DEFAULT_STEP_TIME_MIN;
+  }
+  if (GNUNET_OK
+      != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", 
"RIL_STEP_TIME_MAX",
+          &solver->parameters.step_time_max))
+  {
+    solver->parameters.step_time_max = RIL_DEFAULT_STEP_TIME_MAX;
+  }
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_ALGORITHM", &string))
+  {
+    solver->parameters.algorithm = !strcmp (string, "SARSA") ? RIL_ALGO_SARSA 
: RIL_ALGO_Q;
+    GNUNET_free (string);
+  }
+  else
+  {
+    solver->parameters.algorithm = RIL_DEFAULT_ALGORITHM;
+  }
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_DISCOUNT_BETA", &string))
+  {
+    solver->parameters.beta = strtod (string, NULL);
+    GNUNET_free (string);
+  }
+  else
+  {
+    solver->parameters.beta = RIL_DEFAULT_DISCOUNT_BETA;
+  }
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_DISCOUNT_GAMMA", &string))
+  {
+    solver->parameters.gamma = strtod (string, NULL);
+    GNUNET_free (string);
+  }
+  else
+  {
+    solver->parameters.gamma = RIL_DEFAULT_DISCOUNT_GAMMA;
+  }
+  if (GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_GRADIENT_STEP_SIZE", &string))
+  {
+    solver->parameters.alpha = strtod (string, NULL);
+    GNUNET_free (string);
+  }
+  else
+  {
+    solver->parameters.alpha = RIL_DEFAULT_GRADIENT_STEP_SIZE;
+  }
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_TRACE_DECAY", &string))
+  {
+    solver->parameters.lambda = strtod (string, NULL);
+    GNUNET_free (string);
+  }
+  else
+  {
+    solver->parameters.lambda = RIL_DEFAULT_TRACE_DECAY;
+  }
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_EXPLORE_RATIO", &string))
+  {
+    solver->parameters.explore_ratio = strtod (string, NULL);
+    GNUNET_free (string);
+  }
+  else
+  {
+    solver->parameters.explore_ratio = RIL_DEFAULT_EXPLORE_RATIO;
+  }
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats", 
"RIL_GLOBAL_REWARD_SHARE", &string))
+  {
+    solver->parameters.reward_global_share = strtod (string, NULL);
+    GNUNET_free (string);
+  }
+  else
+  {
+    solver->parameters.reward_global_share = RIL_DEFAULT_GLOBAL_REWARD_SHARE;
+  }
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "ats", 
"RIL_SIMULATE", &solver->simulate))
+  {
+    solver->simulate = GNUNET_NO;
+  }
+
+  env->sf.s_add = &GAS_ril_address_add;
+  env->sf.s_address_update_property = &GAS_ril_address_property_changed;
+  env->sf.s_address_update_session = &GAS_ril_address_session_changed;
+  env->sf.s_address_update_inuse = &GAS_ril_address_inuse_changed;
+  env->sf.s_address_update_network = &GAS_ril_address_change_network;
+  env->sf.s_get = &GAS_ril_get_preferred_address;
+  env->sf.s_get_stop = &GAS_ril_stop_get_preferred_address;
+  env->sf.s_pref = &GAS_ril_address_change_preference;
+  env->sf.s_feedback = &GAS_ril_address_preference_feedback;
+  env->sf.s_del = &GAS_ril_address_delete;
+  env->sf.s_bulk_start = &GAS_ril_bulk_start;
+  env->sf.s_bulk_stop = &GAS_ril_bulk_stop;
+
+  solver->plugin_envi = env;
+  solver->networks_count = env->network_count;
+  solver->network_entries = GNUNET_malloc (env->network_count * sizeof (struct 
RIL_Network));
+  solver->step_count = 0;
+  solver->global_state_networks = GNUNET_malloc (solver->networks_count * 
RIL_FEATURES_NETWORK_COUNT * sizeof (double));
+  solver->done = GNUNET_NO;
+
+  for (c = 0; c < env->network_count; c++)
+  {
+    cur = &solver->network_entries[c];
+    cur->type = env->networks[c];
+    cur->bw_in_available = env->in_quota[c];
+    cur->bw_out_available = env->out_quota[c];
+    LOG(GNUNET_ERROR_TYPE_INFO, "init()  Quotas for %s network:  IN %llu - OUT 
%llu\n", GNUNET_ATS_print_network_type(cur->type), cur->bw_in_available/1024, 
cur->bw_out_available/1024);
+  }
+
+  LOG(GNUNET_ERROR_TYPE_INFO, "init()  Parameters:\n");
+  LOG(GNUNET_ERROR_TYPE_INFO, "init()  Algorithm = %s, alpha = %f, beta = %f, 
lambda = %f\n",
+      solver->parameters.algorithm ? "Q" : "SARSA",
+      solver->parameters.alpha,
+      solver->parameters.beta,
+      solver->parameters.lambda);
+  LOG(GNUNET_ERROR_TYPE_INFO, "init()  explore = %f, global_share = %f\n",
+      solver->parameters.explore_ratio,
+      solver->parameters.reward_global_share);
+
+  return solver;
+}
+
+/**
+ * Exit point for the plugin
+ *
+ * @param cls the solver handle
+ */
+void *
+libgnunet_plugin_ats_ril_done (void *cls)
+{
+  struct GAS_RIL_Handle *s = cls;
+  struct RIL_Peer_Agent *cur_agent;
+  struct RIL_Peer_Agent *next_agent;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_done() Shutting down RIL solver\n");
+
+  s->done = GNUNET_YES;
+
+  cur_agent = s->agents_head;
+  while (NULL != cur_agent)
+  {
+    next_agent = cur_agent->next;
+    GNUNET_CONTAINER_DLL_remove(s->agents_head, s->agents_tail, cur_agent);
+    agent_die (s, cur_agent);
+    cur_agent = next_agent;
+  }
+
+  if (GNUNET_SCHEDULER_NO_TASK != s->step_next_task_id)
+  {
+    GNUNET_SCHEDULER_cancel (s->step_next_task_id);
+  }
+  GNUNET_free(s->network_entries);
+  GNUNET_free(s->global_state_networks);
+  GNUNET_free(s);
+
+  return NULL;
+}
+
+/**
+ * Add a new address for a peer to the solver
+ *
+ * The address is already contained in the addresses hashmap!
+ *
+ * @param solver the solver Handle
+ * @param address the address to add
+ * @param network network type of this address
+ */
+void
+GAS_ril_address_add (void *solver, struct ATS_Address *address, uint32_t 
network)
+{
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+  struct RIL_Address_Wrapped *address_wrapped;
+  struct RIL_Network *net;
+  unsigned int m_new;
+  unsigned int m_old;
+  unsigned int n_new;
+  unsigned int n_old;
+  int i;
+  unsigned int zero;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "API_address_add()\n");
+
+  net = ril_get_network (s, network);
+  address->solver_information = net;
+
+  if (!ril_network_is_active (s, network))
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "API_address_add() Did not add %s address %s for peer '%s', network 
does not have enough bandwidth\n",
+        address->plugin, address->addr, GNUNET_i2s (&address->peer));
+    return;
+  }
+
+  agent = ril_get_agent (s, &address->peer, GNUNET_YES);
+
+  //add address
+  address_wrapped = GNUNET_malloc (sizeof (struct RIL_Address_Wrapped));
+  address_wrapped->address_naked = address;
+  GNUNET_CONTAINER_DLL_insert_tail(agent->addresses_head, 
agent->addresses_tail, address_wrapped);
+
+  //increase size of W
+  m_new = agent->m + RIL_FEATURES_ADDRESS_COUNT;
+  m_old = agent->m;
+  n_new = agent->n + 1;
+  n_old = agent->n;
+
+  GNUNET_array_grow(agent->W, agent->n, n_new);
+  for (i = 0; i < n_new; i++)
+  {
+    if (i < n_old)
+    {
+      agent->m = m_old;
+      GNUNET_array_grow(agent->W[i], agent->m, m_new);
+    }
+    else
+    {
+      zero = 0;
+      GNUNET_array_grow(agent->W[i], zero, m_new);
+    }
+  }
+
+  //increase size of old state vector
+  agent->m = m_old;
+  GNUNET_array_grow(agent->s_old, agent->m, m_new);
+
+  agent->m = m_old;
+  GNUNET_array_grow(agent->e, agent->m, m_new);
+
+  ril_try_unblock_agent(s, agent, GNUNET_NO);
+
+  ril_step (s);
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_add() Added %s %s address %s for 
peer '%s'\n",
+      address->active ? "active" : "inactive", address->plugin, address->addr,
+      GNUNET_i2s (&address->peer));
+}
+
+/**
+ * Delete an address in the solver
+ *
+ * The address is not contained in the address hashmap anymore!
+ *
+ * @param solver the solver handle
+ * @param address the address to remove
+ * @param session_only delete only session not whole address
+ */
+void
+GAS_ril_address_delete (void *solver, struct ATS_Address *address, int 
session_only)
+{
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+  struct RIL_Address_Wrapped *address_wrapped;
+  int address_was_used = address->active;
+  int address_index;
+  unsigned int m_new;
+  unsigned int n_new;
+  int i;
+  struct RIL_Network *net;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_delete() Delete %s%s %s address %s 
for peer '%s'\n",
+      session_only ? "session for " : "", address->active ? "active" : 
"inactive", address->plugin,
+      address->addr, GNUNET_i2s (&address->peer));
+
+  agent = ril_get_agent (s, &address->peer, GNUNET_NO);
+  if (NULL == agent)
+  {
+    net = address->solver_information;
+    GNUNET_assert(!ril_network_is_active (s, net->type));
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "No agent allocated for peer yet, since address was in inactive 
network\n");
+    return;
+  }
+
+  address_index = agent_address_get_index (agent, address);
+  address_wrapped = agent_address_get (agent, address);
+
+  if (NULL == address_wrapped)
+  {
+    net = address->solver_information;
+    GNUNET_assert(!ril_network_is_active (s, net->type));
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "Address not considered by agent, address was in inactive network\n");
+    return;
+  }
+
+  GNUNET_CONTAINER_DLL_remove(agent->addresses_head, agent->addresses_tail, 
address_wrapped);
+  GNUNET_free(address_wrapped);
+
+  //decrease W
+  m_new = agent->m - RIL_FEATURES_ADDRESS_COUNT;
+  n_new = agent->n - 1;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "first\n");
+
+  for (i = 0; i < agent->n; i++)
+  {
+    ril_cut_from_vector ((void **) &agent->W[i], sizeof(double),
+        //((s->networks_count * RIL_FEATURES_NETWORK_COUNT)
+        ((RIL_FEATURES_NETWORK_COUNT) //TODO! replace, when adding more 
networks
+            + (address_index * RIL_FEATURES_ADDRESS_COUNT)), 
RIL_FEATURES_ADDRESS_COUNT, agent->m);
+  }
+  GNUNET_free(agent->W[RIL_ACTION_TYPE_NUM + address_index]);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "second\n");
+  ril_cut_from_vector ((void **) &agent->W, sizeof(double *), 
RIL_ACTION_TYPE_NUM + address_index,
+      1, agent->n);
+  //correct last action
+  if (agent->a_old > (RIL_ACTION_TYPE_NUM + address_index))
+  {
+    agent->a_old -= 1;
+  }
+  else if (agent->a_old == (RIL_ACTION_TYPE_NUM + address_index))
+  {
+    agent->a_old = RIL_ACTION_INVALID;
+  }
+  //decrease old state vector and eligibility vector
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "third\n");
+  ril_cut_from_vector ((void **) &agent->s_old, sizeof(double),
+      //((s->networks_count * RIL_FEATURES_NETWORK_COUNT)
+      ((RIL_FEATURES_NETWORK_COUNT) //TODO! replace when adding more networks
+          + (address_index * RIL_FEATURES_ADDRESS_COUNT)), 
RIL_FEATURES_ADDRESS_COUNT, agent->m);
+  ril_cut_from_vector ((void **) &agent->e, sizeof(double),
+      //((s->networks_count * RIL_FEATURES_NETWORK_COUNT)
+      ((RIL_FEATURES_NETWORK_COUNT) //TODO! replace when adding more networks
+          + (address_index * RIL_FEATURES_ADDRESS_COUNT)), 
RIL_FEATURES_ADDRESS_COUNT, agent->m);
+  agent->m = m_new;
+  agent->n = n_new;
+
+  if (address_was_used)
+  {
+    if (NULL != agent->addresses_head) //if peer has an address left, use it
+    {
+      envi_set_active_suggestion (s, agent, 
agent->addresses_head->address_naked, MIN_BW, MIN_BW,
+          GNUNET_NO);
+    }
+    else
+    {
+      envi_set_active_suggestion (s, agent, NULL, 0, 0, GNUNET_NO);
+    }
+  }
+
+  ril_step (solver);
+}
+
+/**
+ * Update the properties of an address in the solver
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param type the ATSI type in HBO
+ * @param abs_value the absolute value of the property
+ * @param rel_value the normalized value
+ */
+void
+GAS_ril_address_property_changed (void *solver,
+    struct ATS_Address *address,
+    uint32_t type,
+    uint32_t abs_value,
+    double rel_value)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_property_changed() Property '%s' for peer '%s' address %s 
changed "
+          "to %.2f \n", GNUNET_ATS_print_property_type (type), GNUNET_i2s 
(&address->peer),
+      address->addr, rel_value);
+
+  ril_step (solver);
+}
+
+/**
+ * Update the session of an address in the solver
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param cur_session the current session
+ * @param new_session the new session
+ */
+void
+GAS_ril_address_session_changed (void *solver,
+    struct ATS_Address *address,
+    uint32_t cur_session,
+    uint32_t new_session)
+{
+  /*
+   * TODO? Future Work: Potentially add session activity as a feature in state 
vector
+   */
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_session_changed()\n");
+}
+
+/**
+ * Notify the solver that an address is (not) actively used by transport
+ * to communicate with a remote peer
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param in_use usage state
+ */
+void
+GAS_ril_address_inuse_changed (void *solver, struct ATS_Address *address, int 
in_use)
+{
+  /*
+   * TODO? Future Work: Potentially add usage variable to state vector
+   */
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_inuse_changed() Usage for %s address of peer '%s' changed 
to %s\n",
+      address->plugin, GNUNET_i2s (&address->peer), (GNUNET_YES == in_use) ? 
"USED" : "UNUSED");
+}
+
+/**
+ * Notify solver that the network an address is located in has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param current_network the current network
+ * @param new_network the new network
+ */
+void
+GAS_ril_address_change_network (void *solver,
+    struct ATS_Address *address,
+    uint32_t current_network,
+    uint32_t new_network)
+{
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_address_change_network() Network type 
changed, moving "
+      "%s address of peer %s from '%s' to '%s'\n",
+      (GNUNET_YES == address->active) ? "active" : "inactive", GNUNET_i2s 
(&address->peer),
+      GNUNET_ATS_print_network_type (current_network), 
GNUNET_ATS_print_network_type (new_network));
+
+  if (address->active && !ril_network_is_active (solver, new_network))
+  {
+    GAS_ril_address_delete (solver, address, GNUNET_NO);
+    return;
+  }
+
+  agent = ril_get_agent (s, &address->peer, GNUNET_NO);
+  if (NULL == agent)
+  {
+    GNUNET_assert(!ril_network_is_active (solver, current_network));
+
+    GAS_ril_address_add (s, address, new_network);
+    return;
+  }
+
+  address->solver_information = ril_get_network(solver, new_network);
+}
+
+/**
+ * Give feedback about the current assignment
+ *
+ * @param solver the solver handle
+ * @param application the application
+ * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_ril_address_preference_feedback (void *solver,
+    void *application,
+    const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_TIME_Relative scope,
+    enum GNUNET_ATS_PreferenceKind kind,
+    double score)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_preference_feedback() Peer '%s' got a feedback of %+.3f 
from application %s for "
+          "preference %s for %d seconds\n", GNUNET_i2s (peer), "UNKNOWN",
+      GNUNET_ATS_print_preference_type (kind), scope.rel_value_us / 1000000);
+}
+
+/**
+ * Start a bulk operation
+ *
+ * @param solver the solver
+ */
+void
+GAS_ril_bulk_start (void *solver)
+{
+  struct GAS_RIL_Handle *s = solver;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_bulk_start() lock: %d\n", s->bulk_lock+1);
+
+  s->bulk_lock++;
+}
+
+/**
+ * Bulk operation done
+ *
+ * @param solver the solver handle
+ */
+void
+GAS_ril_bulk_stop (void *solver)
+{
+  struct GAS_RIL_Handle *s = solver;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_bulk_stop() lock: %d\n", s->bulk_lock-1);
+
+  if (s->bulk_lock < 1)
+  {
+    GNUNET_break(0);
+    return;
+  }
+  s->bulk_lock--;
+
+  if (0 < s->bulk_changes)
+  {
+    ril_step (solver);
+    s->bulk_changes = 0;
+  }
+}
+
+/**
+ * Tell solver to notify ATS if the address to use changes for a specific
+ * peer using the bandwidth changed callback
+ *
+ * The solver must only notify about changes for peers with pending address
+ * requests!
+ *
+ * @param solver the solver handle
+ * @param peer the identity of the peer
+ */
+const struct ATS_Address *
+GAS_ril_get_preferred_address (void *solver, const struct GNUNET_PeerIdentity 
*peer)
+{
+  /*
+   * activate agent, return currently chosen address
+   */
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_get_preferred_address()\n");
+
+  agent = ril_get_agent (s, peer, GNUNET_YES);
+
+  agent->is_active = GNUNET_YES;
+  envi_set_active_suggestion (solver, agent, agent->address_inuse, 
agent->bw_in, agent->bw_out, GNUNET_YES);
+
+  ril_try_unblock_agent(solver, agent, GNUNET_YES);
+
+  if (agent->address_inuse)
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "API_get_preferred_address() Activated agent for peer '%s' with %s 
address %s\n",
+        GNUNET_i2s (peer), agent->address_inuse->plugin, 
agent->address_inuse->addr);
+  }
+  else
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG,
+        "API_get_preferred_address() Activated agent for peer '%s', but no 
address available\n",
+        GNUNET_i2s (peer));
+  }
+
+  return agent->address_inuse;
+}
+
+/**
+ * Tell solver stop notifying ATS about changes for this peers
+ *
+ * The solver must only notify about changes for peers with pending address
+ * requests!
+ *
+ * @param solver the solver handle
+ * @param peer the peer
+ */
+void
+GAS_ril_stop_get_preferred_address (void *solver, const struct 
GNUNET_PeerIdentity *peer)
+{
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "API_stop_get_preferred_address()");
+
+  agent = ril_get_agent (s, peer, GNUNET_NO);
+
+  if (NULL == agent)
+  {
+    GNUNET_break(0);
+    return;
+  }
+  if (GNUNET_NO == agent->is_active)
+  {
+    GNUNET_break(0);
+    return;
+  }
+
+  agent->is_active = GNUNET_NO;
+
+  envi_set_active_suggestion (s, agent, agent->address_inuse, agent->bw_in, 
agent->bw_out,
+      GNUNET_YES);
+
+  ril_step (s);
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG,
+      "API_stop_get_preferred_address() Paused agent for peer '%s' with %s 
address\n",
+      GNUNET_i2s (peer), agent->address_inuse->plugin);
+}
+
+/* end of plugin_ats_ril.c */

Copied: gnunet/src/ats/plugin_ats_ril.h (from rev 31243, 
gnunet/src/ats/libgnunet_plugin_ats_ril.h)
===================================================================
--- gnunet/src/ats/plugin_ats_ril.h                             (rev 0)
+++ gnunet/src/ats/plugin_ats_ril.h     2013-12-10 07:58:08 UTC (rev 31244)
@@ -0,0 +1,191 @@
+/*
+ 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/plugin_ats_ril.h
+ * @brief ATS reinforcement learning solver
+ * @author Fabian Oehlmann
+ * @author Matthias Wachs
+ */
+#include "platform.h"
+#include <float.h>
+#include <math.h>
+#include "gnunet_ats_plugin.h"
+#include "gnunet-service-ats_addresses.h"
+
+/**
+ * ATS reinforcement learning solver
+ *
+ * General description
+ */
+
+/**
+ * Changes the preferences for a peer in the problem
+ *
+ * @param solver the solver handle
+ * @param peer the peer to change the preference for
+ * @param kind the kind to change the preference
+ * @param pref_rel the normalized preference value for this kind over all 
clients
+ */
+void
+GAS_ril_address_change_preference (void *solver,
+    const struct GNUNET_PeerIdentity *peer,
+    enum GNUNET_ATS_PreferenceKind kind,
+    double pref_rel);
+
+/**
+ * Add a single address within a network to the solver
+ *
+ * @param solver the solver Handle
+ * @param address the address to add
+ * @param network network type of this address
+ */
+void
+GAS_ril_address_add (void *solver,
+    struct ATS_Address *address,
+    uint32_t network);
+
+/**
+ * Transport properties for this address have changed
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param type the ATSI type in HBO
+ * @param abs_value the absolute value of the property
+ * @param rel_value the normalized value
+ */
+void
+GAS_ril_address_property_changed (void *solver,
+    struct ATS_Address *address,
+    uint32_t type,
+    uint32_t abs_value,
+    double rel_value);
+
+/**
+ * Transport session for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param cur_session the current session
+ * @param new_session the new session
+ */
+void
+GAS_ril_address_session_changed (void *solver,
+    struct ATS_Address *address,
+    uint32_t cur_session,
+    uint32_t new_session);
+
+/**
+ * Usage for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param in_use usage state
+ */
+void
+GAS_ril_address_inuse_changed (void *solver,
+    struct ATS_Address *address,
+    int in_use);
+
+/**
+ * Network scope for this address has changed
+ *
+ * NOTE: values in addresses are already updated
+ *
+ * @param solver solver handle
+ * @param address the address
+ * @param current_network the current network
+ * @param new_network the new network
+ */
+void
+GAS_ril_address_change_network (void *solver,
+    struct ATS_Address *address,
+    uint32_t current_network,
+    uint32_t new_network);
+
+/**
+ * Remove an address from the solver
+ *
+ * @param solver the solver handle
+ * @param address the address to remove
+ * @param session_only delete only session not whole address
+ */
+void
+GAS_ril_address_delete (void *solver,
+    struct ATS_Address *address,
+    int session_only);
+
+/**
+ * Get application feedback for a peer
+ *
+ * @param solver the solver handle
+ * @param application the application
+ * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_ril_address_preference_feedback (void *solver,
+    void *application,
+    const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_TIME_Relative scope,
+    enum GNUNET_ATS_PreferenceKind kind,
+    double score);
+
+/**
+ * Start a bulk operation
+ *
+ * @param solver the solver
+ */
+void
+GAS_ril_bulk_start (void *solver);
+
+/**
+ * Bulk operation done
+ */
+void
+GAS_ril_bulk_stop (void *solver);
+
+/**
+ * Stop notifying about address and bandwidth changes for this peer
+ *
+ * @param solver the solver handle
+ * @param peer the peer
+ */
+void
+GAS_ril_stop_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Get the prefered address for a specific peer
+ *
+ * @param solver the solver handle
+ * @param peer the identity of the peer
+ */
+const struct ATS_Address *
+GAS_ril_get_preferred_address (void *solver,
+    const struct GNUNET_PeerIdentity *peer);
+
+/* end of plugin_ats_ril.h */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]