X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fgnunet-service-mesh_local.c;h=9b868124a1d96b3f2d5c4dfbafd9151d2ed6386d;hb=33354bfe79f97acb2c98d08fa4f1c32f2d2b1220;hp=9714034ba44f1f9c4e237952c41e176adcc2e396;hpb=ede5e3950ffad6c6b812d1f210f90cd066961cad;p=oweals%2Fgnunet.git diff --git a/src/mesh/gnunet-service-mesh_local.c b/src/mesh/gnunet-service-mesh_local.c index 9714034ba..9b868124a 100644 --- a/src/mesh/gnunet-service-mesh_local.c +++ b/src/mesh/gnunet-service-mesh_local.c @@ -28,7 +28,6 @@ #include "mesh_protocol_enc.h" // GNUNET_MESH_Data is shared #include "gnunet-service-mesh_local.h" -#include "gnunet-service-mesh_tunnel.h" #define LOG(level, ...) GNUNET_log_from(level,"mesh-loc",__VA_ARGS__) @@ -58,11 +57,16 @@ struct MeshClient */ struct GNUNET_CONTAINER_MultiHashMap32 *own_channels; - /** + /** * Tunnels this client has accepted, indexed by incoming local id */ struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels; + /** + * Channel ID for the next incoming channel. + */ + MESH_ChannelNumber next_chid; + /** * Handle to communicate with the client */ @@ -175,17 +179,44 @@ handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client) { struct MeshClient *c; + LOG (GNUNET_ERROR_TYPE_DEBUG, "client connected: %p\n", client); if (NULL == client) return; - c = GNUNET_malloc (sizeof (struct MeshClient)); + c = GNUNET_new (struct MeshClient); c->handle = client; c->id = next_client_id++; /* overflow not important: just for debug */ + c->next_chid = GNUNET_MESH_LOCAL_CHANNEL_ID_SERV; GNUNET_SERVER_client_keep (client); GNUNET_SERVER_client_set_user_context (client, c); GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c); } +/** + * Iterator for deleting each channel whose client endpoint disconnected. + * + * @param cls Closure (client that has disconnected). + * @param key The local channel id (used to access the hashmap). + * @param value The value stored at the key (channel to destroy). + * + * @return GNUNET_OK, keep iterating. + */ +static int +channel_destroy_iterator (void *cls, + uint32_t key, + void *value) +{ + struct MeshChannel *ch = value; + struct MeshClient *c = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " Channel %s destroy, due to client %s shutdown.\n", + GMCH_2s (ch), GML_2s (c)); + + GMCH_handle_local_destroy (ch, c); + return GNUNET_OK; +} + /** * Handler for client disconnection * @@ -205,7 +236,7 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) return; } - c = client_get (client); + c = GML_client_get (client); if (NULL != c) { LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n", @@ -323,17 +354,12 @@ static void handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { - struct GNUNET_MESH_ChannelMessage *msg; - struct MeshPeer *peer; - struct MeshTunnel2 *t; - struct MeshChannel *ch; struct MeshClient *c; - MESH_ChannelNumber chid; LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n"); /* Sanity check for client registration */ - if (NULL == (c = client_get (client))) + if (NULL == (c = GML_client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); @@ -349,66 +375,13 @@ handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client, return; } - msg = (struct GNUNET_MESH_ChannelMessage *) message; - LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n", - GNUNET_i2s (&msg->peer), ntohl (msg->port)); - chid = ntohl (msg->channel_id); - - /* Sanity check for duplicate channel IDs */ - if (NULL != channel_get_by_local_id (c, chid)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - peer = peer_get (&msg->peer); - if (NULL == peer->tunnel) - { - peer->tunnel = tunnel_new (); - peer->tunnel->peer = peer; - if (peer->id == myid) - { - tunnel_change_state (peer->tunnel, MESH_TUNNEL_READY); - } - else - { - peer_connect (peer); - } - } - t = peer->tunnel; - - /* Create channel */ - ch = channel_new (t, c, chid); - if (NULL == ch) + if (GNUNET_OK != + GMCH_handle_local_create (c, + (struct GNUNET_MESH_ChannelMessage *) message)) { - GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } - ch->port = ntohl (msg->port); - channel_set_options (ch, ntohl (msg->opt)); - - /* In unreliable channels, we'll use the DLL to buffer BCK data */ - ch->root_rel = GNUNET_new (struct MeshChannelReliability); - 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", - peer2s (t->peer), ch->gid, ch->port, ch->lid_root); - - /* Send create channel */ - { - struct GNUNET_MESH_ChannelCreate msgcc; - - msgcc.header.size = htons (sizeof (msgcc)); - msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE); - msgcc.chid = htonl (ch->gid); - msgcc.port = msg->port; - msgcc.opt = msg->opt; - - GMT_queue_data (t, ch, &msgcc.header, GNUNET_YES); - } GNUNET_SERVER_receive_done (client, GNUNET_OK); return; @@ -429,14 +402,13 @@ handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client, struct GNUNET_MESH_ChannelMessage *msg; struct MeshClient *c; struct MeshChannel *ch; - struct MeshTunnel2 *t; MESH_ChannelNumber chid; LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n"); /* Sanity check for client registration */ - if (NULL == (c = client_get (client))) + if (NULL == (c = GML_client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); @@ -456,7 +428,7 @@ handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client, /* Retrieve tunnel */ chid = ntohl (msg->channel_id); - ch = channel_get_by_local_id (c, chid); + ch = GML_channel_get (c, chid); if (NULL == ch) { LOG (GNUNET_ERROR_TYPE_ERROR, " channel %X not found\n", chid); @@ -465,27 +437,7 @@ handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client, return; } - /* Cleanup after the tunnel */ - client_delete_channel (c, ch); - if (c == ch->dest && GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= chid) - { - ch->dest = NULL; - } - else if (c == ch->root && GNUNET_MESH_LOCAL_CHANNEL_ID_SERV > chid) - { - ch->root = NULL; - } - else - { - LOG (GNUNET_ERROR_TYPE_ERROR, - " channel %X client %p (%p, %p)\n", - chid, c, ch->root, ch->dest); - GNUNET_break (0); - } - - t = ch->t; - channel_destroy (ch); - tunnel_destroy_if_empty (t); + GMCH_handle_local_destroy (ch, c); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; @@ -506,7 +458,6 @@ handle_data (void *cls, struct GNUNET_SERVER_Client *client, struct GNUNET_MESH_LocalData *msg; struct MeshClient *c; struct MeshChannel *ch; - struct MeshChannelReliability *rel; MESH_ChannelNumber chid; size_t size; int fwd; @@ -515,7 +466,7 @@ handle_data (void *cls, struct GNUNET_SERVER_Client *client, "Got data from a client!\n"); /* Sanity check for client registration */ - if (NULL == (c = client_get (client))) + if (NULL == (c = GML_client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); @@ -537,7 +488,7 @@ handle_data (void *cls, struct GNUNET_SERVER_Client *client, /* Channel exists? */ chid = ntohl (msg->id); fwd = chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV; - ch = channel_get_by_local_id (c, chid); + ch = GML_channel_get (c, chid); if (NULL == ch) { GNUNET_break (0); @@ -545,44 +496,14 @@ handle_data (void *cls, struct GNUNET_SERVER_Client *client, return; } - /* Is the client in the channel? */ - if ( !( (fwd && - ch->root && - ch->root->handle == client) - || - (!fwd && - ch->dest && - ch->dest->handle == client) ) ) + if (GNUNET_OK != + GMCH_handle_local_data (ch, c, + (struct GNUNET_MessageHeader *)&msg[1], fwd)) { - GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } - rel = fwd ? ch->root_rel : ch->dest_rel; - rel->client_ready = GNUNET_NO; - - /* Ok, everything is correct, send the message. */ - { - struct GNUNET_MESH_Data *payload; - uint16_t p2p_size = sizeof(struct GNUNET_MESH_Data) + size; - unsigned char cbuf[p2p_size]; - - payload = (struct GNUNET_MESH_Data *) cbuf; - payload->mid = htonl (rel->mid_send); - rel->mid_send++; - memcpy (&payload[1], &msg[1], size); - payload->header.size = htons (p2p_size); - payload->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_DATA); - payload->chid = htonl (ch->gid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n"); - send_prebuilt_message_channel (&payload->header, ch, fwd); - - if (GNUNET_YES == ch->reliable) - channel_save_copy (ch, &payload->header, fwd); - } - if (tunnel_get_buffer (ch->t, fwd) > 0) - send_local_ack (ch, fwd); LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n"); GNUNET_SERVER_receive_done (client, GNUNET_OK); @@ -602,7 +523,6 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_LocalAck *msg; - struct MeshChannelReliability *rel; struct MeshChannel *ch; struct MeshClient *c; MESH_ChannelNumber chid; @@ -611,7 +531,7 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client, LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n"); /* Sanity check for client registration */ - if (NULL == (c = client_get (client))) + if (NULL == (c = GML_client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); @@ -624,7 +544,7 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client, /* Channel exists? */ chid = ntohl (msg->channel_id); LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid); - ch = channel_get_by_local_id (c, chid); + ch = GML_channel_get (c, chid); LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch); if (NULL == ch) { @@ -635,15 +555,11 @@ handle_ack (void *cls, struct GNUNET_SERVER_Client *client, return; } - /* If client is root, the ACK is going FWD, therefore this is "BCK". */ - /* If client is dest, the ACK is going BCK, therefore this is "FWD" */ + /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */ + /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */ fwd = chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV; - rel = fwd ? ch->dest_rel : ch->root_rel; - - rel->client_ready = GNUNET_YES; - channel_send_client_buffered_data (ch, c, fwd); - send_ack (NULL, ch, fwd); + GMCH_handle_local_ack (ch, fwd); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; @@ -697,7 +613,7 @@ handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client, struct MeshClient *c; /* Sanity check for client registration */ - if (NULL == (c = client_get (client))) + if (NULL == (c = GML_client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); @@ -734,7 +650,7 @@ handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client, struct MeshChannel *ch; /* Sanity check for client registration */ - if (NULL == (c = client_get (client))) + if (NULL == (c = GML_client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); @@ -810,6 +726,7 @@ static struct GNUNET_SERVER_MessageHandler client_handlers[] = { void GML_init (struct GNUNET_SERVER_Handle *handle) { + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); server_handle = handle; GNUNET_SERVER_suspend (server_handle); ports = GNUNET_CONTAINER_multihashmap32_create (32); @@ -849,6 +766,97 @@ GML_shutdown (void) } +/** + * Get a chennel from a client + * + * @param c the client to check + * @param chid Channel ID, must be local (> 0x800...) + * + * @return non-NULL if channel exists in the clients lists + */ +struct MeshChannel * +GML_channel_get (struct MeshClient *c, MESH_ChannelNumber chid) +{ + if (0 == (chid & GNUNET_MESH_LOCAL_CHANNEL_ID_CLI)) + { + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid); + return NULL; + } + if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV) + return GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels, chid); + return GNUNET_CONTAINER_multihashmap32_get (c->own_channels, chid); +} + + +/** + * Add a channel to a client + * + * @param client Client. + * @param chid Channel ID. + * @param ch Channel. + */ +void +GML_channel_add (struct MeshClient *client, + uint32_t chid, + struct MeshChannel *ch) +{ + if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV) + GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, chid, ch, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + else if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_CLI) + GNUNET_CONTAINER_multihashmap32_put (client->own_channels, chid, ch, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + else + GNUNET_break (0); +} + + +/** + * Remove a channel from a client + * + * @param client Client. + * @param chid Channel ID. + * @param ch Channel. + */ +void +GML_channel_remove (struct MeshClient *client, + uint32_t chid, + struct MeshChannel *ch) +{ + if (GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= chid) + GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels, chid, ch); + else if (GNUNET_MESH_LOCAL_CHANNEL_ID_CLI <= chid) + GNUNET_CONTAINER_multihashmap32_remove (client->own_channels, chid, ch); + else + GNUNET_break (0); +} + + +/** + * Get the tunnel's next free local channel ID. + * + * @param c Client. + * + * @return LID of a channel free to use. + */ +MESH_ChannelNumber +GML_get_next_chid (struct MeshClient *c) +{ + MESH_ChannelNumber chid; + + while (NULL != GML_channel_get (c, c->next_chid)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", c->next_chid); + c->next_chid = (c->next_chid + 1) | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV; + } + chid = c->next_chid; + c->next_chid = (c->next_chid + 1) | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV; + + return chid; +} + + /** * Check if client has registered with the service and has not disconnected * @@ -862,31 +870,51 @@ GML_client_get (struct GNUNET_SERVER_Client *client) return GNUNET_SERVER_client_get_user_context (client, struct MeshClient); } +/** + * Find a client that has opened a port + * + * @param port Port to check. + * + * @return non-NULL if a client has the port. + */ +struct MeshClient * +GML_client_get_by_port (uint32_t port) +{ + return GNUNET_CONTAINER_multihashmap32_get (ports, port); +} + /** - * Deletes a tunnel from a client (either owner or destination). + * Deletes a channel from a client (either owner or destination). * * @param c Client whose tunnel to delete. * @param ch Channel which should be deleted. + * @param id Channel ID. */ void -GML_client_delete_channel (struct MeshClient *c, struct MeshChannel *ch) +GML_client_delete_channel (struct MeshClient *c, + struct MeshChannel *ch, + MESH_ChannelNumber id) { int res; - if (c == ch->root) + if (GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= id) { - res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels, - ch->lid_root, ch); + res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels, + id, ch); if (GNUNET_YES != res) - LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel owner KO\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n"); } - if (c == ch->dest) + else if (GNUNET_MESH_LOCAL_CHANNEL_ID_CLI <= id) { - res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels, - ch->lid_dest, ch); + res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels, + id, ch); if (GNUNET_YES != res) - LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel client KO\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n"); + } + else + { + GNUNET_break (0); } } @@ -895,39 +923,21 @@ GML_client_delete_channel (struct MeshClient *c, struct MeshChannel *ch) * * If the client was already allowed to send data, do nothing. * - * @param ch Channel on which to send the ACK. * @param c Client to whom send the ACK. - * @param fwd Set to GNUNET_YES for FWD ACK (dest->root) + * @param id Channel ID to use */ void -GML_send_ack (struct MeshChannel *ch, int fwd) +GML_send_ack (struct MeshClient *c, MESH_ChannelNumber id) { struct GNUNET_MESH_LocalAck msg; - struct MeshChannelReliability *rel; - struct MeshClient *c; - - c = fwd ? ch->root : ch->dest; - rel = fwd ? ch->root_rel : ch->dest_rel; - - if (GNUNET_YES == rel->client_ready) - return; /* don't send double ACKs to client */ - - rel->client_ready = GNUNET_YES; LOG (GNUNET_ERROR_TYPE_DEBUG, - "send local %s ack on %s:%X towards %p\n", - fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid, c); + "send local %s ack on %X towards %p\n", + id < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV ? "FWD" : "BCK", id, c); - if (NULL == c - || ( fwd && (0 == ch->lid_root || c != ch->root)) - || (!fwd && (0 == ch->lid_dest || c != ch->dest)) ) - { - GNUNET_break (0); - return; - } msg.header.size = htons (sizeof (msg)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK); - msg.channel_id = htonl (fwd ? ch->lid_root : ch->lid_dest); + msg.channel_id = htonl (id); GNUNET_SERVER_notification_context_unicast (nc, c->handle, &msg.header, @@ -944,7 +954,7 @@ GML_send_ack (struct MeshChannel *ch, int fwd) void GML_send_channel_create (struct MeshClient *c, uint32_t id, uint32_t port, uint32_t opt, - struct GNUNET_PeerIdentity *peer) + const struct GNUNET_PeerIdentity *peer) { struct GNUNET_MESH_ChannelMessage msg; @@ -989,11 +999,11 @@ GML_send_channel_destroy (struct MeshClient *c, uint32_t id) /** * Modify the mesh message ID from global to local and send to client. * - * @param msg Message to modify and send. * @param c Client to send to. - * @param tid Tunnel ID to use (c can be both owner and client). + * @param msg Message to modify and send. + * @param id Channel ID to use (c can be both owner and client). */ -static void +void GML_send_data (struct MeshClient *c, const struct GNUNET_MESH_Data *msg, MESH_ChannelNumber id) @@ -1022,4 +1032,18 @@ GML_send_data (struct MeshClient *c, } +/** + * Get the static string to represent a client. + * + * @param c Client. + * + * @return Static string for the client. + */ +const char * +GML_2s (const struct MeshClient *c) +{ + static char buf[32]; + sprintf (buf, "%u", c->id); + return buf; +}