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