[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r29998 - in gnunet/src: ats include
From: |
gnunet |
Subject: |
[GNUnet-SVN] r29998 - in gnunet/src: ats include |
Date: |
Tue, 8 Oct 2013 18:34:07 +0200 |
Author: wachs
Date: 2013-10-08 18:34:07 +0200 (Tue, 08 Oct 2013)
New Revision: 29998
Added:
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/include/gnunet_ats_plugin.h
Removed:
gnunet/src/ats/gnunet-service-ats-solver_mlp.c
gnunet/src/ats/gnunet-service-ats-solver_mlp.h
gnunet/src/ats/gnunet-service-ats-solver_proportional.c
gnunet/src/ats/gnunet-service-ats-solver_proportional.h
Modified:
gnunet/src/ats/Makefile.am
gnunet/src/ats/ats_api_performance.c
gnunet/src/ats/gnunet-service-ats_addresses.c
gnunet/src/ats/gnunet-service-ats_addresses.h
Log:
ats solver are now implemented as plugins
initial commit: tests pass, no crashes with tests ...
Modified: gnunet/src/ats/Makefile.am
===================================================================
--- gnunet/src/ats/Makefile.am 2013-10-08 15:43:03 UTC (rev 29997)
+++ gnunet/src/ats/Makefile.am 2013-10-08 16:34:07 UTC (rev 29998)
@@ -1,5 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/src/include
+plugindir = $(libdir)/gnunet
+
pkgcfgdir= $(pkgdatadir)/config.d/
libexecdir= $(pkglibdir)/libexec/
@@ -17,7 +19,7 @@
if HAVE_LIBGLPK
GN_LIBGLPK = -lglpk
- GN_MLP_SRC = gnunet-service-ats-solver_mlp.c gnunet-service-ats-solver_mlp.h
+ GN_MLP_LIB = libgnunet_plugin_ats_mlp.la
GN_MLP_TEST = test_ats_mlp
GN_MLP_TEST_UPDATE = test_ats_mlp_update
GN_MLP_TEST_AVG = test_ats_mlp_averaging
@@ -32,6 +34,10 @@
lib_LTLIBRARIES = libgnunetats.la
+plugin_LTLIBRARIES = \
+ libgnunet_plugin_ats_proportional.la \
+ libgnunet_plugin_ats_mlp.la
+
libgnunetats_la_SOURCES = \
ats_api_scheduling.c \
ats_api_performance.c
@@ -48,13 +54,14 @@
libexec_PROGRAMS = \
gnunet-service-ats
+# gnunet-service-ats-solver_proportional.c
gnunet-service-ats-solver_proportional.h
+# $(GN_MLP_SRC)
+# gnunet-service-ats-solver_ril.c gnunet-service-ats-solver_ril.h
+
gnunet_service_ats_SOURCES = \
gnunet-service-ats.c gnunet-service-ats.h\
gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \
gnunet-service-ats_normalization.c gnunet-service-ats_normalization.h \
- gnunet-service-ats-solver_proportional.c
gnunet-service-ats-solver_proportional.h \
- $(GN_MLP_SRC) \
- gnunet-service-ats-solver_ril.c gnunet-service-ats-solver_ril.h \
gnunet-service-ats_performance.c gnunet-service-ats_performance.h \
gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \
gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h
@@ -62,7 +69,6 @@
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la \
libgnunetats.la \
- $(GN_LIBGLPK) \
$(GN_LIBINTL)
gnunet_service_ats_DEPENDENCIES = \
libgnunetats.la
@@ -121,6 +127,25 @@
TESTS = $(check_PROGRAMS)
endif
+libgnunet_plugin_ats_proportional_la_SOURCES = \
+ libgnunet_plugin_ats_proportional.c
+libgnunet_plugin_ats_proportional_la_LIBADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(LTLIBINTL)
+
+if HAVE_LIBGLPK
+endif
+libgnunet_plugin_ats_mlp_la_SOURCES = \
+ libgnunet_plugin_ats_mlp.c
+libgnunet_plugin_ats_mlp_la_LIBADD = \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBGLPK)
+libgnunet_plugin_ats_mlp_la_LDFLAGS = \
+ $(GN_LIBGLPK)
+
+
# scheduling API tests
test_ats_api_scheduling_init_SOURCES = \
Modified: gnunet/src/ats/ats_api_performance.c
===================================================================
--- gnunet/src/ats/ats_api_performance.c 2013-10-08 15:43:03 UTC (rev
29997)
+++ gnunet/src/ats/ats_api_performance.c 2013-10-08 16:34:07 UTC (rev
29998)
@@ -1,33 +1,32 @@
/*
- This file is part of GNUnet.
- (C) 2010,2011 Christian Grothoff (and other contributing authors)
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
+ GNUnet is 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.
+ 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.
-*/
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
/**
* @file ats/ats_api_performance.c
* @brief automatic transport selection and outbound bandwidth determination
* @author Christian Grothoff
* @author Matthias Wachs
- */
+ */
#include "platform.h"
#include "gnunet_ats_service.h"
#include "ats.h"
-
/**
* Message in linked list we should send to the ATS service. The
* actual binary message follows this struct.
@@ -56,7 +55,6 @@
int is_init;
};
-
/**
* Linked list of pending reservations.
*/
@@ -104,7 +102,6 @@
int undo;
};
-
/**
* Linked list of pending reservations.
*/
@@ -157,8 +154,6 @@
uint32_t id;
};
-
-
/**
* ATS Handle to obtain and/or modify performance information.
*/
@@ -215,7 +210,6 @@
*/
struct GNUNET_ATS_AddressListHandle *addresslist_tail;
-
/**
* Current request for transmission to ATS.
*/
@@ -237,7 +231,6 @@
uint32_t id;
};
-
/**
* Re-establish the connection to the ATS service.
*
@@ -246,7 +239,6 @@
static void
reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
-
/**
* Re-establish the connection to the ATS service.
*
@@ -262,7 +254,6 @@
reconnect (ph);
}
-
/**
* Transmit messages from the message queue to the service
* (if there are any, and if we are not already trying).
@@ -272,7 +263,6 @@
static void
do_transmit (struct GNUNET_ATS_PerformanceHandle *ph);
-
/**
* Type of a function to call when we receive a message
* from the service.
@@ -307,14 +297,13 @@
memcpy (&cbuf[ret], &p[1], p->size);
ret += p->size;
size -= p->size;
- GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p);
- GNUNET_free (p);
+ GNUNET_CONTAINER_DLL_remove(ph->pending_head, ph->pending_tail, p);
+ GNUNET_free(p);
}
do_transmit (ph);
return ret;
}
-
/**
* Transmit messages from the message queue to the service
* (if there are any, and if we are not already trying).
@@ -331,15 +320,11 @@
if (NULL == (p = ph->pending_head))
return;
if (NULL == ph->client)
- return; /* currently reconnecting */
- ph->th =
- GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES,
&transmit_message_to_ats,
- ph);
+ return; /* currently reconnecting */
+ ph->th = GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size,
+ GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_message_to_ats, ph);
}
-
/**
* We received a peer information message. Validate and process it.
*
@@ -349,7 +334,7 @@
*/
static int
process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph,
- const struct GNUNET_MessageHeader *msg)
+ const struct GNUNET_MessageHeader *msg)
{
const struct PeerInformationMessage *pi;
const struct GNUNET_ATS_Information *atsi;
@@ -361,9 +346,9 @@
uint32_t ats_count;
int addr_active;
- if (ntohs (msg->size) < sizeof (struct PeerInformationMessage))
+ if (ntohs (msg->size) < sizeof(struct PeerInformationMessage))
{
- GNUNET_break (0);
+ GNUNET_break(0);
return GNUNET_SYSERR;
}
@@ -375,31 +360,31 @@
atsi = (const struct GNUNET_ATS_Information *) &pi[1];
plugin_address = (const char *) &atsi[ats_count];
plugin_name = &plugin_address[plugin_address_length];
- if ((plugin_address_length + plugin_name_length +
- ats_count * sizeof (struct GNUNET_ATS_Information) +
- sizeof (struct PeerInformationMessage) != ntohs (msg->size)) ||
- (ats_count >
- GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
+ if ((plugin_address_length + plugin_name_length
+ + ats_count * sizeof(struct GNUNET_ATS_Information)
+ + sizeof(struct PeerInformationMessage) != ntohs (msg->size))
+ || (ats_count
+ > GNUNET_SERVER_MAX_MESSAGE_SIZE
+ / sizeof(struct GNUNET_ATS_Information))
|| (plugin_name[plugin_name_length - 1] != '\0'))
{
- GNUNET_break (0);
+ GNUNET_break(0);
return GNUNET_SYSERR;
}
if (NULL != ph->addr_info_cb)
{
- address.peer = pi->peer;
- address.address = plugin_address;
- address.address_length = plugin_address_length;
- address.transport_name = plugin_name;
+ address.peer = pi->peer;
+ address.address = plugin_address;
+ address.address_length = plugin_address_length;
+ address.transport_name = plugin_name;
- ph->addr_info_cb (ph->addr_info_cb_cls, &address, addr_active,
pi->bandwidth_out, pi->bandwidth_in,
- atsi, ats_count);
+ ph->addr_info_cb (ph->addr_info_cb_cls, &address, addr_active,
+ pi->bandwidth_out, pi->bandwidth_in, atsi, ats_count);
}
return GNUNET_OK;
}
-
/**
* We received a reservation result message. Validate and process it.
*
@@ -409,47 +394,46 @@
*/
static int
process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph,
- const struct GNUNET_MessageHeader *msg)
+ const struct GNUNET_MessageHeader *msg)
{
const struct ReservationResultMessage *rr;
struct GNUNET_ATS_ReservationContext *rc;
int32_t amount;
- if (ntohs (msg->size) < sizeof (struct ReservationResultMessage))
+ if (ntohs (msg->size) < sizeof(struct ReservationResultMessage))
{
- GNUNET_break (0);
+ GNUNET_break(0);
return GNUNET_SYSERR;
}
rr = (const struct ReservationResultMessage *) msg;
amount = ntohl (rr->amount);
rc = ph->reservation_head;
- if (0 != memcmp (&rr->peer, &rc->peer, sizeof (struct GNUNET_PeerIdentity)))
+ if (0 != memcmp (&rr->peer, &rc->peer, sizeof(struct GNUNET_PeerIdentity)))
{
- GNUNET_break (0);
+ GNUNET_break(0);
return GNUNET_SYSERR;
}
- GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail, rc);
- if ((amount == 0) || (rc->rcb != NULL))
+ GNUNET_CONTAINER_DLL_remove(ph->reservation_head, ph->reservation_tail, rc);
+ if ((amount == 0) || (rc->rcb != NULL ))
{
/* tell client if not cancelled */
- if (rc->rcb != NULL)
+ if (rc->rcb != NULL )
rc->rcb (rc->rcb_cls, &rr->peer, amount,
- GNUNET_TIME_relative_ntoh (rr->res_delay));
- GNUNET_free (rc);
+ GNUNET_TIME_relative_ntoh (rr->res_delay));
+ GNUNET_free(rc);
return GNUNET_OK;
}
/* amount non-zero, but client cancelled, consider undo! */
if (GNUNET_YES != rc->undo)
{
- GNUNET_free (rc);
- return GNUNET_OK; /* do not try to undo failed undos or negative
amounts */
+ GNUNET_free(rc);
+ return GNUNET_OK; /* do not try to undo failed undos or negative amounts */
}
- GNUNET_free (rc);
- (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL);
+ GNUNET_free(rc);
+ (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL );
return GNUNET_OK;
}
-
/**
* We received a reservation result message. Validate and process it.
*
@@ -459,7 +443,7 @@
*/
static int
process_ar_message (struct GNUNET_ATS_PerformanceHandle *ph,
- const struct GNUNET_MessageHeader *msg)
+ const struct GNUNET_MessageHeader *msg)
{
const struct PeerInformationMessage *pi;
struct GNUNET_ATS_AddressListHandle *alh;
@@ -476,13 +460,13 @@
uint32_t active;
uint32_t id;
- if (ntohs (msg->size) < sizeof (struct PeerInformationMessage))
+ if (ntohs (msg->size) < sizeof(struct PeerInformationMessage))
{
- GNUNET_break (0);
+ GNUNET_break(0);
return GNUNET_SYSERR;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Received %s message\n"), "ATS_ADDRESSLIST_RESPONSE");
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Received %s message\n"),
+ "ATS_ADDRESSLIST_RESPONSE");
pi = (const struct PeerInformationMessage *) msg;
id = ntohl (pi->id);
@@ -493,49 +477,47 @@
atsi = (const struct GNUNET_ATS_Information *) &pi[1];
plugin_address = (const char *) &atsi[ats_count];
plugin_name = &plugin_address[plugin_address_length];
- if ((plugin_address_length + plugin_name_length +
- ats_count * sizeof (struct GNUNET_ATS_Information) +
- sizeof (struct PeerInformationMessage) != ntohs (msg->size)) ||
- (ats_count >
- GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
+ if ((plugin_address_length + plugin_name_length
+ + ats_count * sizeof(struct GNUNET_ATS_Information)
+ + sizeof(struct PeerInformationMessage) != ntohs (msg->size))
+ || (ats_count
+ > GNUNET_SERVER_MAX_MESSAGE_SIZE
+ / sizeof(struct GNUNET_ATS_Information))
|| (plugin_name[plugin_name_length - 1] != '\0'))
{
- GNUNET_break (0);
+ GNUNET_break(0);
return GNUNET_SYSERR;
}
next = ph->addresslist_head;
while (NULL != (alh = next))
{
- next = alh->next;
- if (alh->id == id)
- break;
+ next = alh->next;
+ if (alh->id == id)
+ break;
}
if (NULL == alh)
{
- /* was canceled */
- return GNUNET_SYSERR;
+ /* was canceled */
+ return GNUNET_SYSERR;
}
- memset (&allzeros, '\0', sizeof (allzeros));
- if ((0 == memcmp (&allzeros, &pi->peer, sizeof (allzeros))) &&
- (0 == plugin_name_length) &&
- (0 == plugin_address_length) &&
- (0 == ats_count))
+ memset (&allzeros, '\0', sizeof(allzeros));
+ if ((0 == memcmp (&allzeros, &pi->peer, sizeof(allzeros)))
+ && (0 == plugin_name_length) && (0 == plugin_address_length)
+ && (0 == ats_count))
{
- /* Done */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Received last message for %s \n"), "ATS_ADDRESSLIST_RESPONSE");
- bandwidth_zero.value__ = htonl (0);
- if (NULL != alh->cb)
- alh->cb (ph->addr_info_cb_cls,
- NULL,
- GNUNET_NO,
- bandwidth_zero, bandwidth_zero,
- NULL, 0);
- GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, ph->addresslist_tail,
alh);
- GNUNET_free (alh);
- return GNUNET_OK;
+ /* Done */
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Received last message for %s \n"),
+ "ATS_ADDRESSLIST_RESPONSE");
+ bandwidth_zero.value__ = htonl (0);
+ if (NULL != alh->cb)
+ alh->cb (ph->addr_info_cb_cls, NULL, GNUNET_NO, bandwidth_zero,
+ bandwidth_zero, NULL, 0);
+ GNUNET_CONTAINER_DLL_remove(ph->addresslist_head, ph->addresslist_tail,
+ alh);
+ GNUNET_free(alh);
+ return GNUNET_OK;
}
address.peer = pi->peer;
@@ -546,16 +528,12 @@
if ((GNUNET_YES == alh->all_addresses) || (GNUNET_YES == active))
{
if (NULL != alh->cb)
- alh->cb (ph->addr_info_cb_cls,
- &address,
- active,
- pi->bandwidth_out, pi->bandwidth_in,
- atsi, ats_count);
+ alh->cb (ph->addr_info_cb_cls, &address, active, pi->bandwidth_out,
+ pi->bandwidth_in, atsi, ats_count);
}
return GNUNET_OK;
}
-
/**
* Type of a function to call when we receive a message
* from the service.
@@ -585,26 +563,23 @@
goto reconnect;
break;
default:
- GNUNET_break (0);
+ GNUNET_break(0);
goto reconnect;
}
GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
- GNUNET_TIME_UNIT_FOREVER_REL);
+ GNUNET_TIME_UNIT_FOREVER_REL);
return;
-reconnect:
- if (NULL != ph->th)
+ reconnect: if (NULL != ph->th)
{
GNUNET_CLIENT_notify_transmit_ready_cancel (ph->th);
ph->th = NULL;
}
GNUNET_CLIENT_disconnect (ph->client);
ph->client = NULL;
- ph->task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
- ph);
+ ph->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &reconnect_task, ph);
}
-
/**
* Re-establish the connection to the ATS service.
*
@@ -616,30 +591,28 @@
struct PendingMessage *p;
struct ClientStartMessage *init;
- GNUNET_assert (NULL == ph->client);
+ GNUNET_assert(NULL == ph->client);
ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg);
- GNUNET_assert (NULL != ph->client);
+ GNUNET_assert(NULL != ph->client);
GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph,
- GNUNET_TIME_UNIT_FOREVER_REL);
+ GNUNET_TIME_UNIT_FOREVER_REL);
if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init))
{
p = GNUNET_malloc (sizeof (struct PendingMessage) +
- sizeof (struct ClientStartMessage));
- p->size = sizeof (struct ClientStartMessage);
+ sizeof (struct ClientStartMessage));
+ p->size = sizeof(struct ClientStartMessage);
p->is_init = GNUNET_YES;
init = (struct ClientStartMessage *) &p[1];
init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
- init->header.size = htons (sizeof (struct ClientStartMessage));
- init->start_flag =
- htonl ((NULL ==ph->addr_info_cb) ?
- START_FLAG_PERFORMANCE_NO_PIC :
START_FLAG_PERFORMANCE_WITH_PIC);
- GNUNET_CONTAINER_DLL_insert (ph->pending_head, ph->pending_tail, p);
+ init->header.size = htons (sizeof(struct ClientStartMessage));
+ init->start_flag = htonl (
+ (NULL == ph->addr_info_cb) ?
+ START_FLAG_PERFORMANCE_NO_PIC : START_FLAG_PERFORMANCE_WITH_PIC);
+ GNUNET_CONTAINER_DLL_insert(ph->pending_head, ph->pending_tail, p);
}
do_transmit (ph);
}
-
-
/**
* Get handle to access performance API of the ATS subsystem.
*
@@ -651,8 +624,7 @@
*/
struct GNUNET_ATS_PerformanceHandle *
GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
- GNUNET_ATS_AddressInformationCallback
addr_info_cb,
- void *addr_info_cb_cls)
+ GNUNET_ATS_AddressInformationCallback addr_info_cb, void *addr_info_cb_cls)
{
struct GNUNET_ATS_PerformanceHandle *ph;
@@ -660,7 +632,7 @@
ph->cfg = cfg;
ph->addr_info_cb = addr_info_cb;
ph->addr_info_cb_cls = addr_info_cb_cls;
- ph->id = 0;
+ ph->id = 0;
reconnect (ph);
return ph;
}
@@ -679,21 +651,20 @@
while (NULL != (p = ph->pending_head))
{
- GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p);
- GNUNET_free (p);
+ GNUNET_CONTAINER_DLL_remove(ph->pending_head, ph->pending_tail, p);
+ GNUNET_free(p);
}
while (NULL != (alh = ph->addresslist_head))
{
- GNUNET_CONTAINER_DLL_remove (ph->addresslist_head, ph->addresslist_tail,
- alh);
- GNUNET_free (alh);
+ GNUNET_CONTAINER_DLL_remove(ph->addresslist_head, ph->addresslist_tail,
+ alh);
+ GNUNET_free(alh);
}
while (NULL != (rc = ph->reservation_head))
{
- GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail,
- rc);
- GNUNET_break (NULL == rc->rcb);
- GNUNET_free (rc);
+ GNUNET_CONTAINER_DLL_remove(ph->reservation_head, ph->reservation_tail,
rc);
+ GNUNET_break(NULL == rc->rcb);
+ GNUNET_free(rc);
}
if (GNUNET_SCHEDULER_NO_TASK != ph->task)
@@ -706,10 +677,9 @@
GNUNET_CLIENT_disconnect (ph->client);
ph->client = NULL;
}
- GNUNET_free (ph);
+ GNUNET_free(ph);
}
-
/**
* Reserve inbound bandwidth from the given peer. ATS will look at
* the current amount of traffic we receive from the peer and ensure
@@ -726,9 +696,8 @@
*/
struct GNUNET_ATS_ReservationContext *
GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph,
- const struct GNUNET_PeerIdentity *peer,
- int32_t amount,
- GNUNET_ATS_ReservationCallback rcb, void
*rcb_cls)
+ const struct GNUNET_PeerIdentity *peer, int32_t amount,
+ GNUNET_ATS_ReservationCallback rcb, void *rcb_cls)
{
struct GNUNET_ATS_ReservationContext *rc;
struct PendingMessage *p;
@@ -739,26 +708,24 @@
rc->peer = *peer;
rc->rcb = rcb;
rc->rcb_cls = rcb_cls;
- if ((rcb != NULL) && (amount > 0))
- rc->undo = GNUNET_YES;
- GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head, ph->reservation_tail,
- rc);
+ if ((rcb != NULL )&& (amount > 0))rc->undo = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert_tail(ph->reservation_head, ph->reservation_tail,
+ rc);
p = GNUNET_malloc (sizeof (struct PendingMessage) +
- sizeof (struct ReservationRequestMessage));
- p->size = sizeof (struct ReservationRequestMessage);
+ sizeof (struct ReservationRequestMessage));
+ p->size = sizeof(struct ReservationRequestMessage);
p->is_init = GNUNET_NO;
m = (struct ReservationRequestMessage *) &p[1];
m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST);
- m->header.size = htons (sizeof (struct ReservationRequestMessage));
+ m->header.size = htons (sizeof(struct ReservationRequestMessage));
m->amount = htonl (amount);
m->peer = *peer;
- GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
+ GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p);
do_transmit (ph);
return rc;
}
-
/**
* Cancel request for reserving bandwidth.
*
@@ -783,23 +750,22 @@
* @return ats performance context
*/
struct GNUNET_ATS_AddressListHandle*
-GNUNET_ATS_performance_list_addresses (struct GNUNET_ATS_PerformanceHandle
*handle,
- const struct GNUNET_PeerIdentity *peer,
- int all,
- GNUNET_ATS_AddressInformationCallback
infocb,
- void *infocb_cls)
+GNUNET_ATS_performance_list_addresses (
+ struct GNUNET_ATS_PerformanceHandle *handle,
+ const struct GNUNET_PeerIdentity *peer, int all,
+ GNUNET_ATS_AddressInformationCallback infocb, void *infocb_cls)
{
struct GNUNET_ATS_AddressListHandle *alh;
struct PendingMessage *p;
struct AddressListRequestMessage *m;
- GNUNET_assert (NULL != handle);
+ GNUNET_assert(NULL != handle);
if (NULL == infocb)
- return NULL;
+ return NULL ;
alh = GNUNET_malloc (sizeof (struct GNUNET_ATS_AddressListHandle));
alh->id = handle->id;
- handle->id ++;
+ handle->id++;
alh->cb = infocb;
alh->cb_cls = infocb_cls;
alh->ph = handle;
@@ -808,49 +774,51 @@
alh->all_peers = GNUNET_YES;
else
{
- alh->all_peers = GNUNET_NO;
- alh->peer = (*peer);
+ alh->all_peers = GNUNET_NO;
+ alh->peer = (*peer);
}
- GNUNET_CONTAINER_DLL_insert (handle->addresslist_head,
handle->addresslist_tail, alh);
+ GNUNET_CONTAINER_DLL_insert(handle->addresslist_head,
+ handle->addresslist_tail, alh);
p = GNUNET_malloc (sizeof (struct PendingMessage) +
- sizeof (struct AddressListRequestMessage));
- p->size = sizeof (struct AddressListRequestMessage);
+ sizeof (struct AddressListRequestMessage));
+ p->size = sizeof(struct AddressListRequestMessage);
m = (struct AddressListRequestMessage *) &p[1];
m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST);
- m->header.size = htons (sizeof (struct AddressListRequestMessage));
+ m->header.size = htons (sizeof(struct AddressListRequestMessage));
m->all = htonl (all);
m->id = htonl (alh->id);
if (NULL != peer)
m->peer = *peer;
else
{
- memset (&m->peer, '\0', sizeof (struct GNUNET_PeerIdentity));
+ memset (&m->peer, '\0', sizeof(struct GNUNET_PeerIdentity));
}
- GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head,
handle->pending_tail, p);
+ GNUNET_CONTAINER_DLL_insert_tail(handle->pending_head, handle->pending_tail,
+ p);
do_transmit (handle);
return alh;
}
-
/**
* Cancel a pending address listing operation
*
* @param handle the GNUNET_ATS_AddressListHandle handle to cancel
*/
void
-GNUNET_ATS_performance_list_addresses_cancel (struct
GNUNET_ATS_AddressListHandle *handle)
+GNUNET_ATS_performance_list_addresses_cancel (
+ struct GNUNET_ATS_AddressListHandle *handle)
{
- GNUNET_assert (NULL != handle);
+ GNUNET_assert(NULL != handle);
- GNUNET_CONTAINER_DLL_remove (handle->ph->addresslist_head,
handle->ph->addresslist_tail, handle);
- GNUNET_free (handle);
+ GNUNET_CONTAINER_DLL_remove(handle->ph->addresslist_head,
+ handle->ph->addresslist_tail, handle);
+ GNUNET_free(handle);
}
-
/**
* Convert a GNUNET_ATS_PreferenceType to a string
*
@@ -863,10 +831,9 @@
char *prefs[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
if (type < GNUNET_ATS_PreferenceCount)
return prefs[type];
- return NULL;
+ return NULL ;
}
-
/**
* Change preferences for the given peer. Preference changes are forgotten if
peers
* disconnect.
@@ -876,8 +843,9 @@
* @param ... 0-terminated specification of the desired changes
*/
void
-GNUNET_ATS_performance_change_preference (struct GNUNET_ATS_PerformanceHandle
*ph,
- const struct GNUNET_PeerIdentity *peer, ...)
+GNUNET_ATS_performance_change_preference (
+ struct GNUNET_ATS_PerformanceHandle *ph,
+ const struct GNUNET_PeerIdentity *peer, ...)
{
struct PendingMessage *p;
struct ChangePreferenceMessage *m;
@@ -888,9 +856,9 @@
enum GNUNET_ATS_PreferenceKind kind;
count = 0;
- va_start (ap, peer);
- while (GNUNET_ATS_PREFERENCE_END !=
- (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
+ va_start(ap, peer);
+ while (GNUNET_ATS_PREFERENCE_END != (kind =
+ va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
{
switch (kind)
{
@@ -905,13 +873,12 @@
break;
default:
- GNUNET_assert (0);
+ GNUNET_assert(0);
}
}
- va_end (ap);
- msize =
- count * sizeof (struct PreferenceInformation) +
- sizeof (struct ChangePreferenceMessage);
+ va_end(ap);
+ msize = count * sizeof(struct PreferenceInformation)
+ + sizeof(struct ChangePreferenceMessage);
p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
p->size = msize;
p->is_init = GNUNET_NO;
@@ -922,9 +889,9 @@
m->peer = *peer;
pi = (struct PreferenceInformation *) &m[1];
count = 0;
- va_start (ap, peer);
- while (GNUNET_ATS_PREFERENCE_END !=
- (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
+ va_start(ap, peer);
+ while (GNUNET_ATS_PREFERENCE_END != (kind =
+ va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
{
pi[count].preference_kind = htonl (kind);
switch (kind)
@@ -940,11 +907,11 @@
count++;
break;
default:
- GNUNET_assert (0);
+ GNUNET_assert(0);
}
}
- va_end (ap);
- GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
+ va_end(ap);
+ GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p);
do_transmit (ph);
}
@@ -959,8 +926,8 @@
*/
void
GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph,
-
const
struct GNUNET_PeerIdentity *peer,
-
const
struct GNUNET_TIME_Relative scope, ...)
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_TIME_Relative scope, ...)
{
struct PendingMessage *p;
struct FeedbackPreferenceMessage *m;
@@ -971,9 +938,9 @@
enum GNUNET_ATS_PreferenceKind kind;
count = 0;
- va_start (ap, scope);
- while (GNUNET_ATS_PREFERENCE_END !=
- (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
+ va_start(ap, scope);
+ while (GNUNET_ATS_PREFERENCE_END != (kind =
+ va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
{
switch (kind)
{
@@ -988,13 +955,12 @@
break;
default:
- GNUNET_assert (0);
+ GNUNET_assert(0);
}
}
- va_end (ap);
- msize =
- count * sizeof (struct PreferenceInformation) +
- sizeof (struct FeedbackPreferenceMessage);
+ va_end(ap);
+ msize = count * sizeof(struct PreferenceInformation)
+ + sizeof(struct FeedbackPreferenceMessage);
p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
p->size = msize;
p->is_init = GNUNET_NO;
@@ -1006,9 +972,9 @@
m->peer = *peer;
pi = (struct PreferenceInformation *) &m[1];
count = 0;
- va_start (ap, scope);
- while (GNUNET_ATS_PREFERENCE_END !=
- (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind)))
+ va_start(ap, scope);
+ while (GNUNET_ATS_PREFERENCE_END != (kind =
+ va_arg (ap, enum GNUNET_ATS_PreferenceKind) ))
{
pi[count].preference_kind = htonl (kind);
switch (kind)
@@ -1024,11 +990,11 @@
count++;
break;
default:
- GNUNET_assert (0);
+ GNUNET_assert(0);
}
}
- va_end (ap);
- GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p);
+ va_end(ap);
+ GNUNET_CONTAINER_DLL_insert_tail(ph->pending_head, ph->pending_tail, p);
do_transmit (ph);
}
Deleted: gnunet/src/ats/gnunet-service-ats-solver_mlp.c
===================================================================
--- gnunet/src/ats/gnunet-service-ats-solver_mlp.c 2013-10-08 15:43:03 UTC
(rev 29997)
+++ gnunet/src/ats/gnunet-service-ats-solver_mlp.c 2013-10-08 16:34:07 UTC
(rev 29998)
@@ -1,2119 +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/gnunet-service-ats-solver_mlp.c
- * @brief ats mlp problem solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet-service-ats-solver_mlp.h"
-#include "gnunet_statistics_service.h"
-#include "glpk.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_UP:
- return "GNUNET_ATS_UTILIZATION_UP";
- case GNUNET_ATS_UTILIZATION_DOWN:
- return "GNUNET_ATS_UTILIZATION_DOWN";
- 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;
-}
-
-/**
- * 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_build;
- struct GNUNET_TIME_Relative duration_build;
- struct GNUNET_TIME_Absolute start_lp;
- struct GNUNET_TIME_Relative duration_lp;
- struct GNUNET_TIME_Absolute start_mlp;
- struct GNUNET_TIME_Relative duration_mlp;
- GNUNET_assert (NULL != solver);
-
- if (GNUNET_YES == mlp->bulk_lock)
- {
- mlp->bulk_request ++;
- return GNUNET_NO;
- }
-
- if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->requested_peers))
- return GNUNET_OK; /* No pending requests */
- if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->addresses))
- 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");
- return GNUNET_OK;
- }
- if (GNUNET_YES == mlp->mlp_prob_changed)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
- mlp_delete_problem (mlp);
- start_build = GNUNET_TIME_absolute_get();
- if (GNUNET_SYSERR == mlp_create_problem (mlp))
- return GNUNET_SYSERR;
- duration_build = GNUNET_TIME_absolute_get_duration (start_build);
- 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");
- duration_build.rel_value_us = 0;
- }
-
- /* Run LP solver */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Running LP solver %s\n",
- (GLP_YES == mlp->control_param_lp.presolve)? "with presolver": "without
presolver");
- start_lp = GNUNET_TIME_absolute_get();
- res_lp = mlp_solve_lp_problem (mlp);
- duration_lp = GNUNET_TIME_absolute_get_duration (start_lp);
-
-
- /* Run MLP solver */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
- start_mlp = GNUNET_TIME_absolute_get();
- res_mip = mlp_solve_mlp_problem (mlp);
-
- duration_mlp = GNUNET_TIME_absolute_get_duration (start_mlp);
-
- /* Save stats */
- mlp->ps.lp_res = res_lp;
- mlp->ps.mip_res = res_mip;
- mlp->ps.build_dur = duration_build;
- mlp->ps.lp_dur = duration_lp;
- mlp->ps.mip_dur = duration_mlp;
- 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;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Execution time: Build %s\n",
- GNUNET_STRINGS_relative_time_to_string (duration_build, GNUNET_NO));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Execution time: LP %s\n",
- GNUNET_STRINGS_relative_time_to_string (duration_lp, GNUNET_NO));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Execution time: MLP %s\n",
- GNUNET_STRINGS_relative_time_to_string (duration_mlp, GNUNET_NO));
-
- /* Propagate result*/
- if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
- {
- GNUNET_CONTAINER_multipeermap_iterate (mlp->addresses,
&mlp_propagate_results, mlp);
- }
-
- 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 (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 (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 solver the solver handle
- */
-void
-GAS_mlp_done (void *solver)
-{
- struct GAS_MLP_Handle *mlp = solver;
- 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");
-}
-
-
-/**
- * Init the MLP problem solving component
- *
- * @param cfg the GNUNET_CONFIGURATION_Handle handle
- * @param stats the GNUNET_STATISTICS handle
- * @param addresses the address hashmap
- * @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
- * @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)
-{
- 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 != cfg);
- GNUNET_assert (NULL != stats);
- GNUNET_assert (NULL != addresses);
- GNUNET_assert (NULL != bw_changed_cb);
- GNUNET_assert (NULL != get_preference);
- GNUNET_assert (NULL != get_properties);
-
- /* 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 (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 (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(cfg, "ats",
"MLP_MAX_DURATION", &max_duration))
- {
- max_duration = MLP_MAX_EXEC_DURATION;
- }
-
- /* Get maximum number of iterations */
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(cfg, "ats",
"MLP_MAX_ITERATIONS", &max_iterations))
- {
- max_iterations = MLP_MAX_ITERATIONS;
- }
-
- /* Get diversity coefficient from configuration */
- if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
- "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 (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 (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 (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 (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 (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 (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 < dest_length; c2++)
- {
- if (quotas[c] == network[c2])
- {
- mlp->pv.quota_index[c] = network[c2];
- mlp->pv.quota_out[c] = out_dest[c2];
- mlp->pv.quota_in[c] = in_dest[c2];
- found = GNUNET_YES;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Quota for network `%s' (in/out)
%llu/%llu\n",
-
GNUNET_ATS_print_network_type(mlp->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]);
- }
- }
-
- /* Assign options to handle */
- mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
- mlp->addresses = addresses;
- mlp->bw_changed_cb = bw_changed_cb;
- mlp->bw_changed_cb_cls = bw_changed_cb_cls;
- mlp->get_preferences = get_preference;
- mlp->get_preferences_cls = get_preference_cls;
- mlp->get_properties = get_properties;
- mlp->get_properties_cls = get_properties_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/gnunet-service-ats-solver_mlp.h
===================================================================
--- gnunet/src/ats/gnunet-service-ats-solver_mlp.h 2013-10-08 15:43:03 UTC
(rev 29997)
+++ gnunet/src/ats/gnunet-service-ats-solver_mlp.h 2013-10-08 16:34:07 UTC
(rev 29998)
@@ -1,551 +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/gnunet-service-ats-solver_mlp.h
- * @brief ats MLP problem solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-ats_addresses.h"
-#if HAVE_LIBGLPK
-#include "glpk.h"
-#endif
-
-#ifndef GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
-#define GNUNET_SERVICE_ATS_ADDRESSES_MLP_H
-
-#define 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
-{
- struct GNUNET_TIME_Relative build_dur;
- struct GNUNET_TIME_Relative lp_dur;
- struct GNUNET_TIME_Relative mip_dur;
-
- 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
-{
- /**
- * 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 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 callback to get relative preferences for a peer
- * @param get_properties_cls for 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/gnunet-service-ats-solver_proportional.c
===================================================================
--- gnunet/src/ats/gnunet-service-ats-solver_proportional.c 2013-10-08
15:43:03 UTC (rev 29997)
+++ gnunet/src/ats/gnunet-service-ats-solver_proportional.c 2013-10-08
16:34:07 UTC (rev 29998)
@@ -1,1528 +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/gnunet-service-ats-solver_proportional.c
- * @brief ATS proportional solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet-service-ats_addresses.h"
-#include "gnunet_statistics_service.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
-{
- /**
- * 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 networks;
-
-};
-
-/**
- * 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;
-};
-
-/**
- * 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
- * ---------------------------
- */
-
-/**
- * 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_in_network (struct GAS_PROPORTIONAL_Handle *s,
- struct Network *net, struct ATS_Address *address_except)
-{
- 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;
- struct AddressWrapper *cur;
-
- if (GNUNET_YES == s->bulk_lock)
- {
- s->bulk_requests++;
- return;
- }
-
- 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 */
- if ((assigned_quota_in != ntohl (cur->addr->assigned_bw_in.value__))
- || (assigned_quota_out != ntohl (cur->addr->assigned_bw_out.value__)))
- {
- cur->addr->assigned_bw_in.value__ = htonl (assigned_quota_in);
- cur->addr->assigned_bw_out.value__ = htonl (assigned_quota_out);
- /* Notify on change */
- if ((GNUNET_YES == cur->addr->active) && (cur->addr != address_except))
- s->bw_changed (s->bw_changed_cls, cur->addr);
- }
-
- }
- 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 Network *net = (struct Network *) current->solver_information;
- const double *norm_prop_cur;
- const double *norm_prop_prev;
- int index;
-
- 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 (net))
- 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
- * ---------------------------
- */
-
-/**
- * Update bandwidth assignment for all networks
- *
- * @param s the solver handle
- */
-static void
-distribute_bandwidth_in_all_networks (struct GAS_PROPORTIONAL_Handle *s)
-{
- int i;
- for (i = 0; i < s->networks; i++)
- distribute_bandwidth_in_network (s, &s->network_entries[i], NULL );
-}
-
-/**
- * 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->networks; 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_all_networks (s);
-}
-
-
-/**
- * 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;
-
- 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));
- net_cur = (struct Network *) fba_ctx.best->solver_information;
- 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)
- {
- net_prev = (struct Network *) prev->solver_information;
- 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
(fba_ctx.best->solver_information)))
- {
- 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 Network *cur_net;
-
- if (GNUNET_YES
- == GNUNET_CONTAINER_multipeermap_contains (s->requests,
- peer))
- GNUNET_CONTAINER_multipeermap_remove (s->requests, peer,
- NULL);
-
- cur = get_active_address (s,
- s->addresses, peer);
- if (NULL != cur)
- {
- /* Disabling current address */
- cur_net = (struct Network *) cur->solver_information;
- 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;
- 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
- */
-
- net = (struct Network *) address->solver_information;
-
- 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(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_DEBUG,
- "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_all_networks (s);
- 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;
-
- GNUNET_assert(NULL != solver);
- GNUNET_assert(NULL != address);
-
- s = (struct GAS_PROPORTIONAL_Handle *) solver;
- n = (struct Network *) address->solver_information;
-
- 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_UP:
- case GNUNET_ATS_UTILIZATION_DOWN:
- 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, GNUNET_NO);
- 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 ATS_Address *new;
- struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *)
solver;
- 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 == (new = (struct ATS_Address *)
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*/
- address->solver_information = 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
- == (new =
- (struct ATS_Address *) 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;
- const struct ATS_Address *new_address;
-
- 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);
- aw->addr->solver_information = net;
-
- if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (s->requests,
&address->peer))
- {
- if (NULL == get_active_address (s, s->addresses, &address->peer))
- {
- if (NULL != (new_address = GAS_proportional_get_preferred_address (s,
&address->peer)))
- s->bw_changed (s->bw_changed_cls, (struct ATS_Address *) address);
- }
- }
- LOG(GNUNET_ERROR_TYPE_DEBUG,
- "After adding address now total %u and active %u addresses in network
`%s'\n",
- net->total_addresses, net->active_addresses, net->desc);
-}
-
-/**
- * Init the proportional problem solver
- *
- * Quotas:
- * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
- * out_quota[i] contains outbound quota for network type i
- * in_quota[i] contains inbound quota for network type i
- *
- * Example
- * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK,
GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
- * network[2] == GNUNET_ATS_NET_LAN
- * out_quota[2] == 65353
- * in_quota[2] == 65353
- *
- * @param cfg configuration handle
- * @param stats the GNUNET_STATISTICS handle
- * @param addresses hashmap containing all addresses
- * @param network array of GNUNET_ATS_NetworkType with length dest_length
- * @param out_quota array of outbound quotas
- * @param in_quota 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
- * @param get_properties for callback to get relative properties
- * @param get_properties_cls cls for callback to get relative properties
- * @return handle for the solver on success, NULL on fail
- */
-void *
-GAS_proportional_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_quota, unsigned long long
*in_quota,
- 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)
-{
- int c;
- struct GAS_PROPORTIONAL_Handle *s =
- GNUNET_malloc (sizeof (struct GAS_PROPORTIONAL_Handle));
- struct Network * cur;
- char * net_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
-
- GNUNET_assert(NULL != cfg);
- GNUNET_assert(NULL != stats);
- GNUNET_assert(NULL != network);
- GNUNET_assert(NULL != bw_changed_cb);
- GNUNET_assert(NULL != get_preference);
- GNUNET_assert(NULL != get_properties);
-
- s->stats = (struct GNUNET_STATISTICS_Handle *) stats;
- s->bw_changed = bw_changed_cb;
- s->bw_changed_cls = bw_changed_cb_cls;
- s->get_preferences = get_preference;
- s->get_preferences_cls = get_preference_cls;
- s->get_properties = get_properties;
- s->get_properties_cls = get_properties_cls;
- s->networks = dest_length;
- s->network_entries = GNUNET_malloc (dest_length * sizeof (struct Network));
- s->active_addresses = 0;
- s->total_addresses = 0;
- s->bulk_lock = GNUNET_NO;
- s->addresses = addresses;
-
- s->requests = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
-
- for (c = 0; c < dest_length; c++)
- {
- cur = &s->network_entries[c];
- cur->total_addresses = 0;
- cur->active_addresses = 0;
- cur->type = network[c];
- cur->total_quota_in = in_quota[c];
- cur->total_quota_out = 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);
- }
- return s;
-}
-
-/**
- * Shutdown the proportional problem solver
- *
- * @param solver the respective handle to shutdown
- */
-void
-GAS_proportional_done (void *solver)
-{
- struct GAS_PROPORTIONAL_Handle *s = solver;
- struct AddressWrapper *cur;
- struct AddressWrapper *next;
- int c;
- GNUNET_assert(s != NULL);
-
- for (c = 0; c < s->networks; c++)
- {
- if (s->network_entries[c].total_addresses > 0)
- {
- LOG(GNUNET_ERROR_TYPE_ERROR,
- "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_ERROR,
- "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(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_ERROR,
- "Had %u addresses not deleted during shutdown\n", s->total_addresses);
- GNUNET_break(0);
- }
- if (s->active_addresses > 0)
- {
- LOG(GNUNET_ERROR_TYPE_ERROR,
- "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);
-}
-
-/* end of gnunet-service-ats-solver_proportional.c */
Deleted: gnunet/src/ats/gnunet-service-ats-solver_proportional.h
===================================================================
--- gnunet/src/ats/gnunet-service-ats-solver_proportional.h 2013-10-08
15:43:03 UTC (rev 29997)
+++ gnunet/src/ats/gnunet-service-ats-solver_proportional.h 2013-10-08
16:34:07 UTC (rev 29998)
@@ -1,224 +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/gnunet-service-ats-solver_proportional.h
- * @brief ATS proportional solver
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_statistics_service.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);
-
-/**
- * Init the proportional problem solver
- *
- * Quotas:
- * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
- * out_quota[i] contains outbound quota for network type i
- * in_quota[i] contains inbound quota for network type i
- *
- * Example
- * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK,
GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
- * network[2] == GNUNET_ATS_NET_LAN
- * out_quota[2] == 65353
- * in_quota[2] == 65353
- *
- * @param cfg configuration handle
- * @param stats the GNUNET_STATISTICS handle
- * @param network array of GNUNET_ATS_NetworkType with length dest_length
- * @param addresses hashmap containing all addresses
- * @param out_quota array of outbound quotas
- * @param in_quota 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
- * @param get_properties_cls for callback to get relative properties
- * @param get_properties_cls cls for callback to get relative properties
- * @return handle for the solver on success, NULL on fail
- */
-void *
-GAS_proportional_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_quota, unsigned long long *in_quota,
- 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);
-
-/**
- * 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 */
Modified: gnunet/src/ats/gnunet-service-ats_addresses.c
===================================================================
--- gnunet/src/ats/gnunet-service-ats_addresses.c 2013-10-08 15:43:03 UTC
(rev 29997)
+++ gnunet/src/ats/gnunet-service-ats_addresses.c 2013-10-08 16:34:07 UTC
(rev 29998)
@@ -26,17 +26,21 @@
*/
#include "platform.h"
#include "gnunet_ats_service.h"
+#include "gnunet_ats_plugin.h"
#include "gnunet-service-ats.h"
#include "gnunet-service-ats_addresses.h"
#include "gnunet-service-ats_normalization.h"
#include "gnunet-service-ats_performance.h"
#include "gnunet-service-ats_scheduling.h"
#include "gnunet-service-ats_reservations.h"
+
+#if 0
#if HAVE_LIBGLPK
#include "gnunet-service-ats-solver_mlp.h"
#endif
#include "gnunet-service-ats-solver_proportional.h"
#include "gnunet-service-ats-solver_ril.h"
+#endif
/**
* NOTE: Do not change this documentation. This documentation is based on
@@ -332,64 +336,9 @@
struct GAS_Addresses_Suggestion_Requests *r_tail;
/* Solver functions */
+ struct GNUNET_ATS_PluginEnvironment env;
- /**
- * Initialize solver
- */
- GAS_solver_init s_init;
-
- /**
- * Add an address to the solver
- */
- GAS_solver_address_add s_add;
-
- GAS_solver_address_property_changed s_address_update_property;
-
- GAS_solver_address_session_changed s_address_update_session;
-
- GAS_solver_address_inuse_changed s_address_update_inuse;
-
- GAS_solver_address_network_changed s_address_update_network;
-
- /**
- * Get address from solver
- */
- GAS_solver_get_preferred_address s_get;
-
- /**
- * Get address from solver
- */
- GAS_solver_stop_get_preferred_address s_get_stop;
-
- /**
- * Delete address in solver
- */
- GAS_solver_address_delete s_del;
-
- /**
- * Change relative preference for quality in solver
- */
- GAS_solver_address_change_preference s_pref;
-
- /**
- * Give feedback about the current assignment
- */
- GAS_solver_address_feedback_preference s_feedback;
-
- /**
- * Start a bulk operation
- */
- GAS_solver_bulk_start s_bulk_start;
-
- /**
- * Bulk operation done
- */
- GAS_solver_bulk_stop s_bulk_stop;
-
- /**
- * Shutdown solver
- */
- GAS_solver_done s_done;
+ char *plugin;
};
/**
@@ -805,12 +754,12 @@
GNUNET_ATS_print_network_type (addr_net));
/* Tell solver about new address */
- handle->s_add (handle->solver, new_address, addr_net);
+ handle->env.sf.s_add (handle->solver, new_address, addr_net);
- handle->s_bulk_start (handle->solver);
+ handle->env.sf.s_bulk_start (handle->solver);
GAS_normalization_normalize_property (handle->addresses, new_address, atsi,
atsi_count);
- handle->s_bulk_stop (handle->solver);
+ handle->env.sf.s_bulk_stop (handle->solver);
/* Notify performance clients about new address */
GAS_performance_notify_all_clients (&new_address->peer,
new_address->plugin,
@@ -866,7 +815,7 @@
GNUNET_i2s (peer), existing_address,
GNUNET_ATS_print_network_type (addr_net),
GNUNET_ATS_print_network_type (ntohl (atsi_delta[c1].value)));
- handle->s_address_update_network (handle->solver, existing_address,
+ handle->env.sf.s_address_update_network (handle->solver,
existing_address,
ntohl (atsi_delta[c1].value),
get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE));
addr_net = get_performance_info (existing_address,
@@ -874,10 +823,10 @@
}
}
/* Notify solver about update with atsi information and session */
- handle->s_bulk_start (handle->solver);
+ handle->env.sf.s_bulk_start (handle->solver);
GAS_normalization_normalize_property (handle->addresses, existing_address,
atsi, atsi_count);
- handle->s_bulk_stop (handle->solver);
+ handle->env.sf.s_bulk_stop (handle->solver);
}
GNUNET_free_non_null(atsi_delta);
@@ -887,7 +836,7 @@
previous_session = existing_address->session_id;
existing_address->session_id = session_id;
- handle->s_address_update_session (handle->solver, existing_address,
+ handle->env.sf.s_address_update_session (handle->solver, existing_address,
previous_session, session_id);
GNUNET_log(GNUNET_ERROR_TYPE_INFO,
@@ -956,7 +905,7 @@
/* Session changed */
prev_session = aa->session_id;
aa->session_id = session_id;
- handle->s_address_update_session (handle->solver, aa, prev_session,
+ handle->env.sf.s_address_update_session (handle->solver, aa, prev_session,
aa->session_id);
}
@@ -972,7 +921,7 @@
if (GNUNET_ATS_NETWORK_TYPE == ntohl (atsi_delta[c1].type))
{
/* Network type changed */
- handle->s_address_update_network (handle->solver, aa,
+ handle->env.sf.s_address_update_network (handle->solver, aa,
ntohl (atsi_delta[c1].value),
get_performance_info (aa, GNUNET_ATS_NETWORK_TYPE));
}
@@ -983,10 +932,10 @@
aa->addr_len, aa->session_id, aa->atsi, aa->atsi_count,
aa->assigned_bw_out, aa->assigned_bw_in);
- handle->s_bulk_start (handle->solver);
+ handle->env.sf.s_bulk_start (handle->solver);
GAS_normalization_normalize_property (handle->addresses, aa, atsi,
atsi_count);
- handle->s_bulk_stop (handle->solver);
+ handle->env.sf.s_bulk_stop (handle->solver);
}
GNUNET_free_non_null(atsi_delta);
}
@@ -1046,7 +995,7 @@
GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove
(handle->addresses,
&aa->peer,
aa));
- handle->s_del (handle->solver, aa, GNUNET_NO);
+ handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
free_address (aa);
dc->result = GNUNET_NO;
return GNUNET_OK; /* Continue iteration */
@@ -1078,7 +1027,7 @@
GNUNET_assert(
GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove
(handle->addresses,
&aa->peer, aa));
- handle->s_del (handle->solver, aa, GNUNET_NO);
+ handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
free_address (aa);
dc->result = GNUNET_NO;
return GNUNET_OK; /* Continue iteration */
@@ -1090,7 +1039,7 @@
"Deleting session for peer `%s': `%s' %u\n", GNUNET_i2s (&aa->peer),
aa->plugin, aa->session_id);
/* Notify solver to delete session */
- handle->s_del (handle->solver, aa, GNUNET_YES);
+ handle->env.sf.s_del (handle->solver, aa, GNUNET_YES);
aa->session_id = 0;
aa->active = GNUNET_NO;
return GNUNET_OK;
@@ -1203,7 +1152,7 @@
/* Tell solver about update */
ea->used = in_use;
- handle->s_address_update_inuse (handle->solver, ea, ea->used);
+ handle->env.sf.s_address_update_inuse (handle->solver, ea, ea->used);
return GNUNET_OK;
}
@@ -1236,7 +1185,7 @@
GNUNET_i2s (peer));
return;
}
- handle->s_get_stop (handle->solver, peer);
+ handle->env.sf.s_get_stop (handle->solver, peer);
GAS_addresses_handle_backoff_reset (handle, peer);
GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Removed request pending for peer `%s\n",
GNUNET_i2s (peer));
@@ -1287,7 +1236,7 @@
*/
/* Get prefered address from solver */
- aa = (struct ATS_Address *) handle->s_get (handle->solver, peer);
+ aa = (struct ATS_Address *) handle->env.sf.s_get (handle->solver, peer);
if (NULL == aa)
{
GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Cannot suggest address for peer
`%s'\n",
@@ -1378,7 +1327,7 @@
struct GAS_Addresses_Handle *handle = cls;
/* Tell solver about update */
- handle->s_pref (handle->solver, peer, kind, pref_rel);
+ handle->env.sf.s_pref (handle->solver, peer, kind, pref_rel);
}
/**
@@ -1401,7 +1350,7 @@
GNUNET_ATS_print_property_type (type), GNUNET_i2s (&address->peer),
prop_rel);
- ah->s_address_update_property (ah->solver, address, type, 0, prop_rel);
+ ah->env.sf.s_address_update_property (ah->solver, address, type, 0,
prop_rel);
}
/**
@@ -1463,10 +1412,10 @@
return;
}
- handle->s_bulk_start (handle->solver);
+ handle->env.sf.s_bulk_start (handle->solver);
/* Tell normalization about change, normalization will call callback if
preference changed */
GAS_normalization_normalize_preference (client, peer, kind, score_abs);
- handle->s_bulk_stop (handle->solver);
+ handle->env.sf.s_bulk_stop (handle->solver);
}
/**
@@ -1502,7 +1451,7 @@
return;
}
- handle->s_feedback (handle->solver, application, peer, scope, kind,
+ handle->env.sf.s_feedback (handle->solver, application, peer, scope, kind,
score_abs);
}
@@ -1704,11 +1653,10 @@
const struct GNUNET_STATISTICS_Handle *stats)
{
struct GAS_Addresses_Handle *ah;
- int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
- int quota_count;
char *mode_str;
+ char *plugin_short;
int c;
ah = GNUNET_malloc (sizeof (struct GAS_Addresses_Handle));
@@ -1734,20 +1682,24 @@
if (0 == strcmp (mode_str, "PROPORTIONAL"))
{
ah->ats_mode = MODE_PROPORTIONAL;
+ plugin_short = "proportional";
}
else if (0 == strcmp (mode_str, "MLP"))
{
ah->ats_mode = MODE_MLP;
+ plugin_short = "mlp";
#if !HAVE_LIBGLPK
GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
"Assignment method `%s' configured, but GLPK is not available,
please install \n",
mode_str);
ah->ats_mode = MODE_PROPORTIONAL;
+ plugin_short = "proportional";
#endif
}
else if (0 == strcmp (mode_str, "RIL"))
{
ah->ats_mode = MODE_RIL;
+ plugin_short = "ril";
}
else
{
@@ -1755,100 +1707,56 @@
"Invalid resource assignment method `%s' configured, using
proportional approach\n",
mode_str);
ah->ats_mode = MODE_PROPORTIONAL;
+ plugin_short = "proportional";
}
GNUNET_free(mode_str);
}
- /* Start configured solution method */
- switch (ah->ats_mode)
+
+ load_quotas (cfg, quotas_in, quotas_out, GNUNET_ATS_NetworkTypeCount);
+ ah->env.bandwidth_changed_cb = &bandwidth_changed_cb;
+ ah->env.bw_changed_cb_cls = ah;
+ ah->env.get_preferences_cb = &get_preferences_cb;
+ ah->env.get_preference_cls = ah;
+ ah->env.get_property_cb = &get_property_cb;
+ ah->env.get_property_cls = ah;
+ ah->env.cfg = cfg;
+ ah->env.stats = stats;
+ ah->env.addresses = ah->addresses;
+
+ ah->env.network_count = GNUNET_ATS_NetworkTypeCount;
+ int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
+ for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
{
- case MODE_MLP:
- /* Init the MLP solver with default values */
-#if HAVE_LIBGLPK
- ah->s_init = &GAS_mlp_init;
- ah->s_add = &GAS_mlp_address_add;
- ah->s_address_update_property = &GAS_mlp_address_property_changed;
- ah->s_address_update_session = &GAS_mlp_address_session_changed;
- ah->s_address_update_inuse = &GAS_mlp_address_inuse_changed;
- ah->s_address_update_network = &GAS_mlp_address_change_network;
- ah->s_get = &GAS_mlp_get_preferred_address;
- ah->s_get_stop = &GAS_mlp_stop_get_preferred_address;
- ah->s_pref = &GAS_mlp_address_change_preference;
- ah->s_feedback = &GAS_mlp_address_preference_feedback;
- ah->s_del = &GAS_mlp_address_delete;
- ah->s_bulk_start = &GAS_mlp_bulk_start;
- ah->s_bulk_stop = &GAS_mlp_bulk_stop;
- ah->s_done = &GAS_mlp_done;
-#else
- GNUNET_free(ah);
- return NULL ;
-#endif
- break;
- case MODE_PROPORTIONAL:
- /* Init the proportional solver with default values */
- ah->s_init = &GAS_proportional_init;
- ah->s_add = &GAS_proportional_address_add;
- ah->s_address_update_property = &GAS_proportional_address_property_changed;
- ah->s_address_update_session = &GAS_proportional_address_session_changed;
- ah->s_address_update_inuse = &GAS_proportional_address_inuse_changed;
- ah->s_address_update_network = &GAS_proportional_address_change_network;
- ah->s_get = &GAS_proportional_get_preferred_address;
- ah->s_get_stop = &GAS_proportional_stop_get_preferred_address;
- ah->s_pref = &GAS_proportional_address_change_preference;
- ah->s_feedback = &GAS_proportional_address_preference_feedback;
- ah->s_del = &GAS_proportional_address_delete;
- ah->s_bulk_start = &GAS_proportional_bulk_start;
- ah->s_bulk_stop = &GAS_proportional_bulk_stop;
- ah->s_done = &GAS_proportional_done;
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n",
- "PROPORTIONAL");
- break;
- case MODE_RIL:
- /* Init the ril solver with default values */
- ah->s_init = &GAS_ril_init;
- ah->s_add = &GAS_ril_address_add;
- ah->s_address_update_property = &GAS_ril_address_property_changed;
- ah->s_address_update_session = &GAS_ril_address_session_changed;
- ah->s_address_update_inuse = &GAS_ril_address_inuse_changed;
- ah->s_address_update_network = &GAS_ril_address_change_network;
- ah->s_get = &GAS_ril_get_preferred_address;
- ah->s_get_stop = &GAS_ril_stop_get_preferred_address;
- ah->s_pref = &GAS_ril_address_change_preference;
- ah->s_feedback = &GAS_ril_address_preference_feedback;
- ah->s_del = &GAS_ril_address_delete;
- ah->s_bulk_start = &GAS_ril_bulk_start;
- ah->s_bulk_stop = &GAS_ril_bulk_stop;
- ah->s_done = &GAS_ril_done;
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "RIL");
- break;
- default:
- return NULL ;
- break;
+ ah->env.networks[c] = networks[c];
+ ah->env.out_quota[c] = quotas_out[c];
+ ah->env.in_quota[c] = quotas_in[c];
}
- GNUNET_assert (NULL != ah->s_init);
- GNUNET_assert (NULL != ah->s_add);
- GNUNET_assert (NULL != ah->s_address_update_inuse);
- GNUNET_assert (NULL != ah->s_address_update_property);
- GNUNET_assert (NULL != ah->s_address_update_session);
- GNUNET_assert (NULL != ah->s_address_update_network);
- GNUNET_assert (NULL != ah->s_get);
- GNUNET_assert (NULL != ah->s_get_stop);
- GNUNET_assert (NULL != ah->s_pref);
- GNUNET_assert (NULL != ah->s_feedback);
- GNUNET_assert (NULL != ah->s_del);
- GNUNET_assert (NULL != ah->s_done);
- GNUNET_assert (NULL != ah->s_bulk_start);
- GNUNET_assert (NULL != ah->s_bulk_stop);
+ GNUNET_asprintf (&ah->plugin, "libgnunet_plugin_ats_%s", plugin_short);
+ GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s '`%s'\n"),
plugin_short, ah->plugin);
+ if (NULL == (ah->solver = GNUNET_PLUGIN_load (ah->plugin, &ah->env)))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver
`%s'!\n"), ah->plugin);
+ return NULL;
+ }
+ GNUNET_assert (NULL != ah->env.sf.s_add);
+ GNUNET_assert (NULL != ah->env.sf.s_address_update_inuse);
+ GNUNET_assert (NULL != ah->env.sf.s_address_update_property);
+ GNUNET_assert (NULL != ah->env.sf.s_address_update_session);
+ GNUNET_assert (NULL != ah->env.sf.s_address_update_network);
+ GNUNET_assert (NULL != ah->env.sf.s_get);
+ GNUNET_assert (NULL != ah->env.sf.s_get_stop);
+ GNUNET_assert (NULL != ah->env.sf.s_pref);
+ GNUNET_assert (NULL != ah->env.sf.s_feedback);
+ GNUNET_assert (NULL != ah->env.sf.s_del);
+ GNUNET_assert (NULL != ah->env.sf.s_bulk_start);
+ GNUNET_assert (NULL != ah->env.sf.s_bulk_stop);
+
+
GAS_normalization_start (&normalized_preference_changed_cb, ah,
&normalized_property_changed_cb, ah);
- quota_count = load_quotas (cfg, quotas_in, quotas_out,
- GNUNET_ATS_NetworkTypeCount);
- ah->solver = ah->s_init (cfg, stats, ah->addresses, quotas, quotas_in,
- quotas_out, quota_count,
- &bandwidth_changed_cb, ah, &get_preferences_cb,
- NULL, &get_property_cb, NULL );
if (NULL == ah->solver)
{
GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver!\n"));
@@ -1884,7 +1792,7 @@
GNUNET_assert(GNUNET_YES ==
GNUNET_CONTAINER_multipeermap_remove (handle->addresses, key,
value));
/* Notify */
- handle->s_del (handle->solver, aa, GNUNET_NO);
+ handle->env.sf.s_del (handle->solver, aa, GNUNET_NO);
/* Destroy */
free_address (aa);
@@ -1904,12 +1812,12 @@
return;
GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Destroying all addresses\n");
- handle->s_bulk_start (handle->solver);
+ handle->env.sf.s_bulk_start (handle->solver);
if (handle->addresses != NULL )
GNUNET_CONTAINER_multipeermap_iterate (handle->addresses,
&destroy_all_address_it,
handle);
- handle->s_bulk_start (handle->solver);
+ handle->env.sf.s_bulk_start (handle->solver);
}
@@ -1934,7 +1842,9 @@
GNUNET_CONTAINER_DLL_remove(handle->r_head, handle->r_tail, cur);
GNUNET_free(cur);
}
- handle->s_done (handle->solver);
+
+ GNUNET_PLUGIN_unload (handle->plugin, handle->solver);
+ GNUNET_free (handle->plugin);
GNUNET_free(handle);
/* Stop configured solution method */
GAS_normalization_stop ();
Modified: gnunet/src/ats/gnunet-service-ats_addresses.h
===================================================================
--- gnunet/src/ats/gnunet-service-ats_addresses.h 2013-10-08 15:43:03 UTC
(rev 29997)
+++ gnunet/src/ats/gnunet-service-ats_addresses.h 2013-10-08 16:34:07 UTC
(rev 29998)
@@ -348,236 +348,9 @@
struct GAS_NormalizationInfo atsin[GNUNET_ATS_QualityPropertiesCount];
};
-/**
- * Callback to call from solver when bandwidth for address has changed
- *
- * @param address the with changed bandwidth assigned
- */
-typedef void
-(*GAS_bandwidth_changed_cb) (void *cls, struct ATS_Address *address);
-/**
- * Callback to call from solver to obtain application preference values for a
- * peer
- *
- * @param cls the cls
- * @param id the peer id
- * @return carry of double values containing the preferences with
- * GNUNET_ATS_PreferenceCount elements
- */
-typedef const double *
-(*GAS_get_preferences) (void *cls, const struct GNUNET_PeerIdentity *id);
/**
- * Callback to call from solver to obtain transport properties for an
- * address
- *
- * @param cls the cls
- * @param address the address
- * @return carry of double values containing the preferences with
- * GNUNET_ATS_PreferenceCount elements
- */
-typedef const double *
-(*GAS_get_properties) (void *cls, const struct ATS_Address *address);
-
-/*
- * Solver API
- * ----------
- */
-
-/**
- * Init the problem solving component
- *
- * Quotas:
- * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
- * out_quota[i] contains outbound quota for network type i
- * in_quota[i] contains inbound quota for network type i
- *
- * Example
- * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK,
GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
- * network[2] == GNUNET_ATS_NET_LAN
- * out_quota[2] == 65353
- * in_quota[2] == 65353
- *
- * @param cfg configuration handle
- * @param stats the GNUNET_STATISTICS handle
- * @param addresses hashmap containing all addresses
- * @param network array of GNUNET_ATS_NetworkType with length dest_length
- * @param out_quota array of outbound quotas
- * @param in_quota array of outbound quota
- * @param bw_changed_cb callback to call when assigned changes
- * @return handle for the solver on success, NULL on fail
- */
-typedef void *
-(*GAS_solver_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_quota, unsigned long long *in_quota,
- 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);
-
-/**
- * Change the preference for a peer
- *
- * @param handle the solver handle
- * @param client the client sending this request
- * @param peer the peer id
- * @param kind the preference kind to change
- * @param score the new preference score
- * @param pref_rel the normalized preference value for this kind over all
clients
- */
-typedef void
-(*GAS_solver_address_change_preference) (void *solver,
- const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind
kind,
- double pref_rel);
-
-/**
- * Give feedback about the current assignment
- *
- * @param handle the solver handle
- * @param application the application sending this request
- * @param peer the peer id
- * @param scope the time interval for this feedback: [now - scope .. now]
- * @param kind the preference kind for this feedback
- * @param score the feedback score
- */
-typedef void
-(*GAS_solver_address_feedback_preference) (void *solver, void *application,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_TIME_Relative scope,
- enum GNUNET_ATS_PreferenceKind kind, double score);
-
-/**
- * Notify the solver about a bulk operation changing possibly a lot of values
- * Solver will not resolve until all bulk operations are marked as done
- *
- * @param solver the solver
- */
-typedef void
-(*GAS_solver_bulk_start) (void *solver);
-
-/**
- * Mark a bulk operation as done
- * Solver will resolve if values have changed
- *
- * @param solver the solver
- */
-typedef void
-(*GAS_solver_bulk_stop) (void *solver);
-
-/**
- * Add a single address within a network to the solver
- *
- * @param solver the solver Handle
- * @param addresses the address hashmap containing all addresses
- * @param address the address to add
- * @param network network type of this address
- */
-typedef void
-(*GAS_solver_address_add) (void *solver, struct ATS_Address *address,
- uint32_t network);
-
-/**
- * Delete an address or just the session from the solver
- *
- * @param solver the solver Handle
- * @param addresses the address hashmap containing all addresses
- * @param address the address to delete
- * @param session_only remove address or just session
- */
-typedef void
-(*GAS_solver_address_delete) (void *solver, struct ATS_Address *address,
- int session_only);
-
-/**
- * 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
- */
-typedef void
-(*GAS_solver_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
- */
-typedef void
-(*GAS_solver_address_session_changed) (void *solver,
- struct ATS_Address *address, uint32_t cur_session, uint32_t new_session);
-
-/**
- * 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
- */
-typedef void
-(*GAS_solver_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
- */
-typedef void
-(*GAS_solver_address_network_changed) (void *solver,
- struct ATS_Address *address, uint32_t current_network, uint32_t
new_network);
-
-/**
- * Get the prefered address for a peer from solver
- *
- * @param solver the solver to use
- * @param addresses the address hashmap containing all addresses
- * @param peer the peer
- */
-typedef const struct ATS_Address *
-(*GAS_solver_get_preferred_address) (void *solver,
- const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Stop getting the prefered address for a peer from solver
- *
- * @param solver the solver to use
- * @param addresses the address hashmap containing all addresses
- * @param peer the peer
- */
-typedef void
-(*GAS_solver_stop_get_preferred_address) (void *solver,
- const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Shutdown solver
- *
- * @param solver the solver to shutdown
- */
-
-typedef void
-(*GAS_solver_done) (void *solver);
-
-/**
* Initialize address subsystem. The addresses subsystem manages the addresses
* known and current performance information. It has a solver component
* responsible for the resource allocation. It tells the solver about changes
Copied: gnunet/src/ats/libgnunet_plugin_ats_mlp.c (from rev 29953,
gnunet/src/ats/gnunet-service-ats-solver_mlp.c)
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_mlp.c (rev 0)
+++ gnunet/src/ats/libgnunet_plugin_ats_mlp.c 2013-10-08 16:34:07 UTC (rev
29998)
@@ -0,0 +1,2104 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file ats/gnunet-service-ats-solver_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_UP:
+ return "GNUNET_ATS_UTILIZATION_UP";
+ case GNUNET_ATS_UTILIZATION_DOWN:
+ return "GNUNET_ATS_UTILIZATION_DOWN";
+ 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;
+}
+
+/**
+ * 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_build;
+ struct GNUNET_TIME_Relative duration_build;
+ struct GNUNET_TIME_Absolute start_lp;
+ struct GNUNET_TIME_Relative duration_lp;
+ struct GNUNET_TIME_Absolute start_mlp;
+ struct GNUNET_TIME_Relative duration_mlp;
+ GNUNET_assert (NULL != solver);
+
+ if (GNUNET_YES == mlp->bulk_lock)
+ {
+ mlp->bulk_request ++;
+ return GNUNET_NO;
+ }
+
+ if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->requested_peers))
+ return GNUNET_OK; /* No pending requests */
+ if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->addresses))
+ 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");
+ return GNUNET_OK;
+ }
+ if (GNUNET_YES == mlp->mlp_prob_changed)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
+ mlp_delete_problem (mlp);
+ start_build = GNUNET_TIME_absolute_get();
+ if (GNUNET_SYSERR == mlp_create_problem (mlp))
+ return GNUNET_SYSERR;
+ duration_build = GNUNET_TIME_absolute_get_duration (start_build);
+ 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");
+ duration_build.rel_value_us = 0;
+ }
+
+ /* Run LP solver */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Running LP solver %s\n",
+ (GLP_YES == mlp->control_param_lp.presolve)? "with presolver": "without
presolver");
+ start_lp = GNUNET_TIME_absolute_get();
+ res_lp = mlp_solve_lp_problem (mlp);
+ duration_lp = GNUNET_TIME_absolute_get_duration (start_lp);
+
+
+ /* Run MLP solver */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
+ start_mlp = GNUNET_TIME_absolute_get();
+ res_mip = mlp_solve_mlp_problem (mlp);
+
+ duration_mlp = GNUNET_TIME_absolute_get_duration (start_mlp);
+
+ /* Save stats */
+ mlp->ps.lp_res = res_lp;
+ mlp->ps.mip_res = res_mip;
+ mlp->ps.build_dur = duration_build;
+ mlp->ps.lp_dur = duration_lp;
+ mlp->ps.mip_dur = duration_mlp;
+ 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;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Execution time: Build %s\n",
+ GNUNET_STRINGS_relative_time_to_string (duration_build, GNUNET_NO));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Execution time: LP %s\n",
+ GNUNET_STRINGS_relative_time_to_string (duration_lp, GNUNET_NO));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Execution time: MLP %s\n",
+ GNUNET_STRINGS_relative_time_to_string (duration_mlp, GNUNET_NO));
+
+ /* Propagate result*/
+ if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
+ {
+ GNUNET_CONTAINER_multipeermap_iterate (mlp->addresses,
&mlp_propagate_results, mlp);
+ }
+
+ 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 (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 (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 solver the solver handle
+ */
+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_cb);
+ GNUNET_assert (NULL != env->get_property_cb);
+
+ /* 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_cb;
+ mlp->get_preferences_cls = env->get_preference_cls;
+ mlp->get_properties = env->get_property_cb;
+ 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 */
Copied: gnunet/src/ats/libgnunet_plugin_ats_mlp.h (from rev 29953,
gnunet/src/ats/gnunet-service-ats-solver_mlp.h)
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_mlp.h (rev 0)
+++ gnunet/src/ats/libgnunet_plugin_ats_mlp.h 2013-10-08 16:34:07 UTC (rev
29998)
@@ -0,0 +1,556 @@
+/*
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file ats/gnunet-service-ats-solver_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
+{
+ struct GNUNET_TIME_Relative build_dur;
+ struct GNUNET_TIME_Relative lp_dur;
+ struct GNUNET_TIME_Relative mip_dur;
+
+ 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 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 callback to get relative preferences for a peer
+ * @param get_properties_cls for 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 */
Copied: gnunet/src/ats/libgnunet_plugin_ats_proportional.c (from rev 29953,
gnunet/src/ats/gnunet-service-ats-solver_proportional.c)
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_proportional.c
(rev 0)
+++ gnunet/src/ats/libgnunet_plugin_ats_proportional.c 2013-10-08 16:34:07 UTC
(rev 29998)
@@ -0,0 +1,1507 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file ats/gnunet-service-ats-solver_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;
+};
+
+/**
+ * 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_cb);
+ GNUNET_assert(NULL != env->get_property_cb);
+
+ 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_cb;
+ s->get_preferences_cls = env->get_preference_cls;
+ s->get_properties = env->get_property_cb;
+ 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_ERROR,
+ "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(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_ERROR,
+ "Had %u addresses not deleted during shutdown\n", s->total_addresses);
+ GNUNET_break(0);
+ }
+ if (s->active_addresses > 0)
+ {
+ LOG(GNUNET_ERROR_TYPE_ERROR,
+ "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_in_network (struct GAS_PROPORTIONAL_Handle *s,
+ struct Network *net, struct ATS_Address *address_except)
+{
+ 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;
+ struct AddressWrapper *cur;
+
+ if (GNUNET_YES == s->bulk_lock)
+ {
+ s->bulk_requests++;
+ return;
+ }
+
+ 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 */
+ if ((assigned_quota_in != ntohl (cur->addr->assigned_bw_in.value__))
+ || (assigned_quota_out != ntohl (cur->addr->assigned_bw_out.value__)))
+ {
+ cur->addr->assigned_bw_in.value__ = htonl (assigned_quota_in);
+ cur->addr->assigned_bw_out.value__ = htonl (assigned_quota_out);
+ /* Notify on change */
+ if ((GNUNET_YES == cur->addr->active) && (cur->addr != address_except))
+ s->bw_changed (s->bw_changed_cls, cur->addr);
+ }
+
+ }
+ 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 Network *net = (struct Network *) current->solver_information;
+ const double *norm_prop_cur;
+ const double *norm_prop_prev;
+ int index;
+
+ 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 (net))
+ 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
+ * ---------------------------
+ */
+
+/**
+ * Update bandwidth assignment for all networks
+ *
+ * @param s the solver handle
+ */
+static void
+distribute_bandwidth_in_all_networks (struct GAS_PROPORTIONAL_Handle *s)
+{
+ int i;
+ for (i = 0; i < s->network_count; i++)
+ distribute_bandwidth_in_network (s, &s->network_entries[i], NULL );
+}
+
+/**
+ * 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_all_networks (s);
+}
+
+
+/**
+ * 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;
+
+ 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));
+ net_cur = (struct Network *) fba_ctx.best->solver_information;
+ 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)
+ {
+ net_prev = (struct Network *) prev->solver_information;
+ 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
(fba_ctx.best->solver_information)))
+ {
+ 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 Network *cur_net;
+
+ if (GNUNET_YES
+ == GNUNET_CONTAINER_multipeermap_contains (s->requests,
+ peer))
+ GNUNET_CONTAINER_multipeermap_remove (s->requests, peer,
+ NULL);
+
+ cur = get_active_address (s,
+ s->addresses, peer);
+ if (NULL != cur)
+ {
+ /* Disabling current address */
+ cur_net = (struct Network *) cur->solver_information;
+ 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;
+ 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
+ */
+
+ net = (struct Network *) address->solver_information;
+
+ 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(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_DEBUG,
+ "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_all_networks (s);
+ 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;
+
+ GNUNET_assert(NULL != solver);
+ GNUNET_assert(NULL != address);
+
+ s = (struct GAS_PROPORTIONAL_Handle *) solver;
+ n = (struct Network *) address->solver_information;
+
+ 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_UP:
+ case GNUNET_ATS_UTILIZATION_DOWN:
+ 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, GNUNET_NO);
+ 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 ATS_Address *new;
+ struct GAS_PROPORTIONAL_Handle *s = (struct GAS_PROPORTIONAL_Handle *)
solver;
+ 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 == (new = (struct ATS_Address *)
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*/
+ address->solver_information = 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
+ == (new =
+ (struct ATS_Address *) 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;
+ const struct ATS_Address *new_address;
+
+ 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);
+ aw->addr->solver_information = net;
+
+ if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (s->requests,
&address->peer))
+ {
+ if (NULL == get_active_address (s, s->addresses, &address->peer))
+ {
+ if (NULL != (new_address = GAS_proportional_get_preferred_address (s,
&address->peer)))
+ s->bw_changed (s->bw_changed_cls, (struct ATS_Address *) address);
+ }
+ }
+ LOG(GNUNET_ERROR_TYPE_DEBUG,
+ "After adding address now total %u and active %u addresses in network
`%s'\n",
+ net->total_addresses, net->active_addresses, net->desc);
+}
+
+
+/* end of gnunet-service-ats-solver_proportional.c */
Copied: gnunet/src/ats/libgnunet_plugin_ats_proportional.h (from rev 29953,
gnunet/src/ats/gnunet-service-ats-solver_proportional.h)
===================================================================
--- gnunet/src/ats/libgnunet_plugin_ats_proportional.h
(rev 0)
+++ gnunet/src/ats/libgnunet_plugin_ats_proportional.h 2013-10-08 16:34:07 UTC
(rev 29998)
@@ -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/gnunet-service-ats-solver_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 */
Added: gnunet/src/include/gnunet_ats_plugin.h
===================================================================
--- gnunet/src/include/gnunet_ats_plugin.h (rev 0)
+++ gnunet/src/include/gnunet_ats_plugin.h 2013-10-08 16:34:07 UTC (rev
29998)
@@ -0,0 +1,328 @@
+/*
+ This file is part of GNUnet
+ (C) 2009, 2010 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 include/gnunet_solver_plugin.h
+ * @brief API for the ATS solvers. This header
+ * specifies the struct that is given to the plugin's entry
+ * method and the other struct that must be returned.
+ * Note that the destructors of ATS plugins will
+ * be given the value returned by the constructor
+ * and is expected to return a NULL pointer.
+ * @author Christian Grothoff
+ */
+#ifndef PLUGIN_ATS_H
+#define PLUGIN_ATS_H
+
+#include "gnunet_ats_service.h"
+#include "gnunet_statistics_service.h"
+
+struct ATS_Address;
+
+
+/*
+ * Solver API
+ * ----------
+ */
+
+
+/**
+ * Change the preference for a peer
+ *
+ * @param handle the solver handle
+ * @param client the client sending this request
+ * @param peer the peer id
+ * @param kind the preference kind to change
+ * @param score the new preference score
+ * @param pref_rel the normalized preference value for this kind over all
clients
+ */
+typedef void
+(*GAS_solver_address_change_preference) (void *solver,
+ const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind
kind,
+ double pref_rel);
+
+/**
+ * Give feedback about the current assignment
+ *
+ * @param handle the solver handle
+ * @param application the application sending this request
+ * @param peer the peer id
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the preference kind for this feedback
+ * @param score the feedback score
+ */
+typedef void
+(*GAS_solver_address_feedback_preference) (void *solver, void *application,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_TIME_Relative scope,
+ enum GNUNET_ATS_PreferenceKind kind, double score);
+
+/**
+ * Notify the solver about a bulk operation changing possibly a lot of values
+ * Solver will not resolve until all bulk operations are marked as done
+ *
+ * @param solver the solver
+ */
+typedef void
+(*GAS_solver_bulk_start) (void *solver);
+
+/**
+ * Mark a bulk operation as done
+ * Solver will resolve if values have changed
+ *
+ * @param solver the solver
+ */
+typedef void
+(*GAS_solver_bulk_stop) (void *solver);
+
+/**
+ * Add a single address within a network to the solver
+ *
+ * @param solver the solver Handle
+ * @param addresses the address hashmap containing all addresses
+ * @param address the address to add
+ * @param network network type of this address
+ */
+typedef void
+(*GAS_solver_address_add) (void *solver, struct ATS_Address *address,
+ uint32_t network);
+
+/**
+ * Delete an address or just the session from the solver
+ *
+ * @param solver the solver Handle
+ * @param addresses the address hashmap containing all addresses
+ * @param address the address to delete
+ * @param session_only remove address or just session
+ */
+typedef void
+(*GAS_solver_address_delete) (void *solver, struct ATS_Address *address,
+ int session_only);
+
+/**
+ * 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
+ */
+typedef void
+(*GAS_solver_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
+ */
+typedef void
+(*GAS_solver_address_session_changed) (void *solver,
+ struct ATS_Address *address, uint32_t cur_session, uint32_t new_session);
+
+/**
+ * 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
+ */
+typedef void
+(*GAS_solver_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
+ */
+typedef void
+(*GAS_solver_address_network_changed) (void *solver,
+ struct ATS_Address *address, uint32_t current_network, uint32_t
new_network);
+
+/**
+ * Get the prefered address for a peer from solver
+ *
+ * @param solver the solver to use
+ * @param addresses the address hashmap containing all addresses
+ * @param peer the peer
+ */
+typedef const struct ATS_Address *
+(*GAS_solver_get_preferred_address) (void *solver,
+ const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Stop getting the prefered address for a peer from solver
+ *
+ * @param solver the solver to use
+ * @param addresses the address hashmap containing all addresses
+ * @param peer the peer
+ */
+typedef void
+(*GAS_solver_stop_get_preferred_address) (void *solver,
+ const struct GNUNET_PeerIdentity *peer);
+
+
+/**
+ * Each plugin is required to return a pointer to a struct of this
+ * type as the return value from its entry point.
+ */
+struct GNUNET_ATS_SolverFunctions
+{
+
+ /**
+ * Closure for all of the callbacks.
+ */
+ void *cls;
+
+ /**
+ * Add an address to the solver
+ */
+ GAS_solver_address_add s_add;
+
+ GAS_solver_address_property_changed s_address_update_property;
+
+ GAS_solver_address_session_changed s_address_update_session;
+
+ GAS_solver_address_inuse_changed s_address_update_inuse;
+
+ GAS_solver_address_network_changed s_address_update_network;
+
+ /**
+ * Get address from solver
+ */
+ GAS_solver_get_preferred_address s_get;
+
+ /**
+ * Get address from solver
+ */
+ GAS_solver_stop_get_preferred_address s_get_stop;
+
+ /**
+ * Delete address in solver
+ */
+ GAS_solver_address_delete s_del;
+
+ /**
+ * Change relative preference for quality in solver
+ */
+ GAS_solver_address_change_preference s_pref;
+
+ /**
+ * Give feedback about the current assignment
+ */
+ GAS_solver_address_feedback_preference s_feedback;
+
+ /**
+ * Start a bulk operation
+ */
+ GAS_solver_bulk_start s_bulk_start;
+
+ /**
+ * Bulk operation done
+ */
+ GAS_solver_bulk_stop s_bulk_stop;
+
+};
+
+
+/**
+ * Callback to call from solver when bandwidth for address has changed
+ *
+ * @param address the with changed bandwidth assigned
+ */
+typedef void
+(*GAS_bandwidth_changed_cb) (void *cls, struct ATS_Address *address);
+
+/**
+ * Callback to call from solver to obtain application preference values for a
+ * peer
+ *
+ * @param cls the cls
+ * @param id the peer id
+ * @return carry of double values containing the preferences with
+ * GNUNET_ATS_PreferenceCount elements
+ */
+typedef const double *
+(*GAS_get_preferences) (void *cls, const struct GNUNET_PeerIdentity *id);
+
+/**
+ * Callback to call from solver to obtain transport properties for an
+ * address
+ *
+ * @param cls the cls
+ * @param address the address
+ * @return carry of double values containing the preferences with
+ * GNUNET_ATS_PreferenceCount elements
+ */
+typedef const double *
+(*GAS_get_properties) (void *cls, const struct ATS_Address *address);
+
+
+/**
+ * The transport service will pass a pointer to a struct
+ * of this type as the first and only argument to the
+ * entry point of each transport plugin.
+ */
+struct GNUNET_ATS_PluginEnvironment
+{
+ /**
+ * Closure for the various callbacks.
+ */
+ void *cls;
+
+ GAS_bandwidth_changed_cb bandwidth_changed_cb;
+ void *bw_changed_cb_cls;
+
+ GAS_get_preferences get_preferences_cb;
+ void *get_preference_cls;
+
+ GAS_get_properties get_property_cb;
+ void *get_property_cls;
+
+ struct GNUNET_ATS_SolverFunctions sf;
+
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_STATISTICS_Handle *stats;
+ struct GNUNET_CONTAINER_MultiPeerMap *addresses;
+
+ /* Available networks */
+ int networks[GNUNET_ATS_NetworkTypeCount];
+ int network_count;
+
+ unsigned long long out_quota[GNUNET_ATS_NetworkTypeCount];
+ unsigned long long in_quota[GNUNET_ATS_NetworkTypeCount];
+};
+
+#endif
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r29998 - in gnunet/src: ats include,
gnunet <=