Changes to integrate mesh application_type re-definition
[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   element->num_types = *num;
317   element->types = GNUNET_malloc (*num * sizeof (GNUNET_MESH_ApplicationType));
318
319   for (i = 0; i < *num; i++)
320     element->types[i] = (GNUNET_MESH_ApplicationType)ntohs (ports[i]);
321
322   struct tunnel_list_element *tunnel = handle->pending_by_type_tunnels.head;
323   while (tunnel != NULL)
324     {
325       struct tunnel_list_element *next = tunnel->next;
326       for (i = 0; i < *num; i++)
327         {
328           if (ntohs (ports[i]) == tunnel->tunnel.message_type)
329             {
330               GNUNET_CONTAINER_DLL_remove (handle->pending_tunnels.head,
331                                            handle->pending_tunnels.tail,
332                                            tunnel);
333               GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.
334                                                  head,
335                                                  handle->established_tunnels.
336                                                  tail,
337                                                  handle->established_tunnels.
338                                                  tail, tunnel);
339               tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls,
340                                               &tunnel->tunnel.peer, atsi);
341               GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
342               break;
343             }
344         }
345       if (ntohs (ports[i]) == tunnel->tunnel.message_type)
346         tunnel = next;
347       else
348         tunnel = tunnel->next;
349     }
350   return GNUNET_OK;
351 }
352
353 /**
354  * Receive a message from core.
355  */
356 static int
357 core_receive (void *cls,
358               const struct GNUNET_PeerIdentity *other,
359               const struct GNUNET_MessageHeader *message,
360               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
361 {
362   struct GNUNET_MESH_Handle *handle = cls;
363   struct tunnel_message *tmessage = (struct tunnel_message *) message;
364   struct GNUNET_MessageHeader *rmessage =
365     (struct GNUNET_MessageHeader *) (tmessage + 1);
366
367   struct GNUNET_MESH_MessageHandler *handler;
368
369   for (handler = handle->handlers; handler->callback != NULL; handler++)
370     {
371       if ( (ntohs (rmessage->type) == handler->type)
372            && ( (handler->expected_size == 0)
373                 || (handler->expected_size == ntohs (rmessage->size))) )
374         {
375           break;
376         }
377     }
378
379   /* handler->callback handles this message */
380
381   /* If no handler was found, drop the message but keep the channel open */
382   if (handler->callback == NULL)
383     return GNUNET_OK;
384
385   struct tunnel_list_element *tunnel = handle->established_tunnels.head;
386
387   while (tunnel != NULL)
388     {
389       if (tunnel->tunnel.id.id == tmessage->id.id &&
390           (0 ==
391            memcmp (&tmessage->id.initiator, &tunnel->tunnel.id.initiator,
392                    sizeof (struct GNUNET_PeerIdentity)))
393           && (0 ==
394               memcmp (&tmessage->id.target, &tunnel->tunnel.id.target,
395                       sizeof (struct GNUNET_PeerIdentity))))
396         break;
397       tunnel = tunnel->next;
398     }
399
400   /* if no tunnel was found: create a new inbound tunnel */
401   if (tunnel == NULL)
402     {
403       tunnel = GNUNET_malloc (sizeof (struct tunnel_list_element));
404       tunnel->tunnel.connect_handler = NULL;
405       tunnel->tunnel.disconnect_handler = NULL;
406       tunnel->tunnel.handler_cls = NULL;
407       tunnel->tunnel.ctx = NULL;
408       tunnel->tunnel.handle = handle;
409       memcpy (&tunnel->tunnel.peer, other,
410               sizeof (struct GNUNET_PeerIdentity));
411       memcpy (&tunnel->tunnel.id, &tmessage->id, sizeof (struct tunnel_id));
412
413       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
414                                          handle->established_tunnels.tail,
415                                          handle->established_tunnels.tail,
416                                          tunnel);
417     }
418
419   return handler->callback (handle->cls, &tunnel->tunnel,
420                             &tunnel->tunnel.ctx, other, rmessage, atsi);
421 }
422
423 struct GNUNET_MESH_Tunnel *
424 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Handle *handle,
425                                           struct GNUNET_TIME_Relative timeout,
426                                           GNUNET_MESH_ApplicationType message_type,
427                                           GNUNET_MESH_TunnelConnectHandler
428                                           connect_handler,
429                                           GNUNET_MESH_TunnelDisconnectHandler
430                                           disconnect_handler,
431                                           void *handler_cls)
432 {
433   /* Look in the list of connected peers */
434   struct peer_list_element *element = handle->connected_peers.head;
435   while (element != NULL)
436     {
437       unsigned int i;
438       for (i = 0; i < element->num_types; i++)
439         if (message_type == element->types[i])
440           return GNUNET_MESH_peer_request_connect_all (handle, timeout, 1,
441                                                        &handle->myself,
442                                                        connect_handler,
443                                                        disconnect_handler,
444                                                        handler_cls);
445       element = element->next;
446     }
447
448   /* Put into pending list */
449   struct tunnel_list_element *tunnel =
450     GNUNET_malloc (sizeof (struct tunnel_list_element));
451
452   tunnel->tunnel.connect_handler = connect_handler;
453   tunnel->tunnel.disconnect_handler = disconnect_handler;
454   tunnel->tunnel.handler_cls = handler_cls;
455   tunnel->tunnel.ctx = NULL;
456   tunnel->tunnel.handle = handle;
457   memcpy (&tunnel->tunnel.id.initiator, &handle->myself,
458           sizeof (struct GNUNET_PeerIdentity));
459   tunnel->tunnel.id.id = current_id++;
460   tunnel->tunnel.message_type = message_type;
461
462   GNUNET_CONTAINER_DLL_insert_after (handle->pending_by_type_tunnels.head,
463                                      handle->pending_by_type_tunnels.tail,
464                                      handle->pending_by_type_tunnels.tail,
465                                      tunnel);
466   return &tunnel->tunnel;
467 }
468
469
470
471 struct GNUNET_MESH_Tunnel *
472 GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle,
473                                       struct GNUNET_TIME_Relative timeout,
474                                       unsigned int num_peers,
475                                       const struct GNUNET_PeerIdentity *peers,
476                                       GNUNET_MESH_TunnelConnectHandler
477                                       connect_handler,
478                                       GNUNET_MESH_TunnelDisconnectHandler
479                                       disconnect_handler, void *handler_cls)
480 {
481   if (num_peers != 1)
482     return NULL;
483
484   struct tunnel_list_element *tunnel =
485     GNUNET_malloc (sizeof (struct tunnel_list_element));
486
487   tunnel->tunnel.connect_handler = connect_handler;
488   tunnel->tunnel.disconnect_handler = disconnect_handler;
489   tunnel->tunnel.handler_cls = handler_cls;
490   tunnel->tunnel.ctx = NULL;
491   tunnel->tunnel.handle = handle;
492   memcpy (&tunnel->tunnel.id.initiator, &handle->myself,
493           sizeof (struct GNUNET_PeerIdentity));
494   memcpy (&tunnel->tunnel.id.target, peers,
495           sizeof (struct GNUNET_PeerIdentity));
496   tunnel->tunnel.id.id = current_id++;
497   memcpy (&tunnel->tunnel.peer, peers, sizeof(struct GNUNET_PeerIdentity));
498
499   struct peer_list_element *element = handle->connected_peers.head;
500   while (element != NULL)
501     {
502       if (0 ==
503           memcmp (&element->peer, peers, sizeof (struct GNUNET_PeerIdentity)))
504         break;
505       element = element->next;
506     }
507
508   if (element != NULL)
509     {
510       /* we are connected to this peer */
511       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
512                                          handle->established_tunnels.tail,
513                                          handle->established_tunnels.tail,
514                                          tunnel);
515       connect_handler (handler_cls, &element->peer, &element->atsi);
516     }
517   else if (0 ==
518            memcmp (peers, &handle->myself,
519                    sizeof (struct GNUNET_PeerIdentity)))
520     {
521       /* we are the peer */
522       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
523                                          handle->established_tunnels.tail,
524                                          handle->established_tunnels.tail,
525                                          tunnel);
526       GNUNET_SCHEDULER_add_now(send_self_connect, tunnel);
527     }
528   else
529     {
530       /* we are not connected to this peer */
531       GNUNET_CONTAINER_DLL_insert_after (handle->pending_tunnels.head,
532                                          handle->pending_tunnels.tail,
533                                          handle->pending_tunnels.tail,
534                                          tunnel);
535       (void) GNUNET_CORE_peer_request_connect (handle->core,
536                                                timeout,
537                                                peers,
538                                                NULL, NULL);                                     
539     }
540
541   return &tunnel->tunnel;
542 }
543
544 const struct GNUNET_PeerIdentity*
545 GNUNET_MESH_get_peer(const struct GNUNET_MESH_Tunnel* tunnel)
546 {
547   return &tunnel->peer;
548 }
549
550 static size_t
551 core_notify(void* cls, size_t size, void* buf)
552 {
553   struct notify_cls *ncls = cls;
554   struct GNUNET_MESH_Tunnel *tunnel = ncls->tunnel;
555   struct tunnel_message* message = buf;
556   void* cbuf = (void*) &message[1];
557   GNUNET_assert(NULL != ncls->notify);
558
559   size_t sent = ncls->notify(ncls->notify_cls, size - sizeof(struct tunnel_message), cbuf);
560
561   GNUNET_free(ncls);
562
563   if (0 == sent) return 0;
564
565   sent += sizeof(struct tunnel_message);
566
567   message->hdr.type = htons(GNUNET_MESSAGE_TYPE_MESH);
568   message->hdr.size = htons(sent);
569   memcpy(&message->id, &tunnel->id, sizeof(struct tunnel_id));
570   return sent;
571 }
572
573
574 /**
575  * Ask the mesh to call "notify" once it is ready to transmit the
576  * given number of bytes to the specified "target".  If we are not yet
577  * connected to the specified peer, a call to this function will cause
578  * us to try to establish a connection.
579  *
580  * @param tunnel tunnel to use for transmission
581  * @param cork is corking allowed for this transmission?
582  * @param priority how important is the message?
583  * @param maxdelay how long can the message wait?
584  * @param target destination for the message, NULL for multicast to all tunnel targets 
585  * @param notify_size how many bytes of buffer space does notify want?
586  * @param notify function to call when buffer space is available;
587  *        will be called with NULL on timeout or if the overall queue
588  *        for this peer is larger than queue_size and this is currently
589  *        the message with the lowest priority
590  * @param notify_cls closure for notify
591  * @return non-NULL if the notify callback was queued,
592  *         NULL if we can not even queue the request (insufficient
593  *         memory); if NULL is returned, "notify" will NOT be called.
594  */
595 struct GNUNET_MESH_TransmitHandle *
596 GNUNET_MESH_notify_transmit_ready (struct
597                                    GNUNET_MESH_Tunnel
598                                    *tunnel,
599                                    int cork,
600                                    uint32_t priority,
601                                    struct
602                                    GNUNET_TIME_Relative
603                                    maxdelay,
604                                    const struct GNUNET_PeerIdentity *target,
605                                    size_t
606                                    notify_size,
607                                    GNUNET_CONNECTION_TransmitReadyNotify
608                                    notify, void *notify_cls)
609 {
610   struct notify_cls *cls = GNUNET_malloc(sizeof(struct notify_cls));
611   cls->notify_cls = notify_cls;
612   GNUNET_assert(NULL != notify);
613   cls->notify = notify;
614   cls->tunnel = tunnel;
615   GNUNET_CORE_notify_transmit_ready(tunnel->handle->core,
616                                     cork,
617                                     priority,
618                                     maxdelay,
619                                     &tunnel->peer,
620                                     notify_size + sizeof(struct tunnel_message),
621                                     &core_notify,
622                                     (void*)cls);
623
624   /* aborting is not implemented yet */
625   return (struct GNUNET_MESH_TransmitHandle*) 1;
626 }
627
628
629 struct GNUNET_MESH_Handle *
630 GNUNET_MESH_connect (const struct
631                      GNUNET_CONFIGURATION_Handle
632                      *cfg, void *cls,
633                      GNUNET_MESH_TunnelEndHandler
634                      cleaner,
635                      const struct GNUNET_MESH_MessageHandler *handlers,
636                      const GNUNET_MESH_ApplicationType *stypes)
637 {
638   struct GNUNET_MESH_Handle *ret =
639     GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
640
641   ret->connected_to_core = GNUNET_NO;
642   ret->connected_peers.head = NULL;
643   ret->connected_peers.tail = NULL;
644   ret->cleaner = cleaner;
645   ret->cls = cls;
646
647   const struct GNUNET_MESH_MessageHandler *it;
648   unsigned int len = 1;
649   for (it = handlers; it->callback != NULL; it++)
650     {
651       len++;
652     }
653
654   ret->handlers =
655     GNUNET_malloc (len * sizeof (struct GNUNET_MESH_MessageHandler));
656   memset(ret->handlers, 0, len * sizeof(struct GNUNET_MESH_MessageHandler));
657   memcpy (ret->handlers, handlers,
658           len * sizeof (struct GNUNET_MESH_MessageHandler));
659
660   const static struct GNUNET_CORE_MessageHandler core_handlers[] = {
661     {&core_receive, GNUNET_MESSAGE_TYPE_MESH, 0},
662     {&receive_hello, GNUNET_MESSAGE_TYPE_MESH_HELLO, 0},
663     {NULL, 0, 0}
664   };
665
666   ret->core = GNUNET_CORE_connect (cfg,
667                                    42,
668                                    ret,
669                                    &core_startup,
670                                    &core_connect,
671                                    &core_disconnect,
672                                    NULL,
673                                    NULL,
674                                    GNUNET_NO, NULL, GNUNET_NO, core_handlers);
675   return ret;
676 }
677
678 void
679 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
680 {
681   GNUNET_free (handle->handlers);
682   GNUNET_CORE_disconnect (handle->core);
683
684   struct peer_list_element *element = handle->connected_peers.head;
685   while (element != NULL)
686     {
687       struct peer_list_element *next = element->next;
688       GNUNET_free (element);
689       element = next;
690     }
691
692   struct tunnel_list_element *tunnel = handle->pending_tunnels.head;
693   while (tunnel != NULL)
694     {
695       struct tunnel_list_element *next = tunnel->next;
696       GNUNET_free (tunnel);
697       tunnel = next;
698     }
699   tunnel = handle->established_tunnels.head;;
700   while (tunnel != NULL)
701     {
702       struct tunnel_list_element *next = tunnel->next;
703       GNUNET_free (tunnel);
704       tunnel = next;
705     }
706
707   GNUNET_free (handle);
708 }
709
710 /* end of mesh_api.c */