From 28653a4922fd5a2d8fb7f72d799c9e79a2400abe Mon Sep 17 00:00:00 2001 From: Bart Polot Date: Fri, 18 Oct 2013 02:23:43 +0000 Subject: [PATCH] - flow control changes and fixes --- src/mesh/gnunet-service-mesh_channel.c | 48 +++- src/mesh/gnunet-service-mesh_channel.h | 22 ++ src/mesh/gnunet-service-mesh_connection.c | 253 ++++++++++++---------- src/mesh/gnunet-service-mesh_connection.h | 11 +- src/mesh/gnunet-service-mesh_local.c | 4 +- src/mesh/gnunet-service-mesh_tunnel.c | 71 +++++- src/mesh/gnunet-service-mesh_tunnel.h | 13 +- 7 files changed, 293 insertions(+), 129 deletions(-) diff --git a/src/mesh/gnunet-service-mesh_channel.c b/src/mesh/gnunet-service-mesh_channel.c index b02da1aba..519dda89d 100644 --- a/src/mesh/gnunet-service-mesh_channel.c +++ b/src/mesh/gnunet-service-mesh_channel.c @@ -143,6 +143,11 @@ struct MeshChannelReliability */ int client_ready; + /** + * Can the client send data to us? + */ + int client_allowed; + /** * Task to resend/poll in case no ACK is received. */ @@ -465,6 +470,13 @@ send_client_ack (struct MeshChannel *ch, int fwd) return; } + if (GNUNET_YES == rel->client_allowed) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n"); + return; + } + rel->client_allowed = GNUNET_YES; + GML_send_ack (fwd ? ch->root : ch->dest, fwd ? ch->lid_root : ch->lid_dest); } @@ -996,6 +1008,25 @@ GMCH_get_buffer (struct MeshChannel *ch, int fwd) } +/** + * Get flow control status of end point: is client allow to send? + * + * @param ch Channel. + * @param fwd Is query about FWD traffic? (Request root status). + * + * @return GNUNET_YES if client is allowed to send us data. + */ +int +GMCH_get_allowed (struct MeshChannel *ch, int fwd) +{ + struct MeshChannelReliability *rel; + + rel = fwd ? ch->root_rel : ch->dest_rel; + + return rel->client_allowed; +} + + /** * Is the root client for this channel on this peer? * @@ -1151,6 +1182,19 @@ GMCH_send_data_ack (struct MeshChannel *ch, int fwd) } +/** + * Allow a client to send us more data, in case it was choked. + * + * @param ch Channel. + * @param fwd Is this about FWD traffic? (Root client). + */ +void +GMCH_allow_client (struct MeshChannel *ch, int fwd) +{ + send_client_ack (ch, fwd); +} + + /** * Log channel info. * @@ -1206,7 +1250,7 @@ GMCH_handle_local_ack (struct MeshChannel *ch, int fwd) rel->client_ready = GNUNET_YES; send_client_buffered_data (ch, c, fwd); - GMC_send_ack (NULL, ch, fwd); + GMT_send_acks (ch->t, fwd); } @@ -1247,6 +1291,8 @@ GMCH_handle_local_data (struct MeshChannel *ch, rel = fwd ? ch->root_rel : ch->dest_rel; + rel->client_allowed = GNUNET_NO; + /* Ok, everything is correct, send the message. */ payload = (struct GNUNET_MESH_Data *) cbuf; payload->mid = htonl (rel->mid_send); diff --git a/src/mesh/gnunet-service-mesh_channel.h b/src/mesh/gnunet-service-mesh_channel.h index 82d85e5be..13bef4799 100644 --- a/src/mesh/gnunet-service-mesh_channel.h +++ b/src/mesh/gnunet-service-mesh_channel.h @@ -84,6 +84,19 @@ GMCH_get_tunnel (const struct MeshChannel *ch); unsigned int GMCH_get_buffer (struct MeshChannel *ch, int fwd); + +/** + * Get flow control status of end point: is client allow to send? + * + * @param ch Channel. + * @param fwd Is query about FWD traffic? (Request root status). + * + * @return GNUNET_YES if client is allowed to send us data. + */ +int +GMCH_get_allowed (struct MeshChannel *ch, int fwd); + + /** * Is the root client for this channel on this peer? * @@ -148,6 +161,15 @@ GMCH_send_create (struct MeshChannel *ch); void GMCH_send_destroy (struct MeshChannel *ch); +/** + * Allow a client to send us more data, in case it was choked. + * + * @param ch Channel. + * @param fwd Is this about FWD traffic? (Root client). + */ +void +GMCH_allow_client (struct MeshChannel *ch, int fwd); + /** * Log channel info. * diff --git a/src/mesh/gnunet-service-mesh_connection.c b/src/mesh/gnunet-service-mesh_connection.c index 7ce26082a..64174f3f5 100644 --- a/src/mesh/gnunet-service-mesh_connection.c +++ b/src/mesh/gnunet-service-mesh_connection.c @@ -269,7 +269,7 @@ connection_debug (struct MeshConnection *c) return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n", - peer2s (c->t->peer), GNUNET_h2s (&c->id)); + peer2s (c->t->peer), GMC_2s (c)); LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n", c->state, c->pending_messages); LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); @@ -343,14 +343,85 @@ connection_change_state (struct MeshConnection* c, { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s state was %s\n", - GNUNET_h2s (&c->id), GMC_state2s (c->state)); + GMC_2s (c), GMC_state2s (c->state)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s state is now %s\n", - GNUNET_h2s (&c->id), GMC_state2s (state)); + GMC_2s (c), GMC_state2s (state)); c->state = state; } +/** + * Send an ACK on the connection, informing the predecessor about + * the available buffer space. Should not be called in case the peer + * is origin (no predecessor). + * + * 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 buffer How much space free to advertise? + * @param fwd Is this FWD ACK? (Going dest->owner) + */ +static void +send_ack (struct MeshConnection *c, unsigned int buffer, int fwd) +{ + struct MeshFlowControl *next_fc; + struct MeshFlowControl *prev_fc; + struct GNUNET_MESH_ACK msg; + uint32_t ack; + int delta; + + /* If origin, there is no connection to send ACKs. Wrong function! */ + if (GMC_is_origin (c, fwd)) + { + GNUNET_break (0); + return; + } + + next_fc = fwd ? &c->fwd_fc : &c->bck_fc; + prev_fc = fwd ? &c->bck_fc : &c->fwd_fc; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connection send %s ack on %s\n", + fwd ? "FWD" : "BCK", GMC_2s (c)); + + /* Check if we need to transmit the ACK */ + delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv; + if (3 < delta && buffer < delta) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " last pid recv: %u, last ack sent: %u\n", + prev_fc->last_pid_recv, prev_fc->last_ack_sent); + return; + } + + /* Ok, ACK might be necessary, what PID to ACK? */ + ack = prev_fc->last_pid_recv + buffer; + LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " last pid %u, last ack %u, qmax %u, q %u\n", + prev_fc->last_pid_recv, prev_fc->last_ack_sent, + next_fc->queue_max, next_fc->queue_n); + if (ack == prev_fc->last_ack_sent) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n"); + return; + } + + prev_fc->last_ack_sent = ack; + + /* Build ACK message and send on connection */ + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ACK); + msg.ack = htonl (ack); + msg.cid = c->id; + + GMC_send_prebuilt_message (&msg.header, c, NULL, !fwd); +} + + /** * Callback called when a queued message is sent. * @@ -374,8 +445,8 @@ message_sent (void *cls, double usecsperbyte; fc = fwd ? &c->fwd_fc : &c->bck_fc; + LOG (GNUNET_ERROR_TYPE_DEBUG, "! sent %s\n", GNUNET_MESH_DEBUG_M2S (type)); LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n); - fc->queue_n--; c->pending_messages--; if (GNUNET_YES == c->destroy && 0 == c->pending_messages) { @@ -387,17 +458,20 @@ message_sent (void *cls, { case GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED: fc->last_pid_sent++; - LOG (GNUNET_ERROR_TYPE_DEBUG, "! accounting pid %u\n", fc->last_pid_sent); -// send_ack (c, ch, fwd); + fc->queue_n--; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "! accounting pid %u\n", + fc->last_pid_sent); + GMC_send_ack (c, fwd); break; default: break; } + LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n"); if (NULL == c->perf) return; /* Only endpoints are interested in timing. */ - LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n"); p = c->perf; usecsperbyte = ((double) wait.rel_value_us) / size; if (p->size == AVG_MSGS) @@ -516,69 +590,6 @@ is_fwd (const struct MeshConnection *c, } - -/** - * Send an ACK informing the predecessor about the available buffer space. - * - * 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 buffer How much space free to advertise? - * @param fwd Is this FWD ACK? (Going dest->owner) - */ -static void -send_ack (struct MeshConnection *c, unsigned int buffer, int fwd) -{ - struct MeshFlowControl *next_fc; - struct MeshFlowControl *prev_fc; - struct GNUNET_MESH_ACK msg; - uint32_t ack; - int delta; - - next_fc = fwd ? &c->fwd_fc : &c->bck_fc; - prev_fc = fwd ? &c->bck_fc : &c->fwd_fc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "connection send %s ack on %s\n", - fwd ? "FWD" : "BCK", GNUNET_h2s (&c->id)); - - /* Check if we need to transmit the ACK */ - delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv; - if (3 < delta && buffer < delta) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " last pid recv: %u, last ack sent: %u\n", - prev_fc->last_pid_recv, prev_fc->last_ack_sent); - return; - } - - /* Ok, ACK might be necessary, what PID to ACK? */ - ack = prev_fc->last_pid_recv + buffer; - LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " last pid %u, last ack %u, qmax %u, q %u\n", - prev_fc->last_pid_recv, prev_fc->last_ack_sent, - next_fc->queue_max, next_fc->queue_n); - if (ack == prev_fc->last_ack_sent) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n"); - return; - } - - prev_fc->last_ack_sent = ack; - - /* Build ACK message and send on connection */ - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ACK); - msg.ack = htonl (ack); - msg.cid = c->id; - - GMC_send_prebuilt_message (&msg.header, c, NULL, !fwd); -} - - /** * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE * or a first CONNECTION_ACK directed to us. @@ -590,7 +601,6 @@ send_ack (struct MeshConnection *c, unsigned int buffer, int fwd) static void send_connection_ack (struct MeshConnection *connection, int fwd) { - struct MeshFlowControl *fc; struct MeshTunnel3 *t; t = connection->t; @@ -604,8 +614,6 @@ send_connection_ack (struct MeshConnection *connection, int fwd) GMT_change_state (t, MESH_TUNNEL3_WAITING); if (MESH_CONNECTION_READY != connection->state) connection_change_state (connection, MESH_CONNECTION_SENT); - fc = fwd ? &connection->fwd_fc : &connection->bck_fc; - fc->queue_n++; } @@ -653,8 +661,8 @@ connection_keepalive (struct MeshConnection *c, int fwd) GNUNET_MESSAGE_TYPE_MESH_BCK_KEEPALIVE; LOG (GNUNET_ERROR_TYPE_DEBUG, - "sending %s keepalive for connection %s[%d]\n", - fwd ? "FWD" : "BCK", GMT_2s (c->t), c->id); + "sending %s keepalive for connection %s]\n", + fwd ? "FWD" : "BCK", GMC_2s (c)); msg = (struct GNUNET_MESH_ConnectionKeepAlive *) cbuf; msg->header.size = htons (size); @@ -763,7 +771,7 @@ connection_unlock_queue (struct MeshConnection *c, int fwd) LOG (GNUNET_ERROR_TYPE_DEBUG, "connection_unlock_queue %s on %s\n", - fwd ? "FWD" : "BCK", GNUNET_h2s (&c->id)); + fwd ? "FWD" : "BCK", GMC_2s (c)); if (GMC_is_terminal (c, fwd)) { @@ -829,8 +837,7 @@ connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) c = fc->c; LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Polling!\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** connection [%X]\n", - GNUNET_h2s (&c->id)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** connection [%s]\n", GMC_2s (c)); LOG (GNUNET_ERROR_TYPE_DEBUG, " *** %s\n", fc == &c->fwd_fc ? "FWD" : "BCK"); @@ -1440,7 +1447,7 @@ handle_mesh_encrypted (const struct GNUNET_PeerIdentity *peer, } fc->last_pid_recv = pid; GMT_handle_encrypted (c->t, msg, fwd); - GMC_send_ack (c, NULL, fwd); + GMC_send_ack (c, fwd); return GNUNET_OK; } @@ -1452,7 +1459,7 @@ handle_mesh_encrypted (const struct GNUNET_PeerIdentity *peer, { GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n"); - GMC_send_ack (c, NULL, fwd); + GMC_send_ack (c, fwd); return GNUNET_OK; } GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO); @@ -1623,7 +1630,7 @@ GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer, pid, fc->last_pid_recv); fc->last_pid_recv = pid; fwd = fc == &c->fwd_fc; - GMC_send_ack (c, NULL, fwd); + GMC_send_ack (c, fwd); return GNUNET_OK; } @@ -1690,25 +1697,28 @@ GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer, * the direction and the position of the peer. * * @param c Which connection to send the hop-by-hop ACK. - * @param ch Channel, if any. * @param fwd Is this a fwd ACK? (will go dest->root) */ void -GMC_send_ack (struct MeshConnection *c, struct MeshChannel *ch, int fwd) +GMC_send_ack (struct MeshConnection *c, int fwd) { unsigned int buffer; LOG (GNUNET_ERROR_TYPE_DEBUG, - "send ack %s on %p %p\n", - fwd ? "FWD" : "BCK", c, ch); + "GMC send %s ACK on %s\n", + fwd ? "FWD" : "BCK", GMC_2s (c)); - /* Get available bufffer space */ - if (NULL == c || GMC_is_terminal (c, fwd)) + if (NULL == c) + { + GNUNET_break (0); + return; + } + + /* Get available buffer space */ + if (GMC_is_terminal (c, fwd)) { - struct MeshTunnel3 *t; - LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all connections\n"); - t = (NULL == c) ? GMCH_get_tunnel (ch) : GMC_get_tunnel (c); - buffer = GMT_get_buffer (t, fwd); + LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n"); + buffer = GMT_get_buffer (c->t, fwd); } else { @@ -1718,23 +1728,16 @@ GMC_send_ack (struct MeshConnection *c, struct MeshChannel *ch, int fwd) LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer); /* Send available buffer space */ - if ( (NULL != ch && GMCH_is_origin (ch, fwd)) || - (NULL != c && GMC_is_origin (c, fwd)) ) + if (GMC_is_origin (c, fwd)) { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n"); + GNUNET_assert (NULL != c->t); + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n"); if (0 < buffer) { - GNUNET_assert (NULL != ch); LOG (GNUNET_ERROR_TYPE_DEBUG, " really sending!\n"); - GMCH_send_data_ack (ch, fwd); + GMT_unchoke_channels (c->t, fwd); } } - else if (NULL == c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on all connections\n"); - GNUNET_assert (NULL != ch); - GMT_send_acks (GMCH_get_tunnel (ch), buffer, fwd); - } else { LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n"); @@ -1838,8 +1841,7 @@ GMC_destroy (struct MeshConnection *c) if (NULL == c) return; - LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n", - GNUNET_h2s (&c->id)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n", GMC_2s (c)); /* Cancel all traffic */ connection_cancel_queues (c, GNUNET_YES); @@ -2106,8 +2108,9 @@ GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, memcpy (data, message, size); type = ntohs (message->type); LOG (GNUNET_ERROR_TYPE_DEBUG, "Send %s (%u) on connection %s\n", - GNUNET_MESH_DEBUG_M2S (type), size, GNUNET_h2s (&c->id)); + GNUNET_MESH_DEBUG_M2S (type), size, GMC_2s (c)); + fc = fwd ? &c->fwd_fc : &c->bck_fc; droppable = GNUNET_YES; switch (type) { @@ -2129,7 +2132,15 @@ GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, emsg->cid = c->id; emsg->ttl = htonl (ttl - 1); emsg->pid = htonl (fwd ? c->fwd_fc.next_pid++ : c->bck_fc.next_pid++); - LOG (GNUNET_ERROR_TYPE_DEBUG, " pid %u\n", ntohl (emsg->pid)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n); + fc->queue_n++; + LOG (GNUNET_ERROR_TYPE_DEBUG, "pid %u\n", ntohl (emsg->pid)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid %u\n", fc->last_pid_sent); + LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", fc->last_ack_recv); + if (GMC_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv)) + { + GMC_start_poll (c, fwd); + } break; case GNUNET_MESSAGE_TYPE_MESH_ACK: @@ -2167,7 +2178,6 @@ GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, GNUNET_break (0); } - fc = fwd ? &c->fwd_fc : &c->bck_fc; if (fc->queue_n >= fc->queue_max && droppable) { GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)", @@ -2179,14 +2189,6 @@ GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, return; /* Drop this message */ } - LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid %u\n", fc->last_pid_sent); - LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", fc->last_ack_recv); - LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n); - if (GMC_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv)) - { - GMC_start_poll (c, fwd); - } - fc->queue_n++; c->pending_messages++; GMP_queue_add (get_hop (c, fwd), data, type, size, c, ch, fwd, @@ -2218,7 +2220,6 @@ GMC_send_create (struct MeshConnection *connection) GMT_change_state (connection->t, MESH_TUNNEL3_WAITING); if (MESH_CONNECTION_NEW == connection->state) connection_change_state (connection, MESH_CONNECTION_SENT); - connection->fwd_fc.queue_n++; } @@ -2244,7 +2245,7 @@ GMC_send_destroy (struct MeshConnection *c) msg.cid = c->id; LOG (GNUNET_ERROR_TYPE_DEBUG, " sending connection destroy for connection %s\n", - GNUNET_h2s (&c->id)); + GMC_2s (c)); if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES)) GMC_send_prebuilt_message (&msg.header, c, NULL, GNUNET_YES); @@ -2299,4 +2300,22 @@ GMC_stop_poll (struct MeshConnection *c, int fwd) GNUNET_SCHEDULER_cancel (fc->poll_task); fc->poll_task = GNUNET_SCHEDULER_NO_TASK; } +} + +/** + * Get a (static) string for a connection. + * + * @param c Connection. + */ +const char * +GMC_2s (struct MeshConnection *c) +{ + if (NULL != c->t) + { + static char buf[128]; + + sprintf (buf, "%s (->%s)", GNUNET_h2s (&c->id), GMT_2s (c->t)); + return buf; + } + return GNUNET_h2s (&c->id); } \ No newline at end of file diff --git a/src/mesh/gnunet-service-mesh_connection.h b/src/mesh/gnunet-service-mesh_connection.h index 3fecf3b63..816d93f45 100644 --- a/src/mesh/gnunet-service-mesh_connection.h +++ b/src/mesh/gnunet-service-mesh_connection.h @@ -197,11 +197,10 @@ GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer, * the direction and the position of the peer. * * @param c Which connection to send the hop-by-hop ACK. - * @param ch Channel, if any. * @param fwd Is this a fwd ACK? (will go dest->root) */ void -GMC_send_ack (struct MeshConnection *c, struct MeshChannel *ch, int fwd); +GMC_send_ack (struct MeshConnection *c, int fwd); /** * Initialize the connections subsystem @@ -451,6 +450,14 @@ GMC_start_poll (struct MeshConnection *c, int fwd); void GMC_stop_poll (struct MeshConnection *c, int fwd); +/** + * Get a (static) string for a connection. + * + * @param c Connection. + */ +const char * +GMC_2s (struct MeshConnection *c); + #if 0 /* keep Emacsens' auto-indent happy */ { #endif diff --git a/src/mesh/gnunet-service-mesh_local.c b/src/mesh/gnunet-service-mesh_local.c index 67d4690e5..9b868124a 100644 --- a/src/mesh/gnunet-service-mesh_local.c +++ b/src/mesh/gnunet-service-mesh_local.c @@ -555,8 +555,8 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client, return; } - /* If client is root, the ACK is going FWD, therefore this is "BCK". */ - /* If client is dest, the ACK is going BCK, therefore this is "FWD" */ + /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */ + /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */ fwd = chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV; GMCH_handle_local_ack (ch, fwd); diff --git a/src/mesh/gnunet-service-mesh_tunnel.c b/src/mesh/gnunet-service-mesh_tunnel.c index 89c9a9db1..5b0573d0a 100644 --- a/src/mesh/gnunet-service-mesh_tunnel.c +++ b/src/mesh/gnunet-service-mesh_tunnel.c @@ -984,7 +984,7 @@ GMT_count_channels (struct MeshTunnel3 *t) for (count = 0, iter = t->channel_head; NULL != iter; - iter = iter->next, count++); + iter = iter->next, count++) /* skip */; return count; } @@ -1008,10 +1008,13 @@ GMT_get_state (struct MeshTunnel3 *t) /** * Get the total buffer space for a tunnel. * + * If terminal, use the biggest channel buffer (or 64) if no channel exists. + * If not terminal, use the sum of all connection buffers. + * * @param t Tunnel. * @param fwd Is this for FWD traffic? * - * @return Buffer space offered by all connections in the tunnel. + * @return Buffer space offered by all entities (c/ch) in the tunnel. */ unsigned int GMT_get_buffer (struct MeshTunnel3 *t, int fwd) @@ -1030,7 +1033,7 @@ GMT_get_buffer (struct MeshTunnel3 *t, int fwd) if (NULL == t->channel_head) { - /* Probably getting buffer for a channel create. */ + /* Probably getting buffer for a channel create/handshake. */ return 64; } @@ -1098,25 +1101,79 @@ GMT_get_next_chid (struct MeshTunnel3 *t) } +/** + * Send ACK on one or more channels due to buffer in connections.. + * + * @param t Channel which has some free buffer space. + * @param fwd Is this for FWD traffic? (ACK goes to root) + */ +void +GMT_unchoke_channels (struct MeshTunnel3 *t, int fwd) +{ + struct MeshTChannel *iter; + unsigned int buffer; + unsigned int channels = GMT_count_channels (t); + unsigned int choked_n; + struct MeshChannel *choked[channels]; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_unchoke_channels on %s\n", GMT_2s (t)); + + if (NULL == t) + { + GNUNET_break (0); + return; + } + + /* Get buffer space */ + buffer = GMT_get_buffer (t, fwd); + if (0 == buffer) + { + return; + } + + /* Count and remember choked channels */ + choked_n = 0; + for (iter = t->channel_head; NULL != iter; iter = iter->next) + { + if (GNUNET_NO == GMCH_get_allowed (iter->ch, fwd)) + { + choked[choked_n++] = iter->ch; + } + } + + /* Unchoke random channels */ + while (0 < buffer && 0 < choked_n) + { + unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + choked_n); + GMCH_allow_client (choked[r], fwd); + choked_n--; + buffer--; + choked[r] = choked[choked_n]; + } +} + + /** * Send ACK on one or more connections due to buffer space to the client. * * Iterates all connections of the tunnel and sends ACKs appropriately. * - * @param ch Channel which has some free buffer space. + * @param t Tunnel. * @param fwd Is this in for FWD traffic? (ACK goes dest->root) */ void -GMT_send_acks (struct MeshTunnel3 *t, unsigned int buffer, int fwd) +GMT_send_acks (struct MeshTunnel3 *t, int fwd) { struct MeshTConnection *iter; uint32_t allowed; uint32_t to_allow; uint32_t allow_per_connection; unsigned int cs; + unsigned int buffer; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Tunnel send acks on %s:%X\n", + "Tunnel send %s ACKs on %s\n", fwd ? "FWD" : "BCK", GMT_2s (t)); if (NULL == t) @@ -1131,6 +1188,8 @@ GMT_send_acks (struct MeshTunnel3 *t, unsigned int buffer, int fwd) return; } + buffer = GMT_get_buffer (t, fwd); + /* Count connections, how many messages are already allowed */ cs = GMT_count_connections (t); for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next) diff --git a/src/mesh/gnunet-service-mesh_tunnel.h b/src/mesh/gnunet-service-mesh_tunnel.h index e15d07988..9e32c5d92 100644 --- a/src/mesh/gnunet-service-mesh_tunnel.h +++ b/src/mesh/gnunet-service-mesh_tunnel.h @@ -280,6 +280,8 @@ GMT_get_state (struct MeshTunnel3 *t); /** * Get the total buffer space for a tunnel. + * + * FIXME get a ch parameter in case of loopback tunnels * * @param t Tunnel. * @param fwd Is this for FWD traffic? @@ -309,6 +311,15 @@ GMT_get_destination (struct MeshTunnel3 *t); MESH_ChannelNumber GMT_get_next_chid (struct MeshTunnel3 *t); +/** + * Send ACK on one or more channels due to buffer in connections.. + * + * @param t Channel which has some free buffer space. + * @param fwd Is this for FWD traffic? (ACK goes to root) + */ +void +GMT_unchoke_channels (struct MeshTunnel3 *t, int fwd); + /** * Send ACK on one or more connections due to buffer space to the client. * @@ -318,7 +329,7 @@ GMT_get_next_chid (struct MeshTunnel3 *t); * @param fwd Is this in for FWD traffic? (ACK goes dest->root) */ void -GMT_send_acks (struct MeshTunnel3 *t, unsigned int buffer, int fwd); +GMT_send_acks (struct MeshTunnel3 *t, int fwd); /** * Sends an already built message on a tunnel, encrypting it and -- 2.25.1