*/
extern GNUNET_PEER_Id myid;
+/**
+ * Local peer own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
/**
* Connections known, indexed by cid (MeshConnection).
*/
/**
* Callback called when a queued message is sent.
*
- * Calculates the average time
+ * 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
message_sent (void *cls,
- struct MeshConnection *c,
+ struct MeshConnection *c, uint16_t type,
+ int fwd, size_t size,
struct GNUNET_TIME_Relative wait)
{
struct MeshConnectionPerformance *p;
- size_t size = (size_t) cls;
+ 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)
+ {
+ 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;
+ default:
+ break;
+ }
+
if (NULL == c->perf)
- return; /* Only endpoints are interested in this. */
+ return; /* Only endpoints are interested in timing. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n");
p = c->perf;
usecsperbyte = ((double) wait.rel_value_us) / size;
if (p->size == AVG_MSGS)
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);
+// }
+// }
}
+/**
+ * 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);
+}
+
+
+/**
+ * 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.
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)
{
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);
+ " 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;
+ 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);
+ " 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)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
t = connection->t;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Send connection ack\n");
- GMP_queue_add (NULL,
+ GMP_queue_add (get_hop (connection, fwd), NULL,
GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK,
sizeof (struct GNUNET_MESH_ConnectionACK),
connection, NULL, fwd,
- &message_sent,
- (void *) sizeof (struct GNUNET_MESH_ConnectionACK));
+ &message_sent, NULL);
if (MESH_TUNNEL3_NEW == GMT_get_state (t))
GMT_change_state (t, MESH_TUNNEL3_WAITING);
if (MESH_CONNECTION_READY != connection->state)
- GMC_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)
-{
-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 (NULL,
- GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE,
- size,
- connection,
- NULL,
- GNUNET_YES, &message_sent, (void *) size);
- 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);
}
{
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);
}
}
-
-/**
- * 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);
-}
-
-
/**
* @brief Re-initiate traffic on this connection if necessary.
*
return;
}
- peer = connection_get_hop (c, fwd);
+ peer = get_hop (c, fwd);
GMP_queue_unlock (peer, c);
}
return;
}
- peer = connection_get_hop (c, fwd);
+ peer = get_hop (c, fwd);
GMP_queue_cancel (peer, c);
fc = fwd ? &c->fwd_fc : &c->bck_fc;
{
struct MeshPeer *peer;
- peer = connection_get_next_hop (c);
+ peer = get_next_hop (c);
if (GNUNET_NO == GMP_is_neighbor (peer))
{
GMC_destroy (c);
return;
}
GMP_add_connection (peer, c);
- peer = connection_get_prev_hop (c);
+ peer = get_prev_hop (c);
if (GNUNET_NO == GMP_is_neighbor (peer))
{
GMC_destroy (c);
{
struct MeshPeer *peer;
- peer = connection_get_next_hop (c);
+ peer = get_next_hop (c);
GMP_remove_connection (peer, c);
- peer = connection_get_prev_hop (c);
+ peer = get_prev_hop (c);
GMP_remove_connection (peer, c);
}
+/**
+ * Bind the connection to the peer and the tunnel to that 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
+add_to_peer (struct MeshConnection *c, struct MeshPeer *peer)
+{
+ GMP_add_tunnel (peer);
+ c->t = GMP_get_tunnel (peer);
+ GMT_add_connection (c->t, c);
+}
+
/******************************************************************************/
/******************************** API ***********************************/
/******************************************************************************/
/* create path: self not found in path through self */
GNUNET_break_op (0);
path_destroy (path);
- GMC_destroy (c);
return GNUNET_OK;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
GMP_add_path_to_origin (orig_peer, path, GNUNET_YES);
- GMP_add_tunnel (orig_peer);
- GMP_add_connection (orig_peer, c);
+ add_to_peer (c, orig_peer);
if (MESH_TUNNEL3_NEW == GMT_get_state (c->t))
GMT_change_state (c->t, MESH_TUNNEL3_WAITING);
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)
{
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)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK\n");
fwd = GNUNET_YES;
p = c->path;
if (NULL != p)
{
- path_add_to_peers (p, GNUNET_YES);
+ GMP_add_path_to_all (p, GNUNET_YES);
}
else
{
if (GMC_is_terminal (c, GNUNET_YES))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n");
- GMC_change_state (c, MESH_CONNECTION_READY);
+ connection_change_state (c, MESH_CONNECTION_READY);
GMT_change_state (c->t, MESH_TUNNEL3_READY);
GMT_send_queued_data (c->t, GNUNET_NO);
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)
*/
int
-GMC_handle_broken (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+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;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received a CONNECTION BROKEN msg from %s\n", GNUNET_i2s (peer));
+ "Received a CONNECTION BROKEN msg from %s\n", GNUNET_i2s (id));
msg = (struct GNUNET_MESH_ConnectionBroken *) message;
LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
GNUNET_i2s (&msg->peer1));
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;
}
{
struct GNUNET_MESH_ConnectionDestroy *msg;
struct MeshConnection *c;
- GNUNET_PEER_Id id;
int fwd;
msg = (struct GNUNET_MESH_ConnectionDestroy *) message;
1, GNUNET_NO);
return GNUNET_OK;
}
- id = GNUNET_PEER_search (peer);
- if (id == GMP_get_short_id (connection_get_prev_hop (c)))
- fwd = GNUNET_YES;
- else if (id == GMP_get_short_id (connection_get_next_hop (c)))
- fwd = GNUNET_NO;
- else
+ fwd = is_fwd (c, peer);
+ if (GNUNET_SYSERR == fwd)
{
GNUNET_break_op (0);
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 MeshTunnel3 *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);
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 (GNUNET_PEER_search (peer) != GMP_get_short_id (neighbor))
+ 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);
/* 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 */
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;
}
{
GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n");
- send_ack (c, NULL, fwd);
+ 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.
* GNUNET_SYSERR to close it (signal serious error)
*/
int
-GMC_handle_fwd (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- return handle_mesh_encrypted (peer,
- (struct GNUNET_MESH_Encrypted *)message,
- GNUNET_YES);
-}
-
-/**
- * Core handler for mesh network traffic going dest->orig.
- *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Peer who sent the message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_bck (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+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_NO);
+ (struct GNUNET_MESH_Encrypted *)message);
}
/* Is this a forward or backward ACK? */
id = GNUNET_PEER_search (peer);
- if (GMP_get_short_id (connection_get_next_hop (c)) == id)
+ if (GMP_get_short_id (get_next_hop (c)) == id)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
fc = &c->fwd_fc;
fwd = GNUNET_YES;
}
- else if (GMP_get_short_id (connection_get_prev_hop (c)) == id)
+ else if (GMP_get_short_id (get_prev_hop (c)) == id)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
fc = &c->bck_fc;
* this way of discerining FWD/BCK should not be a problem.
*/
id = GNUNET_PEER_search (peer);
- if (GMP_get_short_id (connection_get_next_hop (c)) == id)
+ if (GMP_get_short_id (get_next_hop (c)) == id)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
fc = &c->fwd_fc;
}
- else if (GMP_get_short_id (connection_get_prev_hop (c)) == id)
+ else if (GMP_get_short_id (get_prev_hop (c)) == id)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
fc = &c->bck_fc;
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;
}
GNUNET_YES : GNUNET_NO;
/* Check if origin is as expected */
- neighbor = connection_get_hop (c, fwd);
+ neighbor = get_hop (c, fwd);
if (GNUNET_PEER_search (peer) != GMP_get_short_id (neighbor))
{
GNUNET_break_op (0);
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, " buffer available: %u\n", buffer);
+ /* Send available buffer space */
if ( (NULL != ch && GMCH_is_origin (ch, fwd)) ||
(NULL != c && GMC_is_origin (c, fwd)) )
{
{
GNUNET_assert (NULL != ch);
LOG (GNUNET_ERROR_TYPE_DEBUG, " really sending!\n");
- send_local_ack (ch, fwd);
+ GMCH_send_data_ack (ch, fwd);
}
}
else if (NULL == c)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on all connections\n");
GNUNET_assert (NULL != ch);
- channel_send_connections_ack (ch, buffer, fwd);
+ GMT_send_acks (GMCH_get_tunnel (ch), buffer, fwd);
}
else
{
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))
{
- LOG_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
"MESH", "MAX_MSGS_QUEUE", "MISSING");
GNUNET_SCHEDULER_shutdown ();
return;
GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_CONNECTIONS",
&max_connections))
{
- LOG_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
"MESH", "MAX_CONNECTIONS", "MISSING");
GNUNET_SCHEDULER_shutdown ();
return;
GNUNET_CONFIGURATION_get_value_time (c, "MESH", "REFRESH_CONNECTION_TIME",
&refresh_connection_time))
{
- LOG_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
"MESH", "REFRESH_CONNECTION_TIME", "MISSING");
GNUNET_SCHEDULER_shutdown ();
return;
void
GMC_shutdown (void)
{
+ GNUNET_CONTAINER_multihashmap_destroy (connections);
}
}
+/**
+ * Get the connection path.
+ *
+ * @param c Connection to get the path from.
+ *
+ * @return path used by the connection.
+ */
+const struct MeshPeerPath *
+GMC_get_path (const struct MeshConnection *c)
+{
+ return c->path;
+}
+
+
/**
* Get the connection state.
*
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))
+ {
+ return 0;
+ }
+ return (fc->last_ack_sent - fc->last_pid_recv);
+}
+
/**
* Get messages queued in a connection.
*
}
+/**
+ * Allow the connection to advertise a buffer of the given size.
+ *
+ * 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_allow (struct MeshConnection *c, unsigned int buffer, int fwd)
+{
+ connection_send_ack (c, buffer, fwd);
+}
+
+
+/**
+ * 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;
+
+ 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);
+}
+
/**
* 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.
- * @param my_full_id My ID (to send to other peers).
*/
void
GMC_notify_broken (struct MeshConnection *c,
- struct MeshPeer *peer,
- struct GNUNET_PeerIdentity *my_full_id)
+ struct MeshPeer *peer)
{
- struct GNUNET_MESH_ConnectionBroken msg;
int fwd;
- fwd = peer == connection_get_prev_hop (c);
+ fwd = peer == get_prev_hop (c);
connection_cancel_queues (c, !fwd);
if (GMC_is_terminal (c, fwd))
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 = *my_full_id;
- msg.peer2 = *GMP_get_id (peer);
- GMC_send_prebuilt_message (&msg.header, c, NULL, fwd);
+ 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;
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);
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_ConnectionBroken *bmsg;
uint32_t ttl;
- case GNUNET_MESSAGE_TYPE_MESH_FWD:
- case GNUNET_MESSAGE_TYPE_MESH_BCK:
+ case GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED:
emsg = (struct GNUNET_MESH_Encrypted *) data;
ttl = ntohl (emsg->ttl);
if (0 == ttl)
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->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:
GNUNET_break (0);
}
- GMP_queue_add (data, type, size, c, ch, fwd, &message_sent, (void *) size);
+ 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);
}
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)
+{
+ 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);
+}
+
+
+/**
+ * @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;
+
+ 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