- Fixed bugs of incoming data for tunnels without handlers, passing along free'd...
[oweals/gnunet.git] / src / mesh / mesh_api.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.c
20  * @brief mesh api: client implementation of mesh service
21  * @author Bartlomiej Polot
22  *
23  * STRUCTURE:
24  * - CONSTANTS
25  * - DATA STRUCTURES
26  * - AUXILIARY FUNCTIONS
27  * - RECEIVE HANDLERS
28  * - SEND FUNCTIONS
29  * - API CALL DEFINITIONS
30  */
31 #ifdef __cplusplus
32 extern "C"
33 {
34 #if 0                           /* keep Emacsens' auto-indent happy */
35 }
36 #endif
37 #endif
38
39 #include "platform.h"
40 #include "gnunet_common.h"
41 #include "gnunet_client_lib.h"
42 #include "gnunet_util_lib.h"
43 #include "gnunet_peer_lib.h"
44 #include "gnunet_mesh_service.h"
45 #include "mesh.h"
46 #include "mesh_protocol.h"
47
48 #define MESH_API_DEBUG GNUNET_YES
49
50 #if MESH_API_DEBUG
51 #define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__)
52 #else
53 #define LOG(kind,...)
54 #endif
55
56 /******************************************************************************/
57 /************************      DATA STRUCTURES     ****************************/
58 /******************************************************************************/
59
60 /**
61  * Transmission queue to the service
62  */
63 struct GNUNET_MESH_TransmitHandle
64 {
65
66     /**
67      * Double Linked list
68      */
69   struct GNUNET_MESH_TransmitHandle *next;
70
71     /**
72      * Double Linked list
73      */
74   struct GNUNET_MESH_TransmitHandle *prev;
75
76     /**
77      * Tunnel this message is sent on / for (may be NULL for control messages).
78      */
79   struct GNUNET_MESH_Tunnel *tunnel;
80
81     /**
82      * Callback to obtain the message to transmit, or NULL if we
83      * got the message in 'data'.  Notice that messages built
84      * by 'notify' need to be encapsulated with information about
85      * the 'target'.
86      */
87   GNUNET_CONNECTION_TransmitReadyNotify notify;
88
89     /**
90      * Closure for 'notify'
91      */
92   void *notify_cls;
93
94     /**
95      * How long is this message valid.  Once the timeout has been
96      * reached, the message must no longer be sent.  If this
97      * is a message with a 'notify' callback set, the 'notify'
98      * function should be called with 'buf' NULL and size 0.
99      */
100   struct GNUNET_TIME_Absolute timeout;
101
102     /**
103      * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
104      */
105   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
106
107     /**
108      * Priority of the message.  The queue is sorted by priority,
109      * control messages have the maximum priority (UINT32_MAX).
110      */
111   uint32_t priority;
112
113     /**
114      * Target of the message, 0 for multicast.  This field
115      * is only valid if 'notify' is non-NULL.
116      */
117   GNUNET_PEER_Id target;
118
119     /**
120      * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
121      */
122   size_t size;
123 };
124
125
126 /**
127  * Opaque handle to the service.
128  */
129 struct GNUNET_MESH_Handle
130 {
131
132     /**
133      * Handle to the server connection, to send messages later
134      */
135   struct GNUNET_CLIENT_Connection *client;
136
137     /**
138      * Set of handlers used for processing incoming messages in the tunnels
139      */
140   const struct GNUNET_MESH_MessageHandler *message_handlers;
141
142     /**
143      * Set of applications that should be claimed to be offered at this node.
144      * Note that this is just informative, the appropiate handlers must be
145      * registered independently and the mapping is up to the developer of the
146      * client application.
147      */
148   const GNUNET_MESH_ApplicationType *applications;
149
150     /**
151      * Double linked list of the tunnels this client is connected to.
152      */
153   struct GNUNET_MESH_Tunnel *tunnels_head;
154   struct GNUNET_MESH_Tunnel *tunnels_tail;
155
156     /**
157      * Callback for inbound tunnel creation
158      */
159   GNUNET_MESH_InboundTunnelNotificationHandler *new_tunnel;
160
161     /**
162      * Callback for inbound tunnel disconnection
163      */
164   GNUNET_MESH_TunnelEndHandler *cleaner;
165
166     /**
167      * Handle to cancel pending transmissions in case of disconnection
168      */
169   struct GNUNET_CLIENT_TransmitHandle *th;
170
171     /**
172      * Closure for all the handlers given by the client
173      */
174   void *cls;
175
176     /**
177      * Messages to send to the service
178      */
179   struct GNUNET_MESH_TransmitHandle *th_head;
180   struct GNUNET_MESH_TransmitHandle *th_tail;
181
182     /**
183      * tid of the next tunnel to create (to avoid reusing IDs often)
184      */
185   MESH_TunnelNumber next_tid;
186   unsigned int n_handlers;
187   unsigned int n_applications;
188   unsigned int max_queue_size;
189
190     /**
191      * Have we started the task to receive messages from the service
192      * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
193      */
194   int in_receive;
195
196     /**
197      * Number of packets queued
198      */
199   unsigned int npackets;
200
201   /**
202    * Configuration given by the client, in case of reconnection
203    */
204   const struct GNUNET_CONFIGURATION_Handle *cfg;
205
206   /**
207    * Time to the next reconnect in case one reconnect fails
208    */
209   struct GNUNET_TIME_Relative reconnect_time;
210   
211   /**
212    * Task for trying to reconnect.
213    */
214   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
215 };
216
217
218 /**
219  * Description of a peer
220  */
221 struct GNUNET_MESH_Peer
222 {
223     /**
224      * ID of the peer in short form
225      */
226   GNUNET_PEER_Id id;
227
228   /**
229    * Tunnel this peer belongs to
230    */
231   struct GNUNET_MESH_Tunnel *t;
232
233   /**
234    * Flag indicating whether service has informed about its connection
235    */
236   int connected;
237
238 };
239
240
241 /**
242  * Opaque handle to a tunnel.
243  */
244 struct GNUNET_MESH_Tunnel
245 {
246
247     /**
248      * DLL
249      */
250   struct GNUNET_MESH_Tunnel *next;
251   struct GNUNET_MESH_Tunnel *prev;
252
253     /**
254      * Callback to execute when peers connect to the tunnel
255      */
256   GNUNET_MESH_PeerConnectHandler connect_handler;
257
258     /**
259      * Callback to execute when peers disconnect from the tunnel
260      */
261   GNUNET_MESH_PeerDisconnectHandler disconnect_handler;
262
263     /**
264      * Closure for the connect/disconnect handlers
265      */
266   void *cls;
267
268     /**
269      * Handle to the mesh this tunnel belongs to
270      */
271   struct GNUNET_MESH_Handle *mesh;
272
273     /**
274      * Local ID of the tunnel
275      */
276   MESH_TunnelNumber tid;
277
278     /**
279      * Owner of the tunnel. 0 if the tunnel is the local client.
280      */
281   GNUNET_PEER_Id owner;
282
283     /**
284      * All peers added to the tunnel
285      */
286   struct GNUNET_MESH_Peer **peers;
287
288   /**
289    * List of application types that have been requested for this tunnel
290    */
291   GNUNET_MESH_ApplicationType *apps;
292
293   /**
294    * Any data the caller wants to put in here
295    */
296   void *ctx;
297
298   /**
299      * Number of peers added to the tunnel
300      */
301   unsigned int npeers;
302
303     /**
304      * Number of packets queued in this tunnel
305      */
306   unsigned int npackets;
307
308     /**
309      * Number of applications requested this tunnel
310      */
311   unsigned int napps;
312
313 };
314
315
316 /******************************************************************************/
317 /***********************     AUXILIARY FUNCTIONS      *************************/
318 /******************************************************************************/
319
320 /**
321  * Get the tunnel handler for the tunnel specified by id from the given handle
322  * @param h Mesh handle
323  * @param tid ID of the wanted tunnel
324  * @return handle to the required tunnel or NULL if not found
325  */
326 static struct GNUNET_MESH_Tunnel *
327 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
328 {
329   struct GNUNET_MESH_Tunnel *t;
330
331   t = h->tunnels_head;
332   while (t != NULL)
333   {
334     if (t->tid == tid)
335       return t;
336     t = t->next;
337   }
338   return NULL;
339 }
340
341
342 /**
343  * Create a new tunnel and insert it in the tunnel list of the mesh handle
344  * @param h Mesh handle
345  * @param tid desired tid of the tunnel, 0 to assign one automatically
346  * @return handle to the created tunnel
347  */
348 static struct GNUNET_MESH_Tunnel *
349 create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
350 {
351   struct GNUNET_MESH_Tunnel *t;
352
353   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
354   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
355   t->mesh = h;
356   if (0 == tid)
357   {
358     t->tid = h->next_tid;
359     while (NULL != retrieve_tunnel (h, h->next_tid))
360     {
361       h->next_tid++;
362       h->next_tid &= ~GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
363       h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
364     }
365   }
366   else
367   {
368     t->tid = tid;
369   }
370   return t;
371 }
372
373
374 /**
375  * Destroy the specified tunnel.
376  * - Destroys all peers, calling the disconnect callback on each if needed
377  * - Cancels all outgoing traffic for that tunnel, calling respective notifys
378  * - Calls cleaner if tunnel was inbound
379  * - Frees all memory used
380  *
381  * @param t Pointer to the tunnel.
382  * @param call_cleaner Whether to call the cleaner handler.
383  *
384  * @return Handle to the required tunnel or NULL if not found.
385  */
386 static void
387 destroy_tunnel (struct GNUNET_MESH_Tunnel *t, int call_cleaner)
388 {
389   struct GNUNET_MESH_Handle *h;
390   struct GNUNET_PeerIdentity pi;
391   struct GNUNET_MESH_TransmitHandle *th;
392   struct GNUNET_MESH_TransmitHandle *next;
393   unsigned int i;
394
395   if (NULL == t)
396   {
397     GNUNET_break (0);
398     return;
399   }
400   h = t->mesh;
401
402   /* disconnect all peers */
403   GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t);
404   for (i = 0; i < t->npeers; i++)
405   {
406     if ( (NULL != t->disconnect_handler) && t->peers[i]->connected)
407     {
408       GNUNET_PEER_resolve (t->peers[i]->id, &pi);
409       t->disconnect_handler (t->cls, &pi);
410     }
411     GNUNET_PEER_change_rc (t->peers[i]->id, -1);
412     GNUNET_free (t->peers[i]);
413   }
414
415   /* signal tunnel destruction */
416   if ( (NULL != h->cleaner) && (0 != t->owner) && (GNUNET_YES == call_cleaner) )
417     h->cleaner (h->cls, t, t->ctx);
418
419   /* check that clients did not leave messages behind in the queue */
420   for (th = h->th_head; NULL != th; th = next)
421   {
422     next = th->next;
423     if (th->tunnel != t)
424       continue;
425     /* Clients should have aborted their requests already.
426      * Management traffic should be ok, as clients can't cancel that */
427     GNUNET_break (NULL == th->notify);
428     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
429
430     /* clean up request */
431     if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
432       GNUNET_SCHEDULER_cancel (th->timeout_task);
433     GNUNET_free (th);    
434   }
435
436   /* if there are no more pending requests with mesh service, cancel active request */
437   /* Note: this should be unnecessary... */
438   if ( (NULL == h->th_head) && (NULL != h->th))
439   {
440     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
441     h->th = NULL;
442   }
443
444
445   if (t->npeers > 0)
446     GNUNET_free (t->peers);
447   if (0 != t->owner)
448     GNUNET_PEER_change_rc (t->owner, -1);
449   if (0 != t->napps && t->apps)
450     GNUNET_free (t->apps);
451   GNUNET_free (t);
452   return;
453 }
454
455
456 /**
457  * Get the peer descriptor for the peer with id from the given tunnel
458  * @param t Tunnel handle
459  * @param id Short form ID of the wanted peer
460  * @return handle to the requested peer or NULL if not found
461  */
462 static struct GNUNET_MESH_Peer *
463 retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id)
464 {
465   unsigned int i;
466
467   for (i = 0; i < t->npeers; i++)
468     if (t->peers[i]->id == id)
469       return t->peers[i];
470   return NULL;
471 }
472
473
474 /**
475  * Add a peer into a tunnel
476  * @param t Tunnel handle
477  * @param pi Full ID of the new peer
478  * @return handle to the newly created peer
479  */
480 static struct GNUNET_MESH_Peer *
481 add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
482                     const struct GNUNET_PeerIdentity *pi)
483 {
484   struct GNUNET_MESH_Peer *p;
485   GNUNET_PEER_Id id;
486
487   if (0 != t->owner)
488   {
489     GNUNET_break (0);
490     return NULL;
491   }
492   id = GNUNET_PEER_intern (pi);
493
494   p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
495   p->id = id;
496   p->t = t;
497   GNUNET_array_append (t->peers, t->npeers, p);
498   return p;
499 }
500
501
502 /**
503  * Remove a peer from a tunnel
504  * @param p Peer handle
505  */
506 static void
507 remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p)
508 {
509   unsigned int i;
510
511   for (i = 0; i < p->t->npeers; i++)
512   {
513     if (p->t->peers[i] == p)
514       break;
515   }
516   if (i == p->t->npeers)
517   {
518     GNUNET_break (0);
519     return;
520   }
521   p->t->peers[i] = p->t->peers[p->t->npeers - 1];
522   GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1);
523 }
524
525
526 /**
527  * Notify client that the transmission has timed out
528  * @param cls closure
529  * @param tc task context
530  */
531 static void
532 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
533 {
534   struct GNUNET_MESH_TransmitHandle *th = cls;
535   struct GNUNET_MESH_Handle *mesh;
536
537   mesh = th->tunnel->mesh;
538   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
539   if (th->notify != NULL)
540     th->notify (th->notify_cls, 0, NULL);
541   GNUNET_free (th);
542   if ((NULL == mesh->th_head) && (NULL != mesh->th))
543   {
544     /* queue empty, no point in asking for transmission */
545     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
546     mesh->th = NULL;
547   }
548 }
549
550
551 /**
552  * Add a transmit handle to the transmission queue by priority and set the
553  * timeout if needed.
554  *
555  * @param h mesh handle with the queue head and tail
556  * @param th handle to the packet to be transmitted
557  */
558 static void
559 add_to_queue (struct GNUNET_MESH_Handle *h,
560               struct GNUNET_MESH_TransmitHandle *th)
561 {
562   struct GNUNET_MESH_TransmitHandle *p;
563
564   p = h->th_head;
565   while ((NULL != p) && (th->priority <= p->priority))
566     p = p->next;
567   if (NULL == p)
568     p = h->th_tail;
569   else
570     p = p->prev;
571   GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
572   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
573     return;
574   th->timeout_task =
575       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
576                                     (th->timeout), &timeout_transmission, th);
577 }
578
579
580 /**
581  * Auxiliary function to send an already constructed packet to the service.
582  * Takes care of creating a new queue element, copying the message and
583  * calling the tmt_rdy function if necessary.
584  *
585  * @param h mesh handle
586  * @param msg message to transmit
587  * @param tunnel tunnel this send is related to (NULL if N/A)
588  */
589 static void
590 send_packet (struct GNUNET_MESH_Handle *h,
591              const struct GNUNET_MessageHeader *msg,
592              struct GNUNET_MESH_Tunnel *tunnel);
593
594
595 /**
596  * Reconnect callback: tries to reconnect again after a failer previous
597  * reconnecttion
598  * @param cls closure (mesh handle)
599  * @param tc task context
600  */
601 static void
602 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
603
604
605 /**
606  * Send a connect packet to the service with the applications and types
607  * requested by the user.
608  *
609  * @param h The mesh handle.
610  *
611  */
612 static void
613 send_connect (struct GNUNET_MESH_Handle *h)
614 {
615   size_t size;
616
617   size = sizeof (struct GNUNET_MESH_ClientConnect);
618   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
619   size += h->n_handlers * sizeof (uint16_t);
620   {
621     char buf[size];
622     struct GNUNET_MESH_ClientConnect *msg;
623     GNUNET_MESH_ApplicationType *apps;
624     uint16_t napps;
625     uint16_t *types;
626     uint16_t ntypes;
627
628     /* build connection packet */
629     msg = (struct GNUNET_MESH_ClientConnect *) buf;
630     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
631     msg->header.size = htons (size);
632     apps = (GNUNET_MESH_ApplicationType *) &msg[1];
633     for (napps = 0; napps < h->n_applications; napps++)
634     {
635       apps[napps] = htonl (h->applications[napps]);
636       LOG (GNUNET_ERROR_TYPE_DEBUG, " app %u\n", h->applications[napps]);
637     }
638     types = (uint16_t *) & apps[napps];
639     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
640       types[ntypes] = htons (h->message_handlers[ntypes].type);
641     msg->applications = htons (napps);
642     msg->types = htons (ntypes);
643     LOG (GNUNET_ERROR_TYPE_DEBUG,
644          "Sending %lu bytes long message %d types and %d apps\n",
645          ntohs (msg->header.size), ntypes, napps);
646     send_packet (h, &msg->header, NULL);
647   }
648 }
649
650
651 /**
652  * Reconnect to the service, retransmit all infomation to try to restore the
653  * original state.
654  *
655  * @param h handle to the mesh
656  *
657  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
658  */
659 static int
660 do_reconnect (struct GNUNET_MESH_Handle *h)
661 {
662   struct GNUNET_MESH_Tunnel *t;
663   unsigned int i;
664
665   LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
666   LOG (GNUNET_ERROR_TYPE_DEBUG, "*******   RECONNECT   *******\n");
667   LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
668
669   h->in_receive = GNUNET_NO;
670   /* disconnect */
671   if (NULL != h->th)
672   {
673     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
674     h->th = NULL;
675   }
676   if (NULL != h->client)
677   {
678     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
679   }
680
681   /* connect again */
682   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
683   if (h->client == NULL)
684   {
685     h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
686                                                       &reconnect_cbk, h);
687     h->reconnect_time =
688         GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
689                                   GNUNET_TIME_relative_multiply
690                                   (h->reconnect_time, 2));
691     LOG (GNUNET_ERROR_TYPE_DEBUG, "  Next retry in %sms\n",
692          GNUNET_TIME_relative_to_string (h->reconnect_time));
693     GNUNET_break (0);
694     return GNUNET_NO;
695   }
696   else
697   {
698     h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
699   }
700   send_connect (h);
701   /* Rebuild all tunnels */
702   for (t = h->tunnels_head; NULL != t; t = t->next)
703   {
704     struct GNUNET_MESH_TunnelMessage tmsg;
705     struct GNUNET_MESH_PeerControl pmsg;
706
707     if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
708     {
709       /* Tunnel was created by service (incoming tunnel) */
710       /* TODO: Notify service of missing tunnel, to request
711        * creator to recreate path (find a path to him via DHT?)
712        */
713       continue;
714     }
715     tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
716     tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
717     tmsg.tunnel_id = htonl (t->tid);
718     send_packet (h, &tmsg.header, t);
719
720     pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
721     pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
722     pmsg.tunnel_id = htonl (t->tid);
723
724     /* Reconnect all peers */
725     for (i = 0; i < t->npeers; i++)
726     {
727       GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer);
728       if (NULL != t->disconnect_handler && t->peers[i]->connected)
729         t->disconnect_handler (t->cls, &pmsg.peer);
730       /* If the tunnel was "by type", dont connect individual peers */
731       if (0 == t->napps)
732         send_packet (t->mesh, &pmsg.header, t);
733     }
734     /* Reconnect all types, if any  */
735     for (i = 0; i < t->napps; i++)
736     {
737       struct GNUNET_MESH_ConnectPeerByType msg;
738
739       msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
740       msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
741       msg.tunnel_id = htonl (t->tid);
742       msg.type = htonl (t->apps[i]);
743       send_packet (t->mesh, &msg.header, t);
744     }
745   }
746   return GNUNET_YES;
747 }
748
749 /**
750  * Reconnect callback: tries to reconnect again after a failer previous
751  * reconnecttion
752  * @param cls closure (mesh handle)
753  * @param tc task context
754  */
755 static void
756 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
757 {
758   struct GNUNET_MESH_Handle *h = cls;
759
760   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
761   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
762     return;
763   do_reconnect (h);
764 }
765
766
767 /**
768  * Reconnect to the service, retransmit all infomation to try to restore the
769  * original state.
770  *
771  * @param h handle to the mesh
772  *
773  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
774  */
775 static void
776 reconnect (struct GNUNET_MESH_Handle *h)
777 {
778   LOG (GNUNET_ERROR_TYPE_DEBUG, "Requested RECONNECT\n");
779   if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task)
780     h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
781                                                       &reconnect_cbk, h);
782 }
783
784
785 /******************************************************************************/
786 /***********************      RECEIVE HANDLERS     ****************************/
787 /******************************************************************************/
788
789 /**
790  * Process the new tunnel notification and add it to the tunnels in the handle
791  *
792  * @param h     The mesh handle
793  * @param msg   A message with the details of the new incoming tunnel
794  */
795 static void
796 process_tunnel_created (struct GNUNET_MESH_Handle *h,
797                         const struct GNUNET_MESH_TunnelNotification *msg)
798 {
799   struct GNUNET_MESH_Tunnel *t;
800   MESH_TunnelNumber tid;
801
802   tid = ntohl (msg->tunnel_id);
803   if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
804   {
805     GNUNET_break (0);
806     return;
807   }
808   if (NULL != h->new_tunnel)
809   {
810     struct GNUNET_ATS_Information atsi;
811
812     t = create_tunnel (h, tid);
813     t->owner = GNUNET_PEER_intern (&msg->peer);
814     t->npeers = 1;
815     t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *));
816     t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
817     t->peers[0]->t = t;
818     t->peers[0]->connected = 1;
819     t->peers[0]->id = t->owner;
820     GNUNET_PEER_change_rc (t->owner, 1);
821     t->mesh = h;
822     t->tid = tid;
823     atsi.type = 0;
824     atsi.value = 0;
825     t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi);
826     LOG (GNUNET_ERROR_TYPE_DEBUG, "new incoming tunnel %X\n", t->tid);
827   }
828   else
829   {
830     struct GNUNET_MESH_TunnelMessage d_msg;
831
832     LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming tunnels\n");
833
834     d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
835     d_msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
836     d_msg.tunnel_id = msg->tunnel_id;
837
838     send_packet (h, &d_msg.header, NULL);
839   }
840   return;
841 }
842
843
844 /**
845  * Process the tunnel destroy notification and free associated resources
846  *
847  * @param h     The mesh handle
848  * @param msg   A message with the details of the tunnel being destroyed
849  */
850 static void
851 process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
852                         const struct GNUNET_MESH_TunnelMessage *msg)
853 {
854   struct GNUNET_MESH_Tunnel *t;
855   MESH_TunnelNumber tid;
856
857   tid = ntohl (msg->tunnel_id);
858   t = retrieve_tunnel (h, tid);
859
860   if (NULL == t)
861   {
862     return;
863   }
864   if (0 == t->owner)
865   {
866     GNUNET_break (0);
867   }
868   LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %u destroyed\n", t->tid);
869   destroy_tunnel (t, GNUNET_YES);
870   return;
871 }
872
873
874 /**
875  * Process the new peer event and notify the upper level of it
876  *
877  * @param h     The mesh handle
878  * @param msg   A message with the details of the peer event
879  */
880 static void
881 process_peer_event (struct GNUNET_MESH_Handle *h,
882                     const struct GNUNET_MESH_PeerControl *msg)
883 {
884   struct GNUNET_MESH_Tunnel *t;
885   struct GNUNET_MESH_Peer *p;
886   struct GNUNET_ATS_Information atsi;
887   GNUNET_PEER_Id id;
888   uint16_t size;
889
890   LOG (GNUNET_ERROR_TYPE_DEBUG, "processig peer event\n");
891   size = ntohs (msg->header.size);
892   if (size != sizeof (struct GNUNET_MESH_PeerControl))
893   {
894     GNUNET_break (0);
895     return;
896   }
897   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
898   if (NULL == t)
899   {
900     GNUNET_break (0);
901     return;
902   }
903   id = GNUNET_PEER_search (&msg->peer);
904   if ((p = retrieve_peer (t, id)) == NULL)
905     p = add_peer_to_tunnel (t, &msg->peer);
906   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type))
907   {
908     LOG (GNUNET_ERROR_TYPE_DEBUG, "adding peer\n");
909     if (NULL != t->connect_handler)
910     {
911       atsi.type = 0;
912       atsi.value = 0;
913       t->connect_handler (t->cls, &msg->peer, &atsi);
914     }
915     p->connected = 1;
916   }
917   else
918   {
919     LOG (GNUNET_ERROR_TYPE_DEBUG, "removing peer\n");
920     if (NULL != t->disconnect_handler && p->connected)
921     {
922       t->disconnect_handler (t->cls, &msg->peer);
923     }
924     remove_peer_from_tunnel (p);
925     GNUNET_free (p);
926   }
927   LOG (GNUNET_ERROR_TYPE_DEBUG, "processing peer event END\n");
928 }
929
930
931 /**
932  * Process the incoming data packets
933  *
934  * @param h         The mesh handle
935  * @param message   A message encapsulating the data
936  * 
937  * @return GNUNET_YES if everything went fine
938  *         GNUNET_NO if client closed connection (h no longer valid)
939  */
940 static int
941 process_incoming_data (struct GNUNET_MESH_Handle *h,
942                        const struct GNUNET_MessageHeader *message)
943 {
944   const struct GNUNET_MessageHeader *payload;
945   const struct GNUNET_MESH_MessageHandler *handler;
946   const struct GNUNET_PeerIdentity *peer;
947   struct GNUNET_MESH_Unicast *ucast;
948   struct GNUNET_MESH_Multicast *mcast;
949   struct GNUNET_MESH_ToOrigin *to_orig;
950   struct GNUNET_MESH_Tunnel *t;
951   unsigned int i;
952   uint16_t type;
953
954   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n");
955   type = ntohs (message->type);
956   switch (type)
957   {
958   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
959     ucast = (struct GNUNET_MESH_Unicast *) message;
960
961     t = retrieve_tunnel (h, ntohl (ucast->tid));
962     payload = (struct GNUNET_MessageHeader *) &ucast[1];
963     peer = &ucast->oid;
964     LOG (GNUNET_ERROR_TYPE_DEBUG, "  ucast on tunnel %s [%x]\n",
965          GNUNET_i2s (peer), ntohl (ucast->tid));
966     break;
967   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
968     mcast = (struct GNUNET_MESH_Multicast *) message;
969     t = retrieve_tunnel (h, ntohl (mcast->tid));
970     payload = (struct GNUNET_MessageHeader *) &mcast[1];
971     peer = &mcast->oid;
972     LOG (GNUNET_ERROR_TYPE_DEBUG, "  mcast on tunnel %s [%x]\n",
973          GNUNET_i2s (peer), ntohl (mcast->tid));
974     break;
975   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
976     to_orig = (struct GNUNET_MESH_ToOrigin *) message;
977     t = retrieve_tunnel (h, ntohl (to_orig->tid));
978     payload = (struct GNUNET_MessageHeader *) &to_orig[1];
979     peer = &to_orig->sender;
980     LOG (GNUNET_ERROR_TYPE_DEBUG, "  torig on tunnel %s [%x]\n",
981          GNUNET_i2s (peer), ntohl (to_orig->tid));
982     break;
983   default:
984     GNUNET_break (0);
985     return GNUNET_YES;
986   }
987   if (NULL == t)
988   {
989     GNUNET_break (0);
990     return GNUNET_YES;
991   }
992   type = ntohs (payload->type);
993   for (i = 0; i < h->n_handlers; i++)
994   {
995     handler = &h->message_handlers[i];
996     if (handler->type == type)
997     {
998       struct GNUNET_ATS_Information atsi;
999
1000       atsi.type = 0;
1001       atsi.value = 0;
1002       if (GNUNET_OK !=
1003           handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi))
1004       {
1005         LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH: callback caused disconnection\n");
1006         GNUNET_MESH_disconnect (h);
1007         return GNUNET_NO;
1008       }
1009       else
1010       {
1011         LOG (GNUNET_ERROR_TYPE_DEBUG,
1012              "MESH: callback completed successfully\n");
1013
1014       }
1015     }
1016   }
1017   return GNUNET_YES;
1018 }
1019
1020
1021 /**
1022  * Function to process all messages received from the service
1023  *
1024  * @param cls closure
1025  * @param msg message received, NULL on timeout or fatal error
1026  */
1027 static void
1028 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
1029 {
1030   struct GNUNET_MESH_Handle *h = cls;
1031
1032   if (msg == NULL)
1033   {
1034     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL msg\n");
1035     reconnect (h);
1036     return;
1037   }
1038   LOG (GNUNET_ERROR_TYPE_DEBUG, "received a message type %hu from MESH\n",
1039        ntohs (msg->type));
1040   switch (ntohs (msg->type))
1041   {
1042     /* Notify of a new incoming tunnel */
1043   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
1044     process_tunnel_created (h, (struct GNUNET_MESH_TunnelNotification *) msg);
1045     break;
1046     /* Notify of a tunnel disconnection */
1047   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
1048     process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg);
1049     break;
1050     /* Notify of a new peer or a peer disconnect in the tunnel */
1051   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD:
1052   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL:
1053     process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
1054     break;
1055     /* Notify of a new data packet in the tunnel */
1056   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
1057   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
1058   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
1059     if (GNUNET_NO == process_incoming_data (h, msg))
1060       return;
1061     break;
1062     /* We shouldn't get any other packages, log and ignore */
1063   default:
1064     LOG (GNUNET_ERROR_TYPE_WARNING,
1065          "MESH: unsolicited message form service (type %d)\n",
1066          ntohs (msg->type));
1067   }
1068   LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n");
1069   GNUNET_CLIENT_receive (h->client, &msg_received, h,
1070                          GNUNET_TIME_UNIT_FOREVER_REL);
1071 }
1072
1073
1074 /******************************************************************************/
1075 /************************       SEND FUNCTIONS     ****************************/
1076 /******************************************************************************/
1077
1078 /**
1079  * Function called to send a message to the service.
1080  * "buf" will be NULL and "size" zero if the socket was closed for writing in
1081  * the meantime.
1082  *
1083  * @param cls closure, the mesh handle
1084  * @param size number of bytes available in buf
1085  * @param buf where the callee should write the connect message
1086  * @return number of bytes written to buf
1087  */
1088 static size_t
1089 send_callback (void *cls, size_t size, void *buf)
1090 {
1091   struct GNUNET_MESH_Handle *h = cls;
1092   struct GNUNET_MESH_TransmitHandle *th;
1093   char *cbuf = buf;
1094   size_t tsize;
1095   size_t psize;
1096
1097   LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() Buffer %u\n", size);
1098   h->th = NULL;
1099   if ((0 == size) || (NULL == buf))
1100   {
1101     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL callback\n");
1102     reconnect (h);
1103     return 0;
1104   }
1105   tsize = 0;
1106   while ((NULL != (th = h->th_head)) && (size >= th->size))
1107   {
1108     if (NULL != th->notify)
1109     {
1110       if (th->tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1111       {
1112         /* traffic to origin */
1113         struct GNUNET_MESH_ToOrigin to;
1114         struct GNUNET_MessageHeader *mh;
1115
1116         GNUNET_assert (size >= th->size);
1117         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)];
1118         psize = th->notify (th->notify_cls, size - sizeof (to), mh);
1119         LOG (GNUNET_ERROR_TYPE_DEBUG, "  to origin, type %u\n",
1120              ntohs (mh->type));
1121         if (psize > 0)
1122         {
1123           psize += sizeof (to);
1124           GNUNET_assert (size >= psize);
1125           to.header.size = htons (psize);
1126           to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
1127           to.tid = htonl (th->tunnel->tid);
1128           memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1129           memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity));
1130           memcpy (cbuf, &to, sizeof (to));
1131         }
1132       }
1133       else if (th->target == 0)
1134       {
1135         /* multicast */
1136         struct GNUNET_MESH_Multicast mc;
1137         struct GNUNET_MessageHeader *mh;
1138
1139         GNUNET_assert (size >= th->size);
1140         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)];
1141         psize = th->notify (th->notify_cls, size - sizeof (mc), mh);
1142         LOG (GNUNET_ERROR_TYPE_DEBUG, "  multicast, type %u\n",
1143              ntohs (mh->type));
1144         if (psize > 0)
1145         {
1146           psize += sizeof (mc);
1147           GNUNET_assert (size >= psize);
1148           mc.header.size = htons (psize);
1149           mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
1150           mc.tid = htonl (th->tunnel->tid);
1151           mc.mid = 0;
1152           mc.ttl = 0;
1153           memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1154           memcpy (cbuf, &mc, sizeof (mc));
1155         }
1156       }
1157       else
1158       {
1159         /* unicast */
1160         struct GNUNET_MESH_Unicast uc;
1161         struct GNUNET_MessageHeader *mh;
1162
1163         GNUNET_assert (size >= th->size);
1164         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)];
1165         psize = th->notify (th->notify_cls, size - sizeof (uc), mh);
1166         LOG (GNUNET_ERROR_TYPE_DEBUG, "  unicast, type %u\n",
1167              ntohs (mh->type));
1168         if (psize > 0)
1169         {
1170           psize += sizeof (uc);
1171           GNUNET_assert (size >= psize);
1172           uc.header.size = htons (psize);
1173           uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
1174           uc.tid = htonl (th->tunnel->tid);
1175           memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1176           GNUNET_PEER_resolve (th->target, &uc.destination);
1177           memcpy (cbuf, &uc, sizeof (uc));
1178         }
1179       }
1180     }
1181     else
1182     {
1183       memcpy (cbuf, &th[1], th->size);
1184       psize = th->size;
1185     }
1186     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1187       GNUNET_SCHEDULER_cancel (th->timeout_task);
1188     if (NULL != th->notify)
1189     {
1190       th->tunnel->mesh->npackets--;
1191       th->tunnel->npackets--;
1192     }
1193     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1194     GNUNET_free (th);
1195     cbuf += psize;
1196     size -= psize;
1197     tsize += psize;
1198   }
1199   LOG (GNUNET_ERROR_TYPE_DEBUG, "  total size: %u\n", tsize);
1200   if (NULL != (th = h->th_head))
1201   {
1202     LOG (GNUNET_ERROR_TYPE_DEBUG, "  next size: %u\n", th->size);
1203     if (NULL == h->th)
1204       h->th =
1205           GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
1206                                                GNUNET_TIME_UNIT_FOREVER_REL,
1207                                                GNUNET_YES, &send_callback, h);
1208   }
1209   LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() END\n");
1210   if (GNUNET_NO == h->in_receive)
1211   {
1212     h->in_receive = GNUNET_YES;
1213     GNUNET_CLIENT_receive (h->client, &msg_received, h,
1214                            GNUNET_TIME_UNIT_FOREVER_REL);
1215   }
1216   return tsize;
1217 }
1218
1219
1220 /**
1221  * Auxiliary function to send an already constructed packet to the service.
1222  * Takes care of creating a new queue element, copying the message and
1223  * calling the tmt_rdy function if necessary.
1224  * 
1225  * @param h mesh handle
1226  * @param msg message to transmit
1227  * @param tunnel tunnel this send is related to (NULL if N/A)
1228  */
1229 static void
1230 send_packet (struct GNUNET_MESH_Handle *h,
1231              const struct GNUNET_MessageHeader *msg,
1232              struct GNUNET_MESH_Tunnel *tunnel)
1233 {
1234   struct GNUNET_MESH_TransmitHandle *th;
1235   size_t msize;
1236
1237   msize = ntohs (msg->size);
1238   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
1239   th->priority = UINT32_MAX;
1240   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1241   th->size = msize;
1242   th->tunnel = tunnel;
1243   memcpy (&th[1], msg, msize);
1244   add_to_queue (h, th);
1245   if (NULL != h->th)
1246     return;
1247   h->th =
1248       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
1249                                            GNUNET_TIME_UNIT_FOREVER_REL,
1250                                            GNUNET_YES, &send_callback, h);
1251 }
1252
1253
1254 /******************************************************************************/
1255 /**********************      API CALL DEFINITIONS     *************************/
1256 /******************************************************************************/
1257
1258 /**
1259  * Connect to the mesh service.
1260  *
1261  * @param cfg configuration to use
1262  * @param queue_size size of the data message queue, shared among all tunnels
1263  *                   (each tunnel is guaranteed to accept at least one message,
1264  *                    no matter what is the status of other tunnels)
1265  * @param cls closure for the various callbacks that follow
1266  *            (including handlers in the handlers array)
1267  * @param new_tunnel function called when an *inbound* tunnel is created
1268  * @param cleaner function called when an *inbound* tunnel is destroyed by the
1269  *                remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy
1270  *                is called on the tunnel
1271  * @param handlers callbacks for messages we care about, NULL-terminated
1272  *                note that the mesh is allowed to drop notifications about
1273  *                inbound messages if the client does not process them fast
1274  *                enough (for this notification type, a bounded queue is used)
1275  * @param stypes list of the applications that this client claims to provide
1276  * @return handle to the mesh service NULL on error
1277  *         (in this case, init is never called)
1278  */
1279 struct GNUNET_MESH_Handle *
1280 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1281                      unsigned int queue_size, void *cls,
1282                      GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel,
1283                      GNUNET_MESH_TunnelEndHandler cleaner,
1284                      const struct GNUNET_MESH_MessageHandler *handlers,
1285                      const GNUNET_MESH_ApplicationType *stypes)
1286 {
1287   struct GNUNET_MESH_Handle *h;
1288
1289   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect()\n");
1290   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
1291   h->cfg = cfg;
1292   h->max_queue_size = queue_size;
1293   h->new_tunnel = new_tunnel;
1294   h->cleaner = cleaner;
1295   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1296   if (h->client == NULL)
1297   {
1298     GNUNET_break (0);
1299     GNUNET_free (h);
1300     return NULL;
1301   }
1302   h->cls = cls;
1303   /* FIXME memdup? */
1304   h->applications = stypes;
1305   h->message_handlers = handlers;
1306   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
1307   h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1308   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
1309
1310   /* count handlers and apps, calculate size */
1311   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
1312   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
1313   send_connect (h);
1314   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect() END\n");
1315   return h;
1316 }
1317
1318
1319 /**
1320  * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel
1321  * disconnect callbacks will be called on any still connected peers, notifying
1322  * about their disconnection. The registered inbound tunnel cleaner will be
1323  * called should any inbound tunnels still exist.
1324  *
1325  * @param handle connection to mesh to disconnect
1326  */
1327 void
1328 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1329 {
1330   struct GNUNET_MESH_Tunnel *t;
1331   struct GNUNET_MESH_Tunnel *aux;
1332   struct GNUNET_MESH_TransmitHandle *th;
1333
1334   t = handle->tunnels_head;
1335   while (NULL != t)
1336   {
1337     aux = t->next;
1338     if (t->tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1339     {
1340       GNUNET_break (0);
1341       LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %X not destroyed\n", t->tid);
1342     }
1343     destroy_tunnel (t, GNUNET_YES);
1344     t = aux;
1345   }
1346   while ( (th = handle->th_head) != NULL)
1347   {
1348     struct GNUNET_MessageHeader *msg;
1349
1350     /* Make sure it is an allowed packet (everything else should have been
1351      * already canceled).
1352      */
1353     GNUNET_break (UINT32_MAX == th->priority);
1354     GNUNET_break (NULL == th->notify);
1355     msg = (struct GNUNET_MessageHeader *) &th[1];
1356     switch (ntohs(msg->type))
1357     {
1358       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT:
1359       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
1360         break;
1361       default:
1362         GNUNET_break (0);
1363         LOG (GNUNET_ERROR_TYPE_DEBUG, "unexpected msg %u\n",
1364              ntohs(msg->type));
1365     }
1366
1367     GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th);
1368     GNUNET_free (th);
1369   }
1370
1371   if (NULL != handle->th)
1372   {
1373     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1374     handle->th = NULL;
1375   }
1376   if (NULL != handle->client)
1377   {
1378     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
1379     handle->client = NULL;
1380   }
1381   if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
1382   {
1383     GNUNET_SCHEDULER_cancel(handle->reconnect_task);
1384     handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
1385   }
1386   GNUNET_free (handle);
1387 }
1388
1389
1390 /**
1391  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
1392  * and to broadcast).
1393  *
1394  * @param h mesh handle
1395  * @param tunnel_ctx client's tunnel context to associate with the tunnel
1396  * @param connect_handler function to call when peers are actually connected
1397  * @param disconnect_handler function to call when peers are disconnected
1398  * @param handler_cls closure for connect/disconnect handlers
1399  */
1400 struct GNUNET_MESH_Tunnel *
1401 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
1402                            GNUNET_MESH_PeerConnectHandler connect_handler,
1403                            GNUNET_MESH_PeerDisconnectHandler disconnect_handler,
1404                            void *handler_cls)
1405 {
1406   struct GNUNET_MESH_Tunnel *t;
1407   struct GNUNET_MESH_TunnelMessage msg;
1408
1409   LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new tunnel\n");
1410   t = create_tunnel (h, 0);
1411   t->connect_handler = connect_handler;
1412   t->disconnect_handler = disconnect_handler;
1413   t->cls = handler_cls;
1414   t->ctx = tunnel_ctx;
1415   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
1416   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1417   msg.tunnel_id = htonl (t->tid);
1418   send_packet (h, &msg.header, t);
1419   return t;
1420 }
1421
1422
1423 /**
1424  * Destroy an existing tunnel. The existing callback for the tunnel will NOT
1425  * be called.
1426  *
1427  * @param tunnel tunnel handle
1428  */
1429 void
1430 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel)
1431 {
1432   struct GNUNET_MESH_Handle *h;
1433   struct GNUNET_MESH_TunnelMessage msg;
1434   struct GNUNET_MESH_TransmitHandle *th;
1435
1436   LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying tunnel\n");
1437   h = tunnel->mesh;
1438
1439   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
1440   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1441   msg.tunnel_id = htonl (tunnel->tid);
1442   th = h->th_head;
1443   while (th != NULL)
1444   {
1445     struct GNUNET_MESH_TransmitHandle *aux;
1446     if (th->tunnel == tunnel)
1447     {
1448       aux = th->next;
1449       /* FIXME call the handler? */
1450       if (NULL != th->notify)
1451         th->notify (th->notify_cls, 0, NULL);
1452       GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1453       GNUNET_free (th);
1454       th = aux;
1455     }
1456     else
1457       th = th->next;
1458   }
1459
1460   destroy_tunnel (tunnel, GNUNET_NO);
1461   send_packet (h, &msg.header, NULL);
1462 }
1463
1464
1465 /**
1466  * Request that a peer should be added to the tunnel.  The existing
1467  * connect handler will be called ONCE with either success or failure.
1468  * This function should NOT be called again with the same peer before the
1469  * connect handler is called.
1470  *
1471  * @param tunnel handle to existing tunnel
1472  * @param peer peer to add
1473  */
1474 void
1475 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
1476                                       const struct GNUNET_PeerIdentity *peer)
1477 {
1478   struct GNUNET_MESH_PeerControl msg;
1479   GNUNET_PEER_Id peer_id;
1480   unsigned int i;
1481
1482   peer_id = GNUNET_PEER_intern (peer);
1483   for (i = 0; i < tunnel->npeers; i++)
1484   {
1485     if (tunnel->peers[i]->id == peer_id)
1486     {
1487       /* Peer already exists in tunnel */
1488       GNUNET_PEER_change_rc (peer_id, -1);
1489       GNUNET_break (0);
1490       return;
1491     }
1492   }
1493   if (NULL == add_peer_to_tunnel (tunnel, peer))
1494     return;
1495
1496   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1497   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
1498   msg.tunnel_id = htonl (tunnel->tid);
1499   msg.peer = *peer;
1500   send_packet (tunnel->mesh, &msg.header, tunnel);
1501
1502   return;
1503 }
1504
1505
1506 /**
1507  * Request that a peer should be removed from the tunnel.  The existing
1508  * disconnect handler will be called ONCE if we were connected.
1509  *
1510  * @param tunnel handle to existing tunnel
1511  * @param peer peer to remove
1512  */
1513 void
1514 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
1515                                       const struct GNUNET_PeerIdentity *peer)
1516 {
1517   struct GNUNET_MESH_PeerControl msg;
1518   GNUNET_PEER_Id peer_id;
1519   unsigned int i;
1520
1521   peer_id = GNUNET_PEER_search (peer);
1522   if (0 == peer_id)
1523   {
1524     GNUNET_break (0);
1525     return;
1526   }
1527   for (i = 0; i < tunnel->npeers; i++)
1528     if (tunnel->peers[i]->id == peer_id)
1529       break;
1530   if (i == tunnel->npeers)
1531   {
1532     GNUNET_break (0);
1533     return;
1534   }
1535   if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1)
1536     tunnel->disconnect_handler (tunnel->cls, peer);
1537   GNUNET_PEER_change_rc (peer_id, -1);
1538   GNUNET_free (tunnel->peers[i]);
1539   tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
1540   GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
1541
1542   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1543   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
1544   msg.tunnel_id = htonl (tunnel->tid);
1545   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1546   send_packet (tunnel->mesh, &msg.header, tunnel);
1547 }
1548
1549
1550 /**
1551  * Request that the mesh should try to connect to a peer supporting the given
1552  * message type.
1553  *
1554  * @param tunnel handle to existing tunnel
1555  * @param app_type application type that must be supported by the peer (MESH
1556  *                 should discover peer in proximity handling this type)
1557  */
1558 void
1559 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
1560                                           GNUNET_MESH_ApplicationType app_type)
1561 {
1562   struct GNUNET_MESH_ConnectPeerByType msg;
1563
1564   GNUNET_array_append (tunnel->apps, tunnel->napps, app_type);
1565
1566   LOG (GNUNET_ERROR_TYPE_DEBUG, "* CONNECT BY TYPE *\n");
1567   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
1568   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
1569   msg.tunnel_id = htonl (tunnel->tid);
1570   msg.type = htonl (app_type);
1571   send_packet (tunnel->mesh, &msg.header, tunnel);
1572 }
1573
1574
1575 /**
1576  * Ask the mesh to call "notify" once it is ready to transmit the
1577  * given number of bytes to the specified "target".  If we are not yet
1578  * connected to the specified peer, a call to this function will cause
1579  * us to try to establish a connection.
1580  *
1581  * @param tunnel tunnel to use for transmission
1582  * @param cork is corking allowed for this transmission?
1583  * @param priority how important is the message?
1584  * @param maxdelay how long can the message wait?
1585  * @param target destination for the message,
1586  *               NULL for multicast to all tunnel targets
1587  * @param notify_size how many bytes of buffer space does notify want?
1588  * @param notify function to call when buffer space is available;
1589  *        will be called with NULL on timeout or if the overall queue
1590  *        for this peer is larger than queue_size and this is currently
1591  *        the message with the lowest priority
1592  * @param notify_cls closure for notify
1593  * @return non-NULL if the notify callback was queued,
1594  *         NULL if we can not even queue the request (insufficient
1595  *         memory); if NULL is returned, "notify" will NOT be called.
1596  */
1597 struct GNUNET_MESH_TransmitHandle *
1598 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1599                                    uint32_t priority,
1600                                    struct GNUNET_TIME_Relative maxdelay,
1601                                    const struct GNUNET_PeerIdentity *target,
1602                                    size_t notify_size,
1603                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1604                                    void *notify_cls)
1605 {
1606   struct GNUNET_MESH_TransmitHandle *th;
1607   struct GNUNET_MESH_TransmitHandle *least_priority_th;
1608   uint32_t least_priority;
1609   size_t overhead;
1610
1611   GNUNET_assert (NULL != tunnel);
1612   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh notify transmit ready called\n");
1613   if (NULL != target)
1614     LOG (GNUNET_ERROR_TYPE_DEBUG, "    target %s\n", GNUNET_i2s (target));
1615   else
1616     LOG (GNUNET_ERROR_TYPE_DEBUG, "    target multicast\n");
1617   GNUNET_assert (NULL != notify);
1618   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
1619       tunnel->npackets > 0)
1620   {
1621     /* queue full */
1622     if (0 == priority)
1623       return NULL;
1624     th = tunnel->mesh->th_tail;
1625     least_priority = priority;
1626     least_priority_th = NULL;
1627     while (NULL != th)
1628     {
1629       if (th->priority < least_priority && th->tunnel->npackets > 1)
1630       {
1631         least_priority_th = th;
1632         least_priority = th->priority;
1633       }
1634       th = th->prev;
1635     }
1636     if (NULL == least_priority_th)
1637       return NULL;
1638     /* Can't be a control message */
1639     GNUNET_assert (NULL != least_priority_th->notify);
1640     least_priority_th->notify (notify_cls, 0, NULL);
1641     least_priority_th->tunnel->npackets--;
1642     tunnel->mesh->npackets--;
1643     GNUNET_CONTAINER_DLL_remove (tunnel->mesh->th_head, tunnel->mesh->th_tail,
1644                                  least_priority_th);
1645     if (GNUNET_SCHEDULER_NO_TASK != least_priority_th->timeout_task)
1646       GNUNET_SCHEDULER_cancel (least_priority_th->timeout_task);
1647     GNUNET_free (least_priority_th);
1648   }
1649   tunnel->npackets++;
1650   tunnel->mesh->npackets++;
1651   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1652   th->tunnel = tunnel;
1653   th->priority = priority;
1654   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1655   th->target = GNUNET_PEER_intern (target);
1656   if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1657     overhead = sizeof (struct GNUNET_MESH_ToOrigin);
1658   else if (NULL == target)
1659     overhead = sizeof (struct GNUNET_MESH_Multicast);
1660   else
1661     overhead = sizeof (struct GNUNET_MESH_Unicast);
1662   th->size = notify_size + overhead;
1663   th->notify = notify;
1664   th->notify_cls = notify_cls;
1665   add_to_queue (tunnel->mesh, th);
1666   if (NULL != tunnel->mesh->th)
1667     return th;
1668   tunnel->mesh->th =
1669       GNUNET_CLIENT_notify_transmit_ready (tunnel->mesh->client, th->size,
1670                                            GNUNET_TIME_UNIT_FOREVER_REL,
1671                                            GNUNET_YES, &send_callback,
1672                                            tunnel->mesh);
1673   return th;
1674 }
1675
1676
1677 /**
1678  * Cancel the specified transmission-ready notification.
1679  *
1680  * @param th handle that was returned by "notify_transmit_ready".
1681  */
1682 void
1683 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1684 {
1685   struct GNUNET_MESH_Handle *mesh;
1686
1687   mesh = th->tunnel->mesh;
1688   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1689     GNUNET_SCHEDULER_cancel (th->timeout_task);
1690   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1691   GNUNET_free (th);
1692   if ((NULL == mesh->th_head) && (NULL != mesh->th))
1693   {
1694     /* queue empty, no point in asking for transmission */
1695     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1696     mesh->th = NULL;
1697   }
1698 }
1699
1700
1701 /**
1702  * Transition API for tunnel ctx management
1703  */
1704 void
1705 GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data)
1706 {
1707   tunnel->ctx = data;
1708 }
1709
1710 /**
1711  * Transition API for tunnel ctx management
1712  */
1713 void *
1714 GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel)
1715 {
1716   return tunnel->ctx;
1717 }
1718
1719
1720 #if 0                           /* keep Emacsens' auto-indent happy */
1721 {
1722 #endif
1723 #ifdef __cplusplus
1724 }
1725 #endif