- Fixed MESH API logging behavior and code readability
[oweals/gnunet.git] / src / mesh / mesh_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 Christian Grothoff (and other contributing authors)
4      GNUnet is free software; you can redistribute it and/or modify
5      it under the terms of the GNU General Public License as published
6      by the Free Software Foundation; either version 3, or (at your
7      option) any later version.
8      GNUnet is distributed in the hope that it will be useful, but
9      WITHOUT ANY WARRANTY; without even the implied warranty of
10      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11      General Public License for more details.
12      You should have received a copy of the GNU General Public License
13      along with GNUnet; see the file COPYING.  If not, write to the
14      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15      Boston, MA 02111-1307, USA.
16 */
17
18 /**
19  * @file mesh/mesh_api.c
20  * @brief mesh api: client implementation of mesh service
21  * @author Bartlomiej Polot
22  *
23  * STRUCTURE:
24  * - CONSTANTS
25  * - DATA STRUCTURES
26  * - AUXILIARY FUNCTIONS
27  * - RECEIVE HANDLERS
28  * - SEND FUNCTIONS
29  * - API CALL DEFINITIONS
30  */
31 #ifdef __cplusplus
32 extern "C"
33 {
34 #if 0                           /* keep Emacsens' auto-indent happy */
35 }
36 #endif
37 #endif
38
39 #include "platform.h"
40 #include "gnunet_common.h"
41 #include "gnunet_client_lib.h"
42 #include "gnunet_util_lib.h"
43 #include "gnunet_peer_lib.h"
44 #include "gnunet_mesh_service.h"
45 #include "mesh.h"
46 #include "mesh_protocol.h"
47
48 #define MESH_API_DEBUG GNUNET_YES
49
50 #if MESH_API_DEBUG
51 #define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__)
52 #else
53 #define LOG(kind,...)
54 #endif
55
56 /******************************************************************************/
57 /************************      DATA STRUCTURES     ****************************/
58 /******************************************************************************/
59
60 /**
61  * Transmission queue to the service
62  */
63 struct GNUNET_MESH_TransmitHandle
64 {
65
66     /**
67      * Double Linked list
68      */
69   struct GNUNET_MESH_TransmitHandle *next;
70
71     /**
72      * Double Linked list
73      */
74   struct GNUNET_MESH_TransmitHandle *prev;
75
76     /**
77      * Tunnel this message is sent on / for (may be NULL for control messages).
78      */
79   struct GNUNET_MESH_Tunnel *tunnel;
80
81     /**
82      * Callback to obtain the message to transmit, or NULL if we
83      * got the message in 'data'.  Notice that messages built
84      * by 'notify' need to be encapsulated with information about
85      * the 'target'.
86      */
87   GNUNET_CONNECTION_TransmitReadyNotify notify;
88
89     /**
90      * Closure for 'notify'
91      */
92   void *notify_cls;
93
94     /**
95      * How long is this message valid.  Once the timeout has been
96      * reached, the message must no longer be sent.  If this
97      * is a message with a 'notify' callback set, the 'notify'
98      * function should be called with 'buf' NULL and size 0.
99      */
100   struct GNUNET_TIME_Absolute timeout;
101
102     /**
103      * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
104      */
105   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
106
107     /**
108      * Priority of the message.  The queue is sorted by priority,
109      * control messages have the maximum priority (UINT32_MAX).
110      */
111   uint32_t priority;
112
113     /**
114      * Target of the message, 0 for multicast.  This field
115      * is only valid if 'notify' is non-NULL.
116      */
117   GNUNET_PEER_Id target;
118
119     /**
120      * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
121      */
122   size_t size;
123 };
124
125
126 /**
127  * Opaque handle to the service.
128  */
129 struct GNUNET_MESH_Handle
130 {
131
132     /**
133      * Handle to the server connection, to send messages later
134      */
135   struct GNUNET_CLIENT_Connection *client;
136
137     /**
138      * Set of handlers used for processing incoming messages in the tunnels
139      */
140   const struct GNUNET_MESH_MessageHandler *message_handlers;
141
142     /**
143      * Set of applications that should be claimed to be offered at this node.
144      * Note that this is just informative, the appropiate handlers must be
145      * registered independently and the mapping is up to the developer of the
146      * client application.
147      */
148   const GNUNET_MESH_ApplicationType *applications;
149
150     /**
151      * Double linked list of the tunnels this client is connected to.
152      */
153   struct GNUNET_MESH_Tunnel *tunnels_head;
154   struct GNUNET_MESH_Tunnel *tunnels_tail;
155
156     /**
157      * Callback for inbound tunnel creation
158      */
159   GNUNET_MESH_InboundTunnelNotificationHandler *new_tunnel;
160
161     /**
162      * Callback for inbound 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    * Time to the next reconnect in case one reconnect fails
208    */
209   struct GNUNET_TIME_Relative reconnect_time;
210 };
211
212
213 /**
214  * Description of a peer
215  */
216 struct GNUNET_MESH_Peer
217 {
218     /**
219      * ID of the peer in short form
220      */
221   GNUNET_PEER_Id id;
222
223   /**
224    * Tunnel this peer belongs to
225    */
226   struct GNUNET_MESH_Tunnel *t;
227
228   /**
229    * Flag indicating whether service has informed about its connection
230    */
231   int connected;
232
233 };
234
235
236 /**
237  * Opaque handle to a tunnel.
238  */
239 struct GNUNET_MESH_Tunnel
240 {
241
242     /**
243      * DLL
244      */
245   struct GNUNET_MESH_Tunnel *next;
246   struct GNUNET_MESH_Tunnel *prev;
247
248     /**
249      * Callback to execute when peers connect to the tunnel
250      */
251   GNUNET_MESH_PeerConnectHandler connect_handler;
252
253     /**
254      * Callback to execute when peers disconnect from the tunnel
255      */
256   GNUNET_MESH_PeerDisconnectHandler disconnect_handler;
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. 0 if the tunnel is the local client.
275      */
276   GNUNET_PEER_Id owner;
277
278     /**
279      * All peers added to the tunnel
280      */
281   struct GNUNET_MESH_Peer **peers;
282
283   /**
284    * List of application types that have been requested for this tunnel
285    */
286   GNUNET_MESH_ApplicationType *apps;
287
288   /**
289    * Any data the caller wants to put in here
290    */
291   void *ctx;
292
293   /**
294      * Number of peers added to the tunnel
295      */
296   unsigned int npeers;
297
298     /**
299      * Number of packets queued in this tunnel
300      */
301   unsigned int npackets;
302
303     /**
304      * Number of applications requested this tunnel
305      */
306   unsigned int napps;
307
308 };
309
310
311 /******************************************************************************/
312 /***********************     AUXILIARY FUNCTIONS      *************************/
313 /******************************************************************************/
314
315 /**
316  * Get the tunnel handler for the tunnel specified by id from the given handle
317  * @param h Mesh handle
318  * @param tid ID of the wanted tunnel
319  * @return handle to the required tunnel or NULL if not found
320  */
321 static struct GNUNET_MESH_Tunnel *
322 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
323 {
324   struct GNUNET_MESH_Tunnel *t;
325
326   t = h->tunnels_head;
327   while (t != NULL)
328   {
329     if (t->tid == tid)
330       return t;
331     t = t->next;
332   }
333   return NULL;
334 }
335
336
337 /**
338  * Create a new tunnel and insert it in the tunnel list of the mesh handle
339  * @param h Mesh handle
340  * @param tid desired tid of the tunnel, 0 to assign one automatically
341  * @return handle to the created tunnel
342  */
343 static struct GNUNET_MESH_Tunnel *
344 create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
345 {
346   struct GNUNET_MESH_Tunnel *t;
347
348   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
349   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
350   t->mesh = h;
351   if (0 == tid)
352   {
353     t->tid = h->next_tid;
354     while (NULL != retrieve_tunnel (h, h->next_tid))
355     {
356       h->next_tid++;
357       h->next_tid &= ~GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
358       h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
359     }
360   }
361   else
362   {
363     t->tid = tid;
364   }
365   return t;
366 }
367
368
369 /**
370  * Destroy the specified tunnel.
371  * - Destroys all peers, calling the disconnect callback on each if needed
372  * - Cancels all outgoing traffic for that tunnel, calling respective notifys
373  * - Calls cleaner if tunnel was inbound
374  * - Frees all memory used
375  *
376  * @param t Pointer to the tunnel.
377  * @param call_handler Whether to call the cleaner handler.
378  *
379  * @return Handle to the required tunnel or NULL if not found.
380  */
381 static void
382 destroy_tunnel (struct GNUNET_MESH_Tunnel *t, int call_cleaner)
383 {
384   struct GNUNET_MESH_Handle *h;
385   struct GNUNET_PeerIdentity pi;
386   struct GNUNET_MESH_TransmitHandle *th;
387   struct GNUNET_MESH_TransmitHandle *next;
388   unsigned int i;
389
390   if (NULL == t)
391   {
392     GNUNET_break (0);
393     return;
394   }
395   h = t->mesh;
396
397   /* disconnect all peers */
398   GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t);
399   for (i = 0; i < t->npeers; i++)
400   {
401     if ( (NULL != t->disconnect_handler) && t->peers[i]->connected)
402     {
403       GNUNET_PEER_resolve (t->peers[i]->id, &pi);
404       t->disconnect_handler (t->cls, &pi);
405     }
406     GNUNET_PEER_change_rc (t->peers[i]->id, -1);
407     GNUNET_free (t->peers[i]);
408   }
409
410   /* signal tunnel destruction */
411   if ( (NULL != h->cleaner) && (0 != t->owner) && (GNUNET_YES == call_cleaner) )
412     h->cleaner (h->cls, t, t->ctx);
413
414   /* check that clients did not leave messages behind in the queue */
415   for (th = h->th_head; NULL != th; th = next)
416   {
417     next = th->next;
418     if (th->tunnel != t)
419       continue;
420     /* we should not really get here, as clients should have
421        aborted their requests already.
422        Management traffic should be ok, as clients can't cancel that */
423     GNUNET_break (NULL == th->notify);
424     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
425
426     /* clean up request */
427     if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
428       GNUNET_SCHEDULER_cancel (th->timeout_task);
429     GNUNET_free (th);    
430   }
431
432   /* if there are no more pending requests with mesh service, cancel active request */
433   /* Note: this should be unnecessary... */
434   if ( (NULL == h->th_head) && (NULL != h->th))
435   {
436     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
437     h->th = NULL;
438   }
439
440
441   if (t->npeers > 0)
442     GNUNET_free (t->peers);
443   if (0 != t->owner)
444     GNUNET_PEER_change_rc (t->owner, -1);
445   if (0 != t->napps && t->apps)
446     GNUNET_free (t->apps);
447   GNUNET_free (t);
448   return;
449 }
450
451
452 /**
453  * Get the peer descriptor for the peer with id from the given tunnel
454  * @param t Tunnel handle
455  * @param id Short form ID of the wanted peer
456  * @return handle to the requested peer or NULL if not found
457  */
458 static struct GNUNET_MESH_Peer *
459 retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id)
460 {
461   unsigned int i;
462
463   for (i = 0; i < t->npeers; i++)
464     if (t->peers[i]->id == id)
465       return t->peers[i];
466   return NULL;
467 }
468
469
470 /**
471  * Add a peer into a tunnel
472  * @param t Tunnel handle
473  * @param pi Full ID of the new peer
474  * @return handle to the newly created peer
475  */
476 static struct GNUNET_MESH_Peer *
477 add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
478                     const struct GNUNET_PeerIdentity *pi)
479 {
480   struct GNUNET_MESH_Peer *p;
481   GNUNET_PEER_Id id;
482
483   if (0 != t->owner)
484   {
485     GNUNET_break (0);
486     return NULL;
487   }
488   id = GNUNET_PEER_intern (pi);
489
490   p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
491   p->id = id;
492   p->t = t;
493   GNUNET_array_append (t->peers, t->npeers, p);
494   return p;
495 }
496
497
498 /**
499  * Remove a peer from a tunnel
500  * @param p Peer handle
501  */
502 static void
503 remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p)
504 {
505   unsigned int i;
506
507   for (i = 0; i < p->t->npeers; i++)
508   {
509     if (p->t->peers[i] == p)
510       break;
511   }
512   if (i == p->t->npeers)
513   {
514     GNUNET_break (0);
515     return;
516   }
517   p->t->peers[i] = p->t->peers[p->t->npeers - 1];
518   GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1);
519 }
520
521
522 /**
523  * Notify client that the transmission has timed out
524  * @param cls closure
525  * @param tc task context
526  */
527 static void
528 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
529 {
530   struct GNUNET_MESH_TransmitHandle *th = cls;
531   struct GNUNET_MESH_Handle *mesh;
532
533   mesh = th->tunnel->mesh;
534   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
535   if (th->notify != NULL)
536     th->notify (th->notify_cls, 0, NULL);
537   GNUNET_free (th);
538   if ((NULL == mesh->th_head) && (NULL != mesh->th))
539   {
540     /* queue empty, no point in asking for transmission */
541     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
542     mesh->th = NULL;
543   }
544 }
545
546
547 /**
548  * Add a transmit handle to the transmission queue by priority and set the
549  * timeout if needed.
550  *
551  * @param h mesh handle with the queue head and tail
552  * @param th handle to the packet to be transmitted
553  */
554 static void
555 add_to_queue (struct GNUNET_MESH_Handle *h,
556               struct GNUNET_MESH_TransmitHandle *th)
557 {
558   struct GNUNET_MESH_TransmitHandle *p;
559
560   p = h->th_head;
561   while ((NULL != p) && (th->priority <= p->priority))
562     p = p->next;
563   if (NULL == p)
564     p = h->th_tail;
565   else
566     p = p->prev;
567   GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
568   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
569     return;
570   th->timeout_task =
571       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
572                                     (th->timeout), &timeout_transmission, th);
573 }
574
575
576 /**
577  * Auxiliary function to send an already constructed packet to the service.
578  * Takes care of creating a new queue element, copying the message and
579  * calling the tmt_rdy function if necessary.
580  *
581  * @param h mesh handle
582  * @param msg message to transmit
583  * @param tunnel tunnel this send is related to (NULL if N/A)
584  */
585 static void
586 send_packet (struct GNUNET_MESH_Handle *h,
587              const struct GNUNET_MessageHeader *msg,
588              struct GNUNET_MESH_Tunnel *tunnel);
589
590
591 /**
592  * Reconnect callback: tries to reconnect again after a failer previous
593  * reconnecttion
594  * @param cls closure (mesh handle)
595  * @param tc task context
596  */
597 static void
598 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
599
600
601 /**
602  * Send a connect packet to the service with the applications and types
603  * requested by the user.
604  *
605  * @param h The mesh handle.
606  *
607  */
608 static void
609 send_connect (struct GNUNET_MESH_Handle *h)
610 {
611   size_t size;
612
613   size = sizeof (struct GNUNET_MESH_ClientConnect);
614   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
615   size += h->n_handlers * sizeof (uint16_t);
616   {
617     char buf[size];
618     struct GNUNET_MESH_ClientConnect *msg;
619     GNUNET_MESH_ApplicationType *apps;
620     uint16_t napps;
621     uint16_t *types;
622     uint16_t ntypes;
623
624     /* build connection packet */
625     msg = (struct GNUNET_MESH_ClientConnect *) buf;
626     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
627     msg->header.size = htons (size);
628     apps = (GNUNET_MESH_ApplicationType *) &msg[1];
629     for (napps = 0; napps < h->n_applications; napps++)
630     {
631       apps[napps] = htonl (h->applications[napps]);
632       LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:  app %u\n", h->applications[napps]);
633     }
634     types = (uint16_t *) & apps[napps];
635     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
636       types[ntypes] = htons (h->message_handlers[ntypes].type);
637     msg->applications = htons (napps);
638     msg->types = htons (ntypes);
639     LOG (GNUNET_ERROR_TYPE_DEBUG,
640          "mesh: Sending %lu bytes long message %d types and %d apps\n",
641          ntohs (msg->header.size), ntypes, napps);
642     send_packet (h, &msg->header, NULL);
643   }
644 }
645
646
647 /**
648  * Reconnect to the service, retransmit all infomation to try to restore the
649  * original state.
650  *
651  * @param h handle to the mesh
652  *
653  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
654  */
655 static int
656 reconnect (struct GNUNET_MESH_Handle *h)
657 {
658   struct GNUNET_MESH_Tunnel *t;
659   unsigned int i;
660
661   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: *****************************\n");
662   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: *******   RECONNECT   *******\n");
663   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: *****************************\n");
664
665   h->in_receive = GNUNET_NO;
666   /* disconnect */
667   if (NULL != h->th)
668   {
669     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
670     h->th = NULL;
671   }
672   if (NULL != h->client)
673   {
674     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
675   }
676
677   /* connect again */
678   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
679   if (h->client == NULL)
680   {
681     GNUNET_SCHEDULER_add_delayed (h->reconnect_time, &reconnect_cbk, h);
682     h->reconnect_time =
683         GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
684                                   GNUNET_TIME_relative_multiply
685                                   (h->reconnect_time, 2));
686     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   Next retry in %sms\n",
687          GNUNET_TIME_relative_to_string (h->reconnect_time));
688     GNUNET_break (0);
689     return GNUNET_NO;
690   }
691   else
692   {
693     h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
694   }
695   send_connect (h);
696   /* Rebuild all tunnels */
697   for (t = h->tunnels_head; NULL != t; t = t->next)
698   {
699     struct GNUNET_MESH_TunnelMessage tmsg;
700     struct GNUNET_MESH_PeerControl pmsg;
701
702     if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
703     {
704       /* Tunnel was created by service (incoming tunnel) */
705       /* TODO: Notify service of missing tunnel, to request
706        * creator to recreate path (find a path to him via DHT?)
707        */
708       continue;
709     }
710     tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
711     tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
712     tmsg.tunnel_id = htonl (t->tid);
713     send_packet (h, &tmsg.header, t);
714
715     pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
716     pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
717     pmsg.tunnel_id = htonl (t->tid);
718
719     /* Reconnect all peers */
720     for (i = 0; i < t->npeers; i++)
721     {
722       GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer);
723       if (NULL != t->disconnect_handler && t->peers[i]->connected)
724         t->disconnect_handler (t->cls, &pmsg.peer);
725       /* If the tunnel was "by type", dont connect individual peers */
726       if (0 == t->napps)
727         send_packet (t->mesh, &pmsg.header, t);
728     }
729     /* Reconnect all types, if any  */
730     for (i = 0; i < t->napps; i++)
731     {
732       struct GNUNET_MESH_ConnectPeerByType msg;
733
734       msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
735       msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
736       msg.tunnel_id = htonl (t->tid);
737       msg.type = htonl (t->apps[i]);
738       send_packet (t->mesh, &msg.header, t);
739     }
740   }
741   return GNUNET_YES;
742 }
743
744 /**
745  * Reconnect callback: tries to reconnect again after a failer previous
746  * reconnecttion
747  * @param cls closure (mesh handle)
748  * @param tc task context
749  */
750 static void
751 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
752 {
753   struct GNUNET_MESH_Handle *h = cls;
754
755   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
756     return;
757   reconnect (h);
758 }
759
760
761 /******************************************************************************/
762 /***********************      RECEIVE HANDLERS     ****************************/
763 /******************************************************************************/
764
765 /**
766  * Process the new tunnel notification and add it to the tunnels in the handle
767  *
768  * @param h     The mesh handle
769  * @param msg   A message with the details of the new incoming tunnel
770  */
771 static void
772 process_tunnel_created (struct GNUNET_MESH_Handle *h,
773                         const struct GNUNET_MESH_TunnelNotification *msg)
774 {
775   struct GNUNET_MESH_Tunnel *t;
776   MESH_TunnelNumber tid;
777
778   tid = ntohl (msg->tunnel_id);
779   if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
780   {
781     GNUNET_break (0);
782     return;
783   }
784   t = create_tunnel (h, tid);
785   t->owner = GNUNET_PEER_intern (&msg->peer);
786   t->npeers = 1;
787   t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *));
788   t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
789   t->peers[0]->t = t;
790   t->peers[0]->connected = 1;
791   t->peers[0]->id = t->owner;
792   GNUNET_PEER_change_rc (t->owner, 1);
793   t->mesh = h;
794   t->tid = tid;
795   if (NULL != h->new_tunnel)
796   {
797     struct GNUNET_ATS_Information atsi;
798
799     atsi.type = 0;
800     atsi.value = 0;
801     t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi);
802   }
803   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: new incoming tunnel %X\n", t->tid);
804   return;
805 }
806
807
808 /**
809  * Process the tunnel destroy notification and free associated resources
810  *
811  * @param h     The mesh handle
812  * @param msg   A message with the details of the tunnel being destroyed
813  */
814 static void
815 process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
816                         const struct GNUNET_MESH_TunnelMessage *msg)
817 {
818   struct GNUNET_MESH_Tunnel *t;
819   MESH_TunnelNumber tid;
820
821   tid = ntohl (msg->tunnel_id);
822   t = retrieve_tunnel (h, tid);
823
824   if (NULL == t)
825   {
826     return;
827   }
828   if (0 == t->owner)
829   {
830     GNUNET_break (0);
831   }
832   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: tunnel %u destroyed\n", t->tid);
833   destroy_tunnel (t, GNUNET_YES);
834   return;
835 }
836
837
838 /**
839  * Process the new peer event and notify the upper level of it
840  *
841  * @param h     The mesh handle
842  * @param msg   A message with the details of the peer event
843  */
844 static void
845 process_peer_event (struct GNUNET_MESH_Handle *h,
846                     const struct GNUNET_MESH_PeerControl *msg)
847 {
848   struct GNUNET_MESH_Tunnel *t;
849   struct GNUNET_MESH_Peer *p;
850   struct GNUNET_ATS_Information atsi;
851   GNUNET_PEER_Id id;
852   uint16_t size;
853
854   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: processig peer event\n");
855   size = ntohs (msg->header.size);
856   if (size != sizeof (struct GNUNET_MESH_PeerControl))
857   {
858     GNUNET_break (0);
859     return;
860   }
861   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
862   if (NULL == t)
863   {
864     GNUNET_break (0);
865     return;
866   }
867   id = GNUNET_PEER_search (&msg->peer);
868   if ((p = retrieve_peer (t, id)) == NULL)
869     p = add_peer_to_tunnel (t, &msg->peer);
870   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type))
871   {
872     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: adding peer\n");
873     if (NULL != t->connect_handler)
874     {
875       atsi.type = 0;
876       atsi.value = 0;
877       t->connect_handler (t->cls, &msg->peer, &atsi);
878     }
879     p->connected = 1;
880   }
881   else
882   {
883     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: removing peer\n");
884     if (NULL != t->disconnect_handler && p->connected)
885     {
886       t->disconnect_handler (t->cls, &msg->peer);
887     }
888     remove_peer_from_tunnel (p);
889     GNUNET_free (p);
890   }
891   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: processing peer event END\n");
892 }
893
894
895 /**
896  * Process the incoming data packets
897  *
898  * @param h         The mesh handle
899  * @param message   A message encapsulating the data
900  * 
901  * @return GNUNET_YES if everything went fine
902  *         GNUNET_NO if client closed connection (h no longer valid)
903  */
904 static int
905 process_incoming_data (struct GNUNET_MESH_Handle *h,
906                        const struct GNUNET_MessageHeader *message)
907 {
908   const struct GNUNET_MessageHeader *payload;
909   const struct GNUNET_MESH_MessageHandler *handler;
910   const struct GNUNET_PeerIdentity *peer;
911   struct GNUNET_MESH_Unicast *ucast;
912   struct GNUNET_MESH_Multicast *mcast;
913   struct GNUNET_MESH_ToOrigin *to_orig;
914   struct GNUNET_MESH_Tunnel *t;
915   unsigned int i;
916   uint16_t type;
917
918   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Got a data message!\n");
919   type = ntohs (message->type);
920   switch (type)
921   {
922   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
923     ucast = (struct GNUNET_MESH_Unicast *) message;
924
925     t = retrieve_tunnel (h, ntohl (ucast->tid));
926     payload = (struct GNUNET_MessageHeader *) &ucast[1];
927     peer = &ucast->oid;
928     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   ucast on tunnel %s [%x]\n",
929          GNUNET_i2s (peer), ntohl (ucast->tid));
930     break;
931   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
932     mcast = (struct GNUNET_MESH_Multicast *) message;
933     t = retrieve_tunnel (h, ntohl (mcast->tid));
934     payload = (struct GNUNET_MessageHeader *) &mcast[1];
935     peer = &mcast->oid;
936     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   mcast on tunnel %s [%x]\n",
937          GNUNET_i2s (peer), ntohl (mcast->tid));
938     break;
939   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
940     to_orig = (struct GNUNET_MESH_ToOrigin *) message;
941     t = retrieve_tunnel (h, ntohl (to_orig->tid));
942     payload = (struct GNUNET_MessageHeader *) &to_orig[1];
943     peer = &to_orig->sender;
944     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   torig on tunnel %s [%x]\n",
945          GNUNET_i2s (peer), ntohl (to_orig->tid));
946     break;
947   default:
948     GNUNET_break (0);
949     return GNUNET_YES;
950   }
951   if (NULL == t)
952   {
953     GNUNET_break (0);
954     return GNUNET_YES;
955   }
956   type = ntohs (payload->type);
957   for (i = 0; i < h->n_handlers; i++)
958   {
959     handler = &h->message_handlers[i];
960     if (handler->type == type)
961     {
962       struct GNUNET_ATS_Information atsi;
963
964       atsi.type = 0;
965       atsi.value = 0;
966       if (GNUNET_OK !=
967           handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi))
968       {
969         LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH: callback caused disconnection\n");
970         GNUNET_MESH_disconnect (h);
971         return GNUNET_NO;
972       }
973       else
974       {
975         LOG (GNUNET_ERROR_TYPE_DEBUG,
976              "MESH: callback completed successfully\n");
977
978       }
979     }
980   }
981   return GNUNET_YES;
982 }
983
984
985 /**
986  * Function to process all messages received from the service
987  *
988  * @param cls closure
989  * @param msg message received, NULL on timeout or fatal error
990  */
991 static void
992 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
993 {
994   struct GNUNET_MESH_Handle *h = cls;
995
996   if (msg == NULL)
997   {
998     reconnect (h);
999     return;
1000   }
1001   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message type %hu from MESH\n",
1002        ntohs (msg->type));
1003   switch (ntohs (msg->type))
1004   {
1005     /* Notify of a new incoming tunnel */
1006   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
1007     process_tunnel_created (h, (struct GNUNET_MESH_TunnelNotification *) msg);
1008     break;
1009     /* Notify of a tunnel disconnection */
1010   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
1011     process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg);
1012     break;
1013     /* Notify of a new peer or a peer disconnect in the tunnel */
1014   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD:
1015   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL:
1016     process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
1017     break;
1018     /* Notify of a new data packet in the tunnel */
1019   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
1020   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
1021   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
1022     if (GNUNET_NO == process_incoming_data (h, msg))
1023       return;
1024     break;
1025     /* We shouldn't get any other packages, log and ignore */
1026   default:
1027     LOG (GNUNET_ERROR_TYPE_WARNING,
1028          "MESH: unsolicited message form service (type %d)\n",
1029          ntohs (msg->type));
1030   }
1031   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
1032   GNUNET_CLIENT_receive (h->client, &msg_received, h,
1033                          GNUNET_TIME_UNIT_FOREVER_REL);
1034 }
1035
1036
1037 /******************************************************************************/
1038 /************************       SEND FUNCTIONS     ****************************/
1039 /******************************************************************************/
1040
1041 /**
1042  * Function called to send a message to the service.
1043  * "buf" will be NULL and "size" zero if the socket was closed for writing in
1044  * the meantime.
1045  *
1046  * @param cls closure, the mesh handle
1047  * @param size number of bytes available in buf
1048  * @param buf where the callee should write the connect message
1049  * @return number of bytes written to buf
1050  */
1051 static size_t
1052 send_callback (void *cls, size_t size, void *buf)
1053 {
1054   struct GNUNET_MESH_Handle *h = cls;
1055   struct GNUNET_MESH_TransmitHandle *th;
1056   char *cbuf = buf;
1057   size_t tsize;
1058   size_t psize;
1059
1060   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
1061   h->th = NULL;
1062   if ((0 == size) || (NULL == buf))
1063   {
1064     reconnect (h);
1065     return 0;
1066   }
1067   tsize = 0;
1068   while ((NULL != (th = h->th_head)) && (size >= th->size))
1069   {
1070     if (NULL != th->notify)
1071     {
1072       if (th->tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1073       {
1074         /* traffic to origin */
1075         struct GNUNET_MESH_ToOrigin to;
1076         struct GNUNET_MessageHeader *mh;
1077
1078         GNUNET_assert (size >= th->size);
1079         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)];
1080         psize = th->notify (th->notify_cls, size - sizeof (to), mh);
1081         LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   to origin, type %u\n",
1082              ntohs (mh->type));
1083         if (psize > 0)
1084         {
1085           psize += sizeof (to);
1086           GNUNET_assert (size >= psize);
1087           to.header.size = htons (psize);
1088           to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
1089           to.tid = htonl (th->tunnel->tid);
1090           memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1091           memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity));
1092           memcpy (cbuf, &to, sizeof (to));
1093         }
1094       }
1095       else if (th->target == 0)
1096       {
1097         /* multicast */
1098         struct GNUNET_MESH_Multicast mc;
1099         struct GNUNET_MessageHeader *mh;
1100
1101         GNUNET_assert (size >= th->size);
1102         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)];
1103         psize = th->notify (th->notify_cls, size - sizeof (mc), mh);
1104         LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   multicast, type %u\n",
1105              ntohs (mh->type));
1106         if (psize > 0)
1107         {
1108           psize += sizeof (mc);
1109           GNUNET_assert (size >= psize);
1110           mc.header.size = htons (psize);
1111           mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
1112           mc.tid = htonl (th->tunnel->tid);
1113           mc.mid = 0;
1114           mc.ttl = 0;
1115           memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1116           memcpy (cbuf, &mc, sizeof (mc));
1117         }
1118       }
1119       else
1120       {
1121         /* unicast */
1122         struct GNUNET_MESH_Unicast uc;
1123         struct GNUNET_MessageHeader *mh;
1124
1125         GNUNET_assert (size >= th->size);
1126         mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)];
1127         psize = th->notify (th->notify_cls, size - sizeof (uc), mh);
1128         LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   unicast, type %u\n",
1129              ntohs (mh->type));
1130         if (psize > 0)
1131         {
1132           psize += sizeof (uc);
1133           GNUNET_assert (size >= psize);
1134           uc.header.size = htons (psize);
1135           uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
1136           uc.tid = htonl (th->tunnel->tid);
1137           memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
1138           GNUNET_PEER_resolve (th->target, &uc.destination);
1139           memcpy (cbuf, &uc, sizeof (uc));
1140         }
1141       }
1142     }
1143     else
1144     {
1145       memcpy (cbuf, &th[1], th->size);
1146       psize = th->size;
1147     }
1148     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1149       GNUNET_SCHEDULER_cancel (th->timeout_task);
1150     if (NULL != th->notify)
1151     {
1152       th->tunnel->mesh->npackets--;
1153       th->tunnel->npackets--;
1154     }
1155     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1156     GNUNET_free (th);
1157     cbuf += psize;
1158     size -= psize;
1159     tsize += psize;
1160   }
1161   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   total size: %u\n", tsize);
1162   if (NULL != (th = h->th_head))
1163   {
1164     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:   next size: %u\n", th->size);
1165     if (NULL == h->th)
1166       h->th =
1167           GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
1168                                                GNUNET_TIME_UNIT_FOREVER_REL,
1169                                                GNUNET_YES, &send_callback, h);
1170   }
1171   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
1172   if (GNUNET_NO == h->in_receive)
1173   {
1174     h->in_receive = GNUNET_YES;
1175     GNUNET_CLIENT_receive (h->client, &msg_received, h,
1176                            GNUNET_TIME_UNIT_FOREVER_REL);
1177   }
1178   return tsize;
1179 }
1180
1181
1182 /**
1183  * Auxiliary function to send an already constructed packet to the service.
1184  * Takes care of creating a new queue element, copying the message and
1185  * calling the tmt_rdy function if necessary.
1186  * 
1187  * @param h mesh handle
1188  * @param msg message to transmit
1189  * @param tunnel tunnel this send is related to (NULL if N/A)
1190  */
1191 static void
1192 send_packet (struct GNUNET_MESH_Handle *h,
1193              const struct GNUNET_MessageHeader *msg,
1194              struct GNUNET_MESH_Tunnel *tunnel)
1195 {
1196   struct GNUNET_MESH_TransmitHandle *th;
1197   size_t msize;
1198
1199   msize = ntohs (msg->size);
1200   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
1201   th->priority = UINT32_MAX;
1202   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1203   th->size = msize;
1204   th->tunnel = tunnel;
1205   memcpy (&th[1], msg, msize);
1206   add_to_queue (h, th);
1207   if (NULL != h->th)
1208     return;
1209   h->th =
1210       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
1211                                            GNUNET_TIME_UNIT_FOREVER_REL,
1212                                            GNUNET_YES, &send_callback, h);
1213 }
1214
1215
1216 /******************************************************************************/
1217 /**********************      API CALL DEFINITIONS     *************************/
1218 /******************************************************************************/
1219
1220 /**
1221  * Connect to the mesh service.
1222  *
1223  * @param cfg configuration to use
1224  * @param queue_size size of the data message queue, shared among all tunnels
1225  *                   (each tunnel is guaranteed to accept at least one message,
1226  *                    no matter what is the status of other tunnels)
1227  * @param cls closure for the various callbacks that follow
1228  *            (including handlers in the handlers array)
1229  * @param new_tunnel function called when an *inbound* tunnel is created
1230  * @param cleaner function called when an *inbound* tunnel is destroyed by the
1231  *                remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy
1232  *                is called on the tunnel
1233  * @param handlers callbacks for messages we care about, NULL-terminated
1234  *                note that the mesh is allowed to drop notifications about
1235  *                inbound messages if the client does not process them fast
1236  *                enough (for this notification type, a bounded queue is used)
1237  * @param stypes list of the applications that this client claims to provide
1238  * @return handle to the mesh service NULL on error
1239  *         (in this case, init is never called)
1240  */
1241 struct GNUNET_MESH_Handle *
1242 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1243                      unsigned int queue_size, void *cls,
1244                      GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel,
1245                      GNUNET_MESH_TunnelEndHandler cleaner,
1246                      const struct GNUNET_MESH_MessageHandler *handlers,
1247                      const GNUNET_MESH_ApplicationType *stypes)
1248 {
1249   struct GNUNET_MESH_Handle *h;
1250
1251   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
1252   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
1253   h->cfg = cfg;
1254   h->max_queue_size = queue_size;
1255   h->new_tunnel = new_tunnel;
1256   h->cleaner = cleaner;
1257   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1258   if (h->client == NULL)
1259   {
1260     GNUNET_break (0);
1261     GNUNET_free (h);
1262     return NULL;
1263   }
1264   h->cls = cls;
1265   /* FIXME memdup? */
1266   h->applications = stypes;
1267   h->message_handlers = handlers;
1268   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
1269   h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1270
1271   /* count handlers and apps, calculate size */
1272   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
1273   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
1274   send_connect (h);
1275   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
1276   return h;
1277 }
1278
1279
1280 /**
1281  * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel
1282  * disconnect callbacks will be called on any still connected peers, notifying
1283  * about their disconnection. The registered inbound tunnel cleaner will be
1284  * called should any inbound tunnels still exist.
1285  *
1286  * @param handle connection to mesh to disconnect
1287  */
1288 void
1289 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1290 {
1291   struct GNUNET_MESH_Tunnel *t;
1292   struct GNUNET_MESH_Tunnel *aux;
1293   struct GNUNET_MESH_TransmitHandle *th;
1294
1295   t = handle->tunnels_head;
1296   while (NULL != t)
1297   {
1298     aux = t->next;
1299     if (t->tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1300     {
1301       GNUNET_break (0);
1302       LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: tunnel %X not destroyed\n", t->tid);
1303     }
1304     destroy_tunnel (t, GNUNET_YES);
1305     t = aux;
1306   }
1307   while ( (th = handle->th_head) != NULL)
1308   {
1309     struct GNUNET_MessageHeader *msg;
1310
1311     /* Make sure it is an allowed packet (everything else should have been
1312      * already canceled).
1313      */
1314     GNUNET_break (UINT32_MAX == th->priority);
1315     GNUNET_break (NULL == th->notify);
1316     msg = (struct GNUNET_MessageHeader *) &th[1];
1317     switch (ntohs(msg->type))
1318     {
1319       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT:
1320       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
1321         break;
1322       default:
1323         GNUNET_break (0);
1324         LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: unexpected msg %u\n",
1325              ntohs(msg->type));
1326     }
1327
1328     GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th);
1329     GNUNET_free (th);
1330   }
1331
1332   if (NULL != handle->th)
1333   {
1334     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1335     handle->th = NULL;
1336   }
1337   if (NULL != handle->client)
1338   {
1339     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
1340     handle->client = NULL;
1341   }
1342   GNUNET_free (handle);
1343 }
1344
1345
1346 /**
1347  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
1348  * and to broadcast).
1349  *
1350  * @param h mesh handle
1351  * @param tunnel_ctx client's tunnel context to associate with the tunnel
1352  * @param connect_handler function to call when peers are actually connected
1353  * @param disconnect_handler function to call when peers are disconnected
1354  * @param handler_cls closure for connect/disconnect handlers
1355  */
1356 struct GNUNET_MESH_Tunnel *
1357 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
1358                            GNUNET_MESH_PeerConnectHandler connect_handler,
1359                            GNUNET_MESH_PeerDisconnectHandler disconnect_handler,
1360                            void *handler_cls)
1361 {
1362   struct GNUNET_MESH_Tunnel *t;
1363   struct GNUNET_MESH_TunnelMessage msg;
1364
1365   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
1366   t = create_tunnel (h, 0);
1367   t->connect_handler = connect_handler;
1368   t->disconnect_handler = disconnect_handler;
1369   t->cls = handler_cls;
1370   t->ctx = tunnel_ctx;
1371   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
1372   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1373   msg.tunnel_id = htonl (t->tid);
1374   send_packet (h, &msg.header, t);
1375   return t;
1376 }
1377
1378
1379 /**
1380  * Destroy an existing tunnel. The existing callback for the tunnel will NOT
1381  * be called.
1382  *
1383  * @param tunnel tunnel handle
1384  */
1385 void
1386 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel)
1387 {
1388   struct GNUNET_MESH_Handle *h;
1389   struct GNUNET_MESH_TunnelMessage msg;
1390   struct GNUNET_MESH_TransmitHandle *th;
1391
1392   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
1393   h = tunnel->mesh;
1394
1395   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
1396   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1397   msg.tunnel_id = htonl (tunnel->tid);
1398   th = h->th_head;
1399   while (th != NULL)
1400   {
1401     struct GNUNET_MESH_TransmitHandle *aux;
1402     if (th->tunnel == tunnel)
1403     {
1404       aux = th->next;
1405       /* FIXME call the handler? */
1406       if (NULL != th->notify)
1407         th->notify (th->notify_cls, 0, NULL);
1408       GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1409       GNUNET_free (th);
1410       th = aux;
1411     }
1412     else
1413       th = th->next;
1414   }
1415
1416   destroy_tunnel (tunnel, GNUNET_NO);
1417   send_packet (h, &msg.header, tunnel);
1418 }
1419
1420
1421 /**
1422  * Request that a peer should be added to the tunnel.  The existing
1423  * connect handler will be called ONCE with either success or failure.
1424  * This function should NOT be called again with the same peer before the
1425  * connect handler is called.
1426  *
1427  * @param tunnel handle to existing tunnel
1428  * @param peer peer to add
1429  */
1430 void
1431 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
1432                                       const struct GNUNET_PeerIdentity *peer)
1433 {
1434   struct GNUNET_MESH_PeerControl msg;
1435   GNUNET_PEER_Id peer_id;
1436   unsigned int i;
1437
1438   peer_id = GNUNET_PEER_intern (peer);
1439   for (i = 0; i < tunnel->npeers; i++)
1440   {
1441     if (tunnel->peers[i]->id == peer_id)
1442     {
1443       /* Peer already exists in tunnel */
1444       GNUNET_PEER_change_rc (peer_id, -1);
1445       GNUNET_break (0);
1446       return;
1447     }
1448   }
1449   if (NULL == add_peer_to_tunnel (tunnel, peer))
1450     return;
1451
1452   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1453   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
1454   msg.tunnel_id = htonl (tunnel->tid);
1455   msg.peer = *peer;
1456   send_packet (tunnel->mesh, &msg.header, tunnel);
1457
1458   return;
1459 }
1460
1461
1462 /**
1463  * Request that a peer should be removed from the tunnel.  The existing
1464  * disconnect handler will be called ONCE if we were connected.
1465  *
1466  * @param tunnel handle to existing tunnel
1467  * @param peer peer to remove
1468  */
1469 void
1470 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
1471                                       const struct GNUNET_PeerIdentity *peer)
1472 {
1473   struct GNUNET_MESH_PeerControl msg;
1474   GNUNET_PEER_Id peer_id;
1475   unsigned int i;
1476
1477   peer_id = GNUNET_PEER_search (peer);
1478   if (0 == peer_id)
1479   {
1480     GNUNET_break (0);
1481     return;
1482   }
1483   for (i = 0; i < tunnel->npeers; i++)
1484     if (tunnel->peers[i]->id == peer_id)
1485       break;
1486   if (i == tunnel->npeers)
1487   {
1488     GNUNET_break (0);
1489     return;
1490   }
1491   if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1)
1492     tunnel->disconnect_handler (tunnel->cls, peer);
1493   GNUNET_PEER_change_rc (peer_id, -1);
1494   GNUNET_free (tunnel->peers[i]);
1495   tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
1496   GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
1497
1498   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1499   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
1500   msg.tunnel_id = htonl (tunnel->tid);
1501   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1502   send_packet (tunnel->mesh, &msg.header, tunnel);
1503 }
1504
1505
1506 /**
1507  * Request that the mesh should try to connect to a peer supporting the given
1508  * message type.
1509  *
1510  * @param tunnel handle to existing tunnel
1511  * @param app_type application type that must be supported by the peer (MESH
1512  *                 should discover peer in proximity handling this type)
1513  */
1514 void
1515 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
1516                                           GNUNET_MESH_ApplicationType app_type)
1517 {
1518   struct GNUNET_MESH_ConnectPeerByType msg;
1519
1520   GNUNET_array_append (tunnel->apps, tunnel->napps, app_type);
1521
1522   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
1523   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
1524   msg.tunnel_id = htonl (tunnel->tid);
1525   msg.type = htonl (app_type);
1526   send_packet (tunnel->mesh, &msg.header, tunnel);
1527 }
1528
1529
1530 /**
1531  * Ask the mesh to call "notify" once it is ready to transmit the
1532  * given number of bytes to the specified "target".  If we are not yet
1533  * connected to the specified peer, a call to this function will cause
1534  * us to try to establish a connection.
1535  *
1536  * @param tunnel tunnel to use for transmission
1537  * @param cork is corking allowed for this transmission?
1538  * @param priority how important is the message?
1539  * @param maxdelay how long can the message wait?
1540  * @param target destination for the message,
1541  *               NULL for multicast to all tunnel targets
1542  * @param notify_size how many bytes of buffer space does notify want?
1543  * @param notify function to call when buffer space is available;
1544  *        will be called with NULL on timeout or if the overall queue
1545  *        for this peer is larger than queue_size and this is currently
1546  *        the message with the lowest priority
1547  * @param notify_cls closure for notify
1548  * @return non-NULL if the notify callback was queued,
1549  *         NULL if we can not even queue the request (insufficient
1550  *         memory); if NULL is returned, "notify" will NOT be called.
1551  */
1552 struct GNUNET_MESH_TransmitHandle *
1553 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1554                                    uint32_t priority,
1555                                    struct GNUNET_TIME_Relative maxdelay,
1556                                    const struct GNUNET_PeerIdentity *target,
1557                                    size_t notify_size,
1558                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1559                                    void *notify_cls)
1560 {
1561   struct GNUNET_MESH_TransmitHandle *th;
1562   struct GNUNET_MESH_TransmitHandle *least_priority_th;
1563   uint32_t least_priority;
1564   size_t overhead;
1565
1566   GNUNET_assert (NULL != tunnel);
1567   LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: mesh notify transmit ready called\n");
1568   if (NULL != target)
1569     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:     target %s\n", GNUNET_i2s (target));
1570   else
1571     LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh:     target multicast\n");
1572   GNUNET_assert (NULL != notify);
1573   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
1574       tunnel->npackets > 0)
1575   {
1576     /* queue full */
1577     if (0 == priority)
1578       return NULL;
1579     th = tunnel->mesh->th_tail;
1580     least_priority = priority;
1581     least_priority_th = NULL;
1582     while (NULL != th)
1583     {
1584       if (th->priority < least_priority && th->tunnel->npackets > 1)
1585       {
1586         least_priority_th = th;
1587         least_priority = th->priority;
1588       }
1589       th = th->prev;
1590     }
1591     if (NULL == least_priority_th)
1592       return NULL;
1593     /* Can't be a control message */
1594     GNUNET_assert (NULL != least_priority_th->notify);
1595     least_priority_th->notify (notify_cls, 0, NULL);
1596     least_priority_th->tunnel->npackets--;
1597     tunnel->mesh->npackets--;
1598     GNUNET_CONTAINER_DLL_remove (tunnel->mesh->th_head, tunnel->mesh->th_tail,
1599                                  least_priority_th);
1600     if (GNUNET_SCHEDULER_NO_TASK != least_priority_th->timeout_task)
1601       GNUNET_SCHEDULER_cancel (least_priority_th->timeout_task);
1602     GNUNET_free (least_priority_th);
1603   }
1604   tunnel->npackets++;
1605   tunnel->mesh->npackets++;
1606   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1607   th->tunnel = tunnel;
1608   th->priority = priority;
1609   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1610   th->target = GNUNET_PEER_intern (target);
1611   if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
1612     overhead = sizeof (struct GNUNET_MESH_ToOrigin);
1613   else if (NULL == target)
1614     overhead = sizeof (struct GNUNET_MESH_Multicast);
1615   else
1616     overhead = sizeof (struct GNUNET_MESH_Unicast);
1617   th->size = notify_size + overhead;
1618   th->notify = notify;
1619   th->notify_cls = notify_cls;
1620   add_to_queue (tunnel->mesh, th);
1621   if (NULL != tunnel->mesh->th)
1622     return th;
1623   tunnel->mesh->th =
1624       GNUNET_CLIENT_notify_transmit_ready (tunnel->mesh->client, th->size,
1625                                            GNUNET_TIME_UNIT_FOREVER_REL,
1626                                            GNUNET_YES, &send_callback,
1627                                            tunnel->mesh);
1628   return th;
1629 }
1630
1631
1632 /**
1633  * Cancel the specified transmission-ready notification.
1634  *
1635  * @param th handle that was returned by "notify_transmit_ready".
1636  */
1637 void
1638 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1639 {
1640   struct GNUNET_MESH_Handle *mesh;
1641
1642   mesh = th->tunnel->mesh;
1643   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1644     GNUNET_SCHEDULER_cancel (th->timeout_task);
1645   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1646   GNUNET_free (th);
1647   if ((NULL == mesh->th_head) && (NULL != mesh->th))
1648   {
1649     /* queue empty, no point in asking for transmission */
1650     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1651     mesh->th = NULL;
1652   }
1653 }
1654
1655
1656 /**
1657  * Transition API for tunnel ctx management
1658  */
1659 void
1660 GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data)
1661 {
1662   tunnel->ctx = data;
1663 }
1664
1665 /**
1666  * Transition API for tunnel ctx management
1667  */
1668 void *
1669 GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel)
1670 {
1671   return tunnel->ctx;
1672 }
1673
1674
1675 #if 0                           /* keep Emacsens' auto-indent happy */
1676 {
1677 #endif
1678 #ifdef __cplusplus
1679 }
1680 #endif