#include "gnunet_signatures.h"
#include "gnunet_transport_plugin.h"
#include "transport.h"
+#if HAVE_LIBGLPK
+#include <glpk.h>
+#endif
+
+#define DEBUG_BLACKLIST GNUNET_NO
-#define DEBUG_BLACKLIST GNUNET_YES
+#define DEBUG_PING_PONG GNUNET_NO
-#define DEBUG_PING_PONG GNUNET_YES
+#define DEBUG_TRANSPORT_HELLO GNUNET_NO
-#define DEBUG_TRANSPORT_HELLO GNUNET_YES
+#define DEBUG_ATS GNUNET_NO
+#define VERBOSE_ATS GNUNET_NO
/**
* Should we do some additional checks (to validate behavior
*/
static struct GNUNET_STATISTICS_Handle *stats;
+/**
+ * Handle for ats information
+ */
+static struct ATS_info *ats;
+
/**
* The peer specified by the given neighbour has timed-out or a plugin
* has disconnected. We may either need to do nothing (other plugins
* Check the ready list for the given neighbour and if a plugin is
* ready for transmission (and if we have a message), do so!
*
- * @param neighbour target peer for which to transmit
+ * @param nexi target peer for which to transmit
*/
-static void try_transmission_to_peer (struct NeighbourList *neighbour);
+static void try_transmission_to_peer (struct NeighbourList *n);
+
+struct ATS_info * ats_init ();
+
+void ats_shutdown ( );
+
+void ats_notify_peer_connect (
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
+
+void ats_notify_peer_disconnect (
+ const struct GNUNET_PeerIdentity *peer);
+
+void ats_notify_ats_data (
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
+
+struct ForeignAddressList * ats_get_preferred_address (
+ struct NeighbourList *n);
/**
* Find an entry in the neighbour list for a particular peer.
if (plugin->blacklist != NULL)
{
- if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
+ if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
{
#if DEBUG_BLACKLIST
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Peer `%s:%s' is blacklisted!\n"),
+ "Peer `%s:%s' is blacklisted!\n",
plugin->short_name, GNUNET_i2s (peer));
#endif
+ if (stats != NULL)
+ GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
return GNUNET_YES;
}
}
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Option `%s' in section `%s' not specified!\n"),
+ "Option `%s' in section `%s' not specified!\n",
"BLACKLIST_FILE",
"TRANSPORT");
#endif
pos = colon_pos + 1;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Read transport name %s in blacklist file.\n"),
+ "Read transport name %s in blacklist file.\n",
transport_name);
#endif
memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
pos++;
}
+ GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
GNUNET_free (data);
GNUNET_free (fn);
}
client->th = NULL;
if (buf == NULL)
{
+#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Transmission to client failed, closing connection.\n");
+#endif
/* fatal error with client, free message queue! */
while (NULL != (q = client->message_queue_head))
{
* given neighbour.
*
* @param client who to notify
- * @param n neighbour to notify about
+ * @param n neighbour to notify about, can be NULL (on failure)
+ * @param target target of the transmission
* @param result status code for the transmission request
*/
static void
transmit_send_ok (struct TransportClient *client,
struct NeighbourList *n,
+ const struct GNUNET_PeerIdentity *target,
int result)
{
struct SendOkMessage send_ok_msg;
send_ok_msg.header.size = htons (sizeof (send_ok_msg));
send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
send_ok_msg.success = htonl (result);
- send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
- send_ok_msg.peer = n->id;
+ if (n != NULL)
+ send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
+ else
+ send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
+ send_ok_msg.peer = *target;
transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
}
mq->message_buf_size,
GNUNET_NO);
}
- n = find_neighbour(&mq->neighbour_id);
- GNUNET_assert (n != NULL);
if (mq->specific_address != NULL)
{
if (result == GNUNET_OK)
if (! mq->internal_msg)
mq->specific_address->in_transmit = GNUNET_NO;
}
+ n = find_neighbour(&mq->neighbour_id);
if (mq->client != NULL)
- transmit_send_ok (mq->client, n, result);
+ transmit_send_ok (mq->client, n, target, result);
GNUNET_free (mq);
- try_transmission_to_peer (n);
+ if (n != NULL)
+ try_transmission_to_peer (n);
}
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
struct ForeignAddressList *best_address;
+ /* Hack to prefer unix domain sockets */
+ struct ForeignAddressList *unix_address = NULL;
+
best_address = NULL;
while (head != NULL)
{
(unsigned long long) addresses->timeout.abs_value,
(unsigned int) addresses->distance);
#endif
+ if (0==strcmp(head->plugin->short_name,"unix"))
+ {
+ if ((unix_address == NULL) || ((unix_address != NULL) &&
+ (addresses->latency.rel_value < unix_address->latency.rel_value)))
+ unix_address = addresses;
+ }
if ( ( (best_address == NULL) ||
(addresses->connected == GNUNET_YES) ||
(best_address->connected == GNUNET_NO) ) &&
connected a chance some times... */
addresses = addresses->next;
}
+ if (unix_address != NULL)
+ break;
head = head->next;
}
+ if (unix_address != NULL)
+ {
+ best_address = unix_address;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
+#endif
+ }
if (best_address != NULL)
{
#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Best address found (`%s') has latency of %llu ms.\n",
(best_address->addrlen > 0)
? a2s (best_address->ready_list->plugin->short_name,
1,
GNUNET_NO);
}
+
return best_address;
}
* @param neighbour target peer for which to transmit
*/
static void
-try_transmission_to_peer (struct NeighbourList *neighbour)
+try_transmission_to_peer (struct NeighbourList *n)
{
struct ReadyList *rl;
struct MessageQueue *mq;
ssize_t ret;
int force_address;
- if (neighbour->messages_head == NULL)
+ if (n->messages_head == NULL)
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
return; /* nothing to do */
}
rl = NULL;
- mq = neighbour->messages_head;
+ mq = n->messages_head;
force_address = GNUNET_YES;
if (mq->specific_address == NULL)
{
- mq->specific_address = find_ready_address(neighbour);
+ /* TODO: ADD ATS */
+ mq->specific_address = ats_get_preferred_address(n);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# transport selected peer address freely"),
1,
mq->message_buf_size,
GNUNET_NO);
if (mq->client != NULL)
- transmit_send_ok (mq->client, neighbour, GNUNET_NO);
- GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
- neighbour->messages_tail,
+ transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (n->messages_head,
+ n->messages_tail,
mq);
GNUNET_free (mq);
return; /* nobody ready */
gettext_noop ("# message delivery deferred (no address)"),
1,
GNUNET_NO);
- if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (neighbour->retry_task);
- neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
+ if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->retry_task);
+ n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
&retry_transmission_task,
- neighbour);
+ n);
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
(unless that's already pending...) */
return;
}
- GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
- neighbour->messages_tail,
+ GNUNET_CONTAINER_DLL_remove (n->messages_head,
+ n->messages_tail,
mq);
if (mq->specific_address->connected == GNUNET_NO)
mq->specific_address->connect_attempts++;
(&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
(&(cim->ats))[2].value = htonl (0);
memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
+
+ /* notify ats about connecting peer */
+ ats_notify_peer_connect (peer, &(cim->ats));
+
cpos = clients;
while (cpos != NULL)
{
transmit_to_client (cpos, &(cim->header), GNUNET_NO);
cpos = cpos->next;
}
+
GNUNET_free (cim);
}
dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
dim.reserved = htonl (0);
memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
+
+ /* notify ats about connecting peer */
+ ats_notify_peer_disconnect (peer);
+
cpos = clients;
while (cpos != NULL)
{
}
if (fal == NULL)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Failed to add new address for `%4s'\n",
GNUNET_i2s (&n->id));
return GNUNET_OK;
* @param cls closure ('struct NeighbourList*')
* @param peer id of the peer, NULL for last call
* @param h hello message for the peer (can be NULL)
+ * @param err_msg NULL if successful, otherwise contains error message
*/
static void
add_hello_for_peer (void *cls,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *h)
+ const struct GNUNET_HELLO_Message *h,
+ const char *err_msg)
{
struct NeighbourList *n = cls;
- if (peer == NULL)
+ if (err_msg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Error in communication with PEERINFO service\n"));
+ /* return; */
+ }
+ if ((peer == NULL))
{
GNUNET_STATISTICS_update (stats,
gettext_noop ("# outstanding peerinfo iterate requests"),
do_blacklist_check (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc);
-
/**
* Transmit blacklist query to the client.
*
if (GNUNET_NO == n->received_pong)
{
n->received_pong = GNUNET_YES;
+
notify_clients_connect (&target, n->latency, n->distance);
if (NULL != (prem = n->pre_connect_message_buffer))
{
* @param cls closure
* @param peer id of the peer, NULL for last call
* @param h hello message for the peer (can be NULL)
+ * @param err_msg NULL if successful, otherwise contains error message
*/
static void
check_hello_validated (void *cls,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *h)
+ const struct GNUNET_HELLO_Message *h,
+ const char *err_msg)
{
struct CheckHelloValidatedContext *chvc = cls;
struct GNUNET_HELLO_Message *plain_hello;
struct GNUNET_PeerIdentity target;
struct NeighbourList *n;
+ if (err_msg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Error in communication with PEERINFO service\n"));
+ /* return; */
+ }
+
if (peer == NULL)
{
GNUNET_STATISTICS_update (stats,
plugin->env.my_identity,
sizeof (struct GNUNET_PeerIdentity)))
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
_("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
"PING",
(sender_address != NULL)
* @param peer (claimed) identity of the other peer
* @param message the message, NULL if we only care about
* learning about the delay until we should receive again
- * @param ats information for automatic transport selection
- * @param ats_count number of elements in ats not including \0 terminator
+ * @param ats_data information for automatic transport selection
+ * @param ats_count number of elements in ats not including 0-terminator
* @param session identifier used for this session (can be NULL)
* @param sender_address binary address of the sender (if observed)
* @param sender_address_len number of bytes in sender_address
static struct GNUNET_TIME_Relative
plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_MessageHeader *message,
- const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
uint32_t ats_count,
struct Session *session,
const char *sender_address,
distance = 1;
for (c=0; c<ats_count; c++)
{
- if (ntohl(ats[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
+ if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
{
- distance = ntohl(ats[c].value);
+ distance = ntohl(ats_data[c].value);
}
}
+ /* notify ATS about incoming data */
+ ats_notify_ats_data(peer, ats_data);
if (message != NULL)
{
GNUNET_CONTAINER_multihashmap_destroy (validation_map);
validation_map = NULL;
+ ats_shutdown(ats);
+
/* free 'chvc' data structure */
while (NULL != (chvc = chvc_head))
{
GNUNET_break (bc_head == NULL);
}
+struct ATS_mechanism
+{
+ struct ATS_mechanism * prev;
+ struct ATS_mechanism * next;
+ struct ForeignAddressList * addr;
+ struct TransportPlugin * plugin;
+ struct ATS_peer * peer;
+ int col_index;
+ int id;
+ double c_max;
+ double c_1;
+};
+
+struct ATS_peer
+{
+ int id;
+ struct GNUNET_PeerIdentity peer;
+ struct NeighbourList * n;
+ struct ATS_mechanism * m_head;
+ struct ATS_mechanism * m_tail;
+
+ /* preference value f */
+ double f;
+ int t;
+};
+
+
+static void ats_create_problem (int max_it, int max_dur )
+{
+#if !HAVE_LIBGLPK
+ if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
+ return;
+#else
+ if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
+#endif
+
+ glp_prob *prob;
+
+ int c_peers = 0;
+ int c_mechs = 0;
+
+ int c_c_ressources = 0;
+ int c_q_metrics = 0;
+
+ double v_b_min = 100;
+ double v_n_min = 2;
+ double M = 1000000000;
+
+ struct NeighbourList *next = neighbours;
+ while (next!=NULL)
+ {
+ struct ReadyList *r_next = next->plugins;
+ while (r_next != NULL)
+ {
+ struct ForeignAddressList * a_next = r_next->addresses;
+ while (a_next != NULL)
+ {
+ c_mechs++;
+ a_next = a_next->next;
+ }
+ r_next = r_next->next;
+ }
+ next = next->next;
+ c_peers++;
+ }
+
+ if (c_mechs==0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
+ return;
+ }
+
+ struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
+ struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
+
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found mechanisms: %i\n", c_mechs);
+ c_mechs = 1;
+ c_peers = 1;
+ next = neighbours;
+ while (next!=NULL)
+ {
+ peers[c_peers].peer = next->id;
+ peers[c_peers].m_head = NULL;
+ peers[c_peers].m_tail = NULL;
+
+ struct ReadyList *r_next = next->plugins;
+ while (r_next != NULL)
+ {
+ struct ForeignAddressList * a_next = r_next->addresses;
+ while (a_next != NULL)
+ {
+ if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%i Peer: `%s' %x:\n", c_mechs, GNUNET_i2s(&next->id),
+ a_next);
+ mechanisms[c_mechs].addr = a_next;
+ mechanisms[c_mechs].col_index = c_mechs;
+ mechanisms[c_mechs].peer = &peers[c_peers];
+ mechanisms[c_mechs].next = NULL;
+
+ GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
+ c_mechs++;
+ a_next = a_next->next;
+ }
+ r_next = r_next->next;
+ }
+ c_peers++;
+ next = next->next;
+ }
+ c_mechs--;
+ c_peers--;
+
+ /* number of variables == coloumns */
+ //int c_cols = 2 * c_mechs + 3 + c_q_metrics;
+ /* number of constraints == rows */
+ //int c_rows = 2 * c_peers + 2 * c_mechs + c_c_ressources + c_q_metrics + 3;
+
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms\n", c_peers, c_mechs);
+
+ int size = 6 *c_mechs;
+ int row_index;
+ int array_index=0;
+ int * ia = GNUNET_malloc (size * sizeof (int));
+ int * ja = GNUNET_malloc (size * sizeof (int));
+ double * ar = GNUNET_malloc(size* sizeof (double));
+
+ prob = glp_create_prob();
+ glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
+ glp_set_obj_dir(prob, GLP_MAX);
+
+ /* adding columns */
+ int c;
+ char * name;
+ glp_add_cols(prob, 2 * c_mechs);
+ for (c=1; c <= c_mechs; c++)
+ {
+ GNUNET_asprintf(&name, "b%i",c);
+ glp_set_col_name(prob, c, name);
+ GNUNET_free (name);
+ glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
+ glp_set_obj_coef(prob, c, 1.0);
+
+ }
+ for (c=c_mechs; c <= 2*c_mechs; c++)
+ {
+ GNUNET_asprintf(&name, "n%i",c);
+ glp_set_col_name(prob, c, "n1");
+ glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
+ glp_set_col_bnds(prob, c, GLP_LO, 0.0, 1.0);
+ glp_set_col_kind(prob, c, GLP_IV);
+ glp_set_obj_coef(prob, c, 1.0);
+ GNUNET_free (name);
+ }
+
+ /* feasibility constraints */
+ /* one address per peer*/
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 1\n");
+ row_index = 1;
+ glp_add_rows(prob, c_peers);
+ for (c=1; c<=c_peers; c++)
+ {
+ glp_set_row_bnds(prob, row_index, GLP_DB, 0.0, 1.0);
+
+ struct ATS_mechanism *m = peers[c].m_head;
+ while (m!=NULL)
+ {
+ ia[array_index] = row_index;
+ ja[array_index] = (c_mechs + m->col_index);
+ ar[array_index] = 1;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ m = m->next;
+ }
+ row_index++;
+ }
+ GNUNET_assert (row_index-1==c_peers);
+ GNUNET_assert (array_index==c_mechs);
+
+ /* Constraint 1: only active mechanism gets bandwidth assigned */
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 2\n");
+ glp_add_rows(prob, c_mechs);
+ for (c=1; c<=c_mechs; c++)
+ {
+ /* b_t - n_t * M <= 0 */
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
+ glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
+
+ ia[array_index] = row_index;
+ ja[array_index] = mechanisms[c].col_index;
+ ar[array_index] = 1;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ ia[array_index] = row_index;
+ ja[array_index] = c_mechs + mechanisms[c].col_index;
+ ar[array_index] = -M;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ row_index ++;
+ }
+ GNUNET_assert (row_index-1==c_peers+c_mechs);
+ GNUNET_assert (array_index==c_mechs+(2*c_mechs));
+
+ /* Constraint 3: minimum bandwidth*/
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
+ glp_add_rows(prob, c_mechs);
+ for (c=1; c<=c_mechs; c++)
+ {
+ /* b_t - n_t * b_min <= 0 */
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
+ glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
+
+ ia[array_index] = row_index;
+ ja[array_index] = mechanisms[c].col_index;
+ ar[array_index] = 1;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ ia[array_index] = row_index;
+ ja[array_index] = c_mechs + mechanisms[c].col_index;
+ ar[array_index] = -v_b_min;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ row_index ++;
+ }
+ GNUNET_assert (row_index-1==c_peers+(2*c_mechs));
+ GNUNET_assert (array_index==c_mechs+(4*c_mechs));
+
+ /* Constraint 4: max ressource capacity */
+ /*
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
+ glp_add_rows(prob, c_mechs);
+ for (c=1; c<=c_mechs; c++)
+ {
+ // b_t - n_t * b_min >= 0
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
+ glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
+
+ ia[array_index] = row_index;
+ ja[array_index] = mechanisms[c].col_index;
+ ar[array_index] = 1;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ ia[array_index] = row_index;
+ ja[array_index] = c_mechs + mechanisms[c].col_index;
+ ar[array_index] = -v_b_min;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ row_index ++;
+ }
+ GNUNET_assert (row_index-1==c_peers+(2*c_mechs));
+ GNUNET_assert (array_index==5*c_mechs);
+ */
+
+ /* Constraint 5: min number of connections*/
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n");
+ glp_add_rows(prob, 1);
+ for (c=1; c<=c_mechs; c++)
+ {
+ // b_t - n_t * b_min >= 0
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
+ glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
+
+ ia[array_index] = row_index;
+ ja[array_index] = c_mechs + mechanisms[c].col_index;
+ ar[array_index] = 1;
+ if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
+ array_index++;
+ }
+ row_index ++;
+ GNUNET_assert (row_index-1==c_peers+(2*c_mechs)+1);
+ GNUNET_assert (array_index==6*c_mechs);
+
+ glp_load_matrix(prob, array_index-1, ia, ja, ar);
+
+ glp_delete_prob(prob);
+
+ /* clean up */
+
+ GNUNET_free (ja);
+ GNUNET_free (ia);
+ GNUNET_free (ar);
+
+ GNUNET_free(mechanisms);
+ GNUNET_free(peers);
+}
+
+/* To remove: just for testing */
+void ats_benchmark (int peers, int transports, int start_peers, int end_peers)
+{
+ struct GNUNET_TIME_Absolute start;
+ struct GNUNET_TIME_Relative duration;
+/*
+ int test = 11;
+ int mlp = GNUNET_NO;
+
+ for (test=start_peers; test<=end_peers; test++)
+ {
+ int peers = test;
+ int transports = 3;
+
+ double b_min = 5;
+ double b_max = 50;
+ double r = 0.85;//1.0;
+ double R = 1.0;
+
+ int it = ATS_MAX_ITERATIONS;
+ int dur = 500;
+ if (INT_MAX < ats->max_exec_duration.rel_value)
+ dur = INT_MAX;
+ else
+ dur = (int) ats->max_exec_duration.rel_value;
+
+
+ struct ATS_mechanism * tl = GNUNET_malloc(transports * sizeof (struct ATS_peer));
+
+ struct ATS_peer * pl = GNUNET_malloc(peers * sizeof (struct ATS_peer));
+ int c = 0;
+ while (c < peers)
+ {
+ pl[c].peer.hashPubKey.bits[0] = c+1;
+ pl[c].f = 1 / (double) peers ;
+ pl[c].t = 1;
+ //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_calculate_bandwidth_distribution Peer[%i] : %s %p \n",c , GNUNET_i2s(&pl[c].peer), &pl[c].peer);
+ c++;
+ }
+ c = 0;
+ while (c < transports)
+ {
+ tl[c].id = c;
+ tl[c].c_max = 10000;
+ tl[c].c_1 = 1;
+ //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_calculate_bandwidth_distribution Peer[%i] : %i \n",c , tl[c].id);
+ c++;
+
+ }
+
+ // test //
+
+ //pl[0].f = 0.33;
+ //pl[2].f = 0.43;
+ //pl[1].f = 0.33;
+ // test //
+ *
+ */
+ start = GNUNET_TIME_absolute_get();
+ ats_create_problem(5000,5000);
+
+ duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "benchmark result: %llu\n", duration);
+
+ GNUNET_STATISTICS_set (stats, "ATS execution time 100 peers", duration.rel_value, GNUNET_NO);
+}
+
+void ats_calculate_bandwidth_distribution ()
+{
+ struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
+ if (delta.rel_value < ats->min_delta.rel_value)
+ {
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
+#endif
+ return;
+ }
+
+ struct GNUNET_TIME_Absolute start;
+ /*
+ int mlp = GNUNET_NO;
+ int peers;
+ int transports;
+
+ double b_min;
+ double b_max;
+ double r;
+ double R;
+
+ int it = ATS_MAX_ITERATIONS;
+ */
+ int dur = 500;
+ if (INT_MAX < ats->max_exec_duration.rel_value)
+ dur = INT_MAX;
+ else
+ dur = (int) ats->max_exec_duration.rel_value;
+
+ struct ATS_mechanism * tl = NULL;
+ struct ATS_peer * pl = NULL;
+
+ start = GNUNET_TIME_absolute_get();
+ ats_benchmark(100,3,100,100);
+ //ats_create_problem(peers, transports, b_min, b_max, r, R, pl, tl, it, dur, mlp);
+
+ GNUNET_free_non_null (pl);
+ GNUNET_free_non_null (tl);
+
+ ats->last = GNUNET_TIME_absolute_get();
+}
+
+
+
+void
+ats_schedule_calculation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ATS_info *ats = (struct ATS_info *) cls;
+ if (ats==NULL)
+ return;
+
+ ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
+ if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
+#endif
+ ats_calculate_bandwidth_distribution (ats);
+
+ ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
+ &ats_schedule_calculation, ats);
+}
+
+
+int ats_map_remove_peer (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+
+ struct ATS_peer * p = (struct ATS_peer *) value;
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
+#endif
+ /* cleanup peer */
+ GNUNET_free(p);
+
+ return GNUNET_YES;
+}
+
+
+struct ATS_info * ats_init ()
+{
+ struct ATS_info * ats;
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
+#endif
+ ats = GNUNET_malloc(sizeof (struct ATS_info));
+ ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
+ GNUNET_assert(ats->peers!=NULL);
+
+ ats->min_delta = ATS_MIN_INTERVAL;
+ ats->exec_intervall = ATS_EXEC_INTERVAL;
+ ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
+ ats->max_iterations = ATS_MAX_ITERATIONS;
+
+ ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
+/*
+ ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
+ &schedule_calculation, NULL);
+
+ ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &schedule_calculation, NULL);
+*/
+ ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
+
+ return ats;
+}
+
+
+void ats_shutdown ()
+{
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
+#endif
+ if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(ats->ats_task);
+ ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
+ GNUNET_free (ats);
+}
+
+
+void ats_notify_peer_connect (
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
+{
+ int c = 0;
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
+#endif
+
+ while (ntohl(ats_data[c].type)!=0)
+ {
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
+#endif
+ c++;
+ }
+ /* check if peer is already known */
+ if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
+ {
+ struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
+ memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
+ GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+ }
+
+ ats_calculate_bandwidth_distribution(ats);
+}
+
+void ats_notify_peer_disconnect (
+ const struct GNUNET_PeerIdentity *peer)
+{
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
+#endif
+ /* remove peer */
+ if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
+ {
+ ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
+ GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
+ }
+
+ ats_calculate_bandwidth_distribution (ats);
+}
+
+
+void ats_notify_ats_data (
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
+{
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
+#endif
+ ats_calculate_bandwidth_distribution(ats);
+}
+
+struct ForeignAddressList * ats_get_preferred_address (
+ struct NeighbourList *n)
+{
+#if DEBUG_ATS
+ //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
+#endif
+ struct ReadyList *next = n->plugins;
+ while (next != NULL)
+ {
+#if DEBUG_ATS
+ //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
+#endif
+ next = next->next;
+ }
+ return find_ready_address(n);
+}
/**
* Initiate transport service.
validation_map = NULL;
return;
}
+
+ ats = ats_init();
max_connect_per_transport = (uint32_t) tneigh;
peerinfo = GNUNET_PEERINFO_connect (cfg);
if (peerinfo == NULL)