X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fgnunet-service-mesh_tunnel.c;h=f192bb05b5ac49cc6a30c603164bff95c882721c;hb=a107ae89650629fb1d6981bff567ebbdae3dcb8b;hp=4658d29437dddd69aeb04208db2fd5676a0fa836;hpb=c712a1f8b2df7406ac6d7a3346e2b066a23b37ef;p=oweals%2Fgnunet.git diff --git a/src/mesh/gnunet-service-mesh_tunnel.c b/src/mesh/gnunet-service-mesh_tunnel.c index 4658d2943..f192bb05b 100644 --- a/src/mesh/gnunet-service-mesh_tunnel.c +++ b/src/mesh/gnunet-service-mesh_tunnel.c @@ -163,9 +163,9 @@ struct MeshTunnelDelayed struct MeshTunnel3 *t; /** - * Channel. + * Tunnel queue given to the channel to cancel request. Update on send_queued. */ - struct MeshChannel *ch; + struct MeshTunnel3Queue *tq; /** * Message to send. @@ -182,12 +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 *tq; + struct MeshTunnelDelayed *tqd; /** * Continuation to call once sent. @@ -335,6 +335,8 @@ estate2s (enum MeshTunnel3EState es) 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); @@ -607,10 +609,35 @@ tunnel_get_connection (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 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 +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); +} + /** - * Delete a queued message: most probably channel was destroyed before the - * tunnel's key exchange had a chance to finish. + * 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. */ @@ -622,6 +649,142 @@ unqueue_data (struct MeshTunnelDelayed *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 NULL; + } + + 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)) + { + 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)); + + 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; + } + 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; +} + + /** * Send all cached messages that we can, tunnel is online. * @@ -630,7 +793,7 @@ unqueue_data (struct MeshTunnelDelayed *tq) static void send_queued_data (struct MeshTunnel3 *t) { - struct MeshTunnelDelayed *tq; + struct MeshTunnelDelayed *tqd; struct MeshTunnelDelayed *next; unsigned int room; @@ -654,66 +817,22 @@ send_queued_data (struct MeshTunnel3 *t) 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 (tq = t->tq_head; NULL != tq && room > 0; tq = next) + for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next) { - /* GMCH_send_prebuilt_message will call GMT_cancel on the current - * queue handler, therefore free'ing tq before calling GMT_send. - * Since the data to send is part of tq, we need to provide a copy, - * so the data is not invalidated. - */ - struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) &tq[1]; - size_t m_size = ntohs (msg->size); - char cbuf[m_size]; - struct GNUNET_MessageHeader *copy = (struct GNUNET_MessageHeader *) cbuf; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " msg on channel %s\n", GMCH_2s (tq->ch)); - next = tq->next; + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n"); + next = tqd->next; room--; - memcpy (copy, msg, m_size); - GMCH_send_prebuilt_message (copy, - tq->ch, GMCH_is_origin (tq->ch, GNUNET_YES), - NULL); + 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)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_send_queued_data end\n", GMP_2s (t->peer)); } -/** - * Cache a message to be sent once 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). - */ -static struct MeshTunnelDelayed * -queue_data (struct MeshTunnel3 *t, - struct MeshChannel *ch, - const struct GNUNET_MessageHeader *msg) -{ - struct MeshTunnelDelayed *tq; - 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 NULL; - } - - tq = GNUNET_malloc (sizeof (struct MeshTunnelDelayed) + size); - - tq->ch = ch; - tq->t = t; - memcpy (&tq[1], msg, size); - GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tq); - return tq; -} - - - /** * Sends key exchange message on a tunnel, choosing the best connection. * Should not be called on loopback tunnels. @@ -745,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; } @@ -755,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); @@ -1640,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; } @@ -1797,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 == @@ -1855,7 +2001,7 @@ GMT_use_path (struct MeshTunnel3 *t, struct MeshPeerPath *p) } if (own_pos > p->length - 1) { - GNUNET_break (0); + GNUNET_break_op (0); return NULL; } @@ -1980,7 +2126,6 @@ GMT_get_connections_buffer (struct MeshTunnel3 *t) { if (GMC_get_state (iter->c) != MESH_CONNECTION_READY) { - iter = iter->next; continue; } buffer += get_connection_buffer (iter); @@ -2152,32 +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 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 -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. * @@ -2190,14 +2309,14 @@ message_sent (void *cls, void GMT_cancel (struct MeshTunnel3Queue *q) { - if (NULL != q->q) + if (NULL != q->cq) { - GMC_cancel (q->q); + GMC_cancel (q->cq); /* message_sent() will be called and free q */ } - else if (NULL != q->tq) + else if (NULL != q->tqd) { - unqueue_data (q->tq); + unqueue_data (q->tqd); } else { @@ -2212,7 +2331,6 @@ GMT_cancel (struct MeshTunnel3Queue *q) * * @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 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. @@ -2221,76 +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 force, + 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; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t)); - - if (GNUNET_NO == is_ready (t)) - { - q = GNUNET_new (struct MeshTunnel3Queue); - q->tq = queue_data (t, ch, message); - return q; - } - - GNUNET_assert (GNUNET_NO == GMT_is_loopback (t)); - - 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", - 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; - } - q = GNUNET_new (struct MeshTunnel3Queue); /* FIXME valgrind: leak*/ - q->q = GMC_send_prebuilt_message (&msg->header, c, fwd, force, - &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? *