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