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