oops, one more unix path removed
[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 and calling the tmt_rdy function
655  * 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   /* count handlers and apps, calculate size */
736   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
737   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
738   size = sizeof (struct GNUNET_MESH_ClientConnect);
739   size += h->n_handlers * sizeof (uint16_t);
740   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
741   {
742     char buf[size];
743
744     /* build connection packet */
745     msg = (struct GNUNET_MESH_ClientConnect *) buf;
746     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
747     msg->header.size = htons (size);
748     types = (uint16_t *) & msg[1];
749     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
750       types[ntypes] = h->message_handlers[ntypes].type;
751     apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
752     for (napps = 0; napps < h->n_applications; napps++)
753       apps[napps] = h->applications[napps];
754     msg->applications = htons (napps);
755     msg->types = htons (ntypes);
756     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757                 "mesh: Sending %lu bytes long message %d types and %d apps\n",
758                 ntohs (msg->header.size), ntypes, napps);
759     send_packet (h, &msg->header);
760   }
761   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
762   return h;
763 }
764
765
766 /**
767  * Disconnect from the mesh service.
768  *
769  * @param handle connection to mesh to disconnect
770  */
771 void
772 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
773 {
774   if (NULL != handle->th)
775   {
776     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
777   }
778   if (NULL != handle->client)
779   {
780     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
781   }
782   GNUNET_free (handle);
783 }
784
785
786 /**
787  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
788  * and to broadcast).
789  *
790  * @param h mesh handle
791  * @param connect_handler function to call when peers are actually connected
792  * @param disconnect_handler function to call when peers are disconnected
793  * @param handler_cls closure for connect/disconnect handlers
794  */
795 struct GNUNET_MESH_Tunnel *
796 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
797                            GNUNET_MESH_TunnelConnectHandler connect_handler,
798                            GNUNET_MESH_TunnelDisconnectHandler
799                            disconnect_handler, void *handler_cls)
800 {
801   struct GNUNET_MESH_Tunnel *t;
802   struct GNUNET_MESH_TunnelMessage msg;
803
804   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
805   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
806   t->connect_handler = connect_handler;
807   t->disconnect_handler = disconnect_handler;
808   t->cls = handler_cls;
809   t->mesh = h;
810   t->tid = h->next_tid++;
811   h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;      // keep in range
812   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
813   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
814   msg.tunnel_id = htonl (t->tid);
815   send_packet (h, &msg.header);
816   return t;
817 }
818
819
820 /**
821  * Destroy an existing tunnel.
822  *
823  * @param tun tunnel handle
824  */
825 void
826 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tun)
827 {
828   struct GNUNET_MESH_Handle *h;
829   struct GNUNET_MESH_TunnelMessage *msg;
830
831   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
832   h = tun->mesh;
833   msg = GNUNET_malloc (sizeof (struct GNUNET_MESH_TunnelMessage));
834   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
835   msg->header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
836   msg->tunnel_id = htonl (tun->tid);
837   GNUNET_free (tun);
838   send_packet (h, &msg->header);
839 }
840
841
842 /**
843  * Request that a peer should be added to the tunnel.  The existing
844  * connect handler will be called ONCE with either success or failure.
845  *
846  * @param tunnel handle to existing tunnel
847  * @param timeout how long to try to establish a connection
848  * @param peer peer to add
849  */
850 void
851 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
852                                       struct GNUNET_TIME_Relative timeout,
853                                       const struct GNUNET_PeerIdentity *peer)
854 {
855   struct GNUNET_MESH_PeerControl *msg;
856   GNUNET_PEER_Id peer_id;
857   unsigned int i;
858
859   peer_id = GNUNET_PEER_intern (peer);
860   for (i = 0; i < tunnel->npeers; i++)
861   {
862     if (tunnel->peers[i] == peer_id)
863     {
864       GNUNET_PEER_change_rc (peer_id, -1);
865       /* FIXME: peer was already in the tunnel */
866       return;
867     }
868   }
869   tunnel->npeers++;
870   tunnel->peers =
871       GNUNET_realloc (tunnel->peers, tunnel->npeers * sizeof (GNUNET_PEER_Id));
872   tunnel->peers[tunnel->npeers - 1] = peer_id;
873   msg = GNUNET_malloc (sizeof (struct GNUNET_MESH_PeerControl));
874   msg->header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
875   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD);
876   msg->tunnel_id = htonl (tunnel->tid);
877   msg->timeout =
878       GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (timeout));
879   memcpy (&msg->peer, peer, sizeof (struct GNUNET_PeerIdentity));
880   send_packet (tunnel->mesh, &msg->header);
881 //   tunnel->connect_handler (tunnel->cls, peer, NULL); FIXME call this later
882 //   TODO: remember timeout
883   return;
884 }
885
886
887 /**
888  * Request that a peer should be removed from the tunnel.  The existing
889  * disconnect handler will be called ONCE if we were connected.
890  *
891  * @param tunnel handle to existing tunnel
892  * @param peer peer to remove
893  */
894 void
895 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
896                                       const struct GNUNET_PeerIdentity *peer)
897 {
898   struct GNUNET_MESH_PeerControl msg;
899   GNUNET_PEER_Id peer_id;
900   unsigned int i;
901
902   peer_id = GNUNET_PEER_search (peer);
903   if (0 == peer_id)
904   {
905     GNUNET_break (0);
906     return;
907   }
908   for (i = 0; i < tunnel->npeers; i++)
909     if (tunnel->peers[i] == peer_id)
910       break;
911   if (i == tunnel->npeers)
912   {
913     GNUNET_break (0);
914     return;
915   }
916   GNUNET_PEER_change_rc (peer_id, -1);
917   tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
918   GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
919   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
920   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL);
921   msg.tunnel_id = htonl (tunnel->tid);
922   msg.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
923   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
924   send_packet (tunnel->mesh, &msg.header);
925 }
926
927
928 /**
929  * Request that the mesh should try to connect to a peer supporting the given
930  * message type.
931  *
932  * @param tunnel handle to existing tunnel
933  * @param timeout how long to try to establish a connection
934  * @param app_type application type that must be supported by the peer (MESH
935  *                 should discover peer in proximity handling this type)
936  */
937 void
938 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
939                                           struct GNUNET_TIME_Relative timeout,
940                                           GNUNET_MESH_ApplicationType app_type)
941 {
942   struct GNUNET_MESH_ConnectPeerByType msg;
943
944   /* FIXME: remember request connect by type for reconnect! */
945   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
946   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE);
947   msg.tunnel_id = htonl (tunnel->tid);
948   msg.timeout =
949       GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (timeout));
950   msg.type = htonl (app_type);
951   send_packet (tunnel->mesh, &msg.header);
952 }
953
954
955 /**
956  * Ask the mesh to call "notify" once it is ready to transmit the
957  * given number of bytes to the specified "target".  If we are not yet
958  * connected to the specified peer, a call to this function will cause
959  * us to try to establish a connection.
960  *
961  * @param tunnel tunnel to use for transmission
962  * @param cork is corking allowed for this transmission?
963  * @param priority how important is the message?
964  * @param maxdelay how long can the message wait?
965  * @param target destination for the message,
966  *               NULL for multicast to all tunnel targets
967  * @param notify_size how many bytes of buffer space does notify want?
968  * @param notify function to call when buffer space is available;
969  *        will be called with NULL on timeout or if the overall queue
970  *        for this peer is larger than queue_size and this is currently
971  *        the message with the lowest priority
972  * @param notify_cls closure for notify
973  * @return non-NULL if the notify callback was queued,
974  *         NULL if we can not even queue the request (insufficient
975  *         memory); if NULL is returned, "notify" will NOT be called.
976  */
977 struct GNUNET_MESH_TransmitHandle *
978 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
979                                    uint32_t priority,
980                                    struct GNUNET_TIME_Relative maxdelay,
981                                    const struct GNUNET_PeerIdentity *target,
982                                    size_t notify_size,
983                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
984                                    void *notify_cls)
985 {
986   struct GNUNET_MESH_TransmitHandle *th;
987   size_t overhead;
988
989   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
990       tunnel->npackets > 0)
991     return NULL;                /* queue full */
992   tunnel->npackets++;
993   tunnel->mesh->npackets++;
994   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
995   th->tunnel = tunnel;
996   th->priority = priority;
997   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
998   th->target = GNUNET_PEER_intern (target);
999   overhead =
1000       (NULL ==
1001        target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct
1002                                                                  GNUNET_MESH_Unicast);
1003   th->size = notify_size + overhead;
1004   th->notify = notify;
1005   th->notify_cls = notify_cls;
1006   add_to_queue (tunnel->mesh, th);
1007   return th;
1008 }
1009
1010
1011 /**
1012  * Cancel the specified transmission-ready notification.
1013  *
1014  * @param th handle that was returned by "notify_transmit_ready".
1015  */
1016 void
1017 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1018 {
1019   struct GNUNET_MESH_Handle *mesh;
1020
1021   mesh = th->tunnel->mesh;
1022   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1023     GNUNET_SCHEDULER_cancel (th->timeout_task);
1024   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1025   GNUNET_free (th);
1026   if ((NULL == mesh->th_head) && (NULL != mesh->th))
1027   {
1028     /* queue empty, no point in asking for transmission */
1029     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1030     mesh->th = NULL;
1031   }
1032 }
1033
1034
1035 #if 0                           /* keep Emacsens' auto-indent happy */
1036 {
1037 #endif
1038 #ifdef __cplusplus
1039 }
1040 #endif