3 This file is part of GNUnet.
4 (C) 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9 GNUnet is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with GNUnet; see the file COPYING. If not, write to the
15 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 Boston, MA 02111-1307, USA.
20 * @file mesh/mesh_api_new.c
21 * @brief mesh api: client implementation of mesh service
22 * @author Bartlomiej Polot
25 * - handle reconnect (service crash/disconnect) properly
26 * - callbacks to client missing on certain events
27 * - processing messages from service is incomplete
32 * - AUXILIARY FUNCTIONS
35 * - API CALL DEFINITIONS
40 #if 0 /* keep Emacsens' auto-indent happy */
46 #include "gnunet_common.h"
47 #include "gnunet_client_lib.h"
48 #include "gnunet_util_lib.h"
49 #include "gnunet_peer_lib.h"
50 #include "gnunet_mesh_service_new.h"
52 #include "mesh_protocol.h"
55 /******************************************************************************/
56 /************************ DATA STRUCTURES ****************************/
57 /******************************************************************************/
60 * Transmission queue to the service
62 struct GNUNET_MESH_TransmitHandle
68 struct GNUNET_MESH_TransmitHandle *next;
73 struct GNUNET_MESH_TransmitHandle *prev;
76 * Tunnel this message is sent over (may be NULL for control messages).
78 struct GNUNET_MESH_Tunnel *tunnel;
81 * Data itself, currently points to the end of this struct if
82 * we have a message already, NULL if the message is to be
83 * obtained from the callback.
85 const struct GNUNET_MessageHeader *data;
88 * Callback to obtain the message to transmit, or NULL if we
89 * got the message in 'data'. Notice that messages built
90 * by 'notify' need to be encapsulated with information about
93 GNUNET_CONNECTION_TransmitReadyNotify notify;
96 * Closure for 'notify'
101 * How long is this message valid. Once the timeout has been
102 * reached, the message must no longer be sent. If this
103 * is a message with a 'notify' callback set, the 'notify'
104 * function should be called with 'buf' NULL and size 0.
106 struct GNUNET_TIME_Absolute timeout;
109 * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
111 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
114 * Priority of the message. The queue is sorted by priority,
115 * control messages have the maximum priority (UINT32_MAX).
120 * Target of the message, 0 for broadcast. This field
121 * is only valid if 'notify' is non-NULL.
123 GNUNET_PEER_Id target;
126 * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
133 * Opaque handle to the service.
135 struct GNUNET_MESH_Handle
139 * Handle to the server connection, to send messages later
141 struct GNUNET_CLIENT_Connection *client;
144 * Set of handlers used for processing incoming messages in the tunnels
146 const struct GNUNET_MESH_MessageHandler *message_handlers;
149 * Set of applications that should be claimed to be offered at this node.
150 * Note that this is just informative, the appropiate handlers must be
151 * registered independently and the mapping is up to the developer of the
152 * client application.
154 const GNUNET_MESH_ApplicationType *applications;
157 * Double linked list of the tunnels this client is connected to.
159 struct GNUNET_MESH_Tunnel *tunnels_head;
160 struct GNUNET_MESH_Tunnel *tunnels_tail;
163 * Callback for tunnel disconnection
165 GNUNET_MESH_TunnelEndHandler *cleaner;
168 * Handle to cancel pending transmissions in case of disconnection
170 struct GNUNET_CLIENT_TransmitHandle *th;
173 * Closure for all the handlers given by the client
178 * Messages to send to the service
180 struct GNUNET_MESH_TransmitHandle *th_head;
181 struct GNUNET_MESH_TransmitHandle *th_tail;
184 * tid of the next tunnel to create (to avoid reusing IDs often)
186 MESH_TunnelNumber next_tid;
187 unsigned int n_handlers;
188 unsigned int n_applications;
189 unsigned int max_queue_size;
192 * Have we started the task to receive messages from the service
193 * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
198 * Number of packets queued
200 unsigned int npackets;
203 * Configuration given by the client, in case of reconnection
205 const struct GNUNET_CONFIGURATION_Handle *cfg;
210 * Description of a peer
212 struct GNUNET_MESH_Peer
215 * ID of the peer in short form
220 * Tunnel this peer belongs to
222 struct GNUNET_MESH_Tunnel *t;
225 * Flag indicating whether service has informed about its connection
233 * Opaque handle to a tunnel.
235 struct GNUNET_MESH_Tunnel
241 struct GNUNET_MESH_Tunnel *next;
242 struct GNUNET_MESH_Tunnel *prev;
245 * Callback to execute when peers connect to the tunnel
247 GNUNET_MESH_TunnelConnectHandler connect_handler;
250 * Callback to execute when peers disconnect to the tunnel
252 GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
255 * All peers added to the tunnel
257 struct GNUNET_MESH_Peer **peers;
260 * Closure for the connect/disconnect handlers
265 * Handle to the mesh this tunnel belongs to
267 struct GNUNET_MESH_Handle *mesh;
270 * Local ID of the tunnel
272 MESH_TunnelNumber tid;
275 * Owner of the tunnel
277 GNUNET_PEER_Id owner;
280 * List of application types that have been requested for this tunnel
282 GNUNET_MESH_ApplicationType *apps;
285 * Number of peers added to the tunnel
290 * Number of packets queued in this tunnel
292 unsigned int npackets;
295 * Number of applications requested this tunnel
302 /******************************************************************************/
303 /*********************** AUXILIARY FUNCTIONS *************************/
304 /******************************************************************************/
307 * Get the tunnel handler for the tunnel specified by id from the given handle
308 * @param h Mesh handle
309 * @param tid ID of the wanted tunnel
310 * @return handle to the required tunnel or NULL if not found
312 static struct GNUNET_MESH_Tunnel *
313 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
315 struct GNUNET_MESH_Tunnel *t;
329 * Get the peer descriptor for the peer with id from the given tunnel
330 * @param t Tunnel handle
331 * @param id Short form ID of the wanted peer
332 * @return handle to the requested peer or NULL if not found
334 static struct GNUNET_MESH_Peer *
335 retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id)
339 for (i = 0; i < t->npeers; i++)
340 if (t->peers[i]->id == id)
347 * Add a peer into a tunnel
348 * @param t Tunnel handle
349 * @param pi Full ID of the new peer
350 * @return handle to the newly created peer
352 static struct GNUNET_MESH_Peer *
353 add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
354 const struct GNUNET_PeerIdentity *pi)
356 struct GNUNET_MESH_Peer *p;
359 id = GNUNET_PEER_intern (pi);
361 p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
364 GNUNET_array_append (t->peers, t->npeers, p);
370 * Remove a peer from a tunnel
371 * @param t Tunnel handle
372 * @param p Peer handle
375 remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p)
379 for (i = 0; i < p->t->npeers; i++)
381 if (p->t->peers[i] == p)
384 if (i == p->t->npeers)
389 p->t->peers[i] = p->t->peers[p->t->npeers - 1];
390 GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1);
395 * Notify client that the transmission has timed out
397 * @param tc task context
400 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
402 struct GNUNET_MESH_TransmitHandle *th = cls;
403 struct GNUNET_MESH_Handle *mesh;
405 mesh = th->tunnel->mesh;
406 GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
407 if (th->notify != NULL)
408 th->notify (th->notify_cls, 0, NULL);
410 if ((NULL == mesh->th_head) && (NULL != mesh->th))
412 /* queue empty, no point in asking for transmission */
413 GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
420 * Add a transmit handle to the transmission queue by priority and set the
423 * @param h mesh handle with the queue head and tail
424 * @param q handle to the packet to be transmitted
427 add_to_queue (struct GNUNET_MESH_Handle *h,
428 struct GNUNET_MESH_TransmitHandle *th)
430 struct GNUNET_MESH_TransmitHandle *p;
433 while ((NULL != p) && (th->priority <= p->priority))
439 GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
440 if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
443 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
444 (th->timeout), &timeout_transmission, th);
449 send_packet (struct GNUNET_MESH_Handle *h,
450 const struct GNUNET_MessageHeader *msg);
454 * Reconnect to the service, retransmit all infomation to try to restore the
457 * @param h handle to the mesh
459 * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
462 reconnect (struct GNUNET_MESH_Handle *h)
464 struct GNUNET_MESH_Tunnel *t;
471 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
473 if (NULL != h->client)
475 GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
479 h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
480 if (h->client == NULL)
482 /* FIXME: panic? exponential backoff retry? */
486 for (t = h->tunnels_head; NULL != t; t = t->next)
489 for (i = 0; i < t->npeers; i++)
491 struct GNUNET_MESH_PeerControl msg;
492 msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
493 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD);
494 msg.tunnel_id = htonl (t->tid);
495 // msg.peer = *peer; FIXME
496 send_packet (t->mesh, &msg.header);
503 /******************************************************************************/
504 /*********************** RECEIVE HANDLERS ****************************/
505 /******************************************************************************/
508 * Process the new tunnel notification and add it to the tunnels in the handle
510 * @param h The mesh handle
511 * @param msg A message with the details of the new incoming tunnel
514 process_tunnel_create (struct GNUNET_MESH_Handle *h,
515 const struct GNUNET_MESH_TunnelMessage *msg)
517 struct GNUNET_MESH_Tunnel *t;
518 MESH_TunnelNumber tid;
520 tid = ntohl (msg->tunnel_id);
521 if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK)
524 return; //FIXME abort? reconnect?
526 t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
535 * Process the new peer event and notify the upper level of it
537 * @param h The mesh handle
538 * @param msg A message with the details of the peer event
541 process_peer_event (struct GNUNET_MESH_Handle *h,
542 const struct GNUNET_MESH_PeerControl *msg)
544 struct GNUNET_MESH_Tunnel *t;
545 struct GNUNET_MESH_Peer *p;
546 struct GNUNET_TRANSPORT_ATS_Information atsi;
550 size = ntohs (msg->header.size);
551 if (size != sizeof (struct GNUNET_MESH_PeerControl))
556 t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
562 id = GNUNET_PEER_search (&msg->peer);
563 if ((p = retrieve_peer (t, id)) == NULL)
564 p = add_peer_to_tunnel (t, &msg->peer);
567 if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED == msg->header.type)
569 if (NULL != t->connect_handler)
571 t->connect_handler (t->cls, &msg->peer, &atsi);
577 if (NULL != t->disconnect_handler && p->connected)
579 t->disconnect_handler (t->cls, &msg->peer);
581 remove_peer_from_tunnel (p);
588 * Process the incoming data packets
590 * @param h The mesh handle
591 * @param msh A message encapsulating the data
594 process_incoming_data (struct GNUNET_MESH_Handle *h,
595 const struct GNUNET_MessageHeader *message)
597 const struct GNUNET_MessageHeader *payload;
598 const struct GNUNET_MESH_MessageHandler *handler;
599 const struct GNUNET_PeerIdentity *peer;
600 struct GNUNET_MESH_Unicast *ucast;
601 struct GNUNET_MESH_Multicast *mcast;
602 struct GNUNET_MESH_ToOrigin *to_orig;
603 struct GNUNET_MESH_Tunnel *t;
607 type = ntohs (message->type);
610 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
611 ucast = (struct GNUNET_MESH_Unicast *) message;
612 t = retrieve_tunnel (h, ntohl (ucast->tid));
613 payload = (struct GNUNET_MessageHeader *) &ucast[1];
616 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
617 mcast = (struct GNUNET_MESH_Multicast *) message;
618 t = retrieve_tunnel (h, ntohl (mcast->tid));
619 payload = (struct GNUNET_MessageHeader *) &mcast[1];
622 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
623 to_orig = (struct GNUNET_MESH_ToOrigin *) message;
624 t = retrieve_tunnel (h, ntohl (to_orig->tid));
625 payload = (struct GNUNET_MessageHeader *) &to_orig[1];
626 peer = &to_orig->sender;
637 for (i = 0; i < h->n_handlers; i++)
639 handler = &h->message_handlers[i];
640 if (handler->type == type)
642 if (GNUNET_OK == handler->callback (h->cls, t, NULL, /* FIXME ctx */
643 peer, payload, NULL))
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646 "MESH: callback completed successfully\n");
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651 "MESH: callback caused disconnection\n");
652 GNUNET_MESH_disconnect (h);
660 * Function to process all messages received from the service
663 * @param msg message received, NULL on timeout or fatal error
666 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
668 struct GNUNET_MESH_Handle *h = cls;
670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message from MESH\n");
674 h->in_receive = GNUNET_NO;
675 // rather: do_reconnect () -- and set 'in_receive' to NO there...
676 // FIXME: service disconnect, handle!
679 switch (ntohs (msg->type))
681 /* Notify of a new incoming tunnel */
682 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
683 process_tunnel_create (h, (struct GNUNET_MESH_TunnelMessage *) msg);
685 /* Notify of a new peer or a peer disconnect in the tunnel */
686 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED:
687 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED:
688 process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
690 /* Notify of a new data packet in the tunnel */
691 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
692 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
693 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
694 process_incoming_data (h, msg);
696 /* We shouldn't get any other packages, log and ignore */
698 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
699 "MESH: unsolicited message form service (type %d)\n",
702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
703 GNUNET_CLIENT_receive (h->client, &msg_received, h,
704 GNUNET_TIME_UNIT_FOREVER_REL);
708 /******************************************************************************/
709 /************************ SEND FUNCTIONS ****************************/
710 /******************************************************************************/
713 * Function called to send a message to the service.
714 * "buf" will be NULL and "size" zero if the socket was closed for writing in
717 * @param cls closure, the mesh handle
718 * @param size number of bytes available in buf
719 * @param buf where the callee should write the connect message
720 * @return number of bytes written to buf
723 send_callback (void *cls, size_t size, void *buf)
725 struct GNUNET_MESH_Handle *h = cls;
726 struct GNUNET_MESH_TransmitHandle *th;
731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
733 if ((0 == size) || (NULL == buf))
735 // FIXME: disconnect, reconnect, retry?
740 while ((NULL != (th = h->th_head)) && (size >= th->size))
742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: type: %u\n",
743 ntohs (th->data->type));
744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: size: %u\n",
745 ntohs (th->data->size));
746 if (NULL == th->data)
748 GNUNET_assert (NULL != th->notify);
752 struct GNUNET_MESH_Multicast mc;
754 GNUNET_assert (size >= sizeof (mc) + th->size);
756 th->notify (th->notify_cls, size - sizeof (mc), &cbuf[sizeof (mc)]);
759 mc.header.size = htons (sizeof (mc) + th->size);
760 mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
761 mc.tid = htonl (th->tunnel->tid);
762 memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); /* myself */
763 memcpy (cbuf, &mc, sizeof (mc));
764 psize = th->size + sizeof (mc);
770 struct GNUNET_MESH_Unicast uc;
772 GNUNET_assert (size >= sizeof (uc) + th->size);
774 th->notify (th->notify_cls, size - sizeof (uc), &cbuf[sizeof (uc)]);
777 uc.header.size = htons (sizeof (uc) + th->size);
778 uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
779 uc.tid = htonl (th->tunnel->tid);
780 memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); /* myself */
781 GNUNET_PEER_resolve (th->target, &uc.destination);
782 memcpy (cbuf, &uc, sizeof (uc));
783 psize = th->size + sizeof (uc);
789 memcpy (cbuf, th->data, th->size);
792 if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
793 GNUNET_SCHEDULER_cancel (th->timeout_task);
794 GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: total size: %u\n", tsize);
801 if (NULL != (th = h->th_head))
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: next size: %u\n", th->size);
805 GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
806 GNUNET_TIME_UNIT_FOREVER_REL,
807 GNUNET_YES, &send_callback, h);
809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
810 if (GNUNET_NO == h->in_receive)
812 h->in_receive = GNUNET_YES;
813 GNUNET_CLIENT_receive (h->client, &msg_received, h,
814 GNUNET_TIME_UNIT_FOREVER_REL);
821 * Auxiliary function to send an already constructed packet to the service.
822 * Takes care of creating a new queue element, copying the message and
823 * calling the tmt_rdy function if necessary.
824 * @param h mesh handle
825 * @param msg message to transmit
828 send_packet (struct GNUNET_MESH_Handle *h,
829 const struct GNUNET_MessageHeader *msg)
831 struct GNUNET_MESH_TransmitHandle *th;
834 msize = ntohs (msg->size);
835 th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
836 th->priority = UINT32_MAX;
837 th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
839 th->data = (void *) &th[1];
840 memcpy (&th[1], msg, msize);
841 add_to_queue (h, th);
845 GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
846 GNUNET_TIME_UNIT_FOREVER_REL,
847 GNUNET_YES, &send_callback, h);
851 /******************************************************************************/
852 /********************** API CALL DEFINITIONS *************************/
853 /******************************************************************************/
856 * Connect to the mesh service.
858 * @param cfg configuration to use
859 * @param cls closure for the various callbacks that follow
860 * (including handlers in the handlers array)
861 * @param queue_size size of the data message queue, shared among all tunnels
862 * (each tunnel is guaranteed to accept at least one message,
863 * no matter what is the status of other tunnels)
864 * @param cleaner function called when an *inbound* tunnel is destroyed
865 * @param handlers callbacks for messages we care about, NULL-terminated
866 * note that the mesh is allowed to drop notifications about
867 * inbound messages if the client does not process them fast
868 * enough (for this notification type, a bounded queue is used)
869 * @param stypes Application Types the client claims to offer
870 * @return handle to the mesh service
871 * NULL on error (in this case, init is never called)
873 struct GNUNET_MESH_Handle *
874 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
875 unsigned int queue_size, void *cls,
876 GNUNET_MESH_TunnelEndHandler cleaner,
877 const struct GNUNET_MESH_MessageHandler *handlers,
878 const GNUNET_MESH_ApplicationType *stypes)
880 struct GNUNET_MESH_Handle *h;
881 struct GNUNET_MESH_ClientConnect *msg;
882 GNUNET_MESH_ApplicationType *apps;
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
889 h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
891 h->max_queue_size = queue_size;
892 h->cleaner = cleaner;
893 h->client = GNUNET_CLIENT_connect ("mesh", cfg);
894 if (h->client == NULL)
901 h->message_handlers = handlers;
902 h->applications = stypes;
903 h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;
905 /* count handlers and apps, calculate size */
906 for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
907 for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
908 size = sizeof (struct GNUNET_MESH_ClientConnect);
909 size += h->n_handlers * sizeof (uint16_t);
910 size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
915 /* build connection packet */
916 msg = (struct GNUNET_MESH_ClientConnect *) buf;
917 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
918 msg->header.size = htons (size);
919 types = (uint16_t *) & msg[1];
920 for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
921 types[ntypes] = h->message_handlers[ntypes].type;
922 apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
923 for (napps = 0; napps < h->n_applications; napps++)
924 apps[napps] = h->applications[napps];
925 msg->applications = htons (napps);
926 msg->types = htons (ntypes);
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928 "mesh: Sending %lu bytes long message %d types and %d apps\n",
929 ntohs (msg->header.size), ntypes, napps);
930 send_packet (h, &msg->header);
932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
938 * Disconnect from the mesh service.
940 * @param handle connection to mesh to disconnect
943 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
945 if (NULL != handle->th)
947 GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
949 if (NULL != handle->client)
951 GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
953 GNUNET_free (handle);
958 * Create a new tunnel (we're initiator and will be allowed to add/remove peers
961 * @param h mesh handle
962 * @param connect_handler function to call when peers are actually connected
963 * @param disconnect_handler function to call when peers are disconnected
964 * @param handler_cls closure for connect/disconnect handlers
966 struct GNUNET_MESH_Tunnel *
967 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
968 GNUNET_MESH_TunnelConnectHandler connect_handler,
969 GNUNET_MESH_TunnelDisconnectHandler
970 disconnect_handler, void *handler_cls)
972 struct GNUNET_MESH_Tunnel *t;
973 struct GNUNET_MESH_TunnelMessage msg;
975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
976 t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
977 t->connect_handler = connect_handler;
978 t->disconnect_handler = disconnect_handler;
979 t->cls = handler_cls;
981 t->tid = h->next_tid++;
982 h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK; // keep in range
983 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
984 msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
985 msg.tunnel_id = htonl (t->tid);
986 send_packet (h, &msg.header);
992 * Destroy an existing tunnel.
994 * @param tun tunnel handle
997 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tun)
999 struct GNUNET_MESH_Handle *h;
1000 struct GNUNET_MESH_TunnelMessage msg;
1002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
1005 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
1006 msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1007 msg.tunnel_id = htonl (tun->tid);
1009 send_packet (h, &msg.header);
1014 * Request that a peer should be added to the tunnel. The existing
1015 * connect handler will be called ONCE with either success or failure.
1016 * This function should NOT be called again with the same peer before the
1017 * connect handler is called.
1019 * @param tunnel handle to existing tunnel
1020 * @param timeout how long to try to establish a connection
1021 * @param peer peer to add
1024 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
1025 const struct GNUNET_PeerIdentity *peer)
1027 struct GNUNET_MESH_PeerControl msg;
1028 GNUNET_PEER_Id peer_id;
1031 peer_id = GNUNET_PEER_intern (peer);
1032 for (i = 0; i < tunnel->npeers; i++)
1034 if (tunnel->peers[i]->id == peer_id)
1036 GNUNET_PEER_change_rc (peer_id, -1);
1041 add_peer_to_tunnel (tunnel, peer);
1043 msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1044 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD);
1045 msg.tunnel_id = htonl (tunnel->tid);
1047 send_packet (tunnel->mesh, &msg.header);
1054 * Request that a peer should be removed from the tunnel. The existing
1055 * disconnect handler will be called ONCE if we were connected.
1057 * @param tunnel handle to existing tunnel
1058 * @param peer peer to remove
1061 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
1062 const struct GNUNET_PeerIdentity *peer)
1064 struct GNUNET_MESH_PeerControl msg;
1065 GNUNET_PEER_Id peer_id;
1068 peer_id = GNUNET_PEER_search (peer);
1074 for (i = 0; i < tunnel->npeers; i++)
1075 if (tunnel->peers[i]->id == peer_id)
1077 if (i == tunnel->npeers)
1082 if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1)
1083 tunnel->disconnect_handler (tunnel->cls, peer);
1084 GNUNET_PEER_change_rc (peer_id, -1);
1085 GNUNET_free (tunnel->peers[i]);
1086 tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
1087 GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
1089 msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1090 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL);
1091 msg.tunnel_id = htonl (tunnel->tid);
1092 memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1093 send_packet (tunnel->mesh, &msg.header);
1098 * Request that the mesh should try to connect to a peer supporting the given
1101 * @param tunnel handle to existing tunnel
1102 * @param app_type application type that must be supported by the peer (MESH
1103 * should discover peer in proximity handling this type)
1106 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
1107 GNUNET_MESH_ApplicationType app_type)
1109 struct GNUNET_MESH_ConnectPeerByType msg;
1111 GNUNET_array_append(tunnel->apps, tunnel->napps, app_type);
1112 /* FIXME: add a new api call disconnect by type? */
1114 msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
1115 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE);
1116 msg.tunnel_id = htonl (tunnel->tid);
1117 msg.type = htonl (app_type);
1118 send_packet (tunnel->mesh, &msg.header);
1123 * Ask the mesh to call "notify" once it is ready to transmit the
1124 * given number of bytes to the specified "target". If we are not yet
1125 * connected to the specified peer, a call to this function will cause
1126 * us to try to establish a connection.
1128 * @param tunnel tunnel to use for transmission
1129 * @param cork is corking allowed for this transmission?
1130 * @param priority how important is the message?
1131 * @param maxdelay how long can the message wait?
1132 * @param target destination for the message,
1133 * NULL for multicast to all tunnel targets
1134 * @param notify_size how many bytes of buffer space does notify want?
1135 * @param notify function to call when buffer space is available;
1136 * will be called with NULL on timeout or if the overall queue
1137 * for this peer is larger than queue_size and this is currently
1138 * the message with the lowest priority
1139 * @param notify_cls closure for notify
1140 * @return non-NULL if the notify callback was queued,
1141 * NULL if we can not even queue the request (insufficient
1142 * memory); if NULL is returned, "notify" will NOT be called.
1144 struct GNUNET_MESH_TransmitHandle *
1145 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1147 struct GNUNET_TIME_Relative maxdelay,
1148 const struct GNUNET_PeerIdentity *target,
1150 GNUNET_CONNECTION_TransmitReadyNotify notify,
1153 struct GNUNET_MESH_TransmitHandle *th;
1156 if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
1157 tunnel->npackets > 0)
1158 return NULL; /* queue full */
1160 tunnel->mesh->npackets++;
1161 th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1162 th->tunnel = tunnel;
1163 th->priority = priority;
1164 th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1165 th->target = GNUNET_PEER_intern (target);
1168 target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct
1169 GNUNET_MESH_Unicast);
1170 th->size = notify_size + overhead;
1171 th->notify = notify;
1172 th->notify_cls = notify_cls;
1173 add_to_queue (tunnel->mesh, th);
1179 * Cancel the specified transmission-ready notification.
1181 * @param th handle that was returned by "notify_transmit_ready".
1184 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1186 struct GNUNET_MESH_Handle *mesh;
1188 mesh = th->tunnel->mesh;
1189 if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1190 GNUNET_SCHEDULER_cancel (th->timeout_task);
1191 GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1193 if ((NULL == mesh->th_head) && (NULL != mesh->th))
1195 /* queue empty, no point in asking for transmission */
1196 GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1202 #if 0 /* keep Emacsens' auto-indent happy */