doxygen
[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  * - callbacks to client missing on certain events
26  * - processing messages from service is incomplete
27  *
28  * STRUCTURE:
29  * - CONSTANTS
30  * - DATA STRUCTURES
31  * - AUXILIARY FUNCTIONS
32  * - RECEIVE HANDLERS
33  * - SEND FUNCTIONS
34  * - API CALL DEFINITIONS
35  */
36 #ifdef __cplusplus
37 extern "C"
38 {
39 #if 0                           /* keep Emacsens' auto-indent happy */
40 }
41 #endif
42 #endif
43
44 #include "platform.h"
45 #include "gnunet_common.h"
46 #include "gnunet_client_lib.h"
47 #include "gnunet_util_lib.h"
48 #include "gnunet_peer_lib.h"
49 #include "gnunet_mesh_service_new.h"
50 #include "mesh.h"
51 #include "mesh_protocol.h"
52
53
54 /******************************************************************************/
55 /************************      DATA STRUCTURES     ****************************/
56 /******************************************************************************/
57
58 /**
59  * Transmission queue to the service
60  */
61 struct GNUNET_MESH_TransmitHandle
62 {
63
64     /**
65      * Double Linked list
66      */
67   struct GNUNET_MESH_TransmitHandle *next;
68
69     /**
70      * Double Linked list
71      */
72   struct GNUNET_MESH_TransmitHandle *prev;
73
74     /**
75      * Tunnel this message is sent over (may be NULL for control messages).
76      */
77   struct GNUNET_MESH_Tunnel *tunnel;
78
79     /**
80      * Data itself, currently points to the end of this struct if
81      * we have a message already, NULL if the message is to be
82      * obtained from the callback.
83      */
84   const struct GNUNET_MessageHeader *data;
85
86     /**
87      * Callback to obtain the message to transmit, or NULL if we
88      * got the message in 'data'.  Notice that messages built
89      * by 'notify' need to be encapsulated with information about
90      * the 'target'.
91      */
92   GNUNET_CONNECTION_TransmitReadyNotify notify;
93
94     /**
95      * Closure for 'notify'
96      */
97   void *notify_cls;
98
99     /**
100      * How long is this message valid.  Once the timeout has been
101      * reached, the message must no longer be sent.  If this
102      * is a message with a 'notify' callback set, the 'notify'
103      * function should be called with 'buf' NULL and size 0.
104      */
105   struct GNUNET_TIME_Absolute timeout;
106
107     /**
108      * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
109      */
110   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
111
112     /**
113      * Priority of the message.  The queue is sorted by priority,
114      * control messages have the maximum priority (UINT32_MAX).
115      */
116   uint32_t priority;
117
118     /**
119      * Target of the message, 0 for broadcast.  This field
120      * is only valid if 'notify' is non-NULL.
121      */
122   GNUNET_PEER_Id target;
123
124     /**
125      * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
126      */
127   size_t size;
128 };
129
130
131 /**
132  * Opaque handle to the service.
133  */
134 struct GNUNET_MESH_Handle
135 {
136
137     /**
138      * Handle to the server connection, to send messages later
139      */
140   struct GNUNET_CLIENT_Connection *client;
141
142     /**
143      * Set of handlers used for processing incoming messages in the tunnels
144      */
145   const struct GNUNET_MESH_MessageHandler *message_handlers;
146
147     /**
148      * Set of applications that should be claimed to be offered at this node.
149      * Note that this is just informative, the appropiate handlers must be
150      * registered independently and the mapping is up to the developer of the
151      * client application.
152      */
153   const GNUNET_MESH_ApplicationType *applications;
154
155     /**
156      * Double linked list of the tunnels this client is connected to.
157      */
158   struct GNUNET_MESH_Tunnel *tunnels_head;
159   struct GNUNET_MESH_Tunnel *tunnels_tail;
160
161     /**
162      * Callback for tunnel disconnection
163      */
164   GNUNET_MESH_TunnelEndHandler *cleaner;
165
166     /**
167      * Handle to cancel pending transmissions in case of disconnection
168      */
169   struct GNUNET_CLIENT_TransmitHandle *th;
170
171     /**
172      * Closure for all the handlers given by the client
173      */
174   void *cls;
175
176     /**
177      * Messages to send to the service
178      */
179   struct GNUNET_MESH_TransmitHandle *th_head;
180   struct GNUNET_MESH_TransmitHandle *th_tail;
181
182     /**
183      * tid of the next tunnel to create (to avoid reusing IDs often)
184      */
185   MESH_TunnelNumber next_tid;
186   unsigned int n_handlers;
187   unsigned int n_applications;
188   unsigned int max_queue_size;
189
190     /**
191      * Have we started the task to receive messages from the service
192      * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
193      */
194   int in_receive;
195
196     /**
197      * Number of packets queued
198      */
199   unsigned int npackets;
200
201   /**
202    * Configuration given by the client, in case of reconnection
203    */
204   const struct GNUNET_CONFIGURATION_Handle *cfg;
205 };
206
207
208 /**
209  * Description of a peer
210  */
211 struct GNUNET_MESH_Peer
212 {
213     /**
214      * ID of the peer in short form
215      */
216   GNUNET_PEER_Id id;
217
218   /**
219    * Tunnel this peer belongs to
220    */
221   struct GNUNET_MESH_Tunnel *t;
222
223   /**
224    * Flag indicating whether service has informed about its connection
225    */
226   int connected;
227
228 };
229
230
231 /**
232  * Opaque handle to a tunnel.
233  */
234 struct GNUNET_MESH_Tunnel
235 {
236
237     /**
238      * DLL
239      */
240   struct GNUNET_MESH_Tunnel *next;
241   struct GNUNET_MESH_Tunnel *prev;
242
243     /**
244      * Callback to execute when peers connect to the tunnel
245      */
246   GNUNET_MESH_TunnelConnectHandler connect_handler;
247
248     /**
249      * Callback to execute when peers disconnect to the tunnel
250      */
251   GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
252
253     /**
254      * All peers added to the tunnel
255      */
256   struct GNUNET_MESH_Peer **peers;
257
258     /**
259      * Closure for the connect/disconnect handlers
260      */
261   void *cls;
262
263     /**
264      * Handle to the mesh this tunnel belongs to
265      */
266   struct GNUNET_MESH_Handle *mesh;
267
268     /**
269      * Local ID of the tunnel
270      */
271   MESH_TunnelNumber tid;
272
273     /**
274      * Owner of the tunnel
275      */
276   GNUNET_PEER_Id owner;
277
278   /**
279    * List of application types that have been requested for this tunnel
280    */
281   GNUNET_MESH_ApplicationType *apps;
282
283   /**
284      * Number of peers added to the tunnel
285      */
286   unsigned int npeers;
287
288     /**
289      * Number of packets queued in this tunnel
290      */
291   unsigned int npackets;
292
293     /**
294      * Number of applications requested this tunnel
295      */
296   unsigned int napps;
297
298 };
299
300
301 /******************************************************************************/
302 /***********************     AUXILIARY FUNCTIONS      *************************/
303 /******************************************************************************/
304
305 /**
306  * Get the tunnel handler for the tunnel specified by id from the given handle
307  * @param h Mesh handle
308  * @param tid ID of the wanted tunnel
309  * @return handle to the required tunnel or NULL if not found
310  */
311 static struct GNUNET_MESH_Tunnel *
312 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
313 {
314   struct GNUNET_MESH_Tunnel *t;
315
316   t = h->tunnels_head;
317   while (t != NULL)
318   {
319     if (t->tid == tid)
320       return t;
321     t = t->next;
322   }
323   return NULL;
324 }
325
326
327 /**
328  * Create a new tunnel and insert it in the tunnel list of the mesh handle
329  * @param h Mesh handle
330  * @param tid desired tid of the tunnel, 0 to assign one automatically
331  * @return handle to the created tunnel
332  */
333 static struct GNUNET_MESH_Tunnel *
334 create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
335 {
336   struct GNUNET_MESH_Tunnel *t;
337
338   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
339   t->mesh = h;
340   if (0 == tid)
341   {
342     t->tid = h->next_tid++;
343   }
344   else
345   {
346     /* FIXME keep double numbering?
347      * client numbers from 0x8... anx service from 0xB... ? */
348     t->tid = tid;
349     h->next_tid = tid + 1;
350   }
351   h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;      // keep in range
352   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
353   return t;
354 }
355
356
357 /**
358  * Get the tunnel handler for the tunnel specified by id from the given handle
359  * @param h Mesh handle
360  * @param tid ID of the wanted tunnel
361  * @return handle to the required tunnel or NULL if not found
362  */
363 static void
364 destroy_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
365 {
366   struct GNUNET_MESH_Tunnel *t;
367   struct GNUNET_PeerIdentity pi;
368   unsigned int i;
369
370   t = retrieve_tunnel (h, tid);
371   if (NULL == t)
372   {
373     GNUNET_break (0);
374     return;
375   }
376   GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t);
377   for (i = 0; i < t->npeers; i++)
378   {
379     GNUNET_PEER_resolve (t->peers[i]->id, &pi);
380     t->disconnect_handler (t->cls, &pi);
381     GNUNET_PEER_change_rc (t->peers[i]->id, -1);
382     GNUNET_free (t->peers[i]);
383   }
384   h->cleaner (h->cls, t, NULL); /* FIXME ctx? */
385   if (0 != t->owner)
386     GNUNET_PEER_change_rc (t->owner, -1);
387   GNUNET_free (t->peers);
388   GNUNET_free (t);
389   return;
390 }
391
392
393 /**
394  * Get the peer descriptor for the peer with id from the given tunnel
395  * @param t Tunnel handle
396  * @param id Short form ID of the wanted peer
397  * @return handle to the requested peer or NULL if not found
398  */
399 static struct GNUNET_MESH_Peer *
400 retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id)
401 {
402   unsigned int i;
403
404   for (i = 0; i < t->npeers; i++)
405     if (t->peers[i]->id == id)
406       return t->peers[i];
407   return NULL;
408 }
409
410
411 /**
412  * Add a peer into a tunnel
413  * @param t Tunnel handle
414  * @param pi Full ID of the new peer
415  * @return handle to the newly created peer
416  */
417 static struct GNUNET_MESH_Peer *
418 add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
419                     const struct GNUNET_PeerIdentity *pi)
420 {
421   struct GNUNET_MESH_Peer *p;
422   GNUNET_PEER_Id id;
423
424   id = GNUNET_PEER_intern (pi);
425
426   p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
427   p->id = id;
428   p->t = t;
429   GNUNET_array_append (t->peers, t->npeers, p);
430   return p;
431 }
432
433
434 /**
435  * Remove a peer from a tunnel
436  * @param t Tunnel handle
437  * @param p Peer handle
438  */
439 static void
440 remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p)
441 {
442   unsigned int i;
443
444   for (i = 0; i < p->t->npeers; i++)
445   {
446     if (p->t->peers[i] == p)
447       break;
448   }
449   if (i == p->t->npeers)
450   {
451     GNUNET_break (0);
452     return;
453   }
454   p->t->peers[i] = p->t->peers[p->t->npeers - 1];
455   GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1);
456 }
457
458
459 /**
460  * Notify client that the transmission has timed out
461  * @param cls closure
462  * @param tc task context
463  */
464 static void
465 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
466 {
467   struct GNUNET_MESH_TransmitHandle *th = cls;
468   struct GNUNET_MESH_Handle *mesh;
469
470   mesh = th->tunnel->mesh;
471   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
472   if (th->notify != NULL)
473     th->notify (th->notify_cls, 0, NULL);
474   GNUNET_free (th);
475   if ((NULL == mesh->th_head) && (NULL != mesh->th))
476   {
477     /* queue empty, no point in asking for transmission */
478     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
479     mesh->th = NULL;
480   }
481 }
482
483
484 /**
485  * Add a transmit handle to the transmission queue by priority and set the
486  * timeout if needed.
487  *
488  * @param h mesh handle with the queue head and tail
489  * @param q handle to the packet to be transmitted
490  */
491 static void
492 add_to_queue (struct GNUNET_MESH_Handle *h,
493               struct GNUNET_MESH_TransmitHandle *th)
494 {
495   struct GNUNET_MESH_TransmitHandle *p;
496
497   p = h->th_head;
498   while ((NULL != p) && (th->priority <= p->priority))
499     p = p->next;
500   if (NULL == p)
501     p = h->th_tail;
502   else
503     p = p->prev;
504   GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
505   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
506     return;
507   th->timeout_task =
508       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
509                                     (th->timeout), &timeout_transmission, th);
510 }
511
512
513 static void
514 send_packet (struct GNUNET_MESH_Handle *h,
515              const struct GNUNET_MessageHeader *msg);
516
517
518 /**
519  * Reconnect to the service, retransmit all infomation to try to restore the
520  * original state.
521  * FIXME: notify user about it? (call all disconnect callbacks?)
522  *
523  * @param h handle to the mesh
524  *
525  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
526  */
527 static int
528 reconnect (struct GNUNET_MESH_Handle *h)
529 {
530   struct GNUNET_MESH_Tunnel *t;
531   unsigned int i;
532
533   h->in_receive = GNUNET_NO;
534   /* disconnect */
535   if (NULL != h->th)
536   {
537     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
538   }
539   if (NULL != h->client)
540   {
541     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
542   }
543
544   /* connect again */
545   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
546   if (h->client == NULL)
547   {
548     /* FIXME: panic? exponential backoff retry? */
549     GNUNET_break (0);
550     return GNUNET_NO;
551   }
552   for (t = h->tunnels_head; NULL != t; t = t->next)
553   {
554     struct GNUNET_MESH_TunnelMessage msg;
555
556     msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
557     msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
558     msg.tunnel_id = htonl (t->tid);
559     send_packet (h, &msg.header);
560     for (i = 0; i < t->npeers; i++)
561     {
562       struct GNUNET_MESH_PeerControl msg;
563
564       msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
565       msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
566       msg.tunnel_id = htonl (t->tid);
567       GNUNET_PEER_resolve (t->peers[i]->id, &msg.peer);
568       send_packet (t->mesh, &msg.header);
569     }
570     /* FIXME what about connects by type? */
571   }
572   return GNUNET_YES;
573 }
574
575
576 /******************************************************************************/
577 /***********************      RECEIVE HANDLERS     ****************************/
578 /******************************************************************************/
579
580 /**
581  * Process the new tunnel notification and add it to the tunnels in the handle
582  *
583  * @param h     The mesh handle
584  * @param msg   A message with the details of the new incoming tunnel
585  */
586 static void
587 process_tunnel_create (struct GNUNET_MESH_Handle *h,
588                        const struct GNUNET_MESH_TunnelMessage *msg)
589 {
590   struct GNUNET_MESH_Tunnel *t;
591   MESH_TunnelNumber tid;
592
593   tid = ntohl (msg->tunnel_id);
594   if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK)
595   {
596     GNUNET_break (0);
597     return;
598   }
599   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
600   t->cls = h->cls;
601   t->mesh = h;
602   t->tid = tid;
603   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
604   return;
605 }
606
607
608 /**
609  * Process the tunnel destroy notification and free associated resources
610  *
611  * @param h     The mesh handle
612  * @param msg   A message with the details of the tunnel being destroyed
613  */
614 static void
615 process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
616                         const struct GNUNET_MESH_TunnelMessage *msg)
617 {
618   struct GNUNET_MESH_Tunnel *t;
619   MESH_TunnelNumber tid;
620
621   tid = ntohl (msg->tunnel_id);
622   t = retrieve_tunnel (h, tid);
623
624   t->cls = h->cls;
625   t->mesh = h;
626   t->tid = tid;
627   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
628   return;
629 }
630
631
632 /**
633  * Process the new peer event and notify the upper level of it
634  *
635  * @param h     The mesh handle
636  * @param msg   A message with the details of the peer event
637  */
638 static void
639 process_peer_event (struct GNUNET_MESH_Handle *h,
640                     const struct GNUNET_MESH_PeerControl *msg)
641 {
642   struct GNUNET_MESH_Tunnel *t;
643   struct GNUNET_MESH_Peer *p;
644   struct GNUNET_TRANSPORT_ATS_Information atsi;
645   GNUNET_PEER_Id id;
646   uint16_t size;
647
648   size = ntohs (msg->header.size);
649   if (size != sizeof (struct GNUNET_MESH_PeerControl))
650   {
651     GNUNET_break (0);
652     return;
653   }
654   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
655   if (NULL == t)
656   {
657     t = create_tunnel (h, msg->tunnel_id);
658     t->owner = GNUNET_PEER_intern (&msg->peer);
659     t->npeers = 1;
660     t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *));
661     t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
662     t->peers[0]->t = t;
663     t->peers[0]->connected = 1;
664     t->peers[0]->id = t->owner;
665     return;
666   }
667   id = GNUNET_PEER_search (&msg->peer);
668   if ((p = retrieve_peer (t, id)) == NULL)
669     p = add_peer_to_tunnel (t, &msg->peer);
670   atsi.type = 0;
671   atsi.value = 0;
672   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == msg->header.type)
673   {
674     if (NULL != t->connect_handler)
675     {
676       t->connect_handler (t->cls, &msg->peer, &atsi);
677     }
678     p->connected = 1;
679   }
680   else
681   {
682     if (NULL != t->disconnect_handler && p->connected)
683     {
684       t->disconnect_handler (t->cls, &msg->peer);
685     }
686     remove_peer_from_tunnel (p);
687     GNUNET_free (p);
688   }
689 }
690
691
692 /**
693  * Process the incoming data packets
694  *
695  * @param h     The mesh handle
696  * @param msh   A message encapsulating the data
697  */
698 static void
699 process_incoming_data (struct GNUNET_MESH_Handle *h,
700                        const struct GNUNET_MessageHeader *message)
701 {
702   const struct GNUNET_MessageHeader *payload;
703   const struct GNUNET_MESH_MessageHandler *handler;
704   const struct GNUNET_PeerIdentity *peer;
705   struct GNUNET_MESH_Unicast *ucast;
706   struct GNUNET_MESH_Multicast *mcast;
707   struct GNUNET_MESH_ToOrigin *to_orig;
708   struct GNUNET_MESH_Tunnel *t;
709   uint16_t type;
710   int i;
711
712   type = ntohs (message->type);
713   switch (type)
714   {
715   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
716     ucast = (struct GNUNET_MESH_Unicast *) message;
717     t = retrieve_tunnel (h, ntohl (ucast->tid));
718     payload = (struct GNUNET_MessageHeader *) &ucast[1];
719     peer = &ucast->oid;
720     break;
721   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
722     mcast = (struct GNUNET_MESH_Multicast *) message;
723     t = retrieve_tunnel (h, ntohl (mcast->tid));
724     payload = (struct GNUNET_MessageHeader *) &mcast[1];
725     peer = &mcast->oid;
726     break;
727   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
728     to_orig = (struct GNUNET_MESH_ToOrigin *) message;
729     t = retrieve_tunnel (h, ntohl (to_orig->tid));
730     payload = (struct GNUNET_MessageHeader *) &to_orig[1];
731     peer = &to_orig->sender;
732     break;
733   default:
734     GNUNET_break (0);
735     return;
736   }
737   if (NULL == t)
738   {
739     GNUNET_break (0);
740     return;
741   }
742   for (i = 0; i < h->n_handlers; i++)
743   {
744     handler = &h->message_handlers[i];
745     if (handler->type == type)
746     {
747       struct GNUNET_TRANSPORT_ATS_Information atsi;
748
749       atsi.type = 0;
750       atsi.value = 0;
751       /* FIXME ctx */
752       if (GNUNET_OK ==
753           handler->callback (h->cls, t, NULL, peer, payload, &atsi))
754       {
755         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756                     "MESH: callback completed successfully\n");
757       }
758       else
759       {
760         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761                     "MESH: callback caused disconnection\n");
762         GNUNET_MESH_disconnect (h);
763       }
764     }
765   }
766 }
767
768
769 /**
770  * Function to process all messages received from the service
771  *
772  * @param cls closure
773  * @param msg message received, NULL on timeout or fatal error
774  */
775 static void
776 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
777 {
778   struct GNUNET_MESH_Handle *h = cls;
779
780   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message from MESH\n");
781   if (msg == NULL)
782   {
783     reconnect (h);
784     return;
785   }
786   switch (ntohs (msg->type))
787   {
788     /* Notify of a new incoming tunnel */
789   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
790     process_tunnel_create (h, (struct GNUNET_MESH_TunnelMessage *) msg);
791     break;
792     /* Notify of a tunnel disconnection */
793   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
794     process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg);
795     break;
796     /* Notify of a new peer or a peer disconnect in the tunnel */
797   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD:
798   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL:
799     process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
800     break;
801     /* Notify of a new data packet in the tunnel */
802   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
803   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
804   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
805     process_incoming_data (h, msg);
806     break;
807     /* We shouldn't get any other packages, log and ignore */
808   default:
809     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
810                 "MESH: unsolicited message form service (type %d)\n",
811                 ntohs (msg->type));
812   }
813   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
814   GNUNET_CLIENT_receive (h->client, &msg_received, h,
815                          GNUNET_TIME_UNIT_FOREVER_REL);
816 }
817
818
819 /******************************************************************************/
820 /************************       SEND FUNCTIONS     ****************************/
821 /******************************************************************************/
822
823 /**
824  * Function called to send a message to the service.
825  * "buf" will be NULL and "size" zero if the socket was closed for writing in
826  * the meantime.
827  *
828  * @param cls closure, the mesh handle
829  * @param size number of bytes available in buf
830  * @param buf where the callee should write the connect message
831  * @return number of bytes written to buf
832  */
833 static size_t
834 send_callback (void *cls, size_t size, void *buf)
835 {
836   struct GNUNET_MESH_Handle *h = cls;
837   struct GNUNET_MESH_TransmitHandle *th;
838   char *cbuf = buf;
839   size_t tsize;
840   size_t psize;
841
842   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
843   h->th = NULL;
844   if ((0 == size) || (NULL == buf))
845   {
846     reconnect (h);
847     return 0;
848   }
849   tsize = 0;
850   while ((NULL != (th = h->th_head)) && (size >= th->size))
851   {
852     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     type: %u\n",
853                 ntohs (th->data->type));
854     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     size: %u\n",
855                 ntohs (th->data->size));
856     if (NULL == th->data)
857     {
858       GNUNET_assert (NULL != th->notify);
859       if (th->target == 0)
860       {
861         /* multicast */
862         struct GNUNET_MESH_Multicast mc;
863
864         GNUNET_assert (size >= sizeof (mc) + th->size);
865         psize =
866             th->notify (th->notify_cls, size - sizeof (mc), &cbuf[sizeof (mc)]);
867         if (psize > 0)
868         {
869           mc.header.size = htons (sizeof (mc) + th->size);
870           mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
871           mc.tid = htonl (th->tunnel->tid);
872           memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));     /* myself */
873           memcpy (cbuf, &mc, sizeof (mc));
874           psize = th->size + sizeof (mc);
875         }
876       }
877       else
878       {
879         /* unicast */
880         struct GNUNET_MESH_Unicast uc;
881
882         GNUNET_assert (size >= sizeof (uc) + th->size);
883         psize =
884             th->notify (th->notify_cls, size - sizeof (uc), &cbuf[sizeof (uc)]);
885         if (psize > 0)
886         {
887           uc.header.size = htons (sizeof (uc) + th->size);
888           uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
889           uc.tid = htonl (th->tunnel->tid);
890           memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));     /* myself */
891           GNUNET_PEER_resolve (th->target, &uc.destination);
892           memcpy (cbuf, &uc, sizeof (uc));
893           psize = th->size + sizeof (uc);
894         }
895       }
896     }
897     else
898     {
899       memcpy (cbuf, th->data, th->size);
900       psize = th->size;
901     }
902     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
903       GNUNET_SCHEDULER_cancel (th->timeout_task);
904     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
905     GNUNET_free (th);
906     cbuf += psize;
907     size -= psize;
908     tsize += psize;
909   }
910   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   total size: %u\n", tsize);
911   if (NULL != (th = h->th_head))
912   {
913     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   next size: %u\n", th->size);
914     h->th =
915         GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
916                                              GNUNET_TIME_UNIT_FOREVER_REL,
917                                              GNUNET_YES, &send_callback, h);
918   }
919   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
920   if (GNUNET_NO == h->in_receive)
921   {
922     h->in_receive = GNUNET_YES;
923     GNUNET_CLIENT_receive (h->client, &msg_received, h,
924                            GNUNET_TIME_UNIT_FOREVER_REL);
925   }
926   return tsize;
927 }
928
929
930 /**
931  * Auxiliary function to send an already constructed packet to the service.
932  * Takes care of creating a new queue element, copying the message and
933  * calling the tmt_rdy function if necessary.
934  * @param h mesh handle
935  * @param msg message to transmit
936  */
937 static void
938 send_packet (struct GNUNET_MESH_Handle *h,
939              const struct GNUNET_MessageHeader *msg)
940 {
941   struct GNUNET_MESH_TransmitHandle *th;
942   size_t msize;
943
944   msize = ntohs (msg->size);
945   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
946   th->priority = UINT32_MAX;
947   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
948   th->size = msize;
949   th->data = (void *) &th[1];
950   memcpy (&th[1], msg, msize);
951   add_to_queue (h, th);
952   if (NULL != h->th)
953     return;
954   h->th =
955       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
956                                            GNUNET_TIME_UNIT_FOREVER_REL,
957                                            GNUNET_YES, &send_callback, h);
958 }
959
960
961 /******************************************************************************/
962 /**********************      API CALL DEFINITIONS     *************************/
963 /******************************************************************************/
964
965 /**
966  * Connect to the mesh service.
967  *
968  * @param cfg configuration to use
969  * @param cls closure for the various callbacks that follow
970  *            (including handlers in the handlers array)
971  * @param queue_size size of the data message queue, shared among all tunnels
972  *                   (each tunnel is guaranteed to accept at least one message,
973  *                    no matter what is the status of other tunnels)
974  * @param cleaner function called when an *inbound* tunnel is destroyed
975  * @param handlers callbacks for messages we care about, NULL-terminated
976  *                 note that the mesh is allowed to drop notifications about
977  *                 inbound messages if the client does not process them fast
978  *                 enough (for this notification type, a bounded queue is used)
979  * @param stypes Application Types the client claims to offer
980  * @return handle to the mesh service
981  *         NULL on error (in this case, init is never called)
982  */
983 struct GNUNET_MESH_Handle *
984 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
985                      unsigned int queue_size, void *cls,
986                      GNUNET_MESH_TunnelEndHandler cleaner,
987                      const struct GNUNET_MESH_MessageHandler *handlers,
988                      const GNUNET_MESH_ApplicationType *stypes)
989 {
990   struct GNUNET_MESH_Handle *h;
991   struct GNUNET_MESH_ClientConnect *msg;
992   GNUNET_MESH_ApplicationType *apps;
993   uint16_t napps;
994   uint16_t *types;
995   uint16_t ntypes;
996   size_t size;
997
998   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
999   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
1000   h->cfg = cfg;
1001   h->max_queue_size = queue_size;
1002   h->cleaner = cleaner;
1003   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1004   if (h->client == NULL)
1005   {
1006     GNUNET_break (0);
1007     GNUNET_free (h);
1008     return NULL;
1009   }
1010   h->cls = cls;
1011   h->message_handlers = handlers;
1012   h->applications = stypes;
1013   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;
1014
1015   /* count handlers and apps, calculate size */
1016   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
1017   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
1018   size = sizeof (struct GNUNET_MESH_ClientConnect);
1019   size += h->n_handlers * sizeof (uint16_t);
1020   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
1021
1022   {
1023     char buf[size];
1024
1025     /* build connection packet */
1026     msg = (struct GNUNET_MESH_ClientConnect *) buf;
1027     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
1028     msg->header.size = htons (size);
1029     types = (uint16_t *) & msg[1];
1030     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
1031       types[ntypes] = h->message_handlers[ntypes].type;
1032     apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
1033     for (napps = 0; napps < h->n_applications; napps++)
1034       apps[napps] = h->applications[napps];
1035     msg->applications = htons (napps);
1036     msg->types = htons (ntypes);
1037     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1038                 "mesh: Sending %lu bytes long message %d types and %d apps\n",
1039                 ntohs (msg->header.size), ntypes, napps);
1040     send_packet (h, &msg->header);
1041   }
1042   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
1043   return h;
1044 }
1045
1046
1047 /**
1048  * Disconnect from the mesh service.
1049  *
1050  * @param handle connection to mesh to disconnect
1051  */
1052 void
1053 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1054 {
1055   if (NULL != handle->th)
1056   {
1057     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1058   }
1059   if (NULL != handle->client)
1060   {
1061     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
1062   }
1063   GNUNET_free (handle);
1064 }
1065
1066
1067 /**
1068  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
1069  * and to broadcast).
1070  *
1071  * @param h mesh handle
1072  * @param connect_handler function to call when peers are actually connected
1073  * @param disconnect_handler function to call when peers are disconnected
1074  * @param handler_cls closure for connect/disconnect handlers
1075  */
1076 struct GNUNET_MESH_Tunnel *
1077 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
1078                            GNUNET_MESH_TunnelConnectHandler connect_handler,
1079                            GNUNET_MESH_TunnelDisconnectHandler
1080                            disconnect_handler, void *handler_cls)
1081 {
1082   struct GNUNET_MESH_Tunnel *t;
1083   struct GNUNET_MESH_TunnelMessage msg;
1084
1085   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
1086   t = create_tunnel (h, 0);
1087   t->connect_handler = connect_handler;
1088   t->disconnect_handler = disconnect_handler;
1089   t->cls = handler_cls;
1090   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
1091   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1092   msg.tunnel_id = htonl (t->tid);
1093   send_packet (h, &msg.header);
1094   return t;
1095 }
1096
1097
1098 /**
1099  * Destroy an existing tunnel.
1100  *
1101  * @param tun tunnel handle
1102  */
1103 void
1104 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tun)
1105 {
1106   struct GNUNET_MESH_Handle *h;
1107   struct GNUNET_MESH_TunnelMessage msg;
1108
1109   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
1110   h = tun->mesh;
1111
1112   if (0 != tun->owner)
1113     GNUNET_PEER_change_rc (tun->owner, -1);
1114
1115   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
1116   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1117   msg.tunnel_id = htonl (tun->tid);
1118   GNUNET_free (tun);
1119   send_packet (h, &msg.header);
1120 }
1121
1122
1123 /**
1124  * Request that a peer should be added to the tunnel.  The existing
1125  * connect handler will be called ONCE with either success or failure.
1126  * This function should NOT be called again with the same peer before the
1127  * connect handler is called.
1128  *
1129  * @param tunnel handle to existing tunnel
1130  * @param timeout how long to try to establish a connection
1131  * @param peer peer to add
1132  */
1133 void
1134 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
1135                                       const struct GNUNET_PeerIdentity *peer)
1136 {
1137   struct GNUNET_MESH_PeerControl msg;
1138   GNUNET_PEER_Id peer_id;
1139   unsigned int i;
1140
1141   peer_id = GNUNET_PEER_intern (peer);
1142   for (i = 0; i < tunnel->npeers; i++)
1143   {
1144     if (tunnel->peers[i]->id == peer_id)
1145     {
1146       GNUNET_PEER_change_rc (peer_id, -1);
1147       GNUNET_break (0);
1148       return;
1149     }
1150   }
1151   add_peer_to_tunnel (tunnel, peer);
1152
1153   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1154   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
1155   msg.tunnel_id = htonl (tunnel->tid);
1156   msg.peer = *peer;
1157   send_packet (tunnel->mesh, &msg.header);
1158
1159   return;
1160 }
1161
1162
1163 /**
1164  * Request that a peer should be removed from the tunnel.  The existing
1165  * disconnect handler will be called ONCE if we were connected.
1166  *
1167  * @param tunnel handle to existing tunnel
1168  * @param peer peer to remove
1169  */
1170 void
1171 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
1172                                       const struct GNUNET_PeerIdentity *peer)
1173 {
1174   struct GNUNET_MESH_PeerControl msg;
1175   GNUNET_PEER_Id peer_id;
1176   unsigned int i;
1177
1178   peer_id = GNUNET_PEER_search (peer);
1179   if (0 == peer_id)
1180   {
1181     GNUNET_break (0);
1182     return;
1183   }
1184   for (i = 0; i < tunnel->npeers; i++)
1185     if (tunnel->peers[i]->id == peer_id)
1186       break;
1187   if (i == tunnel->npeers)
1188   {
1189     GNUNET_break (0);
1190     return;
1191   }
1192   if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1)
1193     tunnel->disconnect_handler (tunnel->cls, peer);
1194   GNUNET_PEER_change_rc (peer_id, -1);
1195   GNUNET_free (tunnel->peers[i]);
1196   tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
1197   GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
1198
1199   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1200   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
1201   msg.tunnel_id = htonl (tunnel->tid);
1202   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1203   send_packet (tunnel->mesh, &msg.header);
1204 }
1205
1206
1207 /**
1208  * Request that the mesh should try to connect to a peer supporting the given
1209  * message type.
1210  *
1211  * @param tunnel handle to existing tunnel
1212  * @param app_type application type that must be supported by the peer (MESH
1213  *                 should discover peer in proximity handling this type)
1214  */
1215 void
1216 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
1217                                           GNUNET_MESH_ApplicationType app_type)
1218 {
1219   struct GNUNET_MESH_ConnectPeerByType msg;
1220
1221   GNUNET_array_append (tunnel->apps, tunnel->napps, app_type);
1222   /* FIXME: add a new api call disconnect by type? */
1223
1224   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
1225   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
1226   msg.tunnel_id = htonl (tunnel->tid);
1227   msg.type = htonl (app_type);
1228   send_packet (tunnel->mesh, &msg.header);
1229 }
1230
1231
1232 /**
1233  * Ask the mesh to call "notify" once it is ready to transmit the
1234  * given number of bytes to the specified "target".  If we are not yet
1235  * connected to the specified peer, a call to this function will cause
1236  * us to try to establish a connection.
1237  *
1238  * @param tunnel tunnel to use for transmission
1239  * @param cork is corking allowed for this transmission?
1240  * @param priority how important is the message?
1241  * @param maxdelay how long can the message wait?
1242  * @param target destination for the message,
1243  *               NULL for multicast to all tunnel targets
1244  * @param notify_size how many bytes of buffer space does notify want?
1245  * @param notify function to call when buffer space is available;
1246  *        will be called with NULL on timeout or if the overall queue
1247  *        for this peer is larger than queue_size and this is currently
1248  *        the message with the lowest priority
1249  * @param notify_cls closure for notify
1250  * @return non-NULL if the notify callback was queued,
1251  *         NULL if we can not even queue the request (insufficient
1252  *         memory); if NULL is returned, "notify" will NOT be called.
1253  */
1254 struct GNUNET_MESH_TransmitHandle *
1255 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1256                                    uint32_t priority,
1257                                    struct GNUNET_TIME_Relative maxdelay,
1258                                    const struct GNUNET_PeerIdentity *target,
1259                                    size_t notify_size,
1260                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1261                                    void *notify_cls)
1262 {
1263   struct GNUNET_MESH_TransmitHandle *th;
1264   size_t overhead;
1265
1266   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
1267       tunnel->npackets > 0)
1268     return NULL;                /* queue full */
1269   tunnel->npackets++;
1270   tunnel->mesh->npackets++;
1271   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1272   th->tunnel = tunnel;
1273   th->priority = priority;
1274   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1275   th->target = GNUNET_PEER_intern (target);
1276   overhead =
1277       (NULL ==
1278        target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct
1279                                                                  GNUNET_MESH_Unicast);
1280   th->size = notify_size + overhead;
1281   th->notify = notify;
1282   th->notify_cls = notify_cls;
1283   add_to_queue (tunnel->mesh, th);
1284   return th;
1285 }
1286
1287
1288 /**
1289  * Cancel the specified transmission-ready notification.
1290  *
1291  * @param th handle that was returned by "notify_transmit_ready".
1292  */
1293 void
1294 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1295 {
1296   struct GNUNET_MESH_Handle *mesh;
1297
1298   mesh = th->tunnel->mesh;
1299   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1300     GNUNET_SCHEDULER_cancel (th->timeout_task);
1301   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1302   GNUNET_free (th);
1303   if ((NULL == mesh->th_head) && (NULL != mesh->th))
1304   {
1305     /* queue empty, no point in asking for transmission */
1306     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1307     mesh->th = NULL;
1308   }
1309 }
1310
1311
1312 #if 0                           /* keep Emacsens' auto-indent happy */
1313 {
1314 #endif
1315 #ifdef __cplusplus
1316 }
1317 #endif