X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fmesh_api.c;h=8b1655dde501554967adae4b43e0c0424d4472da;hb=2e155cd114a5b983beabc8d7be31437e9aebd0dc;hp=f714d32bb2f91c6ad6606fb0ed91f5a09afe0cd3;hpb=69d9f80b83053162a38a292fc8a024acb6a463a9;p=oweals%2Fgnunet.git diff --git a/src/mesh/mesh_api.c b/src/mesh/mesh_api.c index f714d32bb..8b1655dde 100644 --- a/src/mesh/mesh_api.c +++ b/src/mesh/mesh_api.c @@ -67,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; }; @@ -85,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; }; @@ -103,8 +115,11 @@ 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 @@ -126,6 +141,17 @@ send_self_connect(void* cls, 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, @@ -137,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 @@ -150,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, @@ -214,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); } @@ -248,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. */ @@ -315,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, @@ -363,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, @@ -386,7 +545,7 @@ GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle, (void) GNUNET_CORE_peer_request_connect (handle->core, timeout, peers, - NULL, NULL); + NULL, NULL); } return &tunnel->tunnel; @@ -421,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 @@ -430,6 +611,7 @@ GNUNET_MESH_notify_transmit_ready (struct struct GNUNET_TIME_Relative maxdelay, + const struct GNUNET_PeerIdentity *target, size_t notify_size, GNUNET_CONNECTION_TransmitReadyNotify @@ -441,6 +623,7 @@ GNUNET_MESH_notify_transmit_ready (struct cls->notify = notify; cls->tunnel = tunnel; GNUNET_CORE_notify_transmit_ready(tunnel->handle->core, + cork, priority, maxdelay, &tunnel->peer, @@ -452,6 +635,23 @@ GNUNET_MESH_notify_transmit_ready (struct 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; +} + struct GNUNET_MESH_Handle * GNUNET_MESH_connect (const struct @@ -459,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)); @@ -483,8 +684,11 @@ GNUNET_MESH_connect (const struct 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}, + {&receive_hello, GNUNET_MESSAGE_TYPE_MESH_HELLO, 0}, {NULL, 0, 0} }; @@ -504,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; }