X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fgnunet-service-mesh_tunnel.c;h=231eeabebb97d1a2941b24bd6946ba7c020184d4;hb=1ef7f26b7579ae2a6256751a3f5ebfbf60afbb2f;hp=9e7886626aa0594e210ae8a9f523a2d3e9bc15fe;hpb=9a9d3ed04c07a6749e784d8df1a61127ff2e756a;p=oweals%2Fgnunet.git diff --git a/src/mesh/gnunet-service-mesh_tunnel.c b/src/mesh/gnunet-service-mesh_tunnel.c index 9e7886626..231eeabeb 100644 --- a/src/mesh/gnunet-service-mesh_tunnel.c +++ b/src/mesh/gnunet-service-mesh_tunnel.c @@ -21,56 +21,44 @@ #include "platform.h" #include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" + #include "mesh_protocol_enc.h" #include "gnunet-service-mesh_tunnel.h" #include "gnunet-service-mesh_connection.h" #include "gnunet-service-mesh_channel.h" +#include "gnunet-service-mesh_peer.h" #include "mesh_path.h" #define LOG(level, ...) GNUNET_log_from(level,"mesh-tun",__VA_ARGS__) -/** - * All the states a tunnel can be in. - */ -enum MeshTunnelState -{ - /** - * Uninitialized status, should never appear in operation. - */ - MESH_TUNNEL_NEW, - - /** - * Path to the peer not known yet - */ - MESH_TUNNEL_SEARCHING, - - /** - * Request sent, not yet answered. - */ - MESH_TUNNEL_WAITING, - - /** - * Peer connected and ready to accept data - */ - MESH_TUNNEL_READY, - - /** - * Peer connected previosly but not responding - */ - MESH_TUNNEL_RECONNECTING -}; - +#define START_FUNCTION LOG(GNUNET_ERROR_TYPE_DEBUG, "%s start\n", __FUNCTION__) +#define END_FUNCTION LOG(GNUNET_ERROR_TYPE_DEBUG, "%s end\n", __FUNCTION__) /******************************************************************************/ /******************************** STRUCTS **********************************/ /******************************************************************************/ +struct MeshTChannel +{ + struct MeshTChannel *next; + struct MeshTChannel *prev; + struct MeshChannel *ch; +}; + +struct MeshTConnection +{ + struct MeshTConnection *next; + struct MeshTConnection *prev; + struct MeshConnection *c; +}; + /** * Struct containing all information regarding a tunnel to a peer. */ -struct MeshTunnel2 +struct MeshTunnel3 { /** * Endpoint of the tunnel. @@ -80,22 +68,22 @@ struct MeshTunnel2 /** * State of the tunnel. */ - enum MeshTunnelState state; + enum MeshTunnel3State state; /** * Local peer ephemeral private key */ - struct GNUNET_CRYPTO_EccPrivateKey *my_eph_key; + struct GNUNET_CRYPTO_EddsaPrivateKey *my_eph_key; /** * Local peer ephemeral public key */ - struct GNUNET_CRYPTO_EccPublicSignKey *my_eph; + struct GNUNET_CRYPTO_EddsaPublicKey *my_eph; /** * Remote peer's public key. */ - struct GNUNET_CRYPTO_EccPublicSignKey *peers_eph; + struct GNUNET_CRYPTO_EddsaPublicKey *peers_eph; /** * Encryption ("our") key. @@ -110,8 +98,8 @@ struct MeshTunnel2 /** * Paths that are actively used to reach the destination peer. */ - struct MeshConnection *connection_head; - struct MeshConnection *connection_tail; + struct MeshTConnection *connection_head; + struct MeshTConnection *connection_tail; /** * Next connection number. @@ -121,19 +109,14 @@ struct MeshTunnel2 /** * Channels inside this tunnel. */ - struct MeshChannel *channel_head; - struct MeshChannel *channel_tail; + struct MeshTChannel *channel_head; + struct MeshTChannel *channel_tail; /** * Channel ID for the next created channel. */ MESH_ChannelNumber next_chid; - /** - * Channel ID for the next incoming channel. - */ - MESH_ChannelNumber next_local_chid; - /** * Pending message count. */ @@ -179,31 +162,35 @@ struct MeshTunnelQueue /******************************************************************************/ /** - * Default TTL for payload packets. + * Global handle to the statistics service. */ -static unsigned long long default_ttl; +extern struct GNUNET_STATISTICS_Handle *stats; /** * Local peer own ID (memory efficient handle). */ -static GNUNET_PEER_Id my_short_id; +extern GNUNET_PEER_Id myid; /** * Local peer own ID (full value). */ -const static struct GNUNET_PeerIdentity *my_full_id; +extern struct GNUNET_PeerIdentity my_full_id; + +/** + * Default TTL for payload packets. + */ +static unsigned long long default_ttl; /** * Own private key. */ -const static struct GNUNET_CRYPTO_EccPrivateKey *my_private_key; +const static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; /******************************************************************************/ /******************************** STATIC ***********************************/ /******************************************************************************/ - /** * Get string description for tunnel state. * @@ -212,22 +199,22 @@ const static struct GNUNET_CRYPTO_EccPrivateKey *my_private_key; * @return String representation. */ static const char * -GNUNET_MESH_DEBUG_TS2S (enum MeshTunnelState s) +GMT_state2s (enum MeshTunnel3State s) { static char buf[128]; switch (s) { - case MESH_TUNNEL_NEW: - return "MESH_TUNNEL_NEW"; - case MESH_TUNNEL_SEARCHING: - return "MESH_TUNNEL_SEARCHING"; - case MESH_TUNNEL_WAITING: - return "MESH_TUNNEL_WAITING"; - case MESH_TUNNEL_READY: - return "MESH_TUNNEL_READY"; - case MESH_TUNNEL_RECONNECTING: - return "MESH_TUNNEL_RECONNECTING"; + case MESH_TUNNEL3_NEW: + return "MESH_TUNNEL3_NEW"; + case MESH_TUNNEL3_SEARCHING: + return "MESH_TUNNEL3_SEARCHING"; + case MESH_TUNNEL3_WAITING: + return "MESH_TUNNEL3_WAITING"; + case MESH_TUNNEL3_READY: + return "MESH_TUNNEL3_READY"; + case MESH_TUNNEL3_RECONNECTING: + return "MESH_TUNNEL3_RECONNECTING"; default: sprintf (buf, "%u (UNKNOWN STATE)", s); @@ -235,7 +222,6 @@ GNUNET_MESH_DEBUG_TS2S (enum MeshTunnelState s) } } - /** * Pick a connection on which send the next data message. * @@ -245,34 +231,28 @@ GNUNET_MESH_DEBUG_TS2S (enum MeshTunnelState s) * @return The connection on which to send the next message. */ static struct MeshConnection * -tunnel_get_connection (struct MeshTunnel2 *t, int fwd) +tunnel_get_connection (struct MeshTunnel3 *t, int fwd) { - struct MeshConnection *c; + struct MeshTConnection *iter; struct MeshConnection *best; - struct MeshFlowControl *fc; + unsigned int qn; unsigned int lowest_q; - LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", - peer2s (t->peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GMP_2s (t->peer)); best = NULL; lowest_q = UINT_MAX; - for (c = t->connection_head; NULL != c; c = c->next) + for (iter = t->connection_head; NULL != iter; iter = iter->next) { LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n", - GNUNET_h2s (&c->id), c->state); - if (MESH_CONNECTION_READY == c->state) + GNUNET_h2s (GMC_get_id (iter->c)), GMC_get_state (iter->c)); + if (MESH_CONNECTION_READY == GMC_get_state (iter->c)) { - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if (NULL == fc) - { - GNUNET_break (0); - continue; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", fc->queue_n); - if (fc->queue_n < lowest_q) + qn = GMC_get_qn (iter->c, fwd); + LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn); + if (qn < lowest_q) { - best = c; - lowest_q = fc->queue_n; + best = iter->c; + lowest_q = qn; } } } @@ -281,86 +261,298 @@ tunnel_get_connection (struct MeshTunnel2 *t, int fwd) /** - * Get the total buffer space for a tunnel. + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * Encrypt data with the tunnel key. * - * @param t Tunnel. - * @param fwd Is this for FWD traffic? + * @param t Tunnel whose key to use. + * @param dst Destination for the GMT_encrypted data. + * @param src Source of the plaintext. + * @param size Size of the plaintext. + * @param iv Initialization Vector to use. + * @param fwd Is this a fwd message? + */ +static void +GMT_encrypt (struct MeshTunnel3 *t, + void *dst, const void *src, + size_t size, uint64_t iv, int fwd) +{ + memcpy (dst, src, size); +} + + +/** + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * Decrypt data with the tunnel key. * - * @return Buffer space offered by all connections in the tunnel. + * @param t Tunnel whose key to use. + * @param dst Destination for the plaintext. + * @param src Source of the GMT_encrypted data. + * @param size Size of the GMT_encrypted data. + * @param iv Initialization Vector to use. + * @param fwd Is this a fwd message? */ -static unsigned int -tunnel_get_buffer (struct MeshTunnel2 *t, int fwd) +static void +GMT_decrypt (struct MeshTunnel3 *t, + void *dst, const void *src, + size_t size, uint64_t iv, int fwd) { - struct MeshConnection *c; - struct MeshFlowControl *fc; - unsigned int buffer; + memcpy (dst, src, size); +} - c = t->connection_head; - buffer = 0; - /* If terminal, return biggest channel buffer */ - if (NULL == c || GMC_is_terminal (c, fwd)) +void +handle_data (struct MeshTunnel3 *t, + const struct GNUNET_MESH_Data *msg, + int fwd) +{ + struct MeshChannel *ch; + uint16_t type; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size < + sizeof (struct GNUNET_MESH_Data) + + sizeof (struct GNUNET_MessageHeader)) { - struct MeshChannel *ch; - unsigned int ch_buf; + 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))); + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + GNUNET_STATISTICS_update (stats, "# data on unknown channel", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", + ntohl (msg->chid)); + return; + } - if (NULL == t->channel_head) - return 64; + GMT_change_state (t, MESH_TUNNEL3_READY); + GMCH_handle_data (ch, msg, fwd); +} - for (ch = t->channel_head; NULL != ch; ch = ch->next) - { - ch_buf = GMCH_get_buffer (ch, fwd); - if (ch_buf > buffer) - buffer = ch_buf; - } - return buffer; +void +handle_data_ack (struct MeshTunnel3 *t, + const struct GNUNET_MESH_DataACK *msg, + int fwd) +{ + struct MeshChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_MESH_DataACK)) + { + GNUNET_break (0); + return; } - /* If not terminal, return sum of connection buffers */ - while (NULL != c) + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) { - if (c->state != MESH_CONNECTION_READY) - { - c = c->next; - continue; - } + GNUNET_STATISTICS_update (stats, "# data ack on unknown channel", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", + ntohl (msg->chid)); + return; + } - fc = fwd ? &c->fwd_fc : &c->bck_fc; - buffer += fc->queue_max - fc->queue_n; - c = c->next; + GMCH_handle_data_ack (ch, msg, fwd); +} + +void +handle_ch_create (struct MeshTunnel3 *t, + const struct GNUNET_MESH_ChannelCreate *msg, + int fwd) +{ + ; + + struct MeshTChannel *tch; + struct MeshChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_MESH_ChannelCreate)) + { + GNUNET_break (0); + return; } - return buffer; + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL != ch) + { + /* Probably a retransmission, safe to ignore */ + LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n"); + } + else + { + ch = GMCH_handle_create (t, msg, fwd); + } + + tch = GNUNET_new (struct MeshTChannel); + tch->ch = ch; + GNUNET_CONTAINER_DLL_insert (t->channel_head, t->channel_tail, tch); + + ; +} + +void +handle_ch_ack (struct MeshTunnel3 *t, + const struct GNUNET_MESH_ChannelManage *msg, + int fwd) +{ + struct MeshChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_MESH_ChannelManage)) + { + GNUNET_break (0); + return; + } + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", + ntohl (msg->chid)); + return; + } + + GMCH_handle_ack (ch, msg, fwd); +} + +void +handle_ch_destroy (struct MeshTunnel3 *t, + const struct GNUNET_MESH_ChannelManage *msg, + int fwd) +{ + struct MeshChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_MESH_ChannelManage)) + { + GNUNET_break (0); + return; + } + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + /* Probably a retransmission, safe to ignore */ + return; + } + + GMCH_handle_destroy (ch, msg, fwd); } /** - * Send all cached messages that we can, tunnel is online. + * Demultiplex by message type and call appropriate handler for a message + * towards a channel of a local tunnel. * - * @param t Tunnel that holds the messages. - * @param fwd Is this fwd? + * @param t Tunnel this message came on. + * @param msgh Message header. + * @param fwd Is this message fwd? */ static void -tunnel_send_queued_data (struct MeshTunnel2 *t, int fwd) +handle_decrypted (struct MeshTunnel3 *t, + const struct GNUNET_MessageHeader *msgh, + int fwd) { - struct MeshTunnelQueue *tq; - struct MeshTunnelQueue *next; - unsigned int room; + uint16_t type; + type = ntohs (msgh->type); LOG (GNUNET_ERROR_TYPE_DEBUG, - "tunnel_send_queued_data on tunnel %s\n", - peer2s (t->peer)); - room = tunnel_get_buffer (t, fwd); - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); - for (tq = t->tq_head; NULL != tq && room > 0; tq = next) + "Got a %s message!\n", + GNUNET_MESH_DEBUG_M2S (type)); + + switch (type) { - 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, fwd); + case GNUNET_MESSAGE_TYPE_MESH_DATA: + /* Don't send hop ACK, wait for client to ACK */ + handle_data (t, (struct GNUNET_MESH_Data *) msgh, fwd); + break; - GNUNET_free (tq); + case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK: + handle_data_ack (t, (struct GNUNET_MESH_DataACK *) msgh, fwd); + break; + + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE: + handle_ch_create (t, + (struct GNUNET_MESH_ChannelCreate *) msgh, + fwd); + break; + + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK: + handle_ch_ack (t, + (struct GNUNET_MESH_ChannelManage *) msgh, + fwd); + break; + + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: + handle_ch_destroy (t, + (struct GNUNET_MESH_ChannelManage *) msgh, + fwd); + break; + + default: + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "end-to-end message not known (%u)\n", + ntohs (msgh->type)); + } +} + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + + +/** + * Decrypt and demultiplex by message type. Call appropriate handler + * for every message. + * + * @param t Tunnel this message came on. + * @param msg Encrypted message. + * @param fwd Is this message fwd? + */ +void +GMT_handle_encrypted (struct MeshTunnel3 *t, + const struct GNUNET_MESH_Encrypted *msg, + int fwd) +{ + size_t size = ntohs (msg->header.size); + size_t payload_size = size - sizeof (struct GNUNET_MESH_Encrypted); + char cbuf[payload_size]; + struct GNUNET_MessageHeader *msgh; + unsigned int off; + + GMT_decrypt (t, cbuf, &msg[1], payload_size, msg->iv, fwd); + off = 0; + while (off < payload_size) + { + msgh = (struct GNUNET_MessageHeader *) &cbuf[off]; + handle_decrypted (t, msgh, fwd); + off += ntohs (msgh->size); } } @@ -374,7 +566,7 @@ tunnel_send_queued_data (struct MeshTunnel2 *t, int fwd) * @param fwd Is this fwd? */ void -GMT_queue_data (struct MeshTunnel2 *t, +GMT_queue_data (struct MeshTunnel3 *t, struct MeshChannel *ch, struct GNUNET_MessageHeader *msg, int fwd) @@ -388,15 +580,45 @@ GMT_queue_data (struct MeshTunnel2 *t, memcpy (&tq[1], msg, size); GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tq); - if (MESH_TUNNEL_READY == t->state) - tunnel_send_queued_data (t, fwd); + if (MESH_TUNNEL3_READY == t->state) + GMT_send_queued_data (t, fwd); } +/** + * Send all cached messages that we can, tunnel is online. + * + * @param t Tunnel that holds the messages. + * @param fwd Is this fwd? + */ +void +GMT_send_queued_data (struct MeshTunnel3 *t, int fwd) +{ + struct MeshTunnelQueue *tq; + struct MeshTunnelQueue *next; + unsigned int room; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GMT_send_queued_data on tunnel %s\n", + GMT_2s (t)); + room = GMT_get_buffer (t, fwd); + LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); + for (tq = t->tq_head; NULL != tq && room > 0; tq = next) + { + 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, fwd); + + GNUNET_free (tq); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GMT_send_queued_data end\n", + GMP_2s (t->peer)); +} -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ /** * Initialize the tunnel subsystem. @@ -407,20 +629,18 @@ GMT_queue_data (struct MeshTunnel2 *t, */ void GMT_init (const struct GNUNET_CONFIGURATION_Handle *c, - const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CRYPTO_EccPrivateKey *key) + const struct GNUNET_CRYPTO_EddsaPrivateKey *key) { + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DEFAULT_TTL", &default_ttl)) { - LOG_config_invalid (GNUNET_ERROR_TYPE_WARNING, + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "MESH", "DEFAULT_TTL", "USING DEFAULT"); default_ttl = 64; } - my_full_id = id; my_private_key = key; - my_short_id = GNUNET_PEER_intern (my_full_id); } @@ -430,21 +650,22 @@ GMT_init (const struct GNUNET_CONFIGURATION_Handle *c, void GMT_shutdown (void) { - GNUNET_PEER_change_rc (my_short_id, -1); } /** * Create a tunnel. + * + * @param destination Peer this tunnel is towards. */ -struct MeshTunnel2 * -GMT_new (void) +struct MeshTunnel3 * +GMT_new (struct MeshPeer *destination) { - struct MeshTunnel2 *t; + struct MeshTunnel3 *t; - t = GNUNET_new (struct MeshTunnel2); + t = GNUNET_new (struct MeshTunnel3); t->next_chid = 0; - t->next_local_chid = GNUNET_MESH_LOCAL_CHANNEL_ID_SERV; + t->peer = destination; // if (GNUNET_OK != // GNUNET_CONTAINER_multihashmap_put (tunnels, tid, t, // GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) @@ -472,7 +693,6 @@ GMT_new (void) } - /** * Change the tunnel state. * @@ -480,19 +700,23 @@ GMT_new (void) * @param state New state. */ void -GMT_change_state (struct MeshTunnel2* t, enum MeshTunnelState state) +GMT_change_state (struct MeshTunnel3* t, enum MeshTunnel3State state) { if (NULL == t) return; LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s state was %s\n", - peer2s (t->peer), - GNUNET_MESH_DEBUG_TS2S (t->state)); + GMP_2s (t->peer), + GMT_state2s (t->state)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s state is now %s\n", - peer2s (t->peer), - GNUNET_MESH_DEBUG_TS2S (state)); + GMP_2s (t->peer), + GMT_state2s (state)); t->state = state; + if (MESH_TUNNEL3_READY == state && 3 <= GMT_count_connections (t)) + { + GMP_stop_search (t->peer); + } } @@ -503,35 +727,124 @@ GMT_change_state (struct MeshTunnel2* t, enum MeshTunnelState state) * @param c Connection. */ void -GMT_add_connection (struct MeshTunnel2 *t, struct MeshConnection *c) +GMT_add_connection (struct MeshTunnel3 *t, struct MeshConnection *c) { - struct MeshConnection *aux; - c->t = t; + struct MeshTConnection *aux; + for (aux = t->connection_head; aux != NULL; aux = aux->next) - if (aux == c) + if (aux->c == c) return; - GNUNET_CONTAINER_DLL_insert_tail (t->connection_head, t->connection_tail, c); -} - + aux = GNUNET_new (struct MeshTConnection); + aux->c = c; + GNUNET_CONTAINER_DLL_insert_tail (t->connection_head, t->connection_tail, aux); +} /** - * Tunnel is empty: destroy it. + * Remove a connection from a tunnel. + * + * @param t Tunnel. + * @param c Connection. + */ +void +GMT_remove_connection (struct MeshTunnel3 *t, struct MeshConnection *c) +{ + struct MeshTConnection *aux; + + for (aux = t->connection_head; aux != NULL; aux = aux->next) + if (aux->c == c) + { + GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux); + GNUNET_free (aux); + return; + } +} + + +/** + * Add a channel to a tunnel. + * + * @param t Tunnel. + * @param ch Channel. + */ +void +GMT_add_channel (struct MeshTunnel3 *t, struct MeshChannel *ch) +{ + struct MeshTChannel *aux; + + for (aux = t->channel_head; aux != NULL; aux = aux->next) + if (aux->ch == ch) + return; + + aux = GNUNET_new (struct MeshTChannel); + aux->ch = ch; + GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, t->channel_tail, aux); +} + + +/** + * Remove a channel from a tunnel. + * + * @param t Tunnel. + * @param ch Channel. + */ +void +GMT_remove_channel (struct MeshTunnel3 *t, struct MeshChannel *ch) +{ + struct MeshTChannel *aux; + + for (aux = t->channel_head; aux != NULL; aux = aux->next) + if (aux->ch == ch) + { + GNUNET_CONTAINER_DLL_remove (t->channel_head, t->channel_tail, aux); + GNUNET_free (aux); + return; + } +} + + +/** + * Search for a channel by global ID. + * + * @param t Tunnel containing the channel. + * @param chid Public channel number. + * + * @return channel handler, NULL if doesn't exist + */ +struct MeshChannel * +GMT_get_channel (struct MeshTunnel3 *t, MESH_ChannelNumber chid) +{ + struct MeshTChannel *iter; + + if (NULL == t) + return NULL; + + for (iter = t->channel_head; NULL != iter; iter = iter->next) + { + if (GMCH_get_id (iter->ch) == chid) + break; + } + + return NULL == iter ? NULL : iter->ch; +} + + +/** + * Tunnel is empty: destroy it. * * Notifies all connections about the destruction. * * @param t Tunnel to destroy. */ void -GMT_destroy_empty (struct MeshTunnel2 *t) +GMT_destroy_empty (struct MeshTunnel3 *t) { - struct MeshConnection *c; + struct MeshTConnection *iter; - for (c = t->connection_head; NULL != c; c = c->next) + for (iter = t->connection_head; NULL != iter; iter = iter->next) { - if (GNUNET_NO == c->destroy) - GMC_send_destroy (c); + GMC_send_destroy (iter->c); } if (0 == t->pending_messages) @@ -547,16 +860,15 @@ GMT_destroy_empty (struct MeshTunnel2 *t) * @param t Tunnel to destroy if empty. */ void -GMT_destroy_if_empty (struct MeshTunnel2 *t) +GMT_destroy_if_empty (struct MeshTunnel3 *t) { - if (1 <= GMCH_count (t->channel_head)) + if (1 < GMT_count_channels (t)) return; GMT_destroy_empty (t); } - /** * Destroy the tunnel. * @@ -569,123 +881,32 @@ GMT_destroy_if_empty (struct MeshTunnel2 *t) * @param t The tunnel to destroy. */ void -GMT_destroy (struct MeshTunnel2 *t) +GMT_destroy (struct MeshTunnel3 *t) { - struct MeshConnection *c; - struct MeshConnection *next; + struct MeshTConnection *iter; + struct MeshTConnection *next; if (NULL == t) return; - LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", - peer2s (t->peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer)); // if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (tunnels, &t->id, t)) // GNUNET_break (0); - for (c = t->connection_head; NULL != c; c = next) + for (iter = t->connection_head; NULL != iter; iter = next) { - next = c->next; - GMC_destroy (c); + next = iter->next; + GMC_destroy (iter->c); + GNUNET_free (iter); } GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO); - t->peer->tunnel = NULL; + GMP_set_tunnel (t->peer, NULL); GNUNET_free (t); } -/** - * Demultiplex by message type and call appropriate handler for a message - * towards a channel of a local tunnel. - * - * @param t Tunnel this message came on. - * @param msgh Message header. - * @param fwd Is this message fwd? - */ -void -GMT_handle_decrypted (struct MeshTunnel2 *t, - const struct GNUNET_MessageHeader *msgh, - int fwd) -{ - switch (ntohs (msgh->type)) - { - case GNUNET_MESSAGE_TYPE_MESH_DATA: - /* Don't send hop ACK, wait for client to ACK */ - handle_data (t, (struct GNUNET_MESH_Data *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK: - handle_data_ack (t, (struct GNUNET_MESH_DataACK *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE: - handle_channel_create (t, - (struct GNUNET_MESH_ChannelCreate *) msgh, - fwd); - break; - - case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK: - handle_channel_ack (t, - (struct GNUNET_MESH_ChannelManage *) msgh, - fwd); - break; - - case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: - handle_channel_destroy (t, - (struct GNUNET_MESH_ChannelManage *) msgh, - fwd); - break; - - default: - LOG (GNUNET_ERROR_TYPE_DEBUG, - "end-to-end message not known (%u)\n", - ntohs (msgh->type)); - } -} - - -/** - * Notifies a tunnel that a connection has broken that affects at least - * some of its peers. Sends a notification towards the root of the tree. - * In case the peer is the owner of the tree, notifies the client that owns - * the tunnel and tries to reconnect. - * - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * - * @param t Tunnel affected. - * @param p1 Peer that got disconnected from p2. - * @param p2 Peer that got disconnected from p1. - * - * @return Short ID of the peer disconnected (either p1 or p2). - * 0 if the tunnel remained unaffected. - */ -GNUNET_PEER_Id -GMT_notify_connection_broken (struct MeshTunnel2* t, - GNUNET_PEER_Id p1, GNUNET_PEER_Id p2) -{ -// if (myid != p1 && myid != p2) FIXME -// { -// return; -// } -// -// if (tree_get_predecessor (t->tree) != 0) -// { -// /* We are the peer still connected, notify owner of the disconnection. */ -// struct GNUNET_MESH_PathBroken msg; -// struct GNUNET_PeerIdentity neighbor; -// -// msg.header.size = htons (sizeof (msg)); -// msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN); -// GNUNET_PEER_resolve (t->id.oid, &msg.oid); -// msg.tid = htonl (t->id.tid); -// msg.peer1 = my_full_id; -// GNUNET_PEER_resolve (pid, &msg.peer2); -// GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &neighbor); -// send_prebuilt_message (&msg.header, &neighbor, t); -// } - return 0; -} /** * @brief Use the given path for the tunnel. @@ -698,11 +919,10 @@ GMT_notify_connection_broken (struct MeshTunnel2* t, * @return Connection created. */ struct MeshConnection * -GMT_use_path (struct MeshTunnel2 *t, struct MeshPeerPath *p) +GMT_use_path (struct MeshTunnel3 *t, struct MeshPeerPath *p) { struct MeshConnection *c; struct GNUNET_HashCode cid; - struct MeshPeer *peer; unsigned int own_pos; if (NULL == t || NULL == p) @@ -711,11 +931,6 @@ GMT_use_path (struct MeshTunnel2 *t, struct MeshPeerPath *p) return NULL; } - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &cid); - - c = GMC_new (&cid); - c->t = t; - GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, c); for (own_pos = 0; own_pos < p->length; own_pos++) { if (p->peers[own_pos] == myid) @@ -724,95 +939,293 @@ GMT_use_path (struct MeshTunnel2 *t, struct MeshPeerPath *p) if (own_pos > p->length - 1) { GNUNET_break (0); - connection_destroy (c); return NULL; } - c->own_pos = own_pos; - c->path = p; - if (0 == own_pos) - { - c->fwd_maintenance_task = - GNUNET_SCHEDULER_add_delayed (refresh_connection_time, - &connection_fwd_keepalive, c); - } + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &cid); + c = GMC_new (&cid, t, p, own_pos); + GMT_add_connection (t, c); + return c; +} + + +/** + * Count established (ready) connections of a tunnel. + * + * @param t Tunnel on which to count. + * + * @return Number of connections. + */ +unsigned int +GMT_count_connections (struct MeshTunnel3 *t) +{ + struct MeshTConnection *iter; + unsigned int count; + + for (count = 0, iter = t->connection_head; + NULL != iter; + iter = iter->next, count++); - peer = connection_get_next_hop (c); - if (NULL == peer->connections) + return count; +} + +/** + * Count channels of a tunnel. + * + * @param t Tunnel on which to count. + * + * @return Number of channels. + */ +unsigned int +GMT_count_channels (struct MeshTunnel3 *t) +{ + struct MeshTChannel *iter; + unsigned int count; + + for (count = 0, iter = t->channel_head; + NULL != iter; + iter = iter->next, count++) /* skip */; + + return count; +} + + +/** + * Get the state of a tunnel. + * + * @param t Tunnel. + * + * @return Tunnel's state. + */ +enum MeshTunnel3State +GMT_get_state (struct MeshTunnel3 *t) +{ + if (NULL == t) + return (enum MeshTunnel3State) -1; + return t->state; +} + +/** + * 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 entities (c/ch) in the tunnel. + */ +unsigned int +GMT_get_buffer (struct MeshTunnel3 *t, int fwd) +{ + struct MeshTConnection *iter; + unsigned int buffer; + + iter = t->connection_head; + buffer = 0; + + /* If terminal, return biggest channel buffer */ + if (NULL == iter || GMC_is_terminal (iter->c, fwd)) { - connection_destroy (c); - return NULL; + struct MeshTChannel *iter_ch; + unsigned int ch_buf; + + if (NULL == t->channel_head) + { + /* Probably getting buffer for a channel create/handshake. */ + return 64; + } + + for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = iter_ch->next) + { + ch_buf = GMCH_get_buffer (iter_ch->ch, fwd); + if (ch_buf > buffer) + buffer = ch_buf; + } + return buffer; } - GNUNET_CONTAINER_multihashmap_put (peer->connections, &c->id, c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - peer = connection_get_prev_hop (c); - if (NULL == peer->connections) + + /* If not terminal, return sum of connection buffers */ + while (NULL != iter) { - connection_destroy (c); - return NULL; + if (GMC_get_state (iter->c) != MESH_CONNECTION_READY) + { + iter = iter->next; + continue; + } + + buffer += GMC_get_buffer (iter->c, fwd); + iter = iter->next; } - GNUNET_CONTAINER_multihashmap_put (peer->connections, &c->id, c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - return c; + + return buffer; } /** - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * Encrypt data with the tunnel key. + * Get the tunnel's destination. * - * @param t Tunnel whose key to use. - * @param dst Destination for the encrypted data. - * @param src Source of the plaintext. - * @param size Size of the plaintext. - * @param iv Initialization Vector to use. - * @param fwd Is this a fwd message? + * @param t Tunnel. + * + * @return ID of the destination peer. */ -void -GMT_encrypt (struct MeshTunnel2 *t, - void *dst, const void *src, - size_t size, uint64_t iv, int fwd) +const struct GNUNET_PeerIdentity * +GMT_get_destination (struct MeshTunnel3 *t) { - memcpy (dst, src, size); + return GMP_get_id (t->peer); } /** - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * Decrypt data with the tunnel key. + * Get the tunnel's next free global channel ID. * - * @param t Tunnel whose key to use. - * @param dst Destination for the plaintext. - * @param src Source of the encrypted data. - * @param size Size of the encrypted data. - * @param iv Initialization Vector to use. - * @param fwd Is this a fwd message? + * @param t Tunnel. + * + * @return GID of a channel free to use. + */ +MESH_ChannelNumber +GMT_get_next_chid (struct MeshTunnel3 *t) +{ + MESH_ChannelNumber chid; + + 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; + } + chid = t->next_chid; + t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI; + + return chid; +} + + +/** + * 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_decrypt (struct MeshTunnel2 *t, - void *dst, const void *src, - size_t size, uint64_t iv, int fwd) +GMT_unchoke_channels (struct MeshTunnel3 *t, int fwd) { - memcpy (dst, src, size); + 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]; + } } /** - * Count established (ready) connections of a tunnel. + * Send ACK on one or more connections due to buffer space to the client. * - * @param t Tunnel on which to send the message. + * Iterates all connections of the tunnel and sends ACKs appropriately. * - * @return Number of connections. + * @param t Tunnel. + * @param fwd Is this in for FWD traffic? (ACK goes dest->root) */ -unsigned int -GMT_count_connections (struct MeshTunnel2 *t) +void +GMT_send_acks (struct MeshTunnel3 *t, int fwd) { - return GMC_count (t->connection_head); + struct MeshTConnection *iter; + uint32_t allowed; + uint32_t to_allow; + uint32_t allow_per_connection; + unsigned int cs; + unsigned int buffer; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel send %s ACKs on %s\n", + fwd ? "FWD" : "BCK", GMT_2s (t)); + + if (NULL == t) + { + GNUNET_break (0); + return; + } + if (NULL == t->channel_head || + GNUNET_NO == GMCH_is_origin (t->channel_head->ch, !fwd)) + { + GNUNET_break (0); + 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) + { + allowed += GMC_get_allowed (iter->c, fwd); + } + + /* Make sure there is no overflow */ + if (allowed > buffer) + { + GNUNET_break (0); + return; + } + + /* Authorize connections to send more data */ + to_allow = buffer; /* - allowed; */ + + for (iter = t->connection_head; NULL != iter && to_allow > 0; iter = iter->next) + { + allow_per_connection = to_allow/cs; + to_allow -= allow_per_connection; + cs--; + if (GMC_get_allowed (iter->c, fwd) > 64 / 3) + { + continue; + } + GMC_allow (iter->c, buffer, fwd); + } + + GNUNET_break (to_allow == 0); } /** - * Sends an already built message on a tunnel, choosing the best connection. + * Sends an already built message on a tunnel, GMT_encrypting it and + * choosing the best connection. * * @param message Message to send. Function modifies it. * @param t Tunnel on which this message is transmitted. @@ -820,30 +1233,40 @@ GMT_count_connections (struct MeshTunnel2 *t) * @param fwd Is this a fwd message? */ void -GMT_send_prebuilt_message (struct GNUNET_MESH_Encrypted *msg, - struct MeshTunnel2 *t, +GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, + struct MeshTunnel3 *t, struct MeshChannel *ch, int fwd) { struct MeshConnection *c; + struct GNUNET_MESH_Encrypted *msg; + size_t size = ntohs (message->size); + char *cbuf[sizeof (struct GNUNET_MESH_Encrypted) + size]; + uint64_t iv; uint16_t type; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Send on Tunnel %s\n", - peer2s (t->peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMP_2s (t->peer)); + + iv = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + msg = (struct GNUNET_MESH_Encrypted *) cbuf; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED); + msg->header.size = htons (sizeof (struct GNUNET_MESH_Encrypted) + size); + msg->iv = GNUNET_htonll (iv); + GMT_encrypt (t, &msg[1], message, size, iv, fwd); c = tunnel_get_connection (t, fwd); if (NULL == c) { GNUNET_break (GNUNET_YES == t->destroy); return; } - type = ntohs (msg->header.type); + type = ntohs (message->type); switch (type) { - case GNUNET_MESSAGE_TYPE_MESH_FWD: - case GNUNET_MESSAGE_TYPE_MESH_BCK: + case GNUNET_MESSAGE_TYPE_MESH_DATA: case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE: case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: - msg->cid = c->id; + case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK: + msg->cid = *GMC_get_id (c); msg->ttl = htonl (default_ttl); break; default: @@ -853,5 +1276,95 @@ GMT_send_prebuilt_message (struct GNUNET_MESH_Encrypted *msg, } msg->reserved = 0; + t->pending_messages++; GMC_send_prebuilt_message (&msg->header, c, ch, fwd); } + +/** + * Is the tunnel directed towards the local peer? + * + * @param t Tunnel. + * + * @return GNUNET_YES if it is loopback. + */ +int +GMT_is_loopback (const struct MeshTunnel3 *t) +{ + return (myid == GMP_get_short_id(t->peer)); +} + + +/** + * Is the tunnel using this path already? + * + * @param t Tunnel. + * @param p Path. + * + * @return GNUNET_YES a connection uses this path. + */ +int +GMT_is_path_used (const struct MeshTunnel3 *t, const struct MeshPeerPath *p) +{ + struct MeshTConnection *iter; + + for (iter = t->connection_head; NULL != iter; iter = iter->next) + if (GMC_get_path (iter->c) == p) + return GNUNET_YES; + + return GNUNET_NO; +} + + +/** + * Get a cost of a path for a tunnel considering existing connections. + * + * @param t Tunnel. + * @param path Candidate path. + * + * @return Cost of the path (path length + number of overlapping nodes) + */ +unsigned int +GMT_get_path_cost (const struct MeshTunnel3 *t, + const struct MeshPeerPath *path) +{ + struct MeshTConnection *iter; + unsigned int overlap; + unsigned int i; + unsigned int j; + + if (NULL == path) + return 0; + + overlap = 0; + GNUNET_assert (NULL != t); + + for (i = 0; i < path->length; i++) + { + for (iter = t->connection_head; NULL != iter; iter = iter->next) + { + for (j = 0; j < GMC_get_path (iter->c)->length; j++) + { + if (path->peers[i] == GMC_get_path (iter->c)->peers[j]) + { + overlap++; + break; + } + } + } + } + return (path->length + overlap) * (path->score * -1); +} + + +/** + * Get the static string for the peer this tunnel is directed. + * + * @param t Tunnel. + * + * @return Static string the destination peer's ID. + */ +const char * +GMT_2s (const struct MeshTunnel3 *t) +{ + return GMP_2s (t->peer); +} \ No newline at end of file