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