/**
* Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
*
* @param peer Full identity of the peer.
*
/**
* Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
*
* @param peer Short identity of the peer.
*
/**
- * Use the given path for the tunnel.
+ * @brief Use the given path for the tunnel.
+ * Update the next and prev hops (and RCs).
+ * (Re)start the path refresh in case the tunnel is locally owned.
*
* @param t Tunnel to update.
* @param p Path to use.
}
/**
- * Notify the appropiate client that a new incoming tunnel was created.
+ * Notify the appropriate client that a new incoming tunnel was created.
*
* @param t Tunnel that was created.
*/
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
msg.tunnel_id = htonl (t->local_tid_dest);
msg.port = htonl (t->port);
+ GNUNET_PEER_resolve (t->id.oid, &msg.peer);
GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
&msg.header, GNUNET_NO);
}
/**
* Notify dest client that the incoming tunnel is no longer valid.
*
- * @param t Tunnel that was destroyed.
+ * @param c Client to notify..
+ * @param t Tunnel that is destroyed.
*/
static void
-send_client_tunnel_destroy (struct MeshTunnel *t)
+send_client_tunnel_destroy (struct MeshClient *c, struct MeshTunnel *t)
{
struct GNUNET_MESH_TunnelMessage msg;
- if (NULL == t->client)
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (c != t->client && c != t->owner)
+ {
+ GNUNET_break (0);
return;
+ }
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
msg.tunnel_id = htonl (t->local_tid_dest);
- GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
+ GNUNET_SERVER_notification_context_unicast (nc, c->handle,
&msg.header, GNUNET_NO);
}
/**
* Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
*
* @param peer Full identity of the peer.
*
/**
* Retrieve the MeshPeerInfo stucture associated with the peer, create one
- * and insert it in the appropiate structures if the peer is not known yet.
+ * and insert it in the appropriate structures if the peer is not known yet.
*
* @param peer Short identity of the peer.
*
return best_p;
}
-
-/**
- * Remove the tunnel from the list of tunnels to which a peer is target.
- *
- * @param peer PeerInfo of the peer.
- * @param t Tunnel to remove.
- */
-static void
-peer_remove_tunnel (struct MeshPeerInfo *peer, struct MeshTunnel *t)
-{
- unsigned int i;
-
- for (i = 0; i < peer->ntunnels; i++)
- {
- if (0 ==
- memcmp (&peer->tunnels[i]->id, &t->id, sizeof (struct MESH_TunnelID)))
- {
- peer->ntunnels--;
- peer->tunnels[i] = peer->tunnels[peer->ntunnels];
- peer->tunnels =
- GNUNET_realloc (peer->tunnels,
- peer->ntunnels * sizeof(struct MeshTunnel *));
- return;
- }
- }
-}
-
-
/**
* Core callback to write a pre-constructed data packet to core buffer
*
path_destroy (path);
return;
}
- GNUNET_assert (peer_info->id == path->peers[path->length - 1]);
for (l = 1; l < path->length; l++)
{
if (path->peers[l] == myid)
*
* @param peer_info Peer to add the path to, being the origin of the path.
* @param path New path to add after being inversed.
+ * Path will be either used or freed.
* @param trusted Do we trust that this path is real?
*/
static void
}
+
+/**
+ * Remove a tunnel from the list of tunnels a peer participates in.
+ *
+ * @param p Peer to clean.
+ * @param t Tunnel to remove.
+ */
+static void
+peer_info_remove_tunnel (struct MeshPeerInfo *p, struct MeshTunnel *t)
+{
+ unsigned int i;
+
+ for (i = 0; i < p->ntunnels; i++)
+ {
+ if (p->tunnels[i] == t)
+ {
+ p->tunnels[i] = p->tunnels[p->ntunnels - 1];
+ GNUNET_array_grow (p->tunnels, p->ntunnels, p->ntunnels - 1);
+ return;
+ }
+ }
+}
+
+
/**
* Function called if the connection to the peer has been stalled for a while,
* possibly due to a missed ACK. Poll the peer about its ACK status.
aux = peer_get_short (p->peers[i]);
copy = path_duplicate (p);
copy->length = i + 1;
- peer_info_add_path (aux, copy, GNUNET_NO);
+ peer_info_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed);
}
}
/**
* Add a client to a tunnel, initializing all needed data structures.
*
- * FIXME: make static after implementing port numbers
- *
* @param t Tunnel to which add the client.
* @param c Client which to add to the tunnel.
*/
-void
+static void
tunnel_add_client (struct MeshTunnel *t, struct MeshClient *c)
{
+ struct GNUNET_HashCode hash;
+
if (NULL != t->client)
{
GNUNET_break(0);
return;
}
- if (0 != t->next_hop)
+ GMC_hash32 (t->local_tid_dest, &hash);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (c->incoming_tunnels, &hash, t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
{
- GNUNET_break(0);
+ GNUNET_break (0);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ GNUNET_break (0);
return;
}
t->client = c;
static void
tunnel_use_path (struct MeshTunnel *t, struct MeshPeerPath *p)
{
- unsigned int i;
+ unsigned int own_pos;
- for (i = 0; i < p->length; i++)
+ for (own_pos = 0; own_pos < p->length; own_pos++)
{
- if (p->peers[i] == myid)
+ if (p->peers[own_pos] == myid)
break;
}
- if (i > p->length - 1)
+ if (own_pos > p->length - 1)
{
GNUNET_break (0);
return;
}
- if (i < p->length - 1)
- t->next_hop = p->peers[i + 1];
+ if (own_pos < p->length - 1)
+ t->next_hop = p->peers[own_pos + 1];
else
- t->next_hop = p->peers[i];
- if (0 < i)
- t->prev_hop = p->peers[i - 1];
+ t->next_hop = p->peers[own_pos];
+ GNUNET_PEER_change_rc (t->next_hop, 1);
+ if (0 < own_pos)
+ t->prev_hop = p->peers[own_pos - 1];
else
t->prev_hop = p->peers[0];
+ GNUNET_PEER_change_rc (t->prev_hop, 1);
if (NULL != t->path)
path_destroy (t->path);
t->path = path_duplicate (p);
- if (GNUNET_SCHEDULER_NO_TASK == t->maintenance_task)
- t->maintenance_task =
- GNUNET_SCHEDULER_add_delayed (refresh_path_time, &path_refresh, t);
+ if (0 == own_pos)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK != t->maintenance_task)
+ GNUNET_SCHEDULER_cancel (t->maintenance_task);
+ t->maintenance_task = GNUNET_SCHEDULER_add_delayed (refresh_path_time,
+ &path_refresh, t);
+ }
}
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
msg.tunnel_id = htonl (t->owner == c ? t->local_tid : t->local_tid_dest);
- msg.max_pid = htonl (ack);
+ msg.ack = htonl (ack);
GNUNET_SERVER_notification_context_unicast(nc,
c->handle,
&msg.header,
case GNUNET_MESSAGE_TYPE_MESH_ACK:
case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK:
break;
+ case GNUNET_MESSAGE_TYPE_MESH_PATH_ACK:
case GNUNET_MESSAGE_TYPE_MESH_POLL:
t->force_ack = GNUNET_YES;
break;
}
+/**
+ * Modify the unicast message TID from global to local and send to client.
+ *
+ * @param t Tunnel on which to send the message.
+ * @param msg Message to modify and send.
+ */
+static void
+tunnel_send_client_ucast (struct MeshTunnel *t,
+ const struct GNUNET_MESH_Unicast *msg)
+{
+ struct GNUNET_MESH_Unicast *copy;
+ uint16_t size = ntohs (msg->header.size);
+ char cbuf[size];
+
+ if (size < sizeof (struct GNUNET_MESH_Unicast) +
+ sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (NULL == t->client)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ copy = (struct GNUNET_MESH_Unicast *) cbuf;
+ memcpy (copy, msg, size);
+ copy->tid = htonl (t->local_tid_dest);
+ GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
+ ©->header, GNUNET_NO);
+}
+
+
+/**
+ * Modify the to_origin message TID from global to local and send to client.
+ *
+ * @param t Tunnel on which to send the message.
+ * @param msg Message to modify and send.
+ */
+static void
+tunnel_send_client_to_orig (struct MeshTunnel *t,
+ const struct GNUNET_MESH_ToOrigin *msg)
+{
+ struct GNUNET_MESH_ToOrigin *copy;
+ uint16_t size = ntohs (msg->header.size);
+ char cbuf[size];
+
+ if (size < sizeof (struct GNUNET_MESH_ToOrigin) +
+ sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (NULL == t->owner)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ copy = (struct GNUNET_MESH_ToOrigin *) cbuf;
+ memcpy (cbuf, msg, size);
+ copy->tid = htonl (t->local_tid);
+ GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle,
+ ©->header, GNUNET_NO);
+}
+
+
/**
* @brief Re-initiate traffic to this peer if necessary.
*
/**
- * Send a message to all peers in this tunnel that the tunnel is no longer
- * valid.
+ * Send a message to all peers and clients in this tunnel that the tunnel
+ * is no longer valid. If some peer or client should not receive the message,
+ * should be zero'ed out before calling this function.
*
- * @param t The tunnel whose peers to notify.
+ * @param t The tunnel whose peers and clients to notify.
*/
static void
tunnel_send_destroy (struct MeshTunnel *t)
" sending tunnel destroy for tunnel: %s [%X]\n",
GNUNET_i2s (&msg.oid), t->id.tid);
- if (NULL == t->client)
+ if (NULL == t->client && 0 != t->next_hop)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " child: %u\n", t->next_hop);
GNUNET_PEER_resolve (t->next_hop, &id);
GNUNET_i2s (&id));
send_prebuilt_message (&msg.header, t->next_hop, t);
}
- if (NULL == t->owner)
+ if (NULL == t->owner && 0 != t->prev_hop)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " parent: %u\n", t->prev_hop);
GNUNET_PEER_resolve (t->prev_hop, &id);
GNUNET_i2s (&id));
send_prebuilt_message (&msg.header, t->prev_hop, t);
}
+ if (NULL != t->owner)
+ {
+ send_client_tunnel_destroy (t->owner, t);
+ }
+ if (NULL != t->client)
+ {
+ send_client_tunnel_destroy (t->client, t);
+ }
}
struct MeshPeerQueue *pq;
struct MeshPeerQueue *next;
+ if (0 == neighbor)
+ return; /* Was local peer, 0'ed in tunnel_destroy_iterator */
peer_info = peer_get_short (neighbor);
for (pq = peer_info->queue_head; NULL != pq; pq = next)
{
/**
- * Destroy the tunnel and free any allocated resources linked to it.
+ * Destroy the tunnel.
+ *
+ * This function does not generate any warning traffic to clients or peers.
+ *
+ * Tasks:
+ * Remove the tunnel from peer_info's and clients' hashmaps.
+ * Cancel messages belonging to this tunnel queued to neighbors.
+ * Free any allocated resources linked to the tunnel.
*
* @param t the tunnel to destroy
*
if (NULL != t->client)
{
+ c = t->client;
GMC_hash32 (t->local_tid_dest, &hash);
if (GNUNET_YES !=
GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, &hash, t))
GNUNET_break (0);
r = GNUNET_SYSERR;
}
- }
- if (GNUNET_YES !=
+ if (GNUNET_YES !=
GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t))
- {
- GNUNET_break (0);
- r = GNUNET_SYSERR;
+ {
+ GNUNET_break (0);
+ r = GNUNET_SYSERR;
+ }
}
- peer_cancel_queues (t->next_hop, t);
- peer_cancel_queues (t->prev_hop, t);
+ if (0 != t->prev_hop)
+ {
+ peer_cancel_queues (t->prev_hop, t);
+ GNUNET_PEER_change_rc (t->prev_hop, -1);
+ }
+ if (0 != t->next_hop)
+ {
+ peer_cancel_queues (t->next_hop, t);
+ GNUNET_PEER_change_rc (t->next_hop, -1);
+ }
if (GNUNET_SCHEDULER_NO_TASK != t->maintenance_task)
GNUNET_SCHEDULER_cancel (t->maintenance_task);
n_tunnels--;
GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
+ path_destroy (t->path);
GNUNET_free (t);
return r;
}
-#define TUNNEL_DESTROY_EMPTY_TIME GNUNET_TIME_UNIT_MILLISECONDS
-
/**
* Tunnel is empty: destroy it.
*
+ * Notifies all participants (peers, cleints) about the destruction.
+ *
* @param t Tunnel to destroy.
*/
static void
}
#endif
- tunnel_send_destroy (t);
+ if (GNUNET_NO == t->destroy)
+ tunnel_send_destroy (t);
if (0 == t->pending_messages)
tunnel_destroy (t);
else
/**
- * tunnel_destroy_iterator: iterator for deleting each tunnel that belongs to a
- * client when the client disconnects. If the client is not the owner, the
- * owner will get notified if no more clients are in the tunnel and the client
- * get removed from the tunnel's list.
+ * Iterator for deleting each tunnel whose client endpoint disconnected.
*
- * @param cls closure (client that is disconnecting)
- * @param key the hash of the local tunnel id (used to access the hashmap)
- * @param value the value stored at the key (tunnel to destroy)
+ * @param cls Closure (client that has disconnected).
+ * @param key The hash of the local tunnel id (used to access the hashmap).
+ * @param value The value stored at the key (tunnel to destroy).
*
* @return GNUNET_OK, keep iterating.
*/
struct MeshTunnel *t = value;
struct MeshClient *c = cls;
- send_client_tunnel_destroy (t);
- if (c != t->owner)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " Tunnel %X / %X destroy, due to client %u shutdown.\n",
+ t->local_tid, t->local_tid_dest, c->id);
+ client_delete_tunnel (c, t);
+ if (c == t->client)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %u is destination.\n", c->id);
- client_delete_tunnel (c, t);
- tunnel_destroy_empty (t);
- return GNUNET_OK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is destination.\n", c->id);
+ t->client = NULL;
+ GNUNET_PEER_change_rc (t->next_hop, -1);
+ t->next_hop = 0;
+ }
+ else if (c == t->owner)
+ {
+ struct MeshPeerInfo *p;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is owner.\n", c->id);
+ t->owner = NULL;
+ GNUNET_PEER_change_rc (t->prev_hop, -1);
+ t->prev_hop = 0;
+ p = peer_get_short(t->dest);
+ peer_info_remove_tunnel (p, t);
+ }
+ else
+ {
+ GNUNET_break (0);
}
- tunnel_send_destroy (t);
- t->owner = NULL;
- t->destroy = GNUNET_YES;
+ tunnel_destroy_empty (t);
return GNUNET_OK;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Tunnel %s [%X] timed out. Destroying.\n",
GNUNET_i2s(&id), t->id.tid);
- send_client_tunnel_destroy (t);
- tunnel_destroy (t);
+ if (NULL != t->client)
+ send_client_tunnel_destroy (t->client, t);
+ tunnel_destroy (t); /* Do not notify other */
}
GNUNET_break (0);
return 0;
}
- t->prev_fc.last_ack_sent = t->nobuffer ? 0 : INITIAL_WINDOW_SIZE - 1;
+ t->prev_fc.last_ack_sent = t->nobuffer ? 0 : t->queue_max - 1;
msg->header.size = htons (sizeof (struct GNUNET_MESH_PathACK));
msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
GNUNET_PEER_resolve (t->id.oid, &msg->oid);
queue->peer->queue_tail,
queue);
- /* Delete from appropiate fc in the tunnel */
+ /* Delete from appropriate fc in the tunnel */
if (queue->peer->id == queue->tunnel->next_hop)
fc = &queue->tunnel->next_fc;
else if (queue->peer->id == queue->tunnel->next_hop)
uint32_t pid;
uint32_t ack;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* selecting message\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* selecting message\n");
for (q = peer->queue_head; NULL != q; q = q->next)
{
t = q->tunnel;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* %s\n",
+ "* %s\n",
GNUNET_MESH_DEBUG_M2S(q->type));
switch (q->type)
{
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* OK!\n");
+ "* OK!\n");
return q;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* ACK: %u, PID: %u\n",
+ "* ACK: %u, PID: %u\n",
ack, pid);
if (GNUNET_NO == GMC_is_pid_bigger (pid, ack))
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* OK!\n");
+ "* OK!\n");
return q;
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* NEXT!\n");
+ "* NEXT!\n");
}
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* nothing found\n");
+ "* nothing found\n");
return NULL;
}
peer->core_transmit = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* Queue send\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Queue send\n");
queue = queue_get_next (peer);
/* Queue has no internal mesh traffic nor sendable payload */
if (NULL == queue)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* not ready, return\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* not ready, return\n");
if (NULL == peer->queue_head)
GNUNET_break (0); /* Core tmt_rdy should've been canceled */
return 0;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* not empty\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* not empty\n");
GNUNET_PEER_resolve (peer->id, &dst_id);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* towards %s\n",
+ "* towards %s\n",
GNUNET_i2s (&dst_id));
/* Check if buffer size is enough for the message */
if (queue->size > size)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* not enough room, reissue\n");
+ "* not enough room, reissue\n");
peer->core_transmit =
GNUNET_CORE_notify_transmit_ready (core_handle,
GNUNET_NO,
peer);
return 0;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* size ok\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* size ok\n");
t = queue->tunnel;
GNUNET_assert (0 < t->pending_messages);
case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
case GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "********* raw: %s\n",
+ "* raw: %s\n",
GNUNET_MESH_DEBUG_M2S (queue->type));
/* Fall through */
case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
type = ntohs (msg->type);
break;
case GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* path create\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* path create\n");
data_size = send_core_path_create (queue->cls, size, buf);
break;
case GNUNET_MESSAGE_TYPE_MESH_PATH_ACK:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* path ack\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* path ack\n");
data_size = send_core_path_ack (queue->cls, size, buf);
break;
default:
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "********* type unknown: %u\n",
+ "* type unknown: %u\n",
queue->type);
data_size = 0;
}
if (GNUNET_YES == t->destroy && 0 == t->pending_messages)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* destroying tunnel!\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* destroying tunnel!\n");
tunnel_destroy (t);
}
{
struct GNUNET_PeerIdentity id;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* more data!\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* more data!\n");
GNUNET_PEER_resolve (peer->id, &id);
peer->core_transmit =
GNUNET_CORE_notify_transmit_ready(core_handle,
else if (NULL != peer->queue_head)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "********* %s stalled\n",
+ "* %s stalled\n",
GNUNET_i2s (&my_full_id));
if (peer->id == t->next_hop)
fc = &t->next_fc;
&tunnel_poll, fc);
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* Return %d\n", data_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Return %d\n", data_size);
return data_size;
}
MESH_TunnelNumber tid;
struct GNUNET_MESH_CreateTunnel *msg;
struct GNUNET_PeerIdentity *pi;
- struct GNUNET_HashCode hash;
struct MeshPeerPath *path;
struct MeshPeerInfo *dest_peer_info;
struct MeshPeerInfo *orig_peer_info;
return GNUNET_OK;
}
size /= sizeof (struct GNUNET_PeerIdentity);
- if (size < 2)
+ if (size < 1)
{
GNUNET_break_op (0);
return GNUNET_OK;
tid = ntohl (msg->tid);
pi = (struct GNUNET_PeerIdentity *) &msg[1];
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " path is for tunnel %s [%X].\n", GNUNET_i2s (pi), tid);
+ " path is for tunnel %s[%X].\n", GNUNET_i2s (pi), tid);
t = tunnel_get (pi, tid);
- if (NULL == t)
+ if (NULL == t) /* might be a local tunnel */
{
uint32_t opt;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " nobuffer:%d\n", t->nobuffer);
tunnel_reset_timeout (t);
- GMC_hash32 (t->local_tid_dest, &hash);
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
- {
- tunnel_destroy (t);
- GNUNET_break (0);
- return GNUNET_OK;
- }
- }
- else
- {
- GNUNET_break_op (0);
}
t->state = MESH_TUNNEL_WAITING;
dest_peer_info =
own_pos = i;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
- if (own_pos == 0)
+ if (own_pos == 0 && path->peers[own_pos] != myid)
{
- /* cannot be self, must be 'not found' */
/* create path: self not found in path through self */
GNUNET_break_op (0);
path_destroy (path);
return GNUNET_OK;
}
path_add_to_peers (path, GNUNET_NO);
- t->prev_hop = path->peers[own_pos - 1];
- GNUNET_PEER_change_rc (t->prev_hop, 1);
+ tunnel_use_path (t, path);
+
if (own_pos == size - 1)
{
struct MeshClient *c;
/* TODO send reject */
return GNUNET_OK;
}
- t->client = c;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
peer_info_add_path_to_origin (orig_peer_info, path, GNUNET_YES);
t->local_tid_dest = next_local_tid++;
next_local_tid = next_local_tid | GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
+ tunnel_add_client (t, c);
send_client_tunnel_create (t);
send_path_ack (t);
}
GNUNET_PEER_change_rc(t->next_hop, 1);
/* It's for somebody else! Retransmit. */
- path2 = path_duplicate (path);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n");
- peer_info_add_path (dest_peer_info, path2, GNUNET_NO);
path2 = path_duplicate (path);
- peer_info_add_path_to_origin (orig_peer_info, path2, GNUNET_NO);
+ peer_info_add_path (dest_peer_info, path2, GNUNET_NO);
+ peer_info_add_path_to_origin (orig_peer_info, path, GNUNET_NO);
send_create_path (t);
}
return GNUNET_OK;
}
+
+/**
+ * Core handler for path 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_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_MESH_PathACK *msg;
+ struct MeshPeerInfo *peer_info;
+ struct MeshPeerPath *p;
+ struct MeshTunnel *t;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a path ACK msg [%s]\n",
+ GNUNET_i2s (&my_full_id));
+ msg = (struct GNUNET_MESH_PathACK *) message;
+ t = tunnel_get (&msg->oid, ntohl(msg->tid));
+ if (NULL == t)
+ {
+ /* TODO notify that we don't know the tunnel */
+ GNUNET_STATISTICS_update (stats, "# control on unknown tunnel", 1, GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " don't know the tunnel %s [%X]!\n",
+ GNUNET_i2s (&msg->oid), ntohl(msg->tid));
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " on tunnel %s [%X]\n",
+ GNUNET_i2s (&msg->oid), ntohl(msg->tid));
+
+ peer_info = peer_get (&msg->peer_id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by peer %s\n",
+ GNUNET_i2s (&msg->peer_id));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n",
+ GNUNET_i2s (peer));
+
+ /* Add path to peers? */
+ p = t->path;
+ if (NULL != p)
+ {
+ path_add_to_peers (p, GNUNET_YES);
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+ t->state = MESH_TUNNEL_READY;
+ t->next_fc.last_ack_recv = (NULL == t->client) ? ntohl (msg->ack) : 0;
+ t->prev_fc.last_ack_sent = ntohl (msg->ack);
+
+ /* Message for us? */
+ if (0 == memcmp (&msg->oid, &my_full_id, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
+ if (NULL == t->owner)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ if (NULL != peer_info->dhtget)
+ {
+ GNUNET_DHT_get_stop (peer_info->dhtget);
+ peer_info->dhtget = NULL;
+ }
+ tunnel_send_bck_ack (t, GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
+ tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
+ return GNUNET_OK;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " not for us, retransmitting...\n");
+ peer_info = peer_get (&msg->oid);
+ send_prebuilt_message (message, t->prev_hop, t);
+ return GNUNET_OK;
+}
+
+
/**
* Core handler for notifications of broken paths
*
1, GNUNET_NO);
return GNUNET_OK;
}
- // TODO check owner's signature
if (t->local_tid_dest >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
{
- /* Tunnel was incoming, notify clients */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "INCOMING TUNNEL %X %X\n",
t->local_tid, t->local_tid_dest);
- send_client_tunnel_destroy (t);
}
- tunnel_send_destroy (t);
- t->destroy = GNUNET_YES;
+ if (GNUNET_PEER_search (peer) == t->prev_hop)
+ {
+ // TODO check owner's signature
+ // TODO add owner's signatue to tunnel for retransmission
+ peer_cancel_queues (t->prev_hop, t);
+ GNUNET_PEER_change_rc (t->prev_hop, -1);
+ t->prev_hop = 0;
+ }
+ else if (GNUNET_PEER_search (peer) == t->next_hop)
+ {
+ // TODO check dest's signature
+ // TODO add dest's signatue to tunnel for retransmission
+ peer_cancel_queues (t->next_hop, t);
+ GNUNET_PEER_change_rc (t->next_hop, -1);
+ t->next_hop = 0;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ // TODO check both owner AND destination's signature to see which matches
+ // TODO restransmit in appropriate direction
+ return GNUNET_OK;
+ }
+ tunnel_destroy_empty (t);
+
// TODO: add timeout to destroy the tunnel anyway
return GNUNET_OK;
}
tunnel_reset_timeout (t);
if (t->dest == myid)
{
- if (NULL == t->client)
- {
- GNUNET_break (0);
- return GNUNET_OK;
- }
+ /* TODO signature verification */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" it's for us! sending to clients...\n");
GNUNET_STATISTICS_update (stats, "# unicast received", 1, GNUNET_NO);
- GNUNET_SERVER_notification_context_unicast (nc, t->client->handle,
- message, GNUNET_NO);
+ tunnel_send_client_ucast (t, msg);
tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_UNICAST);
return GNUNET_OK;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" pid %u not seen yet, forwarding\n", pid);
- if (NULL != t->owner)
+ if (myid == t->id.oid)
{
- char cbuf[size];
- struct GNUNET_MESH_ToOrigin *copy;
-
+ /* TODO signature verification */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" it's for us! sending to clients...\n");
- /* TODO signature verification */
- memcpy (cbuf, message, size);
- copy = (struct GNUNET_MESH_ToOrigin *) cbuf;
- copy->tid = htonl (t->local_tid);
GNUNET_STATISTICS_update (stats, "# to origin received", 1, GNUNET_NO);
- GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle,
- ©->header, GNUNET_NO);
+ tunnel_send_client_to_orig (t, msg);
tunnel_send_bck_ack (t, GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
return GNUNET_OK;
}
return GNUNET_OK;
}
-/**
- * Core handler for path 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_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_MESH_PathACK *msg;
- struct MeshPeerInfo *peer_info;
- struct MeshPeerPath *p;
- struct MeshTunnel *t;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a path ACK msg [%s]\n",
- GNUNET_i2s (&my_full_id));
- msg = (struct GNUNET_MESH_PathACK *) message;
- t = tunnel_get (&msg->oid, ntohl(msg->tid));
- if (NULL == t)
- {
- /* TODO notify that we don't know the tunnel */
- GNUNET_STATISTICS_update (stats, "# control on unknown tunnel", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " don't know the tunnel %s [%X]!\n",
- GNUNET_i2s (&msg->oid), ntohl(msg->tid));
- return GNUNET_OK;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " on tunnel %s [%X]\n",
- GNUNET_i2s (&msg->oid), ntohl(msg->tid));
-
- peer_info = peer_get (&msg->peer_id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by peer %s\n",
- GNUNET_i2s (&msg->peer_id));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n",
- GNUNET_i2s (peer));
-
- /* Add path to peers? */
- p = t->path;
- if (NULL != p)
- {
- path_add_to_peers (p, GNUNET_YES);
- }
- else
- {
- GNUNET_break (0);
- }
- t->state = MESH_TUNNEL_READY;
- t->next_fc.last_ack_recv = ntohl (msg->ack);
- t->prev_fc.last_ack_sent = ntohl (msg->ack);
-
- /* Message for us? */
- if (0 == memcmp (&msg->oid, &my_full_id, sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
- if (NULL == t->owner)
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- if (NULL != peer_info->dhtget)
- {
- GNUNET_DHT_get_stop (peer_info->dhtget);
- peer_info->dhtget = NULL;
- }
- tunnel_send_bck_ack (t, GNUNET_MESSAGE_TYPE_MESH_PATH_ACK);
- return GNUNET_OK;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " not for us, retransmitting...\n");
- peer_info = peer_get (&msg->oid);
- send_prebuilt_message (message, t->prev_hop, t);
- return GNUNET_OK;
-}
-
/**
* Core handler for mesh keepalives.
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- t->port = ntohl (t->port);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATED TUNNEL %s[%x] (%x)\n",
- GNUNET_i2s (&my_full_id), t->id.tid, t->local_tid);
+ t->port = ntohl (t_msg->port);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATED TUNNEL %s[%x]:%u (%x)\n",
+ GNUNET_i2s (&my_full_id), t->id.tid, t->port, t->local_tid);
peer_info = peer_get (&t_msg->peer);
GNUNET_array_append (peer_info->tunnels, peer_info->ntunnels, t);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
+
+ /* Cleanup after the tunnel */
+ client_delete_tunnel (c, t);
if (c == t->client)
{
- tunnel_destroy_empty (t);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
+ t->client = NULL;
+ }
+ else if (c == t->owner)
+ {
+ peer_info_remove_tunnel (peer_get_short(t->dest), t);
+ t->owner = NULL;
}
- send_client_tunnel_destroy (t);
- client_delete_tunnel (c, t);
- /* Don't try to ACK the client about the tunnel_destroy multicast packet */
- t->owner = NULL;
- tunnel_send_destroy (t);
- peer_remove_tunnel (peer_get_short(t->dest), t);
- t->destroy = GNUNET_YES;
/* The tunnel will be destroyed when the last message is transmitted. */
+ tunnel_destroy_empty (t);
+
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
return;
}
- ack = ntohl (msg->max_pid);
+ ack = ntohl (msg->ack);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ack);
/* Does client own tunnel? I.E: Is this an ACK for BCK traffic? */
}
+/**
+ * Install server (service) handlers and start listening to clients.
+ */
+static void
+server_init (void)
+{
+ GNUNET_SERVER_add_handlers (server_handle, client_handlers);
+ GNUNET_SERVER_disconnect_notify (server_handle,
+ &handle_local_client_disconnect, NULL);
+ nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
+
+ clients_head = NULL;
+ clients_tail = NULL;
+ next_client_id = 0;
+ GNUNET_SERVER_resume (server_handle);
+}
+
+
/**
* To be called on core init/fail.
*
static int i = 0;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
- core_handle = server;
+ GNUNET_break (core_handle == server);
if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)) ||
NULL == server)
{
if (10 < i++)
GNUNET_abort();
}
- return;
+ server_init ();
+ return;
}
struct MeshPeerInfo *peer;
struct MeshPeerPath *p;
- keygen = NULL;
+ keygen = NULL;
if (NULL == pk)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Mesh service could not access hostkey: %s. Exiting.\n"),
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Could not access hostkey: %s. Exiting.\n"),
emsg);
GNUNET_SCHEDULER_shutdown ();
return;
next_tid = 0;
next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
-
- GNUNET_SERVER_add_handlers (server_handle, client_handlers);
- nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
- GNUNET_SERVER_disconnect_notify (server_handle,
- &handle_local_client_disconnect, NULL);
-
-
- clients_head = NULL;
- clients_tail = NULL;
- next_client_id = 0;
-
announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls);
/* Create a peer_info for the local peer */
p->peers[0] = myid;
GNUNET_PEER_change_rc (myid, 1);
peer_info_add_path (peer, p, GNUNET_YES);
- GNUNET_SERVER_resume (server_handle);
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh service running\n");
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
server_handle = server;
+ GNUNET_SERVER_suspend (server_handle);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (c, "PEER", "PRIVATE_KEY",
}
stats = GNUNET_STATISTICS_create ("mesh", c);
- GNUNET_SERVER_suspend (server_handle);
/* Scheduled the task to clean up when shutdown is called */
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
NULL);