#include "gnunet_service_lib.h"
#include "gnunet_signatures.h"
#include "gnunet_transport_plugin.h"
+#include "gnunet-service-transport_ats.h"
#include "transport.h"
-#if HAVE_LIBGLPK
-#include <glpk.h>
-#endif
+
+
#define DEBUG_BLACKLIST GNUNET_NO
#define DEBUG_TRANSPORT_HELLO GNUNET_NO
-#define DEBUG_ATS GNUNET_NO
-
-#define VERBOSE_ATS GNUNET_NO
+#define DEBUG_INBOUND GNUNET_NO
/**
* Should we do some additional checks (to validate behavior
*/
#define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
-/**
- * Maximum frequency for re-evaluating latencies for all transport addresses.
- */
-#define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
-
-/**
- * Maximum frequency for re-evaluating latencies for connected addresses.
- */
-#define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
-
-#define VERY_BIG_DOUBLE_VALUE 100000000000LL
-
-#define ATS_NEW 0
-#define ATS_Q_UPDATED 1
-#define ATS_C_UPDATED 2
-#define ATS_QC_UPDATED 3
-#define ATS_UNMODIFIED 4
-
/**
* List of addresses of other peers
*/
*/
struct OwnAddressList *next;
- /**
- * How long until we actually auto-expire this address (unless it is
- * re-confirmed by the transport)?
- */
- struct GNUNET_TIME_Absolute expires;
-
/**
* How long until the current signature expires? (ZERO if the
* signature was never created).
*/
struct TransportPlugin
{
-
/**
* This is a linked list.
*/
struct GNUNET_CONTAINER_MultiHashMap *blacklist;
};
-struct NeighbourList;
+struct NeighbourMapEntry;
/**
* For each neighbour we keep a list of messages
/**
* To which neighbour does this ready list belong to?
*/
- struct NeighbourList *neighbour;
+ struct NeighbourMapEntry *neighbour;
};
/**
- * Entry in linked list of all of our current neighbours.
+ * Entry in neighbours.
*/
-struct NeighbourList
+struct NeighbourMapEntry
{
- /**
- * This is a linked list.
- */
- struct NeighbourList *next;
-
/**
* Which of our transports is connected to this peer
* and what is their status?
*/
struct MessageQueue *messages_tail;
+ /**
+ * Head of list of messages of messages we expected the continuation
+ * to be called to destroy the message
+ */
+ struct MessageQueue *cont_head;
+
+ /**
+ * Tail of list of messages of messages we expected the continuation
+ * to be called to destroy the message
+ */
+ struct MessageQueue *cont_tail;
+
/**
* Buffer for at most one payload message used when we receive
* payload data before our PING-PONG has succeeded. We then
int public_key_valid;
/**
- * Performance data for the peer.
+ * Are we already in the process of disconnecting this neighbour?
*/
- struct GNUNET_TRANSPORT_ATS_Information *ats;
+ int in_disconnect;
/**
- * Identity of the neighbour.
+ * Performance data for the peer.
*/
- struct GNUNET_PeerIdentity peer;
-
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
};
/**
/**
* Entry in map of all HELLOs awaiting validation.
*/
-struct ValidationEntry
+struct ValidationEntry
{
/**
unsigned int ve_count;
};
-struct ATS_quality_metric
-{
- int index;
- int atis_index;
- char * name;
-};
-
-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;
- struct ATS_ressource_cost * rc;
-};
-
-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;
-};
-
-struct ATS_stat
-{
- /**
- * result of last GLPK run
- * 5 == OPTIMAL
- */
- int solution;
-
- /**
- * Ressource costs or quality metrics changed
- * update problem before solving
- */
- int modified_resources;
-
- /**
- * Ressource costs or quality metrics changed, update matrix
- * update problem before solving
- */
- int modified_quality;
-
- /**
- * Peers have connected or disconnected
- * problem has to be recreated
- */
- int recreate_problem;
-
- /**
- * Was the available basis invalid and we needed to rerun simplex?
- */
- int simplex_rerun_required;
-
- /**
- * is problem currently valid and can it be solved
- */
- int valid;
-
- /**
- * Number of transport mechanisms in the problem
- */
- int c_mechs;
-
- /**
- * Number of transport mechanisms in the problem
- */
- int c_peers;
-
- /**
- * row index where quality related rows start
- */
- int begin_qm;
-
- /**
- * row index where quality related rows end
- */
- int end_qm;
-
- /**
- * row index where ressource cost related rows start
- */
- int begin_cr;
-
- /**
- * row index where ressource cost related rows end
- */
- int end_cr;
-
- /**
- * column index for objective function value d
- */
- int col_d;
-
- /**
- * column index for objective function value u
- */
- int col_u;
-
- /**
- * column index for objective function value r
- */
- int col_r;
-
- /**
- * column index for objective function value quality metrics
- */
- int col_qm;
-
- /**
- * column index for objective function value cost ressources
- */
- int col_cr;
-};
-
-struct ATS_ressource_entry
-{
- /* index in ressources array */
- int index;
- /* depending ATSi parameter to calculcate limits */
- int atis_index;
- /* lower bound */
- double c;
-};
-
-
-struct ATS_ressource
-{
- /* index in ressources array */
- int index;
- /* depending ATSi parameter to calculcate limits */
- int atis_index;
- /* cfg option to load limits */
- char * cfg_param;
- /* lower bound */
- double c_min;
- /* upper bound */
- double c_max;
-
- /* cofficients for the specific plugins */
- double c_unix;
- double c_tcp;
- double c_udp;
- double c_http;
- double c_https;
- double c_wlan;
- double c_default;
-};
-
-static struct ATS_ressource ressources[] =
-{
- /* FIXME: the coefficients for the specific plugins */
- {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
- {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
- {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
-/*
- {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
- {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
- {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
- {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
-};
-
-static int available_ressources = 3;
-
-
-
-struct ATS_info
-{
-
- /**
- * Time of last execution
- */
- struct GNUNET_TIME_Absolute last;
- /**
- * Minimum intervall between two executions
- */
- struct GNUNET_TIME_Relative min_delta;
- /**
- * Regular intervall when execution is triggered
- */
- struct GNUNET_TIME_Relative exec_interval;
- /**
- * Maximum execution time per calculation
- */
- struct GNUNET_TIME_Relative max_exec_duration;
-
-#if HAVE_LIBGLPK
- /**
- * GLPK (MLP) problem object
- */
- glp_prob *prob;
-#endif
-
- /**
- * task to recalculate the bandwidth assignment
- */
- GNUNET_SCHEDULER_TaskIdentifier ats_task;
-
- /**
- * Current state of the GLPK problem
- */
- struct ATS_stat stat;
-
- /**
- * mechanisms used in current problem
- * needed for problem modification
- */
- struct ATS_mechanism * mechanisms;
-
- /**
- * peers used in current problem
- * needed for problem modification
- */
- struct ATS_peer * peers;
-
- /**
- * number of successful executions
- */
- int successful_executions;
-
- /**
- * number with an invalid result
- */
- int invalid_executions;
-
- /**
- * Maximum number of LP iterations per calculation
- */
- int max_iterations;
-
- /**
- * Dump problem to a file?
- */
- int save_mlp;
-
- /**
- * Dump solution to a file
- */
- int save_solution;
-
- /**
- * Dump solution when minimum peers:
- */
- int dump_min_peers;
-
- /**
- * Dump solution when minimum addresses:
- */
- int dump_min_addr;
-
- /**
- * Dump solution overwrite file:
- */
- int dump_overwrite;
-
- /**
- * Diversity weight
- */
- double D;
-
- /**
- * Utility weight
- */
- double U;
-
- /**
- * Relativity weight
- */
- double R;
-
- /**
- * Minimum bandwidth per peer
- */
- int v_b_min;
-
- /**
- * Minimum number of connections per peer
- */
- int v_n_min;
-};
+/**
+ * All zero hash for comparison.
+ */
+static GNUNET_HashCode null_hash;
/**
* Our HELLO message.
/**
* All known neighbours and their HELLOs.
*/
-static struct NeighbourList *neighbours;
+static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
/**
* Number of neighbours we'd like to have.
static struct GNUNET_STATISTICS_Handle *stats;
/**
- * Handle for ats information
+ * Identifier of 'refresh_hello' task.
*/
-static struct ATS_info *ats;
+static GNUNET_SCHEDULER_TaskIdentifier hello_task;
-struct ATS_quality_entry
-{
- int index;
- int atsi_index;
- uint32_t values[3];
- int current;
-};
+/**
+ * Identifier of ats scheduler task.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ats_task;
-static struct ATS_quality_metric qm[] =
-{
- {1, 1028, "QUALITY_NET_DISTANCE"},
- {2, 1034, "QUALITY_NET_DELAY"},
-};
-static int available_quality_metrics = 2;
+/**
+ * Is transport service shutting down ?
+ */
+static int shutdown_in_progress;
+
+/**
+ * Handle for ats information
+ */
+static struct ATS_Handle *ats;
+/**
+ * Time of last ats execution
+ */
+struct GNUNET_TIME_Absolute last_ats_execution;
+/**
+ * Minimum interval between two ATS executions
+ */
+struct GNUNET_TIME_Relative ats_minimum_interval;
+/**
+ * Regular interval when ATS execution is triggered
+ */
+struct GNUNET_TIME_Relative ats_regular_interval;
/**
* The peer specified by the given neighbour has timed-out or a plugin
* disconnected or must we ask all plugins to
* disconnect?
*/
-static void disconnect_neighbour (struct NeighbourList *n, int check);
+static void disconnect_neighbour (struct NeighbourMapEntry *n, int check);
/**
* Check the ready list for the given neighbour and if a plugin is
*
* @param nexi target peer for which to transmit
*/
-static void try_transmission_to_peer (struct NeighbourList *n);
-
-static void ats_shutdown ( );
-
-static void ats_notify_peer_connect (
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count);
-
-static void ats_notify_peer_disconnect (
- const struct GNUNET_PeerIdentity *peer);
+static void try_transmission_to_peer (struct NeighbourMapEntry *n);
-#if 0
-static void ats_notify_ats_data (
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
-#endif
-
-struct ForeignAddressList * ats_get_preferred_address (
- struct NeighbourList *n);
-
-static void
-ats_calculate_bandwidth_distribution ();
+struct ForeignAddressList * get_preferred_ats_address (
+ struct NeighbourMapEntry *n);
/**
* Find an entry in the neighbour list for a particular peer.
*
* @return NULL if not found.
*/
-static struct NeighbourList *
+static struct NeighbourMapEntry *
find_neighbour (const struct GNUNET_PeerIdentity *key)
{
- struct NeighbourList *head = neighbours;
-
- while ((head != NULL) &&
- (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
- head = head->next;
- return head;
+ return GNUNET_CONTAINER_multihashmap_get (neighbours, &key->hashPubKey);
}
static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
{
- int c;
- int set = GNUNET_NO;
- for (c=0; c<available_quality_metrics; c++)
- {
- if (ats_index == qm[c].atis_index)
- {
- fal->quality[c].values[0] = fal->quality[c].values[1];
- fal->quality[c].values[1] = fal->quality[c].values[2];
- fal->quality[c].values[2] = value;
- set = GNUNET_YES;
- ats->stat.modified_quality = GNUNET_YES;
- }
- }
- if (set == GNUNET_NO)
- {
- for (c=0; c<available_ressources; c++)
- {
- if (ats_index == ressources[c].atis_index)
- {
- fal->ressources[c].c = value;
- set = GNUNET_YES;
- ats->stat.modified_resources = GNUNET_YES;
- }
- }
- }
-
- return set;
+ int c;
+ int set = GNUNET_NO;
+ for (c=0; c<available_quality_metrics; c++)
+ {
+ if (ats_index == qm[c].atis_index)
+ {
+ fal->quality[c].values[0] = fal->quality[c].values[1];
+ fal->quality[c].values[1] = fal->quality[c].values[2];
+ fal->quality[c].values[2] = value;
+ set = GNUNET_YES;
+#if HAVE_LIBGLPK
+ ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
+#endif
+ }
+ }
+ if (set == GNUNET_NO)
+ {
+ for (c=0; c<available_ressources; c++)
+ {
+ if (ats_index == ressources[c].atis_index)
+ {
+ fal->ressources[c].c = value;
+ set = GNUNET_YES;
+#if HAVE_LIBGLPK
+ ats_modify_problem_state (ats, ATS_COST_UPDATED);
+#endif
+ }
+ }
+ }
+ return set;
}
static int
client->th = NULL;
if (buf == NULL)
{
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Transmission to client failed, closing connection.\n");
#endif
if (plugin == NULL)
return NULL;
p = find_transport (plugin);
- if (p == NULL)
+ if ((p == NULL) || (addr_len == 0) || (addr == NULL))
return NULL;
- return p->api->address_to_string (p->api->cls,
+ return p->api->address_to_string (NULL,
addr,
addr_len);
}
+
+
/**
- * Mark the given FAL entry as 'connected' (and hence preferred for
- * sending); also mark all others for the same peer as 'not connected'
- * (since only one can be preferred).
+ * Iterator to free entries in the validation_map.
*
- * @param fal address to set to 'connected'
+ * @param cls closure (unused)
+ * @param key current key code
+ * @param value value in the hash map (validation to abort)
+ * @return GNUNET_YES (always)
*/
-static void
-mark_address_connected (struct ForeignAddressList *fal)
+static int
+abort_validation (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
{
- struct ForeignAddressList *pos;
- int cnt;
+ struct ValidationEntry *va = value;
- GNUNET_assert (GNUNET_YES == fal->validated);
- if (fal->connected == GNUNET_YES)
- return; /* nothing to do */
- cnt = GNUNET_YES;
- pos = fal->ready_list->addresses;
- while (pos != NULL)
+ if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
+ GNUNET_SCHEDULER_cancel (va->timeout_task);
+ GNUNET_free (va->transport_name);
+ if (va->chvc != NULL)
{
- if (GNUNET_YES == pos->connected)
+ va->chvc->ve_count--;
+ if (va->chvc->ve_count == 0)
{
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Marking address `%s' as no longer connected (due to connect on other address)\n",
- a2s (pos->ready_list->plugin->short_name,
- pos->addr,
- pos->addrlen));
-#endif
- GNUNET_break (cnt == GNUNET_YES);
- cnt = GNUNET_NO;
- pos->connected = GNUNET_NO;
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# connected addresses"),
- -1,
- GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (chvc_head,
+ chvc_tail,
+ va->chvc);
+ GNUNET_free (va->chvc);
}
- pos = pos->next;
- }
- fal->connected = GNUNET_YES;
- if (GNUNET_YES == cnt)
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# connected addresses"),
- 1,
- GNUNET_NO);
+ va->chvc = NULL;
}
+ GNUNET_free (va);
+ return GNUNET_YES;
+}
+
+
+/**
+ * HELLO validation cleanup task (validation failed).
+ *
+ * @param cls the 'struct ValidationEntry' that failed
+ * @param tc scheduler context (unused)
+ */
+static void
+timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ValidationEntry *va = cls;
+ struct GNUNET_PeerIdentity pid;
+
+ va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# address validation timeouts"),
+ 1,
+ GNUNET_NO);
+ GNUNET_CRYPTO_hash (&va->publicKey,
+ sizeof (struct
+ GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &pid.hashPubKey);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (validation_map,
+ &pid.hashPubKey,
+ va));
+ abort_validation (NULL, NULL, va);
}
+
/**
* Send the specified message to the specified client. Since multiple
* messages may be pending for the same client at a time, this code
struct ClientMessageQueueEntry *q;
uint16_t msize;
+ /* Client==NULL when GNUNET_SERVER_Client disconnected and was
+ * freed in client_disconnect_notification
+ */
+ if (client->client == NULL)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
memcpy (&q[1], msg, msize);
- GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
- client->message_queue_tail,
- client->message_queue_tail,
- q);
+ GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
+ client->message_queue_tail,
+ q);
client->message_count++;
if (client->th == NULL)
{
*/
static void
transmit_send_ok (struct TransportClient *client,
- struct NeighbourList *n,
+ struct NeighbourMapEntry *n,
const struct GNUNET_PeerIdentity *target,
int result)
{
}
+/**
+ * Mark the given FAL entry as 'connected' (and hence preferred for
+ * sending); also mark all others for the same peer as 'not connected'
+ * (since only one can be preferred).
+ *
+ * @param fal address to set to 'connected'
+ */
+static void
+mark_address_connected (struct ForeignAddressList *fal);
+
+
+
+/**
+ * We should re-try transmitting to the given peer,
+ * hopefully we've learned something in the meantime.
+ */
+static void
+retry_transmission_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct NeighbourMapEntry *n = cls;
+
+ n->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ try_transmission_to_peer (n);
+}
+
+
/**
* Function called by the GNUNET_TRANSPORT_TransmitFunction
* upon "completion" of a send request. This tells the API
int result)
{
struct MessageQueue *mq = cls;
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
GNUNET_STATISTICS_update (stats,
gettext_noop ("# bytes pending with plugins"),
}
else
{
- if (mq->specific_address->connected != GNUNET_NO)
+ if (mq->specific_address->connected == GNUNET_YES)
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
if (! mq->internal_msg)
mq->specific_address->in_transmit = GNUNET_NO;
}
- n = find_neighbour(&mq->neighbour_id);
+ n = find_neighbour (&mq->neighbour_id);
if (mq->client != NULL)
transmit_send_ok (mq->client, n, target, result);
+ GNUNET_assert (n != NULL);
+ GNUNET_CONTAINER_DLL_remove (n->cont_head,
+ n->cont_tail,
+ mq);
GNUNET_free (mq);
- if (n != NULL)
+ if (result == GNUNET_OK)
try_transmission_to_peer (n);
+ else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
+ n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
+ n);
}
/**
- * Find an address in any of the available transports for
- * the given neighbour that would be good for message
- * transmission. This is essentially the transport selection
- * routine.
+ * 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 for whom to select an address
- * @return selected address, NULL if we have none
+ * @param neighbour target peer for which to transmit
*/
-struct ForeignAddressList *
-find_ready_address(struct NeighbourList *neighbour)
-{
- struct ReadyList *head = neighbour->plugins;
- struct ForeignAddressList *addresses;
- 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)
- {
- addresses = head->addresses;
- while (addresses != NULL)
- {
- if ( (addresses->timeout.abs_value < now.abs_value) &&
- (addresses->connected == GNUNET_YES) )
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Marking long-time inactive connection to `%4s' as down.\n",
- GNUNET_i2s (&neighbour->id));
-#endif
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# connected addresses"),
- -1,
- GNUNET_NO);
- addresses->connected = GNUNET_NO;
- }
- addresses = addresses->next;
- }
-
- addresses = head->addresses;
- while (addresses != NULL)
- {
-#if DEBUG_TRANSPORT > 1
- if (addresses->addr != NULL)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
- a2s (head->plugin->short_name,
- addresses->addr,
- addresses->addrlen),
- GNUNET_i2s (&neighbour->id),
- addresses->connected,
- addresses->in_transmit,
- addresses->validated,
- addresses->connect_attempts,
- (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) ) &&
- (addresses->in_transmit == GNUNET_NO) &&
- ( (best_address == NULL) ||
- (addresses->latency.rel_value < best_address->latency.rel_value)) )
- best_address = addresses;
- /* FIXME: also give lower-latency addresses that are not
- 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_ERROR,
- "Best address found (`%s') has latency of %llu ms.\n",
- (best_address->addrlen > 0)
- ? a2s (best_address->ready_list->plugin->short_name,
- best_address->addr,
- best_address->addrlen)
- : "<inbound>",
- best_address->latency.rel_value);
-#endif
- }
- else
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# transmission attempts failed (no address)"),
- 1,
- GNUNET_NO);
- }
-
- return best_address;
-
-}
-
-
-/**
- * We should re-try transmitting to the given peer,
- * hopefully we've learned something in the meantime.
- */
-static void
-retry_transmission_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct NeighbourList *n = cls;
-
- n->retry_task = GNUNET_SCHEDULER_NO_TASK;
- try_transmission_to_peer (n);
-}
-
-
-/**
- * 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
- */
-static void
-try_transmission_to_peer (struct NeighbourList *n)
+static void
+try_transmission_to_peer (struct NeighbourMapEntry *n)
{
struct ReadyList *rl;
struct MessageQueue *mq;
force_address = GNUNET_YES;
if (mq->specific_address == NULL)
{
- /* TODO: ADD ATS */
- mq->specific_address = ats_get_preferred_address(n);
+ /* TODO: ADD ATS */
+ mq->specific_address = get_preferred_ats_address(n);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# transport selected peer address freely"),
1,
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,
- n);
+ &retry_transmission_task,
+ 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",
gettext_noop ("# bytes pending with plugins"),
mq->message_buf_size,
GNUNET_NO);
+
+ GNUNET_CONTAINER_DLL_insert (n->cont_head,
+ n->cont_tail,
+ mq);
+
ret = rl->plugin->api->send (rl->plugin->api->cls,
&mq->neighbour_id,
mq->message_buf,
struct GNUNET_TIME_Relative timeout,
const char *message_buf,
size_t message_buf_size,
- int is_internal, struct NeighbourList *neighbour)
+ int is_internal, struct NeighbourMapEntry *neighbour)
{
struct MessageQueue *mq;
/**
- * FIXME: document.
- */
-struct GeneratorContext
-{
- struct TransportPlugin *plug_pos;
- struct OwnAddressList *addr_pos;
- struct GNUNET_TIME_Absolute expiration;
-};
-
-
-/**
- * FIXME: document.
+ * Send a plain PING (without address or our HELLO) to the given
+ * foreign address to try to establish a connection (and validate
+ * that the other peer is really who he claimed he is).
+ *
+ * @param n neighbour to PING
*/
-static size_t
-address_generator (void *cls, size_t max, void *buf)
+static void
+transmit_plain_ping (struct NeighbourMapEntry *n)
{
- struct GeneratorContext *gc = cls;
- size_t ret;
+ struct ValidationEntry *ve;
+ struct TransportPingMessage ping;
+ struct ReadyList *rl;
+ struct TransportPlugin *plugin;
+ struct ForeignAddressList *fal;
- while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
+ if (! n->public_key_valid)
{
- gc->plug_pos = gc->plug_pos->next;
- gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
+ /* This should not happen since the other peer
+ should send us a HELLO prior to sending his
+ PING */
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Could not transmit plain PING to `%s': public key not known\n",
+ GNUNET_i2s (&n->id));
+ return;
}
- if (NULL == gc->plug_pos)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Looking for addresses to transmit plain PING to `%s'\n",
+ GNUNET_i2s (&n->id));
+ for (rl = n->plugins; rl != NULL; rl = rl->next)
{
-
- return 0;
+ plugin = rl->plugin;
+ for (fal = rl->addresses; fal != NULL; fal = fal->next)
+ {
+ if (! fal->connected)
+ continue;
+ ve = GNUNET_malloc (sizeof (struct ValidationEntry));
+ ve->transport_name = GNUNET_strdup (plugin->short_name);
+ ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ UINT_MAX);
+ ve->send_time = GNUNET_TIME_absolute_get();
+ ve->session = fal->session;
+ memcpy(&ve->publicKey,
+ &n->publicKey,
+ sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+ ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
+ &timeout_hello_validation,
+ ve);
+ GNUNET_CONTAINER_multihashmap_put (validation_map,
+ &n->id.hashPubKey,
+ ve,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ ping.header.size = htons(sizeof(struct TransportPingMessage));
+ ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+ ping.challenge = htonl(ve->challenge);
+ memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# PING without HELLO messages sent"),
+ 1,
+ GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting plain PING to `%s'\n",
+ GNUNET_i2s (&n->id));
+ transmit_to_peer (NULL,
+ fal,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ HELLO_VERIFICATION_TIMEOUT,
+ (const char*) &ping, sizeof (ping),
+ GNUNET_YES, n);
+ }
}
- ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
- gc->expiration,
- &gc->addr_pos[1],
- gc->addr_pos->addrlen, buf, max);
- gc->addr_pos = gc->addr_pos->next;
- return ret;
}
/**
- * Construct our HELLO message from all of the addresses of
- * all of the transports.
+ * Mark the given FAL entry as 'connected' (and hence preferred for
+ * sending); also mark all others for the same peer as 'not connected'
+ * (since only one can be preferred).
+ *
+ * @param fal address to set to 'connected'
*/
static void
-refresh_hello ()
+mark_address_connected(struct ForeignAddressList *fal)
{
- struct GNUNET_HELLO_Message *hello;
- struct TransportClient *cpos;
- struct NeighbourList *npos;
- struct GeneratorContext gc;
+ struct ForeignAddressList *pos;
+ struct ForeignAddressList *inbound;
+ struct ForeignAddressList *outbound;
- gc.plug_pos = plugins;
- gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
- gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
- hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
-#endif
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# refreshed my HELLO"),
- 1,
- GNUNET_NO);
- cpos = clients;
- while (cpos != NULL)
+ GNUNET_assert (GNUNET_YES == fal->validated);
+ if (fal->connected == GNUNET_YES)
+ return; /* nothing to do */
+ inbound = NULL;
+ outbound = NULL;
+
+ pos = fal->ready_list->addresses;
+ while (pos != NULL)
{
- transmit_to_client (cpos,
- (const struct GNUNET_MessageHeader *) hello,
- GNUNET_NO);
- cpos = cpos->next;
+ /* Already have inbound address, and this is also an inbound address, don't switch!! */
+ if ( (GNUNET_YES == pos->connected) &&
+ (0 == pos->addrlen) &&
+ (0 == fal->addrlen) )
+ return;
+ if ( (0 == pos->addrlen) &&
+ (GNUNET_YES == pos->connected) )
+ inbound = pos;
+ pos = pos->next;
}
- GNUNET_free_non_null (our_hello);
- our_hello = hello;
- GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
- npos = neighbours;
- while (npos != NULL)
+ pos = fal->ready_list->addresses;
+ while (pos != NULL)
{
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Transmitting updated `%s' to neighbour `%4s'\n",
- "HELLO", GNUNET_i2s (&npos->id));
-#endif
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# transmitted my HELLO to other peers"),
- 1,
- GNUNET_NO);
- transmit_to_peer (NULL, NULL, 0,
- HELLO_ADDRESS_EXPIRATION,
- (const char *) our_hello,
- GNUNET_HELLO_size(our_hello),
- GNUNET_NO, npos);
- npos = npos->next;
+ /* Already have outbound address, and this is also an outbound address, don't switch!! */
+ if ( (GNUNET_YES == pos->connected) &&
+ (0 < pos->addrlen) &&
+ (0 < fal->addrlen) )
+ return;
+ if ( (0 < pos->addrlen) && (GNUNET_YES == pos->connected) )
+ outbound = pos;
+ pos = pos->next;
}
-}
-
-/**
- * Task used to clean up expired addresses for a plugin.
- *
- * @param cls closure
- * @param tc context
- */
-static void
-expire_address_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
+#if DEBUG_INBOUND
+ if (inbound != NULL)
+ fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
+ if (outbound != NULL)
+ fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
+#endif
+ /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
+ if ((inbound != NULL) && (0 != fal->addrlen) && (1
+ == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
+ &my_identity.hashPubKey, &null_hash)))
+ {
+#if DEBUG_INBOUND
+ fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
+#endif
+ return;
+ }
+ else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
+ == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
+ &my_identity.hashPubKey, &null_hash))))
+ {
+#if DEBUG_INBOUND
+ fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
+#endif
+ return;
+ }
-/**
- * Update the list of addresses for this plugin,
- * expiring those that are past their expiration date.
- *
- * @param plugin addresses of which plugin should be recomputed?
- * @param fresh set to GNUNET_YES if a new address was added
- * and we need to regenerate the HELLO even if nobody
- * expired
- */
-static void
-update_addresses (struct TransportPlugin *plugin,
- int fresh)
-{
- static struct GNUNET_TIME_Absolute last_update;
- struct GNUNET_TIME_Relative min_remaining;
- struct GNUNET_TIME_Relative remaining;
- struct GNUNET_TIME_Absolute now;
- struct OwnAddressList *pos;
- struct OwnAddressList *prev;
- struct OwnAddressList *next;
- int expired;
-
- if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (plugin->address_update_task);
- plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
- now = GNUNET_TIME_absolute_get ();
- min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
- expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
- prev = NULL;
- pos = plugin->addresses;
+ pos = fal->ready_list->addresses;
while (pos != NULL)
{
- next = pos->next;
- if (pos->expires.abs_value < now.abs_value)
- {
- expired = GNUNET_YES;
- if (prev == NULL)
- plugin->addresses = pos->next;
- else
- prev->next = pos->next;
- GNUNET_free (pos);
- }
- else
+ if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
{
- remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
- if (remaining.rel_value < min_remaining.rel_value)
- min_remaining = remaining;
- prev = pos;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Marking address `%s' as no longer connected (due to connect on other address)\n",
+ a2s (pos->ready_list->plugin->short_name, pos->addr,
+ pos->addrlen));
+#endif
+#if DEBUG_INBOUND
+ fprintf(stderr,
+ "Peer: %s, setting %s connection to disconnected.\n",
+ GNUNET_i2s(&my_identity),
+ (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
+#endif
+ pos->connected = GNUNET_NO;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connected addresses"), -1,
+ GNUNET_NO);
}
- pos = next;
- }
-
- if (expired || fresh)
- {
- last_update = now;
- refresh_hello ();
+ pos = pos->next;
}
- min_remaining = GNUNET_TIME_relative_min (min_remaining,
- GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
- 2));
- plugin->address_update_task
- = GNUNET_SCHEDULER_add_delayed (min_remaining,
- &expire_address_task, plugin);
+ GNUNET_assert (GNUNET_NO == fal->connected);
+ fal->connected = GNUNET_YES;
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
+ 1, GNUNET_NO);
}
/**
- * Task used to clean up expired addresses for a plugin.
+ * Find an address in any of the available transports for
+ * the given neighbour that would be good for message
+ * transmission. This is essentially the transport selection
+ * routine.
*
- * @param cls closure
- * @param tc context
+ * @param neighbour for whom to select an address
+ * @return selected address, NULL if we have none
*/
-static void
-expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+struct ForeignAddressList *
+find_ready_address(struct NeighbourMapEntry *neighbour)
{
- struct TransportPlugin *plugin = cls;
+ struct ReadyList *head = neighbour->plugins;
+ struct ForeignAddressList *addresses;
+ 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)
+ {
+ addresses = head->addresses;
+ while (addresses != NULL)
+ {
+ if ( (addresses->timeout.abs_value < now.abs_value) &&
+ (addresses->connected == GNUNET_YES) )
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Marking long-time inactive connection to `%4s' as down.\n",
+ GNUNET_i2s (&neighbour->id));
+#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connected addresses"),
+ -1,
+ GNUNET_NO);
+ addresses->connected = GNUNET_NO;
+ }
+ addresses = addresses->next;
+ }
+
+ addresses = head->addresses;
+ while (addresses != NULL)
+ {
+#if DEBUG_TRANSPORT
+ if (addresses->addr != NULL)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
+ a2s (head->plugin->short_name,
+ addresses->addr,
+ addresses->addrlen),
+ GNUNET_i2s (&neighbour->id),
+ addresses->connected,
+ addresses->in_transmit,
+ addresses->validated,
+ addresses->connect_attempts,
+ (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) ) &&
+ (addresses->in_transmit == GNUNET_NO) &&
+ ( (best_address == NULL) ||
+ (addresses->latency.rel_value < best_address->latency.rel_value)) )
+ best_address = addresses;
+ /* FIXME: also give lower-latency addresses that are not
+ 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_DEBUG,
+ "Found UNIX address, forced this address\n");
+#endif
+ }
+ if (best_address != NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Best address found (`%s') has latency of %llu ms.\n",
+ (best_address->addrlen > 0)
+ ? a2s (best_address->ready_list->plugin->short_name,
+ best_address->addr,
+ best_address->addrlen)
+ : "<inbound>",
+ best_address->latency.rel_value);
+#endif
+ }
+ else
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# transmission attempts failed (no address)"),
+ 1,
+ GNUNET_NO);
+ }
+
+ return best_address;
+}
+
+
+/**
+ * FIXME: document.
+ */
+struct GeneratorContext
+{
+ struct TransportPlugin *plug_pos;
+ struct OwnAddressList *addr_pos;
+ struct GNUNET_TIME_Absolute expiration;
+};
+
+
+/**
+ * FIXME: document.
+ */
+static size_t
+address_generator (void *cls, size_t max, void *buf)
+{
+ struct GeneratorContext *gc = cls;
+ size_t ret;
+
+ while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
+ {
+ gc->plug_pos = gc->plug_pos->next;
+ gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
+ }
+ if (NULL == gc->plug_pos)
+ {
+
+ return 0;
+ }
+ ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
+ gc->expiration,
+ &gc->addr_pos[1],
+ gc->addr_pos->addrlen, buf, max);
+ gc->addr_pos = gc->addr_pos->next;
+ return ret;
+}
+
+
+
+static int
+transmit_our_hello_if_pong (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct NeighbourMapEntry *npos = value;
+
+ if (GNUNET_YES != npos->received_pong)
+ return GNUNET_OK;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Transmitting updated `%s' to neighbour `%4s'\n",
+ "HELLO", GNUNET_i2s (&npos->id));
+#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# transmitted my HELLO to other peers"),
+ 1,
+ GNUNET_NO);
+ transmit_to_peer (NULL, NULL, 0,
+ HELLO_ADDRESS_EXPIRATION,
+ (const char *) our_hello,
+ GNUNET_HELLO_size(our_hello),
+ GNUNET_NO, npos);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Construct our HELLO message from all of the addresses of
+ * all of the transports.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+refresh_hello_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_HELLO_Message *hello;
+ struct TransportClient *cpos;
+ struct GeneratorContext gc;
+
+ hello_task = GNUNET_SCHEDULER_NO_TASK;
+ gc.plug_pos = plugins;
+ gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
+ gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
+ hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
+#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# refreshed my HELLO"),
+ 1,
+ GNUNET_NO);
+ cpos = clients;
+ while (cpos != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting my HELLO to client!\n");
+ transmit_to_client (cpos,
+ (const struct GNUNET_MessageHeader *) hello,
+ GNUNET_NO);
+ cpos = cpos->next;
+ }
+
+ GNUNET_free_non_null (our_hello);
+ our_hello = hello;
+ GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &transmit_our_hello_if_pong,
+ NULL);
+}
+
- plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- update_addresses (plugin, GNUNET_NO);
+/**
+ * Schedule task to refresh hello (unless such a
+ * task exists already).
+ */
+static void
+refresh_hello ()
+{
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "refresh_hello() called!\n");
+#endif
+ if (hello_task != GNUNET_SCHEDULER_NO_TASK)
+ return;
+ hello_task
+ = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
+ NULL);
}
*/
static void
try_fast_reconnect (struct TransportPlugin *p,
- struct NeighbourList *nl)
+ struct NeighbourMapEntry *nl)
{
/* FIXME-MW: fast reconnect / transport switching not implemented... */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
* GNUNET_NO in the call below makes transport disconnect the peer,
* even if only a single address (out of say, six) went away. This
* function must be careful to ONLY disconnect if the peer is gone,
- * not just a specifi address.
+ * not just a specific address.
*
* More specifically, half the places it was used had it WRONG.
*/
/* No reconnect, signal disconnect instead! */
#if DEBUG_TRANSPORT
+#endif
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
"try_fast_reconnect");
-#endif
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to try_fast_reconnect"),
+ 1,
+ GNUNET_NO);
+#if DISCONNECT || 1
disconnect_neighbour (nl, GNUNET_YES);
+#endif
}
struct Session *session)
{
struct TransportPlugin *p = cls;
- struct NeighbourList *nl;
+ struct NeighbourMapEntry *nl;
struct ReadyList *rl;
struct ForeignAddressList *pos;
struct ForeignAddressList *prev;
"Plugin was associated with peer `%4s'\n",
GNUNET_i2s(peer));
#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to session end"),
+ 1,
+ GNUNET_NO);
disconnect_neighbour (nl, GNUNET_YES);
return;
}
"Session was never marked as ready for peer `%4s'\n",
GNUNET_i2s(peer));
#endif
+
+ int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
+
+ /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
+ if (validations_pending ==GNUNET_YES)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
+#endif
+ return;
+ }
+
//FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to unready session"),
+ 1,
+ GNUNET_NO);
+
disconnect_neighbour (nl, GNUNET_YES);
return; /* was never marked as connected */
}
pos->session = NULL;
+ if (GNUNET_YES == pos->connected)
+ {
+ pos->connected = GNUNET_NO;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connected addresses"),
+ -1,
+ GNUNET_NO);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
+ {
+ GNUNET_SCHEDULER_cancel (pos->revalidate_task);
+ pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
if (pos->addrlen != 0)
{
if (nl->received_pong != GNUNET_NO)
- try_fast_reconnect (p, nl);
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
+ 1,
+ GNUNET_NO);
+ if (GNUNET_YES == pos->connected)
+ try_fast_reconnect (p, nl);
+ }
else
- disconnect_neighbour (nl, GNUNET_YES);
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to missing pong"),
+ 1,
+ GNUNET_NO);
+ /* FIXME this is never true?! See: line 2416*/
+ if (GNUNET_YES == pos->connected)
+ disconnect_neighbour (nl, GNUNET_YES);
+ }
return;
}
+
/* was inbound connection, free 'pos' */
if (prev == NULL)
rl->addresses = pos->next;
GNUNET_SCHEDULER_cancel (pos->revalidate_task);
pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
}
- GNUNET_free_non_null(pos->ressources);
- GNUNET_free_non_null(pos->quality);
+ GNUNET_free_non_null (pos->ressources);
+ GNUNET_free_non_null (pos->quality);
+#if HAVE_LIBGLPK
+ ats_modify_problem_state (ats, ATS_MODIFIED);
+#endif
+ if (GNUNET_YES != pos->connected)
+ {
+ /* nothing else to do, connection was never up... */
+ GNUNET_free (pos);
+ return;
+ }
+ pos->connected = GNUNET_NO;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connected addresses"),
+ -1,
+ GNUNET_NO);
GNUNET_free (pos);
- ats->stat.recreate_problem = GNUNET_YES;
+
if (nl->received_pong == GNUNET_NO)
{
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to NO pong"),
+ 1,
+ GNUNET_NO);
disconnect_neighbour (nl, GNUNET_YES);
return; /* nothing to do, never connected... */
}
pos = rl->addresses;
while (pos != NULL)
{
- if (pos->validated)
+ if (GNUNET_YES == pos->validated)
{
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# try_fast_reconnect thanks to validated_address"),
+ 1,
+ GNUNET_NO);
try_fast_reconnect (p, nl);
return;
}
* if there are any addresses that work first, so as not to overdo it.
* --NE
*/
- disconnect_neighbour (nl, GNUNET_YES);
-}
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to plugin_env_session_end"),
+ 1,
+ GNUNET_NO);
+ disconnect_neighbour (nl, GNUNET_YES);
+}
/**
* provided by the plugin can be reached.
*
* @param cls closure
- * @param name name of the transport that generated the address
+ * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
* @param addr one of the addresses of the host, NULL for the last address
* the specific address format depends on the transport
* @param addrlen length of the address
- * @param expires when should this address automatically expire?
*/
static void
plugin_env_notify_address (void *cls,
- const char *name,
+ int add_remove,
const void *addr,
- uint16_t addrlen,
- struct GNUNET_TIME_Relative expires)
+ size_t addrlen)
{
struct TransportPlugin *p = cls;
struct OwnAddressList *al;
- struct GNUNET_TIME_Absolute abex;
+ struct OwnAddressList *prev;
+ GNUNET_assert (p->api != NULL);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ (add_remove == GNUNET_YES)
+ ? "Adding `%s':%s to the set of our addresses\n"
+ : "Removing `%s':%s from the set of our addresses\n",
+ a2s (p->short_name,
+ addr, addrlen),
+ p->short_name);
+#endif
GNUNET_assert (addr != NULL);
- abex = GNUNET_TIME_relative_to_absolute (expires);
- GNUNET_assert (p == find_transport (name));
- al = p->addresses;
- while (al != NULL)
+ if (GNUNET_NO == add_remove)
{
- if ( (addrlen == al->addrlen) &&
- (0 == memcmp (addr, &al[1], addrlen)) )
- {
- al->expires = abex;
- update_addresses (p, GNUNET_NO);
- return;
- }
- al = al->next;
+ prev = NULL;
+ al = p->addresses;
+ while (al != NULL)
+ {
+ if ( (addrlen == al->addrlen) &&
+ (0 == memcmp (addr, &al[1], addrlen)) )
+ {
+ if (prev == NULL)
+ p->addresses = al->next;
+ else
+ prev->next = al->next;
+ GNUNET_free (al);
+ refresh_hello ();
+ return;
+ }
+ prev = al;
+ al = al->next;
+ }
+ GNUNET_break (0);
+ return;
}
al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
al->next = p->addresses;
p->addresses = al;
- al->expires = abex;
al->addrlen = addrlen;
memcpy (&al[1], addr, addrlen);
- update_addresses (p, GNUNET_YES);
+ refresh_hello ();
}
uint32_t ats_count;
size_t size;
+ if (0 == memcmp (peer,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break (0);
+ return;
+ }
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Notifying clients about connection from `%s'\n",
+ "Notifying clients about connection with `%s'\n",
GNUNET_i2s (peer));
#endif
GNUNET_STATISTICS_update (stats,
ats_count = 2;
size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
- if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
- {
- GNUNET_break(0);
- }
+ GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
cim = GNUNET_malloc (size);
-
cim->header.size = htons (size);
cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
cim->ats_count = htonl(2);
- (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
- (&(cim->ats))[0].value = htonl (distance);
- (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
- (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
- (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
- (&(cim->ats))[2].value = htonl (0);
+ (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+ (&cim->ats)[0].value = htonl (distance);
+ (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+ (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
+ (&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), 2);
-
+ if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
+ {
+#if HAVE_LIBGLPK
+ ats_modify_problem_state(ats, ATS_MODIFIED);
+ ats_calculate_bandwidth_distribution (ats);
+#endif
+ }
cpos = clients;
while (cpos != NULL)
{
- transmit_to_client (cpos, &(cim->header), GNUNET_NO);
+ transmit_to_client (cpos, &cim->header, GNUNET_NO);
cpos = cpos->next;
}
-
GNUNET_free (cim);
}
struct DisconnectInfoMessage dim;
struct TransportClient *cpos;
+ if (0 == memcmp (peer,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break (0);
+ return;
+ }
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Notifying clients about lost connection to `%s'\n",
memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
/* notify ats about connecting peer */
- ats_notify_peer_disconnect (peer);
+ if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
+ {
+#if HAVE_LIBGLPK
+ ats_modify_problem_state(ats, ATS_MODIFIED);
+ ats_calculate_bandwidth_distribution (ats);
+#endif
+ }
cpos = clients;
while (cpos != NULL)
* @return NULL if no such entry exists
*/
static struct ForeignAddressList *
-find_peer_address(struct NeighbourList *neighbour,
+find_peer_address(struct NeighbourMapEntry *neighbour,
const char *tname,
struct Session *session,
const char *addr,
* @return NULL if we do not have a transport plugin for 'tname'
*/
static struct ForeignAddressList *
-add_peer_address (struct NeighbourList *neighbour,
+add_peer_address (struct NeighbourMapEntry *neighbour,
const char *tname,
struct Session *session,
const char *addr,
r[c].c = ressources[c].c_default;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
- GNUNET_i2s(&neighbour->peer),
+ GNUNET_i2s(&neighbour->id),
neighbour->plugins->plugin->short_name);
}
}
}
-
-/**
- * Iterator to free entries in the validation_map.
- *
- * @param cls closure (unused)
- * @param key current key code
- * @param value value in the hash map (validation to abort)
- * @return GNUNET_YES (always)
- */
-static int
-abort_validation (void *cls,
- const GNUNET_HashCode * key,
- void *value)
-{
- struct ValidationEntry *va = value;
-
- if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
- GNUNET_SCHEDULER_cancel (va->timeout_task);
- GNUNET_free (va->transport_name);
- if (va->chvc != NULL)
- {
- va->chvc->ve_count--;
- if (va->chvc->ve_count == 0)
- {
- GNUNET_CONTAINER_DLL_remove (chvc_head,
- chvc_tail,
- va->chvc);
- GNUNET_free (va->chvc);
- }
- va->chvc = NULL;
- }
- GNUNET_free (va);
- return GNUNET_YES;
-}
-
-
-/**
- * HELLO validation cleanup task (validation failed).
- *
- * @param cls the 'struct ValidationEntry' that failed
- * @param tc scheduler context (unused)
- */
-static void
-timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct ValidationEntry *va = cls;
- struct GNUNET_PeerIdentity pid;
-
- va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# address validation timeouts"),
- 1,
- GNUNET_NO);
- GNUNET_CRYPTO_hash (&va->publicKey,
- sizeof (struct
- GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
- &pid.hashPubKey);
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_remove (validation_map,
- &pid.hashPubKey,
- va));
- abort_validation (NULL, NULL, va);
-}
-
-
static void
neighbour_timeout_task (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct NeighbourList *n = cls;
+ struct NeighbourMapEntry *n = cls;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
* Add the given address to the list of foreign addresses
* available for the given peer (check for duplicates).
*
- * @param cls the respective 'struct NeighbourList' to update
+ * @param cls the respective 'struct NeighbourMapEntry' to update
* @param tname name of the transport
* @param expiration expiration time
* @param addr the address
const void *addr,
uint16_t addrlen)
{
- struct NeighbourList *n = cls;
+ struct NeighbourMapEntry *n = cls;
struct ForeignAddressList *fal;
int try;
* Add addresses in validated HELLO "h" to the set of addresses
* we have for this peer.
*
- * @param cls closure ('struct NeighbourList*')
+ * @param cls closure ('struct NeighbourMapEntry*')
* @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
const struct GNUNET_HELLO_Message *h,
const char *err_msg)
{
- struct NeighbourList *n = cls;
+ struct NeighbourMapEntry *n = cls;
if (err_msg != NULL)
{
* @param do_hello should we schedule transmitting a HELLO
* @return the new neighbour list entry
*/
-static struct NeighbourList *
+static struct NeighbourMapEntry *
setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
int do_hello)
{
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
struct TransportPlugin *tp;
struct ReadyList *rl;
+ GNUNET_assert (0 != memcmp (peer,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)));
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Setting up state for neighbour `%4s'\n",
GNUNET_i2s (peer));
#endif
- GNUNET_assert (our_hello != NULL);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# active neighbours"),
1,
GNUNET_NO);
- n = GNUNET_malloc (sizeof (struct NeighbourList));
- n->next = neighbours;
- neighbours = n;
+ n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
n->id = *peer;
n->peer_timeout =
GNUNET_TIME_relative_to_absolute
n->distance = -1;
n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
&neighbour_timeout_task, n);
+ GNUNET_CONTAINER_multihashmap_put (neighbours,
+ &n->id.hashPubKey,
+ n,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
if (do_hello)
{
GNUNET_STATISTICS_update (stats,
gettext_noop ("# HELLO's sent to new neighbors"),
1,
GNUNET_NO);
- transmit_to_peer (NULL, NULL, 0,
- HELLO_ADDRESS_EXPIRATION,
- (const char *) our_hello, GNUNET_HELLO_size(our_hello),
- GNUNET_NO, n);
+ if (NULL != our_hello)
+ transmit_to_peer (NULL, NULL, 0,
+ HELLO_ADDRESS_EXPIRATION,
+ (const char *) our_hello, GNUNET_HELLO_size(our_hello),
+ GNUNET_NO, n);
}
return n;
}
* @param n NULL if communication is not acceptable
*/
typedef void (*SetupContinuation)(void *cls,
- struct NeighbourList *n);
+ struct NeighbourMapEntry *n);
/**
/**
- * Obtain a 'struct NeighbourList' for the given peer. If such an entry
+ * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
* does not yet exist, check the blacklist. If the blacklist says creating
* one is acceptable, create one and call the continuation; otherwise
* call the continuation with NULL.
*
- * @param peer peer to setup or look up a struct NeighbourList for
+ * @param peer peer to setup or look up a struct NeighbourMapEntry for
* @param do_hello should we also schedule sending our HELLO to the peer
* if this is a new record
* @param cont function to call with the 'struct NeigbhbourList*'
SetupContinuation cont,
void *cont_cls)
{
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
struct BlacklistCheck *bc;
n = find_neighbour(peer);
* Function called with the result of querying a new blacklister about
* it being allowed (or not) to continue to talk to an existing neighbour.
*
- * @param cls the original 'struct NeighbourList'
+ * @param cls the original 'struct NeighbourMapEntry'
* @param n NULL if we need to disconnect
*/
static void
confirm_or_drop_neighbour (void *cls,
- struct NeighbourList *n)
+ struct NeighbourMapEntry *n)
{
- struct NeighbourList * orig = cls;
+ struct NeighbourMapEntry * orig = cls;
if (n == NULL)
{
"Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
"confirm_or_drop_neighboUr");
#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to blacklist"),
+ 1,
+ GNUNET_NO);
disconnect_neighbour (orig, GNUNET_NO);
}
}
+struct TestConnectionContext
+{
+ int first;
+
+ struct Blacklisters *bl;
+};
+
+
+static int
+test_connection_ok (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct TestConnectionContext *tcc = cls;
+ struct NeighbourMapEntry *n = value;
+ struct BlacklistCheck *bc;
+
+
+ bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
+ GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc->peer = n->id;
+ bc->do_hello = GNUNET_NO;
+ bc->cont = &confirm_or_drop_neighbour;
+ bc->cont_cls = n;
+ bc->bl_pos = tcc->bl;
+ if (GNUNET_YES == tcc->first)
+ {
+ /* all would wait for the same client, no need to
+ create more than just the first task right now */
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+ tcc->first = GNUNET_NO;
+ }
+ return GNUNET_OK;
+}
+
+
/**
* Handle a request to start a blacklist.
*
const struct GNUNET_MessageHeader *message)
{
struct Blacklisters *bl;
- struct BlacklistCheck *bc;
- struct NeighbourList *n;
+ struct TestConnectionContext tcc;
bl = bl_head;
while (bl != NULL)
GNUNET_SERVER_client_keep (client);
GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
/* confirm that all existing connections are OK! */
- n = neighbours;
- while (NULL != n)
- {
- bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
- GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
- bc->peer = n->id;
- bc->do_hello = GNUNET_NO;
- bc->cont = &confirm_or_drop_neighbour;
- bc->cont_cls = n;
- bc->bl_pos = bl;
- if (n == neighbours) /* all would wait for the same client, no need to
- create more than just the first task right now */
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
- bc);
- n = n->next;
- }
+ tcc.bl = bl;
+ tcc.first = GNUNET_YES;
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &test_connection_ok,
+ &tcc);
}
struct ForeignAddressList *peer_address = cls;
struct TransportPlugin *tp;
struct ValidationEntry *va;
- struct NeighbourList *neighbour;
+ struct NeighbourMapEntry *neighbour;
struct TransportPingMessage ping;
struct CheckAddressExistsClosure caec;
char * message_buf;
peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
return;
+ GNUNET_assert (peer_address != NULL);
tp = peer_address->ready_list->plugin;
neighbour = peer_address->ready_list->neighbour;
if (GNUNET_YES != neighbour->public_key_valid)
caec.tname = tp->short_name;
caec.session = peer_address->session;
caec.exists = GNUNET_NO;
+
GNUNET_CONTAINER_multihashmap_iterate (validation_map,
&check_address_exists,
&caec);
HELLO_VERIFICATION_TIMEOUT,
message_buf, tsize,
GNUNET_YES, neighbour);
- GNUNET_free(message_buf);
+ GNUNET_free (message_buf);
schedule_next_ping (peer_address);
}
struct GNUNET_TIME_Relative delay;
if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
- return;
+ {
+ GNUNET_SCHEDULER_cancel(fal->revalidate_task);
+ fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+ }
delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
delay.rel_value /= 2; /* do before expiration */
delay = GNUNET_TIME_relative_min (delay,
delay = GNUNET_TIME_UNIT_ZERO;
fal->estimated = GNUNET_YES;
}
+
if (GNUNET_YES == fal->connected)
{
delay = GNUNET_TIME_relative_min (delay,
GNUNET_TIME_UNIT_SECONDS);
/* randomize a bit (to avoid doing all at the same time) */
delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
+
+ GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
&send_periodic_ping,
fal);
*/
static void
handle_payload_message (const struct GNUNET_MessageHeader *message,
- struct NeighbourList *n)
+ struct NeighbourMapEntry *n)
{
struct InboundMessage *im;
struct TransportClient *cpos;
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
+ "Received message of type %u and size %u from `%4s', but no pong yet!\n",
ntohs (message->type),
ntohs (message->size),
GNUNET_i2s (&n->id));
unsigned int challenge = ntohl(pong->challenge);
struct GNUNET_HELLO_Message *hello;
struct GNUNET_PeerIdentity target;
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
struct ForeignAddressList *fal;
struct OwnAddressList *oal;
struct TransportPlugin *tp;
&my_identity,
sizeof (struct GNUNET_PeerIdentity)))
{
- char * peer;
+ char * peer;
+
GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
if (oal == NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
+ _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
+ GNUNET_i2s (&pong->pid),
a2s (ve->transport_name,
&addr[slen],
alen));
+ /* FIXME: since the sender of the PONG currently uses the
+ wrong address (see FIMXE there!), we cannot run a
+ proper check here... */
+#if FIXME_URGENT
return GNUNET_NO;
+#endif
}
if (GNUNET_OK !=
GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
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))
{
const char *sender_address,
size_t sender_address_len)
{
+ if (0 == memcmp (peer,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* PONG send to self, ignore */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Receiving `%s' message from myself\n",
+ "PONG");
+ return;
+ }
#if DEBUG_TRANSPORT > 1
/* we get tons of these that just get discarded, only log
if we are quite verbose */
*/
static void
transmit_hello_and_ping (void *cls,
- struct NeighbourList *neighbour)
+ struct NeighbourMapEntry *neighbour)
{
struct ValidationEntry *va = cls;
struct ForeignAddressList *peer_address;
abort_validation (NULL, NULL, va);
return;
}
+ if (NULL == our_hello)
+ refresh_hello_task (NULL, NULL);
hello_size = GNUNET_HELLO_size(our_hello);
slen = strlen(va->transport_name) + 1;
tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
HELLO_VERIFICATION_TIMEOUT,
message_buf, tsize,
GNUNET_YES, neighbour);
- GNUNET_free(message_buf);
+ GNUNET_free (message_buf);
}
struct GNUNET_HELLO_Message *plain_hello;
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
struct GNUNET_PeerIdentity target;
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
if (err_msg != NULL)
{
const struct GNUNET_HELLO_Message *hello;
struct CheckHelloValidatedContext *chvc;
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
+ struct NeighbourMapEntry *n;
#if DEBUG_TRANSPORT_HELLO > 2
char *my_id;
#endif
+
hsize = ntohs (message->size);
if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
(hsize < sizeof (struct GNUNET_MessageHeader)))
1,
GNUNET_NO);
- /* first, check if load is too high */
- if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# HELLOs ignored due to high load"),
- 1,
- GNUNET_NO);
-#if DEBUG_TRANSPORT_HELLO
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Ignoring `%s' for `%4s', load too high.\n",
- "HELLO",
- GNUNET_i2s (&target));
-#endif
- return GNUNET_OK;
- }
hello = (const struct GNUNET_HELLO_Message *) message;
if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
-
GNUNET_CRYPTO_hash (&publicKey,
sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
&target.hashPubKey);
"HELLO",
GNUNET_i2s (&target));
#endif
-
if (0 == memcmp (&my_identity,
&target,
sizeof (struct GNUNET_PeerIdentity)))
GNUNET_NO);
return GNUNET_OK;
}
+ n = find_neighbour (&target);
+ if ( (NULL != n) &&
+ (! n->public_key_valid) )
+ {
+ GNUNET_HELLO_get_key (hello, &n->publicKey);
+ n->public_key_valid = GNUNET_YES;
+ }
+
+ /* check if load is too high before doing expensive stuff */
+ if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# HELLOs ignored due to high load"),
+ 1,
+ GNUNET_NO);
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring `%s' for `%4s', load too high.\n",
+ "HELLO",
+ GNUNET_i2s (&target));
+#endif
+ return GNUNET_OK;
+ }
+
+
chvc = chvc_head;
while (NULL != chvc)
{
#endif
return GNUNET_OK; /* validation already pending */
}
- if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
+ if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
GNUNET_break (0 != memcmp (hello, chvc->hello,
GNUNET_HELLO_size(hello)));
chvc = chvc->next;
}
#if BREAK_TESTS
- struct NeighbourList *temp_neighbor = find_neighbour(&target);
+ struct NeighbourMapEntry *temp_neighbor = find_neighbour(&target);
if ((NULL != temp_neighbor))
{
fprintf(stderr, "Already know peer, ignoring hello\n");
#if DEBUG_TRANSPORT_HELLO > 2
if (plugin != NULL)
{
- my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
#if DEBUG_TRANSPORT
+ my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
my_id,
GNUNET_i2s (&target),
plugin->short_name,
GNUNET_HELLO_size(hello));
+ GNUNET_free (my_id);
#endif
- GNUNET_free(my_id);
}
#endif
chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
* regardless of whether other addresses exist.
*/
static void
-disconnect_neighbour (struct NeighbourList *n, int check)
+disconnect_neighbour (struct NeighbourMapEntry *n, int check)
{
struct ReadyList *rpos;
- struct NeighbourList *npos;
- struct NeighbourList *nprev;
struct MessageQueue *mq;
struct ForeignAddressList *peer_addresses;
struct ForeignAddressList *peer_pos;
+ if (GNUNET_YES == n->in_disconnect)
+ return;
if (GNUNET_YES == check)
{
rpos = n->plugins;
peer_addresses = rpos->addresses;
while (peer_addresses != NULL)
{
- // Do not disconnect if: an address is connected or an inbound address exists
+ /* Do not disconnect if: an address is connected or an inbound address exists */
if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "NOT Disconnecting from `%4s', still have live addresses!\n",
- GNUNET_i2s (&n->id));
+ "NOT Disconnecting from `%4s', still have live address `%s'!\n",
+ GNUNET_i2s (&n->id),
+ a2s (peer_addresses->ready_list->plugin->short_name,
+ peer_addresses->addr,
+ peer_addresses->addrlen));
#endif
return; /* still connected */
}
"Disconnecting from `%4s'\n",
GNUNET_i2s (&n->id));
#endif
- /* remove n from neighbours list */
- nprev = NULL;
- npos = neighbours;
- while ((npos != NULL) && (npos != n))
- {
- nprev = npos;
- npos = npos->next;
- }
- GNUNET_assert (npos != NULL);
- if (nprev == NULL)
- neighbours = n->next;
- else
- nprev->next = n->next;
+ n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
/* notify all clients about disconnect */
if (GNUNET_YES == n->received_pong)
- notify_clients_disconnect (&n->id);
-
+ {
+ n->received_pong = GNUNET_NO;
+ notify_clients_disconnect (&n->id);
+ }
+#if HAVE_LIBGLPK
+ ats_modify_problem_state(ats, ATS_MODIFIED);
+#endif
/* clean up all plugins, cancel connections and pending transmissions */
while (NULL != (rpos = n->plugins))
{
peer_pos = rpos->addresses;
rpos->addresses = peer_pos->next;
if (peer_pos->connected == GNUNET_YES)
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# connected addresses"),
- -1,
- GNUNET_NO);
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connected addresses"),
+ -1,
+ GNUNET_NO);
+ peer_pos->connected = GNUNET_NO;
+ }
if (GNUNET_YES == peer_pos->validated)
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peer addresses considered valid"),
GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
}
- GNUNET_free(peer_pos->ressources);
+ GNUNET_free (peer_pos->ressources);
peer_pos->ressources = NULL;
- GNUNET_free(peer_pos->quality);
+ GNUNET_free (peer_pos->quality);
peer_pos->ressources = NULL;
- GNUNET_free(peer_pos);
- ats->stat.recreate_problem = GNUNET_YES;
+ GNUNET_free (peer_pos);
}
GNUNET_free (rpos);
}
sizeof(struct GNUNET_PeerIdentity)));
GNUNET_free (mq);
}
+
+ while (NULL != (mq = n->cont_head))
+ {
+
+ GNUNET_CONTAINER_DLL_remove (n->cont_head,
+ n->cont_tail,
+ mq);
+ GNUNET_assert (0 == memcmp(&mq->neighbour_id,
+ &n->id,
+ sizeof(struct GNUNET_PeerIdentity)));
+ GNUNET_free (mq);
+ }
+
if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
{
GNUNET_SCHEDULER_cancel (n->timeout_task);
GNUNET_NO);
n->piter = NULL;
}
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (neighbours,
+ &n->id.hashPubKey,
+ n));
/* finally, free n itself */
GNUNET_STATISTICS_update (stats,
gettext_noop ("# active neighbours"),
* in response to the peer by any means necessary.
*/
static int
-handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
- const struct GNUNET_PeerIdentity *peer,
- struct Session *session,
- const char *sender_address,
- uint16_t sender_address_len)
+handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ struct Session *session,
+ const char *sender_address,
+ uint16_t sender_address_len)
{
struct TransportPlugin *plugin = cls;
struct SessionHeader *session_header = (struct SessionHeader*) session;
struct TransportPingMessage *ping;
struct TransportPongMessage *pong;
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
struct ReadyList *rl;
struct ForeignAddressList *fal;
struct OwnAddressList *oal;
const char *addr;
size_t alen;
size_t slen;
+ int did_pong;
if (ntohs (message->size) < sizeof (struct TransportPingMessage))
{
GNUNET_i2s (peer));
return GNUNET_SYSERR;
}
+ /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
+ 1) it is NULL when we need to have a real value
+ 2) it is documented to be the address of the sender (source-IP), where
+ what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
+ have...
+ */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
+ a2s (plugin->short_name,
+ sender_address,
+ sender_address_len),
+ GNUNET_i2s (peer));
+
pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Creating PONG signature to indicate ownership.\n");
#endif
- oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
- GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+ oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_rsa_sign (my_private_key,
}
n = find_neighbour(peer);
GNUNET_assert (n != NULL);
+ did_pong = GNUNET_NO;
/* first try reliable response transmission */
rl = n->plugins;
while (rl != NULL)
GNUNET_SYSERR,
NULL, NULL))
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitted PONG to `%s' via reliable mechanism\n",
+ GNUNET_i2s (peer));
/* done! */
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PONGs unicast via reliable transport"),
GNUNET_free (pong);
return GNUNET_OK;
}
+ did_pong = GNUNET_YES;
fal = fal->next;
}
rl = rl->next;
fal = rl->addresses;
while (fal != NULL)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
+ GNUNET_i2s (peer),
+ a2s (rl->plugin->short_name,
+ fal->addr,
+ fal->addrlen),
+ rl->plugin->short_name);
transmit_to_peer(NULL, fal,
TRANSPORT_PONG_PRIORITY,
HELLO_VERIFICATION_TIMEOUT,
ntohs(pong->header.size),
GNUNET_YES,
n);
+ did_pong = GNUNET_YES;
fal = fal->next;
}
rl = rl->next;
}
GNUNET_free(pong);
+ if (GNUNET_YES != did_pong)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not send PONG to `%s': no address available\n"),
+ GNUNET_i2s (peer));
return GNUNET_OK;
}
-
-
-
/**
- * Function called by the plugin for each received message.
- * Update data volumes, possibly notify plugins about
- * reducing the rate at which they read from the socket
- * and generally forward to our receive callback.
+ * Function called by the plugin for each received message. Update
+ * data volumes, possibly notify plugins about reducing the rate at
+ * which they read from the socket and generally forward to our
+ * receive callback.
*
* @param cls the "struct TransportPlugin *" we gave to the plugin
* @param peer (claimed) identity of the other peer
struct ReadyList *service_context;
struct ForeignAddressList *peer_address;
uint16_t msize;
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
struct GNUNET_TIME_Relative ret;
- if (is_blacklisted (peer, plugin))
- return GNUNET_TIME_UNIT_FOREVER_REL;
uint32_t distance;
int c;
+ if (0 == memcmp (peer,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* refuse to receive from myself */
+ GNUNET_break (0);
+ return GNUNET_TIME_UNIT_FOREVER_REL;
+ }
+ if (is_blacklisted (peer, plugin))
+ return GNUNET_TIME_UNIT_FOREVER_REL;
n = find_neighbour (peer);
if (n == NULL)
n = setup_new_neighbour (peer, GNUNET_YES);
distance = 1;
for (c=0; c<ats_count; c++)
- {
- if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
- {
- distance = ntohl(ats_data[c].value);
- }
- }
-
- /* notify ATS about incoming data */
- //ats_notify_ats_data(peer, ats_data);
+ if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
+ distance = ntohl(ats_data[c].value);
if (message != NULL)
sender_address_len);
if (peer_address != NULL)
{
-
- update_addr_ats(peer_address, ats_data, ats_count);
- update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
-
- peer_address->distance = distance;
+ update_addr_ats(peer_address, ats_data, ats_count);
+ update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+
+ peer_address->distance = distance;
if (GNUNET_YES == peer_address->validated)
+ {
mark_address_connected (peer_address);
+ schedule_next_ping (peer_address);
+ }
+ else
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "New address is unvalidated, trying to validate it now\n");
+#endif
+ if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
+ peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
+
+ }
peer_address->timeout
- =
- GNUNET_TIME_relative_to_absolute
- (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
- schedule_next_ping (peer_address);
+ = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
}
/* update traffic received amount ... */
msize = ntohs (message->size);
}
if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
(ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
- {
+ {
+#if HAVE_LIBGLPK
uint32_t value = ntohl(*((uint32_t *) &message[1]));
//GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
/* Force ressource and quality update */
- if (value == 4)
- {
- ats->stat.modified_resources = GNUNET_YES;
- ats->stat.modified_quality = GNUNET_YES;
- }
+ if ((value == 4) && (ats != NULL))
+ ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
/* Force cost update */
- if (value == 3)
- ats->stat.modified_resources = GNUNET_YES;
+ if ((value == 3) && (ats != NULL))
+ ats_modify_problem_state(ats, ATS_COST_UPDATED);
/* Force quality update */
- if (value == 2)
- ats->stat.modified_quality = GNUNET_YES;
+ if ((value == 2) && (ats != NULL))
+ ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
/* Force full rebuild */
- if (value == 1)
- ats->stat.recreate_problem = GNUNET_YES;
- }
-
+ if ((value == 1) && (ats != NULL))
+ ats_modify_problem_state(ats, ATS_MODIFIED);
+#endif
+ }
+
#if DEBUG_PING_PONG
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received message of type %u and size %u from `%4s', sending to all clients.\n",
- ntohs (message->type),
- ntohs (message->size),
- GNUNET_i2s (peer));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received message of type %u and size %u from `%4s', sending to all clients.\n",
+ ntohs (message->type),
+ ntohs (message->size),
+ GNUNET_i2s (peer));
#endif
switch (ntohs (message->type))
{
break;
case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
+ if (GNUNET_YES != n->received_pong)
+ transmit_plain_ping (n);
break;
case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
handle_pong (plugin, message, peer, sender_address, sender_address_len);
ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
if (ret.rel_value > 0)
{
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
+ "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
(unsigned long long) n->in_tracker.consumption_since_last_update__,
(unsigned int) n->in_tracker.available_bytes_per_s__,
(unsigned long long) ret.rel_value);
return ret;
}
+
+static int
+notify_client_about_neighbour (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct TransportClient *c = cls;
+ struct NeighbourMapEntry *n = value;
+ struct ConnectInfoMessage * cim;
+ uint32_t ats_count;
+ size_t size;
+
+ if (GNUNET_YES != n->received_pong)
+ return GNUNET_OK;
+
+ ats_count = 2;
+ size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ cim = GNUNET_malloc (size);
+ cim->header.size = htons (size);
+ cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
+ cim->ats_count = htonl(ats_count);
+ (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ (&(cim->ats))[2].value = htonl (0);
+ if (GNUNET_YES == n->received_pong)
+ {
+ (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+ (&cim->ats)[0].value = htonl (n->distance);
+ (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+ (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
+ cim->id = n->id;
+ transmit_to_client (c, &cim->header, GNUNET_NO);
+ }
+ GNUNET_free (cim);
+ return GNUNET_OK;
+}
+
+
/**
* Handle START-message. This is the first message sent to us
* by any client which causes us to add it to our list.
{
const struct StartMessage *start;
struct TransportClient *c;
- struct ConnectInfoMessage * cim;
- struct NeighbourList *n;
- uint32_t ats_count;
- size_t size;
start = (const struct StartMessage*) message;
#if DEBUG_TRANSPORT
clients = c;
c->client = client;
if (our_hello != NULL)
- {
+ {
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending our own `%s' to new client\n", "HELLO");
(const struct GNUNET_MessageHeader *) our_hello,
GNUNET_NO);
/* tell new client about all existing connections */
- ats_count = 2;
- size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
- if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
- {
- GNUNET_break(0);
- }
- cim = GNUNET_malloc (size);
- cim->header.size = htons (size);
- cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
- cim->ats_count = htonl(ats_count);
- (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
- (&(cim->ats))[2].value = htonl (0);
- n = neighbours;
- while (n != NULL)
- {
- if (GNUNET_YES == n->received_pong)
- {
- (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
- (&(cim->ats))[0].value = htonl (n->distance);
- (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
- (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
- cim->id = n->id;
- transmit_to_client (c, &cim->header, GNUNET_NO);
- }
- n = n->next;
- }
- GNUNET_free (cim);
- }
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ ¬ify_client_about_neighbour,
+ c);
+ }
+ else
+ {
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No HELLO created yet, will transmit HELLO to client later!\n");
+#endif
+ refresh_hello ();
+ }
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
*/
static void
transmit_client_message (void *cls,
- struct NeighbourList *n)
+ struct NeighbourMapEntry *n)
{
struct TransmitClientMessageContext *tcmc = cls;
struct TransportClient *tc;
{
const struct QuotaSetMessage *qsm =
(const struct QuotaSetMessage *) message;
- struct NeighbourList *n;
+ struct NeighbourMapEntry *n;
GNUNET_STATISTICS_update (stats,
gettext_noop ("# SET QUOTA messages received"),
GNUNET_NO);
return;
}
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
"SET_QUOTA",
"Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
"SET_QUOTA");
#endif
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# disconnects due to quota of 0"),
+ 1,
+ GNUNET_NO);
disconnect_neighbour (n, GNUNET_NO);
}
GNUNET_SERVER_receive_done (client, GNUNET_OK);
struct GNUNET_SERVER_TransmitContext *tc = cls;
size_t slen;
- if (NULL == address)
- slen = 0;
+ if (NULL != address)
+ {
+ slen = strlen (address) + 1;
+ GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+ }
else
- slen = strlen (address) + 1;
-
- GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
- GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
- if (NULL == address)
- GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+ {
+ GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+ }
}
const char *address;
uint16_t size;
struct GNUNET_SERVER_TransmitContext *tc;
- struct GNUNET_TIME_Absolute timeout;
struct GNUNET_TIME_Relative rtimeout;
int32_t numeric;
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
- rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
+ rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
numeric = ntohl (alum->numeric_only);
lsPlugin = find_transport (nameTransport);
if (NULL == lsPlugin)
GNUNET_SERVER_transmit_context_run (tc, rtimeout);
return;
}
+ GNUNET_SERVER_disable_receive_done_warning (client);
tc = GNUNET_SERVER_transmit_context_create (client);
lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
nameTransport,
&transmit_address_to_client, tc);
}
+/**
+ * Handle PeerAddressLookupMessage.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_peer_address_lookup (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct PeerAddressLookupMessage *peer_address_lookup;
+ struct NeighbourMapEntry *neighbor_iterator;
+ struct ReadyList *ready_iterator;
+ struct ForeignAddressList *foreign_address_iterator;
+ struct TransportPlugin *transport_plugin;
+
+ uint16_t size;
+ struct GNUNET_SERVER_TransmitContext *tc;
+ struct GNUNET_TIME_Relative rtimeout;
+ char *addr_buf;
+
+ size = ntohs (message->size);
+ if (size < sizeof (struct PeerAddressLookupMessage))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
+
+ rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
+
+ neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
+
+ /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
+ if (neighbor_iterator == NULL)
+ {
+ GNUNET_break(0);
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+ GNUNET_SERVER_transmit_context_run (tc, rtimeout);
+ return;
+ }
+
+ ready_iterator = neighbor_iterator->plugins;
+ GNUNET_SERVER_disable_receive_done_warning (client);
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ while(ready_iterator != NULL)
+ {
+ foreign_address_iterator = ready_iterator->addresses;
+ while (foreign_address_iterator != NULL)
+ {
+ transport_plugin = foreign_address_iterator->ready_list->plugin;
+ if (foreign_address_iterator->addr != NULL)
+ {
+ GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
+ a2s (transport_plugin->short_name,
+ foreign_address_iterator->addr,
+ foreign_address_iterator->addrlen),
+ (foreign_address_iterator->connected
+ == GNUNET_YES) ? "CONNECTED"
+ : "DISCONNECTED",
+ (foreign_address_iterator->validated
+ == GNUNET_YES) ? "VALIDATED"
+ : "UNVALIDATED");
+ transmit_address_to_client(tc, addr_buf);
+ GNUNET_free (addr_buf);
+ }
+ else if (foreign_address_iterator->addrlen == 0)
+ {
+ GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
+ (foreign_address_iterator->connected
+ == GNUNET_YES) ? "CONNECTED"
+ : "DISCONNECTED",
+ (foreign_address_iterator->validated
+ == GNUNET_YES) ? "VALIDATED"
+ : "UNVALIDATED");
+ transmit_address_to_client (tc, addr_buf);
+ GNUNET_free (addr_buf);
+ }
+
+ foreign_address_iterator = foreign_address_iterator->next;
+ }
+ ready_iterator = ready_iterator->next;
+ }
+ GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+
+static int
+output_addresses (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct GNUNET_SERVER_TransmitContext *tc = cls;
+ struct NeighbourMapEntry *neighbor_iterator = value;
+ struct ForeignAddressList *foreign_address_iterator;
+ struct TransportPlugin *transport_plugin;
+ struct ReadyList *ready_iterator;
+ char *addr_buf;
+
+ ready_iterator = neighbor_iterator->plugins;
+ while (ready_iterator != NULL)
+ {
+ foreign_address_iterator = ready_iterator->addresses;
+ while (foreign_address_iterator != NULL)
+ {
+ transport_plugin = foreign_address_iterator->ready_list->plugin;
+ if (foreign_address_iterator->addr != NULL)
+ {
+ GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
+ GNUNET_i2s(&neighbor_iterator->id),
+ a2s (transport_plugin->short_name,
+ foreign_address_iterator->addr,
+ foreign_address_iterator->addrlen),
+ (foreign_address_iterator->connected
+ == GNUNET_YES) ? "CONNECTED"
+ : "DISCONNECTED",
+ (foreign_address_iterator->validated
+ == GNUNET_YES) ? "VALIDATED"
+ : "UNVALIDATED");
+ transmit_address_to_client (tc, addr_buf);
+ GNUNET_free (addr_buf);
+ }
+ else if (foreign_address_iterator->addrlen == 0)
+ {
+ GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
+ GNUNET_i2s (&neighbor_iterator->id),
+ "<inbound>",
+ (foreign_address_iterator->connected
+ == GNUNET_YES) ? "CONNECTED"
+ : "DISCONNECTED",
+ (foreign_address_iterator->validated
+ == GNUNET_YES) ? "VALIDATED"
+ : "UNVALIDATED");
+ transmit_address_to_client (tc, addr_buf);
+ GNUNET_free (addr_buf);
+ }
+
+ foreign_address_iterator = foreign_address_iterator->next;
+ }
+ ready_iterator = ready_iterator->next;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle AddressIterateMessage
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_address_iterate (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_SERVER_TransmitContext *tc;
+ uint16_t size;
+
+ size = ntohs (message->size);
+ if (size < sizeof (struct AddressIterateMessage))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_SERVER_disable_receive_done_warning (client);
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &output_addresses,
+ tc);
+ GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+static const struct GNUNET_MessageHeader *
+do_get_our_hello ()
+{
+ return (const struct GNUNET_MessageHeader*) our_hello;
+}
+
/**
* Setup the environment for this plugin.
{
plug->env.cfg = cfg;
plug->env.my_identity = &my_identity;
- plug->env.our_hello = &our_hello;
+ plug->env.get_our_hello = &do_get_our_hello;
plug->env.cls = plug;
plug->env.receive = &plugin_env_receive;
plug->env.notify_address = &plugin_env_notify_address;
}
+static int
+null_mq_client_pointers (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct TransportClient *pos = cls;
+ struct NeighbourMapEntry *n = value;
+ struct MessageQueue *mq;
+
+ for (mq = n->messages_head; mq != NULL; mq = mq->next)
+ {
+ if (mq->client == pos)
+ mq->client = NULL; /* do not use anymore! */
+ }
+ return GNUNET_OK;
+}
+
+
/**
* Called whenever a client is disconnected. Frees our
* resources associated with that client.
pos->message_count--;
GNUNET_free (mqe);
}
+ if (NULL != neighbours)
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &null_mq_client_pointers,
+ pos);
if (prev == NULL)
clients = pos->next;
else
}
+static int
+disconnect_all_neighbours (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct NeighbourMapEntry *n = value;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting peer `%4s', %s\n",
+ GNUNET_i2s(&n->id),
+ "SHUTDOWN_TASK");
+#endif
+ disconnect_neighbour (n, GNUNET_NO);
+ return GNUNET_OK;
+}
+
+
/**
* Function called when the service shuts down. Unloads our plugins
* and cancels pending validations.
struct OwnAddressList *al;
struct CheckHelloValidatedContext *chvc;
- while (neighbours != NULL)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
- "SHUTDOWN_TASK");
-#endif
- disconnect_neighbour (neighbours, GNUNET_NO);
- }
+ shutdown_in_progress = GNUNET_YES;
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &disconnect_all_neighbours,
+ NULL);
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Transport service is unloading plugins...\n");
#endif
while (NULL != (plug = plugins))
{
- plugins = plug->next;
if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
{
GNUNET_SCHEDULER_cancel (plug->address_update_task);
plug->addresses = al->next;
GNUNET_free (al);
}
+ plugins = plug->next;
GNUNET_free (plug);
}
if (my_private_key != NULL)
GNUNET_CONTAINER_multihashmap_destroy (validation_map);
validation_map = NULL;
- ats_shutdown(ats);
+
+ if (ats_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(ats_task);
+ ats_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+#if HAVE_LIBGLPK
+ if (ats != NULL)
+ ats_shutdown (ats);
+#endif
/* free 'chvc' data structure */
while (NULL != (chvc = chvc_head))
GNUNET_PEERINFO_disconnect (peerinfo);
peerinfo = NULL;
}
+ if (GNUNET_SCHEDULER_NO_TASK != hello_task)
+ {
+ GNUNET_SCHEDULER_cancel (hello_task);
+ hello_task = GNUNET_SCHEDULER_NO_TASK;
+ }
/* Can we assume those are gone by now, or do we need to clean up
explicitly!? */
GNUNET_break (bl_head == NULL);
GNUNET_break (bc_head == NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+ neighbours = NULL;
}
-#if HAVE_LIBGLPK
-static int ats_evaluate_results (int result, int solution, char * problem)
-{
- int cont = GNUNET_NO;
- int error_kind = GNUNET_ERROR_TYPE_DEBUG;
-#if DEBUG_ATS
- error_kind = GNUNET_ERROR_TYPE_ERROR;
-#endif
-
- switch (result) {
- case GLP_ESTOP : /* search terminated by application */
- GNUNET_log (error_kind, "%s , Search terminated by application\n", problem);
- break;
- case GLP_EITLIM : /* iteration limit exceeded */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Iteration limit exceeded\n", problem);
- break;
- break;
- case GLP_ETMLIM : /* time limit exceeded */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Time limit exceeded\n", problem);
- break;
- case GLP_ENOPFS : /* no primal feasible solution */
- case GLP_ENODFS : /* no dual feasible solution */
- GNUNET_log (error_kind, "%s No feasible solution\n", problem);
- break;
-
- case GLP_EBADB : /* invalid basis */
- case GLP_ESING : /* singular matrix */
- case GLP_ECOND : /* ill-conditioned matrix */
- case GLP_EBOUND : /* invalid bounds */
- case GLP_EFAIL : /* solver failed */
- case GLP_EOBJLL : /* objective lower limit reached */
- case GLP_EOBJUL : /* objective upper limit reached */
- case GLP_EROOT : /* root LP optimum not provided */
- GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
- break;
-
- case 0:
- GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
- break;
- }
- switch (solution) {
- case GLP_UNDEF:
- GNUNET_log (error_kind, "%s solution is undefined\n", problem);
- break;
- case GLP_OPT:
- GNUNET_log (error_kind, "%s solution is optimal\n", problem);
- cont=GNUNET_YES;
- break;
- case GLP_FEAS:
- GNUNET_log (error_kind, "%s solution is %s feasible, however, its optimality (or non-optimality) has not been proven, \n", problem, (0==strcmp(problem,"LP")?"":"integer"));
- cont=GNUNET_YES;
- break;
- case GLP_NOFEAS:
- GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem, (0==strcmp(problem,"LP")?"":"integer "));
- break;
- case GLP_INFEAS:
- GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
- break;
- case GLP_UNBND:
- GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
- default:
- break;
- }
-return cont;
+void ats_result_cb ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "ATS Result callback\n");
}
-static void ats_solve_problem (unsigned int max_it, unsigned int max_dur, unsigned int c_peers, unsigned int c_mechs, struct ATS_stat *stat)
-{
- int result;
- int lp_solution;
- int mlp_solution;
- // Solving simplex
+#if HAVE_LIBGLPK
+struct AtsBuildContext
+{
+ struct ATS_mechanism * mechanisms;
+ struct ATS_peer *peers;
+ int c_peers;
+ int c_mechs;
+};
- glp_smcp opt_lp;
- glp_init_smcp(&opt_lp);
-#if VERBOSE_ATS
- opt_lp.msg_lev = GLP_MSG_ALL;
-#else
- opt_lp.msg_lev = GLP_MSG_OFF;
-#endif
- // setting iteration limit
- opt_lp.it_lim = max_it;
- // maximum duration
- opt_lp.tm_lim = max_dur;
+static int
+find_and_count_addresses (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct AtsBuildContext *abc = cls;
+ struct NeighbourMapEntry *next = value;
+ int found_addresses = GNUNET_NO;
+
+ struct ReadyList *r_next = next->plugins;
+ while (r_next != NULL)
+ {
+ struct ForeignAddressList * a_next = r_next->addresses;
+ while (a_next != NULL)
+ {
+ abc->c_mechs++;
+ found_addresses = GNUNET_YES;
+ a_next = a_next->next;
+ }
+ r_next = r_next->next;
+ }
+ if (found_addresses)
+ abc->c_peers++;
+ return GNUNET_OK;
+}
- if (ats->stat.recreate_problem == GNUNET_YES)
- opt_lp.presolve = GLP_ON;
- result = glp_simplex(ats->prob, &opt_lp);
- lp_solution = glp_get_status (ats->prob);
- if ((result == GLP_ETMLIM) || (result == GLP_ETMLIM))
- {
- ats->stat.valid = GNUNET_NO;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ATS exceeded time or iteration limit!\n");
- return;
- }
+static int
+setup_ats_problem (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ struct AtsBuildContext *abc = cls;
+ struct NeighbourMapEntry *next = value;
- if (ats_evaluate_results(result, lp_solution, "LP") == GNUNET_YES)
+ int found_addresses = GNUNET_NO;
+ struct ReadyList *r_next = next->plugins;
+ while (r_next != NULL)
+ {
+ struct ForeignAddressList * a_next = r_next->addresses;
+ while (a_next != NULL)
{
- stat->valid = GNUNET_YES;
+ if (found_addresses == GNUNET_NO)
+ {
+ abc->peers[abc->c_peers].peer = next->id;
+ abc->peers[abc->c_peers].m_head = NULL;
+ abc->peers[abc->c_peers].m_tail = NULL;
+ abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
+ }
+ abc->mechanisms[abc->c_mechs].addr = a_next;
+ abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
+ abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
+ abc->mechanisms[abc->c_mechs].next = NULL;
+ abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
+ abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
+ abc->mechanisms[abc->c_mechs].quality = a_next->quality;
+ GNUNET_CONTAINER_DLL_insert_tail(abc->peers[abc->c_peers].m_head,
+ abc->peers[abc->c_peers].m_tail,
+ &abc->mechanisms[abc->c_mechs]);
+ found_addresses = GNUNET_YES;
+ abc->c_mechs++;
+ a_next = a_next->next;
}
- else
- {
- ats->stat.simplex_rerun_required = GNUNET_YES;
- opt_lp.presolve = GLP_ON;
- result = glp_simplex(ats->prob, &opt_lp);
- lp_solution = glp_get_status (ats->prob);
+ r_next = r_next->next;
+ }
+ if (found_addresses == GNUNET_YES)
+ abc->c_peers++;
+ return GNUNET_OK;
+}
- // TODO: Remove if this does not appear until release
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "EXECUTED SIMPLEX WITH PRESOLVER! %i \n", lp_solution);
- if (ats_evaluate_results(result, lp_solution, "LP") != GNUNET_YES)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "After execution simplex with presolver: STILL INVALID!\n");
- char * filename;
- GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.mlp",ats->stat.c_peers, ats->stat.c_mechs, GNUNET_TIME_absolute_get().abs_value);
- glp_write_lp (ats->prob, NULL, filename);
- GNUNET_free (filename);
- stat->valid = GNUNET_NO;
- ats->stat.recreate_problem = GNUNET_YES;
- return;
- }
- stat->valid = GNUNET_YES;
- }
+static void
+create_ats_information ( struct ATS_peer **p,
+ int * c_p,
+ struct ATS_mechanism ** m,
+ int * c_m )
+{
+ struct AtsBuildContext abc;
- // Solving mlp
- glp_iocp opt_mlp;
- glp_init_iocp(&opt_mlp);
- // maximum duration
- opt_mlp.tm_lim = max_dur;
- // output level
#if VERBOSE_ATS
- opt_mlp.msg_lev = GLP_MSG_ALL;
-#else
- opt_mlp.msg_lev = GLP_MSG_OFF;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "ATS requires clean address information\n");
#endif
-
- result = glp_intopt (ats->prob, &opt_mlp);
- mlp_solution = glp_mip_status (ats->prob);
- stat->solution = mlp_solution;
-
- if (ats_evaluate_results(result, mlp_solution, "MLP") == GNUNET_YES)
- {
- stat->valid = GNUNET_YES;
- }
- else
- {
- // TODO: Remove if this does not appear until release
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP SOLUTION INVALID: %i\n", lp_solution);
- stat->valid = GNUNET_NO;
- }
-
-/*
- int check;
- int error = GNUNET_NO;
- double bw;
- struct ATS_mechanism *t = NULL;
- for (c=1; c<= (c_peers); c++ )
- {
- check = GNUNET_NO;
- t = peers[c].m_head;
- while (t!=NULL)
- {
- bw = glp_get_col_prim(prob, t->col_index);
- if (bw > 1.0)
- {
+ abc.c_peers = 0;
+ abc.c_mechs = 0;
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &find_and_count_addresses,
+ &abc);
#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[%i][%i] `%s' %s %s %f\n", c, t->col_index, GNUNET_h2s(&peers[c].peer.hashPubKey), t->plugin->short_name, glp_get_col_name(prob,t->col_index), bw);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
#endif
- if (check ==GNUNET_YES)
- {
- glp_write_sol(prob, "invalid_solution.mlp");
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
- GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
- error = GNUNET_YES;
- }
- if (check ==GNUNET_NO)
- check = GNUNET_YES;
- }
- t = t->next;
- }
- }*/
-#if VERBOSE_ATS
- if (glp_get_col_prim(ats->prob,2*c_mechs+1) != 1)
- {
- int c;
- for (c=1; c<= available_quality_metrics; c++ )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+3+c), glp_get_col_prim(ats->prob,2*c_mechs+3+c));
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+1), glp_get_col_prim(ats->prob,2*c_mechs+1));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+2), glp_get_col_prim(ats->prob,2*c_mechs+2));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+3), glp_get_col_prim(ats->prob,2*c_mechs+3));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value: %f\n", glp_mip_obj_val(ats->prob));
- }
-#endif
+ if ( (abc.c_peers == 0) && (abc.c_mechs == 0) )
+ {
+ *p = NULL;
+ (*c_p) = 0;
+ *m = NULL;
+ (*c_m) = 0;
+ return;
+ }
+
+ abc.mechanisms = GNUNET_malloc((1+abc.c_mechs) * sizeof (struct ATS_mechanism));
+ abc.peers = GNUNET_malloc((1+abc.c_peers) * sizeof (struct ATS_peer));
+ abc.c_mechs = 1;
+ abc.c_peers = 1;
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+ &setup_ats_problem,
+ &abc);
+ abc.c_mechs--;
+ abc.c_peers--;
+ (*c_m) = abc.c_mechs;
+ (*c_p) = abc.c_peers;
+ (*p) = abc.peers;
+ (*m) = abc.mechanisms;
}
-static void ats_delete_problem ()
-{
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting problem\n");
-#endif
- int c;
- for (c=0; c< (ats->stat).c_mechs; c++)
- GNUNET_free_non_null (ats->mechanisms[c].rc);
+static void
+schedule_ats (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ATS_Handle *ats = (struct ATS_Handle *) cls;
+ if (ats==NULL)
+ return;
+ ats_task = GNUNET_SCHEDULER_NO_TASK;
+ if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
- if (ats->mechanisms!=NULL)
- {
- GNUNET_free(ats->mechanisms);
- ats->mechanisms = NULL;
- }
+ if (shutdown_in_progress == GNUNET_YES)
+ return;
- if (ats->peers!=NULL)
- {
- GNUNET_free(ats->peers);
- ats->peers = NULL;
- }
-
- if (ats->prob != NULL)
- {
- glp_delete_prob(ats->prob);
- ats->prob = NULL;
- }
-
- ats->stat.begin_cr = GNUNET_SYSERR;
- ats->stat.begin_qm = GNUNET_SYSERR;
- ats->stat.c_mechs = 0;
- ats->stat.c_peers = 0;
- ats->stat.end_cr = GNUNET_SYSERR;
- ats->stat.end_qm = GNUNET_SYSERR;
- ats->stat.solution = GNUNET_SYSERR;
- ats->stat.valid = GNUNET_SYSERR;
-}
-
-
-static void ats_update_problem_qm ()
-{
- int array_index;
- int row_index;
- int c, c2;
- int c_q_metrics = available_quality_metrics;
-
- int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
- double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
-#endif
- row_index = ats->stat.begin_qm;
-
- for (c=1; c <= c_q_metrics; c++)
- {
- array_index = 1;
- double value = 1;
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-
- glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
- for (c2=1; c2<=ats->stat.c_mechs; c2++)
- {
- ja[array_index] = c2;
-
- GNUNET_assert (ats->mechanisms[c2].addr != NULL);
- GNUNET_assert (ats->mechanisms[c2].peer != NULL);
-
- if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
- {
- double v0 = 0, v1 = 0, v2 = 0;
-
- v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
- if (v1 < 1) v0 = 0.1;
- v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
- if (v1 < 1) v0 = 0.1;
- v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
- if (v1 < 1) v0 = 0.1;
- value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
- //value = 1;
- }
- if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
- {
- double v0 = 0, v1 = 0, v2 = 0;
- v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
- if (v0 < 1) v0 = 1;
- v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
- if (v1 < 1) v1 = 1;
- v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
- if (v2 < 1) v2 = 1;
- value = (v0 + 2 * v1 + 3 * v2) / 6.0;
- if (value >= 1)
- value = (double) 10 / value;
- else
- value = 10;
- }
- ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: %s [%i,%i]=%f \n",array_index, qm[c-1].name, row_index, ja[array_index], ar[array_index]);
-#endif
- array_index++;
- }
- ja[array_index] = ats->stat.col_qm + c - 1;
- ar[array_index] = -1;
-
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
-#endif
- glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
-
- array_index = 1;
- row_index++;
- }
-
- GNUNET_free_non_null (ja);
- GNUNET_free_non_null (ar);
-}
-
-
-static void ats_update_problem_cr ()
-{
-
- int array_index;
- int row_index;
- int c, c2;
- double ct_max, ct_min;
-
- int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
- double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
-
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
- row_index = ats->stat.begin_cr;
- array_index = 1;
-
- for (c=0; c<available_ressources; c++)
- {
- ct_max = ressources[c].c_max;
- ct_min = ressources[c].c_min;
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
-#endif
- glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
-
- for (c2=1; c2<=ats->stat.c_mechs; c2++)
- {
- double value = 0;
-
- GNUNET_assert (ats->mechanisms[c2].addr != NULL);
- GNUNET_assert (ats->mechanisms[c2].peer != NULL);
-
- ja[array_index] = c2;
- value = ats->mechanisms[c2].addr->ressources[c].c;
- ar[array_index] = value;
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
-#endif
- array_index++;
- }
- glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
-
- row_index ++;
- }
-
-
- GNUNET_free_non_null (ja);
- GNUNET_free_non_null (ar);
-}
-
-
-#if 0
-static void ats_update_problem_qm_TEST ()
-{
- int row_index;
- int c, c2;
-
- int old_ja[ats->stat.c_mechs + 2];
- double old_ar[ats->stat.c_mechs + 2];
- int c_old;
- int changed = 0;
-
- int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
- double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics TEST\n");
-#endif
- if (ats->stat.begin_qm >0)
- row_index = ats->stat.begin_qm;
- else
- return;
-
-
- for (c=0; c<available_quality_metrics; c++)
- {
-
- c_old = glp_get_mat_row (ats->prob, row_index, old_ja, old_ar);
-
- glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
-
- for (c2=1; c2<=c_old; c2++)
- {
- ja[c2] = old_ja[c2];
- if ((changed < 3) && (c2>2) && (old_ar[c2] != -1))
- {
- ar[c2] = old_ar[c2] + 5 - changed;
- changed ++;
- }
- else
- ar[c2] = old_ar[c2];
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: old [%i,%i]=%f new [%i,%i]=%f\n",c2, row_index, old_ja[c2], old_ar[c2], row_index, ja[c2], ar[c2]);
-#endif
- }
- glp_set_mat_row (ats->prob, row_index, c_old, ja, ar);
-
- row_index ++;
- }
-
- GNUNET_free_non_null (ja);
- GNUNET_free_non_null (ar);
-}
-#endif //END: HAVE_LIBGLPK
-
-/** solve the bandwidth distribution problem
- * @param max_it maximum iterations
- * @param max_dur maximum duration in ms
- * @param D weight for diversity
- * @param U weight for utility
- * @param R weight for relativity
- * @param v_b_min minimal bandwidth per peer
- * @param v_n_min minimum number of connections
- * @param stat result struct
- * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
- */
-static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_stat *stat)
-{
- ats->prob = glp_create_prob();
-
- int c;
- int c_peers = 0;
- int c_mechs = 0;
-
- int c_c_ressources = available_ressources;
- int c_q_metrics = available_quality_metrics;
-
- double M = VERY_BIG_DOUBLE_VALUE;
- double Q[c_q_metrics+1];
- for (c=1; c<=c_q_metrics; c++)
- {
- Q[c] = 1;
- }
-
- struct NeighbourList *next = neighbours;
- while (next!=NULL)
- {
- int found_addresses = GNUNET_NO;
- struct ReadyList *r_next = next->plugins;
- while (r_next != NULL)
- {
- struct ForeignAddressList * a_next = r_next->addresses;
- while (a_next != NULL)
- {
- c_mechs++;
- found_addresses = GNUNET_YES;
- a_next = a_next->next;
- }
- r_next = r_next->next;
- }
- if (found_addresses) c_peers++;
- next = next->next;
- }
-
- if (c_mechs==0)
- {
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
-#endif
- stat->valid = GNUNET_NO;
- stat->c_peers = 0;
- stat->c_mechs = 0;
- return GNUNET_SYSERR;
- }
-
- ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
- ats->peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
-
- struct ATS_mechanism * mechanisms = ats->mechanisms;
- struct ATS_peer * peers = ats->peers;
-
- c_mechs = 1;
- c_peers = 1;
-
- next = neighbours;
- while (next!=NULL)
- {
- int found_addresses = GNUNET_NO;
- struct ReadyList *r_next = next->plugins;
- while (r_next != NULL)
- {
- struct ForeignAddressList * a_next = r_next->addresses;
- while (a_next != NULL)
- {
- if (found_addresses == GNUNET_NO)
- {
- peers[c_peers].peer = next->id;
- peers[c_peers].m_head = NULL;
- peers[c_peers].m_tail = NULL;
- peers[c_peers].f = 1.0 / c_mechs;
- }
-
- 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;
- mechanisms[c_mechs].plugin = r_next->plugin;
-
- GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
- found_addresses = GNUNET_YES;
- c_mechs++;
-
- a_next = a_next->next;
- }
- r_next = r_next->next;
- }
- if (found_addresses == GNUNET_YES)
- c_peers++;
- next = next->next;
- }
- c_mechs--;
- c_peers--;
-
- if (v_n_min > c_peers)
- v_n_min = c_peers;
-
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms, %i resource entries, %i quality metrics \n", c_peers, c_mechs, c_c_ressources, c_q_metrics);
-#endif
-
- int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
- int row_index;
- int array_index=1;
- int * ia = GNUNET_malloc (size * sizeof (int));
- int * ja = GNUNET_malloc (size * sizeof (int));
- double * ar = GNUNET_malloc(size* sizeof (double));
-
- glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
- glp_set_obj_dir(ats->prob, GLP_MAX);
-
- /* adding columns */
- char * name;
- glp_add_cols(ats->prob, 2 * c_mechs);
- /* adding b_t cols */
- for (c=1; c <= c_mechs; c++)
- {
-
- GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
- glp_set_col_name(ats->prob, c, name);
- GNUNET_free (name);
- glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
- glp_set_obj_coef(ats->prob, c, 0);
-
- }
- /* adding n_t cols */
- for (c=c_mechs+1; c <= 2*c_mechs; c++)
- {
- GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
- glp_set_col_name(ats->prob, c, name);
- GNUNET_free (name);
- glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
- glp_set_col_kind(ats->prob, c, GLP_IV);
- glp_set_obj_coef(ats->prob, c, 0);
- }
-
- /* feasibility constraints */
- /* Constraint 1: one address per peer*/
- row_index = 1;
- glp_add_rows(ats->prob, c_peers);
- for (c=1; c<=c_peers; c++)
- {
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
- glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.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]);
-#endif
- array_index++;
- m = m->next;
- }
- row_index++;
- }
-
- /* Constraint 2: only active mechanism gets bandwidth assigned */
- glp_add_rows(ats->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);
-#endif
- glp_set_row_bnds(ats->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]);
-#endif
- 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]);
-#endif
- array_index++;
- row_index ++;
- }
-
- /* Constraint 3: minimum bandwidth*/
- glp_add_rows(ats->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);
-#endif
- glp_set_row_bnds(ats->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]);
-#endif
- 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]);
-#endif
- array_index++;
- row_index ++;
- }
- int c2;
- /* Constraint 4: max ressource capacity */
- /* V cr: bt * ct_r <= cr_max
- * */
- glp_add_rows(ats->prob, available_ressources);
- double ct_max = VERY_BIG_DOUBLE_VALUE;
- double ct_min = 0.0;
-
- stat->begin_cr = array_index;
-
- for (c=0; c<available_ressources; c++)
- {
- ct_max = ressources[c].c_max;
- ct_min = ressources[c].c_min;
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
-#endif
- glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
-
- for (c2=1; c2<=c_mechs; c2++)
- {
- double value = 0;
- ia[array_index] = row_index;
- ja[array_index] = c2;
- value = mechanisms[c2].addr->ressources[c].c;
- ar[array_index] = value;
-#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]);
-#endif
- array_index++;
- }
- row_index ++;
- }
- stat->end_cr = array_index--;
-
- /* Constraint 5: min number of connections*/
- glp_add_rows(ats->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);
-#endif
- glp_set_row_bnds(ats->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]);
-#endif
- array_index++;
- }
- row_index ++;
-
- // optimisation constraints
-
- // adding columns
-
- // Constraint 6: optimize for diversity
- int col_d;
- col_d = glp_add_cols(ats->prob, 1);
- stat->col_d = col_d;
- //GNUNET_assert (col_d == (2*c_mechs) + 1);
- glp_set_col_name(ats->prob, col_d, "d");
- glp_set_obj_coef(ats->prob, col_d, D);
- glp_set_col_bnds(ats->prob, col_d, GLP_LO, 0.0, 0.0);
- glp_add_rows(ats->prob, 1);
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
- glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
- for (c=1; c<=c_mechs; c++)
- {
- // b_t - n_t * b_min >= 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]);
-#endif
- array_index++;
- }
- ia[array_index] = row_index;
- ja[array_index] = col_d;
- 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]);
-#endif
- array_index++;
- row_index ++;
-
-
- // Constraint 7: optimize for quality
- int col_qm;
- col_qm = glp_add_cols(ats->prob, c_q_metrics);
- stat->col_qm = col_qm;
- //GNUNET_assert (col_qm == (2*c_mechs) + 3 + 1);
- for (c=0; c< c_q_metrics; c++)
- {
- GNUNET_asprintf(&name, "Q_%s",qm[c].name);
- glp_set_col_name(ats->prob, col_qm + c, name);
- glp_set_col_bnds(ats->prob, col_qm + c, GLP_LO, 0.0, 0.0);
- GNUNET_free (name);
- glp_set_obj_coef(ats->prob, col_qm + c, Q[c]);
- }
- glp_add_rows(ats->prob, available_quality_metrics);
- stat->begin_qm = row_index;
- for (c=1; c <= c_q_metrics; c++)
- {
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
- double value = 1;
- glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
- for (c2=1; c2<=c_mechs; c2++)
- {
-
- ia[array_index] = row_index;
- ja[array_index] = c2;
- if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
- {
- double v0 = 0, v1 = 0, v2 = 0;
- v0 = mechanisms[c2].addr->quality[c-1].values[0];
- if (v1 < 1) v0 = 0.1;
- v1 = mechanisms[c2].addr->quality[c-1].values[1];
- if (v1 < 1) v0 = 0.1;
- v2 = mechanisms[c2].addr->quality[c-1].values[2];
- if (v1 < 1) v0 = 0.1;
- value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
- value = 1;
- }
- if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
- {
- double v0 = 0, v1 = 0, v2 = 0;
- v0 = mechanisms[c2].addr->quality[c-1].values[0];
- if (v0 < 1) v0 = 1;
- v1 = mechanisms[c2].addr->quality[c-1].values[1];
- if (v1 < 1) v1 = 1;
- v2 = mechanisms[c2].addr->quality[c-1].values[2];
- if (v2 < 1) v2 = 1;
- value = (v0 + 2 * v1 + 3 * v2) / 6.0;
- if (value >= 1)
- value = (double) 10 / value;
- else
- value = 10;
- }
- ar[array_index] = (mechanisms[c2].peer->f) * value ;
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: %s [%i,%i]=%f \n",array_index, qm[c-1].name, ia[array_index], ja[array_index], ar[array_index]);
-#endif
- array_index++;
- }
-
- ia[array_index] = row_index;
- ja[array_index] = col_qm + c - 1;
- 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]);
-#endif
- array_index++;
- row_index++;
- }
- stat->end_qm = row_index-1;
-
- // Constraint 8: optimize bandwidth utility
- int col_u;
- col_u = glp_add_cols(ats->prob, 1);
- stat->col_u = col_u;
- //GNUNET_assert (col_u == (2*c_mechs) + 2);
- glp_set_col_name(ats->prob, col_u, "u");
- glp_set_obj_coef(ats->prob, col_u, U);
- glp_set_col_bnds(ats->prob, col_u, GLP_LO, 0.0, 0.0);
- glp_add_rows(ats->prob, 1);
-#if VERBOSE_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
- glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
- for (c=1; c<=c_mechs; c++)
- {
- ia[array_index] = row_index;
- ja[array_index] = c;
- ar[array_index] = mechanisms[c].peer->f;
-#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]);
-#endif
- array_index++;
- }
- ia[array_index] = row_index;
- ja[array_index] = col_u;
- 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]);
-#endif
-
- array_index++;
- row_index ++;
-
- // Constraint 9: optimize relativity
- int col_r;
- col_r = glp_add_cols(ats->prob, 1);
- stat->col_r = col_r;
- //GNUNET_assert (col_r == (2*c_mechs) + 3);
- glp_set_col_name(ats->prob, col_r, "r");
- glp_set_obj_coef(ats->prob, col_r, R);
- glp_set_col_bnds(ats->prob, col_r, GLP_LO, 0.0, 0.0);
- glp_add_rows(ats->prob, c_peers);
- for (c=1; c<=c_peers; c++)
- {
- glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
-
- struct ATS_mechanism *m = peers[c].m_head;
- while (m!=NULL)
- {
- ia[array_index] = row_index;
- ja[array_index] = m->col_index;
- ar[array_index] = 1 / mechanisms[c].peer->f;
-#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]);
-#endif
- array_index++;
- m = m->next;
- }
- ia[array_index] = row_index;
- ja[array_index] = col_r;
- 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]);
-#endif
- array_index++;
-
- row_index++;
- }
-
- /* Loading the matrix */
- glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
-
- stat->c_mechs = c_mechs;
- stat->c_peers = c_peers;
- stat->solution = 0;
- stat->valid = GNUNET_YES;
-
- /* clean up */
-
- GNUNET_free (ja);
- GNUNET_free (ia);
- GNUNET_free (ar);
-
- return GNUNET_OK;
-
-}
-
-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();
-}
-#endif //END: HAVE_LIBGLPK
-
-static void
-ats_calculate_bandwidth_distribution ()
-{
-#if HAVE_LIBGLPK
-
- struct GNUNET_TIME_Absolute start;
- struct GNUNET_TIME_Relative creation;
- struct GNUNET_TIME_Relative solving;
- char *text = "unmodified";
-
- 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;
- }
-
- int dur = 500;
- if (INT_MAX < ats->max_exec_duration.rel_value)
- dur = INT_MAX;
- else
- dur = (int) ats->max_exec_duration.rel_value;
-
- ats->stat.simplex_rerun_required = GNUNET_NO;
- start = GNUNET_TIME_absolute_get();
- if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL) || (ats->stat.valid == GNUNET_NO))
- {
- text = "new";
- ats->stat.recreate_problem = GNUNET_YES;
- ats_delete_problem ();
- ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->stat);
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers/Addresses were modified... new problem: %i peer, %i mechs\n", ats->stat.c_peers, ats->stat.c_mechs);
-#endif
- }
-
- else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_resources == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
- {
- text = "modified resources";
- ats_update_problem_cr();
- }
- else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_quality == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
- {
- text = "modified quality";
- ats_update_problem_qm();
- //ats_update_problem_qm_TEST ();
-
- }
-#if DEBUG_ATS
- else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
-#endif
-
- creation = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
- start = GNUNET_TIME_absolute_get();
-
- ats->stat.solution = GLP_UNDEF;
- if (ats->stat.valid == GNUNET_YES)
- {
- ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->stat.c_peers, ats->stat.c_mechs, &ats->stat);
- }
- solving = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
-
- if (ats->stat.valid == GNUNET_YES)
- {
- int msg_type = GNUNET_ERROR_TYPE_DEBUG;
+ struct GNUNET_TIME_Relative delta =
+ GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
+ if (delta.rel_value < ats_minimum_interval.rel_value)
+ {
#if DEBUG_ATS
- msg_type = GNUNET_ERROR_TYPE_ERROR;
+ GNUNET_log (GNUNET_ERROR_TYPE_BULK,
+ "Minimum time between cycles not reached\n");
#endif
- GNUNET_log (msg_type, "MLP %s: creation time: %llu, execution time: %llu, %i mechanisms, simplex rerun: %s, solution %s\n",
- text, creation.rel_value, solving.rel_value,
- ats->stat.c_mechs,
- (ats->stat.simplex_rerun_required == GNUNET_NO) ? "NO" : "YES", (ats->stat.solution == 5) ? "OPTIMAL" : "INVALID");
- ats->successful_executions ++;
- GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
-
- if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL))
- GNUNET_STATISTICS_set (stats, "ATS state",ATS_NEW, GNUNET_NO);
- else if ((ats->stat.modified_resources == GNUNET_YES) &&
- (ats->stat.modified_quality == GNUNET_NO))
- GNUNET_STATISTICS_set (stats, "ATS state", ATS_C_UPDATED, GNUNET_NO);
- else if ((ats->stat.modified_resources == GNUNET_NO) &&
- (ats->stat.modified_quality == GNUNET_YES) &&
- (ats->stat.simplex_rerun_required == GNUNET_NO))
- GNUNET_STATISTICS_set (stats, "ATS state", ATS_Q_UPDATED, GNUNET_NO);
- else if ((ats->stat.modified_resources == GNUNET_YES) &&
- (ats->stat.modified_quality == GNUNET_YES) &&
- (ats->stat.simplex_rerun_required == GNUNET_NO))
- GNUNET_STATISTICS_set (stats, "ATS state", ATS_QC_UPDATED, GNUNET_NO);
- else if (ats->stat.simplex_rerun_required == GNUNET_NO)
- GNUNET_STATISTICS_set (stats, "ATS state", ATS_UNMODIFIED, GNUNET_NO);
- }
- else
- {
- if (ats->stat.c_peers != 0)
- {
- ats->invalid_executions ++;
- GNUNET_STATISTICS_set (stats, "# ATS invalid executions", ats->invalid_executions, GNUNET_NO);
- }
- else
- {
- GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
- }
- }
-
- GNUNET_STATISTICS_set (stats, "ATS duration", solving.rel_value + creation.rel_value, GNUNET_NO);
- GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->stat.c_mechs, GNUNET_NO);
- GNUNET_STATISTICS_set (stats, "ATS peers", ats->stat.c_peers, GNUNET_NO);
- GNUNET_STATISTICS_set (stats, "ATS solution", ats->stat.solution, GNUNET_NO);
- GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
-
- if ((ats->save_mlp == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
- {
- char * filename;
- if (ats->dump_overwrite == GNUNET_NO)
- {
- GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.mlp",
- ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
- glp_write_lp (ats->prob, NULL, filename);
- }
- else
- {
- GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",
- ats->stat.c_peers, ats->stat.c_mechs );
- glp_write_lp (ats->prob, NULL, filename);
- }
- GNUNET_free (filename);
- }
- if ((ats->save_solution == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
- {
- char * filename;
- if (ats->dump_overwrite == GNUNET_NO)
- {
- GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.sol",
- ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
- glp_print_sol (ats->prob, filename);
- }
- else
- {
- GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.sol",
- ats->stat.c_peers, ats->stat.c_mechs);
- glp_print_sol (ats->prob, filename);
- }
- GNUNET_free (filename);
- }
-
- ats->last = GNUNET_TIME_absolute_get();
- ats->stat.recreate_problem = GNUNET_NO;
- ats->stat.modified_resources = GNUNET_NO;
- ats->stat.modified_quality = GNUNET_NO;
-#endif
-}
-
-static 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;
+ 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_interval,
- &ats_schedule_calculation, ats);
-}
-
-void ats_init ()
-{
- int c = 0;
- unsigned long long value;
- char * section;
-
- ats = GNUNET_malloc(sizeof (struct ATS_info));
-
- ats->min_delta = ATS_MIN_INTERVAL;
- ats->exec_interval = ATS_EXEC_INTERVAL;
- ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
- ats->max_iterations = ATS_MAX_ITERATIONS;
- ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
-
-#if !HAVE_LIBGLPK
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "GLPK not installed, ATS not active\n");
- return;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
#endif
-
- ats->D = 1.0;
- ats->U = 1.0;
- ats->R = 1.0;
- ats->v_b_min = 64000;
- ats->v_n_min = 10;
- ats->dump_min_peers = 1;
- ats->dump_min_addr = 1;
- ats->dump_overwrite = GNUNET_NO;
- ats->mechanisms = NULL;
- ats->peers = NULL;
- ats->successful_executions = 0;
- ats->invalid_executions = 0;
-
#if HAVE_LIBGLPK
- ats->prob = NULL;
-#endif
-
- /* loading cost ressources */
- for (c=0; c<available_ressources; c++)
- {
- GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
- {
- if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
- {
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
-#endif
- ressources[c].c_max = value;
- }
- }
- GNUNET_free (section);
- GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
- {
- if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
- {
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
-#endif
- ressources[c].c_min = value;
- }
- }
- GNUNET_free (section);
- }
-
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
- ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
-
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
- ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
- ats->dump_overwrite = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_OVERWRITE");
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
- {
- GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_PEERS", &value);
- ats->dump_min_peers= value;
- }
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_ADDRS"))
- {
- GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_ADDRS", &value);
- ats->dump_min_addr= value;
- }
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
- {
- GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_OVERWRITE", &value);
- ats->min_delta.rel_value = value;
- }
-
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
- {
- GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
- ats->min_delta.rel_value = value;
- }
-
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_EXEC_INTERVAL"))
- {
- GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_EXEC_INTERVAL", &value);
- ats->exec_interval.rel_value = value;
- }
- if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
- {
- GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
- ats->min_delta.rel_value = value;
- }
-
- ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
-}
-
-
-static void ats_shutdown ()
-{
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
+ ats_calculate_bandwidth_distribution (ats);
#endif
- if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel(ats->ats_task);
- ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
+ last_ats_execution = GNUNET_TIME_absolute_get();
-#if HAVE_LIBGLPK
- ats_delete_problem ();
- glp_free_env();
-#endif
- GNUNET_free (ats);
+ ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
+ &schedule_ats, ats);
}
-
-
-void ats_notify_peer_connect (
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
-{
-#if DEBUG_ATS
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
#endif
- //update_addr_ats();
- ats->stat.recreate_problem = GNUNET_YES;
- 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
- ats->stat.recreate_problem = GNUNET_YES;
- ats_calculate_bandwidth_distribution (ats);
-}
-struct ForeignAddressList * ats_get_preferred_address (
- struct NeighbourList *n)
+struct ForeignAddressList * get_preferred_ats_address (
+ struct NeighbourMapEntry *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);
+ // TODO get ATS prefered address
+ return find_ready_address(n);
}
/**
{&handle_address_lookup, NULL,
GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
0},
+ {&handle_peer_address_lookup, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
+ 0},
+ {&handle_address_iterate, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
+ 0},
{&handle_blacklist_init, NULL,
GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
{&handle_blacklist_reply, NULL,
unsigned long long tneigh;
char *keyfile;
+ shutdown_in_progress = GNUNET_NO;
cfg = c;
stats = GNUNET_STATISTICS_create ("transport", cfg);
validation_map = GNUNET_CONTAINER_multihashmap_create (64);
+ neighbours = GNUNET_CONTAINER_multihashmap_create (256);
/* parse configuration */
if ((GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (c,
}
GNUNET_CONTAINER_multihashmap_destroy (validation_map);
validation_map = NULL;
+ GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+ neighbours = NULL;
return;
}
}
GNUNET_CONTAINER_multihashmap_destroy (validation_map);
validation_map = NULL;
+ GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+ neighbours = NULL;
GNUNET_free (keyfile);
return;
}
}
GNUNET_CONTAINER_multihashmap_destroy (validation_map);
validation_map = NULL;
+ GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+ neighbours = NULL;
return;
}
GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
if (no_transports)
refresh_hello ();
- ats_init();
+ /* Initializing ATS */
+ int co;
+ char * section;
+ unsigned long long value;
+#if HAVE_LIBGLPK
+ double D = 1.0;
+ double U = 1.0;
+ double R = 1.0;
+ int v_b_min = 64000;
+ int v_n_min = 5;
+#endif
+
+ ats_minimum_interval = ATS_MIN_INTERVAL;
+ ats_regular_interval = ATS_EXEC_INTERVAL;
+
+ /* loading cost ressources */
+ for (co=0; co<available_ressources; co++)
+ {
+ GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
+ if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
+ {
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
+ "transport",
+ section,
+ &value))
+ {
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Found ressource cost: [%s] = %llu\n",
+ section, value);
+#endif
+ ressources[co].c_max = value;
+ }
+ }
+ GNUNET_free (section);
+ GNUNET_asprintf(§ion,"%s_DOWN",ressources[co].cfg_param);
+ if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
+ {
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
+ "transport",
+ section,
+ &value))
+ {
+#if DEBUG_ATS
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Found ressource cost: [%s] = %llu\n",
+ section, value);
+#endif
+ ressources[co].c_min = value;
+ }
+ }
+ GNUNET_free (section);
+ }
+#if HAVE_LIBGLPK
+ ats = ats_init (D, U, R, v_b_min, v_n_min,
+ ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
+ &create_ats_information,
+ ats_result_cb);
+ ats_set_logging_options (ats,
+ stats,
+ cfg);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_time (cfg,
+ "transport",
+ "ATS_EXEC_INTERVAL",
+ &ats_regular_interval));
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_time (cfg,
+ "transport",
+ "ATS_MIN_INTERVAL",
+ &ats_minimum_interval));
+ if (ats != NULL)
+ ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
+#endif
+
#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Transport service ready.\n"));
#endif
/* If we have a blacklist file, read from it */
read_blacklist_file(cfg);