2 This file is part of GNUnet.
3 (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.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file mesh/mesh_api_new.c
23 * @brief mesh api: client implementation of mesh service
24 * @author Bartlomiej Polot
27 * - handle reconnect (service crash/disconnect) properly
28 * - count only data for queue length; store current queue length
29 * with tunnel instead of counting each time
30 * (also count per tunnel instead of for the entire mesh handle?)
31 * - callbacks to client missing on certain events
32 * - processing messages from service is incomplete
37 * - AUXILIARY FUNCTIONS
40 * - API CALL DEFINITIONS
47 #if 0 /* keep Emacsens' auto-indent happy */
54 #include "gnunet_common.h"
55 #include "gnunet_client_lib.h"
56 #include "gnunet_util_lib.h"
57 #include "gnunet_peer_lib.h"
58 #include "gnunet_mesh_service_new.h"
60 #include "mesh_protocol.h"
63 * TODO: replace with extra argument to mesh-connect.
65 #define MESH_API_MAX_QUEUE 10
67 /******************************************************************************/
68 /************************ DATA STRUCTURES ****************************/
69 /******************************************************************************/
72 * Transmission queue to the service
74 struct GNUNET_MESH_TransmitHandle
79 struct GNUNET_MESH_TransmitHandle *next;
84 struct GNUNET_MESH_TransmitHandle *prev;
87 * Data itself, currently points to the end of this struct if
88 * we have a message already, NULL if the message is to be
89 * obtained from the callback.
91 const struct GNUNET_MessageHeader *data;
94 * Tunnel this message is sent over (may be NULL for control messages).
96 struct GNUNET_MESH_Tunnel *tunnel;
99 * Callback to obtain the message to transmit, or NULL if we
100 * got the message in 'data'. Notice that messages built
101 * by 'notify' need to be encapsulated with information about
104 GNUNET_CONNECTION_TransmitReadyNotify notify;
107 * Closure for 'notify'
112 * How long is this message valid. Once the timeout has been
113 * reached, the message must no longer be sent. If this
114 * is a message with a 'notify' callback set, the 'notify'
115 * function should be called with 'buf' NULL and size 0.
117 struct GNUNET_TIME_Absolute timeout;
120 * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
122 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
125 * Priority of the message. The queue is sorted by priority,
126 * control messages have the maximum priority (UINT32_MAX).
131 * Target of the message, 0 for broadcast. This field
132 * is only valid if 'notify' is non-NULL.
134 GNUNET_PEER_Id target;
137 * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
144 * Opaque handle to the service.
146 struct GNUNET_MESH_Handle
149 * Handle to the server connection, to send messages later
151 struct GNUNET_CLIENT_Connection *client;
154 * Set of handlers used for processing incoming messages in the tunnels
156 const struct GNUNET_MESH_MessageHandler *message_handlers;
159 * Set of applications that should be claimed to be offered at this node.
160 * Note that this is just informative, the appropiate handlers must be
161 * registered independently and the mapping is up to the developer of the
162 * client application.
164 const GNUNET_MESH_ApplicationType *applications;
167 * Double linked list of the tunnels this client is connected to.
169 struct GNUNET_MESH_Tunnel *tunnels_head;
170 struct GNUNET_MESH_Tunnel *tunnels_tail;
173 * Callback for tunnel disconnection
175 GNUNET_MESH_TunnelEndHandler *cleaner;
178 * Handle to cancel pending transmissions in case of disconnection
180 struct GNUNET_CLIENT_TransmitHandle *th;
183 * Closure for all the handlers given by the client
188 * Messages to send to the service
190 struct GNUNET_MESH_TransmitHandle *queue_head;
191 struct GNUNET_MESH_TransmitHandle *queue_tail;
194 * tid of the next tunnel to create (to avoid reusing IDs often)
196 MESH_TunnelNumber next_tid;
198 unsigned int n_handlers;
200 unsigned int n_applications;
202 unsigned int max_queue_size;
205 * Have we started the task to receive messages from the service
206 * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
212 * Opaque handle to a tunnel.
214 struct GNUNET_MESH_Tunnel
220 struct GNUNET_MESH_Tunnel *next;
221 struct GNUNET_MESH_Tunnel *prev;
224 * Callback to execute when peers connect to the tunnel
226 GNUNET_MESH_TunnelConnectHandler connect_handler;
229 * Callback to execute when peers disconnect to the tunnel
231 GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
234 * All peers added to the tunnel
236 GNUNET_PEER_Id *peers;
239 * Closure for the connect/disconnect handlers
244 * Handle to the mesh this tunnel belongs to
246 struct GNUNET_MESH_Handle *mesh;
249 * Local ID of the tunnel
251 MESH_TunnelNumber tid;
254 * Owner of the tunnel
256 GNUNET_PEER_Id owner;
259 * Number of peer added to the tunnel
265 /******************************************************************************/
266 /*********************** AUXILIARY FUNCTIONS *************************/
267 /******************************************************************************/
270 * Get the tunnel handler for the tunnel specified by id from the given handle
271 * @param h Mesh handle
272 * @param tid ID of the wanted tunnel
273 * @return handle to the required tunnel or NULL if not found
275 static struct GNUNET_MESH_Tunnel *
276 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
278 struct GNUNET_MESH_Tunnel *t;
291 * Get the length of the transmission queue
292 * @param h mesh handle whose queue is to be measured
295 get_queue_length (struct GNUNET_MESH_Handle *h)
297 struct GNUNET_MESH_TransmitHandle *q;
301 for (q = h->queue_head, i = 0; NULL != q; q = q->next, i++) ;
307 /******************************************************************************/
308 /*********************** RECEIVE HANDLERS ****************************/
309 /******************************************************************************/
312 * Process the new tunnel notification and add it to the tunnels in the handle
314 * @param h The mesh handle
315 * @param msg A message with the details of the new incoming tunnel
318 process_tunnel_create (struct GNUNET_MESH_Handle *h,
319 const struct GNUNET_MESH_TunnelMessage *msg)
321 struct GNUNET_MESH_Tunnel *t;
322 MESH_TunnelNumber tid;
324 tid = ntohl (msg->tunnel_id);
325 if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK)
327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
328 "MESH: received an incoming tunnel with tid in local range (%X)\n",
331 return; //FIXME abort? reconnect?
333 t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
343 * Process the new peer event and notify the upper level of it
345 * @param h The mesh handle
346 * @param msg A message with the details of the peer event
349 process_peer_event (struct GNUNET_MESH_Handle *h,
350 const struct GNUNET_MESH_PeerControl *msg)
352 struct GNUNET_MESH_Tunnel *t;
355 size = ntohs (msg->header.size);
356 if (size != sizeof (struct GNUNET_MESH_PeerControl))
361 t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
367 if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED == msg->header.type)
369 if (NULL != t->connect_handler)
371 t->connect_handler (t->cls, &msg->peer, NULL); /* FIXME atsi */
376 if (NULL != t->disconnect_handler)
378 t->disconnect_handler (t->cls, &msg->peer);
385 * Process the incoming data packets
387 * @param h The mesh handle
388 * @param msh A message encapsulating the data
391 process_incoming_data (struct GNUNET_MESH_Handle *h,
392 const struct GNUNET_MessageHeader *message)
394 const struct GNUNET_MessageHeader *payload;
395 const struct GNUNET_MESH_MessageHandler *handler;
396 const struct GNUNET_PeerIdentity *peer;
397 struct GNUNET_MESH_Unicast *ucast;
398 struct GNUNET_MESH_Multicast *mcast;
399 struct GNUNET_MESH_ToOrigin *to_orig;
400 struct GNUNET_MESH_Tunnel *t;
404 type = ntohs (message->type);
407 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
408 ucast = (struct GNUNET_MESH_Unicast *) message;
409 t = retrieve_tunnel (h, ntohl (ucast->tid));
410 payload = (struct GNUNET_MessageHeader *) &ucast[1];
413 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
414 mcast = (struct GNUNET_MESH_Multicast *) message;
415 t = retrieve_tunnel (h, ntohl (mcast->tid));
416 payload = (struct GNUNET_MessageHeader *) &mcast[1];
419 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
420 to_orig = (struct GNUNET_MESH_ToOrigin *) message;
421 t = retrieve_tunnel (h, ntohl (to_orig->tid));
422 payload = (struct GNUNET_MessageHeader *) &to_orig[1];
423 peer = &to_orig->sender;
434 for (i = 0; i < h->n_handlers; i++)
436 handler = &h->message_handlers[i];
437 if (handler->type == type)
439 if (GNUNET_OK == handler->callback (h->cls, t, NULL, /* FIXME ctx */
440 peer, payload, NULL)) /* FIXME atsi */
442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443 "MESH: callback completed successfully\n");
447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 "MESH: callback caused disconnection\n");
449 GNUNET_MESH_disconnect (h);
457 * Function to process all messages received from the service
460 * @param msg message received, NULL on timeout or fatal error
463 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
465 struct GNUNET_MESH_Handle *h = cls;
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message from MESH\n");
471 h->in_receive = GNUNET_NO;
472 // rather: do_reconnect () -- and set 'in_receive' to NO there...
473 // FIXME: service disconnect, handle!
477 switch (ntohs (msg->type))
479 /* Notify of a new incoming tunnel */
480 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
481 process_tunnel_create (h, (struct GNUNET_MESH_TunnelMessage *) msg);
483 /* Notify of a new peer or a peer disconnect in the tunnel */
484 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED:
485 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED:
486 process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
488 /* Notify of a new data packet in the tunnel */
489 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
490 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
491 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
492 process_incoming_data (h, msg);
494 /* We shouldn't get any other packages, log and ignore */
496 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
497 "MESH: unsolicited message form service (type %d)\n",
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
502 GNUNET_CLIENT_receive (h->client, &msg_received, h,
503 GNUNET_TIME_UNIT_FOREVER_REL);
507 /******************************************************************************/
508 /************************ SEND FUNCTIONS ****************************/
509 /******************************************************************************/
512 * Function called to send a message to the service.
513 * "buf" will be NULL and "size" zero if the socket was closed for writing in
516 * @param cls closure, the mesh handle
517 * @param size number of bytes available in buf
518 * @param buf where the callee should write the connect message
519 * @return number of bytes written to buf
522 send_raw (void *cls, size_t size, void *buf)
524 struct GNUNET_MESH_Handle *h = cls;
525 struct GNUNET_MESH_TransmitHandle *q;
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
532 if ( (0 == size) || (NULL == buf) )
534 // FIXME: disconnect, reconnect, retry?
539 while ( (NULL != (q = h->queue_head)) &&
542 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
545 ntohs (q->data->type));
548 GNUNET_assert (NULL != q->notify);
552 struct GNUNET_MESH_Multicast mc;
554 GNUNET_assert (size >= sizeof (mc) + q->size);
555 psize = q->notify (q->notify_cls,
560 mc.header.size = htons (sizeof (mc) + q->size);
561 mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
562 mc.tid = htonl (q->tunnel->tid);
563 memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); /* myself */
564 memcpy (cbuf, &mc, sizeof (mc));
565 psize = q->size + sizeof (mc);
571 struct GNUNET_MESH_Unicast uc;
573 GNUNET_assert (size >= sizeof (uc) + q->size);
574 psize = q->notify (q->notify_cls,
579 uc.header.size = htons (sizeof (uc) + q->size);
580 uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
581 uc.tid = htonl (q->tunnel->tid);
582 memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); /* myself */
583 GNUNET_PEER_resolve (q->target, &uc.destination);
584 memcpy (cbuf, &uc, sizeof (uc));
585 psize = q->size + sizeof (uc);
591 memcpy (cbuf, q->data, q->size);
594 if (q->timeout_task != GNUNET_SCHEDULER_NO_TASK)
595 GNUNET_SCHEDULER_cancel (q->timeout_task);
596 GNUNET_CONTAINER_DLL_remove (h->queue_head, h->queue_tail, q);
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: size: %u\n", ret);
605 if (NULL != (q = h->queue_head))
607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: next size: %u\n",
610 GNUNET_CLIENT_notify_transmit_ready (h->client, q->size,
611 GNUNET_TIME_UNIT_FOREVER_REL,
612 GNUNET_YES, &send_raw, h);
614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
615 if (GNUNET_NO == h->in_receive)
617 h->in_receive = GNUNET_YES;
618 GNUNET_CLIENT_receive (h->client, &msg_received, h,
619 GNUNET_TIME_UNIT_FOREVER_REL);
626 timeout_transmission (void *cls,
627 const struct GNUNET_SCHEDULER_TaskContext *tc)
629 struct GNUNET_MESH_TransmitHandle *q = cls;
630 struct GNUNET_MESH_Handle *mesh;
632 mesh = q->tunnel->mesh;
633 GNUNET_CONTAINER_DLL_remove (mesh->queue_head,
636 if (q->notify != NULL)
637 q->notify (q->notify_cls, 0, NULL); /* signal timeout */
639 if ( (NULL == mesh->queue_head) &&
642 /* queue empty, no point in asking for transmission */
643 GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
650 * Add a transmit handle to the transmission queue (by priority).
651 * Also manage timeout.
653 * @param h mesh handle with the queue head and tail
654 * @param q handle to add
657 queue_transmit_handle (struct GNUNET_MESH_Handle *h,
658 struct GNUNET_MESH_TransmitHandle *q)
660 struct GNUNET_MESH_TransmitHandle *p;
663 while ( (NULL != p) && (q->priority < p->priority) )
665 GNUNET_CONTAINER_DLL_insert_after (h->queue_head, h->queue_tail, p->prev, q);
666 if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value != q->timeout.abs_value)
667 q->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (q->timeout),
668 &timeout_transmission,
674 * Auxiliary function to send a packet to the service
675 * Takes care of creating a new queue element and calling the tmt_rdy function
677 * @param h mesh handle
678 * @param msg message to transmit
681 send_packet (struct GNUNET_MESH_Handle *h,
682 const struct GNUNET_MessageHeader *msg)
684 struct GNUNET_MESH_TransmitHandle *q;
687 msize = ntohs (msg->size);
688 q = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
689 q->priority = UINT32_MAX;
690 q->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
692 q->data = (void*) &q[1];
693 memcpy (&q[1], msg, msize);
694 queue_transmit_handle (h, q);
698 GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
699 GNUNET_TIME_UNIT_FOREVER_REL,
700 GNUNET_YES, &send_raw, h);
703 /******************************************************************************/
704 /********************** API CALL DEFINITIONS *************************/
705 /******************************************************************************/
708 * Connect to the mesh service.
710 * @param cfg configuration to use
711 * @param cls closure for the various callbacks that follow
712 * (including handlers in the handlers array)
713 * @param cleaner function called when an *inbound* tunnel is destroyed
714 * @param handlers callbacks for messages we care about, NULL-terminated
715 * note that the mesh is allowed to drop notifications about
716 * inbound messages if the client does not process them fast
717 * enough (for this notification type, a bounded queue is used)
718 * @param stypes Application Types the client claims to offer
719 * @return handle to the mesh service
720 * NULL on error (in this case, init is never called)
722 struct GNUNET_MESH_Handle *
723 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
724 GNUNET_MESH_TunnelEndHandler cleaner,
725 const struct GNUNET_MESH_MessageHandler *handlers,
726 const GNUNET_MESH_ApplicationType *stypes)
728 struct GNUNET_MESH_Handle *h;
729 struct GNUNET_MESH_ClientConnect *msg;
730 GNUNET_MESH_ApplicationType *apps;
736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
737 h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
738 h->max_queue_size = MESH_API_MAX_QUEUE; /* FIXME: add to arguments to 'GNUNET_MESH_connect' */
739 h->cleaner = cleaner;
740 h->client = GNUNET_CLIENT_connect ("mesh", cfg);
741 if (h->client == NULL)
749 h->message_handlers = handlers;
750 h->applications = stypes;
751 h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;
753 /* count handlers and apps, calculate size */
754 for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
755 for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
757 size = sizeof (struct GNUNET_MESH_ClientConnect);
758 size += h->n_handlers * sizeof (uint16_t);
759 size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
764 /* build connection packet */
765 msg = (struct GNUNET_MESH_ClientConnect *) buf;
766 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
767 msg->header.size = htons (size);
768 types = (uint16_t *) & msg[1];
769 for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
770 types[ntypes] = h->message_handlers[ntypes].type;
771 apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
772 for (napps = 0; napps < h->n_applications; napps++)
773 apps[napps] = h->applications[napps];
774 msg->applications = htons (napps);
775 msg->types = htons (ntypes);
777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778 "mesh: Sending %lu bytes long message %d types and %d apps\n",
779 ntohs (msg->header.size), ntypes, napps);
781 send_packet (h, &msg->header);
784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
791 * Disconnect from the mesh service.
793 * @param handle connection to mesh to disconnect
796 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
798 if (NULL != handle->th)
800 GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
802 if (NULL != handle->client)
804 GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
806 GNUNET_free (handle);
811 * Create a new tunnel (we're initiator and will be allowed to add/remove peers
814 * @param h mesh handle
815 * @param connect_handler function to call when peers are actually connected
816 * @param disconnect_handler function to call when peers are disconnected
817 * @param handler_cls closure for connect/disconnect handlers
819 struct GNUNET_MESH_Tunnel *
820 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
821 GNUNET_MESH_TunnelConnectHandler connect_handler,
822 GNUNET_MESH_TunnelDisconnectHandler
823 disconnect_handler, void *handler_cls)
825 struct GNUNET_MESH_Tunnel *t;
826 struct GNUNET_MESH_TunnelMessage msg;
828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
829 t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
831 t->connect_handler = connect_handler;
832 t->disconnect_handler = disconnect_handler;
833 t->cls = handler_cls;
835 t->tid = h->next_tid++;
836 h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK; // keep in range
838 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
839 msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
840 msg.tunnel_id = htonl (t->tid);
841 send_packet (h, &msg.header);
847 * Destroy an existing tunnel.
849 * @param tun tunnel handle
852 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tun)
854 struct GNUNET_MESH_Handle *h;
855 struct GNUNET_MESH_TunnelMessage *msg;
857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
860 msg = GNUNET_malloc (sizeof (struct GNUNET_MESH_TunnelMessage));
861 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
862 msg->header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
863 msg->tunnel_id = htonl (tun->tid);
867 send_packet (h, &msg->header);
872 * Request that a peer should be added to the tunnel. The existing
873 * connect handler will be called ONCE with either success or failure.
875 * @param tunnel handle to existing tunnel
876 * @param timeout how long to try to establish a connection
877 * @param peer peer to add
880 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
881 struct GNUNET_TIME_Relative timeout,
882 const struct GNUNET_PeerIdentity *peer)
884 struct GNUNET_MESH_PeerControl *msg;
885 GNUNET_PEER_Id peer_id;
888 peer_id = GNUNET_PEER_intern (peer);
889 for (i = 0; i < tunnel->npeers; i++)
891 if (tunnel->peers[i] == peer_id)
893 GNUNET_PEER_change_rc (peer_id, -1);
899 GNUNET_realloc (tunnel->peers, tunnel->npeers * sizeof (GNUNET_PEER_Id));
900 tunnel->peers[tunnel->npeers - 1] = peer_id;
902 msg = GNUNET_malloc (sizeof (struct GNUNET_MESH_PeerControl));
903 msg->header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
904 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD);
905 msg->tunnel_id = htonl (tunnel->tid);
906 msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (timeout));
907 memcpy (&msg->peer, peer, sizeof (struct GNUNET_PeerIdentity));
909 send_packet (tunnel->mesh, &msg->header);
911 // tunnel->connect_handler (tunnel->cls, peer, NULL); FIXME call this later
912 // TODO: remember timeout
918 * Request that a peer should be removed from the tunnel. The existing
919 * disconnect handler will be called ONCE if we were connected.
921 * @param tunnel handle to existing tunnel
922 * @param peer peer to remove
925 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
926 const struct GNUNET_PeerIdentity *peer)
928 struct GNUNET_MESH_PeerControl msg;
929 GNUNET_PEER_Id peer_id;
932 peer_id = GNUNET_PEER_search (peer);
938 for (i = 0; i < tunnel->npeers; i++)
939 if (tunnel->peers[i] == peer_id)
941 if (i == tunnel->npeers)
946 GNUNET_PEER_change_rc (peer_id, -1);
947 tunnel->peers[i] = tunnel->peers[tunnel->npeers-1];
948 GNUNET_array_grow (tunnel->peers,
951 msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
952 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL);
953 msg.tunnel_id = htonl (tunnel->tid);
954 msg.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
955 memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
956 send_packet (tunnel->mesh, &msg.header);
961 * Request that the mesh should try to connect to a peer supporting the given
964 * @param tunnel handle to existing tunnel
965 * @param timeout how long to try to establish a connection
966 * @param app_type application type that must be supported by the peer (MESH
967 * should discover peer in proximity handling this type)
970 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
971 struct GNUNET_TIME_Relative timeout,
972 GNUNET_MESH_ApplicationType app_type)
974 struct GNUNET_MESH_ConnectPeerByType msg;
976 /* FIXME: remember request connect by type for reconnect! */
977 msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
978 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE);
979 msg.tunnel_id = htonl (tunnel->tid);
980 msg.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (timeout));
981 msg.type = htonl (app_type);
982 send_packet (tunnel->mesh, &msg.header);
987 * Ask the mesh to call "notify" once it is ready to transmit the
988 * given number of bytes to the specified "target". If we are not yet
989 * connected to the specified peer, a call to this function will cause
990 * us to try to establish a connection.
992 * @param tunnel tunnel to use for transmission
993 * @param cork is corking allowed for this transmission?
994 * @param priority how important is the message?
995 * @param maxdelay how long can the message wait?
996 * @param target destination for the message,
997 * NULL for multicast to all tunnel targets
998 * @param notify_size how many bytes of buffer space does notify want?
999 * @param notify function to call when buffer space is available;
1000 * will be called with NULL on timeout or if the overall queue
1001 * for this peer is larger than queue_size and this is currently
1002 * the message with the lowest priority
1003 * @param notify_cls closure for notify
1004 * @return non-NULL if the notify callback was queued,
1005 * NULL if we can not even queue the request (insufficient
1006 * memory); if NULL is returned, "notify" will NOT be called.
1008 struct GNUNET_MESH_TransmitHandle *
1009 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1011 struct GNUNET_TIME_Relative maxdelay,
1012 const struct GNUNET_PeerIdentity *target,
1014 GNUNET_CONNECTION_TransmitReadyNotify notify,
1017 struct GNUNET_MESH_TransmitHandle *q;
1020 if (get_queue_length (tunnel->mesh) >= tunnel->mesh->max_queue_size)
1021 return NULL; /* queue full */
1023 q = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1025 q->priority = priority;
1026 q->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1027 q->target = GNUNET_PEER_intern (target);
1028 overhead = (NULL == target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct GNUNET_MESH_Unicast);
1029 q->size = notify_size + overhead;
1031 q->notify_cls = notify_cls;
1032 queue_transmit_handle (tunnel->mesh, q);
1038 * Cancel the specified transmission-ready notification.
1040 * @param th handle that was returned by "notify_transmit_ready".
1043 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1045 struct GNUNET_MESH_Handle *mesh;
1047 mesh = th->tunnel->mesh;
1048 if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1049 GNUNET_SCHEDULER_cancel (th->timeout_task);
1050 GNUNET_CONTAINER_DLL_remove (mesh->queue_head,
1054 if ( (NULL == mesh->queue_head) &&
1055 (NULL != mesh->th) )
1057 /* queue empty, no point in asking for transmission */
1058 GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1064 #if 0 /* keep Emacsens' auto-indent happy */