implement get_path_from_route
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_core.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2017 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file cadet/gnunet-service-cadet_core.c
23  * @brief cadet service; interaction with CORE service
24  * @author Bartlomiej Polot
25  * @author Christian Grothoff
26  *
27  * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
28  *
29  * TODO:
30  * - Optimization: given BROKEN messages, destroy paths (?)
31  */
32 #include "platform.h"
33 #include "gnunet-service-cadet-new_core.h"
34 #include "gnunet-service-cadet-new_paths.h"
35 #include "gnunet-service-cadet-new_peer.h"
36 #include "gnunet-service-cadet-new_connection.h"
37 #include "gnunet-service-cadet-new_tunnels.h"
38 #include "gnunet_core_service.h"
39 #include "cadet_protocol.h"
40
41
42 #define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__)
43
44
45 /**
46  * Number of messages we are willing to buffer per route.
47  */
48 #define ROUTE_BUFFER_SIZE 8
49
50
51 /**
52  * Information we keep per direction for a route.
53  */
54 struct RouteDirection
55 {
56   /**
57    * Target peer.
58    */
59   struct CadetPeer *hop;
60
61   /**
62    * Route this direction is part of.
63    */
64   struct CadetRoute *my_route;
65
66   /**
67    * Message queue manager for @e hop.
68    */
69   struct GCP_MessageQueueManager *mqm;
70
71   /**
72    * Cyclic message buffer to @e hop.
73    */
74   struct GNUNET_MQ_Envelope *out_buffer[ROUTE_BUFFER_SIZE];
75
76   /**
77    * Next write offset to use to append messages to @e out_buffer.
78    */
79   unsigned int out_wpos;
80
81   /**
82    * Next read offset to use to retrieve messages from @e out_buffer.
83    */
84   unsigned int out_rpos;
85
86   /**
87    * Is @e mqm currently ready for transmission?
88    */
89   int is_ready;
90
91 };
92
93
94 /**
95  * Description of a segment of a `struct CadetConnection` at the
96  * intermediate peers.  Routes are basically entries in a peer's
97  * routing table for forwarding traffic.  At both endpoints, the
98  * routes are terminated by a `struct CadetConnection`, which knows
99  * the complete `struct CadetPath` that is formed by the individual
100  * routes.
101  */
102 struct CadetRoute
103 {
104
105   /**
106    * Information about the next hop on this route.
107    */
108   struct RouteDirection next;
109
110   /**
111    * Information about the previous hop on this route.
112    */
113   struct RouteDirection prev;
114
115   /**
116    * Unique identifier for the connection that uses this route.
117    */
118   struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
119
120   /**
121    * When was this route last in use?
122    */
123   struct GNUNET_TIME_Absolute last_use;
124
125 };
126
127
128 /**
129  * Handle to the CORE service.
130  */
131 static struct GNUNET_CORE_Handle *core;
132
133 /**
134  * Routes on which this peer is an intermediate.
135  */
136 static struct GNUNET_CONTAINER_MultiShortmap *routes;
137
138
139 /**
140  * Get the route corresponding to a hash.
141  *
142  * @param cid hash generated from the connection identifier
143  */
144 static struct CadetRoute *
145 get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
146 {
147   return GNUNET_CONTAINER_multishortmap_get (routes,
148                                              &cid->connection_of_tunnel);
149 }
150
151
152 /**
153  * We message @a msg from @a prev.  Find its route by @a cid and
154  * forward to the next hop.  Drop and signal broken route if we do not
155  * have a route.
156  *
157  * @param prev previous hop (sender)
158  * @param cid connection identifier, tells us which route to use
159  * @param msg the message to forward
160  */
161 static void
162 route_message (struct CadetPeer *prev,
163                const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
164                const struct GNUNET_MessageHeader *msg)
165 {
166   struct CadetRoute *route;
167   struct RouteDirection *dir;
168   struct GNUNET_MQ_Envelope *env;
169
170   route = get_route (cid);
171   if (NULL == route)
172   {
173     struct GNUNET_MQ_Envelope *env;
174     struct GNUNET_CADET_ConnectionBrokenMessage *bm;
175
176     env = GNUNET_MQ_msg (bm,
177                          GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
178     bm->cid = *cid;
179     bm->peer1 = my_full_id;
180     GCP_send_ooo (prev,
181                   env);
182     return;
183   }
184   dir = (prev == route->prev.hop) ? &route->next : &route->prev;
185   if (GNUNET_YES == dir->is_ready)
186   {
187     dir->is_ready = GNUNET_NO;
188     GCP_send (dir->mqm,
189               GNUNET_MQ_msg_copy (msg));
190     return;
191   }
192   env = dir->out_buffer[dir->out_wpos];
193   if (NULL != env)
194   {
195     /* Queue full, drop earliest message in queue */
196     GNUNET_assert (dir->out_rpos == dir->out_wpos);
197     GNUNET_MQ_discard (env);
198     dir->out_rpos++;
199     if (ROUTE_BUFFER_SIZE == dir->out_rpos)
200       dir->out_rpos = 0;
201   }
202   env = GNUNET_MQ_msg_copy (msg);
203   dir->out_buffer[dir->out_wpos] = env;
204   dir->out_wpos++;
205   if (ROUTE_BUFFER_SIZE == dir->out_wpos)
206     dir->out_wpos = 0;
207 }
208
209
210 /**
211  * Check if the create_connection message has the appropriate size.
212  *
213  * @param cls Closure (unused).
214  * @param msg Message to check.
215  *
216  * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
217  */
218 static int
219 check_connection_create (void *cls,
220                          const struct GNUNET_CADET_ConnectionCreateMessage *msg)
221 {
222   uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
223
224   if (0 != (size % sizeof (struct GNUNET_PeerIdentity)))
225   {
226     GNUNET_break_op (0);
227     return GNUNET_NO;
228   }
229   return GNUNET_YES;
230 }
231
232
233 /**
234  * Free internal data of a route direction.
235  *
236  * @param dir direction to destroy (do NOT free memory of 'dir' itself)
237  */
238 static void
239 destroy_direction (struct RouteDirection *dir)
240 {
241   for (unsigned int i=0;i<ROUTE_BUFFER_SIZE;i++)
242     if (NULL != dir->out_buffer[i])
243     {
244       GNUNET_MQ_discard (dir->out_buffer[i]);
245       dir->out_buffer[i] = NULL;
246     }
247   if (NULL != dir->mqm)
248   {
249     GCP_request_mq_cancel (dir->mqm,
250                            NULL);
251     dir->mqm = NULL;
252   }
253 }
254
255
256 /**
257  * Destroy our state for @a route.
258  *
259  * @param route route to destroy
260  */
261 static void
262 destroy_route (struct CadetRoute *route)
263 {
264   destroy_direction (&route->prev);
265   destroy_direction (&route->next);
266   GNUNET_free (route);
267 }
268
269
270 /**
271  * Send message that a route is broken between @a peer1 and @a peer2.
272  *
273  * @param target where to send the message
274  * @param cid connection identifier to use
275  * @param peer1 one of the peers where a link is broken
276  * @param peer2 another one of the peers where a link is broken
277  */
278 static void
279 send_broken (struct RouteDirection *target,
280              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
281              const struct GNUNET_PeerIdentity *peer1,
282              const struct GNUNET_PeerIdentity *peer2)
283 {
284   struct GNUNET_MQ_Envelope *env;
285   struct GNUNET_CADET_ConnectionBrokenMessage *bm;
286
287   env = GNUNET_MQ_msg (bm,
288                        GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
289   bm->cid = *cid;
290   if (NULL != peer1)
291     bm->peer1 = *peer1;
292   if (NULL != peer2)
293     bm->peer2 = *peer2;
294   GCP_request_mq_cancel (target->mqm,
295                          env);
296   target->mqm = NULL;
297 }
298
299
300 /**
301  * Function called when the message queue to the previous hop
302  * becomes available/unavailable.  We expect this function to
303  * be called immediately when we register, and then again
304  * later if the connection ever goes down.
305  *
306  * @param cls the `struct RouteDirection`
307  * @param available #GNUNET_YES if sending is now possible,
308  *                  #GNUNET_NO if sending is no longer possible
309  *                  #GNUNET_SYSERR if sending is no longer possible
310  *                                 and the last envelope was discarded
311  */
312 static void
313 dir_ready_cb (void *cls,
314               int ready)
315 {
316   struct RouteDirection *dir = cls;
317   struct CadetRoute *route = dir->my_route;
318   struct RouteDirection *odir;
319
320   if (GNUNET_YES == ready)
321   {
322     struct GNUNET_MQ_Envelope *env;
323
324     dir->is_ready = GNUNET_YES;
325     if (NULL != (env = dir->out_buffer[dir->out_rpos]))
326     {
327       dir->out_buffer[dir->out_rpos] = NULL;
328       dir->out_rpos++;
329       if (ROUTE_BUFFER_SIZE == dir->out_rpos)
330         dir->out_rpos = 0;
331       dir->is_ready = GNUNET_NO;
332       GCP_send (dir->mqm,
333                 env);
334     }
335     return;
336   }
337   odir = (dir == &route->next) ? &route->prev : &route->next;
338   send_broken (&route->next,
339                &route->cid,
340                GCP_get_id (odir->hop),
341                &my_full_id);
342   destroy_route (route);
343 }
344
345
346 /**
347  * Initialize one of the directions of a route.
348  *
349  * @param route route the direction belongs to
350  * @param dir direction to initialize
351  * @param hop next hop on in the @a dir
352  */
353 static void
354 dir_init (struct RouteDirection *dir,
355           struct CadetRoute *route,
356           struct CadetPeer *hop)
357 {
358   dir->hop = hop;
359   dir->my_route = route;
360   dir->mqm = GCP_request_mq (hop,
361                              &dir_ready_cb,
362                              dir);
363   GNUNET_assert (GNUNET_YES == dir->is_ready);
364 }
365
366
367 /**
368  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
369  *
370  * @param cls Closure (CadetPeer for neighbor that sent the message).
371  * @param msg Message itself.
372  */
373 static void
374 handle_connection_create (void *cls,
375                           const struct GNUNET_CADET_ConnectionCreateMessage *msg)
376 {
377   struct CadetPeer *sender = cls;
378   struct CadetPeer *next;
379   const struct GNUNET_PeerIdentity *pids = (const struct GNUNET_PeerIdentity *) &msg[1];
380   struct CadetRoute *route;
381   uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
382   unsigned int path_length;
383   unsigned int off;
384
385   path_length = size / sizeof (struct GNUNET_PeerIdentity);
386   /* Initiator is at offset 0. */
387   for (off=1;off<path_length;off++)
388     if (0 == memcmp (&my_full_id,
389                      &pids[off],
390                      sizeof (struct GNUNET_PeerIdentity)))
391       break;
392   if (off == path_length)
393   {
394     /* We are not on the path, bogus request */
395     GNUNET_break_op (0);
396     return;
397   }
398   /* Check previous hop */
399   if (sender != GCP_get (&pids[off - 1],
400                          GNUNET_NO))
401   {
402     /* sender is not on the path, not allowed */
403     GNUNET_break_op (0);
404     return;
405   }
406   if (NULL !=
407       get_route (&msg->cid))
408   {
409     /* Duplicate CREATE, pass it on, previous one might have been lost! */
410     route_message (sender,
411                    &msg->cid,
412                    &msg->header);
413     return;
414   }
415   if (off == path_length - 1)
416   {
417     /* We are the destination, create connection */
418     struct CadetConnection *cc;
419     struct CadetPeerPath *path;
420     struct CadetPeer *origin;
421
422     cc = GNUNET_CONTAINER_multishortmap_get (connections,
423                                              &msg->cid.connection_of_tunnel);
424     if (NULL != cc)
425     {
426       GCC_handle_duplicate_create (cc);
427       return;
428     }
429
430     path = GCPP_get_path_from_route (path_length - 1,
431                                      pids);
432     origin = GCP_get (&pids[0],
433                       GNUNET_YES);
434     GCT_add_inbound_connection (GCT_create_tunnel (origin),
435                                 &msg->cid,
436                                 path);
437     return;
438   }
439   /* We are merely a hop on the way, check if we can support the route */
440   next = GCP_get (&pids[off + 1],
441                   GNUNET_NO);
442   if ( (NULL == next) ||
443        (GNUNET_NO == GCP_has_core_connection (next)) )
444   {
445     /* unworkable, send back BROKEN notification */
446     struct GNUNET_MQ_Envelope *env;
447     struct GNUNET_CADET_ConnectionBrokenMessage *bm;
448
449     env = GNUNET_MQ_msg (bm,
450                          GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
451     bm->cid = msg->cid;
452     bm->peer1 = pids[off + 1];
453     bm->peer2 = my_full_id;
454     GCP_send_ooo (sender,
455                   env);
456     return;
457   }
458
459   /* Workable route, create routing entry */
460   route = GNUNET_new (struct CadetRoute);
461   route->cid = msg->cid;
462   dir_init (&route->prev,
463             route,
464             sender);
465   dir_init (&route->next,
466             route,
467             next);
468   GNUNET_assert (GNUNET_OK ==
469                  GNUNET_CONTAINER_multishortmap_put (routes,
470                                                      &route->cid.connection_of_tunnel,
471                                                      route,
472                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
473 }
474
475
476 /**
477  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
478  *
479  * @param cls Closure (CadetPeer for neighbor that sent the message).
480  * @param msg Message itself.
481  */
482 static void
483 handle_connection_create_ack (void *cls,
484                               const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
485 {
486   struct CadetPeer *peer = cls;
487   struct CadetConnection *cc;
488
489   /* First, check if ACK belongs to a connection that ends here. */
490   cc = GNUNET_CONTAINER_multishortmap_get (connections,
491                                            &msg->cid.connection_of_tunnel);
492   if (NULL != cc)
493   {
494     /* verify ACK came from the right direction */
495     struct CadetPeerPath *path = GCC_get_path (cc);
496
497     if (peer !=
498         GCPP_get_peer_at_offset (path,
499                                  0))
500     {
501       /* received ACK from unexpected direction, ignore! */
502       GNUNET_break_op (0);
503       return;
504     }
505     GCC_handle_connection_create_ack (cc);
506     return;
507   }
508
509   /* We're just an intermediary peer, route the message along its path */
510   route_message (peer,
511                  &msg->cid,
512                  &msg->header);
513 }
514
515
516 /**
517  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
518  *
519  * @param cls Closure (CadetPeer for neighbor that sent the message).
520  * @param msg Message itself.
521  * @deprecated duplicate logic with #handle_destroy(); dedup!
522  */
523 static void
524 handle_connection_broken (void *cls,
525                           const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
526 {
527   struct CadetPeer *peer = cls;
528   struct CadetConnection *cc;
529   struct CadetRoute *route;
530
531   /* First, check if message belongs to a connection that ends here. */
532   cc = GNUNET_CONTAINER_multishortmap_get (connections,
533                                            &msg->cid.connection_of_tunnel);
534   if (NULL != cc)
535   {
536     /* verify message came from the right direction */
537     struct CadetPeerPath *path = GCC_get_path (cc);
538
539     if (peer !=
540         GCPP_get_peer_at_offset (path,
541                                  0))
542     {
543       /* received message from unexpected direction, ignore! */
544       GNUNET_break_op (0);
545       return;
546     }
547     GCC_destroy (cc);
548
549     /* FIXME: also destroy the path up to the specified link! */
550     return;
551   }
552
553   /* We're just an intermediary peer, route the message along its path */
554   route = get_route (&msg->cid);
555   route_message (peer,
556                  &msg->cid,
557                  &msg->header);
558   destroy_route (route);
559   /* FIXME: also destroy paths we MAY have up to the specified link! */
560 }
561
562
563 /**
564  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
565  *
566  * @param cls Closure (CadetPeer for neighbor that sent the message).
567  * @param msg Message itself.
568  */
569 static void
570 handle_connection_destroy (void *cls,
571                            const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
572 {
573   struct CadetPeer *peer = cls;
574   struct CadetConnection *cc;
575   struct CadetRoute *route;
576
577   /* First, check if message belongs to a connection that ends here. */
578   cc = GNUNET_CONTAINER_multishortmap_get (connections,
579                                            &msg->cid.connection_of_tunnel);
580   if (NULL != cc)
581   {
582     /* verify message came from the right direction */
583     struct CadetPeerPath *path = GCC_get_path (cc);
584
585     if (peer !=
586         GCPP_get_peer_at_offset (path,
587                                  0))
588     {
589       /* received message from unexpected direction, ignore! */
590       GNUNET_break_op (0);
591       return;
592     }
593     GCC_destroy (cc);
594     return;
595   }
596
597   /* We're just an intermediary peer, route the message along its path */
598   route = get_route (&msg->cid);
599   route_message (peer,
600                  &msg->cid,
601                  &msg->header);
602   destroy_route (route);
603 }
604
605
606 /**
607  * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
608  *
609  * @param cls Closure (CadetPeer for neighbor that sent the message).
610  * @param msg Message itself.
611  */
612 static void
613 handle_tunnel_kx (void *cls,
614                   const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
615 {
616   struct CadetPeer *peer = cls;
617   struct CadetConnection *cc;
618
619   /* First, check if message belongs to a connection that ends here. */
620   cc = GNUNET_CONTAINER_multishortmap_get (connections,
621                                            &msg->cid.connection_of_tunnel);
622   if (NULL != cc)
623   {
624     /* verify message came from the right direction */
625     struct CadetPeerPath *path = GCC_get_path (cc);
626
627     if (peer !=
628         GCPP_get_peer_at_offset (path,
629                                  0))
630     {
631       /* received message from unexpected direction, ignore! */
632       GNUNET_break_op (0);
633       return;
634     }
635     GCC_handle_kx (cc,
636                    msg);
637     return;
638   }
639
640   /* We're just an intermediary peer, route the message along its path */
641   route_message (peer,
642                  &msg->cid,
643                  &msg->header);
644 }
645
646
647 /**
648  * Check if the encrypted message has the appropriate size.
649  *
650  * @param cls Closure (unused).
651  * @param msg Message to check.
652  *
653  * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
654  */
655 static int
656 check_tunnel_encrypted (void *cls,
657                         const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
658 {
659   return GNUNET_YES;
660 }
661
662
663 /**
664  * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
665  *
666  * @param cls Closure (CadetPeer for neighbor that sent the message).
667  * @param msg Message itself.
668  */
669 static void
670 handle_tunnel_encrypted (void *cls,
671                          const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
672 {
673   struct CadetPeer *peer = cls;
674   struct CadetConnection *cc;
675
676   /* First, check if message belongs to a connection that ends here. */
677   cc = GNUNET_CONTAINER_multishortmap_get (connections,
678                                            &msg->cid.connection_of_tunnel);
679   if (NULL != cc)
680   {
681     /* verify message came from the right direction */
682     struct CadetPeerPath *path = GCC_get_path (cc);
683
684     if (peer !=
685         GCPP_get_peer_at_offset (path,
686                                  0))
687     {
688       /* received message from unexpected direction, ignore! */
689       GNUNET_break_op (0);
690       return;
691     }
692     GCC_handle_encrypted (cc,
693                           msg);
694     return;
695   }
696   /* We're just an intermediary peer, route the message along its path */
697   route_message (peer,
698                  &msg->cid,
699                  &msg->header);
700 }
701
702
703 /**
704  * Function called after #GNUNET_CORE_connect has succeeded (or failed
705  * for good).  Note that the private key of the peer is intentionally
706  * not exposed here; if you need it, your process should try to read
707  * the private key file directly (which should work if you are
708  * authorized...).  Implementations of this function must not call
709  * #GNUNET_CORE_disconnect (other than by scheduling a new task to
710  * do this later).
711  *
712  * @param cls closure
713  * @param my_identity ID of this peer, NULL if we failed
714  */
715 static void
716 core_init_cb (void *cls,
717               const struct GNUNET_PeerIdentity *my_identity)
718 {
719   if (NULL == my_identity)
720   {
721     GNUNET_break (0);
722     return;
723   }
724   GNUNET_break (0 ==
725                 memcmp (my_identity,
726                         &my_full_id,
727                         sizeof (struct GNUNET_PeerIdentity)));
728 }
729
730
731 /**
732  * Method called whenever a given peer connects.
733  *
734  * @param cls closure
735  * @param peer peer identity this notification is about
736  */
737 static void *
738 core_connect_cb (void *cls,
739                  const struct GNUNET_PeerIdentity *peer,
740                  struct GNUNET_MQ_Handle *mq)
741 {
742   struct CadetPeer *cp;
743
744   cp = GCP_get (peer,
745                 GNUNET_YES);
746   GCP_set_mq (cp,
747               mq);
748   return cp;
749 }
750
751
752 /**
753  * Method called whenever a peer disconnects.
754  *
755  * @param cls closure
756  * @param peer peer identity this notification is about
757  */
758 static void
759 core_disconnect_cb (void *cls,
760                     const struct GNUNET_PeerIdentity *peer,
761                     void *peer_cls)
762 {
763   struct CadetPeer *cp = peer_cls;
764
765   GCP_set_mq (cp,
766               NULL);
767 }
768
769
770 /**
771  * Initialize the CORE subsystem.
772  *
773  * @param c Configuration.
774  */
775 void
776 GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
777 {
778   struct GNUNET_MQ_MessageHandler handlers[] = {
779     GNUNET_MQ_hd_var_size (connection_create,
780                            GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
781                            struct GNUNET_CADET_ConnectionCreateMessage,
782                            NULL),
783     GNUNET_MQ_hd_fixed_size (connection_create_ack,
784                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
785                              struct GNUNET_CADET_ConnectionCreateAckMessage,
786                              NULL),
787     GNUNET_MQ_hd_fixed_size (connection_broken,
788                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
789                              struct GNUNET_CADET_ConnectionBrokenMessage,
790                              NULL),
791     GNUNET_MQ_hd_fixed_size (connection_destroy,
792                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
793                              struct GNUNET_CADET_ConnectionDestroyMessage,
794                              NULL),
795     GNUNET_MQ_hd_fixed_size (tunnel_kx,
796                              GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
797                              struct GNUNET_CADET_TunnelKeyExchangeMessage,
798                              NULL),
799     GNUNET_MQ_hd_var_size (tunnel_encrypted,
800                            GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
801                            struct GNUNET_CADET_TunnelEncryptedMessage,
802                            NULL),
803     GNUNET_MQ_handler_end ()
804   };
805
806   routes = GNUNET_CONTAINER_multishortmap_create (1024,
807                                                   GNUNET_NO);
808   core = GNUNET_CORE_connect (c,
809                               NULL,
810                               &core_init_cb,
811                               &core_connect_cb,
812                               &core_disconnect_cb,
813                               handlers);
814 }
815
816
817 /**
818  * Shut down the CORE subsystem.
819  */
820 void
821 GCO_shutdown ()
822 {
823   if (NULL != core)
824   {
825     GNUNET_CORE_disconnect (core);
826     core = NULL;
827   }
828   GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
829   GNUNET_CONTAINER_multishortmap_destroy (routes);
830 }
831
832 /* end of gnunet-cadet-service_core.c */