/*
This file is part of GNUnet.
- Copyright (C) 2013 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
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
-
-
+/**
+ * @file cadet/gnunet-service-cadet_peer.c
+ * @brief GNUnet CADET service connection handling
+ * @author Bartlomiej Polot
+ */
#include "platform.h"
#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"
-
#include "gnunet-service-cadet_peer.h"
#include "gnunet-service-cadet_dht.h"
#include "gnunet-service-cadet_connection.h"
*/
struct CadetPeerQueue
{
- /**
- * DLL next
- */
+ /**
+ * DLL next
+ */
struct CadetPeerQueue *next;
- /**
- * DLL previous
- */
+ /**
+ * DLL previous
+ */
struct CadetPeerQueue *prev;
- /**
- * Peer this transmission is directed to.
- */
+ /**
+ * Peer this transmission is directed to.
+ */
struct CadetPeer *peer;
- /**
- * Connection this message belongs to.
- */
+ /**
+ * Connection this message belongs to.
+ */
struct CadetConnection *c;
- /**
- * Is FWD in c?
- */
+ /**
+ * Is FWD in c?
+ */
int fwd;
- /**
- * Pointer to info stucture used as cls.
- */
+ /**
+ * Pointer to info stucture used as cls.
+ */
void *cls;
/**
uint32_t payload_id;
/**
- * Size of the message
- */
+ * Size of the message
+ */
size_t size;
- /**
- * Set when this message starts waiting for CORE.
- */
+ /**
+ * Set when this message starts waiting for CORE.
+ */
struct GNUNET_TIME_Absolute start_waiting;
- /**
- * Function to call on sending.
- */
- GCP_sent callback;
+ /**
+ * Function to call on sending.
+ */
+ GCP_sent cont;
- /**
- * Closure for callback.
- */
- void *callback_cls;
+ /**
+ * Closure for callback.
+ */
+ void *cont_cls;
};
+
/**
* Struct containing all information regarding a given peer
*/
struct CadetPeer
{
- /**
- * ID of the peer
- */
+ /**
+ * ID of the peer
+ */
GNUNET_PEER_Id id;
- /**
- * Axolotl permanent public key.
- */
- struct GNUNET_CRYPTO_EcdhePublicKey ax_key;
-
- /**
- * Last time we heard from this peer
- */
+ /**
+ * Last time we heard from this peer
+ */
struct GNUNET_TIME_Absolute last_contact;
- /**
- * Paths to reach the peer, ordered by ascending hop count
- */
+ /**
+ * Paths to reach the peer, ordered by ascending hop count
+ */
struct CadetPeerPath *path_head;
- /**
- * Paths to reach the peer, ordered by ascending hop count
- */
+ /**
+ * Paths to reach the peer, ordered by ascending hop count
+ */
struct CadetPeerPath *path_tail;
- /**
- * Handle to stop the DHT search for paths to this peer
- */
+ /**
+ * Handle to stop the DHT search for paths to this peer
+ */
struct GCD_search_handle *search_h;
/**
*/
struct GNUNET_SCHEDULER_Task *search_delayed;
- /**
- * Tunnel to this peer, if any.
- */
+ /**
+ * Tunnel to this peer, if any.
+ */
struct CadetTunnel *tunnel;
- /**
- * Connections that go through this peer, indexed by tid;
- */
+ /**
+ * Connections that go through this peer; indexed by tid.
+ */
struct GNUNET_CONTAINER_MultiHashMap *connections;
- /**
- * Handle for queued transmissions
- */
+ /**
+ * Handle for queued transmissions
+ */
struct GNUNET_CORE_TransmitHandle *core_transmit;
/**
* 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;
+
};
extern GNUNET_PEER_Id myid;
/**
- * Peers known, indexed by PeerIdentity (CadetPeer).
+ * Peers known, indexed by PeerIdentity, values of type `struct CadetPeer`.
*/
static struct GNUNET_CONTAINER_MultiPeerMap *peers;
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.
*/
static struct GNUNET_TRANSPORT_Handle *transport_handle;
+/**
+ * Shutdown falg.
+ */
+static int in_shutdown;
+
/******************************************************************************/
/***************************** DEBUG *********************************/
static void
queue_debug (const struct CadetPeer *p, enum GNUNET_ErrorType level)
{
+ struct GNUNET_TIME_Relative core_wait_time;
struct CadetPeerQueue *q;
int do_log;
LOG2 (level, "QQQ Message queue towards %s\n", GCP_2s (p));
LOG2 (level, "QQQ queue length: %u\n", p->queue_n);
LOG2 (level, "QQQ core tmt rdy: %p\n", p->core_transmit);
-
+ if (NULL != p->core_transmit)
+ {
+ core_wait_time = GNUNET_TIME_absolute_get_duration (p->tmt_time);
+ LOG2 (level, "QQQ core called %s ago\n",
+ GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_NO));
+ }
for (q = p->queue_head; NULL != q; q = q->next)
{
LOG2 (level, "QQQ - %s %s on %s\n",
LOG2 (level, "PPP core transmit handle %p\n", p->core_transmit);
LOG2 (level, "PPP DHT GET handle %p\n", p->search_h);
+ conns = 0;
if (NULL != p->connections)
- conns = GNUNET_CONTAINER_multihashmap_size (p->connections);
- else
- conns = 0;
+ conns += GNUNET_CONTAINER_multihashmap_size (p->connections);
LOG2 (level, "PPP # connections over link to peer: %u\n", conns);
queue_debug (p, level);
LOG2 (level, "PPP DEBUG END\n");
* Iterator to notify all connections of a broken link. Mark connections
* to destroy after all traffic has been sent.
*
- * @param cls Closure (peer disconnected).
+ * @param cls Closure (disconnected peer).
* @param key Current key code (peer id).
* @param value Value in the hash map (connection).
*
struct CadetPeer *peer = cls;
struct CadetConnection *c = value;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " notifying %s due to %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Notifying %s due to %s disconnect\n",
GCC_2s (c), GCP_2s (peer));
- GCC_notify_broken (c, peer);
-
+ GCC_neighbor_disconnected (c, peer);
return GNUNET_YES;
}
* 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;
}
}
/***************************** CORE CALLBACKS *********************************/
/******************************************************************************/
+
/**
* Method called whenever a given peer connects.
*
* @param peer peer identity this notification is about
*/
static void
-core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
+core_connect (void *cls,
+ const struct GNUNET_PeerIdentity *peer)
{
- struct CadetPeer *mp;
+ struct CadetPeer *neighbor;
struct CadetPeerPath *path;
char own_id[16];
- strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
- mp = GCP_get (peer);
- if (myid == mp->id)
- {
- LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s (self)\n", own_id);
+ GCC_check_connections ();
+ GNUNET_snprintf (own_id,
+ sizeof (own_id),
+ "%s",
+ GNUNET_i2s (&my_full_id));
+ neighbor = GCP_get (peer, GNUNET_YES);
+ if (myid == neighbor->id)
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "CONNECTED %s (self)\n",
+ own_id);
path = path_new (1);
}
else
{
- LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s <= %s\n",
- own_id, GNUNET_i2s (peer));
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "CONNECTED %s <= %s\n",
+ own_id,
+ GNUNET_i2s (peer));
path = path_new (2);
- path->peers[1] = mp->id;
- GNUNET_PEER_change_rc (mp->id, 1);
- GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
+ path->peers[1] = neighbor->id;
+ GNUNET_PEER_change_rc (neighbor->id, 1);
}
path->peers[0] = myid;
GNUNET_PEER_change_rc (myid, 1);
- GCP_add_path (mp, path, GNUNET_YES);
-
- mp->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
-
- if (NULL != GCP_get_tunnel (mp) &&
- 0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer))
- {
- GCP_connect (mp);
- }
-
- return;
+ GCP_add_path (neighbor, path, GNUNET_YES);
+
+ GNUNET_assert (NULL == neighbor->connections);
+ neighbor->connections = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats,
+ "# peers",
+ 1,
+ GNUNET_NO);
+
+ if ( (NULL != GCP_get_tunnel (neighbor)) &&
+ (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) )
+ GCP_connect (neighbor);
+ GCC_check_connections ();
}
* @param peer peer identity this notification is about
*/
static void
-core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+core_disconnect (void *cls,
+ const struct GNUNET_PeerIdentity *peer)
{
struct CadetPeer *p;
struct CadetPeerPath *direct_path;
char own_id[16];
- strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
+ GCC_check_connections ();
+ strncpy (own_id, GNUNET_i2s (&my_full_id), 16);
+ own_id[15] = '\0';
p = GNUNET_CONTAINER_multipeermap_get (peers, peer);
if (NULL == p)
{
- GNUNET_break (0);
+ GNUNET_break (GNUNET_YES == in_shutdown);
return;
}
if (myid == p->id)
- LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s (self)\n", own_id);
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "DISCONNECTED %s (self)\n",
+ own_id);
else
- LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s <= %s\n",
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "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);
- p->core_transmit = NULL;
- p->tmt_time.abs_value_us = 0;
- }
- GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
-
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit);
+ p->core_transmit = NULL;
+ p->tmt_time.abs_value_us = 0;
+ }
+ GNUNET_STATISTICS_update (stats,
+ "# peers",
+ -1,
+ GNUNET_NO);
path_destroy (direct_path);
- return;
+ GCC_check_connections ();
}
{&GCC_handle_poll, GNUNET_MESSAGE_TYPE_CADET_POLL,
sizeof (struct GNUNET_CADET_Poll)},
{&GCC_handle_kx, GNUNET_MESSAGE_TYPE_CADET_KX, 0},
- {&GCC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0}
+ {&GCC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0},
+ {&GCC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_AX, 0},
+ {NULL, 0, 0}
};
GNUNET_assert (0);
}
GML_start ();
- return;
}
}
/* Bulky payload has lower priority, control traffic has higher. */
- if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type)
+ if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type
+ || GNUNET_MESSAGE_TYPE_CADET_AX == q->type)
return low;
else
return high;
/**
- * Iterator over tunnel hash map entries to destroy the tunnel during shutdown.
+ * Destroy the peer_info and free any allocated resources linked to it
+ *
+ * @param peer The peer_info to destroy.
+ * @return #GNUNET_OK on success
+ */
+static int
+peer_destroy (struct CadetPeer *peer)
+{
+ struct GNUNET_PeerIdentity id;
+ struct CadetPeerPath *p;
+ struct CadetPeerPath *nextp;
+
+ GNUNET_PEER_resolve (peer->id, &id);
+ GNUNET_PEER_change_rc (peer->id, -1);
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "destroying peer %s\n",
+ GNUNET_i2s (&id));
+
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " peer not in peermap!!\n");
+ }
+ GCP_stop_search (peer);
+ p = peer->path_head;
+ while (NULL != p)
+ {
+ nextp = p->next;
+ GNUNET_CONTAINER_DLL_remove (peer->path_head,
+ peer->path_tail,
+ p);
+ path_destroy (p);
+ p = nextp;
+ }
+ if (NULL != peer->tunnel)
+ GCT_destroy_empty (peer->tunnel);
+ if (NULL != peer->connections)
+ {
+ 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;
+}
+
+
+/**
+ * Iterator over peer hash map entries to destroy the peer during in_shutdown.
*
* @param cls closure
* @param key current key code
* #GNUNET_NO if not.
*/
static int
-shutdown_tunnel (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
+shutdown_peer (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
{
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);
+ p->tunnel = NULL;
+ peer_destroy (p);
return GNUNET_YES;
}
* Check if peer is searching for a path (either active or delayed search).
*
* @param peer Peer to check
- *
- * @return GNUNET_YES if there is a search active.
- * GNUNET_NO otherwise.
+ * @return #GNUNET_YES if there is a search active.
+ * #GNUNET_NO otherwise.
*/
static int
is_searching (const struct CadetPeer *peer)
{
- return (NULL == peer->search_h && NULL == peer->search_delayed) ?
- GNUNET_NO : GNUNET_YES;
+ return ( (NULL == peer->search_h) &&
+ (NULL == peer->search_delayed) ) ?
+ GNUNET_NO : GNUNET_YES;
}
* @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);
-}
-
-
-/**
- * Destroy the peer_info and free any allocated resources linked to it
- *
- * @param peer The peer_info to destroy.
- *
- * @return GNUNET_OK on success
- */
-static int
-peer_destroy (struct CadetPeer *peer)
-{
- struct GNUNET_PeerIdentity id;
- struct CadetPeerPath *p;
- struct CadetPeerPath *nextp;
-
- GNUNET_PEER_resolve (peer->id, &id);
- GNUNET_PEER_change_rc (peer->id, -1);
-
- LOG (GNUNET_ERROR_TYPE_WARNING, "destroying peer %s\n", GNUNET_i2s (&id));
-
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, " not in peermap!!\n");
- }
- GCP_stop_search (peer);
- p = peer->path_head;
- while (NULL != p)
- {
- nextp = p->next;
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
- path_destroy (p);
- p = nextp;
- }
- GCT_destroy_empty (peer->tunnel);
- GNUNET_free (peer);
- return GNUNET_OK;
+ GCC_check_connections ();
}
* Returns if peer is used (has a tunnel or is neighbor).
*
* @param peer Peer to check.
- *
* @return #GNUNET_YES if peer is in use.
*/
static int
* considering the tunnel properties.
*
* @param peer The destination peer.
- *
* @return Best current known path towards the peer, if any.
*/
static struct CadetPeerPath *
* - For payload traffic, check the connection flow control.
*
* @param q Queue element to inspect.
- *
* @return #GNUNET_YES if it is sendable, #GNUNET_NO otherwise.
*/
static int
* paths form the initial tunnel, which can be optimized later.
* Called on each result obtained for the DHT search.
*
- * @param cls closure
- * @param path
+ * @param cls Closure (peer towards a path has been found).
+ * @param path Path created from the DHT query. Will be freed afterwards.
*/
static void
search_handler (void *cls, const struct CadetPeerPath *path)
struct CadetPeer *peer = cls;
unsigned int connection_count;
+ GCC_check_connections ();
GCP_add_path_to_all (path, GNUNET_NO);
/* Count connections */
/* If we already have our minimum (or more) connections, it's enough */
if (CONNECTIONS_PER_TUNNEL <= connection_count)
+ {
+ GCC_check_connections ();
return;
+ }
if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (peer->tunnel))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
GCP_connect (peer);
}
- return;
+ 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.
{
case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
*pid = GCC_get_pid (queue->c, queue->fwd);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " payload ID %u\n", *pid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " otr payload ID %u\n", *pid);
msg_size = send_core_data_raw (queue->cls, size, buf);
((struct GNUNET_CADET_Encrypted *) buf)->pid = htonl (*pid);
break;
+ case GNUNET_MESSAGE_TYPE_CADET_AX:
+ *pid = GCC_get_pid (queue->c, queue->fwd);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ax payload ID %u\n", *pid);
+ msg_size = send_core_data_raw (queue->cls, size, buf);
+ ((struct GNUNET_CADET_AX *) buf)->pid = htonl (*pid);
+ break;
case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
case GNUNET_MESSAGE_TYPE_CADET_KX:
}
+/**
+ * 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
*
struct CadetConnection *c;
struct CadetPeerQueue *queue;
struct GNUNET_TIME_Relative core_wait_time;
+ const char *wait_s;
const struct GNUNET_PeerIdentity *dst_id;
size_t msg_size;
size_t total_size;
char *dst;
uint32_t pid;
+ GCC_check_connections ();
LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue send towards %s (max %u)\n",
/* Sanity checking */
if (NULL == buf || 0 == size)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Buffer size 0.\n");
- peer->tmt_time.abs_value_us = 0;
- peer->core_transmit = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not allowed/\n");
+ if (GNUNET_NO == in_shutdown)
+ {
+ queue = peer_get_first_message (peer);
+ if (NULL == queue)
+ {
+ peer->core_transmit = NULL;
+ peer->tmt_time.abs_value_us = 0;
+ GCC_check_connections ();
+ return 0;
+ }
+ dst_id = GNUNET_PEER_resolve2 (peer->id);
+ peer->core_transmit =
+ GNUNET_CORE_notify_transmit_ready (core_handle,
+ GNUNET_NO, get_priority (queue),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ dst_id,
+ get_core_size (queue->size),
+ &queue_send,
+ peer);
+ peer->tmt_time = GNUNET_TIME_absolute_get ();
+ }
+ else
+ {
+ peer->core_transmit = NULL;
+ peer->tmt_time.abs_value_us = 0;
+ }
+ GCC_check_connections ();
return 0;
}
return 0;
}
core_wait_time = GNUNET_TIME_absolute_get_duration (peer->tmt_time);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " core wait time %s\n",
- GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_NO));
+ 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_WARNING,
+ " %s: core wait time %s (> 1 second) for %u bytes\n",
+ GCP_2s (peer), wait_s, queue->size);
+ }
peer->tmt_time.abs_value_us = 0;
/* Copy all possible messages to the core buffer */
{
c = queue->c;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on conn %s %s\n",
GCC_2s (c), GC_f2s(queue->fwd));
LOG (GNUNET_ERROR_TYPE_DEBUG, " size %u ok (%u/%u)\n",
queue->size, total_size, 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 connection %s %s\n",
+ LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s (%s %u) on conn %s %s\n",
GC_m2s (queue->type), GC_m2s (queue->payload_type),
queue->payload_id, GCC_2s (c), GC_f2s (queue->fwd));
msg_size = 0;
else
{
LOG (GNUNET_ERROR_TYPE_INFO,
- "snd %s (%s %4u) on connection %s (%p) %s (size %u)\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);
+ queue->payload_id, GCC_2s (c), c,
+ GC_f2s (queue->fwd), msg_size, wait_s);
}
total_size += msg_size;
rest -= msg_size;
LOG (GNUNET_ERROR_TYPE_DEBUG, " return %d\n", total_size);
queue_debug (peer, GNUNET_ERROR_TYPE_DEBUG);
-
+ GCC_check_connections ();
return total_size;
}
* #GNUNET_NO otherwise.
*/
int
-GCP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
- int sent, uint32_t pid)
+GCP_queue_destroy (struct CadetPeerQueue *queue,
+ int clear_cls,
+ int sent,
+ uint32_t pid)
{
struct CadetPeer *peer;
int connection_destroyed;
+ GCC_check_connections ();
peer = queue->peer;
LOG (GNUNET_ERROR_TYPE_DEBUG, "queue destroy %s\n", GC_m2s (queue->type));
if (GNUNET_YES == clear_cls)
case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
case GNUNET_MESSAGE_TYPE_CADET_KX:
case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ case GNUNET_MESSAGE_TYPE_CADET_AX:
case GNUNET_MESSAGE_TYPE_CADET_ACK:
case GNUNET_MESSAGE_TYPE_CADET_POLL:
GNUNET_free_non_null (queue->cls);
}
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--;
}
- if (NULL != queue->callback)
+ if (NULL != queue->cont)
{
struct GNUNET_TIME_Relative wait_time;
wait_time = GNUNET_TIME_absolute_get_duration (queue->start_waiting);
LOG (GNUNET_ERROR_TYPE_DEBUG, " calling callback, time elapsed %s\n",
GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO));
- connection_destroyed = queue->callback (queue->callback_cls,
- queue->c, sent, queue->type, pid,
- queue->fwd, queue->size,
- wait_time);
+ connection_destroyed = queue->cont (queue->cont_cls,
+ queue->c, sent, queue->type, pid,
+ queue->fwd, queue->size, wait_time);
}
else
{
}
GNUNET_free (queue);
+ GCC_check_connections ();
return connection_destroyed;
}
* @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!)
* message has been sent and therefore the handle is no longer valid.
*/
struct CadetPeerQueue *
-GCP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
- uint16_t payload_type, uint32_t payload_id, size_t size,
- struct CadetConnection *c, int fwd,
- GCP_sent cont, void *cont_cls)
+GCP_queue_add (struct CadetPeer *peer,
+ void *cls,
+ uint16_t type,
+ uint16_t payload_type,
+ uint32_t payload_id,
+ size_t size,
+ struct CadetConnection *c,
+ int fwd,
+ GCP_sent cont,
+ void *cont_cls)
{
struct CadetPeerQueue *q;
- int error_level;
int priority;
int call_core;
- if (NULL == c && GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN != type)
- error_level = GNUNET_ERROR_TYPE_ERROR;
- else
- error_level = GNUNET_ERROR_TYPE_INFO;
- LOG (error_level,
- "que %s (%s %9u) on connection %s (%p) %s towards %s (size %u)\n",
+ GCC_check_connections ();
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "que %s (%s %4u) on conn %s (%p) %s towards %s (size %u)\n",
GC_m2s (type), GC_m2s (payload_type), payload_id,
GCC_2s (c), c, GC_f2s (fwd), GCP_2s (peer), size);
- if (error_level == GNUNET_ERROR_TYPE_ERROR)
- GNUNET_assert (0);
if (NULL == peer->connections)
{
/* We are not connected to this peer, ignore request. */
- LOG (GNUNET_ERROR_TYPE_WARNING, "%s not a neighbor\n", GCP_2s (peer));
+ LOG (GNUNET_ERROR_TYPE_INFO, "%s not a neighbor\n", GCP_2s (peer));
GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
GNUNET_NO);
return NULL;
}
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;
q->peer = peer;
q->c = c;
q->fwd = fwd;
- q->callback = cont;
- q->callback_cls = cont_cls;
+ q->cont = cont;
+ q->cont_cls = cont_cls;
if (100 > priority)
{
GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail, q);
}
queue_debug (peer, GNUNET_ERROR_TYPE_DEBUG);
+ GCC_check_connections ();
return q;
}
* the sent continuation call.
*/
void
-GCP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c)
+GCP_queue_cancel (struct CadetPeer *peer,
+ struct CadetConnection *c)
{
struct CadetPeerQueue *q;
struct CadetPeerQueue *next;
struct CadetPeerQueue *prev;
int connection_destroyed;
+ GCC_check_connections ();
connection_destroyed = GNUNET_NO;
for (q = peer->queue_head; NULL != q; q = next)
{
prev = q->prev;
if (q->c == c)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMP queue cancel %s\n", GC_m2s (q->type));
- GNUNET_break (GNUNET_NO == connection_destroyed);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GMP queue cancel %s\n",
+ GC_m2s (q->type));
+ GNUNET_assert (GNUNET_NO == connection_destroyed);
if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY == q->type)
{
q->c = NULL;
}
}
- if (NULL == peer->queue_head && NULL != peer->core_transmit)
+ if ( (NULL == peer->queue_head) &&
+ (NULL != peer->core_transmit) )
{
GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
peer->core_transmit = NULL;
peer->tmt_time.abs_value_us = 0;
}
+ GCC_check_connections ();
}
struct GNUNET_MessageHeader *msg;
int dest;
+ GCC_check_connections ();
GNUNET_assert (NULL != destroyed);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "connection_pop on connection %p\n", c);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "connection_pop on conn %p\n", c);
for (q = peer->queue_head; NULL != q; q = next)
{
next = q->next;
if (q->c != c)
continue;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " - queued: %s (%s %u), callback: %p\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " - queued: %s (%s %u), cont: %p\n",
GC_m2s (q->type), GC_m2s (q->payload_type), q->payload_id,
- q->callback);
+ q->cont);
switch (q->type)
{
case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
case GNUNET_MESSAGE_TYPE_CADET_KX:
case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ case GNUNET_MESSAGE_TYPE_CADET_AX:
+ case GNUNET_MESSAGE_TYPE_CADET_AX_KX:
msg = (struct GNUNET_MessageHeader *) q->cls;
dest = GCP_queue_destroy (q, GNUNET_NO, GNUNET_NO, 0);
if (GNUNET_YES == dest)
LOG (GNUNET_ERROR_TYPE_DEBUG, "Unknown message %s\n", GC_m2s (q->type));
}
}
-
+ GCC_check_connections ();
return NULL;
}
+
/**
* Unlock a possibly locked queue for a connection.
*
struct CadetPeerQueue *q;
size_t size;
+ GCC_check_connections ();
if (NULL != peer->core_transmit)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n");
&queue_send,
peer);
peer->tmt_time = GNUNET_TIME_absolute_get ();
+ GCC_check_connections ();
}
void
GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GCP_init\n");
+ in_shutdown = GNUNET_NO;
peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS",
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)
{
- GNUNET_CONTAINER_multipeermap_iterate (peers, &shutdown_tunnel, NULL);
-
- if (core_handle != NULL)
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Shutting down peer subsystem\n");
+ in_shutdown = GNUNET_YES;
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ &shutdown_peer,
+ NULL);
+ if (NULL != core_handle)
{
GNUNET_CORE_disconnect (core_handle);
core_handle = NULL;
}
- if (transport_handle != NULL)
+ if (NULL != transport_handle)
{
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, 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_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ * #GNUNET_NO otherwise.
*
* @return Existing or newly created peer structure.
+ * NULL if unknown and not requested @a create
*/
struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id)
+GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create)
{
struct CadetPeer *peer;
{
peer_delete_oldest ();
}
- GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
- peer->id = GNUNET_PEER_intern (peer_id);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multipeermap_put (peers,
+ peer_id,
+ peer,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ peer->id = GNUNET_PEER_intern (peer_id);
}
peer->last_contact = GNUNET_TIME_absolute_get ();
/**
- * Retrieve the CadetPeer stucture associated with the peer, 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.
+ * #GNUNET_NO otherwise.
*
* @return Existing or newly created peer structure.
+ * NULL if unknown and not requested @a create
*/
struct CadetPeer *
-GCP_get_short (const GNUNET_PEER_Id peer)
+GCP_get_short (const GNUNET_PEER_Id peer, int create)
{
- return GCP_get (GNUNET_PEER_resolve2 (peer));
+ return GCP_get (GNUNET_PEER_resolve2 (peer), create);
}
/**
- * 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;
}
GCP_connect (struct CadetPeer *peer)
{
struct CadetTunnel *t;
- struct CadetPeerPath *p;
+ struct CadetPeerPath *path;
struct CadetConnection *c;
int rerun_search;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GCP_2s (peer));
-
+ GCC_check_connections ();
+ 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);
if (NULL != peer->path_head)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n");
- p = peer_get_best_path (peer);
- if (NULL != p)
+ path = peer_get_best_path (peer);
+ if (NULL != path)
{
char *s;
- s = path_2s (p);
+ s = path_2s (path);
LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s);
GNUNET_free (s);
- c = GCT_use_path (t, p);
+ c = GCT_use_path (t, path);
if (NULL == c)
{
/* This case can happen when the path includes a first hop that is
* not yet known to be connected.
*
* This happens quite often during testing when running cadet
- * under valgrind: core connect notifications come very late and the
- * DHT result has already come and created a valid path.
- * In this case, the peer->connections hashmap will be NULL and
- * tunnel_use_path will not be able to create a connection from that
- * path.
+ * under valgrind: core connect notifications come very late
+ * and the DHT result has already come and created a valid
+ * path. In this case, the peer->connections
+ * hashmaps will be NULL and tunnel_use_path will not be able
+ * to create a connection from that path.
*
* Re-running the DHT GET should give core time to callback.
*
GCP_stop_search (peer);
delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
- peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay, &delayed_search,
+ peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay,
+ &delayed_search,
peer);
+ GCC_check_connections ();
return;
}
if (GNUNET_NO == is_searching (peer))
GCP_start_search (peer);
+ GCC_check_connections ();
}
}
/* Is not a neighbor but connections is not NULL, probably disconnecting */
+ GNUNET_break (0);
return GNUNET_NO;
}
void
GCP_add_tunnel (struct CadetPeer *peer)
{
+ GCC_check_connections ();
if (NULL != peer->tunnel)
return;
peer->tunnel = GCT_new (peer);
+ GCC_check_connections ();
}
*
* @param peer Peer to add connection to.
* @param c Connection to add.
- *
- * @return GNUNET_OK on success.
+ * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor
*/
-int
+void
GCP_add_connection (struct CadetPeer *peer,
- struct CadetConnection *c)
+ struct CadetConnection *c,
+ int pred)
{
- int result;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "adding connection %s\n", GCC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "to peer %s\n", GCP_2s (peer));
-
- if (NULL == peer->connections)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Peer %s is not a neighbor!\n",
- GCP_2s (peer));
- return GNUNET_SYSERR;
- }
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "peer %s ok, has %u connections.\n",
- GCP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
- result = GNUNET_CONTAINER_multihashmap_put (peer->connections,
- GCC_get_h (c),
- c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ "adding connection %s\n",
+ GCC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "to peer %s\n",
+ GCP_2s (peer));
+ GNUNET_assert (NULL != peer->connections);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (peer->connections,
+ GCC_get_h (c),
+ c,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " now has %u connections.\n",
+ "Peer %s has now %u connections.\n",
+ GCP_2s (peer),
GNUNET_CONTAINER_multihashmap_size (peer->connections));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "result %u\n", result);
-
- return result;
}
* is the shortest.
*
* @param peer Destination peer to add the path to.
- * @param path New path to add. Last peer must be the peer in arg 1.
+ * @param path New path to add. Last peer must be @c peer.
* Path will be either used of freed if already known.
* @param trusted Do we trust that this path is real?
*
* NULL on error.
*/
struct CadetPeerPath *
-GCP_add_path (struct CadetPeer *peer, struct CadetPeerPath *path,
+GCP_add_path (struct CadetPeer *peer,
+ struct CadetPeerPath *path,
int trusted)
{
struct CadetPeerPath *aux;
unsigned int l;
unsigned int l2;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n",
+ GCC_check_connections ();
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "adding path [%u] to peer %s\n",
path->length, GCP_2s (peer));
if (NULL == peer || NULL == path
}
}
}
- 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");
finish:
if (NULL != peer->tunnel
- && CONNECTIONS_PER_TUNNEL < GCT_count_connections (peer->tunnel))
+ && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel)
+ && 2 < path->length) /* Direct paths are handled by core_connect */
{
GCP_connect (peer);
}
+ GCC_check_connections ();
return path;
}
unsigned int i;
/* TODO: invert and add */
+ GCC_check_connections ();
for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
for (i++; i < p->length; i++)
{
- struct CadetPeer *aux;
+ struct CadetPeer *peer;
struct CadetPeerPath *copy;
- aux = GCP_get_short (p->peers[i]);
+ peer = GCP_get_short (p->peers[i], GNUNET_YES);
copy = path_duplicate (p);
copy->length = i + 1;
- GCP_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed);
+ GCP_add_path (peer, copy, 3 > p->length ? GNUNET_NO : confirmed);
}
+ GCC_check_connections ();
}
/**
- * Remove any path to the peer that has the extact same peers as the one given.
+ * Remove any path to the peer that has the exact same peers as the one given.
*
* @param peer Peer to remove the path from.
* @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;
+ GCC_check_connections ();
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);
}
}
path_destroy (path);
+ GCC_check_connections ();
+}
+
+
+/**
+ * Check that we are aware of a connection from a neighboring peer.
+ *
+ * @param peer Peer to the connection is with
+ * @param c Connection that should be in the map with this peer.
+ */
+void
+GCP_check_connection (const struct CadetPeer *peer,
+ const struct CadetConnection *c)
+{
+ GNUNET_assert (NULL != peer);
+ GNUNET_assert (NULL != peer->connections);
+ return;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_contains_value (peer->connections,
+ GCC_get_h (c),
+ c));
}
*
* @param peer Peer to remove connection from.
* @param c Connection to remove.
- *
- * @return GNUNET_OK on success.
*/
-int
+void
GCP_remove_connection (struct CadetPeer *peer,
const struct CadetConnection *c)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "removing connection %s\n", GCC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "from peer %s\n", GCP_2s (peer));
-
- if (NULL == peer || NULL == peer->connections)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Peer %s is not a neighbor!\n",
- GCP_2s (peer));
- return GNUNET_SYSERR;
- }
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "peer %s ok, has %u connections.\n",
- GCP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
-
- return GNUNET_CONTAINER_multihashmap_remove (peer->connections,
- GCC_get_h (c),
- c);
+ "Removing connection %s\n",
+ GCC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "from peer %s\n",
+ GCP_2s (peer));
+ if ( (NULL == peer) ||
+ (NULL == peer->connections) )
+ return;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (peer->connections,
+ GCC_get_h (c),
+ c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s remains with %u connections.\n",
+ GCP_2s (peer),
+ GNUNET_CONTAINER_multihashmap_size (peer->connections));
}
+
/**
* Start the DHT search for new paths towards the peer: we don't have
* enough good connections.
const struct GNUNET_PeerIdentity *id;
struct CadetTunnel *t = peer->tunnel;
- if (NULL != peer->search_h)
+ GCC_check_connections ();
+ if (NULL != peer->search_h)
{
GNUNET_break (0);
return;
{
GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
}
+ GCC_check_connections ();
}
void
GCP_stop_search (struct CadetPeer *peer)
{
+ GCC_check_connections ();
if (NULL != peer->search_h)
{
GCD_search_stop (peer->search_h);
GNUNET_SCHEDULER_cancel (peer->search_delayed);
peer->search_delayed = NULL;
}
+ GCC_check_connections ();
}
struct CadetTunnel *
GCP_get_tunnel (const struct CadetPeer *peer)
{
+ if (NULL == peer)
+ return NULL;
return peer->tunnel;
}
* @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;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer));
+ GCC_check_connections ();
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer));
if (NULL == hello)
return;
if (NULL == old)
{
size = GNUNET_HELLO_size (hello);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " new (%u bytes)\n", size);
peer->hello = GNUNET_malloc (size);
memcpy (peer->hello, hello, size);
}
else
{
peer->hello = GNUNET_HELLO_merge (old, hello);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " merge into %p (%u bytes)\n",
- peer->hello, GNUNET_HELLO_size (hello));
GNUNET_free (old);
}
+ GCC_check_connections ();
}
if (NULL == transport_handle)
return;
-
+ GCC_check_connections ();
+ if (GNUNET_YES == GCP_is_neighbor (peer))
+ return;
hello = GCP_get_hello (peer);
if (NULL == hello)
return;
mh = GNUNET_HELLO_get_header (hello);
- GNUNET_TRANSPORT_offer_hello (transport_handle, mh, try_connect, peer);
-}
-
-
-/**
- * Check if the given ECDH key is correct for the peer.
- *
- * This function caches the results if the key has been previoulsy checked,
- * otherwise checks that the key is signed with the peer's ID (EdDSA key).
- *
- * TODO: save the cached public key to permanent storage / peerinfo.
- *
- * @param peer Peer whose key to check.
- * @param key ECDH key to check.
- * @param purpose Purpose of the signature (followed by the key).
- * @param sig Signature with the peer's EdDSA key (PeerID).
- */
-int
-GCP_check_key (struct CadetPeer *peer,
- const struct GNUNET_CRYPTO_EcdhePublicKey *key,
- const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- const struct GNUNET_CRYPTO_EddsaSignature *sig)
-{
- struct GNUNET_CRYPTO_EddsaPublicKey *pub;
- int verified;
-
- /* Is it the same as the cached key? */
- if (0 == memcmp (&peer->ax_key, key, sizeof (*key)))
- return GNUNET_OK;
-
- /* New key, verify. */
- pub = (struct GNUNET_CRYPTO_EddsaPublicKey *) GCP_get_id (peer);
- verified = GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_CADET_AXKX,
- purpose, sig, pub);
-
- if (GNUNET_OK != verified)
- return GNUNET_SYSERR;
-
- /* Cache key for later. */
- peer->ax_key = *key;
- return GNUNET_OK;
+ 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 ();
}
*/
void
GCP_notify_broken_link (struct CadetPeer *peer,
- struct GNUNET_PeerIdentity *peer1,
- struct GNUNET_PeerIdentity *peer2)
+ const struct GNUNET_PeerIdentity *peer1,
+ const struct GNUNET_PeerIdentity *peer2)
{
struct CadetPeerPath *iter;
struct CadetPeerPath *next;
GNUNET_PEER_Id p1;
GNUNET_PEER_Id p2;
+ GCC_check_connections ();
p1 = GNUNET_PEER_search (peer1);
p2 = GNUNET_PEER_search (peer2);
}
}
}
+ GCC_check_connections ();
}
}
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param peer Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param cls Closure for @a callback.
+ *
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths (struct CadetPeer *peer,
+ GCP_path_iterator callback,
+ void *cls)
+{
+ struct CadetPeerPath *iter;
+ unsigned int i;
+
+ for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
+ {
+ i++;
+ if (GNUNET_YES != callback (cls, peer, iter))
+ break;
+ }
+
+ return i;
+}
+
+
/**
* Iterate all known peers.
*
* @param cls Closure for @c iter.
*/
void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+ void *cls)
{
- GNUNET_CONTAINER_multipeermap_iterate (peers, iter, cls);
+ GCC_check_connections ();
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ iter,
+ cls);
+ GCC_check_connections ();
}
return "(NULL)";
return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id));
}
+
+
+/* end of gnunet-service-cadet_peer.c */