X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fgnunet-service-mesh_tunnel.c;h=f192bb05b5ac49cc6a30c603164bff95c882721c;hb=a107ae89650629fb1d6981bff567ebbdae3dcb8b;hp=1b4e717cabf3aa8410a1635ae2fc0086172190e0;hpb=98f57354c839ba6a8b76aaaf7301edc75b712c43;p=oweals%2Fgnunet.git diff --git a/src/mesh/gnunet-service-mesh_tunnel.c b/src/mesh/gnunet-service-mesh_tunnel.c index 1b4e717ca..f192bb05b 100644 --- a/src/mesh/gnunet-service-mesh_tunnel.c +++ b/src/mesh/gnunet-service-mesh_tunnel.c @@ -82,9 +82,14 @@ struct MeshTunnel3 struct MeshPeer *peer; /** - * State of the tunnel. + * State of the tunnel connectivity. */ - enum MeshTunnel3State state; + enum MeshTunnel3CState cstate; + + /** + * State of the tunnel encryption. + */ + enum MeshTunnel3EState estate; /** * Key eXchange context. @@ -153,9 +158,14 @@ struct MeshTunnelDelayed struct MeshTunnelDelayed *prev; /** - * Channel. + * Tunnel. */ - struct MeshChannel *ch; + struct MeshTunnel3 *t; + + /** + * Tunnel queue given to the channel to cancel request. Update on send_queued. + */ + struct MeshTunnel3Queue *tq; /** * Message to send. @@ -172,7 +182,12 @@ struct MeshTunnel3Queue /** * Connection queue handle, to cancel if necessary. */ - struct MeshConnectionQueue *q; + struct MeshConnectionQueue *cq; + + /** + * Handle in case message hasn't been given to a connection yet. + */ + struct MeshTunnelDelayed *tqd; /** * Continuation to call once sent. @@ -247,18 +262,18 @@ static struct GNUNET_TIME_Relative rekey_period; /******************************************************************************/ /** - * Get string description for tunnel state. + * Get string description for tunnel connectivity state. * - * @param s Tunnel state. + * @param cs Tunnel state. * * @return String representation. */ static const char * -GMT_state2s (enum MeshTunnel3State s) +cstate2s (enum MeshTunnel3CState cs) { static char buf[128]; - switch (s) + switch (cs) { case MESH_TUNNEL3_NEW: return "MESH_TUNNEL3_NEW"; @@ -266,19 +281,65 @@ GMT_state2s (enum MeshTunnel3State s) return "MESH_TUNNEL3_SEARCHING"; case MESH_TUNNEL3_WAITING: return "MESH_TUNNEL3_WAITING"; - case MESH_TUNNEL3_KEY_SENT: - return "MESH_TUNNEL3_KEY_SENT"; case MESH_TUNNEL3_READY: return "MESH_TUNNEL3_READY"; - case MESH_TUNNEL3_RECONNECTING: - return "MESH_TUNNEL3_RECONNECTING"; - case MESH_TUNNEL3_REKEY: - return "MESH_TUNNEL3_REKEY"; default: - sprintf (buf, "%u (UNKNOWN STATE)", s); + sprintf (buf, "%u (UNKNOWN STATE)", cs); return buf; } + return ""; +} + + +/** + * Get string description for tunnel encryption state. + * + * @param es Tunnel state. + * + * @return String representation. + */ +static const char * +estate2s (enum MeshTunnel3EState es) +{ + static char buf[128]; + + switch (es) + { + case MESH_TUNNEL3_KEY_UNINITIALIZED: + return "MESH_TUNNEL3_KEY_UNINITIALIZED"; + case MESH_TUNNEL3_KEY_SENT: + return "MESH_TUNNEL3_KEY_SENT"; + case MESH_TUNNEL3_KEY_PING: + return "MESH_TUNNEL3_KEY_PING"; + case MESH_TUNNEL3_KEY_OK: + return "MESH_TUNNEL3_KEY_OK"; + + default: + sprintf (buf, "%u (UNKNOWN STATE)", es); + return buf; + } + return ""; +} + + +/** + * @brief Check if tunnel is ready to send traffic. + * + * Tunnel must be connected and with encryption correctly set up. + * + * @param t Tunnel to check. + * + * @return #GNUNET_YES if ready, #GNUNET_NO otherwise + */ +static int +is_ready (struct MeshTunnel3 *t) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, " ready: cs=%s, es=%s\n", + cstate2s (t->cstate), estate2s (t->estate)); + return (MESH_TUNNEL3_READY == t->cstate + && MESH_TUNNEL3_KEY_OK == t->estate) + || GMT_is_loopback (t); } @@ -395,7 +456,7 @@ get_connection_allowed (const struct MeshTConnection *tc) * @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise. */ int -check_ephemeral (struct MeshTunnel3 *t, +check_ephemeral (struct MeshTunnel3 *t, const struct GNUNET_MESH_KX_Ephemeral *msg) { /* Check message size */ @@ -531,7 +592,7 @@ tunnel_get_connection (struct MeshTunnel3 *t) for (iter = t->connection_head; NULL != iter; iter = iter->next) { LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n", - GNUNET_h2s (GMC_get_id (iter->c)), GMC_get_state (iter->c)); + GMC_2s (iter->c), GMC_get_state (iter->c)); if (MESH_CONNECTION_READY == GMC_get_state (iter->c)) { qn = GMC_get_qn (iter->c, GMC_is_origin (iter->c, GNUNET_YES)); @@ -543,84 +604,235 @@ tunnel_get_connection (struct MeshTunnel3 *t) } } } + LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GMC_2s (best)); return best; } /** - * Send all cached messages that we can, tunnel is online. + * Callback called when a queued message is sent. * - * @param t Tunnel that holds the messages. Cannot be loopback. + * Calculates the average time and connection packet tracking. + * + * @param cls Closure (TunnelQueue handle). + * @param c Connection this message was on. + * @param q Connection queue handle (unused). + * @param type Type of message sent. + * @param fwd Was this a FWD going message? + * @param size Size of the message. */ static void -send_queued_data (struct MeshTunnel3 *t) +message_sent (void *cls, + struct MeshConnection *c, + struct MeshConnectionQueue *q, + uint16_t type, int fwd, size_t size) { - struct MeshTunnelDelayed *tq; - struct MeshTunnelDelayed *next; - unsigned int room; + struct MeshTunnel3Queue *qt = cls; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "GMT_send_queued_data on tunnel %s\n", - GMT_2s (t)); + GNUNET_assert (NULL != qt->cont); + qt->cont (qt->cont_cls, GMC_get_tunnel (c), qt, type, size); + GNUNET_free (qt); +} - if (GMT_is_loopback (t)) + +/** + * Delete a queued message: either was sent or the channel was destroyed + * before the tunnel's key exchange had a chance to finish. + * + * @param tq Queue handle. + */ +static void +unqueue_data (struct MeshTunnelDelayed *tq) +{ + GNUNET_CONTAINER_DLL_remove (tq->t->tq_head, tq->t->tq_tail, tq); + GNUNET_free (tq); +} + + +/** + * Cache a message to be sent once tunnel is online. + * + * @param t Tunnel to hold the message. + * @param msg Message itself (copy will be made). + */ +static struct MeshTunnelDelayed * +queue_data (struct MeshTunnel3 *t, const struct GNUNET_MessageHeader *msg) +{ + struct MeshTunnelDelayed *tqd; + uint16_t size = ntohs (msg->size); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GMT_2s (t)); + + if (GNUNET_YES == is_ready (t)) { GNUNET_break (0); - return; + return NULL; } - room = GMT_get_connections_buffer (t); - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); - for (tq = t->tq_head; NULL != tq && room > 0; tq = next) + tqd = GNUNET_malloc (sizeof (struct MeshTunnelDelayed) + size); + + tqd->t = t; + memcpy (&tqd[1], msg, size); + GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd); + return tqd; +} + + + +/** + * Sends an already built message on a tunnel, encrypting it and + * choosing the best connection. + * + * @param message Message to send. Function modifies it. + * @param t Tunnel on which this message is transmitted. + * @param force Force the tunnel to take the message (buffer overfill). + * @param cont Continuation to call once message is really sent. + * @param cont_cls Closure for @c cont. + * @param existing_q In case this a transmission of previously queued data, + * this should be TunnelQueue given to the client. + * Otherwise, NULL. + * + * @return Handle to cancel message. NULL if @c cont is NULL. + */ +static struct MeshTunnel3Queue * +send_prebuilt_message (const struct GNUNET_MessageHeader *message, + struct MeshTunnel3 *t, int force, + GMT_sent cont, void *cont_cls, + struct MeshTunnel3Queue *existing_q) +{ + struct MeshTunnel3Queue *tq; + struct MeshConnection *c; + struct GNUNET_MESH_Encrypted *msg; + size_t size = ntohs (message->size); + char cbuf[sizeof (struct GNUNET_MESH_Encrypted) + size]; + uint32_t iv; + uint16_t type; + int fwd; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t)); + + if (GNUNET_NO == is_ready (t)) { - LOG (GNUNET_ERROR_TYPE_DEBUG, " data on channel %s\n", GMCH_2s (tq->ch)); - next = tq->next; - room--; - GNUNET_CONTAINER_DLL_remove (t->tq_head, t->tq_tail, tq); - GMCH_send_prebuilt_message ((struct GNUNET_MessageHeader *) &tq[1], - tq->ch, GMCH_is_origin (tq->ch, GNUNET_YES), - GNUNET_NO); + struct MeshTunnelDelayed *tqd; + /* A non null existing_q indicates sending of queued data. + * Should only happen after tunnel becomes ready. + */ + GNUNET_assert (NULL == existing_q); + tqd = queue_data (t, message); + if (NULL == cont) + return NULL; + tq = GNUNET_new (struct MeshTunnel3Queue); + tq->tqd = tqd; + tqd->tq = tq; + tq->cont = cont; + tq->cont_cls = cont_cls; + return tq; + } + + GNUNET_assert (GNUNET_NO == GMT_is_loopback (t)); - GNUNET_free (tq); + iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + msg = (struct GNUNET_MESH_Encrypted *) cbuf; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED); + msg->iv = iv; + GNUNET_assert (t_encrypt (t, &msg[1], message, size, iv) == size); + msg->header.size = htons (sizeof (struct GNUNET_MESH_Encrypted) + size); + c = tunnel_get_connection (t); + if (NULL == c) + { + GNUNET_break (GNUNET_YES == t->destroy); + return NULL; } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "GMT_send_queued_data end\n", - GMP_2s (t->peer)); -} + type = ntohs (message->type); + switch (type) + { + case GNUNET_MESSAGE_TYPE_MESH_DATA: + case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK: + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE: + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK: + msg->cid = *GMC_get_id (c); + msg->ttl = htonl (default_ttl); + break; + default: + LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n", + GM_m2s (type)); + GNUNET_break (0); + } + + fwd = GMC_is_origin (c, GNUNET_YES); + if (NULL == cont) + { + (void) GMC_send_prebuilt_message (&msg->header, c, fwd, force, NULL, NULL); + return NULL; + } + if (NULL == existing_q) + { + tq = GNUNET_new (struct MeshTunnel3Queue); /* FIXME valgrind: leak*/ + } + else + { + tq = existing_q; + tq->tqd = NULL; + } + tq->cq = GMC_send_prebuilt_message (&msg->header, c, fwd, force, + &message_sent, tq); + tq->cont = cont; + tq->cont_cls = cont_cls; + return tq; +} /** - * Cache a message to be sent once tunnel is online. + * Send all cached messages that we can, tunnel is online. * - * @param t Tunnel to hold the message. - * @param ch Channel the message is about. - * @param msg Message itself (copy will be made). + * @param t Tunnel that holds the messages. Cannot be loopback. */ static void -queue_data (struct MeshTunnel3 *t, - struct MeshChannel *ch, - const struct GNUNET_MessageHeader *msg) +send_queued_data (struct MeshTunnel3 *t) { - struct MeshTunnelDelayed *tq; - uint16_t size = ntohs (msg->size); + struct MeshTunnelDelayed *tqd; + struct MeshTunnelDelayed *next; + unsigned int room; - if (MESH_TUNNEL3_READY == t->state) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GMT_send_queued_data on tunnel %s\n", + GMT_2s (t)); + + if (GMT_is_loopback (t)) { GNUNET_break (0); return; } - tq = GNUNET_malloc (sizeof (struct MeshTunnelDelayed) + size); + if (GNUNET_NO == is_ready (t)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " not ready yet: %s/%s\n", + estate2s (t->estate), cstate2s (t->cstate)); + return; + } - tq->ch = ch; - memcpy (&tq[1], msg, size); - GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tq); + room = GMT_get_connections_buffer (t); + LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); + LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head); + for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n"); + next = tqd->next; + room--; + send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1], + tqd->t, GNUNET_YES, + NULL != tqd->tq ? tqd->tq->cont : NULL, + NULL != tqd->tq ? tqd->tq->cont_cls : NULL, + tqd->tq); + unqueue_data (tqd); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_send_queued_data end\n", GMP_2s (t->peer)); } - /** * Sends key exchange message on a tunnel, choosing the best connection. * Should not be called on loopback tunnels. @@ -652,7 +864,7 @@ send_kx (struct MeshTunnel3 *t, /* Must have a connection. */ if (NULL == t->connection_head) { - GNUNET_break (0); + GNUNET_break (MESH_TUNNEL3_SEARCHING == t->cstate); return; } @@ -662,7 +874,7 @@ send_kx (struct MeshTunnel3 *t, c = tunnel_get_connection (t); if (NULL == c) { - GNUNET_break (GNUNET_YES == t->destroy); + GNUNET_break (GNUNET_YES == t->destroy || MESH_TUNNEL3_READY != t->cstate); return; } type = ntohs (message->type); @@ -676,13 +888,13 @@ send_kx (struct MeshTunnel3 *t, break; default: LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n", - GNUNET_MESH_DEBUG_M2S (type)); + GM_m2s (type)); GNUNET_break (0); } fwd = GMC_is_origin (t->connection_head->c, GNUNET_YES); /* TODO save handle and cancel in case of a unneeded retransmission */ - GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL); + GMC_send_prebuilt_message (&msg->header, c, fwd, GNUNET_YES, NULL, NULL); } @@ -696,7 +908,7 @@ send_ephemeral (struct MeshTunnel3 *t) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __FUNCTION__); - kx_msg.sender_status = htonl (t->state); + kx_msg.sender_status = htonl (t->estate); send_kx (t, &kx_msg.header); } @@ -777,18 +989,20 @@ rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) t->kx_ctx->d_key_old = t->d_key; } send_ephemeral (t); - if (MESH_TUNNEL3_READY == t->state || MESH_TUNNEL3_REKEY == t->state) - { - send_ping (t); - t->state = MESH_TUNNEL3_REKEY; - } - else if (MESH_TUNNEL3_WAITING == t->state) + switch (t->estate) { - t->state = MESH_TUNNEL3_KEY_SENT; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->state); + case MESH_TUNNEL3_KEY_UNINITIALIZED: + t->estate = MESH_TUNNEL3_KEY_SENT; + break; + case MESH_TUNNEL3_KEY_SENT: + break; + case MESH_TUNNEL3_KEY_PING: + case MESH_TUNNEL3_KEY_OK: + send_ping (t); + t->estate = MESH_TUNNEL3_KEY_PING; + break; + default: + LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->estate); } LOG (GNUNET_ERROR_TYPE_DEBUG, " next call in %s\n", @@ -866,6 +1080,27 @@ rekey (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } +/** + * Called only on shutdown, destroy every tunnel. + * + * @param cls Closure (unused). + * @param key Current public key. + * @param value Value in the hash map (tunnel). + * + * @return #GNUNET_YES, so we should continue to iterate, + */ +static int +destroy_iterator (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct MeshTunnel3 *t = value; + + GMT_destroy (t); + return GNUNET_YES; +} + + /** * Demultiplex data per channel and call appropriate channel handler. * @@ -882,7 +1117,6 @@ handle_data (struct MeshTunnel3 *t, int fwd) { struct MeshChannel *ch; - uint16_t type; size_t size; /* Check size */ @@ -894,11 +1128,8 @@ handle_data (struct MeshTunnel3 *t, GNUNET_break (0); return; } - type = ntohs (msg->header.type); - LOG (GNUNET_ERROR_TYPE_DEBUG, "got a %s message\n", - GNUNET_MESH_DEBUG_M2S (type)); LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", - GNUNET_MESH_DEBUG_M2S (ntohs (msg[1].header.type))); + GM_m2s (ntohs (msg[1].header.type))); /* Check channel */ ch = GMT_get_channel (t, ntohl (msg->chid)); @@ -911,7 +1142,6 @@ handle_data (struct MeshTunnel3 *t, return; } - GMT_change_state (t, MESH_TUNNEL3_READY); GMCH_handle_data (ch, msg, fwd); } @@ -1133,11 +1363,11 @@ handle_ephemeral (struct MeshTunnel3 *t, LOG (GNUNET_ERROR_TYPE_DEBUG, " km is %s\n", GNUNET_h2s (&km)); derive_symmertic (&t->e_key, &my_full_id, GMP_get_id (t->peer), &km); derive_symmertic (&t->d_key, GMP_get_id (t->peer), &my_full_id, &km); - if (MESH_TUNNEL3_KEY_SENT == t->state) + if (MESH_TUNNEL3_KEY_SENT == t->estate) { LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, send ping\n"); send_ping (t); - t->state = MESH_TUNNEL3_REKEY; + t->estate = MESH_TUNNEL3_KEY_PING; } } @@ -1211,8 +1441,7 @@ handle_pong (struct MeshTunnel3 *t, t->rekey_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_free (t->kx_ctx); t->kx_ctx = NULL; - t->state = MESH_TUNNEL3_READY; - send_queued_data (t); + GMT_change_estate (t, MESH_TUNNEL3_KEY_OK); } @@ -1237,7 +1466,7 @@ handle_decrypted (struct MeshTunnel3 *t, type = ntohs (msgh->type); LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a %s message!\n", - GNUNET_MESH_DEBUG_M2S (type)); + GM_m2s (type)); switch (type) { @@ -1397,6 +1626,7 @@ GMT_shutdown (void) GNUNET_SCHEDULER_cancel (rekey_task); rekey_task = GNUNET_SCHEDULER_NO_TASK; } + GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL); GNUNET_CONTAINER_multipeermap_destroy (tunnels); } @@ -1428,42 +1658,71 @@ GMT_new (struct MeshPeer *destination) /** - * Change the tunnel state. + * Change the tunnel's connection state. * - * @param t Tunnel whose state to change. - * @param state New state. + * @param t Tunnel whose connection state to change. + * @param cstate New connection state. */ void -GMT_change_state (struct MeshTunnel3* t, enum MeshTunnel3State state) +GMT_change_cstate (struct MeshTunnel3* t, enum MeshTunnel3CState cstate) { if (NULL == t) return; LOG (GNUNET_ERROR_TYPE_DEBUG, - "Tunnel %s state was %s\n", - GMP_2s (t->peer), - GMT_state2s (t->state)); + "Tunnel %s cstate was %s\n", + GMP_2s (t->peer), cstate2s (t->cstate)); LOG (GNUNET_ERROR_TYPE_DEBUG, - "Tunnel %s state is now %s\n", - GMP_2s (t->peer), - GMT_state2s (state)); + "Tunnel %s cstate is now %s\n", + GMP_2s (t->peer), cstate2s (cstate)); if (myid != GMP_get_short_id (t->peer) && - MESH_TUNNEL3_WAITING == t->state && MESH_TUNNEL3_READY == state) + MESH_TUNNEL3_READY != t->cstate && + MESH_TUNNEL3_READY == cstate) { - LOG (GNUNET_ERROR_TYPE_DEBUG, " triggered rekey\n"); - rekey_tunnel (t, NULL); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Tunnel %s state is now %s\n", - GMP_2s (t->peer), - GMT_state2s (t->state)); + t->cstate = cstate; + if (MESH_TUNNEL3_KEY_OK == t->estate) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " triggered send queued data\n"); + send_queued_data (t); + } + else if (MESH_TUNNEL3_KEY_UNINITIALIZED == t->estate) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " triggered rekey\n"); + rekey_tunnel (t, NULL); + } } - else + t->cstate = cstate; + + if (MESH_TUNNEL3_READY == cstate && 3 <= GMT_count_connections (t)) { - t->state = state; + GMP_stop_search (t->peer); } - if (MESH_TUNNEL3_READY == state && 3 <= GMT_count_connections (t)) +} + +/** + * Change the tunnel encryption state. + * + * @param t Tunnel whose encryption state to change. + * @param state New encryption state. + */ +void +GMT_change_estate (struct MeshTunnel3* t, enum MeshTunnel3EState state) +{ + if (NULL == t) + return; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel %s estate was %s\n", + GMP_2s (t->peer), estate2s (t->estate)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel %s estate is now %s\n", + GMP_2s (t->peer), estate2s (state)); + if (myid != GMP_get_short_id (t->peer) && + MESH_TUNNEL3_KEY_OK != t->estate && MESH_TUNNEL3_KEY_OK == state) { - GMP_stop_search (t->peer); + t->estate = state; + send_queued_data (t); + return; } + t->estate = state; } @@ -1478,6 +1737,8 @@ GMT_add_connection (struct MeshTunnel3 *t, struct MeshConnection *c) { struct MeshTConnection *aux; + GNUNET_assert (NULL != c); + for (aux = t->connection_head; aux != NULL; aux = aux->next) if (aux->c == c) return; @@ -1498,14 +1759,39 @@ void GMT_remove_connection (struct MeshTunnel3 *t, struct MeshConnection *c) { struct MeshTConnection *aux; + struct MeshTConnection *next; - for (aux = t->connection_head; aux != NULL; aux = aux->next) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n", + GMC_2s (c), GMT_2s (t)); + for (aux = t->connection_head; aux != NULL; aux = next) + { + next = aux->next; if (aux->c == c) { GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux); GNUNET_free (aux); - return; } + } + + /* Start new connections if needed */ + if (NULL == t->connection_head && GNUNET_NO == t->destroy) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " no more connections\n"); + GMP_connect (t->peer); + t->cstate = MESH_TUNNEL3_SEARCHING; + return; + } + + /* If not marked as ready, no change is needed */ + if (MESH_TUNNEL3_READY != t->cstate) + return; + + /* Check if any connection is ready to maintaing cstate */ + for (aux = t->connection_head; aux != NULL; aux = aux->next) + if (MESH_CONNECTION_READY == GMC_get_state (aux->c)) + return; + + t->cstate = MESH_TUNNEL3_WAITING; } @@ -1535,6 +1821,12 @@ GMT_add_channel (struct MeshTunnel3 *t, struct MeshChannel *ch) aux->ch = ch; LOG (GNUNET_ERROR_TYPE_DEBUG, " adding %p to %p\n", aux, t->channel_head); GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, t->channel_tail, aux); + + if (GNUNET_YES == t->destroy) + { + t->destroy = GNUNET_NO; + LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n"); + } } @@ -1601,11 +1893,13 @@ GMT_destroy_empty (struct MeshTunnel3 *t) { struct MeshTConnection *iter; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel empty: destroying scheduled\n"); for (iter = t->connection_head; NULL != iter; iter = iter->next) { GMC_send_destroy (iter->c); } + t->cstate = MESH_TUNNEL3_NEW; t->destroy = GNUNET_YES; } @@ -1647,6 +1941,8 @@ GMT_destroy (struct MeshTunnel3 *t) if (NULL == t) return; + t->destroy = 2; + LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer)); GNUNET_break (GNUNET_YES == @@ -1705,12 +2001,17 @@ GMT_use_path (struct MeshTunnel3 *t, struct MeshPeerPath *p) } if (own_pos > p->length - 1) { - GNUNET_break (0); + GNUNET_break_op (0); return NULL; } GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &cid); c = GMC_new (&cid, t, p, own_pos); + if (NULL == c) + { + /* Path was flawed */ + return NULL; + } GMT_add_connection (t, c); return c; } @@ -1758,21 +2059,21 @@ GMT_count_channels (struct MeshTunnel3 *t) /** - * Get the state of a tunnel. + * Get the connectivity state of a tunnel. * * @param t Tunnel. * - * @return Tunnel's state. + * @return Tunnel's connectivity state. */ -enum MeshTunnel3State -GMT_get_state (struct MeshTunnel3 *t) +enum MeshTunnel3CState +GMT_get_cstate (struct MeshTunnel3 *t) { if (NULL == t) { GNUNET_break (0); - return (enum MeshTunnel3State) -1; + return (enum MeshTunnel3CState) -1; } - return t->state; + return t->cstate; } @@ -1820,18 +2121,14 @@ GMT_get_connections_buffer (struct MeshTunnel3 *t) struct MeshTConnection *iter; unsigned int buffer; - iter = t->connection_head; buffer = 0; - while (NULL != iter) + for (iter = t->connection_head; NULL != iter; iter = iter->next) { if (GMC_get_state (iter->c) != MESH_CONNECTION_READY) { - iter = iter->next; continue; } - buffer += get_connection_buffer (iter); - iter = iter->next; } return buffer; @@ -1863,14 +2160,28 @@ MESH_ChannelNumber GMT_get_next_chid (struct MeshTunnel3 *t) { MESH_ChannelNumber chid; + MESH_ChannelNumber mask; + int result; + + /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID. + * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0 + * If peer's ID is bigger, start at 0x4... bit 30 = 1 + */ + result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GMP_get_id (t->peer)); + if (0 > result) + mask = 0x4000000; + else + mask = 0x0; while (NULL != GMT_get_channel (t, t->next_chid)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", t->next_chid); t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI; + t->next_chid |= mask; } chid = t->next_chid; t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI; + t->next_chid |= mask; return chid; } @@ -1942,7 +2253,7 @@ GMT_send_connection_acks (struct MeshTunnel3 *t) unsigned int cs; unsigned int buffer; - LOG (GNUNET_ERROR_TYPE_DEBUG, + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n", GMT_2s (t)); @@ -1986,31 +2297,6 @@ GMT_send_connection_acks (struct MeshTunnel3 *t) } -/** - * Callback called when a queued message is sent. - * - * Calculates the average time and connection packet tracking. - * - * @param cls Closure (TunnelQueue handle). - * @param c Connection this message was on. - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -static void -message_sent (void *cls, - struct MeshConnection *c, - struct MeshConnectionQueue *q, - uint16_t type, int fwd, size_t size) -{ - struct MeshTunnel3Queue *qt = cls; - - GNUNET_assert (NULL != qt->cont); - qt->cont (qt->cont_cls, GMC_get_tunnel (c), qt, type, size); - GNUNET_free (qt); -} - - /** * Cancel a previously sent message while it's in the queue. * @@ -2023,18 +2309,29 @@ message_sent (void *cls, void GMT_cancel (struct MeshTunnel3Queue *q) { - GMC_cancel (q->q); - /* message_sent() will be called and free q */ + if (NULL != q->cq) + { + GMC_cancel (q->cq); + /* message_sent() will be called and free q */ + } + else if (NULL != q->tqd) + { + unqueue_data (q->tqd); + } + else + { + GNUNET_break (0); + } } + /** * Sends an already built message on a tunnel, encrypting it and * choosing the best connection. * * @param message Message to send. Function modifies it. * @param t Tunnel on which this message is transmitted. - * @param ch Channel on which this message is transmitted. - * @param fwd Is this a fwd message on @c ch? + * @param force Force the tunnel to take the message (buffer overfill). * @param cont Continuation to call once message is really sent. * @param cont_cls Closure for @c cont. * @@ -2042,79 +2339,13 @@ GMT_cancel (struct MeshTunnel3Queue *q) */ struct MeshTunnel3Queue * GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct MeshTunnel3 *t, - struct MeshChannel *ch, int fwd, + struct MeshTunnel3 *t, int force, GMT_sent cont, void *cont_cls) { - struct MeshTunnel3Queue *q; - struct MeshConnection *c; - struct GNUNET_MESH_Encrypted *msg; - size_t size = ntohs (message->size); - size_t encrypted_size; - char cbuf[sizeof (struct GNUNET_MESH_Encrypted) + size]; - uint32_t iv; - uint16_t type; - - if (MESH_TUNNEL3_READY != t->state) - { - queue_data (t, ch, message); - /* FIXME */ - return NULL; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t)); - - if (GMT_is_loopback (t)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback!\n"); - handle_decrypted (t, message, fwd); - /* FIXME: call cont? */ - return NULL; /* Already delivered, cannot cancel */ - } - - iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - msg = (struct GNUNET_MESH_Encrypted *) cbuf; - msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED); - msg->iv = iv; - encrypted_size = t_encrypt (t, &msg[1], message, size, iv); - msg->header.size = htons (sizeof (struct GNUNET_MESH_Encrypted) + encrypted_size); - c = tunnel_get_connection (t); - if (NULL == c) - { - GNUNET_break (GNUNET_YES == t->destroy); - return NULL; - } - type = ntohs (message->type); - switch (type) - { - case GNUNET_MESSAGE_TYPE_MESH_DATA: - case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK: - case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE: - case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: - case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK: - msg->cid = *GMC_get_id (c); - msg->ttl = htonl (default_ttl); - break; - default: - LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n", - GNUNET_MESH_DEBUG_M2S (type)); - GNUNET_break (0); - } - - fwd = GMC_is_origin (c, GNUNET_YES); - - if (NULL == cont) - { - (void) GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL); - return NULL; - } - q = GNUNET_new (struct MeshTunnel3Queue); /* FIXME valgrind: leak*/ - q->q = GMC_send_prebuilt_message (&msg->header, c, fwd, &message_sent, q); - q->cont = cont; - q->cont_cls = cont_cls; - - return q; + return send_prebuilt_message (message, t, force, cont, cont_cls, NULL); } + /** * Is the tunnel directed towards the local peer? * @@ -2163,6 +2394,7 @@ GMT_get_path_cost (const struct MeshTunnel3 *t, const struct MeshPeerPath *path) { struct MeshTConnection *iter; + const struct MeshPeerPath *aux; unsigned int overlap; unsigned int i; unsigned int j; @@ -2177,9 +2409,13 @@ GMT_get_path_cost (const struct MeshTunnel3 *t, { for (iter = t->connection_head; NULL != iter; iter = iter->next) { - for (j = 0; j < GMC_get_path (iter->c)->length; j++) + aux = GMC_get_path (iter->c); + if (NULL == aux) + continue; + + for (j = 0; j < aux->length; j++) { - if (path->peers[i] == GMC_get_path (iter->c)->peers[j]) + if (path->peers[i] == aux->peers[j]) { overlap++; break; @@ -2205,4 +2441,4 @@ GMT_2s (const struct MeshTunnel3 *t) return "(NULL)"; return GMP_2s (t->peer); -} \ No newline at end of file +}