MESH_TunnelNumber local_tid_dest;
/**
- * Local count ID of the last packet seen/sent.
+ * Is the speed on the tunnel limited to the slowest peer?
*/
- uint32_t pid;
+ int speed_min;
/**
- * SKIP value for this tunnel.
+ * Is the tunnel bufferless (minimum latency)?
*/
- uint32_t skip;
+ int nobuffer;
/**
- * MeshTunnelChildInfo of all children, indexed by GNUNET_PEER_Id.
+ * Packet ID of the last fwd packet seen (sent/retransmitted/received).
*/
- struct GNUNET_CONTAINER_MultiHashMap *children_fc;
+ uint32_t fwd_pid;
/**
- * Last ACK sent towards the origin.
+ * Packet ID of the last bck packet sent (unique counter per hop).
*/
- uint32_t last_ack;
+ uint32_t bck_pid;
- /**
- * How many messages are in the queue.
+ /**
+ * SKIP value for this tunnel.
*/
- unsigned int queue_n;
+ uint32_t skip;
/**
- * How many messages do we accept in the queue.
+ * MeshTunnelChildInfo of all children, indexed by GNUNET_PEER_Id.
+ * Contains the Flow Control info: FWD ACK value received,
+ * last BCK ACK sent, PID and SKIP values.
*/
- unsigned int queue_max;
+ struct GNUNET_CONTAINER_MultiHashMap *children_fc;
/**
- * Is the speed on the tunnel limited to the slowest peer?
+ * Last ACK sent towards the origin (for traffic towards leaf node).
*/
- int speed_min;
+ uint32_t last_fwd_ack;
+
+ /**
+ * BCK ACK value received from the hop towards the owner of the tunnel,
+ * (previous node / owner): up to what message PID can we sent back to him.
+ */
+ uint32_t bck_ack;
/**
- * Is the tunnel bufferless (minimum latency)?
+ * How many messages are in the queue.
*/
- int nobuffer;
+ unsigned int queue_n;
/**
- * Flag to signal the destruction of the tunnel.
- * If this is set GNUNET_YES the tunnel will be destroyed
- * when the queue is empty.
+ * How many messages do we accept in the queue.
*/
- int destroy;
+ unsigned int queue_max;
/**
* Last time the tunnel was used
*/
uint32_t *clients_acks;
- /**
- * BCK ACK value of the root client, owner of the tunnel,
- * up to what message PID can we sent him.
- */
- uint32_t root_client_ack;
-
/**
* Number of elements in clients/clients_acks
*/
*/
struct MeshRegexSearchContext *regex_ctx;
- /**
- * Task to keep the used paths alive
- */
+ /**
+ * Task to keep the used paths alive
+ */
GNUNET_SCHEDULER_TaskIdentifier path_refresh_task;
- /**
- * Task to destroy the tunnel after timeout
- *
- * FIXME: merge the two? a tunnel will have either
- * a path refresh OR a timeout, never both!
- */
+ /**
+ * Task to destroy the tunnel after timeout
+ *
+ * FIXME: merge the two? a tunnel will have either
+ * a path refresh OR a timeout, never both!
+ */
GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * Flag to signal the destruction of the tunnel.
+ * If this is set GNUNET_YES the tunnel will be destroyed
+ * when the queue is empty.
+ */
+ int destroy;
};
* @param bigger Argument that should be bigger.
* @param smaller Argument that should be smaller.
*
- * @return True if big is bigger than small
+ * @return True if bigger (arg1) has a higher value than smaller (arg 2).
*/
static int
is_pid_bigger (uint32_t bigger, uint32_t smaller)
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ack);
- if (t->last_ack == ack)
+ if (t->last_fwd_ack == ack)
return;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending!\n");
- t->last_ack = ack;
+ t->last_fwd_ack = ack;
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
msg.tunnel_id = htonl (tid);
}
+/**
+ * @brief Get neighbor's Flow Control information.
+ *
+ * Retrieves the MeshTunnelChildInfo containing Flow Control data about a direct
+ * descendant of the local node in a certain tunnel.
+ * If the info is not yet there (recently created path), creates the data struct
+ * and inserts it into the tunnel info, initialized to the current tunnel ACK
+ * values.
+ *
+ * @param t Tunnel related.
+ * @param peer Neighbor whose Flow Control info is needed.
+ *
+ * @return Neighbor's Flow Control info.
+ */
+static struct MeshTunnelChildInfo *
+tunnel_get_neighbor_fc (const struct MeshTunnel *t,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct MeshTunnelChildInfo *cinfo;
+ cinfo = GNUNET_CONTAINER_multihashmap_get (t->children_fc,
+ &peer->hashPubKey);
+ if (NULL == cinfo)
+ {
+ cinfo = GNUNET_malloc (sizeof (struct MeshTunnelChildInfo));
+ cinfo->id = GNUNET_PEER_intern (peer);
+ cinfo->skip = t->fwd_pid;
+ cinfo->max_pid = t->fwd_pid + t->queue_max - t->queue_n; // FIXME review
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (t->children_fc,
+ &peer->hashPubKey,
+ cinfo,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+ }
+ return cinfo;
+}
+
/**
* Iterator to get the appropiate ACK value from all children nodes.
uint32_t ack;
GNUNET_PEER_resolve (id, &peer_id);
- cinfo = GNUNET_CONTAINER_multihashmap_get (t->children_fc,
- &peer_id.hashPubKey);
- if (NULL == cinfo)
- {
- cinfo = GNUNET_malloc (sizeof (struct MeshTunnelChildInfo));
- cinfo->id = id;
- cinfo->pid = t->pid;
- cinfo->skip = t->pid;
- cinfo->max_pid = ack = t->pid + 1;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_put(t->children_fc,
- &peer_id.hashPubKey,
- cinfo,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
- }
- else
- {
- ack = cinfo->max_pid;
- }
+ cinfo = tunnel_get_neighbor_fc (t, &peer_id);
+ ack = cinfo->max_pid;
if (0 == ctx->max_child_ack)
ctx->max_child_ack = ack;
GNUNET_array_append (t->clients, t->nclients, c);
t->nclients--;
- ack = t->pid + 1;
+ ack = t->fwd_pid + 1;
GNUNET_array_append (t->clients_acks, t->nclients, ack);
}
}
}
- if (GNUNET_YES == t->nobuffer && ack > t->pid)
- ack = t->pid + 1;
+ if (GNUNET_YES == t->nobuffer && ack > t->fwd_pid)
+ ack = t->fwd_pid + 1;
return (uint32_t) ack;
}
int64_t client_ack;
uint32_t ack;
- count = t->pid - t->skip;
+ count = t->fwd_pid - t->skip;
buffer_free = t->queue_max - t->queue_n;
ack = count + buffer_free; // Might overflow 32bits, it's ok!
child_ack = tunnel_get_children_ack (t);
ack = tunnel_get_fwd_ack (t);
/* If speed_min and not all children have ack'd, dont send yet */
- if (ack == t->last_ack)
+ if (ack == t->last_fwd_ack)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, not ready\n");
return;
}
- t->last_ack = ack;
+ t->last_fwd_ack = ack;
msg.pid = htonl (ack);
GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id);
ack = tunnel_get_bck_ack (t);
/* If speed_min and not all children have ack'd, dont send yet */
- if (ack == t->last_ack)
+ if (ack == t->last_fwd_ack)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, not ready\n");
return;
}
- t->last_ack = ack;
+ t->last_fwd_ack = ack;
msg.pid = htonl (ack);
GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id);
t->queue_max = (max_msgs_queue / max_tunnels) + 1;
t->tree = tree_new (owner);
t->owner = client;
- t->root_client_ack = 1;
+ t->bck_ack = 1;
t->local_tid = local;
t->children_fc = GNUNET_CONTAINER_multihashmap_create (8);
n_tunnels++;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a unicast packet from %s\n",
GNUNET_i2s (peer));
+ /* Check size */
size = ntohs (message->size);
if (size <
sizeof (struct GNUNET_MESH_Unicast) +
msg = (struct GNUNET_MESH_Unicast *) message;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " of type %u\n",
ntohs (msg[1].header.type));
+ /* Check tunnel */
t = tunnel_get (&msg->oid, ntohl (msg->tid));
if (NULL == t)
{
return GNUNET_OK;
}
pid = ntohl (msg->pid);
- if (t->pid == pid)
+ if (t->fwd_pid == pid)
{
- GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats, "# PID drops", 1, GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
" Already seen pid %u, DROPPING!\n", pid);
return GNUNET_OK;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" pid %u not seen yet, forwarding\n", pid);
}
- t->skip += (pid - t->pid) - 1;
- t->pid = pid;
+ t->skip += (pid - t->fwd_pid) - 1;
+ t->fwd_pid = pid;
tunnel_reset_timeout (t);
+ if (is_pid_bigger (pid, t->last_fwd_ack))
+ {
+ GNUNET_STATISTICS_update (stats, "# not allowed unicast", 1, GNUNET_NO);
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ // FIXME peer sent unauthorized data. Break connection? Accept anyway?
+ }
dest_id = GNUNET_PEER_search (&msg->destination);
if (dest_id == myid)
{
" it's for us! sending to clients...\n");
GNUNET_STATISTICS_update (stats, "# unicast received", 1, GNUNET_NO);
send_subscribed_clients (message, (struct GNUNET_MessageHeader *) &msg[1]);
- // FIXME send after client processes the packet
- tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_ACK);
+ // ACK sent by client, service retransmits.
return GNUNET_OK;
}
ttl = ntohl (msg->ttl);
GNUNET_STATISTICS_update (stats, "# unicast forwarded", 1, GNUNET_NO);
neighbor = tree_get_first_hop (t->tree, dest_id);
- cinfo = GNUNET_CONTAINER_multihashmap_get (t->children_fc,
- &neighbor->hashPubKey);
- if (NULL == cinfo)
- {
- cinfo = GNUNET_malloc (sizeof (struct MeshTunnelChildInfo));
- cinfo->id = GNUNET_PEER_intern (neighbor);
- cinfo->skip = pid;
- cinfo->max_pid = pid + t->queue_max - t->queue_n; // FIXME review
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_put (t->children_fc,
- &neighbor->hashPubKey,
- cinfo,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
- }
+ cinfo = tunnel_get_neighbor_fc (t, neighbor);
cinfo->pid = pid;
GNUNET_CONTAINER_multihashmap_iterate (t->children_fc,
&tunnel_add_skip,
&neighbor);
+ if (is_pid_bigger(pid, cinfo->max_pid))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
send_message (message, neighbor, t);
return GNUNET_OK;
}
return GNUNET_OK;
}
pid = ntohl (msg->pid);
- if (t->pid == pid)
+ if (t->fwd_pid == pid)
{
/* already seen this packet, drop */
GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" pid %u not seen yet, forwarding\n", pid);
}
- t->skip += (pid - t->pid) - 1;
- t->pid = pid;
+ t->skip += (pid - t->fwd_pid) - 1;
+ t->fwd_pid = pid;
tunnel_reset_timeout (t);
/* Transmit to locally interested clients */
return GNUNET_OK;
}
ack = ntohl (msg->pid);
- cinfo = GNUNET_CONTAINER_multihashmap_get (t->children_fc,
- &peer->hashPubKey);
- if (NULL == cinfo)
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
+ cinfo = tunnel_get_neighbor_fc (t, peer);
cinfo->max_pid = ack;
tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_ACK);
return GNUNET_OK;
msg->oid = my_full_id;
msg->tid = htonl (t->id.tid);
msg->ttl = htonl (default_ttl);
- msg->pid = htonl (t->pid + 1);
- t->pid++;
+ msg->pid = htonl (t->fwd_pid + 1);
+ t->fwd_pid++;
payload = (struct GNUNET_MessageHeader *) &msg[1];
payload->size = htons (sizeof (struct GNUNET_MessageHeader));
payload->type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE);
struct GNUNET_MESH_TunnelMessage *t_msg;
struct MeshTunnel *t;
struct MeshClient *c;
+ MESH_TunnelNumber tid;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new tunnel requested\n");
t_msg = (struct GNUNET_MESH_TunnelMessage *) message;
/* Sanity check for tunnel numbering */
- if (0 == (ntohl (t_msg->tunnel_id) & GNUNET_MESH_LOCAL_TUNNEL_ID_CLI))
+ tid = ntohl (t_msg->tunnel_id);
+ if (0 == (tid & GNUNET_MESH_LOCAL_TUNNEL_ID_CLI))
{
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
/* Sanity check for duplicate tunnel IDs */
- if (NULL != tunnel_get_by_local_id (c, ntohl (t_msg->tunnel_id)))
+ if (NULL != tunnel_get_by_local_id (c, tid))
{
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
while (NULL != tunnel_get_by_pi (myid, next_tid))
next_tid = (next_tid + 1) & ~GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
- t = tunnel_new (myid, next_tid++, c, ntohl (t_msg->tunnel_id));
+ t = tunnel_new (myid, next_tid++, c, tid);
if (NULL == t)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tunnel creation failed.\n");
copy->oid = my_full_id;
copy->tid = htonl (t->id.tid);
copy->ttl = htonl (default_ttl);
- copy->pid = htonl (t->pid + 1);
+ copy->pid = htonl (t->fwd_pid + 1);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" calling generic handler...\n");
handle_mesh_data_unicast (NULL, &my_full_id, ©->header, NULL, 0);
copy->oid = my_full_id;
copy->tid = htonl (t->id.tid);
copy->ttl = htonl (default_ttl);
- copy->pid = htonl (t->pid + 1);
+ copy->pid = htonl (t->fwd_pid + 1);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" calling generic handler...\n");
handle_mesh_data_multicast (client, &my_full_id, ©->header, NULL, 0);