#include "platform.h"
#include "gnunet_util_lib.h"
+#include "gnunet_transport_service.h"
#include "gnunet_core_service.h"
#include "gnunet_statistics_service.h"
* How many messages are in the queue to this peer.
*/
unsigned int queue_n;
+
+ /**
+ * Hello message.
+ */
+ struct GNUNET_HELLO_Message* hello;
};
*/
static struct GNUNET_CORE_Handle *core_handle;
+static struct GNUNET_TRANSPORT_Handle *transport_handle;
+
/******************************************************************************/
/***************************** CORE CALLBACKS *********************************/
}
+/**
+ * Remove the direct path to the peer.
+ *
+ * @param peer Peer to remove the direct path from.
+ *
+ */
+static struct MeshPeerPath *
+pop_direct_path (struct MeshPeer *peer)
+{
+ struct MeshPeerPath *iter;
+
+ for (iter = peer->path_head; NULL != iter; iter = iter->next)
+ {
+ if (2 <= iter->length)
+ {
+ GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
+ return iter;
+ }
+ }
+ return NULL;
+}
+
+
+
/**
* Method called whenever a given peer connects.
*
core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
{
struct MeshPeer *p;
+ struct MeshPeerPath *direct_path;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer disconnected\n");
p = GNUNET_CONTAINER_multipeermap_get (peers, peer);
else
LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GMP_2s (p));
-
+ direct_path = pop_direct_path (p);
GNUNET_CONTAINER_multihashmap_iterate (p->connections, ¬ify_broken, p);
GNUNET_CONTAINER_multihashmap_destroy (p->connections);
p->connections = NULL;
}
GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
+ path_destroy (direct_path);
return;
}
/******************************** STATIC ***********************************/
/******************************************************************************/
+
+/**
+ * Get priority for a queued message.
+ *
+ * @param q Queued message
+ *
+ * @return CORE priority to use.
+ */
+static enum GNUNET_CORE_Priority
+get_priority (struct MeshPeerQueue *q)
+{
+ enum GNUNET_CORE_Priority low;
+ enum GNUNET_CORE_Priority high;
+
+ if (NULL == q)
+ {
+ GNUNET_break (0);
+ return GNUNET_CORE_PRIO_BACKGROUND;
+ }
+
+ /* Relayed traffic has lower priority, our own traffic has higher */
+ if (NULL == q->c || GNUNET_NO == GMC_is_origin (q->c, q->fwd))
+ {
+ low = GNUNET_CORE_PRIO_BEST_EFFORT;
+ high = GNUNET_CORE_PRIO_URGENT;
+ }
+ else
+ {
+ low = GNUNET_CORE_PRIO_URGENT;
+ high = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
+ }
+
+ /* Bulky payload has lower priority, control traffic has higher. */
+ if (GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED == 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
*
}
+
/**
* Core callback to write a queued packet to core buffer
*
LOG (GNUNET_ERROR_TYPE_DEBUG, "* not enough room, reissue\n");
peer->core_transmit =
GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO,
- 0,
+ GNUNET_NO, get_priority (queue),
GNUNET_TIME_UNIT_FOREVER_REL,
dst_id,
queue->size,
case GNUNET_MESSAGE_TYPE_MESH_KX:
case GNUNET_MESSAGE_TYPE_MESH_ACK:
case GNUNET_MESSAGE_TYPE_MESH_POLL:
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "* raw: %s\n",
- GM_m2s (queue->type));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "* raw: %s\n", GM_m2s (queue->type));
data_size = send_core_data_raw (queue->cls, size, buf);
break;
case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
if (NULL == peer->core_transmit)
{
peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready(core_handle,
- 0,
- 0,
- GNUNET_TIME_UNIT_FOREVER_REL,
- dst_id,
- queue->size,
- &queue_send,
- peer);
+ GNUNET_CORE_notify_transmit_ready (core_handle,
+ GNUNET_NO, get_priority (queue),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ dst_id,
+ queue->size,
+ &queue_send,
+ peer);
queue->start_waiting = GNUNET_TIME_absolute_get ();
}
else
struct MeshPeer *peer;
peer = queue->peer;
- GNUNET_assert (NULL != queue->c);
if (GNUNET_YES == clear_cls)
{
* build the message to be sent if not already prebuilt.
* @param type Type of the message, 0 for a raw message.
* @param size Size of the message.
- * @param c Connection this message belongs to (cannot be NULL).
+ * @param c Connection this message belongs to (can be NULL).
* @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
* @param cont Continuation to be called once CORE has taken the message.
* @param cont_cls Closure for @c cont.
int priority;
int call_core;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_INFO,
"queue add %s %s towards %s (size %u) on c %p (%s)\n",
GM_f2s (fwd), GM_m2s (type), GMP_2s(peer),
size, c, GMC_2s (c));
- GNUNET_assert (NULL != c);
if (NULL == peer->connections)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority);
- call_core = GMC_is_sendable (c, fwd);
- queue = GNUNET_malloc (sizeof (struct MeshPeerQueue));
+ call_core = NULL == c ? GNUNET_YES : GMC_is_sendable (c, fwd);
+ queue = GNUNET_new (struct MeshPeerQueue);
queue->cls = cls;
queue->type = type;
queue->size = size;
GMP_2s (peer), size);
peer->core_transmit =
GNUNET_CORE_notify_transmit_ready (core_handle,
- 0,
- 0,
+ GNUNET_NO, get_priority (queue),
GNUNET_TIME_UNIT_FOREVER_REL,
GNUNET_PEER_resolve2 (peer->id),
size,
size = q->size;
peer->core_transmit =
GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO,
- 0,
+ GNUNET_NO, get_priority (q),
GNUNET_TIME_UNIT_FOREVER_REL,
GNUNET_PEER_resolve2 (peer->id),
size,
NULL, /* Don't notify about all outbound messages */
GNUNET_NO, /* For header-only out notification */
core_handlers); /* Register these handlers */
- if (NULL == core_handle)
+ transport_handle = GNUNET_TRANSPORT_connect (c, &my_full_id,
+ NULL, /* cls */
+ NULL, NULL, NULL); /* Notify callbacks */
+
+ if (NULL == core_handle || NULL == transport_handle)
{
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
return;
}
+
}
/**
GNUNET_CORE_disconnect (core_handle);
core_handle = NULL;
}
+ if (transport_handle != NULL)
+ {
+ GNUNET_TRANSPORT_disconnect (transport_handle);
+ transport_handle = NULL;
+ }
GNUNET_PEER_change_rc (myid, -1);
}
}
+/**
+ * Try to connect to a peer on transport level.
+ *
+ * @param cls Closure (peer).
+ * @param tc TaskContext.
+ */
+static void
+try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct MeshPeer *peer = cls;
+
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+
+ GNUNET_TRANSPORT_try_connect (transport_handle,
+ GNUNET_PEER_resolve2 (peer->id), NULL, NULL);
+}
+
/**
* Try to establish a new connection to this peer (in its tunnel).
* If the peer doesn't have any path to it yet, try to get one.
struct MeshTunnel3 *t;
struct MeshPeerPath *p;
struct MeshConnection *c;
+ struct GNUNET_HELLO_Message *hello;
int rerun_search;
LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GMP_2s (peer));
+
+ /* If we have a current hello, try to connect using it. */
+ hello = GMP_get_hello (peer);
+ if (NULL != hello)
+ {
+ struct GNUNET_MessageHeader *mh;
+
+ mh = GNUNET_HELLO_get_header (hello);
+ GNUNET_TRANSPORT_offer_hello (transport_handle, mh, try_connect, peer);
+ }
+
t = peer->tunnel;
c = NULL;
rerun_search = GNUNET_NO;
}
-/**
- * Set tunnel.
- *
- * @param peer Peer.
- * @param t Tunnel.
- */
-void
-GMP_set_tunnel (struct MeshPeer *peer, struct MeshTunnel3 *t)
-{
- peer->tunnel = t;
-}
-
-
/**
* Chech whether there is a direct (core level) connection to peer.
*
return GNUNET_YES;
}
- GNUNET_break (0); /* Is not a neighbor but connections is not NULL */
+ /* Is not a neighbor but connections is not NULL, probably disconnecting */
return GNUNET_NO;
}
GMP_add_connection (struct MeshPeer *peer,
struct MeshConnection *c)
{
+ int result;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "adding connection %s\n", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "to peer %s\n", GMP_2s (peer));
+
if (NULL == peer->connections)
{
GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s is not a neighbor!\n",
+ GMP_2s (peer));
return GNUNET_SYSERR;
}
- return GNUNET_CONTAINER_multihashmap_put (peer->connections,
- GMC_get_id (c),
- c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "peer %s ok, has %u connections.\n",
+ GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
+ result = GNUNET_CONTAINER_multihashmap_put (peer->connections,
+ GMC_get_id (c),
+ c,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " now has %u connections.\n",
+ GNUNET_CONTAINER_multihashmap_size (peer->connections));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "result %u\n", result);
+
+ return result;
}
GMP_remove_connection (struct MeshPeer *peer,
const struct MeshConnection *c)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "removing connection %s from peer %s\n",
- GMC_2s (c), GMP_2s (peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "removing connection %s\n", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "from peer %s\n", GMP_2s (peer));
+
if (NULL == peer || NULL == peer->connections)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
GMP_2s (peer));
return GNUNET_SYSERR;
}
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "peer %s ok, has %u connections.\n",
+ GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
+
return GNUNET_CONTAINER_multihashmap_remove (peer->connections,
GMC_get_id (c),
c);
}
+/**
+ * Set tunnel.
+ *
+ * @param peer Peer.
+ * @param t Tunnel.
+ */
+void
+GMP_set_tunnel (struct MeshPeer *peer, struct MeshTunnel3 *t)
+{
+ peer->tunnel = t;
+}
+
+
/**
* Get the tunnel towards a peer.
*
struct MeshTunnel3 *
GMP_get_tunnel (const struct MeshPeer *peer)
{
- GNUNET_assert (NULL != peer->tunnel);
return peer->tunnel;
}
+/**
+ * Set the hello message.
+ *
+ * @param peer Peer whose message to set.
+ * @param hello Hello message.
+ */
+void
+GMP_set_hello (struct MeshPeer *peer, const struct GNUNET_HELLO_Message *hello)
+{
+ struct GNUNET_HELLO_Message *old;
+ size_t size;
+
+ old = GMP_get_hello (peer);
+ if (NULL == old)
+ {
+ size = GNUNET_HELLO_size (hello);
+ peer->hello = GNUNET_malloc (size);
+ memcpy (peer->hello, hello, size);
+ return;
+ }
+ else
+ {
+ peer->hello = GNUNET_HELLO_merge (old, hello);
+ GNUNET_free (old);
+ }
+}
+
+
+/**
+ * Get the hello message.
+ *
+ * @param peer Peer whose message to get.
+ *
+ * @return Hello message.
+ */
+struct GNUNET_HELLO_Message *
+GMP_get_hello (struct MeshPeer *peer)
+{
+ struct GNUNET_TIME_Absolute expiration;
+ struct GNUNET_TIME_Relative remaining;
+
+ if (NULL == peer->hello)
+ return NULL;
+
+ expiration = GNUNET_HELLO_get_last_expiration (peer->hello);
+ remaining = GNUNET_TIME_absolute_get_remaining (expiration);
+ if (0 == remaining.rel_value_us)
+ {
+ GNUNET_free (peer->hello);
+ peer->hello = NULL;
+ }
+ return peer->hello;
+}
+
+
+/**
+ * Count the number of known paths toward the peer.
+ *
+ * @param peer Peer to get path info.
+ *
+ * @return Number of known paths.
+ */
+unsigned int
+GMP_count_paths (const struct MeshPeer *peer)
+{
+ struct MeshPeerPath *iter;
+ unsigned int i;
+
+ for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
+ i++;
+
+ return i;
+}
+
+
+/**
+ * Iterate all known peers.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
+{
+ GNUNET_CONTAINER_multipeermap_iterate (peers, iter, cls);
+}
+
+
/**
* Get the static string for a peer ID.
*