#include "platform.h"
#include "gnunet_util_lib.h"
-#include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
+#include "mesh_path.h"
+#include "mesh_protocol_enc.h"
+#include "mesh_enc.h"
#include "gnunet-service-mesh_connection.h"
#include "gnunet-service-mesh_peer.h"
-#include "gnunet-service-mesh_local.h"
-#include "mesh_protocol_enc.h"
-#include "mesh_path.h"
+#include "gnunet-service-mesh_tunnel.h"
+#include "gnunet-service-mesh_channel.h"
-#define MESH_DEBUG_CONNECTION GNUNET_NO
+#define LOG(level, ...) GNUNET_log_from (level,"mesh-con",__VA_ARGS__)
+
#define MESH_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\
GNUNET_TIME_UNIT_MINUTES,\
10)
-#define MESH_RETRANSMIT_TIME GNUNET_TIME_UNIT_SECONDS
-#define MESH_RETRANSMIT_MARGIN 4
-
-
-#if MESH_DEBUG_CONNECTION
-#define DEBUG_CONN(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
-#else
-#define DEBUG_CONN(...)
-#endif
-
-
-/**
- * All the states a connection can be in.
- */
-enum MeshConnectionState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- MESH_CONNECTION_NEW,
-
- /**
- * Connection create message sent, waiting for ACK.
- */
- MESH_CONNECTION_SENT,
-
- /**
- * Connection ACK sent, waiting for ACK.
- */
- MESH_CONNECTION_ACK,
-
- /**
- * Connection confirmed, ready to carry traffic.
- */
- MESH_CONNECTION_READY,
-};
-
-
-
-/**
- * Struct containing info about a queued transmission to this peer
- */
-struct MeshPeerQueue
-{
- /**
- * DLL next
- */
- struct MeshPeerQueue *next;
-
- /**
- * DLL previous
- */
- struct MeshPeerQueue *prev;
-
- /**
- * Peer this transmission is directed to.
- */
- struct MeshPeer *peer;
-
- /**
- * Connection this message belongs to.
- */
- struct MeshConnection *c;
-
- /**
- * Is FWD in c?
- */
- int fwd;
+#define AVG_MSGS 32
- /**
- * Channel this message belongs to, if known.
- */
- struct MeshChannel *ch;
-
- /**
- * Pointer to info stucture used as cls.
- */
- void *cls;
-
- /**
- * Type of message
- */
- uint16_t type;
-
- /**
- * Size of the message
- */
- size_t size;
-};
+/******************************************************************************/
+/******************************** STRUCTS **********************************/
+/******************************************************************************/
/**
* Struct to encapsulate all the Flow Control information to a peer to which
struct GNUNET_TIME_Relative poll_time;
};
-
/**
- * Struct containing all information regarding a connection to a peer.
+ * Keep a record of the last messages sent on this connection.
*/
-struct MeshConnection
+struct MeshConnectionPerformance
{
/**
- * DLL
+ * Circular buffer for storing measurements.
+ */
+ double usecsperbyte[AVG_MSGS];
+
+ /**
+ * Running average of @c usecsperbyte.
*/
- struct MeshConnection *next;
- struct MeshConnection *prev;
+ double avg;
+
+ /**
+ * How many values of @c usecsperbyte are valid.
+ */
+ uint16_t size;
+
+ /**
+ * Index of the next "free" position in @c usecsperbyte.
+ */
+ uint16_t idx;
+};
+
+/**
+ * Struct containing all information regarding a connection to a peer.
+ */
+struct MeshConnection
+{
/**
* Tunnel this connection is part of.
*/
- struct MeshTunnel2 *t;
+ struct MeshTunnel3 *t;
/**
* Flow control information for traffic fwd.
*/
struct MeshFlowControl bck_fc;
+ /**
+ * Measure connection performance on the endpoint.
+ */
+ struct MeshConnectionPerformance *perf;
+
/**
* ID of the connection.
*/
int destroy;
};
+/******************************************************************************/
+/******************************* GLOBALS ***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
+/**
+ * Local peer own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
/**
* Connections known, indexed by cid (MeshConnection).
*/
static struct GNUNET_TIME_Relative refresh_connection_time;
-/**
- * Handle to communicate with core.
- */
-static struct GNUNET_CORE_Handle *core_handle;
+
+/******************************************************************************/
+/******************************** STATIC ***********************************/
+/******************************************************************************/
#if 0 // avoid compiler warning for unused static function
static void
fc_debug (struct MeshFlowControl *fc)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n",
fc->last_pid_recv, fc->last_ack_sent);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n",
fc->last_pid_sent, fc->last_ack_recv);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n",
fc->queue_n, fc->queue_max);
}
{
if (NULL == c)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CONNECTION ***\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CONNECTION ***\n");
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n",
peer2s (c->t->peer), GNUNET_h2s (&c->id));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n",
c->state, c->pending_messages);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
fc_debug (&c->fwd_fc);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
fc_debug (&c->bck_fc);
}
#endif
* @return String representation.
*/
static const char *
-GMC_DEBUG_state2s (enum MeshTunnelState s)
+GMC_state2s (enum MeshConnectionState s)
{
switch (s)
{
}
-
/**
* Initialize a Flow Control structure to the initial state.
*
}
+static void
+connection_change_state (struct MeshConnection* c,
+ enum MeshConnectionState state)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection %s state was %s\n",
+ GNUNET_h2s (&c->id), GMC_state2s (c->state));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection %s state is now %s\n",
+ GNUNET_h2s (&c->id), GMC_state2s (state));
+ c->state = state;
+}
+
+
/**
- * Sends an already built message on a connection, properly registering
- * all used resources.
+ * Callback called when a queued message is sent.
*
- * @param message Message to send. Function makes a copy of it.
- * If message is not hop-by-hop, decrements TTL of copy.
- * @param c Connection on which this message is transmitted.
- * @param ch Channel on which this message is transmitted, or NULL.
- * @param fwd Is this a fwd message?
+ * Calculates the average time and connection packet tracking.
+ *
+ * @param cls Closure.
+ * @param c Connection this message was on.
+ * @param type Type of message sent.
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ * @param wait Time spent waiting for core (only the time for THIS message)
*/
-static void
-send_prebuilt_message_connection (const struct GNUNET_MessageHeader *message,
- struct MeshConnection *c,
- struct MeshChannel *ch,
- int fwd)
+static void
+message_sent (void *cls,
+ struct MeshConnection *c, uint16_t type,
+ int fwd, size_t size,
+ struct GNUNET_TIME_Relative wait)
{
- void *data;
- size_t size;
- uint16_t type;
-
- size = ntohs (message->size);
- data = GNUNET_malloc (size);
- memcpy (data, message, size);
- type = ntohs (message->type);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send %s (%u) on connection %s\n",
- GNUNET_MESH_DEBUG_M2S (type), size, GNUNET_h2s (&c->id));
+ struct MeshConnectionPerformance *p;
+ struct MeshFlowControl *fc;
+ double usecsperbyte;
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n);
+ fc->queue_n--;
+ c->pending_messages--;
+ if (GNUNET_YES == c->destroy && 0 == c->pending_messages)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! destroying connection!\n");
+ GMC_destroy (c);
+ }
+ /* Send ACK if needed, after accounting for sent ID in fc->queue_n */
switch (type)
{
- struct GNUNET_MESH_Encrypted *emsg;
- struct GNUNET_MESH_ACK *amsg;
- struct GNUNET_MESH_Poll *pmsg;
- struct GNUNET_MESH_ConnectionDestroy *dmsg;
- struct GNUNET_MESH_ConnectionBroken *bmsg;
- uint32_t ttl;
-
- case GNUNET_MESSAGE_TYPE_MESH_FWD:
- case GNUNET_MESSAGE_TYPE_MESH_BCK:
- emsg = (struct GNUNET_MESH_Encrypted *) data;
- ttl = ntohl (emsg->ttl);
- if (0 == ttl)
- {
- GNUNET_break_op (0);
- return;
- }
- emsg->cid = c->id;
- emsg->ttl = htonl (ttl - 1);
- emsg->pid = htonl (fwd ? c->fwd_fc.next_pid++ : c->bck_fc.next_pid++);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " pid %u\n", ntohl (emsg->pid));
+ case GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED:
+ fc->last_pid_sent++;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! accounting pid %u\n", fc->last_pid_sent);
+// send_ack (c, ch, fwd);
break;
-
- case GNUNET_MESSAGE_TYPE_MESH_ACK:
- amsg = (struct GNUNET_MESH_ACK *) data;
- amsg->cid = c->id;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ntohl (amsg->ack));
+ default:
break;
+ }
- case GNUNET_MESSAGE_TYPE_MESH_POLL:
- pmsg = (struct GNUNET_MESH_Poll *) data;
- pmsg->cid = c->id;
- pmsg->pid = htonl (fwd ? c->fwd_fc.last_pid_sent : c->bck_fc.last_pid_sent);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid));
- break;
+ if (NULL == c->perf)
+ return; /* Only endpoints are interested in timing. */
- case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
- dmsg = (struct GNUNET_MESH_ConnectionDestroy *) data;
- dmsg->cid = c->id;
- dmsg->reserved = 0;
- break;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n");
+ p = c->perf;
+ usecsperbyte = ((double) wait.rel_value_us) / size;
+ if (p->size == AVG_MSGS)
+ {
+ /* Array is full. Substract oldest value, add new one and store. */
+ p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS);
+ p->usecsperbyte[p->idx] = usecsperbyte;
+ p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS);
+ }
+ else
+ {
+ /* Array not yet full. Add current value to avg and store. */
+ p->usecsperbyte[p->idx] = usecsperbyte;
+ p->avg *= p->size;
+ p->avg += p->usecsperbyte[p->idx];
+ p->size++;
+ p->avg /= p->size;
+ }
+ p->idx = (p->idx + 1) % AVG_MSGS;
+
+// if (NULL != c->t)
+// {
+// c->t->pending_messages--;
+// if (GNUNET_YES == c->t->destroy && 0 == t->pending_messages)
+// {
+// LOG (GNUNET_ERROR_TYPE_DEBUG, "* destroying tunnel!\n");
+// GMT_destroy (c->t);
+// }
+// }
+}
- case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN:
- bmsg = (struct GNUNET_MESH_ConnectionBroken *) data;
- bmsg->cid = c->id;
- bmsg->reserved = 0;
- break;
- case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK:
- break;
+/**
+ * Get the previous hop in a connection
+ *
+ * @param c Connection.
+ *
+ * @return Previous peer in the connection.
+ */
+static struct MeshPeer *
+get_prev_hop (const struct MeshConnection *c)
+{
+ GNUNET_PEER_Id id;
+
+ if (0 == c->own_pos || c->path->length < 2)
+ id = c->path->peers[0];
+ else
+ id = c->path->peers[c->own_pos - 1];
+
+ return GMP_get_short (id);
+}
+
+
+/**
+ * Get the next hop in a connection
+ *
+ * @param c Connection.
+ *
+ * @return Next peer in the connection.
+ */
+static struct MeshPeer *
+get_next_hop (const struct MeshConnection *c)
+{
+ GNUNET_PEER_Id id;
+
+ if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
+ id = c->path->peers[c->path->length - 1];
+ else
+ id = c->path->peers[c->own_pos + 1];
+
+ return GMP_get_short (id);
+}
- default:
- GNUNET_break (0);
- }
- queue_add (data,
- type,
- size,
- c,
- ch,
- fwd);
+/**
+ * Get the hop in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Next hop?
+ *
+ * @return Next peer in the connection.
+ */
+static struct MeshPeer *
+get_hop (struct MeshConnection *c, int fwd)
+{
+ if (fwd)
+ return get_next_hop (c);
+ return get_prev_hop (c);
}
+
/**
* Send an ACK informing the predecessor about the available buffer space.
*
next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"connection send %s ack on %s\n",
fwd ? "FWD" : "BCK", GNUNET_h2s (&c->id));
/* Check if we need to transmit the ACK */
- if (prev_fc->last_ack_sent - prev_fc->last_pid_recv > 3)
+ delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv;
+ if (3 < delta && buffer < delta)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " last pid recv: %u, last ack sent: %u\n",
- prev_fc->last_pid_recv, prev_fc->last_ack_sent);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " last pid recv: %u, last ack sent: %u\n",
+ prev_fc->last_pid_recv, prev_fc->last_ack_sent);
return;
}
/* Ok, ACK might be necessary, what PID to ACK? */
- delta = next_fc->queue_max - next_fc->queue_n;
- ack = prev_fc->last_pid_recv + delta;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " last pid %u, last ack %u, qmax %u, q %u\n",
- prev_fc->last_pid_recv, prev_fc->last_ack_sent,
- next_fc->queue_max, next_fc->queue_n);
+ ack = prev_fc->last_pid_recv + buffer;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " last pid %u, last ack %u, qmax %u, q %u\n",
+ prev_fc->last_pid_recv, prev_fc->last_ack_sent,
+ next_fc->queue_max, next_fc->queue_n);
if (ack == prev_fc->last_ack_sent)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
return;
}
msg.ack = htonl (ack);
msg.cid = c->id;
- send_prebuilt_message_connection (&msg.header, c, NULL, !fwd);
+ GMC_send_prebuilt_message (&msg.header, c, NULL, !fwd);
}
/**
* Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE
- * directed to us.
+ * or a first CONNECTION_ACK directed to us.
*
* @param connection Connection to confirm.
* @param fwd Is this a fwd ACK? (First is bck (SYNACK), second is fwd (ACK))
static void
send_connection_ack (struct MeshConnection *connection, int fwd)
{
- struct MeshTunnel2 *t;
+ struct MeshTunnel3 *t;
t = connection->t;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send connection ack\n");
- queue_add (NULL,
- GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK,
- sizeof (struct GNUNET_MESH_ConnectionACK),
- connection,
- NULL,
- fwd);
- if (MESH_TUNNEL_NEW == t->state)
- tunnel_change_state (t, MESH_TUNNEL_WAITING);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Send connection ack\n");
+ GMP_queue_add (get_hop (connection, fwd), NULL,
+ GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK,
+ sizeof (struct GNUNET_MESH_ConnectionACK),
+ connection, NULL, fwd,
+ &message_sent, NULL);
+ if (MESH_TUNNEL3_NEW == GMT_get_state (t))
+ GMT_change_state (t, MESH_TUNNEL3_WAITING);
if (MESH_CONNECTION_READY != connection->state)
connection_change_state (connection, MESH_CONNECTION_SENT);
}
-/**
- * Sends a CREATE CONNECTION message for a path to a peer.
- * Changes the connection and tunnel states if necessary.
- *
- * @param connection Connection to create.
- */
-static void
-send_connection_create (struct MeshConnection *connection)
-{
- struct MeshTunnel2 *t;
-
- t = connection->t;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send connection create\n");
- queue_add (NULL,
- GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE,
- sizeof (struct GNUNET_MESH_ConnectionCreate) +
- (connection->path->length *
- sizeof (struct GNUNET_PeerIdentity)),
- connection,
- NULL,
- GNUNET_YES);
- if (NULL != t &&
- (MESH_TUNNEL_SEARCHING == t->state || MESH_TUNNEL_NEW == t->state))
- tunnel_change_state (t, MESH_TUNNEL_WAITING);
- if (MESH_CONNECTION_NEW == connection->state)
- connection_change_state (connection, MESH_CONNECTION_SENT);
-}
-
-
-static void
-connection_change_state (struct MeshConnection* c,
- enum MeshConnectionState state)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s state was %s\n",
- GNUNET_h2s (&c->id), GNUNET_MESH_DEBUG_CS2S (c->state));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s state is now %s\n",
- GNUNET_h2s (&c->id), GNUNET_MESH_DEBUG_CS2S (state));
- c->state = state;
-}
-
-
-
/**
* Send keepalive packets for a connection.
*
type = fwd ? GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE :
GNUNET_MESSAGE_TYPE_MESH_BCK_KEEPALIVE;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "sending %s keepalive for connection %s[%d]\n",
- fwd ? "FWD" : "BCK",
- peer2s (c->t->peer),
- c->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "sending %s keepalive for connection %s[%d]\n",
+ fwd ? "FWD" : "BCK", GMT_2s (c->t), c->id);
msg = (struct GNUNET_MESH_ConnectionKeepAlive *) cbuf;
msg->header.size = htons (size);
msg->header.type = htons (type);
msg->cid = c->id;
- send_prebuilt_message_connection (&msg->header, c, NULL, fwd);
+ GMC_send_prebuilt_message (&msg->header, c, NULL, fwd);
}
static void
connection_recreate (struct MeshConnection *c, int fwd)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n");
if (fwd)
- send_connection_create (c);
+ GMC_send_create (c);
else
send_connection_ack (c, GNUNET_NO);
}
static void
connection_maintain (struct MeshConnection *c, int fwd)
{
- if (MESH_TUNNEL_SEARCHING == c->t->state)
+ if (MESH_TUNNEL3_SEARCHING == GMT_get_state (c->t))
{
/* TODO DHT GET with RO_BART */
return;
/**
- * Send a message to all peers in this connection that the connection
- * is no longer valid.
+ * @brief Re-initiate traffic on this connection if necessary.
*
- * If some peer should not receive the message, it should be zero'ed out
- * before calling this function.
+ * Check if there is traffic queued towards this peer
+ * and the core transmit handle is NULL (traffic was stalled).
+ * If so, call core tmt rdy.
*
- * @param c The connection whose peers to notify.
+ * @param c Connection on which initiate traffic.
+ * @param fwd Is this about fwd traffic?
*/
static void
-connection_send_destroy (struct MeshConnection *c)
-{
- struct GNUNET_MESH_ConnectionDestroy msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY);;
- msg.cid = c->id;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " sending connection destroy for connection %s[%X]\n",
- peer2s (c->t->peer),
- c->id);
-
- if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES))
- send_prebuilt_message_connection (&msg.header, c, NULL, GNUNET_YES);
- if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO))
- send_prebuilt_message_connection (&msg.header, c, NULL, GNUNET_NO);
- c->destroy = GNUNET_YES;
-}
-
-
-/**
- * Get free buffer space in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - max_msgs_queue/max_connections]
- */
-static unsigned int
-connection_get_buffer (struct MeshConnection *c, int fwd)
-{
- struct MeshFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
- return (fc->queue_max - fc->queue_n);
-}
-
-
-/**
- * Get the first transmittable message for a connection.
- *
- * @param c Connection.
- * @param fwd Is this FWD?
- *
- * @return First transmittable message.
- */
-static struct MeshPeerQueue *
-connection_get_first_message (struct MeshConnection *c, int fwd)
-{
- struct MeshPeerQueue *q;
- struct MeshPeer *p;
-
- p = connection_get_hop (c, fwd);
-
- for (q = p->queue_head; NULL != q; q = q->next)
- {
- if (q->c != c)
- continue;
- if (queue_is_sendable (q))
- return q;
- }
-
- return NULL;
-}
-
-
-/**
- * @brief Re-initiate traffic on this connection if necessary.
- *
- * Check if there is traffic queued towards this peer
- * and the core transmit handle is NULL (traffic was stalled).
- * If so, call core tmt rdy.
- *
- * @param c Connection on which initiate traffic.
- * @param fwd Is this about fwd traffic?
- */
-static void
-connection_unlock_queue (struct MeshConnection *c, int fwd)
+connection_unlock_queue (struct MeshConnection *c, int fwd)
{
struct MeshPeer *peer;
- struct MeshPeerQueue *q;
- size_t size;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"connection_unlock_queue %s on %s\n",
fwd ? "FWD" : "BCK", GNUNET_h2s (&c->id));
if (GMC_is_terminal (c, fwd))
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " is terminal!\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " is terminal!\n");
return;
}
- peer = connection_get_hop (c, fwd);
-
- if (NULL != peer->core_transmit)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n");
- return; /* Already unlocked */
- }
-
- q = connection_get_first_message (c, fwd);
- if (NULL == q)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " queue empty!\n");
- return; /* Nothing to transmit */
- }
-
- size = q->size;
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO,
- 0,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_PEER_resolve2 (peer->id),
- size,
- &queue_send,
- peer);
+ peer = get_hop (c, fwd);
+ GMP_queue_unlock (peer, c);
}
static void
connection_cancel_queues (struct MeshConnection *c, int fwd)
{
- struct MeshPeerQueue *q;
- struct MeshPeerQueue *next;
+
struct MeshFlowControl *fc;
struct MeshPeer *peer;
GNUNET_break (0);
return;
}
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- peer = connection_get_hop (c, fwd);
- for (q = peer->queue_head; NULL != q; q = next)
- {
- next = q->next;
- if (q->c == c)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "connection_cancel_queue %s\n",
- GNUNET_MESH_DEBUG_M2S (q->type));
- queue_destroy (q, GNUNET_YES);
- }
- }
- if (NULL == peer->queue_head)
+ peer = get_hop (c, fwd);
+ GMP_queue_cancel (peer, c);
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
{
- if (NULL != peer->core_transmit)
- {
- GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
- peer->core_transmit = NULL;
- }
- if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
- {
- GNUNET_SCHEDULER_cancel (fc->poll_task);
- fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
- }
+ GNUNET_SCHEDULER_cancel (fc->poll_task);
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
}
}
-
-
/**
* Function called if a connection has been stalled for a while,
* possibly due to a missed ACK. Poll the neighbor about its ACK status.
}
c = fc->c;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** Polling!\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** connection [%X]\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Polling!\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** connection [%X]\n",
GNUNET_h2s (&c->id));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** %s\n",
fc == &c->fwd_fc ? "FWD" : "BCK");
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_POLL);
msg.header.size = htons (sizeof (msg));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** pid (%u)!\n", fc->last_pid_sent);
- send_prebuilt_message_connection (&msg.header, c, NULL, fc == &c->fwd_fc);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** pid (%u)!\n", fc->last_pid_sent);
+ GMC_send_prebuilt_message (&msg.header, c, NULL, fc == &c->fwd_fc);
fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
&connection_poll, fc);
}
-
-
-/**
- * Get the previous hop in a connection
- *
- * @param c Connection.
- *
- * @return Previous peer in the connection.
- */
-static struct MeshPeer *
-connection_get_prev_hop (struct MeshConnection *c)
-{
- GNUNET_PEER_Id id;
-
- if (0 == c->own_pos || c->path->length < 2)
- id = c->path->peers[0];
- else
- id = c->path->peers[c->own_pos - 1];
-
- return peer_get_short (id);
-}
-
-
-/**
- * Get the next hop in a connection
- *
- * @param c Connection.
- *
- * @return Next peer in the connection.
- */
-static struct MeshPeer *
-connection_get_next_hop (struct MeshConnection *c)
-{
- GNUNET_PEER_Id id;
-
- if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
- id = c->path->peers[c->path->length - 1];
- else
- id = c->path->peers[c->own_pos + 1];
-
- return peer_get_short (id);
-}
-
-
-/**
- * Get the hop in a connection.
- *
- * @param c Connection.
- * @param fwd Next hop?
- *
- * @return Next peer in the connection.
- */
-static struct MeshPeer *
-connection_get_hop (struct MeshConnection *c, int fwd)
-{
- if (fwd)
- return connection_get_next_hop (c);
- return connection_get_prev_hop (c);
-}
-
-
-
-
/**
* Timeout function due to lack of keepalive/traffic from the owner.
* Destroys connection if called.
c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"Connection %s[%X] FWD timed out. Destroying.\n",
- peer2s (c->t->peer),
+ GMT_2s (c->t),
c->id);
if (GMC_is_origin (c, GNUNET_YES)) /* If local, leave. */
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"Connection %s[%X] FWD timed out. Destroying.\n",
- peer2s (c->t->peer),
- c->id);
+ GMT_2s (c->t), c->id);
if (GMC_is_origin (c, GNUNET_NO)) /* If local, leave. */
return;
}
-
-
-
/**
- * Method called whenever a given peer connects.
+ * Add the connection to the list of both neighbors.
*
- * @param cls closure
- * @param peer peer identity this notification is about
+ * @param c Connection.
*/
static void
-core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
+register_neighbors (struct MeshConnection *c)
{
- struct MeshPeer *pi;
- struct MeshPeerPath *path;
+ struct MeshPeer *peer;
- DEBUG_CONN ("Peer connected\n");
- DEBUG_CONN (" %s\n", GNUNET_i2s (&my_full_id));
- pi = peer_get (peer);
- if (myid == pi->id)
+ peer = get_next_hop (c);
+ if (GNUNET_NO == GMP_is_neighbor (peer))
{
- DEBUG_CONN (" (self)\n");
- path = path_new (1);
+ GMC_destroy (c);
+ return;
}
- else
+ GMP_add_connection (peer, c);
+ peer = get_prev_hop (c);
+ if (GNUNET_NO == GMP_is_neighbor (peer))
{
- DEBUG_CONN (" %s\n", GNUNET_i2s (peer));
- path = path_new (2);
- path->peers[1] = pi->id;
- GNUNET_PEER_change_rc (pi->id, 1);
- GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
+ GMC_destroy (c);
+ return;
}
- path->peers[0] = myid;
- GNUNET_PEER_change_rc (myid, 1);
- peer_add_path (pi, path, GNUNET_YES);
-
- pi->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
- return;
+ GMP_add_connection (peer, c);
}
/**
- * Method called whenever a peer disconnects.
+ * Remove the connection from the list of both neighbors.
*
- * @param cls closure
- * @param peer peer identity this notification is about
+ * @param c Connection.
*/
static void
-core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+unregister_neighbors (struct MeshConnection *c)
{
- struct MeshPeer *pi;
+ struct MeshPeer *peer;
- DEBUG_CONN ("Peer disconnected\n");
- pi = GNUNET_CONTAINER_multipeermap_get (peers, peer);
- if (NULL == pi)
- {
- GNUNET_break (0);
- return;
- }
+ peer = get_next_hop (c);
+ GMP_remove_connection (peer, c);
- GNUNET_CONTAINER_multihashmap_iterate (pi->connections,
- GMC_notify_broken,
- pi);
- GNUNET_CONTAINER_multihashmap_destroy (pi->connections);
- pi->connections = NULL;
- if (NULL != pi->core_transmit)
- {
- GNUNET_CORE_notify_transmit_ready_cancel (pi->core_transmit);
- pi->core_transmit = NULL;
- }
- if (myid == pi->id)
- {
- DEBUG_CONN (" (self)\n");
- }
- GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
+ peer = get_prev_hop (c);
+ GMP_remove_connection (peer, c);
- return;
}
-
/**
- * To be called on core init/fail.
+ * Bind the connection to the peer and the tunnel to that peer.
*
- * @param cls Closure (config)
- * @param identity the public identity of this peer
+ * If the peer has no tunnel, create one. Update tunnel and connection
+ * data structres to reflect new status.
+ *
+ * @param c Connection.
+ * @param peer Peer.
*/
static void
-core_init (void *cls,
- const struct GNUNET_PeerIdentity *identity)
+add_to_peer (struct MeshConnection *c, struct MeshPeer *peer)
{
- const struct GNUNET_CONFIGURATION_Handle *c = cls;
- static int i = 0;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
- if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n"));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- " core id %s\n",
- GNUNET_i2s (identity));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- " my id %s\n",
- GNUNET_i2s (&my_full_id));
- GNUNET_CORE_disconnect (core_handle);
- core_handle = GNUNET_CORE_connect (c, /* Main configuration */
- NULL, /* Closure passed to MESH functions */
- &core_init, /* Call core_init once connected */
- &core_connect, /* Handle connects */
- &core_disconnect, /* remove peers on disconnects */
- NULL, /* Don't notify about all incoming messages */
- GNUNET_NO, /* For header only in notification */
- NULL, /* Don't notify about all outbound messages */
- GNUNET_NO, /* For header-only out notification */
- core_handlers); /* Register these handlers */
- if (10 < i++)
- GNUNET_abort();
- }
- GML_start ();
- return;
+ GMP_add_tunnel (peer);
+ c->t = GMP_get_tunnel (peer);
+ GMT_add_connection (c->t, c);
}
-
-
-
+/******************************************************************************/
+/******************************** API ***********************************/
+/******************************************************************************/
/**
* Core handler for connection creation.
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
-static int
-handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_ConnectionCreate *msg;
struct GNUNET_PeerIdentity *id;
uint16_t size;
uint16_t i;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a connection create msg\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a connection create msg\n");
/* Check size */
size = ntohs (message->size);
GNUNET_break_op (0);
return GNUNET_OK;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size);
/* Get parameters */
msg = (struct GNUNET_MESH_ConnectionCreate *) message;
cid = &msg->cid;
id = (struct GNUNET_PeerIdentity *) &msg[1];
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
" connection %s (%s).\n",
GNUNET_h2s (cid), GNUNET_i2s (id));
c = connection_get (cid);
if (NULL == c)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
- c = connection_new (cid);
- if (NULL == c)
- return GNUNET_OK;
- connection_reset_timeout (c, GNUNET_YES);
-
/* Create path */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n");
path = path_new (size);
own_pos = 0;
for (i = 0; i < size; i++)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ... adding %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ... adding %s\n",
GNUNET_i2s (&id[i]));
path->peers[i] = GNUNET_PEER_intern (&id[i]);
if (path->peers[i] == myid)
/* create path: self not found in path through self */
GNUNET_break_op (0);
path_destroy (path);
- connection_destroy (c);
return GNUNET_OK;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
- path_add_to_peers (path, GNUNET_NO);
- c->path = path_duplicate (path);
- c->own_pos = own_pos;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
+ GMP_add_path_to_all (path, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
+ c = GMC_new (cid, NULL, path_duplicate (path), own_pos);
+ if (NULL == c)
+ return GNUNET_OK;
+ connection_reset_timeout (c, GNUNET_YES);
}
else
{
connection_change_state (c, MESH_CONNECTION_SENT);
/* Remember peers */
- dest_peer = peer_get (&id[size - 1]);
- orig_peer = peer_get (&id[0]);
+ dest_peer = GMP_get (&id[size - 1]);
+ orig_peer = GMP_get (&id[0]);
/* Is it a connection to us? */
if (c->own_pos == size - 1)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
- peer_add_path_to_origin (orig_peer, path, GNUNET_YES);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
+ GMP_add_path_to_origin (orig_peer, path, GNUNET_YES);
- if (NULL == orig_peer->tunnel)
- {
- orig_peer->tunnel = tunnel_new ();
- orig_peer->tunnel->peer = orig_peer;
- }
- tunnel_add_connection (orig_peer->tunnel, c);
- if (MESH_TUNNEL_NEW == c->t->state)
- tunnel_change_state (c->t, MESH_TUNNEL_WAITING);
+ add_to_peer (c, orig_peer);
+ if (MESH_TUNNEL3_NEW == GMT_get_state (c->t))
+ GMT_change_state (c->t, MESH_TUNNEL3_WAITING);
send_connection_ack (c, GNUNET_NO);
if (MESH_CONNECTION_SENT == c->state)
else
{
/* It's for somebody else! Retransmit. */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n");
- peer_add_path (dest_peer, path_duplicate (path), GNUNET_NO);
- peer_add_path_to_origin (orig_peer, path, GNUNET_NO);
- send_prebuilt_message_connection (message, c, NULL, GNUNET_YES);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n");
+ GMP_add_path (dest_peer, path_duplicate (path), GNUNET_NO);
+ GMP_add_path_to_origin (orig_peer, path, GNUNET_NO);
+ GMC_send_prebuilt_message (message, c, NULL, GNUNET_YES);
}
return GNUNET_OK;
}
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
-static int
-handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_ConnectionACK *msg;
struct MeshConnection *c;
struct MeshPeer *pi;
int fwd;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a connection ACK msg\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a connection ACK msg\n");
msg = (struct GNUNET_MESH_ConnectionACK *) message;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n",
GNUNET_h2s (&msg->cid));
c = connection_get (&msg->cid);
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# control on unknown connection",
1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " don't know the connection!\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " don't know the connection!\n");
return GNUNET_OK;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n",
GNUNET_i2s (peer));
- pi = peer_get (peer);
- if (connection_get_next_hop (c) == pi)
+ pi = GMP_get (peer);
+ if (get_next_hop (c) == pi)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n");
fwd = GNUNET_NO;
if (MESH_CONNECTION_SENT == c->state)
connection_change_state (c, MESH_CONNECTION_ACK);
}
- else if (connection_get_prev_hop (c) == pi)
+ else if (get_prev_hop (c) == pi)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ACK\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK\n");
fwd = GNUNET_YES;
connection_change_state (c, MESH_CONNECTION_READY);
}
p = c->path;
if (NULL != p)
{
- path_add_to_peers (p, GNUNET_YES);
+ GMP_add_path_to_all (p, GNUNET_YES);
}
else
{
}
/* Message for us as creator? */
- if (connection_is_origin (c, GNUNET_YES))
+ if (GMC_is_origin (c, GNUNET_YES))
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n");
connection_change_state (c, MESH_CONNECTION_READY);
- if (MESH_TUNNEL_READY != c->t->state)
- tunnel_change_state (c->t, MESH_TUNNEL_READY);
+ GMT_change_state (c->t, MESH_TUNNEL3_READY);
send_connection_ack (c, GNUNET_YES);
- tunnel_send_queued_data (c->t, GNUNET_YES);
- if (3 <= tunnel_count_connections (c->t) && NULL != c->t->peer->dhtget)
- {
- GNUNET_DHT_get_stop (c->t->peer->dhtget);
- c->t->peer->dhtget = NULL;
- }
+ GMT_send_queued_data (c->t, GNUNET_YES);
return GNUNET_OK;
}
/* Message for us as destination? */
if (GMC_is_terminal (c, GNUNET_YES))
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n");
- if (MESH_TUNNEL_READY != c->t->state)
- tunnel_change_state (c->t, MESH_TUNNEL_READY);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n");
connection_change_state (c, MESH_CONNECTION_READY);
- tunnel_send_queued_data (c->t, GNUNET_NO);
+ GMT_change_state (c->t, MESH_TUNNEL3_READY);
+ GMT_send_queued_data (c->t, GNUNET_NO);
return GNUNET_OK;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- send_prebuilt_message_connection (message, c, NULL, fwd);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
+ GMC_send_prebuilt_message (message, c, NULL, fwd);
return GNUNET_OK;
}
+/**
+ * Is traffic coming from this sender 'FWD' traffic?
+ *
+ * @param c Connection to check.
+ * @param sender Peer identity of neighbor.
+ *
+ * @return GNUNET_YES in case the sender is the 'prev' hop and therefore
+ * the traffic is 'FWD'. GNUNET_NO for BCK. GNUNET_SYSERR for errors.
+ */
+int
+is_fwd (const struct MeshConnection *c,
+ const struct GNUNET_PeerIdentity *sender)
+{
+ GNUNET_PEER_Id id;
+
+ id = GNUNET_PEER_search (sender);
+ if (GMP_get_short_id (get_prev_hop (c)) == id)
+ return GNUNET_YES;
+
+ if (GMP_get_short_id (get_next_hop (c)) == id)
+ return GNUNET_NO;
+
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+}
+
+
/**
* Core handler for notifications of broken paths
*
* @param cls Closure (unused).
- * @param peer Peer identity of sending neighbor.
+ * @param id Peer identity of sending neighbor.
* @param message Message.
*
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
-static int
-handle_broken (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_broken (void* cls,
+ const struct GNUNET_PeerIdentity* id,
+ const struct GNUNET_MessageHeader* message)
{
struct GNUNET_MESH_ConnectionBroken *msg;
struct MeshConnection *c;
+ int fwd;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received a CONNECTION BROKEN msg from %s\n", GNUNET_i2s (peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received a CONNECTION BROKEN msg from %s\n", GNUNET_i2s (id));
msg = (struct GNUNET_MESH_ConnectionBroken *) message;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
GNUNET_i2s (&msg->peer1));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
GNUNET_i2s (&msg->peer2));
c = connection_get (&msg->cid);
if (NULL == c)
GNUNET_break_op (0);
return GNUNET_OK;
}
- tunnel_notify_connection_broken (c->t, GNUNET_PEER_search (&msg->peer1),
- GNUNET_PEER_search (&msg->peer2));
+
+ fwd = is_fwd (c, id);
+ connection_cancel_queues (c, !fwd);
+ if (GMC_is_terminal (c, fwd))
+ {
+ if (0 < c->pending_messages)
+ c->destroy = GNUNET_YES;
+ else
+ GMC_destroy (c);
+ }
+ else
+ {
+ GMC_send_prebuilt_message (message, c, NULL, fwd);
+ c->destroy = GNUNET_YES;
+ }
+
return GNUNET_OK;
}
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
-static int
-handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_ConnectionDestroy *msg;
struct MeshConnection *c;
- GNUNET_PEER_Id id;
int fwd;
msg = (struct GNUNET_MESH_ConnectionDestroy *) message;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"Got a CONNECTION DESTROY message from %s\n",
GNUNET_i2s (peer));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
" for connection %s\n",
GNUNET_h2s (&msg->cid));
c = connection_get (&msg->cid);
1, GNUNET_NO);
return GNUNET_OK;
}
- id = GNUNET_PEER_search (peer);
- if (id == connection_get_prev_hop (c)->id)
- fwd = GNUNET_YES;
- else if (id == connection_get_next_hop (c)->id)
- fwd = GNUNET_NO;
- else
+ fwd = is_fwd (c, peer);
+ if (GNUNET_SYSERR == fwd)
{
GNUNET_break_op (0);
return GNUNET_OK;
}
- send_prebuilt_message_connection (message, c, NULL, fwd);
+ GMC_send_prebuilt_message (message, c, NULL, fwd);
c->destroy = GNUNET_YES;
return GNUNET_OK;
*
* @param peer Peer identity this notification is about.
* @param message Encrypted message.
- * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
*
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
static int
handle_mesh_encrypted (const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MESH_Encrypted *msg,
- int fwd)
+ const struct GNUNET_MESH_Encrypted *msg)
{
struct MeshConnection *c;
- struct MeshTunnel2 *t;
struct MeshPeer *neighbor;
struct MeshFlowControl *fc;
+ GNUNET_PEER_Id peer_id;
uint32_t pid;
uint32_t ttl;
uint16_t type;
size_t size;
+ int fwd;
/* Check size */
size = ntohs (msg->header.size);
return GNUNET_OK;
}
type = ntohs (msg->header.type);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a %s message from %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "got a %s message from %s\n",
GNUNET_MESH_DEBUG_M2S (type), GNUNET_i2s (peer));
/* Check connection */
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WARNING connection unknown\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING connection unknown\n");
return GNUNET_OK;
}
- t = c->t;
- fc = fwd ? &c->bck_fc : &c->fwd_fc;
/* Check if origin is as expected */
- neighbor = connection_get_hop (c, !fwd);
- if (peer_get (peer)->id != neighbor->id)
+ neighbor = get_prev_hop (c);
+ peer_id = GNUNET_PEER_search (peer);
+ if (peer_id == GMP_get_short_id (neighbor))
{
- GNUNET_break_op (0);
- return GNUNET_OK;
+ fwd = GNUNET_YES;
+ }
+ else
+ {
+ neighbor = get_next_hop (c);
+ if (peer_id == GMP_get_short_id (neighbor))
+ {
+ fwd = GNUNET_NO;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
}
+ fc = fwd ? &c->bck_fc : &c->fwd_fc;
/* Check PID */
pid = ntohl (msg->pid);
if (GMC_is_pid_bigger (pid, fc->last_ack_sent))
{
GNUNET_STATISTICS_update (stats, "# unsolicited message", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"WARNING Received PID %u, (prev %u), ACK %u\n",
pid, fc->last_pid_recv, fc->last_ack_sent);
return GNUNET_OK;
if (GNUNET_NO == GMC_is_pid_bigger (pid, fc->last_pid_recv))
{
GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
" Pid %u not expected (%u+), dropping!\n",
pid, fc->last_pid_recv + 1);
return GNUNET_OK;
/* Is this message for us? */
if (GMC_is_terminal (c, fwd))
{
- size_t dsize = size - sizeof (struct GNUNET_MESH_Encrypted);
- char cbuf[dsize];
- struct GNUNET_MessageHeader *msgh;
- unsigned int off;
-
/* TODO signature verification */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
- fc->last_pid_recv = pid;
- tunnel_decrypt (t, cbuf, &msg[1], dsize, msg->iv, fwd);
- off = 0;
- while (off < dsize)
+ if (NULL == c->t)
{
- msgh = (struct GNUNET_MessageHeader *) &cbuf[off];
- handle_decrypted (t, msgh, fwd);
- off += ntohs (msgh->size);
+ GNUNET_break (0);
+ return GNUNET_OK;
}
- send_ack (c, NULL, fwd);
+ fc->last_pid_recv = pid;
+ GMT_handle_encrypted (c->t, msg, fwd);
+ GMC_send_ack (c, NULL, fwd);
return GNUNET_OK;
}
/* Message not for us: forward to next hop */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
ttl = ntohl (msg->ttl);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ttl);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ttl);
if (ttl == 0)
{
GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n");
- send_ack (c, NULL, fwd);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n");
+ GMC_send_ack (c, NULL, fwd);
return GNUNET_OK;
}
GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
- send_prebuilt_message_connection (&msg->header, c, NULL, fwd);
+ GMC_send_prebuilt_message (&msg->header, c, NULL, fwd);
return GNUNET_OK;
}
/**
- * Core handler for mesh network traffic going orig->dest.
+ * Core handler for encrypted mesh network traffic (channel mgmt, data).
*
* @param cls Closure (unused).
* @param message Message received.
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
-static int
-handle_fwd (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
return handle_mesh_encrypted (peer,
- (struct GNUNET_MESH_Encrypted *)message,
- GNUNET_YES);
+ (struct GNUNET_MESH_Encrypted *)message);
}
+
/**
- * Core handler for mesh network traffic going dest->orig.
+ * Core handler for mesh network traffic point-to-point acks.
*
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Peer who sent the message.
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
*
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
-static int
-handle_bck (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- return handle_mesh_encrypted (peer,
- (struct GNUNET_MESH_Encrypted *)message,
- GNUNET_NO);
-}
-
-
-/**
- * Core handler for mesh network traffic point-to-point acks.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_ACK *msg;
struct MeshConnection *c;
uint32_t ack;
int fwd;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK packet from %s!\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK packet from %s!\n",
GNUNET_i2s (peer));
msg = (struct GNUNET_MESH_ACK *) message;
/* Is this a forward or backward ACK? */
id = GNUNET_PEER_search (peer);
- if (connection_get_next_hop (c)->id == id)
+ if (GMP_get_short_id (get_next_hop (c)) == id)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
fc = &c->fwd_fc;
fwd = GNUNET_YES;
}
- else if (connection_get_prev_hop (c)->id == id)
+ else if (GMP_get_short_id (get_prev_hop (c)) == id)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
fc = &c->bck_fc;
fwd = GNUNET_NO;
}
}
ack = ntohl (msg->ack);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ACK %u (was %u)\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u (was %u)\n",
ack, fc->last_ack_recv);
if (GMC_is_pid_bigger (ack, fc->last_ack_recv))
fc->last_ack_recv = ack;
if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task &&
GMC_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n");
GNUNET_SCHEDULER_cancel (fc->poll_task);
fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
-static int
-handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_Poll *msg;
struct MeshConnection *c;
uint32_t pid;
int fwd;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a POLL packet from %s!\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a POLL packet from %s!\n",
GNUNET_i2s (peer));
msg = (struct GNUNET_MESH_Poll *) message;
* this way of discerining FWD/BCK should not be a problem.
*/
id = GNUNET_PEER_search (peer);
- if (connection_get_next_hop (c)->id == id)
+ if (GMP_get_short_id (get_next_hop (c)) == id)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
fc = &c->fwd_fc;
}
- else if (connection_get_prev_hop (c)->id == id)
+ else if (GMP_get_short_id (get_prev_hop (c)) == id)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
fc = &c->bck_fc;
}
else
}
pid = ntohl (msg->pid);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " PID %u, OLD %u\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u, OLD %u\n",
pid, fc->last_pid_recv);
fc->last_pid_recv = pid;
fwd = fc == &c->fwd_fc;
- send_ack (c, NULL, fwd);
+ GMC_send_ack (c, NULL, fwd);
return GNUNET_OK;
}
*
* TODO: Check who we got this from, to validate route.
*/
-static int
-handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+int
+GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_ConnectionKeepAlive *msg;
struct MeshConnection *c;
int fwd;
msg = (struct GNUNET_MESH_ConnectionKeepAlive *) message;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a keepalive packet from %s\n",
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "got a keepalive packet from %s\n",
GNUNET_i2s (peer));
c = connection_get (&msg->cid);
GNUNET_YES : GNUNET_NO;
/* Check if origin is as expected */
- neighbor = connection_get_hop (c, fwd);
- if (peer_get (peer)->id != neighbor->id)
+ neighbor = get_hop (c, fwd);
+ if (GNUNET_PEER_search (peer) != GMP_get_short_id (neighbor))
{
GNUNET_break_op (0);
return GNUNET_OK;
return GNUNET_OK;
GNUNET_STATISTICS_update (stats, "# keepalives forwarded", 1, GNUNET_NO);
- send_prebuilt_message_connection (message, c, NULL, fwd);
+ GMC_send_prebuilt_message (message, c, NULL, fwd);
return GNUNET_OK;
}
/**
- * Functions to handle messages from core
+ * Send an ACK on the appropriate connection/channel, depending on
+ * the direction and the position of the peer.
+ *
+ * @param c Which connection to send the hop-by-hop ACK.
+ * @param ch Channel, if any.
+ * @param fwd Is this a fwd ACK? (will go dest->root)
*/
-static struct GNUNET_CORE_MessageHandler core_handlers[] = {
- {&handle_create, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE,
- 0},
- {&handle_confirm, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK,
- sizeof (struct GNUNET_MESH_ConnectionACK)},
- {&handle_broken, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN,
- sizeof (struct GNUNET_MESH_ConnectionBroken)},
- {&handle_destroy, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_DESTROY,
- sizeof (struct GNUNET_MESH_ConnectionDestroy)},
- {&handle_keepalive, GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE,
- sizeof (struct GNUNET_MESH_ConnectionKeepAlive)},
- {&handle_keepalive, GNUNET_MESSAGE_TYPE_MESH_BCK_KEEPALIVE,
- sizeof (struct GNUNET_MESH_ConnectionKeepAlive)},
- {&handle_ack, GNUNET_MESSAGE_TYPE_MESH_ACK,
- sizeof (struct GNUNET_MESH_ACK)},
- {&handle_poll, GNUNET_MESSAGE_TYPE_MESH_POLL,
- sizeof (struct GNUNET_MESH_Poll)},
- {&handle_fwd, GNUNET_MESSAGE_TYPE_MESH_FWD, 0},
- {&handle_bck, GNUNET_MESSAGE_TYPE_MESH_BCK, 0},
- {NULL, 0, 0}
-};
+void
+GMC_send_ack (struct MeshConnection *c, struct MeshChannel *ch, int fwd)
+{
+ unsigned int buffer;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "send ack %s on %p %p\n",
+ fwd ? "FWD" : "BCK", c, ch);
+
+ /* Get available bufffer space */
+ if (NULL == c || GMC_is_terminal (c, fwd))
+ {
+ struct MeshTunnel3 *t;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all connections\n");
+ t = (NULL == c) ? GMCH_get_tunnel (ch) : GMC_get_tunnel (c);
+ buffer = GMT_get_buffer (t, fwd);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n");
+ buffer = GMC_get_buffer (c, fwd);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer);
+
+ /* Send available buffer space */
+ if ( (NULL != ch && GMCH_is_origin (ch, fwd)) ||
+ (NULL != c && GMC_is_origin (c, fwd)) )
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n");
+ if (0 < buffer)
+ {
+ GNUNET_assert (NULL != ch);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " really sending!\n");
+ GMCH_send_data_ack (ch, fwd);
+ }
+ }
+ else if (NULL == c)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on all connections\n");
+ GNUNET_assert (NULL != ch);
+ GMT_send_acks (GMCH_get_tunnel (ch), buffer, fwd);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n");
+ connection_send_ack (c, buffer, fwd);
+ }
+}
+
+
+/**
+ * Initialize the connections subsystem
+ *
+ * @param c Configuration handle.
+ */
+void
+GMC_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_MSGS_QUEUE",
+ &max_msgs_queue))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "MESH", "MAX_MSGS_QUEUE", "MISSING");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_CONNECTIONS",
+ &max_connections))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "MESH", "MAX_CONNECTIONS", "MISSING");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (c, "MESH", "REFRESH_CONNECTION_TIME",
+ &refresh_connection_time))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "MESH", "REFRESH_CONNECTION_TIME", "MISSING");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
+}
+
+/**
+ * Shut down the connections subsystem.
+ */
+void
+GMC_shutdown (void)
+{
+ GNUNET_CONTAINER_multihashmap_destroy (connections);
+}
struct MeshConnection *
-GMC_new (const struct GNUNET_HashCode *cid)
+GMC_new (const struct GNUNET_HashCode *cid,
+ struct MeshTunnel3 *t,
+ struct MeshPeerPath *p,
+ unsigned int own_pos)
{
struct MeshConnection *c;
-
+
c = GNUNET_new (struct MeshConnection);
c->id = *cid;
GNUNET_CONTAINER_multihashmap_put (connections, &c->id, c,
fc_init (&c->bck_fc);
c->fwd_fc.c = c;
c->bck_fc.c = c;
-
+
+ c->t = t;
+ if (own_pos > p->length - 1)
+ {
+ GNUNET_break (0);
+ GMC_destroy (c);
+ return NULL;
+ }
+ c->own_pos = own_pos;
+ c->path = p;
+
+ if (0 == own_pos)
+ {
+ c->fwd_maintenance_task =
+ GNUNET_SCHEDULER_add_delayed (refresh_connection_time,
+ &connection_fwd_keepalive, c);
+ }
+ register_neighbors (c);
return c;
}
-static void
+void
GMC_destroy (struct MeshConnection *c)
{
- struct MeshPeer *peer;
-
if (NULL == c)
return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s[%X]\n",
- peer2s (c->t->peer),
- c->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n",
+ GNUNET_h2s (&c->id));
/* Cancel all traffic */
connection_cancel_queues (c, GNUNET_YES);
if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task)
GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
- /* Deregister from neighbors */
- peer = connection_get_next_hop (c);
- if (NULL != peer && NULL != peer->connections)
- GNUNET_CONTAINER_multihashmap_remove (peer->connections, &c->id, c);
- peer = connection_get_prev_hop (c);
- if (NULL != peer && NULL != peer->connections)
- GNUNET_CONTAINER_multihashmap_remove (peer->connections, &c->id, c);
+ /* Unregister from neighbors */
+ unregister_neighbors (c);
/* Delete */
GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO);
- GNUNET_CONTAINER_DLL_remove (c->t->connection_head, c->t->connection_tail, c);
+ GMT_remove_connection (c->t, c);
GNUNET_free (c);
}
+/**
+ * Get the connection ID.
+ *
+ * @param c Connection to get the ID from.
+ *
+ * @return ID of the connection.
+ */
+const struct GNUNET_HashCode *
+GMC_get_id (const struct MeshConnection *c)
+{
+ return &c->id;
+}
+
/**
- * Iterator to notify all connections of a broken link. Mark connections
- * to destroy after all traffic has been sent.
+ * Get the connection path.
*
- * @param cls Closure (peer disconnected).
- * @param key Current key code (tid).
- * @param value Value in the hash map (connection).
+ * @param c Connection to get the path from.
*
- * @return GNUNET_YES if we should continue to iterate,
- * GNUNET_NO if not.
+ * @return path used by the connection.
*/
-int
-GMC_notify_broken (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
+const struct MeshPeerPath *
+GMC_get_path (const struct MeshConnection *c)
{
- struct MeshPeer *peer = cls;
- struct MeshConnection *c = value;
- struct GNUNET_MESH_ConnectionBroken msg;
- int fwd;
+ return c->path;
+}
- fwd = peer == connection_get_prev_hop (c);
- connection_cancel_queues (c, !fwd);
- if (GMC_is_terminal (c, fwd))
+/**
+ * Get the connection state.
+ *
+ * @param c Connection to get the state from.
+ *
+ * @return state of the connection.
+ */
+enum MeshConnectionState
+GMC_get_state (const struct MeshConnection *c)
+{
+ return c->state;
+}
+
+/**
+ * Get the connection tunnel.
+ *
+ * @param c Connection to get the tunnel from.
+ *
+ * @return tunnel of the connection.
+ */
+struct MeshTunnel3 *
+GMC_get_tunnel (const struct MeshConnection *c)
+{
+ return c->t;
+}
+
+
+/**
+ * Get free buffer space in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Free buffer space [0 - max_msgs_queue/max_connections]
+ */
+unsigned int
+GMC_get_buffer (struct MeshConnection *c, int fwd)
+{
+ struct MeshFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+
+ return (fc->queue_max - fc->queue_n);
+}
+
+/**
+ * Get how many messages have we allowed to send to us from a direction..
+ *
+ * @param c Connection.
+ * @param fwd Are we asking about traffic from FWD (BCK messages)?
+ *
+ * @return last_ack_sent - last_pid_recv
+ */
+unsigned int
+GMC_get_allowed (struct MeshConnection *c, int fwd)
+{
+ struct MeshFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GMC_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
{
- /* Local shutdown, no one to notify about this. */
- GMC_destroy (c);
- return GNUNET_YES;
+ return 0;
}
+ return (fc->last_ack_sent - fc->last_pid_recv);
+}
- msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectionBroken));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN);
- msg.cid = c->id;
- msg.peer1 = my_full_id;
- msg.peer2 = *GNUNET_PEER_resolve2 (peer->id);
- send_prebuilt_message_connection (&msg.header, c, NULL, fwd);
- c->destroy = GNUNET_YES;
+/**
+ * Get messages queued in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Number of messages queued.
+ */
+unsigned int
+GMC_get_qn (struct MeshConnection *c, int fwd)
+{
+ struct MeshFlowControl *fc;
- return GNUNET_YES;
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+
+ return fc->queue_n;
}
/**
- * Initialize the connections subsystem
+ * Allow the connection to advertise a buffer of the given size.
*
- * @param c Configuration handle.
+ * The connection will send an @c fwd ACK message (so: in direction !fwd)
+ * allowing up to last_pid_recv + buffer.
+ *
+ * @param c Connection.
+ * @param buffer How many more messages the connection can accept.
+ * @param fwd Is this about FWD traffic? (The ack will go dest->root).
*/
void
-GMC_init (const struct GNUNET_CONFIGURATION_Handle *c)
+GMC_allow (struct MeshConnection *c, unsigned int buffer, int fwd)
{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_MSGS_QUEUE",
- &max_msgs_queue))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "MESH", "MAX_MSGS_QUEUE", "MISSING");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
+ connection_send_ack (c, buffer, fwd);
+}
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_CONNECTIONS",
- &max_connections))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "MESH", "MAX_CONNECTIONS", "MISSING");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (c, "MESH", "REFRESH_CONNECTION_TIME",
- &refresh_connection_time))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "MESH", "REFRESH_CONNECTION_TIME", "MISSING");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
+/**
+ * Send a notification that a connection is broken.
+ *
+ * @param c Connection that is broken.
+ * @param id1 Peer that has disconnected.
+ * @param id2 Peer that has disconnected.
+ * @param fwd Direction towards which to send it.
+ */
+static void
+send_broken (struct MeshConnection *c,
+ const struct GNUNET_PeerIdentity *id1,
+ const struct GNUNET_PeerIdentity *id2,
+ int fwd)
+{
+ struct GNUNET_MESH_ConnectionBroken msg;
- core_handle = GNUNET_CORE_connect (c, /* Main configuration */
- NULL, /* Closure passed to MESH functions */
- &core_init, /* Call core_init once connected */
- &core_connect, /* Handle connects */
- &core_disconnect, /* remove peers on disconnects */
- NULL, /* Don't notify about all incoming messages */
- GNUNET_NO, /* For header only in notification */
- NULL, /* Don't notify about all outbound messages */
- GNUNET_NO, /* For header-only out notification */
- core_handlers); /* Register these handlers */
- if (NULL == core_handle)
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
+ msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectionBroken));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN);
+ msg.cid = c->id;
+ msg.peer1 = *id1;
+ msg.peer2 = *id2;
+ GMC_send_prebuilt_message (&msg.header, c, NULL, fwd);
}
/**
- * Shut down the connections subsystem.
+ * Notify other peers on a connection of a broken link. Mark connections
+ * to destroy after all traffic has been sent.
+ *
+ * @param c Connection on which there has been a disconnection.
+ * @param peer Peer that disconnected.
*/
void
-GMC_shutdown (void)
+GMC_notify_broken (struct MeshConnection *c,
+ struct MeshPeer *peer)
{
- if (core_handle != NULL)
+ int fwd;
+
+ fwd = peer == get_prev_hop (c);
+
+ connection_cancel_queues (c, !fwd);
+ if (GMC_is_terminal (c, fwd))
{
- GNUNET_CORE_disconnect (core_handle);
- core_handle = NULL;
+ /* Local shutdown, no one to notify about this. */
+ GMC_destroy (c);
+ return;
}
+
+ send_broken (c, &my_full_id, GMP_get_id (peer), fwd);
+
+ /* Connection will have at least one pending message
+ * (the one we just scheduled), so no point in checking whether to
+ * destroy immediately. */
+ c->destroy = GNUNET_YES;
+
+ return;
}
/**
- * Count connections in a DLL.
+ * See if we are allowed to send by the next hop in the given direction.
+ *
+ * @param c Connection.
+ * @param fwd Is this about fwd traffic?
+ *
+ * @return GNUNET_YES in case it's OK.
*/
-unsigned int
-GMC_count (const struct MeshConnection *head)
+int
+GMC_is_sendable (struct MeshConnection *c, int fwd)
+{
+ struct MeshFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GMC_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+/**
+ * Sends an already built message on a connection, properly registering
+ * all used resources.
+ *
+ * @param message Message to send. Function makes a copy of it.
+ * If message is not hop-by-hop, decrements TTL of copy.
+ * @param c Connection on which this message is transmitted.
+ * @param ch Channel on which this message is transmitted, or NULL.
+ * @param fwd Is this a fwd message?
+ */
+void
+GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ struct MeshConnection *c,
+ struct MeshChannel *ch,
+ int fwd)
+{
+ struct MeshFlowControl *fc;
+ void *data;
+ size_t size;
+ uint16_t type;
+ int droppable;
+
+ size = ntohs (message->size);
+ data = GNUNET_malloc (size);
+ memcpy (data, message, size);
+ type = ntohs (message->type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Send %s (%u) on connection %s\n",
+ GNUNET_MESH_DEBUG_M2S (type), size, GNUNET_h2s (&c->id));
+
+ droppable = GNUNET_YES;
+ switch (type)
+ {
+ struct GNUNET_MESH_Encrypted *emsg;
+ struct GNUNET_MESH_ACK *amsg;
+ struct GNUNET_MESH_Poll *pmsg;
+ struct GNUNET_MESH_ConnectionDestroy *dmsg;
+ struct GNUNET_MESH_ConnectionBroken *bmsg;
+ uint32_t ttl;
+
+ case GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED:
+ emsg = (struct GNUNET_MESH_Encrypted *) data;
+ ttl = ntohl (emsg->ttl);
+ if (0 == ttl)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ emsg->cid = c->id;
+ emsg->ttl = htonl (ttl - 1);
+ emsg->pid = htonl (fwd ? c->fwd_fc.next_pid++ : c->bck_fc.next_pid++);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " pid %u\n", ntohl (emsg->pid));
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_ACK:
+ amsg = (struct GNUNET_MESH_ACK *) data;
+ amsg->cid = c->id;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ntohl (amsg->ack));
+ droppable = GNUNET_NO;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_POLL:
+ pmsg = (struct GNUNET_MESH_Poll *) data;
+ pmsg->cid = c->id;
+ pmsg->pid = htonl (fwd ? c->fwd_fc.last_pid_sent : c->bck_fc.last_pid_sent);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid));
+ droppable = GNUNET_NO;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
+ dmsg = (struct GNUNET_MESH_ConnectionDestroy *) data;
+ dmsg->cid = c->id;
+ dmsg->reserved = 0;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN:
+ bmsg = (struct GNUNET_MESH_ConnectionBroken *) data;
+ bmsg->cid = c->id;
+ bmsg->reserved = 0;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
+ case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK:
+ break;
+
+ default:
+ GNUNET_break (0);
+ }
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (fc->queue_n >= fc->queue_max && droppable)
+ {
+ GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)",
+ 1, GNUNET_NO);
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "queue full: %u/%u\n",
+ fc->queue_n, fc->queue_max);
+ return; /* Drop this message */
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid %u\n", fc->last_pid_sent);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", fc->last_ack_recv);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n);
+ if (GMC_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
+ {
+ GMC_start_poll (c, fwd);
+ }
+ fc->queue_n++;
+ c->pending_messages++;
+
+ GMP_queue_add (get_hop (c, fwd), data, type, size, c, ch, fwd,
+ &message_sent, NULL);
+}
+
+
+/**
+ * Sends a CREATE CONNECTION message for a path to a peer.
+ * Changes the connection and tunnel states if necessary.
+ *
+ * @param connection Connection to create.
+ */
+void
+GMC_send_create (struct MeshConnection *connection)
+{
+enum MeshTunnel3State state;
+ size_t size;
+
+ size = sizeof (struct GNUNET_MESH_ConnectionCreate);
+ size += connection->path->length * sizeof (struct GNUNET_PeerIdentity);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Send connection create\n");
+ GMP_queue_add (get_next_hop (connection), NULL,
+ GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE,
+ size, connection, NULL,
+ GNUNET_YES, &message_sent, NULL);
+ state = GMT_get_state (connection->t);
+ if (MESH_TUNNEL3_SEARCHING == state || MESH_TUNNEL3_NEW == state)
+ GMT_change_state (connection->t, MESH_TUNNEL3_WAITING);
+ if (MESH_CONNECTION_NEW == connection->state)
+ connection_change_state (connection, MESH_CONNECTION_SENT);
+}
+
+
+/**
+ * Send a message to all peers in this connection that the connection
+ * is no longer valid.
+ *
+ * If some peer should not receive the message, it should be zero'ed out
+ * before calling this function.
+ *
+ * @param c The connection whose peers to notify.
+ */
+void
+GMC_send_destroy (struct MeshConnection *c)
+{
+ struct GNUNET_MESH_ConnectionDestroy msg;
+
+ if (GNUNET_YES == c->destroy)
+ return;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY);;
+ msg.cid = c->id;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " sending connection destroy for connection %s\n",
+ GNUNET_h2s (&c->id));
+
+ if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES))
+ GMC_send_prebuilt_message (&msg.header, c, NULL, GNUNET_YES);
+ if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO))
+ GMC_send_prebuilt_message (&msg.header, c, NULL, GNUNET_NO);
+ c->destroy = GNUNET_YES;
+}
+
+
+/**
+ * @brief Start a polling timer for the connection.
+ *
+ * When a neighbor does not accept more traffic on the connection it could be
+ * caused by a simple congestion or by a lost ACK. Polling enables to check
+ * for the lastest ACK status for a connection.
+ *
+ * @param c Connection.
+ * @param fwd Should we poll in the FWD direction?
+ */
+void
+GMC_start_poll (struct MeshConnection *c, int fwd)
{
- unsigned int count;
- struct MeshConnection *iter;
+ struct MeshFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
+ {
+ return;
+ }
+ fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
+ &connection_poll,
+ fc);
+}
+
- for (count = 0, iter = head; NULL != iter; iter = iter->next, count++);
+/**
+ * @brief Stop polling a connection for ACKs.
+ *
+ * Once we have enough ACKs for future traffic, polls are no longer necessary.
+ *
+ * @param c Connection.
+ * @param fwd Should we stop the poll in the FWD direction?
+ */
+void
+GMC_stop_poll (struct MeshConnection *c, int fwd)
+{
+ struct MeshFlowControl *fc;
- return count;
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
+ {
+ GNUNET_SCHEDULER_cancel (fc->poll_task);
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ }
}
\ No newline at end of file