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