added TODOs
[oweals/gnunet.git] / src / mesh / mesh_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file mesh/mesh_api.c
23  * @brief mesh service; API for the Mesh. This is used to talk to arbitrary peers
24  *        as of 2011-01Jan-06 this is a mockup.
25  * @author Philipp Tölke
26  */
27 #include <platform.h>
28 #include <gnunet_constants.h>
29 #include <gnunet_mesh_service.h>
30 #include <gnunet_core_service.h>
31 #include <gnunet_container_lib.h>
32
33 struct tunnel_id
34 {
35   uint32_t id GNUNET_PACKED;
36   struct GNUNET_PeerIdentity initiator;
37   struct GNUNET_PeerIdentity target;
38 };
39
40 static uint32_t current_id = 0;
41
42 struct tunnel_message
43 {
44   struct GNUNET_MessageHeader hdr;
45   struct tunnel_id id;
46   /* followed by another GNUNET_MessageHeader */
47 };
48
49 struct notify_cls
50 {
51   void* notify_cls;
52   GNUNET_CONNECTION_TransmitReadyNotify notify;
53   struct GNUNET_MESH_Tunnel *tunnel;
54 };
55
56 struct GNUNET_MESH_Tunnel
57 {
58   /* The other peer this tunnel leads to; just unicast for the moment! */
59   struct GNUNET_PeerIdentity peer;
60
61   struct tunnel_id id;
62
63   /* The handlers and cls for outbound tunnels. Are NULL for inbound tunnels. */
64   GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
65   GNUNET_MESH_TunnelConnectHandler connect_handler;
66   void *handler_cls;
67
68   struct GNUNET_MESH_Handle* handle;
69
70   /* The message-type requested for this tunnel. Is only needed for pending
71    * by_tupe-tunnels
72    */
73   uint16_t message_type;
74
75   /* The context of the receive-function. */
76   void *ctx;
77 };
78
79 struct tunnel_list_element
80 {
81   struct GNUNET_MESH_Tunnel tunnel;
82   struct tunnel_list_element *next, *prev;
83 };
84
85 struct tunnel_list
86 {
87   struct tunnel_list_element *head, *tail;
88 };
89
90 struct peer_list_element
91 {
92   struct GNUNET_PeerIdentity peer;
93
94   /* how many Message-Types can this peer receive */
95   unsigned int num_types;
96
97   /* array of message-types */
98   GNUNET_MESH_ApplicationType *types;
99
100   struct GNUNET_TRANSPORT_ATS_Information atsi;
101   struct peer_list_element *next, *prev;
102 };
103
104 struct peer_list
105 {
106   struct peer_list_element *head, *tail;
107 };
108
109 struct GNUNET_MESH_Handle
110 {
111   struct GNUNET_CORE_Handle *core;
112   struct GNUNET_MESH_MessageHandler *handlers;
113   struct GNUNET_PeerIdentity myself;
114   unsigned int connected_to_core;
115   struct peer_list connected_peers;
116   struct tunnel_list established_tunnels;
117   struct tunnel_list pending_tunnels;
118   struct tunnel_list pending_by_type_tunnels;
119   void *cls;
120   GNUNET_MESH_TunnelEndHandler *cleaner;
121   size_t hello_message_size;
122   uint16_t *hello_message;
123 };
124
125 static void
126 send_end_connect(void* cls,
127                      const struct GNUNET_SCHEDULER_TaskContext* tc)
128 {
129   struct GNUNET_MESH_Tunnel* tunnel = cls;
130
131   tunnel->connect_handler(tunnel->handler_cls, NULL, NULL);
132 }
133
134 static void
135 send_self_connect(void* cls,
136                         const struct GNUNET_SCHEDULER_TaskContext* tc)
137 {
138   struct GNUNET_MESH_Tunnel* tunnel = cls;
139
140   tunnel->connect_handler(tunnel->handler_cls, &tunnel->handle->myself, NULL);
141   GNUNET_SCHEDULER_add_now(send_end_connect, tunnel);
142 }
143
144 static void
145 core_startup (void *cls,
146               struct GNUNET_CORE_Handle *core,
147               const struct GNUNET_PeerIdentity *my_identity,
148               const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
149 {
150   struct GNUNET_MESH_Handle *handle = cls;
151   memcpy (&handle->myself, my_identity, sizeof (struct GNUNET_PeerIdentity));
152   handle->connected_to_core = GNUNET_YES;
153 }
154
155 static size_t
156 send_hello_message (void *cls, size_t size, void *buf)
157 {
158   struct GNUNET_MESH_Handle *handle = cls;
159   struct GNUNET_MessageHeader *hdr = buf;
160
161   size_t sent = sizeof(struct GNUNET_MessageHeader) + handle->hello_message_size;
162
163   hdr->type = htons(GNUNET_MESSAGE_TYPE_MESH_HELLO);
164   hdr->size = htons(size);
165
166   memcpy(hdr+1, handle->hello_message, handle->hello_message_size);
167   return sent;
168 }
169
170
171 /**
172  * Core calls this if we are connected to a new peer.
173  *
174  * If core tells us that we are connected to ourself, we ignore it. Otherwise, the
175  * peer is added to the connected_peers-list.
176  *
177  */
178 static void
179 core_connect (void *cls,
180               const struct GNUNET_PeerIdentity *peer,
181               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
182 {
183   struct GNUNET_MESH_Handle *handle = cls;
184   /* Check for connect-to-self-message, which we ignore */
185   if (0 ==
186       memcmp (peer, &handle->myself, sizeof (struct GNUNET_PeerIdentity)))
187     return;
188
189
190   /* put the new peer into the list of connected peers */
191   struct peer_list_element *element =
192     GNUNET_malloc (sizeof (struct peer_list_element));
193   memcpy (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity));
194   memcpy (&element->atsi, atsi,
195           sizeof (struct GNUNET_TRANSPORT_ATS_Information));
196
197   GNUNET_CONTAINER_DLL_insert_after (handle->connected_peers.head,
198                                      handle->connected_peers.tail,
199                                      handle->connected_peers.tail, element);
200
201   struct tunnel_list_element *tunnel = handle->pending_tunnels.head;
202   while (tunnel != NULL)
203     {
204       if (0 ==
205           memcmp (&tunnel->tunnel.peer, peer,
206                   sizeof (struct GNUNET_PeerIdentity)))
207         {
208           struct tunnel_list_element *next = tunnel->next;
209           GNUNET_CONTAINER_DLL_remove (handle->pending_tunnels.head,
210                                        handle->pending_tunnels.tail, tunnel);
211           GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
212                                              handle->established_tunnels.tail,
213                                              handle->established_tunnels.tail,
214                                              tunnel);
215           tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls,
216                                           peer, atsi);
217           GNUNET_SCHEDULER_add_now(send_end_connect, tunnel);
218           tunnel = next;
219         }
220       else
221         tunnel = tunnel->next;
222     }
223   GNUNET_CORE_notify_transmit_ready(handle->core,
224                                     GNUNET_NO,
225                                     42,
226                                     GNUNET_TIME_UNIT_SECONDS,
227                                     peer,
228                                     sizeof(struct GNUNET_MessageHeader) + handle->hello_message_size,
229                                     &send_hello_message,
230                                     cls);
231
232 }
233
234 /**
235  * Core calls this if we disconnect a peer
236  *
237  * Remove this peer from the list of connected peers
238  * Close all tunnels this peer belongs to
239  */
240 static void
241 core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
242 {
243   struct GNUNET_MESH_Handle *handle = cls;
244
245   struct peer_list_element *element = handle->connected_peers.head;
246   while (element != NULL)
247     {
248       if (0 ==
249           memcmp (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity)))
250         break;
251       element = element->next;
252     }
253   if (element != NULL)
254     {
255       GNUNET_CONTAINER_DLL_remove (handle->connected_peers.head,
256                                    handle->connected_peers.tail, element);
257       GNUNET_free_non_null(element->types);
258       GNUNET_free (element);
259     }
260
261   struct tunnel_list_element *telement = handle->established_tunnels.head;
262   while (telement != NULL)
263     {
264       if (0 ==
265           memcmp (&telement->tunnel.peer, peer,
266                   sizeof (struct GNUNET_PeerIdentity)))
267         {
268           /* disconnect tunnels */
269           /* outbound tunnels */
270           if (telement->tunnel.connect_handler != NULL && NULL != telement->tunnel.disconnect_handler)
271             telement->tunnel.disconnect_handler (telement->tunnel.handler_cls,
272                                                  peer);
273           /* inbound tunnels */
274           else if (NULL != handle->cleaner)
275             handle->cleaner (handle->cls, &telement->tunnel,
276                              &telement->tunnel.ctx);
277
278           struct tunnel_list_element *next = telement->next;
279           GNUNET_CONTAINER_DLL_remove (handle->established_tunnels.head,
280                                        handle->established_tunnels.tail,
281                                        telement);
282           GNUNET_free (telement);
283           telement = next;
284         }
285       else
286         {
287           telement = telement->next;
288         }
289     }
290 }
291
292 /**
293  * Receive a message from core.
294  * This is a hello-message, containing the message-types the other peer can receive
295  */
296 static int
297 receive_hello (void *cls,
298                const struct GNUNET_PeerIdentity *other,
299                const struct GNUNET_MessageHeader *message,
300                const struct GNUNET_TRANSPORT_ATS_Information *atsi)
301 {
302   struct GNUNET_MESH_Handle *handle = cls;
303   uint16_t *num = (uint16_t *) (message + 1);
304   uint16_t *ports = num + 1;
305   unsigned int i;
306
307   struct peer_list_element *element = handle->connected_peers.head;
308   while (element != NULL)
309     {
310       if (0 ==
311           memcmp (&element->peer, other, sizeof (struct GNUNET_PeerIdentity)))
312         break;
313       element = element->next;
314     }
315
316   /* TODO: handle self */
317   /* TODO: add, not replace! */
318   /* TODO: if this changes anything: send new hello */
319   element->num_types = *num;
320   element->types = GNUNET_malloc (*num * sizeof (GNUNET_MESH_ApplicationType));
321
322   for (i = 0; i < *num; i++)
323     element->types[i] = (GNUNET_MESH_ApplicationType)ntohs (ports[i]);
324
325   struct tunnel_list_element *tunnel = handle->pending_by_type_tunnels.head;
326   while (tunnel != NULL)
327     {
328       struct tunnel_list_element *next = tunnel->next;
329       for (i = 0; i < *num; i++)
330         {
331           if (ntohs (ports[i]) == tunnel->tunnel.message_type)
332             {
333               GNUNET_CONTAINER_DLL_remove (handle->pending_tunnels.head,
334                                            handle->pending_tunnels.tail,
335                                            tunnel);
336               GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.
337                                                  head,
338                                                  handle->established_tunnels.
339                                                  tail,
340                                                  handle->established_tunnels.
341                                                  tail, tunnel);
342               tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls,
343                                               &tunnel->tunnel.peer, atsi);
344               GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
345               break;
346             }
347         }
348       if (ntohs (ports[i]) == tunnel->tunnel.message_type)
349         tunnel = next;
350       else
351         tunnel = tunnel->next;
352     }
353   return GNUNET_OK;
354 }
355
356 /**
357  * Receive a message from core.
358  */
359 static int
360 core_receive (void *cls,
361               const struct GNUNET_PeerIdentity *other,
362               const struct GNUNET_MessageHeader *message,
363               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
364 {
365   struct GNUNET_MESH_Handle *handle = cls;
366   struct tunnel_message *tmessage = (struct tunnel_message *) message;
367   struct GNUNET_MessageHeader *rmessage =
368     (struct GNUNET_MessageHeader *) (tmessage + 1);
369
370   struct GNUNET_MESH_MessageHandler *handler;
371
372   for (handler = handle->handlers; handler->callback != NULL; handler++)
373     {
374       if ( (ntohs (rmessage->type) == handler->type)
375            && ( (handler->expected_size == 0)
376                 || (handler->expected_size == ntohs (rmessage->size))) )
377         {
378           break;
379         }
380     }
381
382   /* handler->callback handles this message */
383
384   /* If no handler was found, drop the message but keep the channel open */
385   if (handler->callback == NULL)
386     return GNUNET_OK;
387
388   struct tunnel_list_element *tunnel = handle->established_tunnels.head;
389
390   while (tunnel != NULL)
391     {
392       if (tunnel->tunnel.id.id == tmessage->id.id &&
393           (0 ==
394            memcmp (&tmessage->id.initiator, &tunnel->tunnel.id.initiator,
395                    sizeof (struct GNUNET_PeerIdentity)))
396           && (0 ==
397               memcmp (&tmessage->id.target, &tunnel->tunnel.id.target,
398                       sizeof (struct GNUNET_PeerIdentity))))
399         break;
400       tunnel = tunnel->next;
401     }
402
403   /* if no tunnel was found: create a new inbound tunnel */
404   if (tunnel == NULL)
405     {
406       tunnel = GNUNET_malloc (sizeof (struct tunnel_list_element));
407       tunnel->tunnel.connect_handler = NULL;
408       tunnel->tunnel.disconnect_handler = NULL;
409       tunnel->tunnel.handler_cls = NULL;
410       tunnel->tunnel.ctx = NULL;
411       tunnel->tunnel.handle = handle;
412       memcpy (&tunnel->tunnel.peer, other,
413               sizeof (struct GNUNET_PeerIdentity));
414       memcpy (&tunnel->tunnel.id, &tmessage->id, sizeof (struct tunnel_id));
415
416       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
417                                          handle->established_tunnels.tail,
418                                          handle->established_tunnels.tail,
419                                          tunnel);
420     }
421
422   return handler->callback (handle->cls, &tunnel->tunnel,
423                             &tunnel->tunnel.ctx, other, rmessage, atsi);
424 }
425
426 struct GNUNET_MESH_Tunnel *
427 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Handle *handle,
428                                           struct GNUNET_TIME_Relative timeout,
429                                           GNUNET_MESH_ApplicationType message_type,
430                                           GNUNET_MESH_TunnelConnectHandler
431                                           connect_handler,
432                                           GNUNET_MESH_TunnelDisconnectHandler
433                                           disconnect_handler,
434                                           void *handler_cls)
435 {
436   /* Look in the list of connected peers */
437   struct peer_list_element *element = handle->connected_peers.head;
438   while (element != NULL)
439     {
440       unsigned int i;
441       for (i = 0; i < element->num_types; i++)
442         if (message_type == element->types[i])
443           return GNUNET_MESH_peer_request_connect_all (handle, timeout, 1,
444                                                        &handle->myself,
445                                                        connect_handler,
446                                                        disconnect_handler,
447                                                        handler_cls);
448       element = element->next;
449     }
450
451   /* Put into pending list */
452   struct tunnel_list_element *tunnel =
453     GNUNET_malloc (sizeof (struct tunnel_list_element));
454
455   tunnel->tunnel.connect_handler = connect_handler;
456   tunnel->tunnel.disconnect_handler = disconnect_handler;
457   tunnel->tunnel.handler_cls = handler_cls;
458   tunnel->tunnel.ctx = NULL;
459   tunnel->tunnel.handle = handle;
460   memcpy (&tunnel->tunnel.id.initiator, &handle->myself,
461           sizeof (struct GNUNET_PeerIdentity));
462   tunnel->tunnel.id.id = current_id++;
463   tunnel->tunnel.message_type = message_type;
464
465   GNUNET_CONTAINER_DLL_insert_after (handle->pending_by_type_tunnels.head,
466                                      handle->pending_by_type_tunnels.tail,
467                                      handle->pending_by_type_tunnels.tail,
468                                      tunnel);
469   return &tunnel->tunnel;
470 }
471
472
473
474 struct GNUNET_MESH_Tunnel *
475 GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle,
476                                       struct GNUNET_TIME_Relative timeout,
477                                       unsigned int num_peers,
478                                       const struct GNUNET_PeerIdentity *peers,
479                                       GNUNET_MESH_TunnelConnectHandler
480                                       connect_handler,
481                                       GNUNET_MESH_TunnelDisconnectHandler
482                                       disconnect_handler, void *handler_cls)
483 {
484   if (num_peers != 1)
485     return NULL;
486
487   struct tunnel_list_element *tunnel =
488     GNUNET_malloc (sizeof (struct tunnel_list_element));
489
490   tunnel->tunnel.connect_handler = connect_handler;
491   tunnel->tunnel.disconnect_handler = disconnect_handler;
492   tunnel->tunnel.handler_cls = handler_cls;
493   tunnel->tunnel.ctx = NULL;
494   tunnel->tunnel.handle = handle;
495   memcpy (&tunnel->tunnel.id.initiator, &handle->myself,
496           sizeof (struct GNUNET_PeerIdentity));
497   memcpy (&tunnel->tunnel.id.target, peers,
498           sizeof (struct GNUNET_PeerIdentity));
499   tunnel->tunnel.id.id = current_id++;
500   memcpy (&tunnel->tunnel.peer, peers, sizeof(struct GNUNET_PeerIdentity));
501
502   struct peer_list_element *element = handle->connected_peers.head;
503   while (element != NULL)
504     {
505       if (0 ==
506           memcmp (&element->peer, peers, sizeof (struct GNUNET_PeerIdentity)))
507         break;
508       element = element->next;
509     }
510
511   if (element != NULL)
512     {
513       /* we are connected to this peer */
514       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
515                                          handle->established_tunnels.tail,
516                                          handle->established_tunnels.tail,
517                                          tunnel);
518       connect_handler (handler_cls, &element->peer, &element->atsi);
519     }
520   else if (0 ==
521            memcmp (peers, &handle->myself,
522                    sizeof (struct GNUNET_PeerIdentity)))
523     {
524       /* we are the peer */
525       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
526                                          handle->established_tunnels.tail,
527                                          handle->established_tunnels.tail,
528                                          tunnel);
529       GNUNET_SCHEDULER_add_now(send_self_connect, tunnel);
530     }
531   else
532     {
533       /* we are not connected to this peer */
534       GNUNET_CONTAINER_DLL_insert_after (handle->pending_tunnels.head,
535                                          handle->pending_tunnels.tail,
536                                          handle->pending_tunnels.tail,
537                                          tunnel);
538       (void) GNUNET_CORE_peer_request_connect (handle->core,
539                                                timeout,
540                                                peers,
541                                                NULL, NULL);                                     
542     }
543
544   return &tunnel->tunnel;
545 }
546
547 const struct GNUNET_PeerIdentity*
548 GNUNET_MESH_get_peer(const struct GNUNET_MESH_Tunnel* tunnel)
549 {
550   return &tunnel->peer;
551 }
552
553 static size_t
554 core_notify(void* cls, size_t size, void* buf)
555 {
556   struct notify_cls *ncls = cls;
557   struct GNUNET_MESH_Tunnel *tunnel = ncls->tunnel;
558   struct tunnel_message* message = buf;
559   void* cbuf = (void*) &message[1];
560   GNUNET_assert(NULL != ncls->notify);
561
562   size_t sent = ncls->notify(ncls->notify_cls, size - sizeof(struct tunnel_message), cbuf);
563
564   GNUNET_free(ncls);
565
566   if (0 == sent) return 0;
567
568   sent += sizeof(struct tunnel_message);
569
570   message->hdr.type = htons(GNUNET_MESSAGE_TYPE_MESH);
571   message->hdr.size = htons(sent);
572   memcpy(&message->id, &tunnel->id, sizeof(struct tunnel_id));
573   return sent;
574 }
575
576
577 /**
578  * Ask the mesh to call "notify" once it is ready to transmit the
579  * given number of bytes to the specified "target".  If we are not yet
580  * connected to the specified peer, a call to this function will cause
581  * us to try to establish a connection.
582  *
583  * @param tunnel tunnel to use for transmission
584  * @param cork is corking allowed for this transmission?
585  * @param priority how important is the message?
586  * @param maxdelay how long can the message wait?
587  * @param target destination for the message, NULL for multicast to all tunnel targets 
588  * @param notify_size how many bytes of buffer space does notify want?
589  * @param notify function to call when buffer space is available;
590  *        will be called with NULL on timeout or if the overall queue
591  *        for this peer is larger than queue_size and this is currently
592  *        the message with the lowest priority
593  * @param notify_cls closure for notify
594  * @return non-NULL if the notify callback was queued,
595  *         NULL if we can not even queue the request (insufficient
596  *         memory); if NULL is returned, "notify" will NOT be called.
597  */
598 struct GNUNET_MESH_TransmitHandle *
599 GNUNET_MESH_notify_transmit_ready (struct
600                                    GNUNET_MESH_Tunnel
601                                    *tunnel,
602                                    int cork,
603                                    uint32_t priority,
604                                    struct
605                                    GNUNET_TIME_Relative
606                                    maxdelay,
607                                    const struct GNUNET_PeerIdentity *target,
608                                    size_t
609                                    notify_size,
610                                    GNUNET_CONNECTION_TransmitReadyNotify
611                                    notify, void *notify_cls)
612 {
613   struct notify_cls *cls = GNUNET_malloc(sizeof(struct notify_cls));
614   cls->notify_cls = notify_cls;
615   GNUNET_assert(NULL != notify);
616   cls->notify = notify;
617   cls->tunnel = tunnel;
618   GNUNET_CORE_notify_transmit_ready(tunnel->handle->core,
619                                     cork,
620                                     priority,
621                                     maxdelay,
622                                     &tunnel->peer,
623                                     notify_size + sizeof(struct tunnel_message),
624                                     &core_notify,
625                                     (void*)cls);
626
627   /* aborting is not implemented yet */
628   return (struct GNUNET_MESH_TransmitHandle*) 1;
629 }
630
631
632 struct GNUNET_MESH_Handle *
633 GNUNET_MESH_connect (const struct
634                      GNUNET_CONFIGURATION_Handle
635                      *cfg, void *cls,
636                      GNUNET_MESH_TunnelEndHandler
637                      cleaner,
638                      const struct GNUNET_MESH_MessageHandler *handlers,
639                      const GNUNET_MESH_ApplicationType *stypes)
640 {
641   struct GNUNET_MESH_Handle *ret =
642     GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
643
644   ret->connected_to_core = GNUNET_NO;
645   ret->connected_peers.head = NULL;
646   ret->connected_peers.tail = NULL;
647   ret->cleaner = cleaner;
648   ret->cls = cls;
649
650   const struct GNUNET_MESH_MessageHandler *it;
651   unsigned int len = 1;
652   for (it = handlers; it->callback != NULL; it++)
653     {
654       len++;
655     }
656
657   ret->handlers =
658     GNUNET_malloc (len * sizeof (struct GNUNET_MESH_MessageHandler));
659   memset(ret->handlers, 0, len * sizeof(struct GNUNET_MESH_MessageHandler));
660   memcpy (ret->handlers, handlers,
661           len * sizeof (struct GNUNET_MESH_MessageHandler));
662
663   /* TODO: build hello */
664
665   const static struct GNUNET_CORE_MessageHandler core_handlers[] = {
666     {&core_receive, GNUNET_MESSAGE_TYPE_MESH, 0},
667     {&receive_hello, GNUNET_MESSAGE_TYPE_MESH_HELLO, 0},
668     {NULL, 0, 0}
669   };
670
671   ret->core = GNUNET_CORE_connect (cfg,
672                                    42,
673                                    ret,
674                                    &core_startup,
675                                    &core_connect,
676                                    &core_disconnect,
677                                    NULL,
678                                    NULL,
679                                    GNUNET_NO, NULL, GNUNET_NO, core_handlers);
680   return ret;
681 }
682
683 void
684 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
685 {
686   GNUNET_free (handle->handlers);
687   GNUNET_CORE_disconnect (handle->core);
688
689   struct peer_list_element *element = handle->connected_peers.head;
690   while (element != NULL)
691     {
692       struct peer_list_element *next = element->next;
693       GNUNET_free (element);
694       element = next;
695     }
696
697   struct tunnel_list_element *tunnel = handle->pending_tunnels.head;
698   while (tunnel != NULL)
699     {
700       struct tunnel_list_element *next = tunnel->next;
701       GNUNET_free (tunnel);
702       tunnel = next;
703     }
704   tunnel = handle->established_tunnels.head;;
705   while (tunnel != NULL)
706     {
707       struct tunnel_list_element *next = tunnel->next;
708       GNUNET_free (tunnel);
709       tunnel = next;
710     }
711
712   GNUNET_free (handle);
713 }
714
715 /* end of mesh_api.c */