[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 */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r31244 - gnunet/src/ats,
gnunet <=