X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fgnunet-service-mesh_channel.c;h=05cdeaa2e31906fbf1b96627252687fba211902d;hb=3ab14ab0253aeb1e715caad470e8f308c8243cdf;hp=be4f7d0c071bdd751169fadbf5b9e84edd630fa3;hpb=03b222dc177798ed9448cdeca67ba4051c6397e3;p=oweals%2Fgnunet.git diff --git a/src/mesh/gnunet-service-mesh_channel.c b/src/mesh/gnunet-service-mesh_channel.c index be4f7d0c0..05cdeaa2e 100644 --- a/src/mesh/gnunet-service-mesh_channel.c +++ b/src/mesh/gnunet-service-mesh_channel.c @@ -54,7 +54,7 @@ enum MeshChannelState MESH_CHANNEL_SENT, /** - * Connection confirmed, ready to carry traffic.. + * Connection confirmed, ready to carry traffic. */ MESH_CHANNEL_READY, }; @@ -112,11 +112,6 @@ struct MeshChannelReliability struct MeshReliableMessage *head_sent; struct MeshReliableMessage *tail_sent; - /** - * Messages pending to send. - */ - unsigned int n_sent; - /** * DLL of messages received out of order. */ @@ -143,6 +138,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. */ @@ -274,9 +274,13 @@ extern GNUNET_PEER_Id myid; * timers and frees all memory. * * @param copy Message that is no longer needed: remote peer got it. + * @param update_time Is the timing information relevant? + * If this message is ACK in a batch the timing information + * is skewed by the retransmission, count only for the + * retransmitted message. */ static void -rel_message_free (struct MeshReliableMessage *copy); +rel_message_free (struct MeshReliableMessage *copy, int update_time); /** * We have received a message out of order, or the client is not ready. @@ -303,6 +307,7 @@ add_buffered_data (const struct GNUNET_MESH_Data *msg, copy = GNUNET_malloc (sizeof (*copy) + size); copy->mid = mid; copy->rel = rel; + copy->type = GNUNET_MESSAGE_TYPE_MESH_DATA; memcpy (©[1], msg, size); rel->n_recv++; @@ -325,6 +330,36 @@ add_buffered_data (const struct GNUNET_MESH_Data *msg, LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n"); } +/** + * Add a destination client to a channel, initializing all data structures + * in the channel and the client. + * + * @param ch Channel to which add the destination. + * @param c Client which to add to the channel. + */ +static void +add_destination (struct MeshChannel *ch, struct MeshClient *c) +{ + if (NULL != ch->dest) + { + GNUNET_break (0); + return; + } + + /* Assign local id as destination */ + ch->lid_dest = GML_get_next_chid (c); + + /* Store in client's hashmap */ + GML_channel_add (c, ch->lid_dest, ch); + + GNUNET_break (NULL == ch->dest_rel); + ch->dest_rel = GNUNET_new (struct MeshChannelReliability); + ch->dest_rel->ch = ch; + ch->dest_rel->expected_delay = MESH_RETRANSMIT_TIME; + + ch->dest = c; +} + /** * Send data to a client. @@ -359,32 +394,107 @@ send_client_data (struct MeshChannel *ch, /** - * Add a client to a channel, initializing all needed data structures. + * Send a buffered message to the client, for in order delivery or + * as result of client ACK. * - * @param ch Channel to which add the client. - * @param c Client which to add to the channel. + * @param ch Channel on which to empty the message buffer. + * @param c Client to send to. + * @param fwd Is this to send FWD data?. */ -void -GMCH_add_client (struct MeshChannel *ch, struct MeshClient *c) +static void +send_client_buffered_data (struct MeshChannel *ch, + struct MeshClient *c, + int fwd) { - if (NULL != ch->dest) + struct MeshReliableMessage *copy; + struct MeshChannelReliability *rel; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n"); + rel = fwd ? ch->dest_rel : ch->root_rel; + if (GNUNET_NO == rel->client_ready) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n"); + return; + } + + copy = rel->head_recv; + /* We never buffer channel management messages */ + if (NULL != copy) + { + if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) + { + struct GNUNET_MESH_Data *msg = (struct GNUNET_MESH_Data *) ©[1]; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " have %u! now expecting %u\n", + copy->mid, rel->mid_recv + 1); + send_client_data (ch, msg, fwd); + rel->n_recv--; + rel->mid_recv++; + GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); + GNUNET_free (copy); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + " reliable && don't have %u, next is %u\n", + rel->mid_recv, + copy->mid); + return; + } + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n"); +} + + +/** + * Allow a client to send more data. + * + * In case the client was already allowed to send data, do nothing. + * + * @param ch Channel. + * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root) + */ +static void +send_client_ack (struct MeshChannel *ch, int fwd) +{ + struct MeshChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " sending %s ack to client on channel %s\n", + fwd ? "FWD" : "BCK", GMCH_2s (ch)); + + if (NULL == rel) { GNUNET_break (0); return; } - /* Assign local id as destination */ - ch->lid_dest = GML_get_next_chid (c); + if (GNUNET_YES == rel->client_allowed) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n"); + return; + } + rel->client_allowed = GNUNET_YES; - /* Store in client's hashmap */ - GML_channel_add (c, ch->lid_dest, ch); + GML_send_ack (fwd ? ch->root : ch->dest, fwd ? ch->lid_root : ch->lid_dest); +} - GNUNET_break (NULL == ch->dest_rel); - ch->dest_rel = GNUNET_new (struct MeshChannelReliability); - ch->dest_rel->ch = ch; - ch->dest_rel->expected_delay = MESH_RETRANSMIT_TIME; - ch->dest = c; +/** + * Notify the root that the destination rejected the channel. + * + * @param ch Rejected channel. + */ +static void +send_client_nack (struct MeshChannel *ch) +{ + if (NULL == ch->root) + { + GNUNET_break (0); + return; + } + GML_send_nack (ch->root, ch->lid_root); } @@ -443,7 +553,7 @@ channel_rel_free_sent (struct MeshChannelReliability *rel, bitfield = msg->futures; mid = ntohl (msg->mid); LOG (GNUNET_ERROR_TYPE_DEBUG, - "free_sent_reliable %u %llX\n", + "!!! free_sent_reliable %u %llX\n", mid, bitfield); LOG (GNUNET_ERROR_TYPE_DEBUG, " rel %p, head %p\n", @@ -486,7 +596,7 @@ channel_rel_free_sent (struct MeshChannelReliability *rel, /* Now copy->mid == target, free it */ next = copy->next; - rel_message_free (copy); + rel_message_free (copy, GNUNET_YES); copy = next; } LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n"); @@ -560,6 +670,7 @@ channel_retransmit_message (void *cls, // LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! ALREADY IN QUEUE %u\n", copy->mid); // } + copy->timestamp = GNUNET_TIME_absolute_get(); rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer); rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer, &channel_retransmit_message, @@ -573,27 +684,36 @@ channel_retransmit_message (void *cls, * timers and frees all memory. * * @param copy Message that is no longer needed: remote peer got it. + * @param update_time Is the timing information relevant? + * If this message is ACK in a batch the timing information + * is skewed by the retransmission, count only for the + * retransmitted message. */ static void -rel_message_free (struct MeshReliableMessage *copy) +rel_message_free (struct MeshReliableMessage *copy, int update_time) { struct MeshChannelReliability *rel; struct GNUNET_TIME_Relative time; rel = copy->rel; - time = GNUNET_TIME_absolute_get_duration (copy->timestamp); - 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--; LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " n_sent %u\n", rel->n_sent); - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! took %s\n", - GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! new expected delay %s\n", - GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, - GNUNET_NO)); - rel->retry_timer = rel->expected_delay; + if (update_time) + { + time = GNUNET_TIME_absolute_get_duration (copy->timestamp); + rel->expected_delay.rel_value_us *= 7; + rel->expected_delay.rel_value_us += time.rel_value_us; + rel->expected_delay.rel_value_us /= 8; + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! took %s\n", + GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! new expected delay %s\n", + GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, + GNUNET_NO)); + rel->retry_timer = rel->expected_delay; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! batch free, ignoring timing\n"); + } GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); GNUNET_free (copy); } @@ -603,7 +723,7 @@ rel_message_free (struct MeshReliableMessage *copy) * Confirm we got a channel create. * * @param ch The channel to confirm. - * @param fwd Should we send the ACK fwd? + * @param fwd Should we send a FWD ACK? (going dest->root) */ static void channel_send_ack (struct MeshChannel *ch, int fwd) @@ -621,11 +741,32 @@ channel_send_ack (struct MeshChannel *ch, int fwd) } +/** + * Notify that a channel create didn't succeed. + * + * @param ch The channel to reject. + */ +static void +channel_send_nack (struct MeshChannel *ch) +{ + struct GNUNET_MESH_ChannelManage msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_NACK); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " sending channel NACK for channel %s\n", + GMCH_2s (ch)); + + msg.chid = htonl (ch->gid); + GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO); +} + + /** * Channel was ACK'd by remote peer, mark as ready and cancel retransmission. * * @param ch Channel to mark as ready. - * @param fwd Was the CREATE message sent fwd? + * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK) */ static void channel_confirm (struct MeshChannel *ch, int fwd) @@ -640,6 +781,7 @@ channel_confirm (struct MeshChannel *ch, int fwd) ch->state = MESH_CHANNEL_READY; rel = fwd ? ch->root_rel : ch->dest_rel; + rel->client_ready = GNUNET_YES; for (copy = rel->head_sent; NULL != copy; copy = next) { struct GNUNET_MessageHeader *msg; @@ -648,11 +790,15 @@ channel_confirm (struct MeshChannel *ch, int fwd) msg = (struct GNUNET_MessageHeader *) ©[1]; if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE) { - rel_message_free (copy); + rel_message_free (copy, GNUNET_YES); /* TODO return? */ } } - channel_send_ack (ch, fwd); + send_client_ack (ch, fwd); + + /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */ + if (fwd) + channel_send_ack (ch, !fwd); } @@ -677,19 +823,18 @@ channel_save_copy (struct MeshChannel *ch, uint16_t size; rel = fwd ? ch->root_rel : ch->dest_rel; - mid = rel->mid_send; + mid = rel->mid_send - 1; type = ntohs (msg->type); size = ntohs (msg->size); - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u\n", mid); + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u %s\n", + mid, GNUNET_MESH_DEBUG_M2S (type)); copy = GNUNET_malloc (sizeof (struct MeshReliableMessage) + size); copy->mid = mid; copy->timestamp = GNUNET_TIME_absolute_get (); copy->rel = rel; copy->type = type; memcpy (©[1], msg, size); - rel->n_sent++; - LOG (GNUNET_ERROR_TYPE_DEBUG, " n_sent %u\n", rel->n_sent); GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy); if (GNUNET_SCHEDULER_NO_TASK == rel->retry_task) { @@ -704,63 +849,6 @@ channel_save_copy (struct MeshChannel *ch, } - -/** - * 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. - * @param fwd Is this to send FWD data?. - */ -static void -send_client_buffered_data (struct MeshChannel *ch, - struct MeshClient *c, - int fwd) -{ - struct MeshReliableMessage *copy; - struct MeshChannelReliability *rel; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n"); - rel = fwd ? ch->dest_rel : ch->root_rel; - if (GNUNET_NO == rel->client_ready) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n"); - return; - } - - copy = rel->head_recv; - /* We never buffer channel management messages */ - if (NULL != copy) - { - if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) - { - struct GNUNET_MESH_Data *msg = (struct GNUNET_MESH_Data *) ©[1]; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " have %u! now expecting %u\n", - copy->mid, rel->mid_recv + 1); - send_client_data (ch, msg, fwd); - rel->n_recv--; - rel->mid_recv++; - GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); - GNUNET_free (copy); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - " reliable && don't have %u, next is %u\n", - rel->mid_recv, - copy->mid); - return; - } - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n"); -} - - - - /** * Destroy a channel and free all resources. * @@ -811,7 +899,8 @@ channel_destroy (struct MeshChannel *ch) */ static struct MeshChannel * channel_new (struct MeshTunnel3 *t, - struct MeshClient *owner, MESH_ChannelNumber lid_root) + struct MeshClient *owner, + MESH_ChannelNumber lid_root) { struct MeshChannel *ch; @@ -848,6 +937,15 @@ channel_set_options (struct MeshChannel *ch, uint32_t options) GNUNET_YES : GNUNET_NO; } +static int +is_loopback (const struct MeshChannel *ch) +{ + if (NULL != ch->t) + return GMT_is_loopback (ch->t); + + return (NULL != ch->root && NULL != ch->dest); +} + /** * Handle a loopback message: call the appropriate handler for the message type. @@ -865,8 +963,8 @@ handle_loopback (struct MeshChannel *ch, type = ntohs (msgh->type); LOG (GNUNET_ERROR_TYPE_DEBUG, - "Loopback %s message!\n", - GNUNET_MESH_DEBUG_M2S (type)); + "Loopback %s %s message!\n", + fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (type)); switch (type) { @@ -880,9 +978,8 @@ handle_loopback (struct MeshChannel *ch, break; case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE: - // FIXME store channel in loopback tunnel? - GMCH_handle_create ((struct GNUNET_MESH_ChannelCreate *) msgh, - fwd); + GMCH_handle_create (ch->t, + (struct GNUNET_MESH_ChannelCreate *) msgh); break; case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK: @@ -891,6 +988,10 @@ handle_loopback (struct MeshChannel *ch, fwd); break; + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_NACK: + GMCH_handle_nack (ch); + break; + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: GMCH_handle_destroy (ch, (struct GNUNET_MESH_ChannelManage *) msgh, @@ -911,6 +1012,7 @@ handle_loopback (struct MeshChannel *ch, /******************************** API ***********************************/ /******************************************************************************/ + /** * Get channel ID. * @@ -965,13 +1067,32 @@ 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? * * @param ch Channel. * @param fwd Is this for fwd traffic? * - * @return GNUNET_YES in case it is. + * @return #GNUNET_YES in case it is. */ int GMCH_is_origin (struct MeshChannel *ch, int fwd) @@ -989,7 +1110,7 @@ GMCH_is_origin (struct MeshChannel *ch, int fwd) * @param ch Channel. * @param fwd Is this for fwd traffic? * - * @return GNUNET_YES in case it is. + * @return #GNUNET_YES in case it is. */ int GMCH_is_terminal (struct MeshChannel *ch, int fwd) @@ -1024,18 +1145,32 @@ GMCH_send_create (struct MeshChannel *ch) /** * Notify a client that the channel is no longer valid. - * FIXME send on tunnel if some client == NULL? * * @param ch Channel that is destroyed. */ void GMCH_send_destroy (struct MeshChannel *ch) { + struct GNUNET_MESH_ChannelManage msg; + + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY); + msg.header.size = htons (sizeof (msg)); + msg.chid = htonl (ch->gid); + + /* If root is not NULL, notify. + * If it's NULL, check lid_root. When a local destroy comes in, root + * is set to NULL but lid_root is left untouched. In this case, do nothing, + * the client is the one who reuqested the channel to be destroyed. + */ if (NULL != ch->root) GML_send_channel_destroy (ch->root, ch->lid_root); + else if (0 == ch->lid_root) + GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO); if (NULL != ch->dest) GML_send_channel_destroy (ch->dest, ch->lid_dest); + else if (0 == ch->lid_dest) + GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES); } @@ -1083,43 +1218,94 @@ GMCH_send_data_ack (struct MeshChannel *ch, int fwd) struct MeshReliableMessage *copy; unsigned int delta; uint64_t mask; - uint16_t type; + uint32_t ack; if (GNUNET_NO == ch->reliable) { return; } rel = fwd ? ch->dest_rel : ch->root_rel; + ack = rel->mid_recv - 1; LOG (GNUNET_ERROR_TYPE_DEBUG, - "send_data_ack for %u\n", - rel->mid_recv - 1); + " !! Send DATA_ACK for %u\n", + ack); - type = GNUNET_MESSAGE_TYPE_MESH_DATA_ACK; - msg.header.type = htons (type); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_DATA_ACK); msg.header.size = htons (sizeof (msg)); msg.chid = htonl (ch->gid); - msg.mid = htonl (rel->mid_recv - 1); msg.futures = 0; for (copy = rel->head_recv; NULL != copy; copy = copy->next) { - if (copy->type != type) + if (copy->type != GNUNET_MESSAGE_TYPE_MESH_DATA) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "!! Type %s, expected DATA\n", + GNUNET_MESH_DEBUG_M2S (copy->type)); continue; - delta = copy->mid - rel->mid_recv; + } + if (copy->mid == ack + 1) + { + ack++; + continue; + } + delta = copy->mid - (ack + 1); if (63 < delta) break; mask = 0x1LL << delta; msg.futures |= mask; LOG (GNUNET_ERROR_TYPE_DEBUG, - " setting bit for %u (delta %u) (%llX) -> %llX\n", - copy->mid, delta, mask, msg.futures); + " !! setting bit for %u (delta %u) (%llX) -> %llX\n", + copy->mid, delta, mask, msg.futures); } - LOG (GNUNET_ERROR_TYPE_DEBUG, " final futures %llX\n", msg.futures); + msg.mid = htonl (ack); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "!!! ACK for %u, futures %llX\n", + ack, msg.futures); - GMCH_send_prebuilt_message (&msg.header, ch, fwd); + GMCH_send_prebuilt_message (&msg.header, ch, !fwd); LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n"); } +/** + * 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) +{ + struct MeshChannelReliability *rel; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n"); + + if (MESH_CHANNEL_READY != ch->state) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " not ready yet!\n"); + return; + } + + if (GNUNET_YES == ch->reliable) + { + rel = fwd ? ch->root_rel : ch->dest_rel; + if (NULL == rel) + { + GNUNET_break (0); + return; + } + if (NULL != rel->head_sent && 64 <= rel->mid_send - rel->head_sent->mid) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + " too big mid gap! Wait for ACK.\n"); + return; + } + } + + send_client_ack (ch, fwd); +} + + /** * Log channel info. * @@ -1162,7 +1348,7 @@ GMCH_debug (struct MeshChannel *ch) * Mark client as ready and send him any buffered data we could have for him. * * @param ch Channel. - * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK) + * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK) */ void GMCH_handle_local_ack (struct MeshChannel *ch, int fwd) @@ -1175,7 +1361,17 @@ 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); + if (is_loopback (ch)) + { + unsigned int buffer; + + buffer = GMCH_get_buffer (ch, fwd); + if (0 < buffer) + GMCH_allow_client (ch, fwd); + + return; + } + GMT_send_connection_acks (ch->t); } @@ -1187,6 +1383,8 @@ GMCH_handle_local_ack (struct MeshChannel *ch, int fwd) * in the tunnel. * * @param ch Channel. + * @param c Client which sent the data. + * @param message Message. * @param fwd Is this a FWD data? * * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error. @@ -1210,12 +1408,20 @@ GMCH_handle_local_data (struct MeshChannel *ch, (!fwd && ch->dest == c) ) ) { - GNUNET_break (0); + GNUNET_break_op (0); return GNUNET_SYSERR; } rel = fwd ? ch->root_rel : ch->dest_rel; + if (GNUNET_NO == rel->client_allowed) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + rel->client_allowed = GNUNET_NO; + /* Ok, everything is correct, send the message. */ payload = (struct GNUNET_MESH_Data *) cbuf; payload->mid = htonl (rel->mid_send); @@ -1225,12 +1431,22 @@ GMCH_handle_local_data (struct MeshChannel *ch, payload->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_DATA); payload->chid = htonl (ch->gid); LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n"); - GMCH_send_prebuilt_message (&payload->header, ch, fwd); - if (GNUNET_YES == ch->reliable) channel_save_copy (ch, &payload->header, fwd); - if (GMT_get_buffer (ch->t, fwd) > 0) - GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest); + GMCH_send_prebuilt_message (&payload->header, ch, fwd); + + if (is_loopback (ch)) + { + if (GMCH_get_buffer (ch, fwd) > 0); + send_client_ack (ch, fwd); + + return GNUNET_OK; + } + + if (GMT_get_connections_buffer (ch->t) > 0) + { + send_client_ack (ch, fwd); + } return GNUNET_OK; } @@ -1329,8 +1545,7 @@ GMCH_handle_local_create (struct MeshClient *c, ch->root_rel->ch = ch; ch->root_rel->expected_delay = MESH_RETRANSMIT_TIME; - LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s[%x]:%u (%x)\n", - GMT_2s (t), ch->gid, ch->port, ch->lid_root); + LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch)); /* Send create channel */ { @@ -1342,17 +1557,21 @@ GMCH_handle_local_create (struct MeshClient *c, msgcc.port = msg->port; msgcc.opt = msg->opt; - GMT_queue_data (t, ch, &msgcc.header, GNUNET_YES); + GMT_send_prebuilt_message (&msgcc.header, t, ch, GNUNET_YES); } return GNUNET_OK; } + /** * Handler for mesh network payload traffic. * * @param ch Channel for the message. - * @param message Unencryted data message. - * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO; + * @param msg Unencryted data message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) */ void GMCH_handle_data (struct MeshChannel *ch, @@ -1363,6 +1582,18 @@ GMCH_handle_data (struct MeshChannel *ch, struct MeshClient *c; uint32_t mid; + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; + } + /* Initialize FWD/BCK data */ c = fwd ? ch->dest : ch->root; rel = fwd ? ch->dest_rel : ch->root_rel; @@ -1376,7 +1607,7 @@ GMCH_handle_data (struct MeshChannel *ch, GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO); mid = ntohl (msg->mid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " mid %u\n", mid); + LOG (GNUNET_ERROR_TYPE_DEBUG, "!! got mid %u\n", mid); if (GNUNET_NO == ch->reliable || ( !GMC_is_pid_bigger (rel->mid_recv, mid) && @@ -1411,7 +1642,7 @@ GMCH_handle_data (struct MeshChannel *ch, GNUNET_break_op (0); LOG (GNUNET_ERROR_TYPE_DEBUG, " MID %u not expected (%u - %u), dropping!\n", - mid, rel->mid_recv, rel->mid_recv + 64); + mid, rel->mid_recv, rel->mid_recv + 63); } GMCH_send_data_ack (ch, fwd); @@ -1421,9 +1652,12 @@ GMCH_handle_data (struct MeshChannel *ch, /** * 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) + * @param ch Channel on which we got this message. + * @param msg Data message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) */ void GMCH_handle_data_ack (struct MeshChannel *ch, @@ -1436,9 +1670,22 @@ GMCH_handle_data_ack (struct MeshChannel *ch, uint32_t ack; int work; + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + /* Inverted: if message came 'FWD' is a 'BCK ACK'. */ + fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES; + } + ack = ntohl (msg->mid); LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! %s ACK %u\n", - (GNUNET_YES == fwd) ? "FWD" : "BCK", ack); + (GNUNET_YES == fwd) ? "FWD" : "BCK", ack); if (GNUNET_YES == fwd) { @@ -1450,10 +1697,11 @@ GMCH_handle_data_ack (struct MeshChannel *ch, } if (NULL == rel) { - GNUNET_break (0); + GNUNET_break_op (0); return; } + /* Free ACK'd copies: no need to retransmit those anymore */ for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next) { if (GMC_is_pid_bigger (copy->mid, ack)) @@ -1463,14 +1711,15 @@ GMCH_handle_data_ack (struct MeshChannel *ch, break; } work = GNUNET_YES; - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! id %u\n", copy->mid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " !! id %u\n", copy->mid); next = copy->next; - rel_message_free (copy); + rel_message_free (copy, GNUNET_YES); } + /* ACK client if needed */ -// channel_send_ack (t, type, GNUNET_MESSAGE_TYPE_MESH_UNICAST_ACK == type); + GMCH_allow_client (ch, fwd); - /* If some message was free'd, update the retransmission delay*/ + /* If some message was free'd, update the retransmission delay */ if (GNUNET_YES == work) { if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task) @@ -1505,12 +1754,14 @@ GMCH_handle_data_ack (struct MeshChannel *ch, /** * Handler for channel create messages. * - * @param msg Message. - * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO; + * Does not have fwd parameter because it's always 'FWD': channel is incoming. + * + * @param t Tunnel this channel will be in. + * @param msg Channel crate message. */ struct MeshChannel * -GMCH_handle_create (const struct GNUNET_MESH_ChannelCreate *msg, - int fwd) +GMCH_handle_create (struct MeshTunnel3 *t, + const struct GNUNET_MESH_ChannelCreate *msg) { MESH_ChannelNumber chid; struct MeshChannel *ch; @@ -1519,9 +1770,13 @@ GMCH_handle_create (const struct GNUNET_MESH_ChannelCreate *msg, chid = ntohl (msg->chid); - /* Create channel */ - ch = channel_new (NULL, NULL, 0); /* FIXME pass t */ - ch->gid = chid; + ch = GMT_get_channel (t, chid); + if (NULL == ch) + { + /* Create channel */ + ch = channel_new (t, NULL, 0); + ch->gid = chid; + } channel_set_options (ch, ntohl (msg->opt)); /* Find a destination client */ @@ -1532,40 +1787,79 @@ GMCH_handle_create (const struct GNUNET_MESH_ChannelCreate *msg, { /* TODO send reject */ LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n"); - channel_destroy (ch); + if (is_loopback (ch)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback: destroy on handler\n"); + channel_send_nack (ch); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " not loopback: destroy now\n"); + channel_send_nack (ch); + channel_destroy (ch); + } return NULL; } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c); + } - GMCH_add_client (ch, c); + add_destination (ch, c); if (GNUNET_YES == ch->reliable) LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n"); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Not Reliable\n"); GMCH_send_create (ch); - GMCH_send_data_ack (ch, fwd); - channel_send_ack (ch, !fwd); - - if (GNUNET_NO == ch->dest_rel->client_ready) - { - GML_send_ack (ch->dest, ch->lid_dest); - ch->dest_rel->client_ready = GNUNET_YES; - } + channel_send_ack (ch, GNUNET_YES); return ch; } +/** + * Handler for channel NACK messages. + * + * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. + * + * @param ch Channel. + */ +void +GMCH_handle_nack (struct MeshChannel *ch) +{ + send_client_nack (ch); + channel_destroy (ch); +} + + /** * Handler for channel ack messages. * * @param ch Channel. * @param msg Message. - * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO; + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) */ void GMCH_handle_ack (struct MeshChannel *ch, const struct GNUNET_MESH_ChannelManage *msg, int fwd) { + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; + } + channel_confirm (ch, !fwd); } @@ -1575,7 +1869,10 @@ GMCH_handle_ack (struct MeshChannel *ch, * * @param ch Channel to be destroyed of. * @param msg Message. - * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO; + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) */ void GMCH_handle_destroy (struct MeshChannel *ch, @@ -1584,6 +1881,18 @@ GMCH_handle_destroy (struct MeshChannel *ch, { struct MeshTunnel3 *t; + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; + } + GMCH_debug (ch); if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) ) { @@ -1617,10 +1926,9 @@ void GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, struct MeshChannel *ch, int fwd) { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Send on Channel %s:%X %s\n", - GMT_2s (ch->t), ch->gid, fwd ? "FWD" : "BCK"); - LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", - GNUNET_MESH_DEBUG_M2S (ntohs (message->type))); + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH Send %s %s on channel %s\n", + fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (ntohs (message->type)), + GMCH_2s (ch)); if (GMT_is_loopback (ch->t)) {