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