From 74e7bb910aef410888f92fdff592ebc592757c12 Mon Sep 17 00:00:00 2001 From: Bart Polot Date: Thu, 22 Nov 2012 18:02:19 +0000 Subject: [PATCH] - monitor tunnel inital implementation, WIP --- src/mesh/gnunet-service-mesh.c | 202 ++++++++++++++++++++++++++++++--- src/mesh/mesh.h | 2 +- src/mesh/mesh_api.c | 79 ++++++++++++- 3 files changed, 260 insertions(+), 23 deletions(-) diff --git a/src/mesh/gnunet-service-mesh.c b/src/mesh/gnunet-service-mesh.c index 097eca3b6..01f30156e 100644 --- a/src/mesh/gnunet-service-mesh.c +++ b/src/mesh/gnunet-service-mesh.c @@ -1186,7 +1186,7 @@ tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer); * @return tunnel handler, NULL if doesn't exist. */ static struct MeshTunnel * -tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid); +tunnel_get (const struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid); /** @@ -3237,7 +3237,7 @@ tunnel_get_by_pi (GNUNET_PEER_Id pi, MESH_TunnelNumber tid) * @return tunnel handler, NULL if doesn't exist */ static struct MeshTunnel * -tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid) +tunnel_get (const struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid) { return tunnel_get_by_pi (GNUNET_PEER_search (oid), tid); } @@ -8066,6 +8066,7 @@ monitor_peers_iterator (void *cls, } + /** * Iterator over all tunnels to send a monitoring client info about each tunnel. * @@ -8076,44 +8077,44 @@ monitor_peers_iterator (void *cls, * @return GNUNET_YES, to keep iterating. */ static int -monitor_tunnel_iterator (void *cls, - const struct GNUNET_HashCode * key, - void *value) +monitor_all_tunnels_iterator (void *cls, + const struct GNUNET_HashCode * key, + void *value) { struct GNUNET_SERVER_Client *client = cls; struct MeshTunnel *t = value; struct GNUNET_MESH_LocalMonitor *msg; uint32_t npeers; - + npeers = GNUNET_CONTAINER_multihashmap_size (t->peers); msg = GNUNET_malloc (sizeof(struct GNUNET_MESH_LocalMonitor) + - npeers * sizeof (struct GNUNET_PeerIdentity)); + npeers * sizeof (struct GNUNET_PeerIdentity)); GNUNET_PEER_resolve(t->id.oid, &msg->owner); msg->tunnel_id = htonl (t->id.tid); msg->header.size = htons (sizeof (struct GNUNET_MESH_LocalMonitor) + - npeers * sizeof (struct GNUNET_PeerIdentity)); + npeers * sizeof (struct GNUNET_PeerIdentity)); msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR); msg->npeers = 0; (void) GNUNET_CONTAINER_multihashmap_iterate (t->peers, monitor_peers_iterator, msg); - + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "* sending info about tunnel %s [%u] (%u peers)\n", GNUNET_i2s (&msg->owner), t->id.tid, npeers); - + if (msg->npeers != npeers) { GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Monitor fail: size %u - iter %u\n", npeers, msg->npeers); } - - msg->npeers = htonl (npeers); - GNUNET_SERVER_notification_context_unicast (nc, client, - &msg->header, - GNUNET_NO); - return GNUNET_YES; + + msg->npeers = htonl (npeers); + GNUNET_SERVER_notification_context_unicast (nc, client, + &msg->header, + GNUNET_NO); + return GNUNET_YES; } @@ -8142,7 +8143,7 @@ handle_local_monitor (void *cls, struct GNUNET_SERVER_Client *client, "Received monitor request from client %u\n", c->id); GNUNET_CONTAINER_multihashmap_iterate (tunnels, - monitor_tunnel_iterator, + monitor_all_tunnels_iterator, client); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Monitor request from client %u completed\n", @@ -8151,6 +8152,170 @@ handle_local_monitor (void *cls, struct GNUNET_SERVER_Client *client, } +/** + * Data needed to build a Monitor_Tunnel message. + * + * Both arrays can be combined to look up the position of the parent of + * a peer: lookup[parent[peer]]. + */ +struct MeshMonitorTunnelContext +{ + /** + * Partial message, including peer count. + */ + struct GNUNET_MESH_LocalMonitor *msg; + + /** + * Array with parents: peer->parent. + */ + GNUNET_PEER_Id *parents; + + /** + * Array with positions: peer->position. + */ + uint32_t *lookup; + + /** + * Size of the message so far. + */ + size_t size; + + /** + * Client requesting the info. + */ + struct MeshClient *c; +}; + + +/** + * Send a client a message about + */ +static void +send_client_monitor_tunnel (struct MeshMonitorTunnelContext *ctx) +{ + struct GNUNET_MESH_LocalMonitor *resp = ctx->msg; + struct GNUNET_PeerIdentity *pid; + unsigned int *parent; + unsigned int i; + size_t size; + + size = sizeof (struct GNUNET_MESH_LocalMonitor); + size += (sizeof (struct GNUNET_PeerIdentity) + sizeof (int)) * resp->npeers; + resp->header.size = htons (size); + pid = (struct GNUNET_PeerIdentity *) &resp[1]; + parent = (unsigned int *) &pid[resp->npeers]; + for (i = 0; i < resp->npeers; i++) + parent[i] = htonl (ctx->lookup[ctx->parents[i]]); + GNUNET_SERVER_notification_context_unicast (nc, ctx->c->handle, + &resp->header, GNUNET_NO); +} + +/** + * Iterator over a tunnel tree to build a message containing all peers + * the in the tunnel, including relay nodes. + * + * @param cls Closure (pointer to pointer of message being built). + * @param peer Short ID of a peer. + * @param parent Short ID of the @c peer 's parent. + * + * FIXME: limit iterating to a message size / split if necessary + */ +static void +monitor_tunnel_iterator (void *cls, + GNUNET_PEER_Id peer, + GNUNET_PEER_Id parent) +{ + struct MeshMonitorTunnelContext *ctx = cls; + struct GNUNET_MESH_LocalMonitor *msg = ctx->msg; + struct GNUNET_PeerIdentity *pid; + + msg = ctx->msg; + pid = (struct GNUNET_PeerIdentity *) &msg[1]; + GNUNET_PEER_resolve(peer, &pid[msg->npeers]); + ctx->parents[msg->npeers] = parent; + ctx->lookup[peer] = msg->npeers; + ctx->size += sizeof (struct GNUNET_PeerIdentity) * sizeof (uint32_t); + msg->npeers++; + + if ( (ctx->size + sizeof (struct GNUNET_PeerIdentity) * sizeof (uint32_t)) + > USHRT_MAX ) + { + send_client_monitor_tunnel (ctx); + ctx->size = sizeof (struct GNUNET_MESH_LocalMonitor); + ctx->msg->npeers = 0; + } +} + + +/** + * Handler for client's MONITOR_TUNNEL request. + * + * @param cls Closure (unused). + * @param client Identification of the client. + * @param message The actual message. + */ +static void +handle_local_monitor_tunnel (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_MESH_LocalMonitor *msg; + struct GNUNET_MESH_LocalMonitor *resp; + struct MeshMonitorTunnelContext ctx; + struct MeshClient *c; + struct MeshTunnel *t; + + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + msg = (struct GNUNET_MESH_LocalMonitor *) message; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received monitor tunnel request from client %u\n", + c->id); + t = tunnel_get (&msg->owner, ntohl (msg->tunnel_id)); + if (NULL == t) + { + /* We don't know the tunnel */ + struct GNUNET_MESH_LocalMonitor warn; + + warn = *msg; + warn.npeers = htonl (UINT_MAX); + GNUNET_SERVER_notification_context_unicast (nc, client, + &warn.header, + GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + resp = GNUNET_malloc (USHRT_MAX); /* avoid realloc'ing on each step */ + *resp = *msg; + resp->npeers = 0; + ctx.msg = resp; + ctx.parents = GNUNET_malloc (sizeof (GNUNET_PEER_Id) * 1024); /* hard limit anyway */ + ctx.lookup = GNUNET_malloc (sizeof (int) * 1024); + ctx.size = sizeof (struct GNUNET_MESH_LocalMonitor); + ctx.c = c; + + tree_iterate_all (t->tree, + monitor_tunnel_iterator, + &ctx); + send_client_monitor_tunnel (&ctx); + + GNUNET_free (ctx.parents); + GNUNET_free (ctx.lookup); + GNUNET_free (resp); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Monitor tunnel request from client %u completed\n", + c->id); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + /** * Functions to handle messages from clients */ @@ -8206,6 +8371,9 @@ static struct GNUNET_SERVER_MessageHandler client_handlers[] = { {&handle_local_monitor, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR, sizeof (struct GNUNET_MessageHeader)}, + {&handle_local_monitor_tunnel, NULL, + GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR_TUNNEL, + sizeof (struct GNUNET_MESH_LocalMonitor)}, {NULL, NULL, 0, 0} }; diff --git a/src/mesh/mesh.h b/src/mesh/mesh.h index 68f163fa5..873b7f17a 100644 --- a/src/mesh/mesh.h +++ b/src/mesh/mesh.h @@ -305,7 +305,7 @@ struct GNUNET_MESH_LocalAck struct GNUNET_MESH_LocalMonitor { /** - * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR + * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR[_TUNNEL] */ struct GNUNET_MessageHeader header; diff --git a/src/mesh/mesh_api.c b/src/mesh/mesh_api.c index f7aa6b9b1..9e55f2549 100644 --- a/src/mesh/mesh_api.c +++ b/src/mesh/mesh_api.c @@ -217,6 +217,16 @@ struct GNUNET_MESH_Handle */ void *monitor_cls; + /** + * Tunnel callback. + */ + GNUNET_MESH_MonitorTunnelCB tunnel_cb; + + /** + * Tunnel callback closure. + */ + void *tunnel_cls; + #if DEBUG_ACK unsigned int acks_sent; unsigned int acks_recv; @@ -1295,6 +1305,20 @@ process_monitor (struct GNUNET_MESH_Handle *h, } + +/** + * Process a local monitor_tunnel reply, pass info to the user. + * + * @param h Mesh handle. + * @param message Message itself. + */ +static void +process_monitor_tunnel (struct GNUNET_MESH_Handle *h, + const struct GNUNET_MessageHeader *message) +{ +} + + /** * Function to process all messages received from the service * @@ -1345,11 +1369,14 @@ msg_received (void *cls, const struct GNUNET_MessageHeader *msg) case GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR: process_monitor (h, msg); break; + case GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR_TUNNEL: + process_monitor_tunnel (h, msg); + break; default: /* We shouldn't get any other packages, log and ignore */ LOG (GNUNET_ERROR_TYPE_WARNING, - "unsolicited message form service (type %hu)\n", - ntohs (msg->type)); + "unsolicited message form service (type %s)\n", + GNUNET_MESH_DEBUG_M2S (ntohs (msg->type))); } LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n"); if (GNUNET_YES == h->in_receive) @@ -2202,15 +2229,23 @@ GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th) /** * Request information about the running mesh peer. + * The callback will be called for every tunnel known to the service, + * listing all peers that blong to the tunnel (active only). + * + * If called again on the same handle, it will overwrite the previous + * callback and cls. To retrieve the cls, monitor_cancel must be + * called first. + * + * WARNING: unstable API, likely to change in the future! * * @param h Handle to the mesh peer. * @param callback Function to call with the requested data. - * @param monitor_cls Closure for @c callback. + * @param callback_cls Closure for @c callback. */ void GNUNET_MESH_monitor (struct GNUNET_MESH_Handle *h, GNUNET_MESH_MonitorCB callback, - void *monitor_cls) + void *callback_cls) { struct GNUNET_MessageHeader msg; @@ -2218,7 +2253,7 @@ GNUNET_MESH_monitor (struct GNUNET_MESH_Handle *h, msg.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR); send_packet (h, &msg, NULL); h->monitor_cb = callback; - h->monitor_cls = monitor_cls; + h->monitor_cls = callback_cls; return; } @@ -2243,6 +2278,40 @@ GNUNET_MESH_monitor_cancel (struct GNUNET_MESH_Handle *h) } +/** + * Request information about a specific tunnel of the running mesh peer. + * + * WARNING: unstable API, likely to change in the future! + * + * @param h Handle to the mesh peer. + * @param initiator ID of the owner of the tunnel. + * @param tunnel_number Tunnel number. + * @param callback Function to call with the requested data. + * @param callback_cls Closure for @c callback. + */ +void +GNUNET_MESH_monitor_tunnel (struct GNUNET_MESH_Handle *h, + struct GNUNET_PeerIdentity *initiator, + unsigned int tunnel_number, + GNUNET_MESH_MonitorTunnelCB callback, + void *callback_cls) +{ + struct GNUNET_MESH_LocalMonitor msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_MONITOR_TUNNEL); + msg.npeers = htonl (0); + msg.owner = *initiator; + msg.tunnel_id = htonl (tunnel_number); + msg.reserved = 0; + send_packet (h, &msg.header, NULL); + h->tunnel_cb = callback; + h->tunnel_cls = callback_cls; + + return; +} + + /** * Transition API for tunnel ctx management */ -- 2.25.1