X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fmesh_api.c;h=8b1655dde501554967adae4b43e0c0424d4472da;hb=2e155cd114a5b983beabc8d7be31437e9aebd0dc;hp=32996e0db2991797c2fc95f26795f2b45eab735d;hpb=85aebf0bc477953b80f62bd26cd528a8932501a4;p=oweals%2Fgnunet.git diff --git a/src/mesh/mesh_api.c b/src/mesh/mesh_api.c index 32996e0db..8b1655dde 100644 --- a/src/mesh/mesh_api.c +++ b/src/mesh/mesh_api.c @@ -32,7 +32,7 @@ struct tunnel_id { - uint32_t id; + uint32_t id GNUNET_PACKED; struct GNUNET_PeerIdentity initiator; struct GNUNET_PeerIdentity target; }; @@ -46,6 +46,13 @@ struct tunnel_message /* followed by another GNUNET_MessageHeader */ }; +struct notify_cls +{ + void* notify_cls; + GNUNET_CONNECTION_TransmitReadyNotify notify; + struct GNUNET_MESH_Tunnel *tunnel; +}; + struct GNUNET_MESH_Tunnel { /* The other peer this tunnel leads to; just unicast for the moment! */ @@ -53,9 +60,6 @@ struct GNUNET_MESH_Tunnel struct tunnel_id id; - void* notify_cls; - GNUNET_CONNECTION_TransmitReadyNotify notify; - /* The handlers and cls for outbound tunnels. Are NULL for inbound tunnels. */ GNUNET_MESH_TunnelDisconnectHandler disconnect_handler; GNUNET_MESH_TunnelConnectHandler connect_handler; @@ -63,6 +67,11 @@ struct GNUNET_MESH_Tunnel struct GNUNET_MESH_Handle* handle; + /* The message-type requested for this tunnel. Is only needed for pending + * by_tupe-tunnels + */ + uint16_t message_type; + /* The context of the receive-function. */ void *ctx; }; @@ -81,6 +90,13 @@ struct tunnel_list struct peer_list_element { struct GNUNET_PeerIdentity peer; + + /* how many Message-Types can this peer receive */ + unsigned int num_types; + + /* array of message-types */ + GNUNET_MESH_ApplicationType *types; + struct GNUNET_TRANSPORT_ATS_Information atsi; struct peer_list_element *next, *prev; }; @@ -99,10 +115,43 @@ struct GNUNET_MESH_Handle struct peer_list connected_peers; struct tunnel_list established_tunnels; struct tunnel_list pending_tunnels; + struct tunnel_list pending_by_type_tunnels; void *cls; GNUNET_MESH_TunnelEndHandler *cleaner; + size_t hello_message_size; + uint16_t *hello_message; }; +static void +send_end_connect(void* cls, + const struct GNUNET_SCHEDULER_TaskContext* tc) +{ + struct GNUNET_MESH_Tunnel* tunnel = cls; + + tunnel->connect_handler(tunnel->handler_cls, NULL, NULL); +} + +static void +send_self_connect(void* cls, + const struct GNUNET_SCHEDULER_TaskContext* tc) +{ + struct GNUNET_MESH_Tunnel* tunnel = cls; + + tunnel->connect_handler(tunnel->handler_cls, &tunnel->handle->myself, NULL); + GNUNET_SCHEDULER_add_now(send_end_connect, tunnel); +} + +static void +call_connect_handler (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_MESH_Tunnel *tunnel = cls; + + tunnel->connect_handler (tunnel->handler_cls, &tunnel->peer, + NULL); + GNUNET_SCHEDULER_add_now (send_end_connect, tunnel); +} + static void core_startup (void *cls, struct GNUNET_CORE_Handle *core, @@ -114,11 +163,26 @@ core_startup (void *cls, handle->connected_to_core = GNUNET_YES; } +static size_t +send_hello_message (void *cls, size_t size, void *buf) +{ + struct GNUNET_MESH_Handle *handle = cls; + struct GNUNET_MessageHeader *hdr = buf; + + size_t sent = sizeof(struct GNUNET_MessageHeader) + handle->hello_message_size; + + hdr->type = htons(GNUNET_MESSAGE_TYPE_MESH_HELLO); + hdr->size = htons(size); + + memcpy(hdr+1, handle->hello_message, handle->hello_message_size); + return sent; +} + + /** * Core calls this if we are connected to a new peer. * - * If core tells us that we are connected to ourself, we ignore it. Otherwise, the - * peer is added to the connected_peers-list. + * The peer is added to the connected_peers-list. * */ static void @@ -127,18 +191,25 @@ core_connect (void *cls, const struct GNUNET_TRANSPORT_ATS_Information *atsi) { struct GNUNET_MESH_Handle *handle = cls; - /* Check for connect-to-self-message, which we ignore */ - if (0 == - memcmp (peer, &handle->myself, sizeof (struct GNUNET_PeerIdentity))) - return; + /* Send a hello to this peer */ + GNUNET_CORE_notify_transmit_ready(handle->core, + GNUNET_NO, + 42, + GNUNET_TIME_UNIT_SECONDS, + peer, + sizeof(struct GNUNET_MessageHeader) + handle->hello_message_size, + &send_hello_message, + cls); /* put the new peer into the list of connected peers */ struct peer_list_element *element = GNUNET_malloc (sizeof (struct peer_list_element)); memcpy (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity)); - memcpy (&element->atsi, atsi, - sizeof (struct GNUNET_TRANSPORT_ATS_Information)); + + if (NULL != atsi) + memcpy (&element->atsi, atsi, + sizeof (struct GNUNET_TRANSPORT_ATS_Information)); GNUNET_CONTAINER_DLL_insert_after (handle->connected_peers.head, handle->connected_peers.tail, @@ -160,6 +231,7 @@ core_connect (void *cls, tunnel); tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls, peer, atsi); + GNUNET_SCHEDULER_add_now(send_end_connect, tunnel); tunnel = next; } else @@ -190,6 +262,7 @@ core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_CONTAINER_DLL_remove (handle->connected_peers.head, handle->connected_peers.tail, element); + GNUNET_free_non_null(element->types); GNUNET_free (element); } @@ -202,11 +275,11 @@ core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { /* disconnect tunnels */ /* outbound tunnels */ - if (telement->tunnel.connect_handler != NULL) + if (telement->tunnel.connect_handler != NULL && NULL != telement->tunnel.disconnect_handler) telement->tunnel.disconnect_handler (telement->tunnel.handler_cls, peer); /* inbound tunnels */ - else + else if (NULL != handle->cleaner) handle->cleaner (handle->cls, &telement->tunnel, &telement->tunnel.ctx); @@ -224,6 +297,69 @@ core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) } } +/** + * Receive a message from core. + * This is a hello-message, containing the message-types the other peer can receive + */ +static int +receive_hello (void *cls, + const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_TRANSPORT_ATS_Information *atsi) +{ + struct GNUNET_MESH_Handle *handle = cls; + uint16_t *num = (uint16_t *) (message + 1); + uint16_t *ports = num + 1; + unsigned int i; + + struct peer_list_element *element = handle->connected_peers.head; + while (element != NULL) + { + if (0 == + memcmp (&element->peer, other, sizeof (struct GNUNET_PeerIdentity))) + break; + element = element->next; + } + + /* TODO: add, not replace! */ + /* TODO: if this changes anything: send new hello */ + element->num_types = *num; + element->types = GNUNET_malloc (*num * sizeof (GNUNET_MESH_ApplicationType)); + + for (i = 0; i < *num; i++) + element->types[i] = (GNUNET_MESH_ApplicationType)ntohs (ports[i]); + + struct tunnel_list_element *tunnel = handle->pending_by_type_tunnels.head; + while (tunnel != NULL) + { + struct tunnel_list_element *next = tunnel->next; + for (i = 0; i < *num; i++) + { + if (ntohs (ports[i]) == tunnel->tunnel.message_type) + { + GNUNET_CONTAINER_DLL_remove (handle->pending_tunnels.head, + handle->pending_tunnels.tail, + tunnel); + GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels. + head, + handle->established_tunnels. + tail, + handle->established_tunnels. + tail, tunnel); + tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls, + &tunnel->tunnel.peer, atsi); + GNUNET_SCHEDULER_add_now (send_end_connect, tunnel); + break; + } + } + if (ntohs (ports[i]) == tunnel->tunnel.message_type) + tunnel = next; + else + tunnel = tunnel->next; + } + return GNUNET_OK; +} + /** * Receive a message from core. */ @@ -240,11 +376,11 @@ core_receive (void *cls, struct GNUNET_MESH_MessageHandler *handler; - for (handler = handle->handlers; handler != NULL; handler++) + for (handler = handle->handlers; handler->callback != NULL; handler++) { - if (ntohs (rmessage->type) == handler->type - && (handler->expected_size == 0 - || handler->expected_size == ntohs (rmessage->size))) + if ( (ntohs (rmessage->type) == handler->type) + && ( (handler->expected_size == 0) + || (handler->expected_size == ntohs (rmessage->size))) ) { break; } @@ -253,7 +389,7 @@ core_receive (void *cls, /* handler->callback handles this message */ /* If no handler was found, drop the message but keep the channel open */ - if (handler == NULL) + if (handler->callback == NULL) return GNUNET_OK; struct tunnel_list_element *tunnel = handle->established_tunnels.head; @@ -291,9 +427,56 @@ core_receive (void *cls, } return handler->callback (handle->cls, &tunnel->tunnel, - &tunnel->tunnel.ctx, rmessage, atsi); + &tunnel->tunnel.ctx, other, rmessage, atsi); } +struct GNUNET_MESH_Tunnel * +GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Handle *handle, + struct GNUNET_TIME_Relative timeout, + GNUNET_MESH_ApplicationType message_type, + GNUNET_MESH_TunnelConnectHandler + connect_handler, + GNUNET_MESH_TunnelDisconnectHandler + disconnect_handler, + void *handler_cls) +{ + /* Look in the list of connected peers */ + struct peer_list_element *element = handle->connected_peers.head; + while (element != NULL) + { + unsigned int i; + for (i = 0; i < element->num_types; i++) + if (message_type == element->types[i]) + return GNUNET_MESH_peer_request_connect_all (handle, timeout, 1, + &handle->myself, + connect_handler, + disconnect_handler, + handler_cls); + element = element->next; + } + + /* Put into pending list */ + struct tunnel_list_element *tunnel = + GNUNET_malloc (sizeof (struct tunnel_list_element)); + + tunnel->tunnel.connect_handler = connect_handler; + tunnel->tunnel.disconnect_handler = disconnect_handler; + tunnel->tunnel.handler_cls = handler_cls; + tunnel->tunnel.ctx = NULL; + tunnel->tunnel.handle = handle; + memcpy (&tunnel->tunnel.id.initiator, &handle->myself, + sizeof (struct GNUNET_PeerIdentity)); + tunnel->tunnel.id.id = current_id++; + tunnel->tunnel.message_type = message_type; + + GNUNET_CONTAINER_DLL_insert_after (handle->pending_by_type_tunnels.head, + handle->pending_by_type_tunnels.tail, + handle->pending_by_type_tunnels.tail, + tunnel); + return &tunnel->tunnel; +} + + struct GNUNET_MESH_Tunnel * GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle, @@ -321,6 +504,7 @@ GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle, memcpy (&tunnel->tunnel.id.target, peers, sizeof (struct GNUNET_PeerIdentity)); tunnel->tunnel.id.id = current_id++; + memcpy (&tunnel->tunnel.peer, peers, sizeof(struct GNUNET_PeerIdentity)); struct peer_list_element *element = handle->connected_peers.head; while (element != NULL) @@ -338,7 +522,7 @@ GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle, handle->established_tunnels.tail, handle->established_tunnels.tail, tunnel); - connect_handler (handler_cls, &element->peer, &element->atsi); + GNUNET_SCHEDULER_add_now(call_connect_handler, tunnel); } else if (0 == memcmp (peers, &handle->myself, @@ -349,7 +533,7 @@ GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle, handle->established_tunnels.tail, handle->established_tunnels.tail, tunnel); - connect_handler (handler_cls, &handle->myself, NULL); + GNUNET_SCHEDULER_add_now(send_self_connect, tunnel); } else { @@ -358,22 +542,35 @@ GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle, handle->pending_tunnels.tail, handle->pending_tunnels.tail, tunnel); + (void) GNUNET_CORE_peer_request_connect (handle->core, + timeout, + peers, + NULL, NULL); } return &tunnel->tunnel; } +const struct GNUNET_PeerIdentity* +GNUNET_MESH_get_peer(const struct GNUNET_MESH_Tunnel* tunnel) +{ + return &tunnel->peer; +} + static size_t core_notify(void* cls, size_t size, void* buf) { - struct GNUNET_MESH_Tunnel *tunnel = cls; + struct notify_cls *ncls = cls; + struct GNUNET_MESH_Tunnel *tunnel = ncls->tunnel; struct tunnel_message* message = buf; - void* cbuf = (void*)(message + 1); + void* cbuf = (void*) &message[1]; + GNUNET_assert(NULL != ncls->notify); + + size_t sent = ncls->notify(ncls->notify_cls, size - sizeof(struct tunnel_message), cbuf); - size_t sent = tunnel->notify(tunnel->notify_cls, size - sizeof(struct tunnel_message), cbuf); + GNUNET_free(ncls); - tunnel->notify = NULL; - tunnel->notify_cls = NULL; + if (0 == sent) return 0; sent += sizeof(struct tunnel_message); @@ -383,6 +580,28 @@ core_notify(void* cls, size_t size, void* buf) return sent; } + +/** + * Ask the mesh to call "notify" once it is ready to transmit the + * given number of bytes to the specified "target". If we are not yet + * connected to the specified peer, a call to this function will cause + * us to try to establish a connection. + * + * @param tunnel tunnel to use for transmission + * @param cork is corking allowed for this transmission? + * @param priority how important is the message? + * @param maxdelay how long can the message wait? + * @param target destination for the message, NULL for multicast to all tunnel targets + * @param notify_size how many bytes of buffer space does notify want? + * @param notify function to call when buffer space is available; + * will be called with NULL on timeout or if the overall queue + * for this peer is larger than queue_size and this is currently + * the message with the lowest priority + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we can not even queue the request (insufficient + * memory); if NULL is returned, "notify" will NOT be called. + */ struct GNUNET_MESH_TransmitHandle * GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel @@ -392,23 +611,45 @@ GNUNET_MESH_notify_transmit_ready (struct struct GNUNET_TIME_Relative maxdelay, + const struct GNUNET_PeerIdentity *target, size_t notify_size, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { - tunnel->notify_cls = notify_cls; - tunnel->notify = notify; + struct notify_cls *cls = GNUNET_malloc(sizeof(struct notify_cls)); + cls->notify_cls = notify_cls; + GNUNET_assert(NULL != notify); + cls->notify = notify; + cls->tunnel = tunnel; GNUNET_CORE_notify_transmit_ready(tunnel->handle->core, + cork, priority, maxdelay, &tunnel->peer, notify_size + sizeof(struct tunnel_message), - core_notify, - (void*)tunnel); + &core_notify, + (void*)cls); /* aborting is not implemented yet */ - return (struct GNUNET_MESH_TransmitHandle*)1; + return (struct GNUNET_MESH_TransmitHandle*) 1; +} + +void build_hello_message(struct GNUNET_MESH_Handle* handle, int num) +{ + handle->hello_message_size = sizeof(uint16_t) + /* For the number of types */ + num * sizeof(uint16_t); /* For the types */ + + uint16_t *nums = GNUNET_malloc(handle->hello_message_size); + uint16_t *types = nums + 1; + + *nums = num; + + unsigned int i; + for(i = 0; i < num; i++) + types[i] = handle->handlers[i].type; + + handle->hello_message = nums; } @@ -418,7 +659,8 @@ GNUNET_MESH_connect (const struct *cfg, void *cls, GNUNET_MESH_TunnelEndHandler cleaner, - const struct GNUNET_MESH_MessageHandler *handlers) + const struct GNUNET_MESH_MessageHandler *handlers, + const GNUNET_MESH_ApplicationType *stypes) { struct GNUNET_MESH_Handle *ret = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle)); @@ -438,20 +680,24 @@ GNUNET_MESH_connect (const struct ret->handlers = GNUNET_malloc (len * sizeof (struct GNUNET_MESH_MessageHandler)); + memset(ret->handlers, 0, len * sizeof(struct GNUNET_MESH_MessageHandler)); memcpy (ret->handlers, handlers, len * sizeof (struct GNUNET_MESH_MessageHandler)); + build_hello_message(ret, len); + const static struct GNUNET_CORE_MessageHandler core_handlers[] = { - {core_receive, GNUNET_MESSAGE_TYPE_MESH, 0}, + {&core_receive, GNUNET_MESSAGE_TYPE_MESH, 0}, + {&receive_hello, GNUNET_MESSAGE_TYPE_MESH_HELLO, 0}, {NULL, 0, 0} }; ret->core = GNUNET_CORE_connect (cfg, 42, ret, - core_startup, - core_connect, - core_disconnect, + &core_startup, + &core_connect, + &core_disconnect, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, core_handlers); @@ -462,12 +708,14 @@ void GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle) { GNUNET_free (handle->handlers); + GNUNET_free (handle->hello_message); GNUNET_CORE_disconnect (handle->core); struct peer_list_element *element = handle->connected_peers.head; while (element != NULL) { struct peer_list_element *next = element->next; + GNUNET_free_non_null(element->types); GNUNET_free (element); element = next; } @@ -490,4 +738,4 @@ GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle) GNUNET_free (handle); } -/* end of core_api.c */ +/* end of mesh_api.c */