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