*/
struct MeshConnection *c;
+ /**
+ * Is FWD in c?
+ */
+ int fwd;
+
/**
* Channel this message belongs to, if known.
*/
struct MeshFlowControl
{
/**
- * Peer
- */
- struct MeshPeer *peer;
-
- /**
- * Transmission queue to core DLL head
- */
- struct MeshPeerQueue *queue_head;
-
- /**
- * Transmission queue to core DLL tail
+ * Connection this controls.
*/
- struct MeshPeerQueue *queue_tail;
+ struct MeshConnection *c;
/**
- * How many messages are in the queue to this peer.
+ * How many messages are in the queue on this connection.
*/
unsigned int queue_n;
*/
unsigned int queue_max;
- /**
- * Handle for queued transmissions
- */
- struct GNUNET_CORE_TransmitHandle *core_transmit;
-
/**
* ID of the last packet sent towards the peer.
*/
*/
struct GNUNET_TIME_Absolute last_contact;
- /**
- * Number of attempts to reconnect so far
- */
- int n_reconnect_attempts;
-
/**
* Paths to reach the peer, ordered by ascending hop count
*/
struct MeshTunnel2 *tunnel;
/**
- * Flow control information for direct traffic.
+ * Connections that go through this peer, indexed by tid;
*/
- struct MeshFlowControl *fc;
+ struct GNUNET_CONTAINER_MultiHashMap *connections;
+
+ /**
+ * Handle for queued transmissions
+ */
+ struct GNUNET_CORE_TransmitHandle *core_transmit;
+
+ /**
+ * Transmission queue to core DLL head
+ */
+ struct MeshPeerQueue *queue_head;
+
+ /**
+ * Transmission queue to core DLL tail
+ */
+ struct MeshPeerQueue *queue_tail;
+ /**
+ * How many messages are in the queue to this peer.
+ */
+ unsigned int queue_n;
};
struct MeshReliableMessage *tail_sent;
/**
- * Messages pending
+ * Messages pending to send.
*/
unsigned int n_sent;
- /**
- * Next MID to use.
- */
- uint32_t mid_sent;
-
/**
* DLL of messages received out of order.
*/
struct MeshReliableMessage *tail_recv;
/**
- * Next MID expected.
+ * Messages received.
+ */
+ unsigned int n_recv;
+
+ /**
+ * Can we send data to the client?
*/
- uint32_t mid_recv;
+ int client_ready;
/**
* Task to resend/poll in case no ACK is received.
uint32_t port;
/**
- * Local tunnel number ( >= GNUNET_MESH_LOCAL_CHANNEL_ID_CLI or 0 )
+ * Global channel number ( < GNUNET_MESH_LOCAL_CHANNEL_ID_CLI)
*/
- MESH_ChannelNumber id;
+ MESH_ChannelNumber gid;
+
+ /**
+ * Local tunnel number for root (owner) client.
+ * ( >= GNUNET_MESH_LOCAL_CHANNEL_ID_CLI or 0 )
+ */
+ MESH_ChannelNumber lid_root;
/**
* Local tunnel number for local destination clients (incoming number)
- * ( >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV or 0). All clients share the same
- * number.
+ * ( >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV or 0).
+ */
+ MESH_ChannelNumber lid_dest;
+
+ /**
+ * Next MID to use for fwd traffic.
+ */
+ uint32_t mid_send_fwd;
+
+ /**
+ * Next MID expected for fwd traffic.
+ */
+ uint32_t mid_recv_fwd;
+
+ /**
+ * Next MID to use for bck traffic.
*/
- MESH_ChannelNumber id_dest;
+ uint32_t mid_send_bck;
/**
+ * Next MID expected for bck traffic.
+ */
+ uint32_t mid_recv_bck;
+
+ /**
* Is the tunnel bufferless (minimum latency)?
*/
int nobuffer;
/**
* Client owner of the tunnel, if any
*/
- struct MeshClient *owner;
+ struct MeshClient *root;
/**
* Client destination of the tunnel, if any.
*/
- struct MeshClient *client;
+ struct MeshClient *dest;
/**
* Flag to signal the destruction of the channel.
*/
struct MeshTunnel2 *t;
+ /**
+ * Flow control information for traffic fwd.
+ */
+ struct MeshFlowControl fwd_fc;
+
+ /**
+ * Flow control information for traffic bck.
+ */
+ struct MeshFlowControl bck_fc;
+
/**
* Connection number.
*/
/**
* Local peer ephemeral public key
*/
- struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *my_eph;
+ struct GNUNET_CRYPTO_EccPublicKey *my_eph;
/**
* Remote peer's public key.
*/
- struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *peers_eph;
+ struct GNUNET_CRYPTO_EccPublicKey *peers_eph;
/**
* Encryption ("our") key.
struct MeshChannel *channel_tail;
/**
- * Channel ID for the next created tunnel.
+ * Channel ID for the next created channel.
*/
MESH_ChannelNumber next_chid;
/**
- * Channel ID for the next incoming tunnel.
+ * Channel ID for the next incoming channel.
*/
MESH_ChannelNumber next_local_chid;
/**
* Own public key.
*/
-static struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded my_public_key;
+static struct GNUNET_CRYPTO_EccPublicKey my_public_key;
/**
* All ports clients of this peer have opened.
/**
- * Search for a channel by global ID using full PeerIdentities.
+ * Search for a tunnel by global ID using full PeerIdentities.
*
- * @param oid owner of the tunnel.
- * @param tid global tunnel number.
+ * @param t Tunnel containing the channel.
+ * @param chid Public channel number.
*
- * @return tunnel handler, NULL if doesn't exist.
+ * @return channel handler, NULL if doesn't exist
*/
static struct MeshChannel *
-channel_get (const struct GNUNET_PeerIdentity *oid, MESH_ChannelNumber tid);
+channel_get (struct MeshTunnel2 *t, MESH_ChannelNumber chid);
/**
queue_destroy (struct MeshPeerQueue *queue, int clear_cls);
-/**
- * @brief Get the next transmittable message from the queue.
- *
- * This will be the head, except in the case of being a data packet
- * not allowed by the destination peer.
- *
- * @param peer Destination peer.
- *
- * @return The next viable MeshPeerQueue element to send to that peer.
- * NULL when there are no transmittable messages.
- */
-struct MeshPeerQueue *
-queue_get_next (const struct MeshPeer *peer);
-
-
/**
* Core callback to write a queued packet to core buffer
*
}
+/**
+ * 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);
+}
+
/**
* Check if client has registered with the service and has not disconnected
*
/**
- * Deletes a tunnel from a client (either owner or destination). To be used on
- * tunnel destroy.
+ * Deletes a tunnel from a client (either owner or destination).
*
* @param c Client whose tunnel to delete.
* @param ch Channel which should be deleted.
{
int res;
- if (c == ch->owner)
+ if (c == ch->root)
{
res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
- ch->id, ch);
+ ch->lid_root, ch);
if (GNUNET_YES != res)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel owner KO\n");
}
- if (c == ch->client)
+ if (c == ch->dest)
{
res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
- ch->id_dest, ch);
+ ch->lid_dest, ch);
if (GNUNET_YES != res)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel client KO\n");
}
struct GNUNET_MESH_ChannelMessage msg;
struct MeshTunnel2 *t = ch->t;
- if (NULL == ch->client)
+ if (NULL == ch->dest)
return;
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
- msg.channel_id = htonl (ch->id_dest);
+ msg.channel_id = htonl (ch->lid_dest);
msg.port = htonl (ch->port);
msg.opt = 0;
msg.opt |= GNUNET_YES == ch->reliable ? GNUNET_MESH_OPTION_RELIABLE : 0;
msg.opt |= GNUNET_YES == ch->nobuffer ? GNUNET_MESH_OPTION_NOBUFFER : 0;
msg.opt = htonl (msg.opt);
GNUNET_PEER_resolve (t->peer->id, &msg.peer);
- GNUNET_SERVER_notification_context_unicast (nc, ch->client->handle,
+ GNUNET_SERVER_notification_context_unicast (nc, ch->dest->handle,
&msg.header, GNUNET_NO);
}
struct GNUNET_MESH_ChannelMessage msg;
struct MeshClient *c;
- c = fwd ? ch->client : ch->owner;
+ c = fwd ? ch->dest : ch->root;
if (NULL == c)
{
GNUNET_break (0);
}
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
- msg.channel_id = htonl (fwd ? ch->id_dest : ch->id);
+ msg.channel_id = htonl (fwd ? ch->lid_dest : ch->lid_root);
msg.port = htonl (0);
memset (&msg.peer, 0, sizeof (msg.peer));
msg.opt = htonl (0);
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
- msg.channel_id = htonl (is_fwd ? ch->id : ch->id_dest);
+ msg.channel_id = htonl (is_fwd ? ch->lid_root : ch->lid_dest);
GNUNET_SERVER_notification_context_unicast (nc,
c->handle,
&msg.header,
{
struct MeshConnection *c;
struct MeshConnection *best;
- struct MeshPeer *peer;
+ struct MeshFlowControl *fc;
unsigned int lowest_q;
-
- peer = NULL;
best = NULL;
lowest_q = UINT_MAX;
for (c = t->connection_head; NULL != c; c = c->next)
{
if (MESH_CONNECTION_READY == c->state)
{
- peer = fwd ? connection_get_next_hop (c) : connection_get_prev_hop (c);
- if (NULL == peer->fc)
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (NULL == fc)
{
GNUNET_break (0);
continue;
}
- if (peer->fc->queue_n < lowest_q)
+ if (fc->queue_n < lowest_q)
{
best = c;
- lowest_q = peer->fc->queue_n;
+ lowest_q = fc->queue_n;
}
}
}
}
+/**
+ * Get the total buffer space for a tunnel
+ */
+static unsigned int
+tunnel_get_buffer (struct MeshTunnel2 *t, int fwd)
+{
+ struct MeshConnection *c;
+ struct MeshFlowControl *fc;
+ unsigned int buffer;
+
+ for (buffer = 0, c = t->connection_head; NULL != c; c = c->next)
+ {
+ if (c->state != MESH_CONNECTION_READY)
+ continue;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ buffer += fc->last_ack_recv - fc->last_pid_sent;
+ }
+
+ return buffer;
+}
+
+
/**
* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
* Encrypt data with the tunnel key.
size_t size;
uint16_t type;
- neighbor = fwd ? connection_get_next_hop (c) : connection_get_prev_hop (c);
+ neighbor = connection_get_hop (c, fwd);
if (NULL == neighbor)
{
GNUNET_break (0);
}
-/**
- * Sends an already built message directly to a peer.
- * Message does must not belong to a connection or channel.
- *
- * @param message Message to send. Function makes a copy of it.
- * @param peer Tunnel on which this message is transmitted.
- */
-static void
-send_prebuilt_message_peer (const struct GNUNET_MessageHeader *message,
- struct MeshPeer *peer)
-{
- void *data;
- size_t size;
- uint16_t type;
-
- if (NULL == peer)
- {
- GNUNET_break (0);
- return;
- }
-
- size = ntohs (message->size);
- data = GNUNET_malloc (size);
- memcpy (data, message, size);
- type = ntohs(message->type);
-
- queue_add (data,
- type,
- size,
- peer,
- NULL,
- NULL);
-}
-
-
/**
* Sends a CREATE CONNECTION message for a path to a peer.
* Changes the connection and tunnel states if necessary.
/**
- * Build an ACK message and queue it to send to the given peer.
+ * Build a hop-by-hop ACK message and queue it to send for the given connection.
*
- * @param peer Peer to whom send the ACK.
+ * @param c Which connection to send the hop-by-hop ACK.
* @param ack Value of the ACK.
+ * @param fwd Is this fwd?
*/
static void
-send_ack (struct MeshPeer *peer, uint32_t ack)
+send_ack (struct MeshConnection *c, uint32_t ack, int fwd)
{
struct GNUNET_MESH_ACK msg;
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ACK);
msg.ack = htonl (ack);
+ msg.tid = c->t->id;
+ msg.cid = htonl (c->id);
- send_prebuilt_message_peer (&msg.header, peer);
+ send_prebuilt_message_connection (&msg.header, c, NULL, fwd);
}
/**
- * Iterator over all the peers to remove the oldest not-used entry.
+ * Destroy the peer_info and free any allocated resources linked to it
+ *
+ * @param peer The peer_info to destroy.
+ *
+ * @return GNUNET_OK on success
+ */
+static int
+peer_destroy (struct MeshPeer *peer)
+{
+ struct GNUNET_PeerIdentity id;
+ struct MeshPeerPath *p;
+ struct MeshPeerPath *nextp;
+
+ GNUNET_PEER_resolve (peer->id, &id);
+ GNUNET_PEER_change_rc (peer->id, -1);
+
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_remove (peers, &id.hashPubKey, peer))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "removing peer %s, not in hashmap\n", GNUNET_i2s (&id));
+ }
+ if (NULL != peer->dhtget)
+ {
+ GNUNET_DHT_get_stop (peer->dhtget);
+ }
+ p = peer->path_head;
+ while (NULL != p)
+ {
+ nextp = p->next;
+ GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
+ path_destroy (p);
+ p = nextp;
+ }
+ tunnel_destroy_empty (peer->tunnel);
+ GNUNET_free (peer);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Returns if peer is used (has a tunnel, is neighbor).
+ *
+ * @peer Peer to check.
+ *
+ * @return GNUNET_YES if peer is in use.
+ */
+static int
+peer_is_used (struct MeshPeer *peer)
+{
+ struct MeshPeerPath *p;
+
+ if (NULL != peer->tunnel)
+ return GNUNET_YES;
+
+ for (p = peer->path_head; NULL != p; p = p->next)
+ {
+ if (p->length < 3)
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+/**
+ * Iterator over all the peers to get the oldest timestamp.
*
* @param cls Closure (unsued).
* @param key ID of the peer.
* @param value Peer_Info of the peer.
+ */
+static int
+peer_get_oldest (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct MeshPeer *p = value;
+ struct GNUNET_TIME_Absolute *abs = cls;
+
+ /* Don't count active peers */
+ if (GNUNET_YES == peer_is_used (p))
+ return GNUNET_YES;
+
+ if (abs->abs_value_us < p->last_contact.abs_value_us)
+ abs->abs_value_us = p->last_contact.abs_value_us;
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Iterator over all the peers to remove the oldest entry.
*
- * FIXME implement
+ * @param cls Closure (unsued).
+ * @param key ID of the peer.
+ * @param value Peer_Info of the peer.
*/
static int
peer_timeout (void *cls,
const struct GNUNET_HashCode *key,
void *value)
{
+ struct MeshPeer *p = value;
+ struct GNUNET_TIME_Absolute *abs = cls;
+
+ if (p->last_contact.abs_value_us == abs->abs_value_us &&
+ GNUNET_NO == peer_is_used (p))
+ {
+ peer_destroy (p);
+ return GNUNET_NO;
+ }
return GNUNET_YES;
}
+/**
+ * Delete oldest unused peer.
+ */
+static void
+peer_delete_oldest (void)
+{
+ struct GNUNET_TIME_Absolute abs;
+
+ abs = GNUNET_TIME_UNIT_FOREVER_ABS;
+
+ GNUNET_CONTAINER_multihashmap_iterate (peers,
+ &peer_get_oldest,
+ &abs);
+ GNUNET_CONTAINER_multihashmap_iterate (peers,
+ &peer_timeout,
+ &abs);
+}
+
+
/**
* Retrieve the MeshPeer stucture associated with the peer, create one
* and insert it in the appropriate structures if the peer is not known yet.
peer = GNUNET_new (struct MeshPeer);
if (GNUNET_CONTAINER_multihashmap_size (peers) > max_peers)
{
- GNUNET_CONTAINER_multihashmap_iterate (peers,
- &peer_timeout,
- NULL);
+ peer_delete_oldest ();
}
GNUNET_CONTAINER_multihashmap_put (peers, &peer_id->hashPubKey, peer,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
return best_p;
}
+static int
+queue_is_sendable (struct MeshPeerQueue *q)
+{
+ struct MeshFlowControl *fc;
+
+ /* Is PID-independent? */
+ switch (q->type)
+ {
+ case GNUNET_MESSAGE_TYPE_MESH_ACK:
+ case GNUNET_MESSAGE_TYPE_MESH_POLL:
+ return GNUNET_YES;
+ }
+
+ /* Is PID allowed? */
+ fc = q->fwd ? &q->c->fwd_fc : &q->c->bck_fc;
+ if (GMC_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
+ return GNUNET_YES;
+
+ return GNUNET_NO;
+}
+
+
+/**
+ * Get first sendable message.
+ *
+ * @param peer The destination peer.
+ *
+ * @return Best current known path towards the peer, if any.
+ */
+static struct MeshPeerQueue *
+peer_get_first_message (const struct MeshPeer *peer)
+{
+ struct MeshPeerQueue *q;
+
+ for (q = peer->queue_head; NULL != q; q = q->next)
+ {
+ if (queue_is_sendable (q))
+ return q;
+ }
+
+ return NULL;
+}
+
/**
* Try to establish a new connection to this peer in the given tunnel.
/**
- * @brief Re-initiate traffic to this peer if necessary.
+ * Get the first transmittable message for a connection.
*
- * Check if there is traffic queued towards this peer
- * and the core transmit handle is NULL (traffic was stalled).
- * If so, call core tmt rdy.
+ * @param c Connection.
+ * @param fwd Is this FWD?
*
- * @param peer_id Short ID of peer to which initiate traffic.
+ * @return First transmittable message.
*/
-static void
-peer_unlock_queue (GNUNET_PEER_Id peer_id)
+static struct MeshPeerQueue *
+connection_get_first_message (struct MeshConnection *c, int fwd)
{
- struct MeshPeer *peer;
struct MeshPeerQueue *q;
- size_t size;
+ struct MeshPeer *p;
- peer = peer_get_short (peer_id);
- if (NULL != peer->fc->core_transmit)
- return; /* Already unlocked */
+ p = connection_get_hop (c, fwd);
- q = queue_get_next (peer);
- if (NULL == q)
+ for (q = p->queue_head; NULL != q; q = q->next)
+ {
+ if (q->c != c)
+ continue;
+ if (queue_is_sendable (q))
+ return q;
+ }
+
+ return NULL;
+}
+
+
+
+/**
+ * @brief Re-initiate traffic on this connection if necessary.
+ *
+ * Check if there is traffic queued towards this peer
+ * and the core transmit handle is NULL (traffic was stalled).
+ * If so, call core tmt rdy.
+ *
+ * @param c Connection on which initiate traffic.
+ * @param fwd Is this about fwd traffic?
+ */
+static void
+connection_unlock_queue (struct MeshConnection *c, int fwd)
+{
+ struct MeshPeer *peer;
+ struct MeshPeerQueue *q;
+ size_t size;
+
+ peer = connection_get_hop (c, fwd);
+
+ if (NULL != peer->core_transmit)
+ return; /* Already unlocked */
+
+ q = connection_get_first_message (c, fwd);
+ if (NULL == q)
return; /* Nothing to transmit */
size = q->size;
- peer->fc->core_transmit =
+ peer->core_transmit =
GNUNET_CORE_notify_transmit_ready (core_handle,
GNUNET_NO,
0,
/**
- * Cancel all transmissions towards a neighbor that belong to
- * a certain connection.
+ * Cancel all transmissions that belong to a certain connection.
*
- * @param peer Neighbor to whom cancel the transmissions.
* @param c Connection which to cancel.
+ * @param fwd Cancel fwd traffic?
*/
static void
-peer_cancel_queues (struct MeshPeer *peer, struct MeshConnection *c)
+connection_cancel_queues (struct MeshConnection *c, int fwd)
{
struct MeshPeerQueue *q;
struct MeshPeerQueue *next;
struct MeshFlowControl *fc;
+ struct MeshPeer *peer;
- if (NULL == peer || NULL == peer->fc)
+ if (NULL == c)
{
GNUNET_break (0);
return;
}
- fc = peer->fc;
- for (q = fc->queue_head; NULL != q; q = next)
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ peer = connection_get_hop (c, fwd);
+
+ for (q = peer->queue_head; NULL != q; q = next)
{
next = q->next;
if (q->c == c)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "peer_cancel_queue %s\n",
+ "connection_cancel_queue %s\n",
GNUNET_MESH_DEBUG_M2S (q->type));
queue_destroy (q, GNUNET_YES);
}
}
- if (NULL == fc->queue_head)
+ if (NULL == peer->queue_head)
{
- if (NULL != fc->core_transmit)
+ if (NULL != peer->core_transmit)
{
- GNUNET_CORE_notify_transmit_ready_cancel (fc->core_transmit);
- fc->core_transmit = NULL;
+ GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
+ peer->core_transmit = NULL;
}
if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
{
}
-/**
- * Destroy the peer_info and free any allocated resources linked to it
- *
- * @param peer The peer_info to destroy.
- *
- * @return GNUNET_OK on success
- */
-static int
-peer_destroy (struct MeshPeer *peer)
-{
- struct GNUNET_PeerIdentity id;
- struct MeshPeerPath *p;
- struct MeshPeerPath *nextp;
-
- GNUNET_PEER_resolve (peer->id, &id);
- GNUNET_PEER_change_rc (peer->id, -1);
-
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_remove (peers, &id.hashPubKey, peer))
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "removing peer %s, not in hashmap\n", GNUNET_i2s (&id));
- }
- if (NULL != peer->dhtget)
- {
- GNUNET_DHT_get_stop (peer->dhtget);
- }
- p = peer->path_head;
- while (NULL != p)
- {
- nextp = p->next;
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
- path_destroy (p);
- p = nextp;
- }
- tunnel_destroy_empty (peer->tunnel);
- GNUNET_free (peer);
- return GNUNET_OK;
-}
-
-
/**
* Remove all paths that rely on a direct connection between p1 and p2
* from the peer itself and notify all tunnels about it.
/**
- * 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.
+ * Function called if a connection has been stalled for a while,
+ * possibly due to a missed ACK. Poll the neighbor about its ACK status.
*
* @param cls Closure (poll ctx).
* @param tc TaskContext.
*/
static void
-peer_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct MeshFlowControl *fc = cls;
struct GNUNET_MESH_Poll msg;
- struct MeshPeer *peer;
+ struct MeshConnection *c;
fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
}
+ c = fc->c;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** Polling!\n");
- peer = fc->peer;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** peer: %s!\n",
- GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id)));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** connection %s[%X]\n",
+ GNUNET_i2s (GNUNET_PEER_resolve2 (c->t->peer->id)), c->id);
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_POLL);
msg.header.size = htons (sizeof (msg));
msg.pid = htonl (fc->last_pid_sent);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** pid (%u)!\n", fc->last_pid_sent);
- send_prebuilt_message_peer (&msg.header, peer);
+ send_prebuilt_message_connection (&msg.header, c, NULL, fc == &c->fwd_fc);
fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
- &peer_poll, fc);
+ &connection_poll, fc);
}
return GNUNET_CONTAINER_multihashmap32_get (c->own_channels, chid);
}
-
/**
- * Search for a tunnel by global ID using PEER_ID
+ * Search for a tunnel by global ID using full PeerIdentities.
*
- * @param pi owner of the tunnel
- * @param tid global tunnel number
+ * @param t Tunnel containing the channel.
+ * @param chid Public channel number.
*
- * @return tunnel handler, NULL if doesn't exist
+ * @return channel handler, NULL if doesn't exist
*/
static struct MeshChannel *
-channel_get_by_pi (GNUNET_PEER_Id pi, MESH_ChannelNumber tid)
+channel_get (struct MeshTunnel2 *t, MESH_ChannelNumber chid)
{
-// struct GNUNET_HashCode hash;
+ struct MeshChannel *ch;
-// return GNUNET_CONTAINER_multihashmap_get (tunnels, &hash); FIXME
- return NULL;
-}
+ if (NULL == t)
+ return NULL;
+ for (ch = t->channel_head; NULL != ch; ch = ch->next)
+ {
+ if (ch->gid == chid)
+ break;
+ }
-/**
- * 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 MeshChannel *
-channel_get (const struct GNUNET_PeerIdentity *oid, MESH_ChannelNumber tid)
-{
- return channel_get_by_pi (GNUNET_PEER_search (oid), tid);
+ return ch;
}
static void
channel_add_client (struct MeshChannel *ch, struct MeshClient *c)
{
- if (NULL != ch->client)
+ struct MeshTunnel2 *t = ch->t;
+
+ if (NULL != ch->dest)
{
GNUNET_break(0);
return;
}
+
+ /* Assign local id as destination */
+ while (NULL != channel_get_by_local_id (c, t->next_local_chid))
+ t->next_local_chid = (t->next_local_chid + 1) | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
+ ch->lid_dest = t->next_local_chid++;
+ t->next_local_chid = t->next_local_chid | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
+
+ /* Store in client's hashmap */
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap32_put (c->incoming_channels,
- ch->id_dest, ch,
+ ch->lid_dest, ch,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
{
GNUNET_break (0);
return;
}
- ch->client = c;
+ ch->dest = c;
}
/**
* Send an end-to-end FWD ACK message for the most recent in-sequence payload.
- *
+ *
* @param ch Channel this is about.
* @param fwd Is for FWD traffic? (ACK dest->owner)
*/
struct MeshChannelReliability *rel;
struct MeshReliableMessage *copy;
uint64_t mask;
+ uint32_t *mid;
unsigned int delta;
if (GNUNET_NO == ch->reliable)
GNUNET_break (0);
return;
}
- rel = fwd ? ch->bck_rel : ch->fwd_rel;
+ rel = fwd ? ch->bck_rel : ch->fwd_rel;
+ mid = fwd ? &ch->mid_recv_fwd : &ch->mid_recv_bck;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"send_data_ack for %u\n",
- rel->mid_recv - 1);
+ *mid - 1);
msg.header.type = htons (fwd ? GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK :
GNUNET_MESSAGE_TYPE_MESH_TO_ORIG_ACK);
msg.header.size = htons (sizeof (msg));
- msg.chid = htonl (ch->id);
- msg.mid = htonl (rel->mid_recv - 1);
+ msg.chid = htonl (ch->gid);
+ msg.mid = htonl (*mid - 1);
msg.futures = 0;
for (copy = rel->head_recv; NULL != copy; copy = copy->next)
{
- delta = copy->mid - rel->mid_recv;
+ delta = copy->mid - *mid;
if (63 < delta)
break;
mask = 0x1LL << delta;
/**
* Send an ACK informing the predecessor about the available buffer space.
*
- * Note that although the name is fwd_ack, the FWD mean forward *traffic*,
- * the ACK itself goes "back" (towards root).
+ * Note that for fwd ack, the FWD mean forward *traffic* (root->dest),
+ * the ACK itself goes "back" (dest->root).
*
* @param c Connection on which to send the ACK.
* @param fwd Is this FWD ACK? (Going dest->owner)
{
struct MeshFlowControl *next_fc;
struct MeshFlowControl *prev_fc;
- struct MeshPeer *next;
- struct MeshPeer *prev;
uint32_t ack;
int delta;
- next = fwd ? connection_get_next_hop (c) : connection_get_prev_hop (c);
- prev = fwd ? connection_get_prev_hop (c) : connection_get_next_hop (c);
- next_fc = next->fc;
- prev_fc = prev->fc;
+ next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
/* Check if we need to transmit the ACK */
if (prev_fc->last_ack_sent - prev_fc->last_pid_recv > 3)
}
prev_fc->last_ack_sent = ack;
- send_ack (prev, ack);
+ send_ack (c, ack, fwd);
}
int fwd)
{
if (fwd)
- channel_send_client_to_tid (ch, msg, ch->client, ch->id_dest);
+ channel_send_client_to_tid (ch, msg, ch->dest, ch->lid_dest);
else
- channel_send_client_to_tid (ch, msg, ch->owner, ch->id);
+ channel_send_client_to_tid (ch, msg, ch->root, ch->lid_root);
}
/**
- * Send up to 64 buffered messages to the client for in order delivery.
+ * Send a buffered message to the client, for in order delivery or
+ * as result of client ACK.
*
* @param ch Channel on which to empty the message buffer.
* @param c Client to send to.
struct MeshChannelReliability *rel)
{
struct MeshReliableMessage *copy;
- struct MeshReliableMessage *next;
+ uint32_t *mid;
- if (GNUNET_NO == ch->reliable)
+ if (GNUNET_NO == rel->client_ready)
{
- GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
return;
}
+ mid = rel == ch->bck_rel ? &ch->mid_recv_fwd : &ch->mid_recv_bck;
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
- for (copy = rel->head_recv; NULL != copy; copy = next)
+ copy = rel->head_recv;
+ if (NULL != copy)
{
- next = copy->next;
- if (copy->mid == rel->mid_recv)
+ if (copy->mid == *mid || GNUNET_NO == ch->reliable)
{
struct GNUNET_MESH_Data *msg = (struct GNUNET_MESH_Data *) ©[1];
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" have %u! now expecting %u\n",
- copy->mid, rel->mid_recv + 1);
+ copy->mid, *mid + 1);
channel_send_client_data (ch, msg, (rel == ch->bck_rel));
- rel->mid_recv++;
+ rel->n_recv--;
+ *mid = *mid + 1;
GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
GNUNET_free (copy);
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " don't have %u, next is %u\n",
- rel->mid_recv,
+ " reliable && don't have %u, next is %u\n",
+ *mid,
copy->mid);
return;
}
/**
- * We have received a message out of order, buffer it until we receive
- * the missing one and we can feed the rest to the client.
+ * We have received a message out of order, or the client is not ready.
+ * Buffer it until we receive an ACK from the client or the missing
+ * message from the channel.
*
* @param msg Message to buffer.
* @param rel Reliability data to the corresponding direction.
copy->rel = rel;
memcpy (©[1], msg, size);
+ rel->n_recv++;
+
// FIXME do something better than O(n), although n < 64...
// FIXME start from the end (most messages are the latest ones)
for (prev = rel->head_recv; NULL != prev; prev = prev->next)
rel = copy->rel;
time = GNUNET_TIME_absolute_get_duration (copy->timestamp);
- rel->expected_delay.rel_value *= 7;
- rel->expected_delay.rel_value += time.rel_value;
- rel->expected_delay.rel_value /= 8;
+ rel->expected_delay.rel_value_us *= 7;
+ rel->expected_delay.rel_value_us += time.rel_value_us;
+ rel->expected_delay.rel_value_us /= 8;
rel->n_sent--;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " n_sent %u\n", rel->n_sent);
struct MeshChannelReliability *rel = cls;
struct MeshReliableMessage *copy;
struct MeshPeerQueue *q;
- struct MeshPeer *pi;
struct MeshChannel *ch;
struct MeshConnection *c;
struct GNUNET_MESH_Data *payload;
+ struct MeshPeer *hop;
int fwd;
rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
*/
payload = (struct GNUNET_MESH_Data *) ©[1];
fwd = (rel == ch->fwd_rel);
- c = tunnel_get_connection(ch->t, fwd);
- pi = connection_get_next_hop (c);
- for (q = pi->fc->queue_head; NULL != q; q = q->next)
+ c = tunnel_get_connection (ch->t, fwd);
+ hop = connection_get_hop (c, fwd);
+ for (q = hop->queue_head; NULL != q; q = q->next)
{
if (ntohs (payload->header.type) == q->type && ch == q->ch)
{
}
+
+/**
+ * Send ACK on one or more connections due to buffer space to the client.
+ */
+static void
+channel_send_ack (struct MeshChannel *ch, uint32_t buffer, int fwd)
+{
+ struct MeshTunnel2 *t = ch->t;
+ struct MeshConnection *c;
+ struct MeshFlowControl *fc;
+ uint32_t allowed;
+ uint32_t to_allow;
+ unsigned int cs;
+
+ /* Count connections, how many messages are already allowed */
+ for (cs = 0, allowed = 0, c = t->connection_head; NULL != c; c = c->next)
+ {
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GMC_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
+ {
+ GNUNET_break (0);
+ continue;
+ }
+ allowed += fc->last_ack_sent - fc->last_pid_recv;
+ cs++;
+ }
+
+ /* Make sure there is no overflow */
+ if (allowed > buffer)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Authorize connections to send more data */
+ to_allow = buffer - allowed;
+ for (c = t->connection_head; NULL != c && to_allow > 0; c = c->next)
+ {
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (fc->last_ack_sent - fc->last_pid_recv > 64 / 3)
+ {
+ continue;
+ }
+ send_ack (c, fc->last_ack_sent + 1, fwd);
+ to_allow--;
+ }
+
+ GNUNET_break (to_allow == 0);
+}
+
+
/**
* Send keepalive packets for a connection.
*
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- connection_keepalive (c, GNUNET_YES);
+ connection_maintain (c, GNUNET_YES);
c->fwd_maintenance_task = GNUNET_SCHEDULER_add_delayed (refresh_connection_time,
&connection_fwd_keepalive,
c);
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- connection_keepalive (c, GNUNET_NO);
+ connection_maintain (c, GNUNET_NO);
c->bck_maintenance_task = GNUNET_SCHEDULER_add_delayed (refresh_connection_time,
&connection_bck_keepalive,
c);
send_prebuilt_message_connection (&msg.header, c, NULL, GNUNET_YES);
send_prebuilt_message_connection (&msg.header, c, NULL, GNUNET_NO);
+ c->destroy = GNUNET_YES;
}
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
- msg.chid = htonl (ch->id);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" sending tunnel destroy for channel %s:%X\n",
GNUNET_i2s (GNUNET_PEER_resolve2 (ch->t->peer->id)),
- ch->id);
+ ch->gid);
- if (NULL != ch->owner)
+ if (NULL != ch->root)
+ {
+ msg.chid = htonl (ch->lid_root);
send_local_channel_destroy (ch, GNUNET_NO);
+ }
else
+ {
+ msg.chid = htonl (ch->gid);
send_prebuilt_message_channel (&msg.header, ch, GNUNET_NO);
+ }
- if (NULL != ch->client)
+ if (NULL != ch->dest)
+ {
+ msg.chid = htonl (ch->lid_dest);
send_local_channel_destroy (ch, GNUNET_YES);
+ }
else
+ {
+ msg.chid = htonl (ch->gid);
send_prebuilt_message_channel (&msg.header, ch, GNUNET_YES);
+ }
}
* @param tid Tunnel ID.
*/
static struct MeshTunnel2 *
-tunnel_new (struct GNUNET_HashCode *tid)
+tunnel_new (const struct GNUNET_HashCode *tid)
{
struct MeshTunnel2 *t;
* @param tid Tunnel ID.
*/
static struct MeshTunnel2 *
-tunnel_get (struct GNUNET_HashCode *tid)
+tunnel_get (const struct GNUNET_HashCode *tid)
{
return GNUNET_CONTAINER_multihashmap_get (tunnels, tid);
}
}
+/**
+ * Initialize a Flow Control structure to the initial state.
+ *
+ * @param fc Flow Control structure to initialize.
+ */
+static void
+fc_init (struct MeshFlowControl *fc)
+{
+ fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */
+ fc->last_pid_recv = (uint32_t) -1;
+ fc->last_ack_sent = (uint32_t) -1; /* No traffic allowed yet */
+ fc->last_ack_recv = (uint32_t) -1;
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
+ fc->queue_n = 0;
+}
+
+
/**
* Create a connection.
*
c = GNUNET_new (struct MeshConnection);
c->id = cid;
+ fc_init (&c->fwd_fc);
+ fc_init (&c->bck_fc);
tunnel_add_connection (t, c);
return c;
* @param cid Connection ID.
*/
static struct MeshConnection *
-connection_get (struct GNUNET_HashCode *tid, uint32_t cid)
+connection_get (const struct GNUNET_HashCode *tid, uint32_t cid)
{
struct MeshConnection *c;
struct MeshTunnel2 *t;
static void
connection_destroy (struct MeshConnection *c)
{
- struct MeshPeer *peer;
-
if (NULL == c)
return;
GNUNET_i2s (GNUNET_PEER_resolve2 (c->t->peer->id)),
c->id);
- peer = connection_get_next_hop (c);
- if (NULL != peer)
- peer_cancel_queues (peer, c);
- peer = connection_get_prev_hop (c);
- if (NULL != peer)
- peer_cancel_queues (peer, c);
+ connection_cancel_queues (c, GNUNET_YES);
+ connection_cancel_queues (c, GNUNET_NO);
if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task)
GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
return;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n",
- GNUNET_i2s (GNUNET_PEER_resolve2 (c->t->peer->id)));
+ GNUNET_i2s (GNUNET_PEER_resolve2 (t->peer->id)));
if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (tunnels, &t->id, t))
GNUNET_break (0);
}
-/**
- * Initialize a Flow Control structure to the initial state.
- *
- * @param fc Flow Control structure to initialize.
- */
-static void
-fc_init (struct MeshFlowControl *fc)
-{
- fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */
- fc->last_pid_recv = (uint32_t) -1;
- fc->last_ack_sent = (uint32_t) -1; /* No traffic allowed yet */
- fc->last_ack_recv = (uint32_t) -1;
- fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
- fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
- fc->queue_n = 0;
-}
-
-
/**
* Destroy a channel and free all resources.
*
if (NULL == ch)
return;
- c = ch->owner;
+ c = ch->root;
if (NULL != c)
{
if (GNUNET_YES != GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
- c->id, ch))
+ ch->lid_root, ch))
{
GNUNET_break (0);
}
}
- c = ch->client;
+ c = ch->dest;
if (NULL != c)
{
if (GNUNET_YES !=
GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
- ch->id_dest, ch))
+ ch->lid_dest, ch))
{
GNUNET_break (0);
}
/**
* Create a new channel.
- *
- * @param owner Clients that owns the channel, NULL for foreign channels.
- * @param id Channel Number for the channel, for the owner point of view.
- *
+ *
+ * @param t Tunnel this channel is in.
+ * @param owner Client that owns the channel, NULL for foreign channels.
+ * @param lid_root Local ID for root client.
+ *
* @return A new initialized channel. NULL on error.
*/
static struct MeshChannel *
-channel_new (struct MeshClient *owner,
- MESH_ChannelNumber id)
+channel_new (struct MeshTunnel2 *t,
+ struct MeshClient *owner, MESH_ChannelNumber lid_root)
{
struct MeshChannel *ch;
- if (NULL == owner)
- return NULL;
-
ch = GNUNET_new (struct MeshChannel);
- ch->owner = owner;
- ch->id = id;
+ ch->root = owner;
+ ch->lid_root = lid_root;
+ ch->t = t;
GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multihashmap32_put (owner->own_channels, id, ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ if (NULL != owner)
{
- GNUNET_break (0);
- channel_destroy (ch);
- GNUNET_SERVER_receive_done (owner->handle, GNUNET_SYSERR);
- return NULL;
+ while (NULL != channel_get_by_local_id (owner, t->next_chid))
+ t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
+ ch->gid = t->next_chid;
+ t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
+
+ if(GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap32_put (owner->own_channels, lid_root, ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_break (0);
+ channel_destroy (ch);
+ GNUNET_SERVER_receive_done (owner->handle, GNUNET_SYSERR);
+ return NULL;
+ }
}
return ch;
struct MeshTunnel2 *t;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " Channel %X / %X destroy, due to client %u shutdown.\n",
- ch->id, ch->id_dest, c->id);
+ " Channel %X (%X / %X) destroy, due to client %u shutdown.\n",
+ ch->gid, ch->lid_root, ch->lid_dest, c->id);
- if (c == ch->client)
+ if (c == ch->dest)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is destination.\n", c->id);
- ch->client = NULL;
+ ch->dest = NULL;
}
- if (c == ch->owner)
+ if (c == ch->root)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Client %u is owner.\n", c->id);
- ch->owner = NULL;
+ ch->root = NULL;
}
t = ch->t;
}
+/**
+ * Iterator to notify all connections of a broken link. Mark connections
+ * to destroy after all traffic has been sent.
+ *
+ * @param cls Closure (peer disconnected).
+ * @param key Current key code (tid).
+ * @param value Value in the hash map (connection).
+ *
+ * @return GNUNET_YES if we should continue to iterate,
+ * GNUNET_NO if not.
+ */
+static int
+connection_broken (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct MeshPeer *peer = cls;
+ struct MeshConnection *c = value;
+ struct GNUNET_MESH_ConnectionBroken msg;
+ int fwd;
+
+ fwd = peer == connection_get_prev_hop (c);
+ connection_cancel_queues (c, !fwd);
+
+ msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectionBroken));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN);
+ msg.cid = htonl (c->id);
+ msg.tid = c->t->id;
+ msg.peer1 = my_full_id;
+ msg.peer2 = *GNUNET_PEER_resolve2 (peer->id);
+ send_prebuilt_message_connection (&msg.header, c, NULL, fwd);
+ c->destroy = GNUNET_YES;
+
+ return GNUNET_YES;
+}
+
/******************************************************************************/
/**************** MESH NETWORK HANDLER HELPERS ***********************/
/******************************************************************************/
static void
queue_destroy (struct MeshPeerQueue *queue, int clear_cls)
{
+ struct MeshPeer *peer;
struct MeshFlowControl *fc;
+ int fwd;
+
+ fwd = queue->fwd;
+ peer = queue->peer;
+ fc = fwd ? &queue->c->fwd_fc : &queue->c->bck_fc;
- fc = queue->peer->fc;
if (GNUNET_YES == clear_cls)
{
switch (queue->type)
}
GNUNET_free_non_null (queue->cls);
}
- GNUNET_CONTAINER_DLL_remove (fc->queue_head, fc->queue_tail, queue);
+ GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue);
fc->queue_n--;
+ peer->queue_n--;
+ if (NULL != queue->c)
+ {
+ queue->c->pending_messages--;
+ if (NULL != queue->c->t)
+ {
+ queue->c->t->pending_messages--;
+ }
+ }
GNUNET_free (queue);
}
+
static size_t
queue_send (void *cls, size_t size, void *buf)
{
struct MeshPeer *peer = cls;
- const struct GNUNET_PeerIdentity *dst_id;
+ struct MeshFlowControl *fc;
+ struct MeshConnection *c;
struct GNUNET_MessageHeader *msg;
struct MeshPeerQueue *queue;
struct MeshTunnel2 *t;
- struct MeshFlowControl *fc;
- struct MeshConnection *c;
+ const struct GNUNET_PeerIdentity *dst_id;
size_t data_size;
uint32_t pid;
uint16_t type;
int fwd;
- fc = peer->fc;
- if (NULL == fc)
- {
- GNUNET_break (0);
- return 0;
- }
- fc->core_transmit = NULL;
-
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Queue send\n");
if (NULL == buf || 0 == size)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Buffer size 0.\n");
return 0;
}
- queue = fc->queue_head;
- /* Queue has no traffic */
+ /* Initialize */
+ queue = peer_get_first_message (peer);
if (NULL == queue)
{
GNUNET_break (0); /* Core tmt_rdy should've been canceled */
return 0;
}
+ queue->peer->core_transmit = NULL;
+ c = queue->c;
+ fwd = queue->fwd;
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+
dst_id = GNUNET_PEER_resolve2 (peer->id);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* towards %s\n", GNUNET_i2s (dst_id));
if (queue->size > size)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* not enough room, reissue\n");
- fc->core_transmit =
+ peer->core_transmit =
GNUNET_CORE_notify_transmit_ready (core_handle,
GNUNET_NO,
0,
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* size ok\n");
- c = queue->c;
t = (NULL != c) ? c->t : NULL;
type = 0;
data_size = 0;
}
- fc->queue_n--;
-
if (0 < drop_percent &&
GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
{
queue_destroy (queue, GNUNET_NO);
/* Send ACK if needed, after accounting for sent ID in fc->queue_n */
- fwd = GNUNET_NO;
switch (type)
{
case GNUNET_MESSAGE_TYPE_MESH_FWD:
- fwd = GNUNET_YES;
- /* fall through */
case GNUNET_MESSAGE_TYPE_MESH_BCK:
pid = ntohl ( ((struct GNUNET_MESH_Encrypted *) buf)->pid );
fc->last_pid_sent = pid;
}
/* If more data in queue, send next */
- queue = fc->queue_head;
+ queue = peer_get_first_message (peer);
if (NULL != queue)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* more data!\n");
- if (NULL == fc->core_transmit) {
- peer->fc->core_transmit =
+ if (NULL == peer->core_transmit) {
+ peer->core_transmit =
GNUNET_CORE_notify_transmit_ready(core_handle,
0,
0,
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "* %s starting poll timeout\n");
fc->poll_task =
- GNUNET_SCHEDULER_add_delayed (fc->poll_time, &peer_poll, fc);
+ GNUNET_SCHEDULER_add_delayed (fc->poll_time, &connection_poll, fc);
}
}
else
struct MeshPeerQueue *queue;
struct MeshFlowControl *fc;
int priority;
+ int fwd;
+
+ fwd = (dst == connection_get_next_hop (c));
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
- fc = dst->fc;
if (NULL == fc)
{
GNUNET_break (0);
priority = 100;
if (NULL != ch &&
- ( (NULL != ch->owner && GNUNET_MESSAGE_TYPE_MESH_FWD == type) ||
- (NULL != ch->client && GNUNET_MESSAGE_TYPE_MESH_BCK == type) ))
+ ( (NULL != ch->root && GNUNET_MESSAGE_TYPE_MESH_FWD == type) ||
+ (NULL != ch->dest && GNUNET_MESSAGE_TYPE_MESH_BCK == type) ))
priority = 50;
if (fc->queue_n >= fc->queue_max && 0 == priority)
return; /* Drop this message */
}
- fc->queue_n++;
if (GMC_is_pid_bigger(fc->last_pid_sent + 1, fc->last_ack_recv) &&
GNUNET_SCHEDULER_NO_TASK == fc->poll_task)
fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
- &peer_poll,
+ &connection_poll,
dst);
queue = GNUNET_malloc (sizeof (struct MeshPeerQueue));
queue->cls = cls;
queue->peer = dst;
queue->c = c;
queue->ch = ch;
+ queue->fwd = fwd;
if (100 <= priority)
- GNUNET_CONTAINER_DLL_insert (fc->queue_head, fc->queue_tail, queue);
+ GNUNET_CONTAINER_DLL_insert (dst->queue_head, dst->queue_tail, queue);
else
- GNUNET_CONTAINER_DLL_insert_tail (fc->queue_head, fc->queue_tail, queue);
+ GNUNET_CONTAINER_DLL_insert_tail (dst->queue_head, dst->queue_tail, queue);
- if (NULL == fc->core_transmit)
+ if (NULL == dst->core_transmit)
{
- fc->core_transmit =
+ dst->core_transmit =
GNUNET_CORE_notify_transmit_ready (core_handle,
0,
0,
}
c->pending_messages++;
c->t->pending_messages++;
+ fc->queue_n++;
+ dst->queue_n++;
}
/**
- * Core handler for connection creation.
+ * Generic handler for mesh network payload traffic.
*
- * @param cls Closure (unused).
- * @param peer Sender (neighbor).
- * @param message Message.
+ * @param t Tunnel on which we got this message.
+ * @param message Unencryted data 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_connection_create (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+handle_data (struct MeshTunnel2 *t, const struct GNUNET_MESH_Data *msg, int fwd)
{
- struct GNUNET_MESH_ConnectionCreate *msg;
- struct GNUNET_PeerIdentity *id;
- struct GNUNET_HashCode *tid;
- struct MeshPeerPath *path;
+ struct MeshChannelReliability *rel;
+ struct MeshChannel *ch;
+ struct MeshClient *c;
+ uint32_t mid;
+ uint32_t *mid_recv;
+ uint16_t type;
+ size_t size;
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size <
+ sizeof (struct GNUNET_MESH_Data) +
+ sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+ type = ntohs (msg->header.type);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a %s message\n",
+ GNUNET_MESH_DEBUG_M2S (type));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n",
+ GNUNET_MESH_DEBUG_M2S (ntohs (msg[1].header.type)));
+
+ /* Check channel */
+ ch = channel_get (t, ntohl (msg->chid));
+ if (NULL == ch)
+ {
+ GNUNET_STATISTICS_update (stats, "# data on unknown channel", 1, GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel unknown\n");
+ return GNUNET_OK;
+ }
+
+ /* Initialize FWD/BCK data */
+ c = fwd ? ch->dest : ch->root;
+ rel = fwd ? ch->bck_rel : ch->fwd_rel;
+ mid_recv = fwd ? &ch->mid_recv_fwd : &ch->mid_recv_bck;
+
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+
+ tunnel_change_state (t, MESH_TUNNEL_READY);
+
+ GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO);
+
+ mid = ntohl (msg->mid);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " mid %u\n", mid);
+
+ if (GNUNET_NO == ch->reliable ||
+ ( !GMC_is_pid_bigger (*mid_recv, mid) &&
+ GMC_is_pid_bigger (*mid_recv + 64, mid) ) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! RECV %u\n", mid);
+ if (GNUNET_YES == ch->reliable)
+ {
+ /* Is this the exact next expected messasge? */
+ if (mid == *mid_recv)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "as expected\n");
+ *mid_recv = *mid_recv + 1;
+ channel_send_client_data (ch, msg, fwd);
+ channel_send_client_buffered_data (ch, c, rel);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "save for later\n");
+ channel_rel_add_buffered_data (msg, rel);
+ }
+ }
+ else /* Tunnel unreliable, send to clients directly */
+ {
+ channel_send_client_data (ch, msg, fwd);
+ }
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " MID %u not expected (%u - %u), dropping!\n",
+ mid, *mid_recv, *mid_recv + 64);
+ }
+
+ channel_send_data_ack (ch, fwd);
+ return GNUNET_OK;
+}
+
+/**
+ * Handler for mesh network traffic end-to-end ACKs.
+ *
+ * @param t Tunnel on which we got this message.
+ * @param message Data message.
+ * @param fwd Is this a fwd ACK? (dest->orig)
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_data_ack (struct MeshTunnel2 *t,
+ const struct GNUNET_MESH_DataACK *msg, int fwd)
+{
+ struct MeshChannelReliability *rel;
+ struct MeshReliableMessage *copy;
+ struct MeshReliableMessage *next;
+ struct MeshChannel *ch;
+ uint32_t ack;
+ uint16_t type;
+ int work;
+
+ type = ntohs (msg->header.type);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a %s message!\n",
+ GNUNET_MESH_DEBUG_M2S (type));
+ ch = channel_get (t, ntohl (msg->chid));
+ if (NULL == ch)
+ {
+ GNUNET_STATISTICS_update (stats, "# ack on unknown channel", 1, GNUNET_NO);
+ return GNUNET_OK;
+ }
+ ack = ntohl (msg->mid);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! %s ACK %u\n",
+ (GNUNET_YES == fwd) ? "FWD" : "BCK", ack);
+
+ if (GNUNET_YES == fwd)
+ {
+ rel = ch->fwd_rel;
+ }
+ else
+ {
+ rel = ch->bck_rel;
+ }
+ if (NULL == rel)
+ {
+ return GNUNET_OK;
+ }
+
+ for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next)
+ {
+ if (GMC_is_pid_bigger (copy->mid, ack))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! head %u, out!\n", copy->mid);
+ channel_rel_free_sent (rel, msg);
+ break;
+ }
+ work = GNUNET_YES;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! id %u\n", copy->mid);
+ next = copy->next;
+ rel_message_free (copy);
+ }
+ /* ACK client if needed */
+// channel_send_ack (t, type, GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK == type);
+
+ /* If some message was free'd, update the retransmission delay*/
+ if (GNUNET_YES == work)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (rel->retry_task);
+ if (NULL == rel->head_sent)
+ {
+ rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ else
+ {
+ struct GNUNET_TIME_Absolute new_target;
+ struct GNUNET_TIME_Relative delay;
+
+ delay = GNUNET_TIME_relative_multiply (rel->retry_timer,
+ MESH_RETRANSMIT_MARGIN);
+ new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp,
+ delay);
+ delay = GNUNET_TIME_absolute_get_remaining (new_target);
+ rel->retry_task =
+ GNUNET_SCHEDULER_add_delayed (delay,
+ &channel_retransmit_message,
+ rel);
+ }
+ }
+ else
+ GNUNET_break (0);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Core handler for connection creation.
+ *
+ * @param cls Closure (unused).
+ * @param peer Sender (neighbor).
+ * @param message Message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_mesh_connection_create (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_MESH_ConnectionCreate *msg;
+ struct GNUNET_PeerIdentity *id;
+ struct GNUNET_HashCode *tid;
+ struct MeshPeerPath *path;
struct MeshPeer *dest_peer;
struct MeshPeer *orig_peer;
struct MeshConnection *c;
/**
* Core handler for tunnel destruction
*
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
+ * @param cls Closure (unused).
+ * @param peer Peer identity of sending neighbor.
+ * @param message Message.
*
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
static int
-handle_mesh_tunnel_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
+handle_mesh_connection_destroy (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
{
- struct GNUNET_MESH_TunnelDestroy *msg;
- struct MeshTunnel *t;
+ struct GNUNET_MESH_ConnectionDestroy *msg;
+ struct MeshConnection *c;
+ GNUNET_PEER_Id id;
+ int fwd;
- msg = (struct GNUNET_MESH_TunnelDestroy *) message;
+ msg = (struct GNUNET_MESH_ConnectionDestroy *) message;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got a TUNNEL DESTROY packet from %s\n",
+ "Got a CONNECTION DESTROY message from %s\n",
GNUNET_i2s (peer));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " for tunnel %s [%u]\n",
- GNUNET_i2s (&msg->oid), ntohl (msg->tid));
- t = channel_get (&msg->oid, ntohl (msg->tid));
- if (NULL == t)
+ " for connection %s[%X]\n",
+ GNUNET_h2s (&msg->tid), ntohl (msg->cid));
+ c = connection_get (&msg->tid, ntohl (msg->cid));
+ if (NULL == c)
{
/* Probably already got the message from another path,
* destroyed the tunnel and retransmitted to children.
1, GNUNET_NO);
return GNUNET_OK;
}
- if (t->local_tid_dest >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
+ id = GNUNET_PEER_search (peer);
+ if (id == connection_get_prev_hop (c)->id)
+ fwd = GNUNET_YES;
+ else if (id == connection_get_next_hop (c)->id)
+ fwd = GNUNET_NO;
+ else
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "INCOMING TUNNEL %X %X\n",
- t->local_tid, t->local_tid_dest);
+ GNUNET_break_op (0);
+ return GNUNET_OK;
}
- if (GNUNET_PEER_search (peer) == t->prev_hop)
+ send_prebuilt_message_connection (message, c, NULL, fwd);
+ c->destroy = GNUNET_YES;
+
+ return GNUNET_OK;
+}
+
+/**
+ * Handler for channel create messages.
+ *
+ * @param t Tunnel this channel is to be created in.
+ * @param msg 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_channel_create (struct MeshTunnel2 *t,
+ struct GNUNET_MESH_ChannelCreate *msg,
+ int fwd)
+{
+ MESH_ChannelNumber chid;
+ struct MeshChannel *ch;
+ struct MeshClient *c;
+
+ /* Check message size */
+ if (ntohs (msg->header.size) != sizeof (struct GNUNET_MESH_ChannelCreate))
{
- // 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;
+ GNUNET_break_op (0);
+ return GNUNET_OK;
}
- else if (GNUNET_PEER_search (peer) == t->next_hop)
+
+ /* Check if channel exists */
+ chid = ntohl (msg->chid);
+ ch = channel_get (t, chid);
+ if (NULL != ch)
{
- // 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;
+ /* Probably a retransmission, safe to ignore */
+ return GNUNET_OK;
}
- else
+
+ /* Find a destination client */
+ c = GNUNET_CONTAINER_multihashmap32_get (ports, msg->port);
+ if (NULL == c)
+ {
+ /* TODO send reject */
+ return GNUNET_OK;
+ }
+
+ /* Create channel */
+ ch = channel_new (t, NULL, 0);
+ channel_set_options (ch, ntohl (msg->opt));
+ channel_add_client (ch, c);
+ if (GNUNET_YES == ch->reliable)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n");
+ ch->bck_rel = GNUNET_malloc (sizeof (struct MeshChannelReliability));
+ ch->bck_rel->ch = ch;
+ ch->bck_rel->expected_delay = MESH_RETRANSMIT_TIME;
+ }
+
+ send_local_channel_create (ch);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handler for channel destroy messages.
+ *
+ * @param t Tunnel this channel is to be destroyed of.
+ * @param msg 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_channel_destroy (struct MeshTunnel2 *t,
+ struct GNUNET_MESH_ChannelDestroy *msg,
+ int fwd)
+{
+ MESH_ChannelNumber chid;
+ struct MeshChannel *ch;
+
+ /* Check message size */
+ if (ntohs (msg->header.size) != sizeof (struct GNUNET_MESH_ChannelDestroy))
{
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
+ /* Check if channel exists */
+ chid = ntohl (msg->chid);
+ ch = channel_get (t, chid);
+ if (NULL == ch)
+ {
+ /* Probably a retransmission, safe to ignore */
+ return GNUNET_OK;
+ }
+
+ send_local_channel_destroy (ch, fwd);
+ channel_destroy (ch);
+
return GNUNET_OK;
}
/**
- * Generic handler for mesh network payload traffic.
+ * Generic handler for mesh network encrypted traffic.
*
* @param peer Peer identity this notification is about.
- * @param message Data message.
+ * @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_data (const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message,
- int fwd)
+handle_mesh_encrypted (const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MESH_Encrypted *msg,
+ int fwd)
{
- struct GNUNET_MESH_Data *msg;
+ struct MeshConnection *c;
+ struct MeshTunnel2 *t;
+ struct MeshPeer *neighbor;
struct MeshFlowControl *fc;
- struct MeshChannelReliability *rel;
- struct MeshTunnel *t;
- struct MeshClient *c;
- GNUNET_PEER_Id hop;
uint32_t pid;
uint32_t ttl;
uint16_t type;
size_t size;
/* Check size */
- size = ntohs (message->size);
+ size = ntohs (msg->header.size);
if (size <
- sizeof (struct GNUNET_MESH_Data) +
+ sizeof (struct GNUNET_MESH_Encrypted) +
sizeof (struct GNUNET_MessageHeader))
{
GNUNET_break (0);
return GNUNET_OK;
}
- type =ntohs (message->type);
+ type = ntohs (msg->header.type);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a %s message from %s\n",
GNUNET_MESH_DEBUG_M2S (type), GNUNET_i2s (peer));
- msg = (struct GNUNET_MESH_Data *) message;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n",
- GNUNET_MESH_DEBUG_M2S (ntohs (msg[1].header.type)));
- /* Check tunnel */
- t = channel_get (&msg->oid, ntohl (msg->tid));
- if (NULL == t)
+
+ /* Check connection */
+ c = connection_get (&msg->tid, ntohl (msg->cid));
+ if (NULL == c)
{
- /* TODO notify back: we don't know this tunnel */
- GNUNET_STATISTICS_update (stats, "# data on unknown tunnel", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WARNING tunnel unknown\n");
+ GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WARNING connection unknown\n");
return GNUNET_OK;
}
+ t = c->t;
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
- /* Initialize FWD/BCK data */
+ /* Check if origin is as expected */
+ neighbor = connection_get_hop (c, fwd);
+ if (peer_get (peer)->id != neighbor->id)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ /* Check PID */
pid = ntohl (msg->pid);
- fc = fwd ? &t->prev_fc : &t->next_fc;
- c = fwd ? t->client : t->owner;
- rel = fwd ? t->bck_rel : t->fwd_rel;
- hop = fwd ? t->next_hop : t->prev_hop;
if (GMC_is_pid_bigger (pid, fc->last_ack_sent))
{
- GNUNET_STATISTICS_update (stats, "# unsolicited data", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats, "# unsolicited message", 1, GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"WARNING Received PID %u, (prev %u), ACK %u\n",
pid, fc->last_pid_recv, fc->last_ack_sent);
return GNUNET_OK;
}
- if (NULL != c)
- tunnel_change_state (t, MESH_TUNNEL_READY);
- tunnel_reset_timeout (t, fwd);
- if (NULL != c)
+ if (GNUNET_NO == GMC_is_pid_bigger (pid, fc->last_pid_recv))
{
- /* TODO signature verification */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " it's for us! sending to client\n");
- GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO);
- if (GMC_is_pid_bigger (pid, fc->last_pid_recv))
- {
- uint32_t mid;
+ GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " Pid %u not expected (%u+), dropping!\n",
+ pid, fc->last_pid_recv + 1);
+ return GNUNET_OK;
+ }
+ if (MESH_CONNECTION_SENT == c->state)
+ connection_change_state (c, MESH_CONNECTION_READY);
+ connection_reset_timeout (c, fwd);
+ fc->last_pid_recv = pid;
- mid = ntohl (msg->mid);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " pid %u (mid %u) not seen yet\n", pid, mid);
- fc->last_pid_recv = pid;
+ /* Is this message for us? */
+ if (NULL != c->t->channel_head)
+ {
+ size_t dsize = size - sizeof (struct GNUNET_MESH_Encrypted);
+ char cbuf[dsize];
+ struct GNUNET_MessageHeader *msgh;
- if (GNUNET_NO == t->reliable ||
- ( !GMC_is_pid_bigger (rel->mid_recv, mid) &&
- GMC_is_pid_bigger (rel->mid_recv + 64, mid) ) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "!!! RECV %u\n", ntohl (msg->mid));
- if (GNUNET_YES == t->reliable)
- {
- /* Is this the exact next expected messasge? */
- if (mid == rel->mid_recv)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "as expected\n");
- rel->mid_recv++;
- tunnel_send_client_data (t, msg, fwd);
- tunnel_send_client_buffered_data (t, c, rel);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "save for later\n");
- tunnel_add_buffered_data (t, msg, rel);
- }
- }
- else /* Tunnel unreliable, send to clients directly */
- {
- tunnel_send_client_data (t, msg, fwd);
- }
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " MID %u not expected (%u - %u), dropping!\n",
- ntohl (msg->mid), rel->mid_recv, rel->mid_recv + 64);
- }
- }
- else
+ /* TODO signature verification */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " it's 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);
+ msgh = (struct GNUNET_MessageHeader *) cbuf;
+ switch (ntohs (msgh->type))
{
-// GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " Pid %u not expected (%u+), dropping!\n",
- pid, fc->last_pid_recv + 1);
+ case GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK:
+ if (GNUNET_YES == fwd)
+ return handle_data_ack (t, (struct GNUNET_MESH_DataACK *) msgh,
+ GNUNET_YES);
+ GNUNET_break_op (0);
+ break;
+ case GNUNET_MESSAGE_TYPE_MESH_TO_ORIG_ACK:
+ if (GNUNET_NO == fwd)
+ return handle_data_ack (t, (struct GNUNET_MESH_DataACK *) msgh,
+ GNUNET_YES);
+ GNUNET_break_op (0);
+ break;
+ case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
+ if (GNUNET_YES == fwd)
+ handle_data (t, (struct GNUNET_MESH_Data *) msgh, GNUNET_YES);
+ GNUNET_break_op (0);
+ break;
+ case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
+ if (GNUNET_NO == fwd)
+ handle_data (t, (struct GNUNET_MESH_Data *) msgh, GNUNET_NO);
+ GNUNET_break_op (0);
+ break;
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
+ return handle_channel_create (t,
+ (struct GNUNET_MESH_ChannelCreate *) msgh,
+ fwd);
+ break;
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
+ return handle_channel_destroy (t,
+ (struct GNUNET_MESH_ChannelDestroy *)
+ msgh,
+ fwd);
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "end-to-end message not known (%u)\n",
+ ntohs (msgh->type));
}
- tunnel_send_ack (t, type, fwd);
+
+ connection_send_ack (c, fwd);
return GNUNET_OK;
}
- fc->last_pid_recv = pid;
- if (0 == hop)
- {
- GNUNET_STATISTICS_update (stats, "# data on dying tunnel", 1, GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "data on dying tunnel %s[%X]\n",
- GNUNET_PEER_resolve2 (t->id.oid), ntohl (msg->tid));
- return GNUNET_OK; /* Next hop has destoyed the tunnel, drop */
- }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
ttl = ntohl (msg->ttl);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ttl);
if (ttl == 0)
{
GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n");
- tunnel_send_ack (t, GNUNET_MESSAGE_TYPE_MESH_ACK, fwd);
+ connection_send_ack (c, fwd);
return GNUNET_OK;
}
+ GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
+
+ send_prebuilt_message_connection (&msg->header, c, NULL, fwd);
+ connection_send_ack (c, fwd);
- if (myid != hop)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- send_prebuilt_message (message, hop, t);
- GNUNET_STATISTICS_update (stats, "# unicast forwarded", 1, GNUNET_NO);
- }
return GNUNET_OK;
}
/**
- * Core handler for mesh network traffic going from the origin to a peer
+ * Core handler for mesh network traffic going orig->dest.
*
* @param cls Closure (unused).
* @param message Message received.
* GNUNET_SYSERR to close it (signal serious error)
*/
static int
-handle_mesh_unicast (void *cls, const struct GNUNET_PeerIdentity *peer,
+handle_mesh_fwd (void *cls, const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_MessageHeader *message)
{
- return handle_mesh_data (peer, message, GNUNET_YES);
+ return handle_mesh_encrypted (peer,
+ (struct GNUNET_MESH_Encrypted *)message,
+ GNUNET_YES);
}
/**
- * Core handler for mesh network traffic towards the owner of a tunnel.
+ * Core handler for mesh network traffic going dest->orig.
*
* @param cls Closure (unused).
* @param message Message received.
* GNUNET_SYSERR to close it (signal serious error)
*/
static int
-handle_mesh_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer,
+handle_mesh_bck (void *cls, const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_MessageHeader *message)
{
- return handle_mesh_data (peer, message, GNUNET_NO);
+ return handle_mesh_encrypted (peer,
+ (struct GNUNET_MESH_Encrypted *)message,
+ GNUNET_NO);
}
-/**
- * Core handler for mesh network traffic end-to-end 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_data_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_MESH_DataACK *msg;
- struct MeshChannelReliability *rel;
- struct MeshReliableMessage *copy;
- struct MeshReliableMessage *next;
- struct MeshTunnel *t;
- GNUNET_PEER_Id id;
- uint32_t ack;
- uint16_t type;
- int work;
-
- type = ntohs (message->type);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a %s message from %s!\n",
- GNUNET_MESH_DEBUG_M2S (type), GNUNET_i2s (peer));
- msg = (struct GNUNET_MESH_DataACK *) message;
-
- t = channel_get (&msg->oid, ntohl (msg->tid));
- if (NULL == t)
- {
- /* TODO notify that we dont know this tunnel (whom)? */
- GNUNET_STATISTICS_update (stats, "# ack on unknown tunnel", 1, GNUNET_NO);
- return GNUNET_OK;
- }
- ack = ntohl (msg->mid);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack);
-
- /* Is this a forward or backward ACK? */
- id = GNUNET_PEER_search (peer);
- if (t->next_hop == id && GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK == type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
- if (NULL == t->owner)
- {
- send_prebuilt_message (message, t->prev_hop, t);
- return GNUNET_OK;
- }
- rel = t->fwd_rel;
- }
- else if (t->prev_hop == id && GNUNET_MESSAGE_TYPE_MESH_TO_ORIG_ACK == type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
- if (NULL == t->client)
- {
- send_prebuilt_message (message, t->next_hop, t);
- return GNUNET_OK;
- }
- rel = t->bck_rel;
- }
- else
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! ACK %u\n", ack);
- for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next)
- {
- if (GMC_is_pid_bigger (copy->mid, ack))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! head %u, out!\n", copy->mid);
- tunnel_free_sent_reliable (t, msg, rel);
- break;
- }
- work = GNUNET_YES;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! id %u\n", copy->mid);
- next = copy->next;
- tunnel_free_reliable_message (copy);
- }
- /* Once buffers have been free'd, send ACK */
- tunnel_send_ack (t, type, GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK == type);
-
- /* If some message was free'd, update the retransmission delay*/
- if (GNUNET_YES == work)
- {
- if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rel->retry_task);
- if (NULL == rel->head_sent)
- {
- rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
- }
- else
- {
- struct GNUNET_TIME_Absolute new_target;
- struct GNUNET_TIME_Relative delay;
-
- delay = GNUNET_TIME_relative_multiply (rel->retry_timer,
- MESH_RETRANSMIT_MARGIN);
- new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp,
- delay);
- delay = GNUNET_TIME_absolute_get_remaining (new_target);
- rel->retry_task =
- GNUNET_SCHEDULER_add_delayed (delay,
- &tunnel_retransmit_message,
- rel);
- }
- }
- else
- GNUNET_break (0);
- }
- return GNUNET_OK;
-}
-
/**
* Core handler for mesh network traffic point-to-point acks.
*
const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_ACK *msg;
- struct MeshTunnel *t;
+ struct MeshConnection *c;
struct MeshFlowControl *fc;
GNUNET_PEER_Id id;
uint32_t ack;
GNUNET_i2s (peer));
msg = (struct GNUNET_MESH_ACK *) message;
- t = channel_get (&msg->oid, ntohl (msg->tid));
+ c = connection_get (&msg->tid, ntohl (msg->cid));
- if (NULL == t)
+ if (NULL == c)
{
- /* TODO notify that we dont know this tunnel (whom)? */
- GNUNET_STATISTICS_update (stats, "# ack on unknown tunnel", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats, "# ack on unknown connection", 1,
+ GNUNET_NO);
return GNUNET_OK;
}
- ack = ntohl (msg->pid);
+
+ ack = ntohl (msg->ack);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack);
/* Is this a forward or backward ACK? */
id = GNUNET_PEER_search (peer);
- if (t->next_hop == id)
+ if (connection_get_next_hop (c)->id == id)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
- fc = &t->next_fc;
+ fc = &c->fwd_fc;
}
- else if (t->prev_hop == id)
+ else if (connection_get_prev_hop (c)->id == id)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
- fc = &t->prev_fc;
+ fc = &c->bck_fc;
}
else
{
return GNUNET_OK;
}
+ /* Cancel polling if the ACK is bigger than before. */
if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task &&
GMC_is_pid_bigger (ack, fc->last_ack_recv))
{
}
fc->last_ack_recv = ack;
- peer_unlock_queue (id);
- tunnel_change_state (t, MESH_TUNNEL_READY);
-
- tunnel_send_ack (t, GNUNET_MESSAGE_TYPE_MESH_ACK, t->next_hop == id);
+ connection_unlock_queue (c, fc == &c->fwd_fc);
return GNUNET_OK;
}
const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_Poll *msg;
- struct MeshTunnel *t;
+ struct MeshConnection *c;
struct MeshFlowControl *fc;
GNUNET_PEER_Id id;
uint32_t pid;
- uint32_t old;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a POLL packet from %s!\n",
GNUNET_i2s (peer));
msg = (struct GNUNET_MESH_Poll *) message;
- t = channel_get (&msg->oid, ntohl (msg->tid));
+ c = connection_get (&msg->tid, ntohl (msg->cid));
- if (NULL == t)
+ if (NULL == c)
{
- /* TODO notify that we dont know this tunnel (whom)? */
- GNUNET_STATISTICS_update (stats, "# poll on unknown tunnel", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1,
+ GNUNET_NO);
GNUNET_break_op (0);
return GNUNET_OK;
}
/* Is this a forward or backward ACK? */
id = GNUNET_PEER_search (peer);
- pid = ntohl (msg->pid);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " PID %u\n", pid);
- if (t->next_hop == id)
+ if (connection_get_next_hop (c)->id == id)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " from FWD\n");
- fc = &t->next_fc;
- old = fc->last_pid_recv;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
+ fc = &c->fwd_fc;
}
- else if (t->prev_hop == id)
+ else if (connection_get_prev_hop (c)->id == id)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " from BCK\n");
- fc = &t->prev_fc;
- old = fc->last_pid_recv;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
+ fc = &c->bck_fc;
}
else
{
- GNUNET_break (0);
+ GNUNET_break_op (0);
return GNUNET_OK;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " was %u\n", fc->last_pid_recv);
+ pid = ntohl (msg->pid);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " PID %u, OLD %u\n",
+ pid, fc->last_pid_recv);
fc->last_pid_recv = pid;
- tunnel_send_ack (t, GNUNET_MESSAGE_TYPE_MESH_POLL, t->prev_hop == id);
-
- if (GNUNET_YES == t->reliable)
- fc->last_pid_recv = old;
+ connection_send_ack (c, fc == &c->fwd_fc);
return GNUNET_OK;
}
handle_mesh_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_MessageHeader *message)
{
- struct GNUNET_MESH_TunnelKeepAlive *msg;
- struct MeshTunnel *t;
- struct MeshClient *c;
- GNUNET_PEER_Id hop;
+ struct GNUNET_MESH_ConnectionKeepAlive *msg;
+ struct MeshConnection *c;
+ struct MeshPeer *neighbor;
int fwd;
- msg = (struct GNUNET_MESH_TunnelKeepAlive *) message;
+ msg = (struct GNUNET_MESH_ConnectionKeepAlive *) message;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a keepalive packet from %s\n",
GNUNET_i2s (peer));
- t = channel_get (&msg->oid, ntohl (msg->tid));
- if (NULL == t)
+ c = connection_get (&msg->tid, ntohl (msg->cid));
+ if (NULL == c)
{
- /* TODO notify that we dont know that tunnel */
- GNUNET_STATISTICS_update (stats, "# keepalive on unknown tunnel", 1,
+ GNUNET_STATISTICS_update (stats, "# keepalive on unknown connection", 1,
GNUNET_NO);
return GNUNET_OK;
}
fwd = GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE == ntohs (message->type) ?
GNUNET_YES : GNUNET_NO;
- c = fwd ? t->client : t->owner;
- hop = fwd ? t->next_hop : t->prev_hop;
- if (NULL != c)
- tunnel_change_state (t, MESH_TUNNEL_READY);
- tunnel_reset_timeout (t, fwd);
- if (NULL != c || 0 == hop || myid == hop)
+ /* Check if origin is as expected */
+ neighbor = connection_get_hop (c, fwd);
+ if (peer_get (peer)->id != neighbor->id)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ connection_change_state (c, MESH_CONNECTION_READY);
+ connection_reset_timeout (c, fwd);
+
+ if (NULL != c->t->channel_head)
return GNUNET_OK;
GNUNET_STATISTICS_update (stats, "# keepalives forwarded", 1, GNUNET_NO);
- send_prebuilt_message (message, hop, t);
+ send_prebuilt_message_connection (message, c, NULL, fwd);
+
return GNUNET_OK;
- }
+}
{&handle_mesh_connection_ack, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK,
sizeof (struct GNUNET_MESH_ConnectionACK)},
{&handle_mesh_connection_broken, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN,
- sizeof (struct GNUNET_MESH_ConnectionBroken)},
- {&handle_mesh_tunnel_destroy, GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY,
- sizeof (struct GNUNET_MESH_TunnelDestroy)},
- {&handle_mesh_unicast, GNUNET_MESSAGE_TYPE_MESH_UNICAST, 0},
- {&handle_mesh_to_orig, GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN, 0},
- {&handle_mesh_data_ack, GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK,
- sizeof (struct GNUNET_MESH_DataACK)},
- {&handle_mesh_data_ack, GNUNET_MESSAGE_TYPE_MESH_TO_ORIG_ACK,
- sizeof (struct GNUNET_MESH_DataACK)},
+ sizeof (struct GNUNET_MESH_ConnectionBroken)},
+ {&handle_mesh_connection_destroy, GNUNET_MESSAGE_TYPE_MESH_CONNECTION_DESTROY,
+ sizeof (struct GNUNET_MESH_ConnectionDestroy)},
{&handle_mesh_keepalive, GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE,
- sizeof (struct GNUNET_MESH_TunnelKeepAlive)},
+ sizeof (struct GNUNET_MESH_ConnectionKeepAlive)},
{&handle_mesh_keepalive, GNUNET_MESSAGE_TYPE_MESH_BCK_KEEPALIVE,
- sizeof (struct GNUNET_MESH_TunnelKeepAlive)},
+ sizeof (struct GNUNET_MESH_ConnectionKeepAlive)},
{&handle_mesh_ack, GNUNET_MESSAGE_TYPE_MESH_ACK,
sizeof (struct GNUNET_MESH_ACK)},
{&handle_mesh_poll, GNUNET_MESSAGE_TYPE_MESH_POLL,
sizeof (struct GNUNET_MESH_Poll)},
+ {&handle_mesh_fwd, GNUNET_MESSAGE_TYPE_MESH_FWD, 0},
+ {&handle_mesh_bck, GNUNET_MESSAGE_TYPE_MESH_BCK, 0},
{NULL, 0, 0}
};
return;
c = GNUNET_malloc (sizeof (struct MeshClient));
c->handle = client;
+ c->id = next_client_id++; /* overflow not important: just for debug */
GNUNET_SERVER_client_keep (client);
GNUNET_SERVER_client_set_user_context (client, c);
GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c);
c->id, c);
GNUNET_SERVER_client_drop (c->handle);
c->shutting_down = GNUNET_YES;
- if (NULL != c->own_tunnels)
+ if (NULL != c->own_channels)
{
- GNUNET_CONTAINER_multihashmap32_iterate (c->own_tunnels,
- &tunnel_destroy_iterator, c);
- GNUNET_CONTAINER_multihashmap32_destroy (c->own_tunnels);
+ GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
+ &channel_destroy_iterator, c);
+ GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
}
- if (NULL != c->incoming_tunnels)
+ if (NULL != c->incoming_channels)
{
- GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_tunnels,
- &tunnel_destroy_iterator, c);
- GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_tunnels);
+ GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
+ &channel_destroy_iterator, c);
+ GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels);
}
if (NULL != c->ports)
}
next = c->next;
GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c);
+ GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client free (%p)\n", c);
GNUNET_free (c);
- GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
c = next;
}
else
/* Initialize new client structure */
c = GNUNET_SERVER_client_get_user_context (client, struct MeshClient);
- c->id = next_client_id++; /* overflow not important: just for debug */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client id %u\n", c->id);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client has %u ports\n", size);
if (size > 0)
GNUNET_i2s (&msg->peer), ntohl (msg->port));
chid = ntohl (msg->channel_id);
- /* Sanity check for duplicate tunnel IDs */
+ /* Sanity check for duplicate channel IDs */
if (NULL != channel_get_by_local_id (c, chid))
{
GNUNET_break (0);
peer = peer_get (&msg->peer);
if (NULL == peer->tunnel)
- peer->tunnel = tunnel_new ();
+ {
+ struct GNUNET_HashCode tid;
+
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &tid);
+ peer->tunnel = tunnel_new (&tid);
+ }
t = peer->tunnel;
/* Create channel */
- while (NULL != channel_get_by_pi (myid, next_tid))
- next_tid = (next_tid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
- t = tunnel_new (myid, next_tid, c, chid);
- next_tid = (next_tid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
- if (NULL == t)
+ ch = channel_new (t, c, chid);
+ if (NULL == ch)
{
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- t->port = ntohl (msg->port);
- tunnel_set_options (t, ntohl (msg->opt));
- if (GNUNET_YES == t->reliable)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n");
- t->fwd_rel = GNUNET_malloc (sizeof (struct MeshChannelReliability));
- t->fwd_rel->t = t;
- t->fwd_rel->expected_delay = MESH_RETRANSMIT_TIME;
- }
+ ch->port = ntohl (msg->port);
+ channel_set_options (ch, ntohl (msg->opt));
- 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);
+ /* In unreliable channels, we'll use the DLL to buffer data for the root */
+ ch->fwd_rel = GNUNET_malloc (sizeof (struct MeshChannelReliability));
+ ch->fwd_rel->ch = ch;
+ ch->fwd_rel->expected_delay = MESH_RETRANSMIT_TIME;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s[%x]:%u (%x)\n",
+ GNUNET_h2s (&t->id), ch->gid, ch->port, ch->lid_root);
+ peer_connect (peer);
+ /* FIXME send create channel */
- peer_info = peer_get (&msg->peer);
- peer_add_tunnel (peer_info, t);
- peer_connect (peer_info, t);
- tunnel_reset_timeout (t, GNUNET_YES);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
handle_local_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
- struct GNUNET_MESH_ChannelMessage *tunnel_msg;
+ struct GNUNET_MESH_ChannelMessage *msg;
struct MeshClient *c;
- struct MeshTunnel *t;
- MESH_ChannelNumber tid;
+ struct MeshChannel *ch;
+ struct MeshTunnel2 *t;
+ MESH_ChannelNumber chid;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got a DESTROY TUNNEL from client!\n");
+ "Got a DESTROY CHANNEL from client!\n");
/* Sanity check for client registration */
if (NULL == (c = client_get (client)))
return;
}
- tunnel_msg = (struct GNUNET_MESH_ChannelMessage *) message;
+ msg = (struct GNUNET_MESH_ChannelMessage *) message;
/* Retrieve tunnel */
- tid = ntohl (tunnel_msg->channel_id);
- t = channel_get_by_local_id (c, tid);
- if (NULL == t)
+ chid = ntohl (msg->channel_id);
+ ch = channel_get_by_local_id (c, chid);
+ if (NULL == ch)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " tunnel %X not found\n", tid);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " channel %X not found\n", chid);
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
/* Cleanup after the tunnel */
- client_delete_tunnel (c, t);
- if (c == t->client && GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= tid)
+ client_delete_channel (c, ch);
+ if (c == ch->dest && GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= chid)
{
- t->client = NULL;
+ ch->dest = NULL;
}
- else if (c == t->owner && GNUNET_MESH_LOCAL_CHANNEL_ID_SERV > tid)
+ else if (c == ch->root && GNUNET_MESH_LOCAL_CHANNEL_ID_SERV > chid)
{
- peer_remove_tunnel (peer_get_short (t->dest), t);
- t->owner = NULL;
+ ch->root = NULL;
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- " tunnel %X client %p (%p, %p)\n",
- tid, c, t->owner, t->client);
+ " channel %X client %p (%p, %p)\n",
+ chid, c, ch->root, ch->dest);
GNUNET_break (0);
}
- /* The tunnel will be destroyed when the last message is transmitted. */
- tunnel_destroy_empty (t);
+ t = ch->t;
+ channel_destroy (ch);
+ tunnel_destroy_if_empty (t);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
handle_local_data (void *cls, struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
- struct GNUNET_MESH_LocalData *data_msg;
+ struct GNUNET_MESH_LocalData *msg;
struct MeshClient *c;
- struct MeshTunnel *t;
- struct MeshFlowControl *fc;
- MESH_ChannelNumber tid;
+ struct MeshChannel *ch;
+ MESH_ChannelNumber chid;
size_t size;
+ int fwd;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got data from a client!\n");
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
- data_msg = (struct GNUNET_MESH_LocalData *) message;
+ msg = (struct GNUNET_MESH_LocalData *) message;
/* Sanity check for message size */
size = ntohs (message->size) - sizeof (struct GNUNET_MESH_LocalData);
return;
}
- /* Tunnel exists? */
- tid = ntohl (data_msg->tid);
- t = channel_get_by_local_id (c, tid);
- if (NULL == t)
+ /* Channel exists? */
+ chid = ntohl (msg->id);
+ fwd = chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
+ ch = channel_get_by_local_id (c, chid);
+ if (NULL == ch)
{
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- /* Is the client in the tunnel? */
- if ( !( (tid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV &&
- t->owner &&
- t->owner->handle == client)
+ /* Is the client in the channel? */
+ if ( !( (fwd &&
+ ch->root &&
+ ch->root->handle == client)
||
- (tid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV &&
- t->client &&
- t->client->handle == client) ) )
+ (!fwd &&
+ ch->dest &&
+ ch->dest->handle == client) ) )
{
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
{
struct GNUNET_MESH_Data *payload;
char cbuf[sizeof(struct GNUNET_MESH_Data) + size];
+ uint32_t *mid;
- fc = tid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV ? &t->prev_fc : &t->next_fc;
- if (GNUNET_YES == t->reliable)
+ mid = fwd ? &ch->mid_send_fwd : &ch->mid_send_bck;
+ if (GNUNET_YES == ch->reliable)
{
struct MeshChannelReliability *rel;
struct MeshReliableMessage *copy;
- rel = (tid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV) ? t->fwd_rel : t->bck_rel;
+ rel = fwd ? ch->fwd_rel : ch->bck_rel;
copy = GNUNET_malloc (sizeof (struct MeshReliableMessage)
+ sizeof(struct GNUNET_MESH_Data)
+ size);
- copy->mid = rel->mid_sent++;
+ copy->mid = *mid;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "!!! DATA %u\n", copy->mid);
copy->timestamp = GNUNET_TIME_absolute_get ();
copy->rel = rel;
MESH_RETRANSMIT_MARGIN);
rel->retry_task =
GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
- &tunnel_retransmit_message,
+ &channel_retransmit_message,
rel);
}
payload = (struct GNUNET_MESH_Data *) ©[1];
- payload->mid = htonl (copy->mid);
}
else
{
payload = (struct GNUNET_MESH_Data *) cbuf;
- payload->mid = htonl (fc->last_pid_recv + 1);
}
- memcpy (&payload[1], &data_msg[1], size);
+ payload->mid = htonl (*mid);
+ *mid = *mid + 1;
+ memcpy (&payload[1], &msg[1], size);
payload->header.size = htons (sizeof (struct GNUNET_MESH_Data) + size);
- payload->header.type = htons (tid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV ?
+ payload->header.type = htons (chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV ?
GNUNET_MESSAGE_TYPE_MESH_UNICAST :
GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
- GNUNET_PEER_resolve(t->id.oid, &payload->oid);;
- payload->tid = htonl (t->id.tid);
- payload->ttl = htonl (default_ttl);
- payload->pid = htonl (fc->last_pid_recv + 1);
+ payload->chid = htonl (ch->gid);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
" calling generic handler...\n");
- if (tid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
- handle_mesh_unicast (NULL, &my_full_id, &payload->header);
- else
- handle_mesh_to_orig (NULL, &my_full_id, &payload->header);
+ send_prebuilt_message_channel (&payload->header, ch, fwd);
}
+ if (tunnel_get_buffer (ch->t, fwd) > 0)
+ send_local_ack (ch, c, fwd);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n");
GNUNET_SERVER_receive_done (client, GNUNET_OK);
const struct GNUNET_MessageHeader *message)
{
struct GNUNET_MESH_LocalAck *msg;
- struct MeshTunnel *t;
+ struct MeshChannelReliability *rel;
+ struct MeshChannel *ch;
struct MeshClient *c;
- MESH_ChannelNumber tid;
+ MESH_ChannelNumber chid;
+ int fwd;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n");
+
/* Sanity check for client registration */
if (NULL == (c = client_get (client)))
{
msg = (struct GNUNET_MESH_LocalAck *) message;
- /* Tunnel exists? */
- tid = ntohl (msg->channel_id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " on tunnel %X\n", tid);
- t = channel_get_by_local_id (c, tid);
- if (NULL == t)
+ /* Channel exists? */
+ chid = ntohl (msg->channel_id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid);
+ ch = channel_get_by_local_id (c, chid);
+ if (NULL == ch)
{
GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tunnel %X unknown.\n", tid);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Channel %X unknown.\n", chid);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " for client %u.\n", c->id);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- /* Does client own tunnel? I.E: Is this an ACK for BCK traffic? */
- if (tid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
- {
- /* The client owns the tunnel, ACK is for data to_origin, send BCK ACK. */
- t->prev_fc.last_ack_recv++;
- tunnel_send_ack (t, GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK, GNUNET_NO);
- }
- else
- {
- /* The client doesn't own the tunnel, this ACK is for FWD traffic. */
- t->next_fc.last_ack_recv++;
- tunnel_send_ack (t, GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK, GNUNET_YES);
- }
+ fwd = chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
+ rel = fwd ? ch->fwd_rel : ch->bck_rel;
+
+ rel->client_ready = GNUNET_YES;
+ channel_send_client_buffered_data (ch, c, rel);
+ channel_send_ack (ch, 64 - rel->n_recv, fwd);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
-
/**
* Iterator over all tunnels to send a monitoring client info about each tunnel.
*
struct GNUNET_MESH_LocalMonitor *msg;
msg = GNUNET_malloc (sizeof(struct GNUNET_MESH_LocalMonitor));
- msg->channel_id = htonl (ch->id);
+ msg->channel_id = htonl (ch->gid);
msg->header.size = htons (sizeof (struct GNUNET_MESH_LocalMonitor));
msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS);
c->id,
&msg->owner,
ntohl (msg->channel_id));
- ch = channel_get (&msg->owner, ntohl (msg->channel_id));
+// ch = channel_get (&msg->owner, ntohl (msg->channel_id));
+ ch = NULL; // FIXME
if (NULL == ch)
{
/* We don't know the tunnel */
static void
core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
{
- struct MeshPeer *peer_info;
+ struct MeshPeer *pi;
struct MeshPeerPath *path;
DEBUG_CONN ("Peer connected\n");
DEBUG_CONN (" %s\n", GNUNET_i2s (&my_full_id));
- peer_info = peer_get (peer);
- if (myid == peer_info->id)
+ pi = peer_get (peer);
+ if (myid == pi->id)
{
DEBUG_CONN (" (self)\n");
path = path_new (1);
{
DEBUG_CONN (" %s\n", GNUNET_i2s (peer));
path = path_new (2);
- path->peers[1] = peer_info->id;
- GNUNET_PEER_change_rc (peer_info->id, 1);
+ path->peers[1] = pi->id;
+ GNUNET_PEER_change_rc (pi->id, 1);
GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
}
path->peers[0] = myid;
GNUNET_PEER_change_rc (myid, 1);
- peer_add_path (peer_info, path, GNUNET_YES);
- if (NULL == peer_info->fc)
- {
- peer_info->fc = GNUNET_new (struct MeshFlowControl);
- fc_init (peer_info->fc);
- peer_info->fc->peer = peer_info;
- }
+ peer_add_path (pi, path, GNUNET_YES);
+
+ pi->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
return;
}
core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
{
struct MeshPeer *pi;
- struct MeshPeerQueue *q;
- struct MeshPeerQueue *n;
- struct MeshFlowControl *fc;
DEBUG_CONN ("Peer disconnected\n");
pi = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
GNUNET_break (0);
return;
}
- fc = pi->fc;
- if (NULL != fc)
- {
- GNUNET_break (0);
- return;
- }
- pi->fc = NULL;
- q = fc->queue_head;
- while (NULL != q)
- {
- n = q->next;
- queue_destroy (q, GNUNET_YES);
- q = n;
- }
- if (NULL != fc->core_transmit)
- GNUNET_CORE_notify_transmit_ready_cancel (fc->core_transmit);
- if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
- GNUNET_SCHEDULER_cancel (fc->poll_task);
+ peer_remove_path (pi, myid, pi->id);
- peer_remove_path (pi, pi->id, myid);
+ GNUNET_CONTAINER_multihashmap_iterate (pi->connections,
+ connection_broken,
+ pi);
+ GNUNET_CONTAINER_multihashmap_destroy (pi->connections);
+ pi->connections = NULL;
if (myid == pi->id)
{
DEBUG_CONN (" (self)\n");
}
GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
- GNUNET_free (fc);
return;
}
return GNUNET_YES;
}
-/**
- * Iterator over peer hash map entries to destroy the tunnel during shutdown.
- *
- * @param cls closure
- * @param key current key code
- * @param value value in the hash map
- * @return GNUNET_YES if we should continue to iterate,
- * GNUNET_NO if not.
- */
-static int
-shutdown_peer (void *cls, const struct GNUNET_HashCode * key, void *value)
-{
- struct MeshPeer *p = value;
- struct MeshPeerQueue *q;
- struct MeshPeerQueue *n;
-
- q = p->fc->queue_head;
- while (NULL != q)
- {
- n = q->next;
- if (q->peer == p)
- {
- queue_destroy(q, GNUNET_YES);
- }
- q = n;
- }
- peer_destroy (p);
- return GNUNET_YES;
-}
-
/**
* Task run during shutdown.
core_handle = NULL;
}
GNUNET_CONTAINER_multihashmap_iterate (tunnels, &shutdown_tunnel, NULL);
- GNUNET_CONTAINER_multihashmap_iterate (peers, &shutdown_peer, NULL);
if (dht_handle != NULL)
{
GNUNET_DHT_disconnect (dht_handle);