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);
}
}
+
+/**
+ * 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.
/**
* 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;
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.
*
" 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);
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)
{
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);
n_tunnels--;
GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
+ path_destroy (t->path);
GNUNET_free (t);
return r;
}
}
#endif
- tunnel_send_destroy (t);
+ if (GNUNET_NO == t->destroy)
+ tunnel_send_destroy (t);
if (0 == t->pending_messages)
tunnel_destroy (t);
else
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);
+ if (GNUNET_NO == c->shutting_down)
+ send_client_tunnel_destroy (t);
+ 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;
+ t->next_hop = 0;
}
- tunnel_send_destroy (t);
- t->owner = NULL;
- t->destroy = GNUNET_YES;
+ else if (c == t->owner)
+ {
+ struct MeshPeerInfo *p;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is owner.\n", c->id);
+ t->owner = NULL;
+ t->prev_hop = 0;
+ p = peer_get_short(t->dest);
+ peer_info_remove_tunnel (p, t);
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+ tunnel_destroy_empty (t);
return GNUNET_OK;
}
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;
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;
- }
}
t->state = MESH_TUNNEL_WAITING;
dest_peer_info =
/* 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);
}
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;
}
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;
}