- Doxygen, reconnect and let caller take care of CTRL-C handling
[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     /* we should not really get here, as clients should have
426        aborted their requests already.
427        Management traffic should be ok, as clients can't cancel that */
428     GNUNET_break (NULL == th->notify);
429     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
430
431     /* clean up request */
432     if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
433       GNUNET_SCHEDULER_cancel (th->timeout_task);
434     GNUNET_free (th);    
435   }
436
437   /* if there are no more pending requests with mesh service, cancel active request */
438   /* Note: this should be unnecessary... */
439   if ( (NULL == h->th_head) && (NULL != h->th))
440   {
441     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
442     h->th = NULL;
443   }
444
445
446   if (t->npeers > 0)
447     GNUNET_free (t->peers);
448   if (0 != t->owner)
449     GNUNET_PEER_change_rc (t->owner, -1);
450   if (0 != t->napps && t->apps)
451     GNUNET_free (t->apps);
452   GNUNET_free (t);
453   return;
454 }
455
456
457 /**
458  * Get the peer descriptor for the peer with id from the given tunnel
459  * @param t Tunnel handle
460  * @param id Short form ID of the wanted peer
461  * @return handle to the requested peer or NULL if not found
462  */
463 static struct GNUNET_MESH_Peer *
464 retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id)
465 {
466   unsigned int i;
467
468   for (i = 0; i < t->npeers; i++)
469     if (t->peers[i]->id == id)
470       return t->peers[i];
471   return NULL;
472 }
473
474
475 /**
476  * Add a peer into a tunnel
477  * @param t Tunnel handle
478  * @param pi Full ID of the new peer
479  * @return handle to the newly created peer
480  */
481 static struct GNUNET_MESH_Peer *
482 add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
483                     const struct GNUNET_PeerIdentity *pi)
484 {
485   struct GNUNET_MESH_Peer *p;
486   GNUNET_PEER_Id id;
487
488   if (0 != t->owner)
489   {
490     GNUNET_break (0);
491     return NULL;
492   }
493   id = GNUNET_PEER_intern (pi);
494
495   p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
496   p->id = id;
497   p->t = t;
498   GNUNET_array_append (t->peers, t->npeers, p);
499   return p;
500 }
501
502
503 /**
504  * Remove a peer from a tunnel
505  * @param p Peer handle
506  */
507 static void
508 remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p)
509 {
510   unsigned int i;
511
512   for (i = 0; i < p->t->npeers; i++)
513   {
514     if (p->t->peers[i] == p)
515       break;
516   }
517   if (i == p->t->npeers)
518   {
519     GNUNET_break (0);
520     return;
521   }
522   p->t->peers[i] = p->t->peers[p->t->npeers - 1];
523   GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1);
524 }
525
526
527 /**
528  * Notify client that the transmission has timed out
529  * @param cls closure
530  * @param tc task context
531  */
532 static void
533 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
534 {
535   struct GNUNET_MESH_TransmitHandle *th = cls;
536   struct GNUNET_MESH_Handle *mesh;
537
538   mesh = th->tunnel->mesh;
539   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
540   if (th->notify != NULL)
541     th->notify (th->notify_cls, 0, NULL);
542   GNUNET_free (th);
543   if ((NULL == mesh->th_head) && (NULL != mesh->th))
544   {
545     /* queue empty, no point in asking for transmission */
546     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
547     mesh->th = NULL;
548   }
549 }
550
551
552 /**
553  * Add a transmit handle to the transmission queue by priority and set the
554  * timeout if needed.
555  *
556  * @param h mesh handle with the queue head and tail
557  * @param th handle to the packet to be transmitted
558  */
559 static void
560 add_to_queue (struct GNUNET_MESH_Handle *h,
561               struct GNUNET_MESH_TransmitHandle *th)
562 {
563   struct GNUNET_MESH_TransmitHandle *p;
564
565   p = h->th_head;
566   while ((NULL != p) && (th->priority <= p->priority))
567     p = p->next;
568   if (NULL == p)
569     p = h->th_tail;
570   else
571     p = p->prev;
572   GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
573   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
574     return;
575   th->timeout_task =
576       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
577                                     (th->timeout), &timeout_transmission, th);
578 }
579
580
581 /**
582  * Auxiliary function to send an already constructed packet to the service.
583  * Takes care of creating a new queue element, copying the message and
584  * calling the tmt_rdy function if necessary.
585  *
586  * @param h mesh handle
587  * @param msg message to transmit
588  * @param tunnel tunnel this send is related to (NULL if N/A)
589  */
590 static void
591 send_packet (struct GNUNET_MESH_Handle *h,
592              const struct GNUNET_MessageHeader *msg,
593              struct GNUNET_MESH_Tunnel *tunnel);
594
595
596 /**
597  * Reconnect callback: tries to reconnect again after a failer previous
598  * reconnecttion
599  * @param cls closure (mesh handle)
600  * @param tc task context
601  */
602 static void
603 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
604
605
606 /**
607  * Send a connect packet to the service with the applications and types
608  * requested by the user.
609  *
610  * @param h The mesh handle.
611  *
612  */
613 static void
614 send_connect (struct GNUNET_MESH_Handle *h)
615 {
616   size_t size;
617
618   size = sizeof (struct GNUNET_MESH_ClientConnect);
619   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
620   size += h->n_handlers * sizeof (uint16_t);
621   {
622     char buf[size];
623     struct GNUNET_MESH_ClientConnect *msg;
624     GNUNET_MESH_ApplicationType *apps;
625     uint16_t napps;
626     uint16_t *types;
627     uint16_t ntypes;
628
629     /* build connection packet */
630     msg = (struct GNUNET_MESH_ClientConnect *) buf;
631     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
632     msg->header.size = htons (size);
633     apps = (GNUNET_MESH_ApplicationType *) &msg[1];
634     for (napps = 0; napps < h->n_applications; napps++)
635     {
636       apps[napps] = htonl (h->applications[napps]);
637       LOG (GNUNET_ERROR_TYPE_DEBUG, " app %u\n", h->applications[napps]);
638     }
639     types = (uint16_t *) & apps[napps];
640     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
641       types[ntypes] = htons (h->message_handlers[ntypes].type);
642     msg->applications = htons (napps);
643     msg->types = htons (ntypes);
644     LOG (GNUNET_ERROR_TYPE_DEBUG,
645          "Sending %lu bytes long message %d types and %d apps\n",
646          ntohs (msg->header.size), ntypes, napps);
647     send_packet (h, &msg->header, NULL);
648   }
649 }
650
651
652 /**
653  * Reconnect to the service, retransmit all infomation to try to restore the
654  * original state.
655  *
656  * @param h handle to the mesh
657  *
658  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
659  */
660 static int
661 do_reconnect (struct GNUNET_MESH_Handle *h)
662 {
663   struct GNUNET_MESH_Tunnel *t;
664   unsigned int i;
665
666   LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
667   LOG (GNUNET_ERROR_TYPE_DEBUG, "*******   RECONNECT   *******\n");
668   LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
669
670   h->in_receive = GNUNET_NO;
671   /* disconnect */
672   if (NULL != h->th)
673   {
674     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
675     h->th = NULL;
676   }
677   if (NULL != h->client)
678   {
679     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
680   }
681
682   /* connect again */
683   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
684   if (h->client == NULL)
685   {
686     h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
687                                                       &reconnect_cbk, h);
688     h->reconnect_time =
689         GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
690                                   GNUNET_TIME_relative_multiply
691                                   (h->reconnect_time, 2));
692     LOG (GNUNET_ERROR_TYPE_DEBUG, "  Next retry in %sms\n",
693          GNUNET_TIME_relative_to_string (h->reconnect_time));
694     GNUNET_break (0);
695     return GNUNET_NO;
696   }
697   else
698   {
699     h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
700   }
701   send_connect (h);
702   /* Rebuild all tunnels */
703   for (t = h->tunnels_head; NULL != t; t = t->next)
704   {
705     struct GNUNET_MESH_TunnelMessage tmsg;
706     struct GNUNET_MESH_PeerControl pmsg;
707
708     if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
709     {
710       /* Tunnel was created by service (incoming tunnel) */
711       /* TODO: Notify service of missing tunnel, to request
712        * creator to recreate path (find a path to him via DHT?)
713        */
714       continue;
715     }
716     tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
717     tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
718     tmsg.tunnel_id = htonl (t->tid);
719     send_packet (h, &tmsg.header, t);
720
721     pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
722     pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
723     pmsg.tunnel_id = htonl (t->tid);
724
725     /* Reconnect all peers */
726     for (i = 0; i < t->npeers; i++)
727     {
728       GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer);
729       if (NULL != t->disconnect_handler && t->peers[i]->connected)
730         t->disconnect_handler (t->cls, &pmsg.peer);
731       /* If the tunnel was "by type", dont connect individual peers */
732       if (0 == t->napps)
733         send_packet (t->mesh, &pmsg.header, t);
734     }
735     /* Reconnect all types, if any  */
736     for (i = 0; i < t->napps; i++)
737     {
738       struct GNUNET_MESH_ConnectPeerByType msg;
739
740       msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
741       msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
742       msg.tunnel_id = htonl (t->tid);
743       msg.type = htonl (t->apps[i]);
744       send_packet (t->mesh, &msg.header, t);
745     }
746   }
747   return GNUNET_YES;
748 }
749
750 /**
751  * Reconnect callback: tries to reconnect again after a failer previous
752  * reconnecttion
753  * @param cls closure (mesh handle)
754  * @param tc task context
755  */
756 static void
757 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
758 {
759   struct GNUNET_MESH_Handle *h = cls;
760
761   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
762   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
763     return;
764   do_reconnect (h);
765 }
766
767
768 /**
769  * Reconnect to the service, retransmit all infomation to try to restore the
770  * original state.
771  *
772  * @param h handle to the mesh
773  *
774  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
775  */
776 static void
777 reconnect (struct GNUNET_MESH_Handle *h)
778 {
779   if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
780     GNUNET_SCHEDULER_add_delayed (h->reconnect_time, &reconnect_cbk, h);
781 }
782
783
784 /******************************************************************************/
785 /***********************      RECEIVE HANDLERS     ****************************/
786 /******************************************************************************/
787
788 /**
789  * Process the new tunnel notification and add it to the tunnels in the handle
790  *
791  * @param h     The mesh handle
792  * @param msg   A message with the details of the new incoming tunnel
793  */
794 static void
795 process_tunnel_created (struct GNUNET_MESH_Handle *h,
796                         const struct GNUNET_MESH_TunnelNotification *msg)
797 {
798   struct GNUNET_MESH_Tunnel *t;
799   MESH_TunnelNumber tid;
800
801   tid = ntohl (msg->tunnel_id);
802   if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
803   {
804     GNUNET_break (0);
805     return;
806   }
807   t = create_tunnel (h, tid);
808   t->owner = GNUNET_PEER_intern (&msg->peer);
809   t->npeers = 1;
810   t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *));
811   t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
812   t->peers[0]->t = t;
813   t->peers[0]->connected = 1;
814   t->peers[0]->id = t->owner;
815   GNUNET_PEER_change_rc (t->owner, 1);
816   t->mesh = h;
817   t->tid = tid;
818   if (NULL != h->new_tunnel)
819   {
820     struct GNUNET_ATS_Information atsi;
821
822     atsi.type = 0;
823     atsi.value = 0;
824     t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi);
825   }
826   LOG (GNUNET_ERROR_TYPE_DEBUG, "new incoming tunnel %X\n", t->tid);
827   return;
828 }
829
830
831 /**
832  * Process the tunnel destroy notification and free associated resources
833  *
834  * @param h     The mesh handle
835  * @param msg   A message with the details of the tunnel being destroyed
836  */
837 static void
838 process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
839                         const struct GNUNET_MESH_TunnelMessage *msg)
840 {
841   struct GNUNET_MESH_Tunnel *t;
842   MESH_TunnelNumber tid;
843
844   tid = ntohl (msg->tunnel_id);
845   t = retrieve_tunnel (h, tid);
846
847   if (NULL == t)
848   {
849     return;
850   }
851   if (0 == t->owner)
852   {
853     GNUNET_break (0);
854   }
855   LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %u destroyed\n", t->tid);
856   destroy_tunnel (t, GNUNET_YES);
857   return;
858 }
859
860
861 /**
862  * Process the new peer event and notify the upper level of it
863  *
864  * @param h     The mesh handle
865  * @param msg   A message with the details of the peer event
866  */
867 static void
868 process_peer_event (struct GNUNET_MESH_Handle *h,
869                     const struct GNUNET_MESH_PeerControl *msg)
870 {
871   struct GNUNET_MESH_Tunnel *t;
872   struct GNUNET_MESH_Peer *p;
873   struct GNUNET_ATS_Information atsi;
874   GNUNET_PEER_Id id;
875   uint16_t size;
876
877   LOG (GNUNET_ERROR_TYPE_DEBUG, "processig peer event\n");
878   size = ntohs (msg->header.size);
879   if (size != sizeof (struct GNUNET_MESH_PeerControl))
880   {
881     GNUNET_break (0);
882     return;
883   }
884   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
885   if (NULL == t)
886   {
887     GNUNET_break (0);
888     return;
889   }
890   id = GNUNET_PEER_search (&msg->peer);
891   if ((p = retrieve_peer (t, id)) == NULL)
892     p = add_peer_to_tunnel (t, &msg->peer);
893   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type))
894   {
895     LOG (GNUNET_ERROR_TYPE_DEBUG, "adding peer\n");
896     if (NULL != t->connect_handler)
897     {
898       atsi.type = 0;
899       atsi.value = 0;
900       t->connect_handler (t->cls, &msg->peer, &atsi);
901     }
902     p->connected = 1;
903   }
904   else
905   {
906     LOG (GNUNET_ERROR_TYPE_DEBUG, "removing peer\n");
907     if (NULL != t->disconnect_handler && p->connected)
908     {
909       t->disconnect_handler (t->cls, &msg->peer);
910     }
911     remove_peer_from_tunnel (p);
912     GNUNET_free (p);
913   }
914   LOG (GNUNET_ERROR_TYPE_DEBUG, "processing peer event END\n");
915 }
916
917
918 /**
919  * Process the incoming data packets
920  *
921  * @param h         The mesh handle
922  * @param message   A message encapsulating the data
923  * 
924  * @return GNUNET_YES if everything went fine
925  *         GNUNET_NO if client closed connection (h no longer valid)
926  */
927 static int
928 process_incoming_data (struct GNUNET_MESH_Handle *h,
929                        const struct GNUNET_MessageHeader *message)
930 {
931   const struct GNUNET_MessageHeader *payload;
932   const struct GNUNET_MESH_MessageHandler *handler;
933   const struct GNUNET_PeerIdentity *peer;
934   struct GNUNET_MESH_Unicast *ucast;
935   struct GNUNET_MESH_Multicast *mcast;
936   struct GNUNET_MESH_ToOrigin *to_orig;
937   struct GNUNET_MESH_Tunnel *t;
938   unsigned int i;
939   uint16_t type;
940
941   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n");
942   type = ntohs (message->type);
943   switch (type)
944   {
945   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
946     ucast = (struct GNUNET_MESH_Unicast *) message;
947
948     t = retrieve_tunnel (h, ntohl (ucast->tid));
949     payload = (struct GNUNET_MessageHeader *) &ucast[1];
950     peer = &ucast->oid;
951     LOG (GNUNET_ERROR_TYPE_DEBUG, "  ucast on tunnel %s [%x]\n",
952          GNUNET_i2s (peer), ntohl (ucast->tid));
953     break;
954   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
955     mcast = (struct GNUNET_MESH_Multicast *) message;
956     t = retrieve_tunnel (h, ntohl (mcast->tid));
957     payload = (struct GNUNET_MessageHeader *) &mcast[1];
958     peer = &mcast->oid;
959     LOG (GNUNET_ERROR_TYPE_DEBUG, "  mcast on tunnel %s [%x]\n",
960          GNUNET_i2s (peer), ntohl (mcast->tid));
961     break;
962   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
963     to_orig = (struct GNUNET_MESH_ToOrigin *) message;
964     t = retrieve_tunnel (h, ntohl (to_orig->tid));
965     payload = (struct GNUNET_MessageHeader *) &to_orig[1];
966     peer = &to_orig->sender;
967     LOG (GNUNET_ERROR_TYPE_DEBUG, "  torig on tunnel %s [%x]\n",
968          GNUNET_i2s (peer), ntohl (to_orig->tid));
969     break;
970   default:
971     GNUNET_break (0);
972     return GNUNET_YES;
973   }
974   if (NULL == t)
975   {
976     GNUNET_break (0);
977     return GNUNET_YES;
978   }
979   type = ntohs (payload->type);
980   for (i = 0; i < h->n_handlers; i++)
981   {
982     handler = &h->message_handlers[i];
983     if (handler->type == type)
984     {
985       struct GNUNET_ATS_Information atsi;
986
987       atsi.type = 0;
988       atsi.value = 0;
989       if (GNUNET_OK !=
990           handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi))
991       {
992         LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH: callback caused disconnection\n");
993         GNUNET_MESH_disconnect (h);
994         return GNUNET_NO;
995       }
996       else
997       {
998         LOG (GNUNET_ERROR_TYPE_DEBUG,
999              "MESH: callback completed successfully\n");
1000
1001       }
1002     }
1003   }
1004   return GNUNET_YES;
1005 }
1006
1007
1008 /**
1009  * Function to process all messages received from the service
1010  *
1011  * @param cls closure
1012  * @param msg message received, NULL on timeout or fatal error
1013  */
1014 static void
1015 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
1016 {
1017   struct GNUNET_MESH_Handle *h = cls;
1018
1019   if (msg == NULL)
1020   {
1021     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL msg\n");
1022     reconnect (h);
1023     return;
1024   }
1025   LOG (GNUNET_ERROR_TYPE_DEBUG, "received a message type %hu from MESH\n",
1026        ntohs (msg->type));
1027   switch (ntohs (msg->type))
1028   {
1029     /* Notify of a new incoming tunnel */
1030   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
1031     process_tunnel_created (h, (struct GNUNET_MESH_TunnelNotification *) msg);
1032     break;
1033     /* Notify of a tunnel disconnection */
1034   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
1035     process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg);
1036     break;
1037     /* Notify of a new peer or a peer disconnect in the tunnel */
1038   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD:
1039   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL:
1040     process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
1041     break;
1042     /* Notify of a new data packet in the tunnel */
1043   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
1044   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
1045   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
1046     if (GNUNET_NO == process_incoming_data (h, msg))
1047       return;
1048     break;
1049     /* We shouldn't get any other packages, log and ignore */
1050   default:
1051     LOG (GNUNET_ERROR_TYPE_WARNING,
1052          "MESH: unsolicited message form service (type %d)\n",
1053          ntohs (msg->type));
1054   }
1055   LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n");
1056   GNUNET_CLIENT_receive (h->client, &msg_received, h,
1057                          GNUNET_TIME_UNIT_FOREVER_REL);
1058 }
1059
1060
1061 /******************************************************************************/
1062 /************************       SEND FUNCTIONS     ****************************/
1063 /******************************************************************************/
1064
1065 /**
1066  * Function called to send a message to the service.
1067  * "buf" will be NULL and "size" zero if the socket was closed for writing in
1068  * the meantime.
1069  *
1070  * @param cls closure, the mesh handle
1071  * @param size number of bytes available in buf
1072  * @param buf where the callee should write the connect message
1073  * @return number of bytes written to buf
1074  */
1075 static size_t
1076 send_callback (void *cls, size_t size, void *buf)
1077 {
1078   struct GNUNET_MESH_Handle *h = cls;
1079   struct GNUNET_MESH_TransmitHandle *th;
1080   char *cbuf = buf;
1081   size_t tsize;
1082   size_t psize;
1083
1084   LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() Buffer %u\n", size);
1085   h->th = NULL;
1086   if ((0 == size) || (NULL == buf))
1087   {
1088     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL callback\n");
1089     reconnect (h);
1090     return 0;
1091   }
1092   tsize = 0;
1093   while ((NULL != (th = h->th_head)) && (size >= th->size))
1094   {
1095     if (NULL != th->notify)
1096     {
1097       if (th->tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1098       {
1099         /* traffic to origin */
1100         struct GNUNET_MESH_ToOrigin to;
1101         struct GNUNET_MessageHeader *mh;
1102
1103         GNUNET_assert (size >= th->size);
1104         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)];
1105         psize = th->notify (th->notify_cls, size - sizeof (to), mh);
1106         LOG (GNUNET_ERROR_TYPE_DEBUG, "  to origin, type %u\n",
1107              ntohs (mh->type));
1108         if (psize > 0)
1109         {
1110           psize += sizeof (to);
1111           GNUNET_assert (size >= psize);
1112           to.header.size = htons (psize);
1113           to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
1114           to.tid = htonl (th->tunnel->tid);
1115           memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1116           memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity));
1117           memcpy (cbuf, &to, sizeof (to));
1118         }
1119       }
1120       else if (th->target == 0)
1121       {
1122         /* multicast */
1123         struct GNUNET_MESH_Multicast mc;
1124         struct GNUNET_MessageHeader *mh;
1125
1126         GNUNET_assert (size >= th->size);
1127         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)];
1128         psize = th->notify (th->notify_cls, size - sizeof (mc), mh);
1129         LOG (GNUNET_ERROR_TYPE_DEBUG, "  multicast, type %u\n",
1130              ntohs (mh->type));
1131         if (psize > 0)
1132         {
1133           psize += sizeof (mc);
1134           GNUNET_assert (size >= psize);
1135           mc.header.size = htons (psize);
1136           mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
1137           mc.tid = htonl (th->tunnel->tid);
1138           mc.mid = 0;
1139           mc.ttl = 0;
1140           memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1141           memcpy (cbuf, &mc, sizeof (mc));
1142         }
1143       }
1144       else
1145       {
1146         /* unicast */
1147         struct GNUNET_MESH_Unicast uc;
1148         struct GNUNET_MessageHeader *mh;
1149
1150         GNUNET_assert (size >= th->size);
1151         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)];
1152         psize = th->notify (th->notify_cls, size - sizeof (uc), mh);
1153         LOG (GNUNET_ERROR_TYPE_DEBUG, "  unicast, type %u\n",
1154              ntohs (mh->type));
1155         if (psize > 0)
1156         {
1157           psize += sizeof (uc);
1158           GNUNET_assert (size >= psize);
1159           uc.header.size = htons (psize);
1160           uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
1161           uc.tid = htonl (th->tunnel->tid);
1162           memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1163           GNUNET_PEER_resolve (th->target, &uc.destination);
1164           memcpy (cbuf, &uc, sizeof (uc));
1165         }
1166       }
1167     }
1168     else
1169     {
1170       memcpy (cbuf, &th[1], th->size);
1171       psize = th->size;
1172     }
1173     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1174       GNUNET_SCHEDULER_cancel (th->timeout_task);
1175     if (NULL != th->notify)
1176     {
1177       th->tunnel->mesh->npackets--;
1178       th->tunnel->npackets--;
1179     }
1180     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1181     GNUNET_free (th);
1182     cbuf += psize;
1183     size -= psize;
1184     tsize += psize;
1185   }
1186   LOG (GNUNET_ERROR_TYPE_DEBUG, "  total size: %u\n", tsize);
1187   if (NULL != (th = h->th_head))
1188   {
1189     LOG (GNUNET_ERROR_TYPE_DEBUG, "  next size: %u\n", th->size);
1190     if (NULL == h->th)
1191       h->th =
1192           GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
1193                                                GNUNET_TIME_UNIT_FOREVER_REL,
1194                                                GNUNET_YES, &send_callback, h);
1195   }
1196   LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() END\n");
1197   if (GNUNET_NO == h->in_receive)
1198   {
1199     h->in_receive = GNUNET_YES;
1200     GNUNET_CLIENT_receive (h->client, &msg_received, h,
1201                            GNUNET_TIME_UNIT_FOREVER_REL);
1202   }
1203   return tsize;
1204 }
1205
1206
1207 /**
1208  * Auxiliary function to send an already constructed packet to the service.
1209  * Takes care of creating a new queue element, copying the message and
1210  * calling the tmt_rdy function if necessary.
1211  * 
1212  * @param h mesh handle
1213  * @param msg message to transmit
1214  * @param tunnel tunnel this send is related to (NULL if N/A)
1215  */
1216 static void
1217 send_packet (struct GNUNET_MESH_Handle *h,
1218              const struct GNUNET_MessageHeader *msg,
1219              struct GNUNET_MESH_Tunnel *tunnel)
1220 {
1221   struct GNUNET_MESH_TransmitHandle *th;
1222   size_t msize;
1223
1224   msize = ntohs (msg->size);
1225   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
1226   th->priority = UINT32_MAX;
1227   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1228   th->size = msize;
1229   th->tunnel = tunnel;
1230   memcpy (&th[1], msg, msize);
1231   add_to_queue (h, th);
1232   if (NULL != h->th)
1233     return;
1234   h->th =
1235       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
1236                                            GNUNET_TIME_UNIT_FOREVER_REL,
1237                                            GNUNET_YES, &send_callback, h);
1238 }
1239
1240
1241 /******************************************************************************/
1242 /**********************      API CALL DEFINITIONS     *************************/
1243 /******************************************************************************/
1244
1245 /**
1246  * Connect to the mesh service.
1247  *
1248  * @param cfg configuration to use
1249  * @param queue_size size of the data message queue, shared among all tunnels
1250  *                   (each tunnel is guaranteed to accept at least one message,
1251  *                    no matter what is the status of other tunnels)
1252  * @param cls closure for the various callbacks that follow
1253  *            (including handlers in the handlers array)
1254  * @param new_tunnel function called when an *inbound* tunnel is created
1255  * @param cleaner function called when an *inbound* tunnel is destroyed by the
1256  *                remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy
1257  *                is called on the tunnel
1258  * @param handlers callbacks for messages we care about, NULL-terminated
1259  *                note that the mesh is allowed to drop notifications about
1260  *                inbound messages if the client does not process them fast
1261  *                enough (for this notification type, a bounded queue is used)
1262  * @param stypes list of the applications that this client claims to provide
1263  * @return handle to the mesh service NULL on error
1264  *         (in this case, init is never called)
1265  */
1266 struct GNUNET_MESH_Handle *
1267 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1268                      unsigned int queue_size, void *cls,
1269                      GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel,
1270                      GNUNET_MESH_TunnelEndHandler cleaner,
1271                      const struct GNUNET_MESH_MessageHandler *handlers,
1272                      const GNUNET_MESH_ApplicationType *stypes)
1273 {
1274   struct GNUNET_MESH_Handle *h;
1275
1276   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect()\n");
1277   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
1278   h->cfg = cfg;
1279   h->max_queue_size = queue_size;
1280   h->new_tunnel = new_tunnel;
1281   h->cleaner = cleaner;
1282   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1283   if (h->client == NULL)
1284   {
1285     GNUNET_break (0);
1286     GNUNET_free (h);
1287     return NULL;
1288   }
1289   h->cls = cls;
1290   /* FIXME memdup? */
1291   h->applications = stypes;
1292   h->message_handlers = handlers;
1293   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
1294   h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1295
1296   /* count handlers and apps, calculate size */
1297   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
1298   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
1299   send_connect (h);
1300   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect() END\n");
1301   return h;
1302 }
1303
1304
1305 /**
1306  * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel
1307  * disconnect callbacks will be called on any still connected peers, notifying
1308  * about their disconnection. The registered inbound tunnel cleaner will be
1309  * called should any inbound tunnels still exist.
1310  *
1311  * @param handle connection to mesh to disconnect
1312  */
1313 void
1314 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1315 {
1316   struct GNUNET_MESH_Tunnel *t;
1317   struct GNUNET_MESH_Tunnel *aux;
1318   struct GNUNET_MESH_TransmitHandle *th;
1319
1320   t = handle->tunnels_head;
1321   while (NULL != t)
1322   {
1323     aux = t->next;
1324     if (t->tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1325     {
1326       GNUNET_break (0);
1327       LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %X not destroyed\n", t->tid);
1328     }
1329     destroy_tunnel (t, GNUNET_YES);
1330     t = aux;
1331   }
1332   while ( (th = handle->th_head) != NULL)
1333   {
1334     struct GNUNET_MessageHeader *msg;
1335
1336     /* Make sure it is an allowed packet (everything else should have been
1337      * already canceled).
1338      */
1339     GNUNET_break (UINT32_MAX == th->priority);
1340     GNUNET_break (NULL == th->notify);
1341     msg = (struct GNUNET_MessageHeader *) &th[1];
1342     switch (ntohs(msg->type))
1343     {
1344       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT:
1345       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
1346         break;
1347       default:
1348         GNUNET_break (0);
1349         LOG (GNUNET_ERROR_TYPE_DEBUG, "unexpected msg %u\n",
1350              ntohs(msg->type));
1351     }
1352
1353     GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th);
1354     GNUNET_free (th);
1355   }
1356
1357   if (NULL != handle->th)
1358   {
1359     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1360     handle->th = NULL;
1361   }
1362   if (NULL != handle->client)
1363   {
1364     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
1365     handle->client = NULL;
1366   }
1367   if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
1368   {
1369     GNUNET_SCHEDULER_cancel(handle->reconnect_task);
1370     handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
1371   }
1372   GNUNET_free (handle);
1373 }
1374
1375
1376 /**
1377  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
1378  * and to broadcast).
1379  *
1380  * @param h mesh handle
1381  * @param tunnel_ctx client's tunnel context to associate with the tunnel
1382  * @param connect_handler function to call when peers are actually connected
1383  * @param disconnect_handler function to call when peers are disconnected
1384  * @param handler_cls closure for connect/disconnect handlers
1385  */
1386 struct GNUNET_MESH_Tunnel *
1387 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
1388                            GNUNET_MESH_PeerConnectHandler connect_handler,
1389                            GNUNET_MESH_PeerDisconnectHandler disconnect_handler,
1390                            void *handler_cls)
1391 {
1392   struct GNUNET_MESH_Tunnel *t;
1393   struct GNUNET_MESH_TunnelMessage msg;
1394
1395   LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new tunnel\n");
1396   t = create_tunnel (h, 0);
1397   t->connect_handler = connect_handler;
1398   t->disconnect_handler = disconnect_handler;
1399   t->cls = handler_cls;
1400   t->ctx = tunnel_ctx;
1401   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
1402   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1403   msg.tunnel_id = htonl (t->tid);
1404   send_packet (h, &msg.header, t);
1405   return t;
1406 }
1407
1408
1409 /**
1410  * Destroy an existing tunnel. The existing callback for the tunnel will NOT
1411  * be called.
1412  *
1413  * @param tunnel tunnel handle
1414  */
1415 void
1416 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel)
1417 {
1418   struct GNUNET_MESH_Handle *h;
1419   struct GNUNET_MESH_TunnelMessage msg;
1420   struct GNUNET_MESH_TransmitHandle *th;
1421
1422   LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying tunnel\n");
1423   h = tunnel->mesh;
1424
1425   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
1426   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1427   msg.tunnel_id = htonl (tunnel->tid);
1428   th = h->th_head;
1429   while (th != NULL)
1430   {
1431     struct GNUNET_MESH_TransmitHandle *aux;
1432     if (th->tunnel == tunnel)
1433     {
1434       aux = th->next;
1435       /* FIXME call the handler? */
1436       if (NULL != th->notify)
1437         th->notify (th->notify_cls, 0, NULL);
1438       GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1439       GNUNET_free (th);
1440       th = aux;
1441     }
1442     else
1443       th = th->next;
1444   }
1445
1446   destroy_tunnel (tunnel, GNUNET_NO);
1447   send_packet (h, &msg.header, tunnel);
1448 }
1449
1450
1451 /**
1452  * Request that a peer should be added to the tunnel.  The existing
1453  * connect handler will be called ONCE with either success or failure.
1454  * This function should NOT be called again with the same peer before the
1455  * connect handler is called.
1456  *
1457  * @param tunnel handle to existing tunnel
1458  * @param peer peer to add
1459  */
1460 void
1461 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
1462                                       const struct GNUNET_PeerIdentity *peer)
1463 {
1464   struct GNUNET_MESH_PeerControl msg;
1465   GNUNET_PEER_Id peer_id;
1466   unsigned int i;
1467
1468   peer_id = GNUNET_PEER_intern (peer);
1469   for (i = 0; i < tunnel->npeers; i++)
1470   {
1471     if (tunnel->peers[i]->id == peer_id)
1472     {
1473       /* Peer already exists in tunnel */
1474       GNUNET_PEER_change_rc (peer_id, -1);
1475       GNUNET_break (0);
1476       return;
1477     }
1478   }
1479   if (NULL == add_peer_to_tunnel (tunnel, peer))
1480     return;
1481
1482   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1483   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
1484   msg.tunnel_id = htonl (tunnel->tid);
1485   msg.peer = *peer;
1486   send_packet (tunnel->mesh, &msg.header, tunnel);
1487
1488   return;
1489 }
1490
1491
1492 /**
1493  * Request that a peer should be removed from the tunnel.  The existing
1494  * disconnect handler will be called ONCE if we were connected.
1495  *
1496  * @param tunnel handle to existing tunnel
1497  * @param peer peer to remove
1498  */
1499 void
1500 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
1501                                       const struct GNUNET_PeerIdentity *peer)
1502 {
1503   struct GNUNET_MESH_PeerControl msg;
1504   GNUNET_PEER_Id peer_id;
1505   unsigned int i;
1506
1507   peer_id = GNUNET_PEER_search (peer);
1508   if (0 == peer_id)
1509   {
1510     GNUNET_break (0);
1511     return;
1512   }
1513   for (i = 0; i < tunnel->npeers; i++)
1514     if (tunnel->peers[i]->id == peer_id)
1515       break;
1516   if (i == tunnel->npeers)
1517   {
1518     GNUNET_break (0);
1519     return;
1520   }
1521   if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1)
1522     tunnel->disconnect_handler (tunnel->cls, peer);
1523   GNUNET_PEER_change_rc (peer_id, -1);
1524   GNUNET_free (tunnel->peers[i]);
1525   tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
1526   GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
1527
1528   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1529   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
1530   msg.tunnel_id = htonl (tunnel->tid);
1531   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1532   send_packet (tunnel->mesh, &msg.header, tunnel);
1533 }
1534
1535
1536 /**
1537  * Request that the mesh should try to connect to a peer supporting the given
1538  * message type.
1539  *
1540  * @param tunnel handle to existing tunnel
1541  * @param app_type application type that must be supported by the peer (MESH
1542  *                 should discover peer in proximity handling this type)
1543  */
1544 void
1545 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
1546                                           GNUNET_MESH_ApplicationType app_type)
1547 {
1548   struct GNUNET_MESH_ConnectPeerByType msg;
1549
1550   GNUNET_array_append (tunnel->apps, tunnel->napps, app_type);
1551
1552   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
1553   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
1554   msg.tunnel_id = htonl (tunnel->tid);
1555   msg.type = htonl (app_type);
1556   send_packet (tunnel->mesh, &msg.header, tunnel);
1557 }
1558
1559
1560 /**
1561  * Ask the mesh to call "notify" once it is ready to transmit the
1562  * given number of bytes to the specified "target".  If we are not yet
1563  * connected to the specified peer, a call to this function will cause
1564  * us to try to establish a connection.
1565  *
1566  * @param tunnel tunnel to use for transmission
1567  * @param cork is corking allowed for this transmission?
1568  * @param priority how important is the message?
1569  * @param maxdelay how long can the message wait?
1570  * @param target destination for the message,
1571  *               NULL for multicast to all tunnel targets
1572  * @param notify_size how many bytes of buffer space does notify want?
1573  * @param notify function to call when buffer space is available;
1574  *        will be called with NULL on timeout or if the overall queue
1575  *        for this peer is larger than queue_size and this is currently
1576  *        the message with the lowest priority
1577  * @param notify_cls closure for notify
1578  * @return non-NULL if the notify callback was queued,
1579  *         NULL if we can not even queue the request (insufficient
1580  *         memory); if NULL is returned, "notify" will NOT be called.
1581  */
1582 struct GNUNET_MESH_TransmitHandle *
1583 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1584                                    uint32_t priority,
1585                                    struct GNUNET_TIME_Relative maxdelay,
1586                                    const struct GNUNET_PeerIdentity *target,
1587                                    size_t notify_size,
1588                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1589                                    void *notify_cls)
1590 {
1591   struct GNUNET_MESH_TransmitHandle *th;
1592   struct GNUNET_MESH_TransmitHandle *least_priority_th;
1593   uint32_t least_priority;
1594   size_t overhead;
1595
1596   GNUNET_assert (NULL != tunnel);
1597   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh notify transmit ready called\n");
1598   if (NULL != target)
1599     LOG (GNUNET_ERROR_TYPE_DEBUG, "    target %s\n", GNUNET_i2s (target));
1600   else
1601     LOG (GNUNET_ERROR_TYPE_DEBUG, "    target multicast\n");
1602   GNUNET_assert (NULL != notify);
1603   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
1604       tunnel->npackets > 0)
1605   {
1606     /* queue full */
1607     if (0 == priority)
1608       return NULL;
1609     th = tunnel->mesh->th_tail;
1610     least_priority = priority;
1611     least_priority_th = NULL;
1612     while (NULL != th)
1613     {
1614       if (th->priority < least_priority && th->tunnel->npackets > 1)
1615       {
1616         least_priority_th = th;
1617         least_priority = th->priority;
1618       }
1619       th = th->prev;
1620     }
1621     if (NULL == least_priority_th)
1622       return NULL;
1623     /* Can't be a control message */
1624     GNUNET_assert (NULL != least_priority_th->notify);
1625     least_priority_th->notify (notify_cls, 0, NULL);
1626     least_priority_th->tunnel->npackets--;
1627     tunnel->mesh->npackets--;
1628     GNUNET_CONTAINER_DLL_remove (tunnel->mesh->th_head, tunnel->mesh->th_tail,
1629                                  least_priority_th);
1630     if (GNUNET_SCHEDULER_NO_TASK != least_priority_th->timeout_task)
1631       GNUNET_SCHEDULER_cancel (least_priority_th->timeout_task);
1632     GNUNET_free (least_priority_th);
1633   }
1634   tunnel->npackets++;
1635   tunnel->mesh->npackets++;
1636   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1637   th->tunnel = tunnel;
1638   th->priority = priority;
1639   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1640   th->target = GNUNET_PEER_intern (target);
1641   if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1642     overhead = sizeof (struct GNUNET_MESH_ToOrigin);
1643   else if (NULL == target)
1644     overhead = sizeof (struct GNUNET_MESH_Multicast);
1645   else
1646     overhead = sizeof (struct GNUNET_MESH_Unicast);
1647   th->size = notify_size + overhead;
1648   th->notify = notify;
1649   th->notify_cls = notify_cls;
1650   add_to_queue (tunnel->mesh, th);
1651   if (NULL != tunnel->mesh->th)
1652     return th;
1653   tunnel->mesh->th =
1654       GNUNET_CLIENT_notify_transmit_ready (tunnel->mesh->client, th->size,
1655                                            GNUNET_TIME_UNIT_FOREVER_REL,
1656                                            GNUNET_YES, &send_callback,
1657                                            tunnel->mesh);
1658   return th;
1659 }
1660
1661
1662 /**
1663  * Cancel the specified transmission-ready notification.
1664  *
1665  * @param th handle that was returned by "notify_transmit_ready".
1666  */
1667 void
1668 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1669 {
1670   struct GNUNET_MESH_Handle *mesh;
1671
1672   mesh = th->tunnel->mesh;
1673   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1674     GNUNET_SCHEDULER_cancel (th->timeout_task);
1675   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1676   GNUNET_free (th);
1677   if ((NULL == mesh->th_head) && (NULL != mesh->th))
1678   {
1679     /* queue empty, no point in asking for transmission */
1680     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1681     mesh->th = NULL;
1682   }
1683 }
1684
1685
1686 /**
1687  * Transition API for tunnel ctx management
1688  */
1689 void
1690 GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data)
1691 {
1692   tunnel->ctx = data;
1693 }
1694
1695 /**
1696  * Transition API for tunnel ctx management
1697  */
1698 void *
1699 GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel)
1700 {
1701   return tunnel->ctx;
1702 }
1703
1704
1705 #if 0                           /* keep Emacsens' auto-indent happy */
1706 {
1707 #endif
1708 #ifdef __cplusplus
1709 }
1710 #endif