todo list
[oweals/gnunet.git] / src / mesh / mesh_api_new.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file mesh/mesh_api_new.c
23  * @brief mesh api: client implementation of mesh service
24  * @author Bartlomiej Polot
25  *
26  * TODO:
27  * - handle reconnect (service crash/disconnect) properly
28  * - count only data for queue length; store current queue length
29  *   with tunnel instead of counting each time
30  *   (also count per tunnel instead of for the entire mesh handle?)
31  * - callbacks to client missing on certain events
32  * - processing messages from service is incomplete
33  *
34  * STRUCTURE:
35  * - CONSTANTS
36  * - DATA STRUCTURES
37  * - AUXILIARY FUNCTIONS
38  * - RECEIVE HANDLERS
39  * - SEND FUNCTIONS
40  * - API CALL DEFINITIONS
41  */
42
43 #ifdef __cplusplus
44
45 extern "C"
46 {
47 #if 0                           /* keep Emacsens' auto-indent happy */
48 }
49 #endif
50 #endif
51
52
53 #include "platform.h"
54 #include "gnunet_common.h"
55 #include "gnunet_client_lib.h"
56 #include "gnunet_util_lib.h"
57 #include "gnunet_peer_lib.h"
58 #include "gnunet_mesh_service_new.h"
59 #include "mesh.h"
60 #include "mesh_protocol.h"
61
62 /**
63  * TODO: replace with extra argument to mesh-connect.
64  */
65 #define MESH_API_MAX_QUEUE 10
66
67 /******************************************************************************/
68 /************************      DATA STRUCTURES     ****************************/
69 /******************************************************************************/
70
71 /**
72  * Transmission queue to the service
73  */
74 struct GNUNET_MESH_TransmitHandle
75 {
76     /**
77      * Double Linked list
78      */
79   struct GNUNET_MESH_TransmitHandle *next;
80
81     /**
82      * Double Linked list
83      */
84   struct GNUNET_MESH_TransmitHandle *prev;
85
86     /**
87      * Data itself, currently points to the end of this struct if 
88      * we have a message already, NULL if the message is to be 
89      * obtained from the callback.
90      */
91   const struct GNUNET_MessageHeader *data;
92
93   /**
94    * Tunnel this message is sent over (may be NULL for control messages).
95    */
96   struct GNUNET_MESH_Tunnel *tunnel;
97
98   /**
99    * Callback to obtain the message to transmit, or NULL if we
100    * got the message in 'data'.  Notice that messages built
101    * by 'notify' need to be encapsulated with information about
102    * the 'target'.
103    */
104   GNUNET_CONNECTION_TransmitReadyNotify notify;
105
106   /**
107    * Closure for 'notify'
108    */
109   void *notify_cls;
110   
111   /**
112    * How long is this message valid.  Once the timeout has been
113    * reached, the message must no longer be sent.  If this 
114    * is a message with a 'notify' callback set, the 'notify'
115    * function should be called with 'buf' NULL and size 0.
116    */
117   struct GNUNET_TIME_Absolute timeout;
118
119   /**
120    * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
121    */
122   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
123
124   /**
125    * Priority of the message.  The queue is sorted by priority,
126    * control messages have the maximum priority (UINT32_MAX).
127    */
128   uint32_t priority;
129  
130   /**
131    * Target of the message, 0 for broadcast.  This field
132    * is only valid if 'notify' is non-NULL.
133    */
134   GNUNET_PEER_Id target;
135                                  
136   /**
137    * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
138    */
139   size_t size;
140 };
141
142
143 /**
144  * Opaque handle to the service.
145  */
146 struct GNUNET_MESH_Handle
147 {
148     /**
149      * Handle to the server connection, to send messages later
150      */
151   struct GNUNET_CLIENT_Connection *client;
152
153     /**
154      * Set of handlers used for processing incoming messages in the tunnels
155      */
156   const struct GNUNET_MESH_MessageHandler *message_handlers;
157
158     /**
159      * Set of applications that should be claimed to be offered at this node.
160      * Note that this is just informative, the appropiate handlers must be
161      * registered independently and the mapping is up to the developer of the
162      * client application.
163      */
164   const GNUNET_MESH_ApplicationType *applications; 
165
166     /**
167      * Double linked list of the tunnels this client is connected to.
168      */
169   struct GNUNET_MESH_Tunnel *tunnels_head;
170   struct GNUNET_MESH_Tunnel *tunnels_tail;
171
172     /**
173      * Callback for tunnel disconnection
174      */
175   GNUNET_MESH_TunnelEndHandler *cleaner;
176
177     /**
178      * Handle to cancel pending transmissions in case of disconnection
179      */
180   struct GNUNET_CLIENT_TransmitHandle *th;
181
182     /**
183      * Closure for all the handlers given by the client
184      */
185   void *cls;
186
187     /**
188      * Messages to send to the service
189      */
190   struct GNUNET_MESH_TransmitHandle *queue_head;
191   struct GNUNET_MESH_TransmitHandle *queue_tail;
192
193     /**
194      * tid of the next tunnel to create (to avoid reusing IDs often)
195      */
196   MESH_TunnelNumber next_tid;
197
198   unsigned int n_handlers;
199
200   unsigned int n_applications;
201
202   unsigned int max_queue_size;
203
204   /**
205    * Have we started the task to receive messages from the service
206    * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
207    */
208   int in_receive;
209 };
210
211 /**
212  * Opaque handle to a tunnel.
213  */
214 struct GNUNET_MESH_Tunnel
215 {
216
217     /**
218      * DLL
219      */
220   struct GNUNET_MESH_Tunnel *next;
221   struct GNUNET_MESH_Tunnel *prev;
222
223     /**
224      * Callback to execute when peers connect to the tunnel
225      */
226   GNUNET_MESH_TunnelConnectHandler connect_handler;
227
228     /**
229      * Callback to execute when peers disconnect to the tunnel
230      */
231   GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
232
233     /**
234      * All peers added to the tunnel
235      */
236   GNUNET_PEER_Id *peers;
237
238     /**
239      * Closure for the connect/disconnect handlers
240      */
241   void *cls;
242
243     /**
244      * Handle to the mesh this tunnel belongs to
245      */
246   struct GNUNET_MESH_Handle *mesh;
247
248     /**
249      * Local ID of the tunnel
250      */
251   MESH_TunnelNumber tid;
252
253     /**
254      * Owner of the tunnel
255      */
256   GNUNET_PEER_Id owner;
257
258     /**
259      * Number of peer added to the tunnel
260      */
261   unsigned int npeers;
262 };
263
264
265 /******************************************************************************/
266 /***********************     AUXILIARY FUNCTIONS      *************************/
267 /******************************************************************************/
268
269 /**
270  * Get the tunnel handler for the tunnel specified by id from the given handle
271  * @param h Mesh handle
272  * @param tid ID of the wanted tunnel
273  * @return handle to the required tunnel or NULL if not found
274  */
275 static struct GNUNET_MESH_Tunnel *
276 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
277 {
278   struct GNUNET_MESH_Tunnel *t;
279
280   t = h->tunnels_head;
281   while (t != NULL)
282   {
283     if (t->tid == tid)
284       return t;
285     t = t->next;
286   }
287   return NULL;
288 }
289
290 /**
291  * Get the length of the transmission queue
292  * @param h mesh handle whose queue is to be measured
293  */
294 static unsigned int
295 get_queue_length (struct GNUNET_MESH_Handle *h)
296 {
297   struct GNUNET_MESH_TransmitHandle *q;
298   unsigned int i;
299
300   /* count */
301   for (q = h->queue_head, i = 0; NULL != q; q = q->next, i++) ;
302
303   return i;
304 }
305
306
307 /******************************************************************************/
308 /***********************      RECEIVE HANDLERS     ****************************/
309 /******************************************************************************/
310
311 /**
312  * Process the new tunnel notification and add it to the tunnels in the handle
313  *
314  * @param h     The mesh handle
315  * @param msg   A message with the details of the new incoming tunnel
316  */
317 static void
318 process_tunnel_create (struct GNUNET_MESH_Handle *h,
319                        const struct GNUNET_MESH_TunnelMessage *msg)
320 {
321   struct GNUNET_MESH_Tunnel *t;
322   MESH_TunnelNumber tid;
323
324   tid = ntohl (msg->tunnel_id);
325   if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK)
326   {
327     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
328                 "MESH: received an incoming tunnel with tid in local range (%X)\n",
329                 tid);
330     GNUNET_break_op (0);
331     return;                     //FIXME abort? reconnect?
332   }
333   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
334   t->cls = h->cls;
335   t->mesh = h;
336   t->tid = tid;
337
338   return;
339 }
340
341
342 /**
343  * Process the new peer event and notify the upper level of it
344  *
345  * @param h     The mesh handle
346  * @param msg   A message with the details of the peer event
347  */
348 static void
349 process_peer_event (struct GNUNET_MESH_Handle *h,
350                     const struct GNUNET_MESH_PeerControl *msg)
351 {
352   struct GNUNET_MESH_Tunnel *t;
353   uint16_t size;
354
355   size = ntohs (msg->header.size);
356   if (size != sizeof (struct GNUNET_MESH_PeerControl))
357   {
358     GNUNET_break_op (0);
359     return;
360   }
361   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
362   if (NULL == t)
363   {
364     GNUNET_break_op (0);
365     return;
366   }
367   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED == msg->header.type)
368   {
369     if (NULL != t->connect_handler)
370     {
371       t->connect_handler (t->cls, &msg->peer, NULL);    /* FIXME atsi */
372     }
373   }
374   else
375   {
376     if (NULL != t->disconnect_handler)
377     {
378       t->disconnect_handler (t->cls, &msg->peer);
379     }
380   }
381 }
382
383
384 /**
385  * Process the incoming data packets
386  *
387  * @param h     The mesh handle
388  * @param msh   A message encapsulating the data
389  */
390 static void
391 process_incoming_data (struct GNUNET_MESH_Handle *h,
392                        const struct GNUNET_MessageHeader *message)
393 {
394   const struct GNUNET_MessageHeader *payload;
395   const struct GNUNET_MESH_MessageHandler *handler;
396   const struct GNUNET_PeerIdentity *peer;
397   struct GNUNET_MESH_Unicast *ucast;
398   struct GNUNET_MESH_Multicast *mcast;
399   struct GNUNET_MESH_ToOrigin *to_orig;
400   struct GNUNET_MESH_Tunnel *t;
401   uint16_t type;
402   int i;
403
404   type = ntohs (message->type);
405   switch (type)
406   {
407   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
408     ucast = (struct GNUNET_MESH_Unicast *) message;
409     t = retrieve_tunnel (h, ntohl (ucast->tid));
410     payload = (struct GNUNET_MessageHeader *) &ucast[1];
411     peer = &ucast->oid;
412     break;
413   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
414     mcast = (struct GNUNET_MESH_Multicast *) message;
415     t = retrieve_tunnel (h, ntohl (mcast->tid));
416     payload = (struct GNUNET_MessageHeader *) &mcast[1];
417     peer = &mcast->oid;
418     break;
419   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
420     to_orig = (struct GNUNET_MESH_ToOrigin *) message;
421     t = retrieve_tunnel (h, ntohl (to_orig->tid));
422     payload = (struct GNUNET_MessageHeader *) &to_orig[1];
423     peer = &to_orig->sender;
424     break;
425   default:
426     GNUNET_break_op (0);
427     return;
428   }
429   if (NULL == t)
430   {
431     GNUNET_break_op (0);
432     return;
433   }
434   for (i = 0; i < h->n_handlers; i++)
435   {
436     handler = &h->message_handlers[i];
437     if (handler->type == type)
438     {
439       if (GNUNET_OK == handler->callback (h->cls, t, NULL,      /* FIXME ctx */
440                                           peer, payload, NULL)) /* FIXME atsi */
441       {
442         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443                     "MESH: callback completed successfully\n");
444       }
445       else
446       {
447         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448                     "MESH: callback caused disconnection\n");
449         GNUNET_MESH_disconnect (h);
450       }
451     }
452   }
453 }
454
455
456 /**
457  * Function to process all messages received from the service
458  *
459  * @param cls closure
460  * @param msg message received, NULL on timeout or fatal error
461  */
462 static void
463 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
464 {
465   struct GNUNET_MESH_Handle *h = cls;
466
467   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message from MESH\n");
468   if (msg == NULL)
469   {
470     GNUNET_break (0);
471     h->in_receive = GNUNET_NO;
472     // rather: do_reconnect () -- and set 'in_receive' to NO there...
473     // FIXME: service disconnect, handle!
474     return;
475   }
476
477   switch (ntohs (msg->type))
478   {
479     /* Notify of a new incoming tunnel */
480   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
481     process_tunnel_create (h, (struct GNUNET_MESH_TunnelMessage *) msg);
482     break;
483     /* Notify of a new peer or a peer disconnect in the tunnel */
484   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED:
485   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED:
486     process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
487     break;
488     /* Notify of a new data packet in the tunnel */
489   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
490   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
491   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
492     process_incoming_data (h, msg);
493     break;
494     /* We shouldn't get any other packages, log and ignore */
495   default:
496     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
497                 "MESH: unsolicited message form service (type %d)\n",
498                 ntohs (msg->type));
499   }
500
501   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
502   GNUNET_CLIENT_receive (h->client, &msg_received, h,
503                          GNUNET_TIME_UNIT_FOREVER_REL);
504 }
505
506
507 /******************************************************************************/
508 /************************       SEND FUNCTIONS     ****************************/
509 /******************************************************************************/
510
511 /**
512  * Function called to send a message to the service.
513  * "buf" will be NULL and "size" zero if the socket was closed for writing in
514  * the meantime.
515  *
516  * @param cls closure, the mesh handle
517  * @param size number of bytes available in buf
518  * @param buf where the callee should write the connect message
519  * @return number of bytes written to buf
520  */
521 static size_t
522 send_raw (void *cls, size_t size, void *buf)
523 {
524   struct GNUNET_MESH_Handle *h = cls;
525   struct GNUNET_MESH_TransmitHandle *q;
526   char *cbuf = buf;
527   size_t ret;
528   size_t psize;
529
530   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
531   h->th = NULL;
532   if ( (0 == size) || (NULL == buf) )
533   {
534     // FIXME: disconnect, reconnect, retry?
535     // do_reconnect ();
536     return 0;
537   }
538   ret = 0;
539   while ( (NULL != (q = h->queue_head)) &&
540           (size >= q->size) )
541     {
542       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
543                        "mesh-api",
544                        "type: %u\n",
545                        ntohs (q->data->type));
546       if (NULL == q->data)
547         {
548           GNUNET_assert (NULL != q->notify);
549           if (q->target == 0)
550             {
551               /* multicast */
552               struct GNUNET_MESH_Multicast mc; 
553               
554               GNUNET_assert (size >= sizeof (mc) + q->size);
555               psize = q->notify (q->notify_cls,
556                                  size - sizeof (mc), 
557                                  &cbuf[sizeof(mc)]);
558               if (psize > 0)
559                 {
560                   mc.header.size = htons (sizeof (mc) + q->size);
561                   mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
562                   mc.tid = htonl (q->tunnel->tid);
563                   memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); /* myself */
564                   memcpy (cbuf, &mc, sizeof (mc));
565                   psize = q->size + sizeof (mc);
566                 }
567             }
568           else
569             {
570               /* unicast */
571               struct GNUNET_MESH_Unicast uc; 
572               
573               GNUNET_assert (size >= sizeof (uc) + q->size);
574               psize = q->notify (q->notify_cls,
575                                  size - sizeof (uc), 
576                                  &cbuf[sizeof(uc)]);
577               if (psize > 0)
578                 {
579                   uc.header.size = htons (sizeof (uc) + q->size);
580                   uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
581                   uc.tid = htonl (q->tunnel->tid);
582                   memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); /* myself */
583                   GNUNET_PEER_resolve (q->target, &uc.destination);
584                   memcpy (cbuf, &uc, sizeof (uc));
585                   psize = q->size + sizeof (uc);
586                 }         
587             }
588         }
589       else
590         {
591           memcpy (cbuf, q->data, q->size);
592           psize = q->size;
593         }
594       if (q->timeout_task != GNUNET_SCHEDULER_NO_TASK)
595         GNUNET_SCHEDULER_cancel (q->timeout_task);
596       GNUNET_CONTAINER_DLL_remove (h->queue_head, h->queue_tail, q);
597       GNUNET_free (q);
598       cbuf += psize;
599       size -= psize;
600       ret += psize;
601     }
602
603   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   size: %u\n", ret);
604
605   if (NULL != (q = h->queue_head))
606   {
607     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   next size: %u\n",
608                 q->size);
609     h->th =
610       GNUNET_CLIENT_notify_transmit_ready (h->client, q->size,
611                                            GNUNET_TIME_UNIT_FOREVER_REL,
612                                            GNUNET_YES, &send_raw, h);
613   }
614   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
615   if (GNUNET_NO == h->in_receive)
616     {
617       h->in_receive = GNUNET_YES;
618       GNUNET_CLIENT_receive (h->client, &msg_received, h,
619                              GNUNET_TIME_UNIT_FOREVER_REL);
620     }
621   return ret;
622 }
623
624
625 static void
626 timeout_transmission (void *cls,
627                       const struct GNUNET_SCHEDULER_TaskContext *tc)
628 {
629   struct GNUNET_MESH_TransmitHandle *q = cls;
630   struct GNUNET_MESH_Handle *mesh;
631   
632   mesh = q->tunnel->mesh;
633   GNUNET_CONTAINER_DLL_remove (mesh->queue_head, 
634                                mesh->queue_tail,
635                                q);
636   if (q->notify != NULL)
637     q->notify (q->notify_cls, 0, NULL); /* signal timeout */
638   GNUNET_free (q);    
639   if ( (NULL == mesh->queue_head) &&
640        (NULL != mesh->th) )
641     {
642       /* queue empty, no point in asking for transmission */
643       GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
644       mesh->th = NULL;
645     }    
646 }
647
648
649 /**
650  * Add a transmit handle to the transmission queue (by priority).
651  * Also manage timeout.
652  *
653  * @param h mesh handle with the queue head and tail
654  * @param q handle to add
655  */
656 static void
657 queue_transmit_handle (struct GNUNET_MESH_Handle *h,
658                        struct GNUNET_MESH_TransmitHandle *q)
659 {
660   struct GNUNET_MESH_TransmitHandle *p;
661
662   p = h->queue_head;
663   while ( (NULL != p) && (q->priority < p->priority) )
664     p = p->next;
665   GNUNET_CONTAINER_DLL_insert_after (h->queue_head, h->queue_tail, p->prev, q);
666   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value != q->timeout.abs_value)
667     q->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (q->timeout),
668                                                     &timeout_transmission,
669                                                     q);
670 }
671
672
673 /**
674  * Auxiliary function to send a packet to the service
675  * Takes care of creating a new queue element and calling the tmt_rdy function
676  * if necessary.
677  * @param h mesh handle
678  * @param msg message to transmit
679  */
680 static void
681 send_packet (struct GNUNET_MESH_Handle *h, 
682              const struct GNUNET_MessageHeader *msg)
683 {
684   struct GNUNET_MESH_TransmitHandle *q;
685   size_t msize;
686
687   msize = ntohs (msg->size);
688   q = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
689   q->priority = UINT32_MAX;
690   q->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;  
691   q->size = msize;
692   q->data = (void*) &q[1];
693   memcpy (&q[1], msg, msize);
694   queue_transmit_handle (h, q);
695   if (NULL != h->th)
696     return;
697   h->th =
698     GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
699                                          GNUNET_TIME_UNIT_FOREVER_REL,
700                                          GNUNET_YES, &send_raw, h);
701 }
702
703 /******************************************************************************/
704 /**********************      API CALL DEFINITIONS     *************************/
705 /******************************************************************************/
706
707 /**
708  * Connect to the mesh service.
709  *
710  * @param cfg configuration to use
711  * @param cls closure for the various callbacks that follow
712  *            (including handlers in the handlers array)
713  * @param cleaner function called when an *inbound* tunnel is destroyed
714  * @param handlers callbacks for messages we care about, NULL-terminated
715  *                 note that the mesh is allowed to drop notifications about
716  *                 inbound messages if the client does not process them fast
717  *                 enough (for this notification type, a bounded queue is used)
718  * @param stypes Application Types the client claims to offer
719  * @return handle to the mesh service
720  *         NULL on error (in this case, init is never called)
721  */
722 struct GNUNET_MESH_Handle *
723 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
724                      GNUNET_MESH_TunnelEndHandler cleaner,
725                      const struct GNUNET_MESH_MessageHandler *handlers,
726                      const GNUNET_MESH_ApplicationType *stypes)
727 {
728   struct GNUNET_MESH_Handle *h;
729   struct GNUNET_MESH_ClientConnect *msg;
730   GNUNET_MESH_ApplicationType *apps;
731   uint16_t napps;
732   uint16_t *types;
733   uint16_t ntypes;
734   size_t size;
735
736   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
737   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
738   h->max_queue_size = MESH_API_MAX_QUEUE; /* FIXME: add to arguments to 'GNUNET_MESH_connect' */
739   h->cleaner = cleaner;
740   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
741   if (h->client == NULL)
742   {
743     GNUNET_break (0);
744     GNUNET_free (h);
745     return NULL;
746   }
747
748   h->cls = cls;
749   h->message_handlers = handlers;
750   h->applications = stypes;
751   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;
752
753   /* count handlers and apps, calculate size */
754   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
755   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
756
757   size = sizeof (struct GNUNET_MESH_ClientConnect);
758   size += h->n_handlers * sizeof (uint16_t);
759   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
760
761   {
762     char buf[size];
763
764     /* build connection packet */
765     msg = (struct GNUNET_MESH_ClientConnect *) buf;
766     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
767     msg->header.size = htons (size);
768     types = (uint16_t *) & msg[1];
769     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
770       types[ntypes] = h->message_handlers[ntypes].type;      
771     apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
772     for (napps = 0; napps < h->n_applications; napps++)
773       apps[napps] = h->applications[napps];      
774     msg->applications = htons (napps);
775     msg->types = htons (ntypes);
776
777     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778                 "mesh: Sending %lu bytes long message %d types and %d apps\n",
779                 ntohs (msg->header.size), ntypes, napps);
780     
781     send_packet (h, &msg->header);
782   }
783
784   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
785
786   return h;
787 }
788
789
790 /**
791  * Disconnect from the mesh service.
792  *
793  * @param handle connection to mesh to disconnect
794  */
795 void
796 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
797 {
798   if (NULL != handle->th)
799   {
800     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
801   }
802   if (NULL != handle->client)
803   {
804     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
805   }
806   GNUNET_free (handle);
807 }
808
809
810 /**
811  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
812  * and to broadcast).
813  *
814  * @param h mesh handle
815  * @param connect_handler function to call when peers are actually connected
816  * @param disconnect_handler function to call when peers are disconnected
817  * @param handler_cls closure for connect/disconnect handlers
818  */
819 struct GNUNET_MESH_Tunnel *
820 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
821                            GNUNET_MESH_TunnelConnectHandler connect_handler,
822                            GNUNET_MESH_TunnelDisconnectHandler
823                            disconnect_handler, void *handler_cls)
824 {
825   struct GNUNET_MESH_Tunnel *t;
826   struct GNUNET_MESH_TunnelMessage msg;
827
828   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
829   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
830
831   t->connect_handler = connect_handler;
832   t->disconnect_handler = disconnect_handler;
833   t->cls = handler_cls;
834   t->mesh = h;
835   t->tid = h->next_tid++;
836   h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;      // keep in range
837
838   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
839   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
840   msg.tunnel_id = htonl (t->tid);
841   send_packet (h, &msg.header);
842   return t;
843 }
844
845
846 /**
847  * Destroy an existing tunnel.
848  *
849  * @param tun tunnel handle
850  */
851 void
852 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tun)
853 {
854   struct GNUNET_MESH_Handle *h;
855   struct GNUNET_MESH_TunnelMessage *msg;
856
857   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
858
859   h = tun->mesh;
860   msg = GNUNET_malloc (sizeof (struct GNUNET_MESH_TunnelMessage));
861   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
862   msg->header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
863   msg->tunnel_id = htonl (tun->tid);
864
865   GNUNET_free (tun);
866
867   send_packet (h, &msg->header);
868 }
869
870
871 /**
872  * Request that a peer should be added to the tunnel.  The existing
873  * connect handler will be called ONCE with either success or failure.
874  *
875  * @param tunnel handle to existing tunnel
876  * @param timeout how long to try to establish a connection
877  * @param peer peer to add
878  */
879 void
880 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
881                                       struct GNUNET_TIME_Relative timeout,
882                                       const struct GNUNET_PeerIdentity *peer)
883 {
884   struct GNUNET_MESH_PeerControl *msg;
885   GNUNET_PEER_Id peer_id;
886   unsigned int i;
887   
888   peer_id = GNUNET_PEER_intern (peer);
889   for (i = 0; i < tunnel->npeers; i++)
890   {
891     if (tunnel->peers[i] == peer_id)
892     {
893       GNUNET_PEER_change_rc (peer_id, -1);
894       return;
895     }
896   }
897   tunnel->npeers++;
898   tunnel->peers =
899       GNUNET_realloc (tunnel->peers, tunnel->npeers * sizeof (GNUNET_PEER_Id));
900   tunnel->peers[tunnel->npeers - 1] = peer_id;
901
902   msg = GNUNET_malloc (sizeof (struct GNUNET_MESH_PeerControl));
903   msg->header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
904   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD);
905   msg->tunnel_id = htonl (tunnel->tid);
906   msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (timeout));
907   memcpy (&msg->peer, peer, sizeof (struct GNUNET_PeerIdentity));
908
909   send_packet (tunnel->mesh, &msg->header);
910
911 //   tunnel->connect_handler (tunnel->cls, peer, NULL); FIXME call this later
912 //   TODO: remember timeout
913   return;
914 }
915
916
917 /**
918  * Request that a peer should be removed from the tunnel.  The existing
919  * disconnect handler will be called ONCE if we were connected.
920  *
921  * @param tunnel handle to existing tunnel
922  * @param peer peer to remove
923  */
924 void
925 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
926                                       const struct GNUNET_PeerIdentity *peer)
927 {
928   struct GNUNET_MESH_PeerControl msg;
929   GNUNET_PEER_Id peer_id;
930   unsigned int i;
931
932   peer_id = GNUNET_PEER_search (peer);
933   if (0 == peer_id)
934     {
935       GNUNET_break (0);
936       return;
937     }
938   for (i = 0; i < tunnel->npeers; i++)
939     if (tunnel->peers[i] == peer_id)
940       break;
941   if (i == tunnel->npeers)
942     {
943       GNUNET_break (0);
944       return;
945     }
946   GNUNET_PEER_change_rc (peer_id, -1);
947   tunnel->peers[i] = tunnel->peers[tunnel->npeers-1];
948   GNUNET_array_grow (tunnel->peers,
949                      tunnel->npeers,
950                      tunnel->npeers - 1);
951   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
952   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL);
953   msg.tunnel_id = htonl (tunnel->tid);
954   msg.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
955   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
956   send_packet (tunnel->mesh, &msg.header);
957 }
958
959
960 /**
961  * Request that the mesh should try to connect to a peer supporting the given
962  * message type.
963  *
964  * @param tunnel handle to existing tunnel
965  * @param timeout how long to try to establish a connection
966  * @param app_type application type that must be supported by the peer (MESH
967  *                 should discover peer in proximity handling this type)
968  */
969 void
970 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
971                                           struct GNUNET_TIME_Relative timeout,
972                                           GNUNET_MESH_ApplicationType app_type)
973 {
974   struct GNUNET_MESH_ConnectPeerByType msg;
975
976   /* FIXME: remember request connect by type for reconnect! */
977   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
978   msg.header.type =  htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE);
979   msg.tunnel_id = htonl (tunnel->tid);
980   msg.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (timeout));
981   msg.type = htonl (app_type);
982   send_packet (tunnel->mesh, &msg.header);
983 }
984
985
986 /**
987  * Ask the mesh to call "notify" once it is ready to transmit the
988  * given number of bytes to the specified "target".  If we are not yet
989  * connected to the specified peer, a call to this function will cause
990  * us to try to establish a connection.
991  *
992  * @param tunnel tunnel to use for transmission
993  * @param cork is corking allowed for this transmission?
994  * @param priority how important is the message?
995  * @param maxdelay how long can the message wait?
996  * @param target destination for the message,
997  *               NULL for multicast to all tunnel targets
998  * @param notify_size how many bytes of buffer space does notify want?
999  * @param notify function to call when buffer space is available;
1000  *        will be called with NULL on timeout or if the overall queue
1001  *        for this peer is larger than queue_size and this is currently
1002  *        the message with the lowest priority
1003  * @param notify_cls closure for notify
1004  * @return non-NULL if the notify callback was queued,
1005  *         NULL if we can not even queue the request (insufficient
1006  *         memory); if NULL is returned, "notify" will NOT be called.
1007  */
1008 struct GNUNET_MESH_TransmitHandle *
1009 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1010                                    uint32_t priority,
1011                                    struct GNUNET_TIME_Relative maxdelay,
1012                                    const struct GNUNET_PeerIdentity *target,
1013                                    size_t notify_size,
1014                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1015                                    void *notify_cls)
1016 {
1017   struct GNUNET_MESH_TransmitHandle *q;
1018   size_t overhead;
1019
1020   if (get_queue_length (tunnel->mesh) >= tunnel->mesh->max_queue_size)
1021     return NULL; /* queue full */
1022
1023   q = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1024   q->tunnel = tunnel;
1025   q->priority = priority;
1026   q->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1027   q->target = GNUNET_PEER_intern (target);
1028   overhead = (NULL == target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct GNUNET_MESH_Unicast);
1029   q->size = notify_size + overhead;
1030   q->notify = notify;
1031   q->notify_cls = notify_cls;
1032   queue_transmit_handle (tunnel->mesh, q);
1033   return q;
1034 }
1035
1036
1037 /**
1038  * Cancel the specified transmission-ready notification.
1039  *
1040  * @param th handle that was returned by "notify_transmit_ready".
1041  */
1042 void
1043 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1044 {
1045   struct GNUNET_MESH_Handle *mesh;
1046   
1047   mesh = th->tunnel->mesh;
1048   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1049     GNUNET_SCHEDULER_cancel (th->timeout_task);
1050   GNUNET_CONTAINER_DLL_remove (mesh->queue_head, 
1051                                mesh->queue_tail,
1052                                th);
1053   GNUNET_free (th);
1054   if ( (NULL == mesh->queue_head) &&
1055        (NULL != mesh->th) )
1056     {
1057       /* queue empty, no point in asking for transmission */
1058       GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1059       mesh->th = NULL;
1060     }    
1061 }
1062
1063
1064 #if 0                           /* keep Emacsens' auto-indent happy */
1065 {
1066 #endif
1067 #ifdef __cplusplus
1068 }
1069 #endif