/*
This file is part of GNUnet.
- Copyright (C) 2013, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2013, 2015 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
#include "gnunet_util_lib.h"
#include "gnunet_signatures.h"
#include "gnunet_transport_service.h"
+#include "gnunet_ats_service.h"
#include "gnunet_core_service.h"
#include "gnunet_statistics_service.h"
#include "cadet_protocol.h"
* Hello message.
*/
struct GNUNET_HELLO_Message* hello;
+
+ /**
+ * Handle to us offering the HELLO to the transport.
+ */
+ struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
+
+ /**
+ * Handle to our ATS request asking ATS to suggest an address
+ * to TRANSPORT for this peer (to establish a direct link).
+ */
+ struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+
};
static unsigned long long drop_percent;
/**
- * Handle to communicate with core.
+ * Handle to communicate with CORE.
*/
static struct GNUNET_CORE_Handle *core_handle;
+/**
+ * Handle to communicate with ATS.
+ */
+static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
/**
* Handle to try to start new connections.
*/
* Remove the direct path to the peer.
*
* @param peer Peer to remove the direct path from.
- *
*/
static struct CadetPeerPath *
pop_direct_path (struct CadetPeer *peer)
{
if (2 >= iter->length)
{
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
+ GNUNET_CONTAINER_DLL_remove (peer->path_head,
+ peer->path_tail,
+ iter);
return iter;
}
}
GNUNET_assert (NULL == neighbor->connections);
neighbor->connections = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
- GNUNET_assert (NULL != neighbor->connections);
-
GNUNET_STATISTICS_update (stats,
"# peers",
1,
"DISCONNECTED %s <= %s\n",
own_id, GNUNET_i2s (peer));
direct_path = pop_direct_path (p);
- GNUNET_CONTAINER_multihashmap_iterate (p->connections,
- ¬ify_broken,
- p);
- GNUNET_CONTAINER_multihashmap_destroy (p->connections);
- p->connections = NULL;
+ if (NULL != p->connections)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (p->connections,
+ ¬ify_broken,
+ p);
+ GNUNET_CONTAINER_multihashmap_destroy (p->connections);
+ p->connections = NULL;
+ }
if (NULL != p->core_transmit)
{
GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit);
"destroying peer %s\n",
GNUNET_i2s (&id));
- if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
{
GNUNET_break (0);
LOG (GNUNET_ERROR_TYPE_WARNING, " peer not in peermap!!\n");
while (NULL != p)
{
nextp = p->next;
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
+ GNUNET_CONTAINER_DLL_remove (peer->path_head,
+ peer->path_tail,
+ p);
path_destroy (p);
p = nextp;
}
{
GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (peer->connections));
GNUNET_CONTAINER_multihashmap_destroy (peer->connections);
+ peer->connections = NULL;
+ }
+ if (NULL != peer->hello_offer)
+ {
+ GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
+ peer->hello_offer = NULL;
+ }
+ if (NULL != peer->connectivity_suggestion)
+ {
+ GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
+ peer->connectivity_suggestion = NULL;
+ }
+ while (NULL != peer->queue_head)
+ {
+ GCP_queue_destroy (peer->queue_head, GNUNET_YES, GNUNET_NO, 0);
}
if (NULL != peer->core_transmit)
+ {
+ GNUNET_break (0); /* GCP_queue_destroy should've cancelled it! */
GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
+ peer->core_transmit = NULL;
+ }
+
GNUNET_free_non_null (peer->hello);
GNUNET_free (peer);
return GNUNET_OK;
{
struct CadetPeer *p = value;
struct CadetTunnel *t = p->tunnel;
+
LOG (GNUNET_ERROR_TYPE_DEBUG, " shutting down %s\n", GCP_2s (p));
if (NULL != t)
GCT_destroy (t);
* @brief Start a search for a peer.
*
* @param cls Closure (Peer to search for).
- * @param tc Task context.
*/
static void
-delayed_search (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+delayed_search (void *cls)
{
struct CadetPeer *peer = cls;
peer->search_delayed = NULL;
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
GCC_check_connections ();
GCP_start_search (peer);
GCC_check_connections ();
return message_size + sizeof (struct GNUNET_CADET_ACK);
}
+/**
+ * Test if a message type is connection management traffic
+ * or regular payload traffic.
+ *
+ * @param type Message type.
+ *
+ * @return #GNUNET_YES if connection management, #GNUNET_NO otherwise.
+ */
+static int
+is_connection_management (uint16_t type)
+{
+ return type == GNUNET_MESSAGE_TYPE_CADET_ACK ||
+ type == GNUNET_MESSAGE_TYPE_CADET_POLL;
+}
+
/**
* Fill a core buffer with the appropriate data for the queued message.
}
+/**
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
+ *
+ * @param q Queue handle with info about the message.
+ *
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
+ */
+static int
+should_I_drop (struct CadetPeerQueue *q)
+{
+ if (0 == drop_percent)
+ return GNUNET_NO;
+
+ if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
+ return GNUNET_YES;
+
+ return GNUNET_NO;
+}
+
+
/**
* Core callback to write a queued packet to core buffer
*
wait_s = GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_YES);
if (core_wait_time.rel_value_us >= 1000000)
{
- LOG (GNUNET_ERROR_TYPE_ERROR,
+ LOG (GNUNET_ERROR_TYPE_WARNING,
" %s: core wait time %s (> 1 second) for %u bytes\n",
GCP_2s (peer), wait_s, queue->size);
}
msg_size = fill_buf (queue, (void *) dst, size, &pid);
- if (0 < drop_percent &&
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
+ if (should_I_drop (queue))
{
LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s (%s %u) on conn %s %s\n",
GC_m2s (queue->type), GC_m2s (queue->payload_type),
else
{
LOG (GNUNET_ERROR_TYPE_INFO,
- ">>> %s (%s %4u) on conn %s (%p) %s (%u bytes), after %s\n",
+ ">>> %s (%s %4u) on conn %s (%p) %s [%5u], after %s\n",
GC_m2s (queue->type), GC_m2s (queue->payload_type),
queue->payload_id, GCC_2s (c), c,
GC_f2s (queue->fwd), msg_size, wait_s);
}
GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue);
- if (queue->type != GNUNET_MESSAGE_TYPE_CADET_ACK &&
- queue->type != GNUNET_MESSAGE_TYPE_CADET_POLL)
+ if (!is_connection_management (queue->type))
{
peer->queue_n--;
}
* @param peer Peer towards which to queue the message.
* @param cls Closure (@c type dependant). It will be used by queue_send to
* build the message to be sent if not already prebuilt.
- * @param type Type of the message, 0 for a raw message.
+ * @param type Type of the message.
+ * @param payload_type Type of the message's payload
+ * 0 if the message is a retransmission (unknown payload).
+ * UINT16_MAX if the message does not have payload.
+ * @param payload_id ID of the payload (MID, ACK #, etc)
* @param size Size of the message.
* @param c Connection this message belongs to (can be NULL).
* @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
}
priority = 0;
-
- if (GNUNET_MESSAGE_TYPE_CADET_POLL == type ||
- GNUNET_MESSAGE_TYPE_CADET_ACK == type)
+ if (is_connection_management (type))
{
priority = 100;
}
-
LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority);
- call_core = (NULL == c || type == GNUNET_MESSAGE_TYPE_CADET_KX) ?
+ call_core = (NULL == c || GNUNET_MESSAGE_TYPE_CADET_KX == type) ?
GNUNET_YES : GCC_is_sendable (c, fwd);
q = GNUNET_new (struct CadetPeerQueue);
q->cls = cls;
LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
}
-
+ ats_ch = GNUNET_ATS_connectivity_init (c);
core_handle = GNUNET_CORE_connect (c, /* Main configuration */
NULL, /* Closure passed to CADET functions */
&core_init, /* Call core_init once connected */
void
GCP_shutdown (void)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down peers\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Shutting down peer subsystem\n");
in_shutdown = GNUNET_YES;
GNUNET_CONTAINER_multipeermap_iterate (peers,
&shutdown_peer,
GNUNET_TRANSPORT_disconnect (transport_handle);
transport_handle = NULL;
}
+ if (NULL != ats_ch)
+ {
+ GNUNET_ATS_connectivity_done (ats_ch);
+ ats_ch = NULL;
+ }
GNUNET_PEER_change_rc (myid, -1);
GNUNET_CONTAINER_multipeermap_destroy (peers);
peers = NULL;
/**
- * Retrieve the CadetPeer stucture associated with the peer. Optionally create
- * one and insert it in the appropriate structures if the peer is not known yet.
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
*
* @param peer Short identity of the peer.
* @param create #GNUNET_YES if a new peer should be created if unknown.
/**
- * Try to connect to a peer on transport level.
+ * Function called once #GNUNET_TRANSPORT_offer_hello() is done.
+ * Marks the operation as finished.
*
- * @param cls Closure (peer).
- * @param tc TaskContext.
+ * @param cls Closure (our `struct CadetPeer`).
*/
static void
-try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+hello_offer_done (void *cls)
{
struct CadetPeer *peer = cls;
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
-
- GNUNET_TRANSPORT_try_connect (transport_handle,
- GNUNET_PEER_resolve2 (peer->id), NULL, NULL);
+ peer->hello_offer = NULL;
}
int rerun_search;
GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GCP_2s (peer));
-
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "peer_connect towards %s\n",
+ GCP_2s (peer));
/* If we have a current hello, try to connect using it. */
GCP_try_connect (peer);
}
}
}
- GNUNET_CONTAINER_DLL_insert_tail (peer->path_head, peer->path_tail,
+ GNUNET_CONTAINER_DLL_insert_tail (peer->path_head,
+ peer->path_tail,
path);
LOG (GNUNET_ERROR_TYPE_DEBUG, " added last\n");
* @param path Path to remove. Is always destroyed .
*/
void
-GCP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path)
+GCP_remove_path (struct CadetPeer *peer,
+ struct CadetPeerPath *path)
{
struct CadetPeerPath *iter;
struct CadetPeerPath *next;
GNUNET_assert (myid == path->peers[0]);
GNUNET_assert (peer->id == path->peers[path->length - 1]);
- LOG (GNUNET_ERROR_TYPE_INFO, "Removing path %p (%u) from %s\n",
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Removing path %p (%u) from %s\n",
path, path->length, GCP_2s (peer));
for (iter = peer->path_head; NULL != iter; iter = next)
next = iter->next;
if (0 == path_cmp (path, iter))
{
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
+ GNUNET_CONTAINER_DLL_remove (peer->path_head,
+ peer->path_tail,
+ iter);
if (iter != path)
path_destroy (iter);
}
* @param hello Hello message.
*/
void
-GCP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message *hello)
+GCP_set_hello (struct CadetPeer *peer,
+ const struct GNUNET_HELLO_Message *hello)
{
struct GNUNET_HELLO_Message *old;
size_t size;
return;
mh = GNUNET_HELLO_get_header (hello);
- GNUNET_TRANSPORT_offer_hello (transport_handle,
- mh,
- &try_connect,
- peer);
+ if (NULL != peer->hello_offer)
+ {
+ GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
+ peer->hello_offer = NULL;
+ }
+ peer->hello_offer = GNUNET_TRANSPORT_offer_hello (transport_handle,
+ mh,
+ &hello_offer_done,
+ peer);
+ if (NULL == peer->connectivity_suggestion)
+ peer->connectivity_suggestion
+ = GNUNET_ATS_connectivity_suggest (ats_ch,
+ GNUNET_PEER_resolve2 (peer->id),
+ 1 /* strength */);
GCC_check_connections ();
}