refactoring and renaming
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_mlp.c
index 21604edad8822168d8b7de3f27bf88fb9a480b03..50983cec1eed0cc6480d344705ba5d3fee76ff95 100644 (file)
@@ -31,6 +31,8 @@
 #include "gnunet_statistics_service.h"
 #include "glpk.h"
 
+#define LOG(kind,...) GNUNET_log_from (kind, "ats-mlp",__VA_ARGS__)
+
 #define WRITE_MLP GNUNET_NO
 #define DEBUG_ATS GNUNET_NO
 #define VERBOSE_GLPK GNUNET_NO
@@ -48,68 +50,46 @@ mlp_solve_to_string (int retcode)
   switch (retcode) {
     case 0:
       return "ok";
-      break;
     case GLP_EBADB:
       return "invalid basis";
-      break;
     case GLP_ESING:
       return "singular matrix";
-      break;
     case GLP_ECOND:
       return "ill-conditioned matrix";
-      break;
     case GLP_EBOUND:
       return "invalid bounds";
-      break;
     case GLP_EFAIL:
       return "solver failed";
-      break;
     case GLP_EOBJLL:
       return "objective lower limit reached";
-      break;
     case GLP_EOBJUL:
       return "objective upper limit reached";
-      break;
     case GLP_EITLIM:
       return "iteration limit exceeded";
-      break;
     case GLP_ETMLIM:
       return "time limit exceeded";
-      break;
     case GLP_ENOPFS:
       return "no primal feasible solution";
-      break;
     case GLP_EROOT:
       return "root LP optimum not provided";
-      break;
     case GLP_ESTOP:
       return "search terminated by application";
-      break;
     case GLP_EMIPGAP:
       return "relative mip gap tolerance reached";
-      break;
     case GLP_ENOFEAS:
       return "no dual feasible solution";
-      break;
     case GLP_ENOCVG:
       return "no convergence";
-      break;
     case GLP_EINSTAB:
       return "numerical instability";
-      break;
     case GLP_EDATA:
       return "invalid data";
-      break;
     case GLP_ERANGE:
       return "result out of range";
-      break;
     default:
       GNUNET_break (0);
       return "unknown error";
-      break;
   }
-  GNUNET_break (0);
-  return "unknown error";
 }
 
 
@@ -124,29 +104,20 @@ mlp_status_to_string (int retcode)
   switch (retcode) {
     case GLP_UNDEF:
       return "solution is undefined";
-      break;
     case GLP_FEAS:
       return "solution is feasible";
-      break;
     case GLP_INFEAS:
       return "solution is infeasible";
-      break;
     case GLP_NOFEAS:
       return "no feasible solution exists";
-      break;
     case GLP_OPT:
       return "solution is optimal";
-      break;
     case GLP_UNBND:
       return "solution is unbounded";
-      break;
     default:
       GNUNET_break (0);
       return "unknown error";
-      break;
   }
-  GNUNET_break (0);
-  return "unknown error";
 }
 
 /**
@@ -162,37 +133,26 @@ mlp_ats_to_string (int ats_index)
   switch (ats_index) {
     case GNUNET_ATS_ARRAY_TERMINATOR:
       return "GNUNET_ATS_ARRAY_TERMINATOR";
-      break;
     case GNUNET_ATS_UTILIZATION_UP:
       return "GNUNET_ATS_UTILIZATION_UP";
-      break;
     case GNUNET_ATS_UTILIZATION_DOWN:
       return "GNUNET_ATS_UTILIZATION_DOWN";
-      break;
     case GNUNET_ATS_COST_LAN:
       return "GNUNET_ATS_COST_LAN";
-      break;
     case GNUNET_ATS_COST_WAN:
       return "GNUNET_ATS_COST_LAN";
-      break;
     case GNUNET_ATS_COST_WLAN:
       return "GNUNET_ATS_COST_WLAN";
-      break;
     case GNUNET_ATS_NETWORK_TYPE:
       return "GNUNET_ATS_NETWORK_TYPE";
-      break;
     case GNUNET_ATS_QUALITY_NET_DELAY:
       return "GNUNET_ATS_QUALITY_NET_DELAY";
-      break;
     case GNUNET_ATS_QUALITY_NET_DISTANCE:
       return "GNUNET_ATS_QUALITY_NET_DISTANCE";
-      break;
     default:
+      GNUNET_break (0);
       return "unknown";
-      break;
   }
-  GNUNET_break (0);
-  return "unknown error";
 }
 
 /**
@@ -278,7 +238,7 @@ mlp_delete_problem (struct GAS_MLP_Handle *mlp)
  * @return GNUNET_OK to continue
  */
 static int
-create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
+create_constraint_it (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
   struct GAS_MLP_Handle *mlp = cls;
   struct ATS_Address *address = value;
@@ -286,8 +246,8 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
   unsigned int row_index;
   char *name;
 
-  GNUNET_assert (address->mlp_information != NULL);
-  mlpi = (struct MLP_information *) address->mlp_information;
+  GNUNET_assert (address->solver_information != NULL);
+  mlpi = (struct MLP_information *) address->solver_information;
 
   /* c 1) bandwidth capping
    * b_t  + (-M) * n_t <= 0
@@ -379,6 +339,7 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
   return GNUNET_OK;
 }
 
+#if 0
 /**
  * Find the required ATS information for an address
  *
@@ -387,7 +348,6 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
  *
  * @return the index on success, otherwise GNUNET_SYSERR
  */
-
 static int
 mlp_lookup_ats (struct ATS_Address *addr, int ats_index)
 {
@@ -407,6 +367,7 @@ mlp_lookup_ats (struct ATS_Address *addr, int ats_index)
   else
     return GNUNET_SYSERR;
 }
+#endif
 
 /**
  * Adds the problem constraints for all addresses
@@ -505,7 +466,9 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
    * c 10) obey network specific quota
    */
 
+  /* Row for c4) minimum connection */
   int min = mlp->n_min;
+  /* Number of minimum connections is min(|Peers|, n_min) */
   if (mlp->n_min > mlp->c_p)
     min = mlp->c_p;
 
@@ -565,6 +528,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
   mlp->ci++;
 
   struct ATS_Peer * peer = mlp->peer_head;
+  /* For all peers */
   while (peer != NULL)
   {
     struct ATS_Address *addr = peer->head;
@@ -590,16 +554,15 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
     /* Set -r */
     ia[mlp->ci] = peer->r_c9;
     ja[mlp->ci] = mlp->c_r;
-    ar[mlp->ci] = -1;
+    ar[mlp->ci] = -peer->f;
     mlp->ci++;
 #endif
-
+    /* For all addresses of this peer */
     while (addr != NULL)
     {
-      mlpi = (struct MLP_information *) addr->mlp_information;
+      mlpi = (struct MLP_information *) addr->solver_information;
 
       /* coefficient for c 2) */
-
       ia[mlp->ci] = peer->r_c2;
       ja[mlp->ci] = mlpi->c_n;
       ar[mlp->ci] = 1;
@@ -625,8 +588,6 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
   }
 
   /* c 7) For all quality metrics */
-
-
   for (c = 0; c < mlp->m_q; c++)
   {
     struct ATS_Peer *tp;
@@ -640,7 +601,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
     glp_set_row_name (mlp->prob, mlp->r_q[c], name);
     GNUNET_free (name);
     /* Set row bound == 0 */
-    glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_LO, 0.0, 0.0);
+    glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_FX, 0.0, 0.0);
 
     ia[mlp->ci] = mlp->r_q[c];
     ja[mlp->ci] = mlp->c_q[c];
@@ -650,14 +611,14 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
     for (tp = mlp->peer_head; tp != NULL; tp = tp->next)
       for (ta = tp->head; ta != NULL; ta = ta->next)
         {
-          mlpi = ta->mlp_information;
+          mlpi = ta->solver_information;
           value = mlpi->q_averaged[c];
 
           mlpi->r_q[c] = mlp->r_q[c];
 
           ia[mlp->ci] = mlp->r_q[c];
           ja[mlp->ci] = mlpi->c_b;
-          ar[mlp->ci] = tp->f * value;
+          ar[mlp->ci] = tp->f_q[c] * value;
           mlp->ci++;
         }
   }
@@ -674,7 +635,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
  * @return GNUNET_OK to continue
  */
 static int
-create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
+create_columns_it (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
   struct GAS_MLP_Handle *mlp = cls;
   struct ATS_Address *address = value;
@@ -682,8 +643,8 @@ create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
   unsigned int col;
   char *name;
 
-  GNUNET_assert (address->mlp_information != NULL);
-  mlpi = address->mlp_information;
+  GNUNET_assert (address->solver_information != NULL);
+  mlpi = address->solver_information;
 
   /* Add bandwidth column */
   col = glp_add_cols (mlp->prob, 2);
@@ -747,7 +708,6 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   /* Adding invariant columns */
 
   /* Diversity d column  */
-
   col = glp_add_cols (mlp->prob, 1);
   mlp->c_d = col;
   /* Column name */
@@ -758,7 +718,6 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
 
   /* Utilization u column  */
-
   col = glp_add_cols (mlp->prob, 1);
   mlp->c_u = col;
   /* Column name */
@@ -806,14 +765,16 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   return res;
 }
 
+
 /**
  * Solves the LP problem
  *
  * @param mlp the MLP Handle
+ * @param s_ctx context to return results
  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
  */
 static int
-mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
+mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
 {
   int res;
   struct GNUNET_TIME_Relative duration;
@@ -866,14 +827,14 @@ lp_solv:
   end = GNUNET_TIME_absolute_get ();
   duration = GNUNET_TIME_absolute_get_difference (start, end);
   mlp->lp_solved++;
-  mlp->lp_total_duration =+ duration.rel_value;
+  mlp->lp_total_duration += duration.rel_value;
+  s_ctx->lp_duration = duration;
 
   GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
   GNUNET_STATISTICS_set (mlp->stats,"# LP execution time (ms)", duration.rel_value, GNUNET_NO);
   GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average (ms)",
                          mlp->lp_total_duration / mlp->lp_solved,  GNUNET_NO);
 
-
   /* Analyze problem status  */
   res = glp_get_status (mlp->prob);
   switch (res) {
@@ -903,10 +864,11 @@ lp_solv:
  * Solves the MLP problem
  *
  * @param mlp the MLP Handle
+ * @param s_ctx context to return results
  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
  */
 int
-mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
+mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
 {
   int res;
   struct GNUNET_TIME_Relative duration;
@@ -942,7 +904,8 @@ mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
   end = GNUNET_TIME_absolute_get ();
   duration = GNUNET_TIME_absolute_get_difference (start, end);
   mlp->mlp_solved++;
-  mlp->mlp_total_duration =+ duration.rel_value;
+  mlp->mlp_total_duration += duration.rel_value;
+  s_ctx->mlp_duration = duration;
 
   GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
   GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time (ms)", duration.rel_value, GNUNET_NO);
@@ -970,41 +933,60 @@ mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
   return GNUNET_OK;
 }
 
-int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp);
+int GAS_mlp_solve_problem (void *solver, struct GAS_MLP_SolutionContext *ctx);
+
 
 static void
 mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GAS_MLP_Handle *mlp = cls;
+  struct GAS_MLP_SolutionContext ctx;
 
   mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
 
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
 
-
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
 
   if (mlp->addr_in_problem != 0)
-    GAS_mlp_solve_problem(mlp);
+    GAS_mlp_solve_problem(mlp, &ctx);
 }
 
 
 /**
  * Solves the MLP problem
  *
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
+ * @param ctx solution context
  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
  */
 int
-GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
+GAS_mlp_solve_problem (void *solver, struct GAS_MLP_SolutionContext *ctx)
 {
+  struct GAS_MLP_Handle *mlp = solver;
   int res;
-  mlp->last_execution = GNUNET_TIME_absolute_get ();
+  /* Check if solving is already running */
+  if (GNUNET_YES == mlp->semaphore)
+  {
+    if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
+    {
+      GNUNET_SCHEDULER_cancel(mlp->mlp_task);
+      mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
+    }
+    mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
+    return GNUNET_SYSERR;
+  }
+  mlp->semaphore = GNUNET_YES;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n");
+  mlp->last_execution = GNUNET_TIME_absolute_get ();
 
+  ctx->lp_result = GNUNET_SYSERR;
+  ctx->mlp_result = GNUNET_SYSERR;
+  ctx->lp_duration = GNUNET_TIME_UNIT_FOREVER_REL;
+  ctx->mlp_duration = GNUNET_TIME_UNIT_FOREVER_REL;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve LP problem\n");
 #if WRITE_MLP
   char * name;
   static int i;
@@ -1014,7 +996,14 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
   GNUNET_free (name);
 # endif
 
-  res = mlp_solve_lp_problem (mlp);
+  res = mlp_solve_lp_problem (mlp, ctx);
+  ctx->lp_result = res;
+  if (res != GNUNET_OK)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "LP Problem solving failed\n");
+    mlp->semaphore = GNUNET_NO;
+    return GNUNET_SYSERR;
+  }
 
 #if WRITE_MLP
   GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
@@ -1022,31 +1011,24 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
   GNUNET_free (name);
 # endif
 
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve MLP problem\n");
+  res = mlp_solve_mlp_problem (mlp, ctx);
+  ctx->mlp_result = res;
   if (res != GNUNET_OK)
   {
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
-
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP Problem solving failed\n");
+    mlp->semaphore = GNUNET_NO;
     return GNUNET_SYSERR;
   }
-
-  res = mlp_solve_mlp_problem (mlp);
-
 #if WRITE_MLP
   GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
   glp_print_mip (mlp->prob, name);
   GNUNET_free (name);
 # endif
-  if (res != GNUNET_OK)
-  {
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n");
-
-    return GNUNET_SYSERR;
-  }
-
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved %s (LP duration %llu / MLP duration %llu)\n",
+      (GNUNET_OK == res) ? "successfully" : "failed", ctx->lp_duration.rel_value, ctx->mlp_duration.rel_value);
   /* Process result */
   struct ATS_Peer *p = NULL;
   struct ATS_Address *a = NULL;
@@ -1060,7 +1042,7 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
       double b = 0.0;
       double n = 0.0;
 
-      mlpi = a->mlp_information;
+      mlpi = a->solver_information;
 
       b = glp_mip_col_val(mlp->prob, mlpi->c_b);
       mlpi->b = b;
@@ -1082,6 +1064,7 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
     mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
   }
   mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
+  mlp->semaphore = GNUNET_NO;
   return res;
 }
 
@@ -1090,70 +1073,120 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
  *
  * @param cfg the GNUNET_CONFIGURATION_Handle handle
  * @param stats the GNUNET_STATISTICS handle
- * @param max_duration maximum numbers of iterations for the LP/MLP Solver
- * @param max_iterations maximum time limit for the LP/MLP Solver
- * @return struct GAS_MLP_Handle * on success, NULL on fail
+ * @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
+ * @return struct GAS_MLP_Handle on success, NULL on fail
  */
-struct GAS_MLP_Handle *
+void *
 GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
               const struct GNUNET_STATISTICS_Handle *stats,
-              struct GNUNET_TIME_Relative max_duration,
-              unsigned int max_iterations)
+              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)
 {
   struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
 
   double D;
   double R;
   double U;
-  long long unsigned int tmp;
+  unsigned long long tmp;
   unsigned int b_min;
   unsigned int n_min;
   struct GNUNET_TIME_Relative i_exec;
   int c;
-  char * quota_out_str;
-  char * quota_in_str;
+  int c2;
+  int found;
+
+  struct GNUNET_TIME_Relative max_duration;
+  long long unsigned int max_iterations;
 
   /* Init GLPK environment */
-  GNUNET_assert (glp_init_env() == 0);
+  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;
+  }
 
   /* Create initial MLP problem */
   mlp->prob = glp_create_prob();
-  GNUNET_assert (mlp->prob != NULL);
+  if (NULL == mlp->prob)
+  {
+               GNUNET_assert (mlp->prob != NULL);
+  }
 
   mlp->BIG_M = (double) BIG_M_VALUE;
 
+  /* Get timeout for iterations */
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(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(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 (cfg, "ats",
-                                                      "COEFFICIENT_D",
+                                                      "MLP_COEFFICIENT_D",
                                                       &tmp))
     D = (double) tmp / 100;
   else
-    D = 1.0;
+    D = DEFAULT_D;
 
   /* Get proportionality coefficient from configuration */
   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
-                                                      "COEFFICIENT_R",
+                                                      "MLP_COEFFICIENT_R",
                                                       &tmp))
     R = (double) tmp / 100;
   else
-    R = 1.0;
+    R = DEFAULT_R;
 
   /* Get utilization coefficient from configuration */
   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
-                                                      "COEFFICIENT_U",
+                                                      "MLP_COEFFICIENT_U",
                                                       &tmp))
     U = (double) tmp / 100;
   else
-    U = 1.0;
+    U = DEFAULT_U;
 
   /* Get quality metric coefficients from configuration */
-  int i_delay = -1;
-  int i_distance = -1;
+  int i_delay = NaN;
+  int i_distance = 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->co_Q[c] = 1.0;
+    mlp->co_Q[c] = DEFAULT_QUALITY;
 
     mlp->q[c] = q[c];
     if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
@@ -1162,24 +1195,24 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
       i_distance = c;
   }
 
-  if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
-                                                      "COEFFICIENT_QUALITY_DELAY",
+  if ((i_delay != NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+                                                      "MLP_COEFFICIENT_QUALITY_DELAY",
                                                       &tmp)))
 
     mlp->co_Q[i_delay] = (double) tmp / 100;
   else
-    mlp->co_Q[i_delay] = 1.0;
+    mlp->co_Q[i_delay] = DEFAULT_QUALITY;
 
-  if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
-                                                      "COEFFICIENT_QUALITY_DISTANCE",
+  if ((i_distance != NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+                                                      "MLP_COEFFICIENT_QUALITY_DISTANCE",
                                                       &tmp)))
     mlp->co_Q[i_distance] = (double) tmp / 100;
   else
-    mlp->co_Q[i_distance] = 1.0;
+    mlp->co_Q[i_distance] = DEFAULT_QUALITY;
 
   /* Get minimum bandwidth per used address from configuration */
   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
-                                                      "MIN_BANDWIDTH",
+                                                      "MLP_MIN_BANDWIDTH",
                                                       &tmp))
     b_min = tmp;
   else
@@ -1189,103 +1222,78 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   /* Get minimum number of connections from configuration */
   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
-                                                      "MIN_CONNECTIONS",
+                                                      "MLP_MIN_CONNECTIONS",
                                                       &tmp))
     n_min = tmp;
   else
-    n_min = 4;
+    n_min = DEFAULT_MIN_CONNECTIONS;
 
   /* Init network quotas */
   int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
   {
-    mlp->quota_index[c] = quotas[c];
-    static char * entry_in = NULL;
-    static char * entry_out = NULL;
-    unsigned long long quota_in = 0;
-    unsigned long long quota_out = 0;
-
-    switch (quotas[c]) {
-      case GNUNET_ATS_NET_UNSPECIFIED:
-        entry_out = "UNSPECIFIED_QUOTA_OUT";
-        entry_in = "UNSPECIFIED_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_LOOPBACK:
-        entry_out = "LOOPBACK_QUOTA_OUT";
-        entry_in = "LOOPBACK_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_LAN:
-        entry_out = "LAN_QUOTA_OUT";
-        entry_in = "LAN_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_WAN:
-        entry_out = "WAN_QUOTA_OUT";
-        entry_in = "WAN_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_WLAN:
-        entry_out = "WLAN_QUOTA_OUT";
-        entry_in = "WLAN_QUOTA_IN";
-        break;
-      default:
-        break;
-    }
-
-    if ((entry_in == NULL) || (entry_out == NULL))
-      continue;
-
-    if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, &quota_out_str))
-    {
-      if (0 == strcmp(quota_out_str, BIG_M_STRING) ||
-          (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &quota_out)))
-        quota_out = mlp->BIG_M;
-
-      GNUNET_free (quota_out_str);
-      quota_out_str = NULL;
-    }
-    else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
-    {
-      quota_out = mlp->BIG_M;
-    }
-    else
-    {
-      quota_out = mlp->BIG_M;
-    }
-
-    if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, &quota_in_str))
-    {
-      if (0 == strcmp(quota_in_str, BIG_M_STRING) ||
-          (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
-        quota_in = mlp->BIG_M;
-
-      GNUNET_free (quota_in_str);
-      quota_in_str = NULL;
-    }
-    else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
-    {
-      quota_in = mlp->BIG_M;
-    }
-    else
-    {
-      quota_in = mlp->BIG_M;
-    }
-
-    /* Check if defined quota could make problem unsolvable */
-    if (((n_min * b_min) > quota_out) && (GNUNET_ATS_NET_UNSPECIFIED != quotas[c]))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent quota configuration value `%s': " \
-          "outbound quota (%u Bps) too small for combination of minimum connections and minimum bandwidth per peer (%u * %u Bps = %u)\n", entry_out, quota_out, n_min, b_min, n_min * b_min);
+               found = GNUNET_NO;
+         for (c2 = 0; c2 < dest_length; c2++)
+         {
+                       if (quotas[c] == network[c2])
+                 {
+                               mlp->quota_index[c] = network[c2];
+                     mlp->quota_out[c] = out_dest[c2];
+                     mlp->quota_in[c] = in_dest[c2];
+                     found = GNUNET_YES;
+                     LOG (GNUNET_ERROR_TYPE_DEBUG, "Quota for network `%s' (in/out) %llu/%llu\n",
+                                                               GNUNET_ATS_print_network_type(mlp->quota_index[c]),
+                                                               mlp->quota_out[c],
+                                                               mlp->quota_in[c]);
+                     break;
+                 }
+         }
+
+      /* Check if defined quota could make problem unsolvable */
+      if ((n_min * b_min) > mlp->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->quota_index[c]),
+                       mlp->quota_out[c],
+                       (n_min * b_min));
+        mlp->quota_out[c] = (n_min * b_min);
+      }
+      if ((n_min * b_min) > mlp->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->quota_index[c]),
+                       mlp->quota_in[c],
+                       (n_min * b_min));
+        mlp->quota_in[c] = (n_min * b_min);
+      }
 
-      GAS_mlp_done(mlp);
-      mlp = NULL;
-      return NULL;
-    }
+      /* Check if bandwidth is too big to make problem solvable */
+      if (mlp->BIG_M < mlp->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->quota_index[c]),
+                       mlp->quota_out[c],
+                       mlp->BIG_M);
+        mlp->quota_out[c] = mlp->BIG_M;
+      }
+      if (mlp->BIG_M < mlp->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->quota_index[c]),
+                       mlp->quota_in[c],
+                       mlp->BIG_M);
+        mlp->quota_in[c] = mlp->BIG_M;
+      }
 
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n",
-                entry_out, quota_out, entry_in, quota_in);
-    GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_out, quota_out, GNUNET_NO);
-    GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_in, quota_in, GNUNET_NO);
-    mlp->quota_out[c] = quota_out;
-    mlp->quota_in[c] = quota_in;
+         if (GNUNET_NO == found)
+                       {
+               mlp->quota_in[c] = ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+               mlp->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->quota_index[c]),
+                                               mlp->quota_in[c],
+                                               mlp->quota_out[c]);
+                       }
   }
 
   /* Get minimum number of connections from configuration */
@@ -1296,6 +1304,8 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   else
     mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);
 
+
+  /* Assign options to handle */
   mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
   mlp->max_iterations = max_iterations;
   mlp->max_exec_duration = max_duration;
@@ -1324,7 +1334,7 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 #endif
   mlp->control_param_mlp.tm_lim = max_duration.rel_value;
 
-  mlp->last_execution = GNUNET_TIME_absolute_get_forever();
+  mlp->last_execution = GNUNET_TIME_UNIT_FOREVER_ABS;
 
   mlp->co_D = D;
   mlp->co_R = R;
@@ -1332,6 +1342,9 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   mlp->b_min = b_min;
   mlp->n_min = n_min;
   mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
+  mlp->semaphore = GNUNET_NO;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
 
   return mlp;
 }
@@ -1343,29 +1356,33 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address)
       GNUNET_i2s (&address->peer));
 
   GNUNET_assert (NULL != address);
-  GNUNET_assert (NULL != address->mlp_information);
-  GNUNET_assert (NULL != address->ats);
+  GNUNET_assert (NULL != address->solver_information);
+//  GNUNET_assert (NULL != address->ats);
 
-  struct MLP_information *mlpi = address->mlp_information;
-  struct GNUNET_ATS_Information *ats = address->ats;
+  struct MLP_information *mlpi = address->solver_information;
+  //struct GNUNET_ATS_Information *ats = address->ats;
   GNUNET_assert (mlpi != NULL);
 
   int c;
   for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
   {
-    int index = mlp_lookup_ats(address, mlp->q[c]);
+
+    /* FIXME int index = mlp_lookup_ats(address, mlp->q[c]); */
+    int index = GNUNET_SYSERR;
 
     if (index == GNUNET_SYSERR)
       continue;
-
+    /* FIXME
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' value `%s': %f\n",
         GNUNET_i2s (&address->peer),
         mlp_ats_to_string(mlp->q[c]),
         (double) ats[index].value);
 
-    int i = mlpi->q_avg_i[c];
+    int i = mlpi->q_avg_i[c];*/
     double * qp = mlpi->q[c];
+    /* FIXME
     qp[i] = (double) ats[index].value;
+    */
 
     int t;
     for (t = 0; t < MLP_AVERAGING_QUEUE_LENGTH; t++)
@@ -1399,7 +1416,7 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address)
             c3 ++;
           }
         }
-        if (c3 > 0)
+        if ((c3 > 0) && (avg > 0))
           /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
           mlpi->q_averaged[c] = (double) c3 / avg;
         else
@@ -1424,7 +1441,7 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address)
             c3 ++;
           }
         }
-        if (c3 > 0)
+        if ((c3 > 0) && (avg > 0))
           /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
           mlpi->q_averaged[c] = (double) c3 / avg;
         else
@@ -1493,6 +1510,20 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address)
   }
 }
 
+
+/**
+ * Add a single address to the solve
+ *
+ * @param solver the solver Handle
+ * @param addresses the address hashmap containing all addresses
+ * @param address the address to add
+ */
+void
+GAS_mlp_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+{
+       LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s'\n", GNUNET_i2s(&address->peer));
+}
+
 /**
  * Updates a single address in the MLP problem
  *
@@ -1502,21 +1533,34 @@ update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address)
  * Otherwise the addresses' values can be updated and the existing base can
  * be reused
  *
- * @param mlp the MLP Handle
- * @param addresses the address hashmap
- *        the address has to be already removed from the hashmap
- * @param address the address to update
+ * @param solver the solver Handle
+ * @param addresses the address hashmap containing all addresses
+ * @param address the update address
+ * @param session the new session (if changed otherwise current)
+ * @param in_use the new address in use state (if changed otherwise current)
+ * @param atsi the latest ATS information
+ * @param atsi_count the atsi count
  */
 void
-GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+GAS_mlp_address_update (void *solver,
+                        struct GNUNET_CONTAINER_MultiHashMap *addresses,
+                        struct ATS_Address *address,
+                        uint32_t session,
+                        int in_use,
+                        const struct GNUNET_ATS_Information *atsi,
+                        uint32_t atsi_count)
 {
+  struct GAS_MLP_Handle *mlp = solver;
   int new;
   struct MLP_information *mlpi;
+  struct GAS_MLP_SolutionContext ctx;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s'\n", GNUNET_i2s(&address->peer));
 
   GNUNET_STATISTICS_update (mlp->stats, "# MLP address updates", 1, GNUNET_NO);
 
   /* We add a new address */
-  if (address->mlp_information == NULL)
+  if (address->solver_information == NULL)
     new = GNUNET_YES;
   else
     new = GNUNET_NO;
@@ -1537,7 +1581,7 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
       mlpi->q_averaged[c] = 0.0;
     }
 
-    address->mlp_information = mlpi;
+    address->solver_information = mlpi;
     mlp->addr_in_problem ++;
     GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", 1, GNUNET_NO);
 
@@ -1596,7 +1640,7 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
     mlp->presolver_required = GNUNET_YES;
   }
   if (mlp->auto_solve == GNUNET_YES)
-    GAS_mlp_solve_problem (mlp);
+    GAS_mlp_solve_problem (mlp, &ctx);
 }
 
 /**
@@ -1604,21 +1648,29 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
  *
  * The MLP problem has to be recreated and the problem has to be resolved
  *
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
  * @param addresses the address hashmap
  *        the address has to be already removed from the hashmap
  * @param address the address to delete
+ * @param session_only delete only session not whole address
  */
 void
-GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+GAS_mlp_address_delete (void *solver,
+    struct GNUNET_CONTAINER_MultiHashMap * addresses,
+    struct ATS_Address *address,
+    int session_only)
 {
+  struct GAS_MLP_Handle *mlp = solver;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for peer `%s'\n", GNUNET_i2s(&address->peer));
   GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
+  struct GAS_MLP_SolutionContext ctx;
 
   /* Free resources */
-  if (address->mlp_information != NULL)
+  if (address->solver_information != NULL)
   {
-    GNUNET_free (address->mlp_information);
-    address->mlp_information = NULL;
+    GNUNET_free (address->solver_information);
+    address->solver_information = NULL;
 
     mlp->addr_in_problem --;
     GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", -1, GNUNET_NO);
@@ -1654,27 +1706,27 @@ GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
     /* Recalculate */
     mlp->presolver_required = GNUNET_YES;
     if (mlp->auto_solve == GNUNET_YES)
-      GAS_mlp_solve_problem (mlp);
+      GAS_mlp_solve_problem (mlp, &ctx);
   }
 }
 
 static int
-mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *value)
+mlp_get_preferred_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
 
-  struct ATS_PreferedAddress *aa = (struct ATS_PreferedAddress *) cls;
+  struct ATS_Address *aa = (struct ATS_Address *) cls;
   struct ATS_Address *addr = value;
-  struct MLP_information *mlpi = addr->mlp_information;
+  struct MLP_information *mlpi = addr->solver_information;
   if (mlpi == NULL)
     return GNUNET_YES;
   if (mlpi->n == GNUNET_YES)
   {
-    aa->address = addr;
+    aa = addr;
     if (mlpi->b > (double) UINT32_MAX)
-      aa->bandwidth_out = UINT32_MAX;
+      aa->assigned_bw_out.value__ = htonl (UINT32_MAX);
     else
-      aa->bandwidth_out = (uint32_t) mlpi->b;
-    aa->bandwidth_in = 0;
+      aa->assigned_bw_out.value__ = htonl((uint32_t) mlpi->b);
+    aa->assigned_bw_in.value__ = htonl(0);
     return GNUNET_NO;
   }
   return GNUNET_YES;
@@ -1684,20 +1736,17 @@ mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *valu
 /**
  * Get the preferred address for a specific peer
  *
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
  * @param addresses address hashmap
  * @param peer the peer
  * @return suggested address
  */
-struct ATS_PreferedAddress *
-GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp,
+const struct ATS_Address *
+GAS_mlp_get_preferred_address (void *solver,
                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
                                const struct GNUNET_PeerIdentity *peer)
 {
-  struct ATS_PreferedAddress * aa = GNUNET_malloc (sizeof (struct ATS_PreferedAddress));
-  aa->address = NULL;
-  aa->bandwidth_in = 0;
-  aa->bandwidth_out = 0;
+  struct ATS_Address * aa = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n", GNUNET_i2s (peer));
   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, mlp_get_preferred_address_it, aa);
   return aa;
@@ -1707,33 +1756,39 @@ GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp,
 /**
  * Changes the preferences for a peer in the MLP problem
  *
- * @param mlp the MLP Handle
+ * @param solver the MLP Handle
+ * @param client client
  * @param peer the peer
  * @param kind the kind to change the preference
  * @param score the score
  */
 void
-GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
+GAS_mlp_address_change_preference (void *solver,
+                                   void *client,
                                    const struct GNUNET_PeerIdentity *peer,
                                    enum GNUNET_ATS_PreferenceKind kind,
                                    float score)
 {
+  struct GAS_MLP_Handle *mlp = solver;
   GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
 
-  struct ATS_Peer *p = mlp_find_peer (mlp, peer);
-  p = p;
+  //struct ATS_Peer *p = mlp_find_peer (mlp, peer);
+  //FIXME to finish implementation
   /* Here we have to do the matching */
+
 }
 
 /**
  * Shutdown the MLP problem solving component
- * @param mlp the MLP handle
+ *
+ * @param solver the solver handle
  */
 void
-GAS_mlp_done (struct GAS_MLP_Handle *mlp)
+GAS_mlp_done (void *solver)
 {
+  struct GAS_MLP_Handle *mlp = solver;
   struct ATS_Peer * peer;
-  struct ATS_Peer * tmp;
+  struct ATS_Address *addr;
 
   GNUNET_assert (mlp != NULL);
 
@@ -1747,10 +1802,16 @@ GAS_mlp_done (struct GAS_MLP_Handle *mlp)
   peer = mlp->peer_head;
   while (peer != NULL)
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up peer `%s'\n", GNUNET_i2s (&peer->id));
     GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
-    tmp = peer->next;
+    for (addr = peer->head; NULL != addr; addr = peer->head)
+    {
+      GNUNET_CONTAINER_DLL_remove(peer->head, peer->tail, addr);
+      GNUNET_free (addr->solver_information);
+      addr->solver_information = NULL;
+    }
     GNUNET_free (peer);
-    peer = tmp;
+    peer = mlp->peer_head;
   }
   mlp_delete_problem (mlp);