*/
unsigned int nclients;
+ /**
+ * Clients that have requested to leave the tunnel
+ */
+ struct MeshClient **ignore;
+
+ /**
+ * Number of elements in clients
+ */
+ unsigned int nignore;
+
/**
* Messages ready to transmit
*/
*/
struct GNUNET_CONTAINER_MultiHashMap *incoming_tunnels;
+ /**
+ * Tunnels this client has rejected, indexed by incoming local id
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *ignore_tunnels;
/**
* Handle to communicate with the client
*/
/****************** GENERAL HELPER FUNCTIONS ************************/
/******************************************************************************/
+/**
+ * Search for a tunnel by global ID using full PeerIdentities
+ *
+ * @param oid owner of the tunnel
+ * @param tid global tunnel number
+ *
+ * @return tunnel handler, NULL if doesn't exist
+ */
+static struct MeshTunnel *
+tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid);
+
+
+/**
+ * Delete an active client from the tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Client.
+ */
+static void
+tunnel_delete_active_client (struct MeshTunnel *t, const struct MeshClient *c);
+
+/**
+ * Notify a tunnel that a connection has broken that affects at least
+ * some of its peers.
+ *
+ * @param t Tunnel affected.
+ * @param p1 Peer that got disconnected from p2.
+ * @param p2 Peer that got disconnected from p1.
+ *
+ * @return Short ID of the peer disconnected (either p1 or p2).
+ * 0 if the tunnel remained unaffected.
+ */
+static GNUNET_PEER_Id
+tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1,
+ GNUNET_PEER_Id p2);
+
+
/**
* Check if client has registered with the service and has not disconnected
*
/**
- * Search for a tunnel by global ID using full PeerIdentities
+ * Check whether client wants traffic from a tunnel.
*
- * @param oid owner of the tunnel
- * @param tid global tunnel number
+ * @param c Client to check.
+ * @param t Tunnel to be found.
*
- * @return tunnel handler, NULL if doesn't exist
+ * @return GNUNET_YES if client knows tunnel.
+ *
+ * TODO look in client hashmap
*/
-static struct MeshTunnel *
-tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid);
+static int
+client_wants_tunnel (struct MeshClient *c, struct MeshTunnel *t)
+{
+ unsigned int i;
+
+ for (i = 0; i < t->nclients; i++)
+ if (t->clients[i] == c)
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
/**
- * Gets the index in t->clients of the client.
+ * Check whether client has been informed about a tunnel.
*
- * @param t Tunnel where to find client.
- * @param c Client to be found.
+ * @param c Client to check.
+ * @param t Tunnel to be found.
*
- * @return Index of the client, -1 if not present
+ * @return GNUNET_YES if client knows tunnel.
+ *
+ * TODO look in client hashmap
*/
static int
-tunnel_get_client_index (struct MeshTunnel *t, struct MeshClient *c);
+client_knows_tunnel (struct MeshClient *c, struct MeshTunnel *t)
+{
+ unsigned int i;
+
+ for (i = 0; i < t->nignore; i++)
+ if (t->ignore[i] == c)
+ return GNUNET_YES;
+ return client_wants_tunnel(c, t);
+}
/**
- * Notify a tunnel that a connection has broken that affects at least
- * some of its peers.
+ * Marks a client as uninterested in traffic from the tunnel, updating both
+ * client and tunnel to reflect this.
*
- * @param t Tunnel affected.
- * @param p1 Peer that got disconnected from p2.
- * @param p2 Peer that got disconnected from p1.
+ * @param c Client that doesn't want traffic anymore.
+ * @param t Tunnel which should be ignored.
*
- * @return Short ID of the peer disconnected (either p1 or p2).
- * 0 if the tunnel remained unaffected.
+ * FIXME when to delete an incoming tunnel?
*/
-static GNUNET_PEER_Id
-tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1,
- GNUNET_PEER_Id p2);
+static void
+client_ignore_tunnel (struct MeshClient *c, struct MeshTunnel *t)
+{
+ GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash);
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels,
+ &hash, t));
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_put (c->ignore_tunnels, &hash, t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+ tunnel_delete_active_client (t, c);
+ GNUNET_array_append (t->ignore, t->nignore, c);
+}
+
+
+/**
+ * Deletes a tunnel from a client (either owner or destination). To be used on
+ * tunnel destroy, otherwise, use client_ignore_tunnel.
+ *
+ * @param c Client whose tunnel to delete.
+ * @param t Tunnel which should be deleted.
+ */
+static void
+client_delete_tunnel (struct MeshClient *c, struct MeshTunnel *t)
+{
+ GNUNET_HashCode hash;
+
+ if (c == t->owner)
+ {
+ GNUNET_CRYPTO_hash(&t->local_tid, sizeof (MESH_TunnelNumber), &hash);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->own_tunnels,
+ &hash,
+ t));
+ }
+ else
+ {
+ GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash);
+ // FIXME XOR?
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels,
+ &hash,
+ t) ||
+ GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->ignore_tunnels,
+ &hash,
+ t));
+ }
+
+}
/**
struct MeshClient *c;
struct MeshTunnel *t;
MESH_TunnelNumber *tid;
- GNUNET_HashCode hash;
unsigned int count;
uint16_t type;
char cbuf[htons (msg->size)];
}
else
{
- if (-1 == tunnel_get_client_index (t, c))
+ if (GNUNET_NO == client_knows_tunnel (c, t))
{
/* This client doesn't know the tunnel */
struct GNUNET_MESH_TunnelNotification tmsg;
}
/* Check if the client wants to get traffic from the tunnel */
- GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash);
- if (GNUNET_NO ==
- GNUNET_CONTAINER_multihashmap_contains(c->incoming_tunnels, &hash))
+ if (GNUNET_NO == client_wants_tunnel(c, t))
continue;
count++;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: sending\n");
GNUNET_SERVER_notification_context_unicast (nc, t->clients[i]->handle,
&msg.header, GNUNET_NO);
}
+ // FIXME when to disconnect an incoming tunnel?
else if (1 == t->nclients && NULL != t->owner)
{
struct GNUNET_MESH_PeerControl msg;
}
+/**
+ * Delete an active client from the tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Client.
+ */
+static void
+tunnel_delete_active_client (struct MeshTunnel *t, const struct MeshClient *c)
+{
+ unsigned int i;
+
+ for (i = 0; i < t->nclients; i++)
+ {
+ if (t->clients[i] == c)
+ {
+ t->clients[i] = t->clients[t->nclients - 1];
+ GNUNET_array_grow (t->clients, t->nclients, t->nclients - 1);
+ break;
+ }
+ }
+}
+
+
+/**
+ * Delete an ignored client from the tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Client.
+ */
+static void
+tunnel_delete_ignored_client (struct MeshTunnel *t, const struct MeshClient *c)
+{
+ unsigned int i;
+
+ for (i = 0; i < t->nignore; i++)
+ {
+ if (t->ignore[i] == c)
+ {
+ t->ignore[i] = t->ignore[t->nignore - 1];
+ GNUNET_array_grow (t->ignore, t->nignore, t->nignore - 1);
+ break;
+ }
+ }
+}
+
+
+/**
+ * Delete a client from the tunnel. It should be only done on
+ * client disconnection, otherwise use client_ignore_tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Client.
+ */
+static void
+tunnel_delete_client (struct MeshTunnel *t, const struct MeshClient *c)
+{
+ tunnel_delete_ignored_client (t, c);
+ tunnel_delete_active_client (t, c);
+}
+
+
/**
* Callback used to notify a client owner of a tunnel that a peer has
* disconnected, most likely because of a path change.
}
-/**
- * Gets the index in t->clients of the client.
- *
- * @param t Tunnel where to find client.
- * @param c Client to be found.
- *
- * @return Index of the client, -1 if not present
- */
-static int
-tunnel_get_client_index (struct MeshTunnel *t, struct MeshClient *c)
-{
- int i;
-
- for (i = 0; i < t->nclients; i++)
- if (t->clients[i] == c)
- break;
- if (i < t->nclients)
- return i;
- return -1;
-}
-
/**
* Send a message to all peers in this tunnel that the tunnel is no longer
* valid.
r = GNUNET_SYSERR;
}
}
+ for (i = 0; i < t->nignore; i++)
+ {
+ c = t->ignore[i];
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_remove (c->ignore_tunnels, &hash, t))
+ {
+ r = GNUNET_SYSERR;
+ }
+ }
if (t->nclients > 0)
{
if (GNUNET_YES !=
}
-/**
- * Removes a client from the tunnel.
- *
- * @param t Tunnel from which to remove the client.
- * @param c Client that should be removed.
- *
- * FIXME when to delete an incoming tunnel?
- */
-static void
-tunnel_delete_client (struct MeshTunnel *t, struct MeshClient *c)
-{
- GNUNET_HashCode hash;
-
- GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash);
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels,
- &hash, t));
-
-}
-
/**
* 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
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Client %u is destination, keeping the tunnel alive.\n", c->id);
#endif
- tunnel_delete_client (t, c);
+ tunnel_delete_client(t, c);
+ client_delete_tunnel(c, t);
return GNUNET_OK;
}
tunnel_send_destroy(t);
&tunnel_destroy_iterator, c);
GNUNET_CONTAINER_multihashmap_iterate (c->incoming_tunnels,
&tunnel_destroy_iterator, c);
+ GNUNET_CONTAINER_multihashmap_iterate (c->ignore_tunnels,
+ &tunnel_destroy_iterator, c);
GNUNET_CONTAINER_multihashmap_destroy (c->own_tunnels);
GNUNET_CONTAINER_multihashmap_destroy (c->incoming_tunnels);
+ GNUNET_CONTAINER_multihashmap_destroy (c->ignore_tunnels);
/* deregister clients applications */
if (NULL != c->apps)
GNUNET_CONTAINER_DLL_insert (clients, clients_tail, c);
c->own_tunnels = GNUNET_CONTAINER_multihashmap_create (32);
c->incoming_tunnels = GNUNET_CONTAINER_multihashmap_create (32);
+ c->ignore_tunnels = GNUNET_CONTAINER_multihashmap_create (32);
GNUNET_SERVER_notification_context_add (nc, client);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
struct MeshClient *c;
struct MeshTunnel *t;
MESH_TunnelNumber tid;
- GNUNET_HashCode hash;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"MESH: Got a DESTROY TUNNEL from client!\n");
/* Retrieve tunnel */
tid = ntohl (tunnel_msg->tunnel_id);
-
- /* Remove from local id hashmap */
- GNUNET_CRYPTO_hash (&tid, sizeof (MESH_TunnelNumber), &hash);
- t = GNUNET_CONTAINER_multihashmap_get (c->own_tunnels, &hash);
+ t = tunnel_get_by_local_id(c, tid);
if (NULL == t)
{
GNUNET_break (0);
+#if MESH_DEBUG
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MESH: tunnel %X not found\n", tid);
+#endif
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
send_client_tunnel_disconnect(t, c);
if (c != t->owner)
{
- tunnel_delete_client (t, c);
+ client_ignore_tunnel (c, t);
#if 0
// TODO: when to destroy incoming tunnel?
if (t->nclients == 0)
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (c->own_tunnels,
- &hash,
- t));
+ client_delete_tunnel(c, t);
/* Don't try to ACK the client about the tunnel_destroy multicast packet */
t->owner = NULL;
}
/* It should be sent by someone who has this as incoming tunnel. */
- if (-1 == tunnel_get_client_index (t, c))
+ if (-1 == client_knows_tunnel (c, t))
{
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);