Changes in API, adapted code and testfiles, improved client reconnect, new documentat...
[oweals/gnunet.git] / src / mesh / mesh_api_new.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 Christian Grothoff (and other contributing authors)
4      GNUnet is free software; you can redistribute it and/or modify
5      it under the terms of the GNU General Public License as published
6      by the Free Software Foundation; either version 3, or (at your
7      option) any later version.
8      GNUnet is distributed in the hope that it will be useful, but
9      WITHOUT ANY WARRANTY; without even the implied warranty of
10      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11      General Public License for more details.
12      You should have received a copy of the GNU General Public License
13      along with GNUnet; see the file COPYING.  If not, write to the
14      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15      Boston, MA 02111-1307, USA.
16 */
17
18 /**
19  * @file mesh/mesh_api_new.c
20  * @brief mesh api: client implementation of mesh service
21  * @author Bartlomiej Polot
22  *
23  * TODO:
24  * - callbacks to client missing on certain events
25  * - processing messages from service is incomplete
26  *
27  * STRUCTURE:
28  * - CONSTANTS
29  * - DATA STRUCTURES
30  * - AUXILIARY FUNCTIONS
31  * - RECEIVE HANDLERS
32  * - SEND FUNCTIONS
33  * - API CALL DEFINITIONS
34  */
35 #ifdef __cplusplus
36 extern "C"
37 {
38 #if 0                           /* keep Emacsens' auto-indent happy */
39 }
40 #endif
41 #endif
42
43 #include "platform.h"
44 #include "gnunet_common.h"
45 #include "gnunet_client_lib.h"
46 #include "gnunet_util_lib.h"
47 #include "gnunet_peer_lib.h"
48 #include "gnunet_mesh_service_new.h"
49 #include "mesh.h"
50 #include "mesh_protocol.h"
51
52
53 /******************************************************************************/
54 /************************      DATA STRUCTURES     ****************************/
55 /******************************************************************************/
56
57 /**
58  * Transmission queue to the service
59  */
60 struct GNUNET_MESH_TransmitHandle
61 {
62
63     /**
64      * Double Linked list
65      */
66   struct GNUNET_MESH_TransmitHandle *next;
67
68     /**
69      * Double Linked list
70      */
71   struct GNUNET_MESH_TransmitHandle *prev;
72
73     /**
74      * Tunnel this message is sent over (may be NULL for control messages).
75      */
76   struct GNUNET_MESH_Tunnel *tunnel;
77
78     /**
79      * Data itself, currently points to the end of this struct if
80      * we have a message already, NULL if the message is to be
81      * obtained from the callback.
82      */
83   const struct GNUNET_MessageHeader *data;
84
85     /**
86      * Callback to obtain the message to transmit, or NULL if we
87      * got the message in 'data'.  Notice that messages built
88      * by 'notify' need to be encapsulated with information about
89      * the 'target'.
90      */
91   GNUNET_CONNECTION_TransmitReadyNotify notify;
92
93     /**
94      * Closure for 'notify'
95      */
96   void *notify_cls;
97
98     /**
99      * How long is this message valid.  Once the timeout has been
100      * reached, the message must no longer be sent.  If this
101      * is a message with a 'notify' callback set, the 'notify'
102      * function should be called with 'buf' NULL and size 0.
103      */
104   struct GNUNET_TIME_Absolute timeout;
105
106     /**
107      * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
108      */
109   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
110
111     /**
112      * Priority of the message.  The queue is sorted by priority,
113      * control messages have the maximum priority (UINT32_MAX).
114      */
115   uint32_t priority;
116
117     /**
118      * Target of the message, 0 for broadcast.  This field
119      * is only valid if 'notify' is non-NULL.
120      */
121   GNUNET_PEER_Id target;
122
123     /**
124      * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
125      */
126   size_t size;
127 };
128
129
130 /**
131  * Opaque handle to the service.
132  */
133 struct GNUNET_MESH_Handle
134 {
135
136     /**
137      * Handle to the server connection, to send messages later
138      */
139   struct GNUNET_CLIENT_Connection *client;
140
141     /**
142      * Set of handlers used for processing incoming messages in the tunnels
143      */
144   const struct GNUNET_MESH_MessageHandler *message_handlers;
145
146     /**
147      * Set of applications that should be claimed to be offered at this node.
148      * Note that this is just informative, the appropiate handlers must be
149      * registered independently and the mapping is up to the developer of the
150      * client application.
151      */
152   const GNUNET_MESH_ApplicationType *applications;
153
154     /**
155      * Double linked list of the tunnels this client is connected to.
156      */
157   struct GNUNET_MESH_Tunnel *tunnels_head;
158   struct GNUNET_MESH_Tunnel *tunnels_tail;
159
160     /**
161      * Callback for inbound tunnel creation
162      */
163   GNUNET_MESH_InboundTunnelNotificationHandler *new_tunnel;
164
165     /**
166      * Callback for inbound tunnel disconnection
167      */
168   GNUNET_MESH_TunnelEndHandler *cleaner;
169
170     /**
171      * Handle to cancel pending transmissions in case of disconnection
172      */
173   struct GNUNET_CLIENT_TransmitHandle *th;
174
175     /**
176      * Closure for all the handlers given by the client
177      */
178   void *cls;
179
180     /**
181      * Messages to send to the service
182      */
183   struct GNUNET_MESH_TransmitHandle *th_head;
184   struct GNUNET_MESH_TransmitHandle *th_tail;
185
186     /**
187      * tid of the next tunnel to create (to avoid reusing IDs often)
188      */
189   MESH_TunnelNumber next_tid;
190   unsigned int n_handlers;
191   unsigned int n_applications;
192   unsigned int max_queue_size;
193
194     /**
195      * Have we started the task to receive messages from the service
196      * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
197      */
198   int in_receive;
199
200     /**
201      * Number of packets queued
202      */
203   unsigned int npackets;
204
205   /**
206    * Configuration given by the client, in case of reconnection
207    */
208   const struct GNUNET_CONFIGURATION_Handle *cfg;
209 };
210
211
212 /**
213  * Description of a peer
214  */
215 struct GNUNET_MESH_Peer
216 {
217     /**
218      * ID of the peer in short form
219      */
220   GNUNET_PEER_Id id;
221
222   /**
223    * Tunnel this peer belongs to
224    */
225   struct GNUNET_MESH_Tunnel *t;
226
227   /**
228    * Flag indicating whether service has informed about its connection
229    */
230   int connected;
231
232 };
233
234
235 /**
236  * Opaque handle to a tunnel.
237  */
238 struct GNUNET_MESH_Tunnel
239 {
240
241     /**
242      * DLL
243      */
244   struct GNUNET_MESH_Tunnel *next;
245   struct GNUNET_MESH_Tunnel *prev;
246
247     /**
248      * Callback to execute when peers connect to the tunnel
249      */
250   GNUNET_MESH_TunnelConnectHandler connect_handler;
251
252     /**
253      * Callback to execute when peers disconnect from the tunnel
254      */
255   GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
256
257     /**
258      * Closure for the connect/disconnect handlers
259      */
260   void *cls;
261
262     /**
263      * Handle to the mesh this tunnel belongs to
264      */
265   struct GNUNET_MESH_Handle *mesh;
266
267     /**
268      * Local ID of the tunnel
269      */
270   MESH_TunnelNumber tid;
271
272     /**
273      * Owner of the tunnel
274      */
275   GNUNET_PEER_Id owner;
276
277     /**
278      * All peers added to the tunnel
279      */
280   struct GNUNET_MESH_Peer **peers;
281
282   /**
283    * List of application types that have been requested for this tunnel
284    */
285   GNUNET_MESH_ApplicationType *apps;
286
287   /**
288    * Any data the caller wants to put in here
289    */
290   void *ctx;
291
292   /**
293      * Number of peers added to the tunnel
294      */
295   unsigned int npeers;
296
297     /**
298      * Number of packets queued in this tunnel
299      */
300   unsigned int npackets;
301
302     /**
303      * Number of applications requested this tunnel
304      */
305   unsigned int napps;
306
307 };
308
309
310 /******************************************************************************/
311 /***********************     AUXILIARY FUNCTIONS      *************************/
312 /******************************************************************************/
313
314 /**
315  * Get the tunnel handler for the tunnel specified by id from the given handle
316  * @param h Mesh handle
317  * @param tid ID of the wanted tunnel
318  * @return handle to the required tunnel or NULL if not found
319  */
320 static struct GNUNET_MESH_Tunnel *
321 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
322 {
323   struct GNUNET_MESH_Tunnel *t;
324
325   t = h->tunnels_head;
326   while (t != NULL)
327   {
328     if (t->tid == tid)
329       return t;
330     t = t->next;
331   }
332   return NULL;
333 }
334
335
336 /**
337  * Create a new tunnel and insert it in the tunnel list of the mesh handle
338  * @param h Mesh handle
339  * @param tid desired tid of the tunnel, 0 to assign one automatically
340  * @return handle to the created tunnel
341  */
342 static struct GNUNET_MESH_Tunnel *
343 create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
344 {
345   struct GNUNET_MESH_Tunnel *t;
346
347   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
348   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
349   t->mesh = h;
350   if (0 == tid)
351   {
352     t->tid = h->next_tid;
353     while (NULL != retrieve_tunnel (h, h->next_tid))
354     {
355       h->next_tid++;
356       h->next_tid &= ~GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
357       h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
358     }
359   }
360   else
361   {
362     t->tid = tid;
363   }
364   return t;
365 }
366
367
368 /**
369  * Get the tunnel handler for the tunnel specified by id from the given handle
370  * @param h Mesh handle
371  * @param tid ID of the wanted tunnel
372  * @return handle to the required tunnel or NULL if not found
373  */
374 static void
375 destroy_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
376 {
377   struct GNUNET_MESH_Tunnel *t;
378   struct GNUNET_PeerIdentity pi;
379   unsigned int i;
380
381   t = retrieve_tunnel (h, tid);
382   if (NULL == t)
383   {
384     GNUNET_break (0);
385     return;
386   }
387   /* TODO remove data packets from queue */
388   GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t);
389   for (i = 0; i < t->npeers; i++)
390   {
391     if (NULL != t->disconnect_handler && t->peers[i]->connected)
392     {
393       GNUNET_PEER_resolve (t->peers[i]->id, &pi);
394       t->disconnect_handler (t->cls, &pi);
395     }
396     GNUNET_PEER_change_rc (t->peers[i]->id, -1);
397     GNUNET_free (t->peers[i]);
398   }
399   if (NULL != h->cleaner && 0 != t->owner)
400     h->cleaner (h->cls, t, t->ctx);
401   if (0 != t->owner)
402     GNUNET_PEER_change_rc (t->owner, -1);
403   if (0 != t->napps && t->apps)
404     GNUNET_free (t->apps);
405   if (t->npeers > 0)
406     GNUNET_free (t->peers);
407   GNUNET_free (t);
408   return;
409   }
410   GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t);
411   for (i = 0; i < t->npeers; i++)
412   {
413     GNUNET_PEER_resolve (t->peers[i]->id, &pi);
414     t->disconnect_handler (t->cls, &pi);
415     GNUNET_PEER_change_rc (t->peers[i]->id, -1);
416     GNUNET_free (t->peers[i]);
417   }
418   h->cleaner (h->cls, t, NULL); /* FIXME ctx? */
419   if (0 != t->owner)
420     GNUNET_PEER_change_rc (t->owner, -1);
421   GNUNET_free (t->peers);
422   GNUNET_free (t);
423   return;
424 }
425
426
427 /**
428  * Get the peer descriptor for the peer with id from the given tunnel
429  * @param t Tunnel handle
430  * @param id Short form ID of the wanted peer
431  * @return handle to the requested peer or NULL if not found
432  */
433 static struct GNUNET_MESH_Peer *
434 retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id)
435 {
436   unsigned int i;
437
438   for (i = 0; i < t->npeers; i++)
439     if (t->peers[i]->id == id)
440       return t->peers[i];
441   return NULL;
442 }
443
444
445 /**
446  * Add a peer into a tunnel
447  * @param t Tunnel handle
448  * @param pi Full ID of the new peer
449  * @return handle to the newly created peer
450  */
451 static struct GNUNET_MESH_Peer *
452 add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
453                     const struct GNUNET_PeerIdentity *pi)
454 {
455   struct GNUNET_MESH_Peer *p;
456   GNUNET_PEER_Id id;
457
458   id = GNUNET_PEER_intern (pi);
459
460   p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
461   p->id = id;
462   p->t = t;
463   GNUNET_array_append (t->peers, t->npeers, p);
464   return p;
465 }
466
467
468 /**
469  * Remove a peer from a tunnel
470  * @param t Tunnel handle
471  * @param p Peer handle
472  */
473 static void
474 remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p)
475 {
476   unsigned int i;
477
478   for (i = 0; i < p->t->npeers; i++)
479   {
480     if (p->t->peers[i] == p)
481       break;
482   }
483   if (i == p->t->npeers)
484   {
485     GNUNET_break (0);
486     return;
487   }
488   p->t->peers[i] = p->t->peers[p->t->npeers - 1];
489   GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1);
490 }
491
492
493 /**
494  * Notify client that the transmission has timed out
495  * @param cls closure
496  * @param tc task context
497  */
498 static void
499 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
500 {
501   struct GNUNET_MESH_TransmitHandle *th = cls;
502   struct GNUNET_MESH_Handle *mesh;
503
504   mesh = th->tunnel->mesh;
505   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
506   if (th->notify != NULL)
507     th->notify (th->notify_cls, 0, NULL);
508   GNUNET_free (th);
509   if ((NULL == mesh->th_head) && (NULL != mesh->th))
510   {
511     /* queue empty, no point in asking for transmission */
512     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
513     mesh->th = NULL;
514   }
515 }
516
517
518 /**
519  * Add a transmit handle to the transmission queue by priority and set the
520  * timeout if needed.
521  *
522  * @param h mesh handle with the queue head and tail
523  * @param q handle to the packet to be transmitted
524  */
525 static void
526 add_to_queue (struct GNUNET_MESH_Handle *h,
527               struct GNUNET_MESH_TransmitHandle *th)
528 {
529   struct GNUNET_MESH_TransmitHandle *p;
530
531   p = h->th_head;
532   while ((NULL != p) && (th->priority <= p->priority))
533     p = p->next;
534   if (NULL == p)
535     p = h->th_tail;
536   else
537     p = p->prev;
538   GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
539   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
540     return;
541   th->timeout_task =
542       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
543                                     (th->timeout), &timeout_transmission, th);
544 }
545
546
547 static void
548 send_packet (struct GNUNET_MESH_Handle *h,
549              const struct GNUNET_MessageHeader *msg);
550
551
552 /**
553  * Reconnect to the service, retransmit all infomation to try to restore the
554  * original state.
555  *
556  * @param h handle to the mesh
557  *
558  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
559  */
560 static int
561 reconnect (struct GNUNET_MESH_Handle *h)
562 {
563   struct GNUNET_MESH_Tunnel *t;
564   unsigned int i;
565
566   h->in_receive = GNUNET_NO;
567   /* disconnect */
568   if (NULL != h->th)
569   {
570     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
571   }
572   if (NULL != h->client)
573   {
574     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
575   }
576
577   /* connect again */
578   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
579   if (h->client == NULL)
580   {
581     /* FIXME: panic? exponential backoff retry? */
582     GNUNET_break (0);
583     return GNUNET_NO;
584   }
585   /* Rebuild all tunnels */
586   for (t = h->tunnels_head; NULL != t; t = t->next)
587   {
588     struct GNUNET_MESH_TunnelMessage tmsg;
589     struct GNUNET_MESH_PeerControl pmsg;
590
591     tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
592     tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
593     tmsg.tunnel_id = htonl (t->tid);
594     send_packet (h, &tmsg.header);
595
596     pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
597     pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
598     pmsg.tunnel_id = htonl (t->tid);
599
600     /* Reconnect all peers */
601     for (i = 0; i < t->npeers; i++)
602     {
603       GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer);
604       if (NULL != t->disconnect_handler && t->peers[i]->connected)
605         t->disconnect_handler (t->cls, &pmsg.peer);
606       /* If the tunnel was "by type", dont connect individual peers */
607       if (0 == t->napps)
608         send_packet (t->mesh, &pmsg.header);
609     }
610     /* Reconnect all types, if any  */
611     for (i = 0; i < t->napps; i++)
612     {
613       struct GNUNET_MESH_ConnectPeerByType msg;
614
615       msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
616       msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
617       msg.tunnel_id = htonl (t->tid);
618       msg.type = htonl (t->apps[i]);
619       send_packet (t->mesh, &msg.header);
620     }
621   }
622   return GNUNET_YES;
623 }
624
625
626 /******************************************************************************/
627 /***********************      RECEIVE HANDLERS     ****************************/
628 /******************************************************************************/
629
630 /**
631  * Process the new tunnel notification and add it to the tunnels in the handle
632  *
633  * @param h     The mesh handle
634  * @param msg   A message with the details of the new incoming tunnel
635  */
636 static void
637 process_tunnel_create (struct GNUNET_MESH_Handle *h,
638                        const struct GNUNET_MESH_TunnelMessage *msg)
639 {
640   struct GNUNET_MESH_Tunnel *t;
641   MESH_TunnelNumber tid;
642
643   tid = ntohl (msg->tunnel_id);
644   if (tid <= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI)
645   {
646     GNUNET_break (0);
647     return;
648   }
649   t = create_tunnel (h, tid);
650   t->mesh = h;
651   t->tid = tid;
652   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
653   return;
654 }
655
656
657 /**
658  * Process the tunnel destroy notification and free associated resources
659  *
660  * @param h     The mesh handle
661  * @param msg   A message with the details of the tunnel being destroyed
662  */
663 static void
664 process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
665                         const struct GNUNET_MESH_TunnelMessage *msg)
666 {
667   struct GNUNET_MESH_Tunnel *t;
668   MESH_TunnelNumber tid;
669
670   tid = ntohl (msg->tunnel_id);
671   t = retrieve_tunnel (h, tid);
672
673   t->cls = h->cls;
674   t->mesh = h;
675   t->tid = tid;
676   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
677   return;
678 }
679
680
681 /**
682  * Process the new peer event and notify the upper level of it
683  *
684  * @param h     The mesh handle
685  * @param msg   A message with the details of the peer event
686  */
687 static void
688 process_peer_event (struct GNUNET_MESH_Handle *h,
689                     const struct GNUNET_MESH_PeerControl *msg)
690 {
691   struct GNUNET_MESH_Tunnel *t;
692   struct GNUNET_MESH_Peer *p;
693   struct GNUNET_TRANSPORT_ATS_Information atsi;
694   GNUNET_PEER_Id id;
695   uint16_t size;
696
697   size = ntohs (msg->header.size);
698   if (size != sizeof (struct GNUNET_MESH_PeerControl))
699   {
700     GNUNET_break (0);
701     return;
702   }
703   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
704   if (NULL == t)
705   {
706     t = create_tunnel (h, msg->tunnel_id);
707     t->owner = GNUNET_PEER_intern (&msg->peer);
708     t->npeers = 1;
709     t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *));
710     t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
711     t->peers[0]->t = t;
712     t->peers[0]->connected = 1;
713     t->peers[0]->id = t->owner;
714     return;
715   }
716   id = GNUNET_PEER_search (&msg->peer);
717   if ((p = retrieve_peer (t, id)) == NULL)
718     p = add_peer_to_tunnel (t, &msg->peer);
719   atsi.type = 0;
720   atsi.value = 0;
721   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == msg->header.type)
722   {
723     if (NULL != t->connect_handler)
724     {
725       t->connect_handler (t->cls, &msg->peer, &atsi);
726     }
727     p->connected = 1;
728   }
729   else
730   {
731     if (NULL != t->disconnect_handler && p->connected)
732     {
733       t->disconnect_handler (t->cls, &msg->peer);
734     }
735     remove_peer_from_tunnel (p);
736     GNUNET_free (p);
737   }
738 }
739
740
741 /**
742  * Process the incoming data packets
743  *
744  * @param h     The mesh handle
745  * @param msh   A message encapsulating the data
746  */
747 static void
748 process_incoming_data (struct GNUNET_MESH_Handle *h,
749                        const struct GNUNET_MessageHeader *message)
750 {
751   const struct GNUNET_MessageHeader *payload;
752   const struct GNUNET_MESH_MessageHandler *handler;
753   const struct GNUNET_PeerIdentity *peer;
754   struct GNUNET_MESH_Unicast *ucast;
755   struct GNUNET_MESH_Multicast *mcast;
756   struct GNUNET_MESH_ToOrigin *to_orig;
757   struct GNUNET_MESH_Tunnel *t;
758   uint16_t type;
759   int i;
760
761   type = ntohs (message->type);
762   switch (type)
763   {
764   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
765     ucast = (struct GNUNET_MESH_Unicast *) message;
766     t = retrieve_tunnel (h, ntohl (ucast->tid));
767     payload = (struct GNUNET_MessageHeader *) &ucast[1];
768     peer = &ucast->oid;
769     break;
770   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
771     mcast = (struct GNUNET_MESH_Multicast *) message;
772     t = retrieve_tunnel (h, ntohl (mcast->tid));
773     payload = (struct GNUNET_MessageHeader *) &mcast[1];
774     peer = &mcast->oid;
775     break;
776   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
777     to_orig = (struct GNUNET_MESH_ToOrigin *) message;
778     t = retrieve_tunnel (h, ntohl (to_orig->tid));
779     payload = (struct GNUNET_MessageHeader *) &to_orig[1];
780     peer = &to_orig->sender;
781     break;
782   default:
783     GNUNET_break (0);
784     return;
785   }
786   if (NULL == t)
787   {
788     GNUNET_break (0);
789     return;
790   }
791   for (i = 0; i < h->n_handlers; i++)
792   {
793     handler = &h->message_handlers[i];
794     if (handler->type == type)
795     {
796       struct GNUNET_TRANSPORT_ATS_Information atsi;
797
798       atsi.type = 0;
799       atsi.value = 0;
800       if (GNUNET_OK ==
801           handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi))
802       {
803         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804                     "MESH: callback completed successfully\n");
805       }
806       else
807       {
808         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
809                     "MESH: callback caused disconnection\n");
810         GNUNET_MESH_disconnect (h);
811       }
812     }
813   }
814 }
815
816
817 /**
818  * Function to process all messages received from the service
819  *
820  * @param cls closure
821  * @param msg message received, NULL on timeout or fatal error
822  */
823 static void
824 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
825 {
826   struct GNUNET_MESH_Handle *h = cls;
827
828   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message from MESH\n");
829   if (msg == NULL)
830   {
831     reconnect (h);
832     return;
833   }
834   switch (ntohs (msg->type))
835   {
836     /* Notify of a new incoming tunnel */
837   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
838     process_tunnel_create (h, (struct GNUNET_MESH_TunnelMessage *) msg);
839     break;
840     /* Notify of a tunnel disconnection */
841   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
842     process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg);
843     break;
844     /* Notify of a new peer or a peer disconnect in the tunnel */
845   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD:
846   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL:
847     process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
848     break;
849     /* Notify of a new data packet in the tunnel */
850   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
851   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
852   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
853     process_incoming_data (h, msg);
854     break;
855     /* We shouldn't get any other packages, log and ignore */
856   default:
857     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
858                 "MESH: unsolicited message form service (type %d)\n",
859                 ntohs (msg->type));
860   }
861   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
862   GNUNET_CLIENT_receive (h->client, &msg_received, h,
863                          GNUNET_TIME_UNIT_FOREVER_REL);
864 }
865
866
867 /******************************************************************************/
868 /************************       SEND FUNCTIONS     ****************************/
869 /******************************************************************************/
870
871 /**
872  * Function called to send a message to the service.
873  * "buf" will be NULL and "size" zero if the socket was closed for writing in
874  * the meantime.
875  *
876  * @param cls closure, the mesh handle
877  * @param size number of bytes available in buf
878  * @param buf where the callee should write the connect message
879  * @return number of bytes written to buf
880  */
881 static size_t
882 send_callback (void *cls, size_t size, void *buf)
883 {
884   struct GNUNET_MESH_Handle *h = cls;
885   struct GNUNET_MESH_TransmitHandle *th;
886   char *cbuf = buf;
887   size_t tsize;
888   size_t psize;
889
890   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
891   h->th = NULL;
892   if ((0 == size) || (NULL == buf))
893   {
894     reconnect (h);
895     return 0;
896   }
897   tsize = 0;
898   while ((NULL != (th = h->th_head)) && (size >= th->size))
899   {
900     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     type: %u\n",
901                 ntohs (th->data->type));
902     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     size: %u\n",
903                 ntohs (th->data->size));
904     if (NULL == th->data)
905     {
906       GNUNET_assert (NULL != th->notify);
907       if (th->target == 0)
908       {
909         /* multicast */
910         struct GNUNET_MESH_Multicast mc;
911
912         GNUNET_assert (size >= sizeof (mc) + th->size);
913         psize =
914             th->notify (th->notify_cls, size - sizeof (mc), &cbuf[sizeof (mc)]);
915         if (psize > 0)
916         {
917           mc.header.size = htons (sizeof (mc) + th->size);
918           mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
919           mc.tid = htonl (th->tunnel->tid);
920           memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));     /* myself */
921           memcpy (cbuf, &mc, sizeof (mc));
922           psize = th->size + sizeof (mc);
923         }
924       }
925       else
926       {
927         /* unicast */
928         struct GNUNET_MESH_Unicast uc;
929
930         GNUNET_assert (size >= sizeof (uc) + th->size);
931         psize =
932             th->notify (th->notify_cls, size - sizeof (uc), &cbuf[sizeof (uc)]);
933         if (psize > 0)
934         {
935           uc.header.size = htons (sizeof (uc) + th->size);
936           uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
937           uc.tid = htonl (th->tunnel->tid);
938           memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));     /* myself */
939           GNUNET_PEER_resolve (th->target, &uc.destination);
940           memcpy (cbuf, &uc, sizeof (uc));
941           psize = th->size + sizeof (uc);
942         }
943       }
944     }
945     else
946     {
947       memcpy (cbuf, th->data, th->size);
948       psize = th->size;
949     }
950     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
951       GNUNET_SCHEDULER_cancel (th->timeout_task);
952     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
953     GNUNET_free (th);
954     cbuf += psize;
955     size -= psize;
956     tsize += psize;
957   }
958   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   total size: %u\n", tsize);
959   if (NULL != (th = h->th_head))
960   {
961     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   next size: %u\n", th->size);
962     h->th =
963         GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
964                                              GNUNET_TIME_UNIT_FOREVER_REL,
965                                              GNUNET_YES, &send_callback, h);
966   }
967   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
968   if (GNUNET_NO == h->in_receive)
969   {
970     h->in_receive = GNUNET_YES;
971     GNUNET_CLIENT_receive (h->client, &msg_received, h,
972                            GNUNET_TIME_UNIT_FOREVER_REL);
973   }
974   return tsize;
975 }
976
977
978 /**
979  * Auxiliary function to send an already constructed packet to the service.
980  * Takes care of creating a new queue element, copying the message and
981  * calling the tmt_rdy function if necessary.
982  * @param h mesh handle
983  * @param msg message to transmit
984  */
985 static void
986 send_packet (struct GNUNET_MESH_Handle *h,
987              const struct GNUNET_MessageHeader *msg)
988 {
989   struct GNUNET_MESH_TransmitHandle *th;
990   size_t msize;
991
992   msize = ntohs (msg->size);
993   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
994   th->priority = UINT32_MAX;
995   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
996   th->size = msize;
997   th->data = (void *) &th[1];
998   memcpy (&th[1], msg, msize);
999   add_to_queue (h, th);
1000   if (NULL != h->th)
1001     return;
1002   h->th =
1003       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
1004                                            GNUNET_TIME_UNIT_FOREVER_REL,
1005                                            GNUNET_YES, &send_callback, h);
1006 }
1007
1008
1009 /******************************************************************************/
1010 /**********************      API CALL DEFINITIONS     *************************/
1011 /******************************************************************************/
1012
1013 /**
1014  * Connect to the mesh service.
1015  *
1016  * @param cfg configuration to use
1017  * @param queue_size size of the data message queue, shared among all tunnels
1018  *                   (each tunnel is guaranteed to accept at least one message,
1019  *                    no matter what is the status of other tunnels)
1020  * @param cls closure for the various callbacks that follow
1021  *            (including handlers in the handlers array)
1022  * @param new_tunnel function called when an *inbound* tunnel is created
1023  * @param cleaner function called when an *inbound* tunnel is destroyed
1024  * @param handlers callbacks for messages we care about, NULL-terminated
1025  *                note that the mesh is allowed to drop notifications about
1026  *                inbound messages if the client does not process them fast
1027  *                enough (for this notification type, a bounded queue is used)
1028  * @param stypes list of the applications that this client claims to provide
1029  * @return handle to the mesh service NULL on error
1030  *         (in this case, init is never called)
1031  */
1032 struct GNUNET_MESH_Handle *
1033 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1034                      unsigned int queue_size, void *cls,
1035                      GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel,
1036                      GNUNET_MESH_TunnelEndHandler cleaner,
1037                      const struct GNUNET_MESH_MessageHandler *handlers,
1038                      const GNUNET_MESH_ApplicationType *stypes)
1039 {
1040   struct GNUNET_MESH_Handle *h;
1041   struct GNUNET_MESH_ClientConnect *msg;
1042   GNUNET_MESH_ApplicationType *apps;
1043   uint16_t napps;
1044   uint16_t *types;
1045   uint16_t ntypes;
1046   size_t size;
1047
1048   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
1049   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
1050   h->cfg = cfg;
1051   h->max_queue_size = queue_size;
1052   h->new_tunnel = new_tunnel;
1053   h->cleaner = cleaner;
1054   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1055   if (h->client == NULL)
1056   {
1057     GNUNET_break (0);
1058     GNUNET_free (h);
1059     return NULL;
1060   }
1061   h->cls = cls;
1062   h->message_handlers = handlers;
1063   h->applications = stypes;
1064   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
1065
1066   /* count handlers and apps, calculate size */
1067   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
1068   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
1069   size = sizeof (struct GNUNET_MESH_ClientConnect);
1070   size += h->n_handlers * sizeof (uint16_t);
1071   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
1072
1073   {
1074     char buf[size];
1075
1076     /* build connection packet */
1077     msg = (struct GNUNET_MESH_ClientConnect *) buf;
1078     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
1079     msg->header.size = htons (size);
1080     types = (uint16_t *) & msg[1];
1081     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
1082       types[ntypes] = h->message_handlers[ntypes].type;
1083     apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
1084     for (napps = 0; napps < h->n_applications; napps++)
1085       apps[napps] = h->applications[napps];
1086     msg->applications = htons (napps);
1087     msg->types = htons (ntypes);
1088     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089                 "mesh: Sending %lu bytes long message %d types and %d apps\n",
1090                 ntohs (msg->header.size), ntypes, napps);
1091     send_packet (h, &msg->header);
1092   }
1093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
1094   return h;
1095 }
1096
1097
1098 /**
1099  * Disconnect from the mesh service.
1100  *
1101  * @param handle connection to mesh to disconnect
1102  */
1103 void
1104 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1105 {
1106   struct GNUNET_MESH_Tunnel *t;
1107
1108   for (t = handle->tunnels_head; NULL != t; t = t->next)
1109   {
1110     destroy_tunnel (handle, t->tid);
1111   }
1112   if (NULL != handle->th)
1113   {
1114     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1115   }
1116   if (NULL != handle->client)
1117   {
1118     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
1119   }
1120   GNUNET_free (handle);
1121 }
1122
1123
1124 /**
1125  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
1126  * and to broadcast).
1127  *
1128  * @param h mesh handle
1129  * @param tunnel_ctx client's tunnel context to associate with the tunnel
1130  * @param connect_handler function to call when peers are actually connected
1131  * @param disconnect_handler function to call when peers are disconnected
1132  * @param handler_cls closure for connect/disconnect handlers
1133  */
1134 struct GNUNET_MESH_Tunnel *
1135 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
1136                            GNUNET_MESH_TunnelConnectHandler connect_handler,
1137                            GNUNET_MESH_TunnelDisconnectHandler
1138                            disconnect_handler, void *handler_cls)
1139 {
1140   struct GNUNET_MESH_Tunnel *t;
1141   struct GNUNET_MESH_TunnelMessage msg;
1142
1143   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
1144   t = create_tunnel (h, 0);
1145   t->connect_handler = connect_handler;
1146   t->disconnect_handler = disconnect_handler;
1147   t->cls = handler_cls;
1148   t->ctx = tunnel_ctx;
1149   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
1150   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1151   msg.tunnel_id = htonl (t->tid);
1152   send_packet (h, &msg.header);
1153   return t;
1154 }
1155
1156
1157 /**
1158  * Destroy an existing tunnel.
1159  *
1160  * @param tun tunnel handle
1161  */
1162 void
1163 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tun)
1164 {
1165   struct GNUNET_MESH_Handle *h;
1166   struct GNUNET_MESH_TunnelMessage msg;
1167
1168   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
1169   h = tun->mesh;
1170
1171   if (0 != tun->owner)
1172     GNUNET_PEER_change_rc (tun->owner, -1);
1173
1174   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
1175   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1176   msg.tunnel_id = htonl (t->tid);
1177   destroy_tunnel (h, t->tid);
1178   send_packet (h, &msg.header);
1179 }
1180
1181
1182 /**
1183  * Request that a peer should be added to the tunnel.  The existing
1184  * connect handler will be called ONCE with either success or failure.
1185  * This function should NOT be called again with the same peer before the
1186  * connect handler is called.
1187  *
1188  * @param tunnel handle to existing tunnel
1189  * @param timeout how long to try to establish a connection
1190  * @param peer peer to add
1191  */
1192 void
1193 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
1194                                       const struct GNUNET_PeerIdentity *peer)
1195 {
1196   struct GNUNET_MESH_PeerControl msg;
1197   GNUNET_PEER_Id peer_id;
1198   unsigned int i;
1199
1200   peer_id = GNUNET_PEER_intern (peer);
1201   for (i = 0; i < tunnel->npeers; i++)
1202   {
1203     if (tunnel->peers[i]->id == peer_id)
1204     {
1205       GNUNET_PEER_change_rc (peer_id, -1);
1206       GNUNET_break (0);
1207       return;
1208     }
1209   }
1210   add_peer_to_tunnel (tunnel, peer);
1211
1212   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1213   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
1214   msg.tunnel_id = htonl (tunnel->tid);
1215   msg.peer = *peer;
1216   send_packet (tunnel->mesh, &msg.header);
1217
1218   return;
1219 }
1220
1221
1222 /**
1223  * Request that a peer should be removed from the tunnel.  The existing
1224  * disconnect handler will be called ONCE if we were connected.
1225  *
1226  * @param tunnel handle to existing tunnel
1227  * @param peer peer to remove
1228  */
1229 void
1230 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
1231                                       const struct GNUNET_PeerIdentity *peer)
1232 {
1233   struct GNUNET_MESH_PeerControl msg;
1234   GNUNET_PEER_Id peer_id;
1235   unsigned int i;
1236
1237   peer_id = GNUNET_PEER_search (peer);
1238   if (0 == peer_id)
1239   {
1240     GNUNET_break (0);
1241     return;
1242   }
1243   for (i = 0; i < tunnel->npeers; i++)
1244     if (tunnel->peers[i]->id == peer_id)
1245       break;
1246   if (i == tunnel->npeers)
1247   {
1248     GNUNET_break (0);
1249     return;
1250   }
1251   if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1)
1252     tunnel->disconnect_handler (tunnel->cls, peer);
1253   GNUNET_PEER_change_rc (peer_id, -1);
1254   GNUNET_free (tunnel->peers[i]);
1255   tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
1256   GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
1257
1258   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1259   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
1260   msg.tunnel_id = htonl (tunnel->tid);
1261   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1262   send_packet (tunnel->mesh, &msg.header);
1263 }
1264
1265
1266 /**
1267  * Request that the mesh should try to connect to a peer supporting the given
1268  * message type.
1269  *
1270  * @param tunnel handle to existing tunnel
1271  * @param app_type application type that must be supported by the peer (MESH
1272  *                 should discover peer in proximity handling this type)
1273  */
1274 void
1275 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
1276                                           GNUNET_MESH_ApplicationType app_type)
1277 {
1278   struct GNUNET_MESH_ConnectPeerByType msg;
1279
1280   GNUNET_array_append (tunnel->apps, tunnel->napps, app_type);
1281
1282   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
1283   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
1284   msg.tunnel_id = htonl (tunnel->tid);
1285   msg.type = htonl (app_type);
1286   send_packet (tunnel->mesh, &msg.header);
1287 }
1288
1289
1290 /**
1291  * Ask the mesh to call "notify" once it is ready to transmit the
1292  * given number of bytes to the specified "target".  If we are not yet
1293  * connected to the specified peer, a call to this function will cause
1294  * us to try to establish a connection.
1295  *
1296  * @param tunnel tunnel to use for transmission
1297  * @param cork is corking allowed for this transmission?
1298  * @param priority how important is the message?
1299  * @param maxdelay how long can the message wait?
1300  * @param target destination for the message,
1301  *               NULL for multicast to all tunnel targets
1302  * @param notify_size how many bytes of buffer space does notify want?
1303  * @param notify function to call when buffer space is available;
1304  *        will be called with NULL on timeout or if the overall queue
1305  *        for this peer is larger than queue_size and this is currently
1306  *        the message with the lowest priority
1307  * @param notify_cls closure for notify
1308  * @return non-NULL if the notify callback was queued,
1309  *         NULL if we can not even queue the request (insufficient
1310  *         memory); if NULL is returned, "notify" will NOT be called.
1311  */
1312 struct GNUNET_MESH_TransmitHandle *
1313 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1314                                    uint32_t priority,
1315                                    struct GNUNET_TIME_Relative maxdelay,
1316                                    const struct GNUNET_PeerIdentity *target,
1317                                    size_t notify_size,
1318                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1319                                    void *notify_cls)
1320 {
1321   struct GNUNET_MESH_TransmitHandle *th;
1322   size_t overhead;
1323
1324   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
1325       tunnel->npackets > 0)
1326     return NULL;                /* queue full */
1327   tunnel->npackets++;
1328   tunnel->mesh->npackets++;
1329   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1330   th->tunnel = tunnel;
1331   th->priority = priority;
1332   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1333   th->target = GNUNET_PEER_intern (target);
1334   overhead =
1335       (NULL ==
1336        target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct
1337                                                                  GNUNET_MESH_Unicast);
1338   th->size = notify_size + overhead;
1339   th->notify = notify;
1340   th->notify_cls = notify_cls;
1341   add_to_queue (tunnel->mesh, th);
1342   return th;
1343 }
1344
1345
1346 /**
1347  * Cancel the specified transmission-ready notification.
1348  *
1349  * @param th handle that was returned by "notify_transmit_ready".
1350  */
1351 void
1352 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1353 {
1354   struct GNUNET_MESH_Handle *mesh;
1355
1356   mesh = th->tunnel->mesh;
1357   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1358     GNUNET_SCHEDULER_cancel (th->timeout_task);
1359   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1360   GNUNET_free (th);
1361   if ((NULL == mesh->th_head) && (NULL != mesh->th))
1362   {
1363     /* queue empty, no point in asking for transmission */
1364     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1365     mesh->th = NULL;
1366   }
1367 }
1368
1369
1370 #if 0                           /* keep Emacsens' auto-indent happy */
1371 {
1372 #endif
1373 #ifdef __cplusplus
1374 }
1375 #endif