-remove debug message
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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_core.h"
34 #include "gnunet-service-cadet_paths.h"
35 #include "gnunet-service-cadet_peer.h"
36 #include "gnunet-service-cadet_connection.h"
37 #include "gnunet-service-cadet_tunnels.h"
38 #include "gnunet_core_service.h"
39 #include "gnunet_statistics_service.h"
40 #include "cadet_protocol.h"
41
42 #define LOG(level, ...) GNUNET_log_from (level, "cadet-cor", __VA_ARGS__)
43
44 /**
45  * Information we keep per direction for a route.
46  */
47 struct RouteDirection;
48
49 /**
50  * Set of CadetRoutes that have exactly the same number of messages
51  * in their buffer.  Used so we can efficiently find all of those
52  * routes that have the current maximum of messages in the buffer (in
53  * case we have to purge).
54  */
55 struct Rung
56 {
57   /**
58    * Rung of RouteDirections with one more buffer entry each.
59    */
60   struct Rung *next;
61
62   /**
63    * Rung of RouteDirections with one less buffer entry each.
64    */
65   struct Rung *prev;
66
67   /**
68    * DLL of route directions with a number of buffer entries matching this rung.
69    */
70   struct RouteDirection *rd_head;
71
72   /**
73    * DLL of route directions with a number of buffer entries matching this rung.
74    */
75   struct RouteDirection *rd_tail;
76
77   /**
78    * Total number of route directions in this rung.
79    */
80   unsigned int num_routes;
81
82   /**
83    * Number of messages route directions at this rung have
84    * in their buffer.
85    */
86   unsigned int rung_off;
87 };
88
89
90 /**
91  * Information we keep per direction for a route.
92  */
93 struct RouteDirection
94 {
95   /**
96    * DLL of other route directions within the same `struct Rung`.
97    */
98   struct RouteDirection *prev;
99
100   /**
101    * DLL of other route directions within the same `struct Rung`.
102    */
103   struct RouteDirection *next;
104
105   /**
106    * Rung of this route direction (matches length of the buffer DLL).
107    */
108   struct Rung *rung;
109
110   /**
111    * Head of DLL of envelopes we have in the buffer for this direction.
112    */
113   struct GNUNET_MQ_Envelope *env_head;
114
115   /**
116    * Tail of DLL of envelopes we have in the buffer for this direction.
117    */
118   struct GNUNET_MQ_Envelope *env_tail;
119
120   /**
121    * Target peer.
122    */
123   struct CadetPeer *hop;
124
125   /**
126    * Route this direction is part of.
127    */
128   struct CadetRoute *my_route;
129
130   /**
131    * Message queue manager for @e hop.
132    */
133   struct GCP_MessageQueueManager *mqm;
134
135   /**
136    * Is @e mqm currently ready for transmission?
137    */
138   int is_ready;
139 };
140
141
142 /**
143  * Description of a segment of a `struct CadetConnection` at the
144  * intermediate peers.  Routes are basically entries in a peer's
145  * routing table for forwarding traffic.  At both endpoints, the
146  * routes are terminated by a `struct CadetConnection`, which knows
147  * the complete `struct CadetPath` that is formed by the individual
148  * routes.
149  */
150 struct CadetRoute
151 {
152   /**
153    * Information about the next hop on this route.
154    */
155   struct RouteDirection next;
156
157   /**
158    * Information about the previous hop on this route.
159    */
160   struct RouteDirection prev;
161
162   /**
163    * Unique identifier for the connection that uses this route.
164    */
165   struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
166
167   /**
168    * When was this route last in use?
169    */
170   struct GNUNET_TIME_Absolute last_use;
171
172   /**
173    * Position of this route in the #route_heap.
174    */
175   struct GNUNET_CONTAINER_HeapNode *hn;
176 };
177
178
179 /**
180  * Handle to the CORE service.
181  */
182 static struct GNUNET_CORE_Handle *core;
183
184 /**
185  * Routes on which this peer is an intermediate.
186  */
187 static struct GNUNET_CONTAINER_MultiShortmap *routes;
188
189 /**
190  * Heap of routes, MIN-sorted by last activity.
191  */
192 static struct GNUNET_CONTAINER_Heap *route_heap;
193
194 /**
195  * Rung zero (always pointed to by #rung_head).
196  */
197 static struct Rung rung_zero;
198
199 /**
200  * DLL of rungs, with the head always point to a rung of
201  * route directions with no messages in the queue.
202  */
203 static struct Rung *rung_head = &rung_zero;
204
205 /**
206  * Tail of the #rung_head DLL.
207  */
208 static struct Rung *rung_tail = &rung_zero;
209
210 /**
211  * Maximum number of concurrent routes this peer will support.
212  */
213 static unsigned long long max_routes;
214
215 /**
216  * Maximum number of envelopes we will buffer at this peer.
217  */
218 static unsigned long long max_buffers;
219
220 /**
221  * Current number of envelopes we have buffered at this peer.
222  */
223 static unsigned long long cur_buffers;
224
225 /**
226  * Task to timeout routes.
227  */
228 static struct GNUNET_SCHEDULER_Task *timeout_task;
229
230 /**
231  * Get the route corresponding to a hash.
232  *
233  * @param cid hash generated from the connection identifier
234  */
235 static struct CadetRoute *
236 get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
237 {
238   return GNUNET_CONTAINER_multishortmap_get (routes,
239                                              &cid->connection_of_tunnel);
240 }
241
242
243 /**
244  * Lower the rung in which @a dir is by 1.
245  *
246  * @param dir direction to lower in rung.
247  */
248 static void
249 lower_rung (struct RouteDirection *dir)
250 {
251   struct Rung *rung = dir->rung;
252   struct Rung *prev;
253
254   GNUNET_CONTAINER_DLL_remove (rung->rd_head, rung->rd_tail, dir);
255   prev = rung->prev;
256   GNUNET_assert (NULL != prev);
257   if (prev->rung_off != rung->rung_off - 1)
258   {
259     prev = GNUNET_new (struct Rung);
260     prev->rung_off = rung->rung_off - 1;
261     GNUNET_CONTAINER_DLL_insert_after (rung_head, rung_tail, rung->prev, prev);
262   }
263   GNUNET_assert (NULL != prev);
264   GNUNET_CONTAINER_DLL_insert (prev->rd_head, prev->rd_tail, dir);
265   dir->rung = prev;
266 }
267
268
269 /**
270  * Discard the buffer @a env from the route direction @a dir and
271  * move @a dir down a rung.
272  *
273  * @param dir direction that contains the @a env in the buffer
274  * @param env envelope to discard
275  */
276 static void
277 discard_buffer (struct RouteDirection *dir, struct GNUNET_MQ_Envelope *env)
278 {
279   GNUNET_MQ_dll_remove (&dir->env_head, &dir->env_tail, env);
280   cur_buffers--;
281   GNUNET_MQ_discard (env);
282   lower_rung (dir);
283   GNUNET_STATISTICS_set (stats, "# buffer use", cur_buffers, GNUNET_NO);
284 }
285
286
287 /**
288  * Discard all messages from the highest rung, to make space.
289  */
290 static void
291 discard_all_from_rung_tail ()
292 {
293   struct Rung *tail = rung_tail;
294   struct RouteDirection *dir;
295
296   while (NULL != (dir = tail->rd_head))
297   {
298     LOG (GNUNET_ERROR_TYPE_DEBUG,
299          "Queue full due new message %s on connection %s, dropping old message\n",
300          GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
301     GNUNET_STATISTICS_update (stats,
302                               "# messages dropped due to full buffer",
303                               1,
304                               GNUNET_NO);
305     discard_buffer (dir, dir->env_head);
306   }
307   GNUNET_CONTAINER_DLL_remove (rung_head, rung_tail, tail);
308   GNUNET_free (tail);
309 }
310
311
312 /**
313  * We message @a msg from @a prev.  Find its route by @a cid and
314  * forward to the next hop.  Drop and signal broken route if we do not
315  * have a route.
316  *
317  * @param prev previous hop (sender)
318  * @param cid connection identifier, tells us which route to use
319  * @param msg the message to forward
320  */
321 static void
322 route_message (struct CadetPeer *prev,
323                const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
324                const struct GNUNET_MessageHeader *msg,
325                const enum GNUNET_MQ_PriorityPreferences priority)
326 {
327   struct CadetRoute *route;
328   struct RouteDirection *dir;
329   struct Rung *rung;
330   struct Rung *nxt;
331   struct GNUNET_MQ_Envelope *env;
332
333   route = get_route (cid);
334   if (NULL == route)
335   {
336     struct GNUNET_MQ_Envelope *env;
337     struct GNUNET_CADET_ConnectionBrokenMessage *bm;
338
339     LOG (GNUNET_ERROR_TYPE_DEBUG,
340          "Failed to route message of type %u from %s on connection %s: no route\n",
341          ntohs (msg->type),
342          GCP_2s (prev),
343          GNUNET_sh2s (&cid->connection_of_tunnel));
344     switch (ntohs (msg->type))
345     {
346     case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
347     case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
348       /* No need to respond to these! */
349       return;
350     }
351     env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
352     bm->cid = *cid;
353     bm->peer1 = my_full_id;
354     GCP_send_ooo (prev, env);
355     return;
356   }
357   route->last_use = GNUNET_TIME_absolute_get ();
358   GNUNET_CONTAINER_heap_update_cost (route->hn, route->last_use.abs_value_us);
359   dir = (prev == route->prev.hop) ? &route->next : &route->prev;
360   if (GNUNET_YES == dir->is_ready)
361   {
362     LOG (GNUNET_ERROR_TYPE_DEBUG,
363          "Routing message of type %u from %s to %s on connection %s\n",
364          ntohs (msg->type),
365          GCP_2s (prev),
366          GNUNET_i2s (GCP_get_id (dir->hop)),
367          GNUNET_sh2s (&cid->connection_of_tunnel));
368     dir->is_ready = GNUNET_NO;
369     GCP_send (dir->mqm, GNUNET_MQ_msg_copy (msg));
370     return;
371   }
372   /* Check if low latency is required and if the previous message was
373      unreliable; if so, make sure we only queue one message per
374      direction (no buffering). */
375   if ((0 != (priority & GNUNET_MQ_PREF_LOW_LATENCY)) &&
376       (NULL != dir->env_head) &&
377       (0 ==
378        (GNUNET_MQ_env_get_options (dir->env_head) & GNUNET_MQ_PREF_UNRELIABLE)))
379     discard_buffer (dir, dir->env_head);
380   /* Check for duplicates */
381   for (const struct GNUNET_MQ_Envelope *env = dir->env_head; NULL != env;
382        env = GNUNET_MQ_env_next (env))
383   {
384     const struct GNUNET_MessageHeader *hdr = GNUNET_MQ_env_get_msg (env);
385
386     if ((hdr->size == msg->size) && (0 == memcmp (hdr, msg, ntohs (msg->size))))
387     {
388       LOG (GNUNET_ERROR_TYPE_DEBUG,
389            "Received duplicate of message already in buffer, dropping\n");
390       GNUNET_STATISTICS_update (stats,
391                                 "# messages dropped due to duplicate in buffer",
392                                 1,
393                                 GNUNET_NO);
394       return;
395     }
396   }
397
398   rung = dir->rung;
399   if (cur_buffers == max_buffers)
400   {
401     /* Need to make room. */
402     if (NULL != rung->next)
403     {
404       /* Easy case, drop messages from route directions in highest rung */
405       discard_all_from_rung_tail ();
406     }
407     else
408     {
409       /* We are in the highest rung, drop our own! */
410       LOG (GNUNET_ERROR_TYPE_DEBUG,
411            "Queue full due new message %s on connection %s, dropping old message\n",
412            GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
413       GNUNET_STATISTICS_update (stats,
414                                 "# messages dropped due to full buffer",
415                                 1,
416                                 GNUNET_NO);
417       discard_buffer (dir, dir->env_head);
418       rung = dir->rung;
419     }
420   }
421   /* remove 'dir' from current rung */
422   GNUNET_CONTAINER_DLL_remove (rung->rd_head, rung->rd_tail, dir);
423   /* make 'nxt' point to the next higher rung, create if necessary */
424   nxt = rung->next;
425   if ((NULL == nxt) || (rung->rung_off + 1 != nxt->rung_off))
426   {
427     nxt = GNUNET_new (struct Rung);
428     nxt->rung_off = rung->rung_off + 1;
429     GNUNET_CONTAINER_DLL_insert_after (rung_head, rung_tail, rung, nxt);
430   }
431   /* insert 'dir' into next higher rung */
432   GNUNET_CONTAINER_DLL_insert (nxt->rd_head, nxt->rd_tail, dir);
433   dir->rung = nxt;
434
435   /* add message into 'dir' buffer */
436   LOG (GNUNET_ERROR_TYPE_DEBUG,
437        "Queueing new message of type %u from %s to %s on connection %s\n",
438        ntohs (msg->type),
439        GCP_2s (prev),
440        GNUNET_i2s (GCP_get_id (dir->hop)),
441        GNUNET_sh2s (&cid->connection_of_tunnel));
442   env = GNUNET_MQ_msg_copy (msg);
443   GNUNET_MQ_env_set_options (env, priority);
444   if ((0 != (priority & GNUNET_MQ_PREF_LOW_LATENCY)) &&
445       (0 != (priority & GNUNET_MQ_PREF_OUT_OF_ORDER)) &&
446       (NULL != dir->env_head) &&
447       (0 == (GNUNET_MQ_env_get_options (dir->env_head)
448              & GNUNET_MQ_PREF_LOW_LATENCY)))
449     GNUNET_MQ_dll_insert_head (&dir->env_head, &dir->env_tail, env);
450   else
451     GNUNET_MQ_dll_insert_tail (&dir->env_head, &dir->env_tail, env);
452   cur_buffers++;
453   GNUNET_STATISTICS_set (stats, "# buffer use", cur_buffers, GNUNET_NO);
454   /* Clean up 'rung' if now empty (and not head) */
455   if ((NULL == rung->rd_head) && (rung != rung_head))
456   {
457     GNUNET_CONTAINER_DLL_remove (rung_head, rung_tail, rung);
458     GNUNET_free (rung);
459   }
460 }
461
462
463 /**
464  * Check if the create_connection message has the appropriate size.
465  *
466  * @param cls Closure (unused).
467  * @param msg Message to check.
468  *
469  * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
470  */
471 static int
472 check_connection_create (void *cls,
473                          const struct GNUNET_CADET_ConnectionCreateMessage *msg)
474 {
475   uint16_t size = ntohs (msg->header.size) - sizeof(*msg);
476
477   if (0 != (size % sizeof(struct GNUNET_PeerIdentity)))
478   {
479     GNUNET_break_op (0);
480     return GNUNET_NO;
481   }
482   return GNUNET_YES;
483 }
484
485
486 /**
487  * Free internal data of a route direction.
488  *
489  * @param dir direction to destroy (do NOT free memory of 'dir' itself)
490  */
491 static void
492 destroy_direction (struct RouteDirection *dir)
493 {
494   struct GNUNET_MQ_Envelope *env;
495
496   while (NULL != (env = dir->env_head))
497   {
498     GNUNET_STATISTICS_update (stats,
499                               "# messages dropped due to route destruction",
500                               1,
501                               GNUNET_NO);
502     discard_buffer (dir, env);
503   }
504   if (NULL != dir->mqm)
505   {
506     GCP_request_mq_cancel (dir->mqm, NULL);
507     dir->mqm = NULL;
508   }
509   GNUNET_CONTAINER_DLL_remove (rung_head->rd_head, rung_head->rd_tail, dir);
510 }
511
512
513 /**
514  * Destroy our state for @a route.
515  *
516  * @param route route to destroy
517  */
518 static void
519 destroy_route (struct CadetRoute *route)
520 {
521   LOG (GNUNET_ERROR_TYPE_DEBUG,
522        "Destroying route from %s to %s of connection %s\n",
523        GNUNET_i2s (GCP_get_id (route->prev.hop)),
524        GNUNET_i2s2 (GCP_get_id (route->next.hop)),
525        GNUNET_sh2s (&route->cid.connection_of_tunnel));
526   GNUNET_assert (route == GNUNET_CONTAINER_heap_remove_node (route->hn));
527   GNUNET_assert (
528     GNUNET_YES ==
529     GNUNET_CONTAINER_multishortmap_remove (routes,
530                                            &route->cid.connection_of_tunnel,
531                                            route));
532   GNUNET_STATISTICS_set (stats,
533                          "# routes",
534                          GNUNET_CONTAINER_multishortmap_size (routes),
535                          GNUNET_NO);
536   destroy_direction (&route->prev);
537   destroy_direction (&route->next);
538   GNUNET_free (route);
539 }
540
541
542 /**
543  * Send message that a route is broken between @a peer1 and @a peer2.
544  *
545  * @param target where to send the message
546  * @param cid connection identifier to use
547  * @param peer1 one of the peers where a link is broken
548  * @param peer2 another one of the peers where a link is broken
549  */
550 static void
551 send_broken (struct RouteDirection *target,
552              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
553              const struct GNUNET_PeerIdentity *peer1,
554              const struct GNUNET_PeerIdentity *peer2)
555 {
556   struct GNUNET_MQ_Envelope *env;
557   struct GNUNET_CADET_ConnectionBrokenMessage *bm;
558
559   if (NULL == target->mqm)
560     return; /* Can't send notification, connection is down! */
561   LOG (GNUNET_ERROR_TYPE_DEBUG,
562        "Notifying %s about BROKEN route at %s-%s of connection %s\n",
563        GCP_2s (target->hop),
564        GNUNET_i2s (peer1),
565        GNUNET_i2s2 (peer2),
566        GNUNET_sh2s (&cid->connection_of_tunnel));
567
568   env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
569   bm->cid = *cid;
570   if (NULL != peer1)
571     bm->peer1 = *peer1;
572   if (NULL != peer2)
573     bm->peer2 = *peer2;
574   GCP_request_mq_cancel (target->mqm, env);
575   target->mqm = NULL;
576 }
577
578
579 /**
580  * Function called to check if any routes have timed out, and if
581  * so, to clean them up.  Finally, schedules itself again at the
582  * earliest time where there might be more work.
583  *
584  * @param cls NULL
585  */
586 static void
587 timeout_cb (void *cls)
588 {
589   struct CadetRoute *r;
590   struct GNUNET_TIME_Relative linger;
591   struct GNUNET_TIME_Absolute exp;
592
593   timeout_task = NULL;
594   linger = GNUNET_TIME_relative_multiply (keepalive_period, 3);
595   while (NULL != (r = GNUNET_CONTAINER_heap_peek (route_heap)))
596   {
597     exp = GNUNET_TIME_absolute_add (r->last_use, linger);
598     if (0 != GNUNET_TIME_absolute_get_remaining (exp).rel_value_us)
599     {
600       /* Route not yet timed out, wait until it does. */
601       timeout_task = GNUNET_SCHEDULER_add_at (exp, &timeout_cb, NULL);
602       return;
603     }
604     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
605                 "Sending BROKEN due to timeout (%s was last use, %s linger)\n",
606                 GNUNET_STRINGS_absolute_time_to_string (r->last_use),
607                 GNUNET_STRINGS_relative_time_to_string (linger, GNUNET_YES));
608     send_broken (&r->prev, &r->cid, NULL, NULL);
609     send_broken (&r->next, &r->cid, NULL, NULL);
610     destroy_route (r);
611   }
612   /* No more routes left, so no need for a #timeout_task */
613 }
614
615
616 /**
617  * Function called when the message queue to the previous hop
618  * becomes available/unavailable.  We expect this function to
619  * be called immediately when we register, and then again
620  * later if the connection ever goes down.
621  *
622  * @param cls the `struct RouteDirection`
623  * @param available #GNUNET_YES if sending is now possible,
624  *                  #GNUNET_NO if sending is no longer possible
625  *                  #GNUNET_SYSERR if sending is no longer possible
626  *                                 and the last envelope was discarded
627  */
628 static void
629 dir_ready_cb (void *cls, int ready)
630 {
631   struct RouteDirection *dir = cls;
632   struct CadetRoute *route = dir->my_route;
633   struct RouteDirection *odir;
634
635   if (GNUNET_YES == ready)
636   {
637     struct GNUNET_MQ_Envelope *env;
638
639     dir->is_ready = GNUNET_YES;
640     if (NULL != (env = dir->env_head))
641     {
642       GNUNET_MQ_dll_remove (&dir->env_head, &dir->env_tail, env);
643       cur_buffers--;
644       GNUNET_STATISTICS_set (stats, "# buffer use", cur_buffers, GNUNET_NO);
645       lower_rung (dir);
646       dir->is_ready = GNUNET_NO;
647       GCP_send (dir->mqm, env);
648     }
649     return;
650   }
651   odir = (dir == &route->next) ? &route->prev : &route->next;
652   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending BROKEN due to MQ going down\n");
653   send_broken (&route->next, &route->cid, GCP_get_id (odir->hop), &my_full_id);
654   destroy_route (route);
655 }
656
657
658 /**
659  * Initialize one of the directions of a route.
660  *
661  * @param route route the direction belongs to
662  * @param dir direction to initialize
663  * @param hop next hop on in the @a dir
664  */
665 static void
666 dir_init (struct RouteDirection *dir,
667           struct CadetRoute *route,
668           struct CadetPeer *hop)
669 {
670   dir->hop = hop;
671   dir->my_route = route;
672   dir->mqm = GCP_request_mq (hop, &dir_ready_cb, dir);
673   GNUNET_CONTAINER_DLL_insert (rung_head->rd_head, rung_head->rd_tail, dir);
674   dir->rung = rung_head;
675   GNUNET_assert (GNUNET_YES == dir->is_ready);
676 }
677
678
679 /**
680  * We could not create the desired route.  Send a
681  * #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
682  * message to @a target.
683  *
684  * @param target who should receive the message
685  * @param cid identifier of the connection/route that failed
686  * @param failure_at neighbour with which we failed to route,
687  *        or NULL.
688  */
689 static void
690 send_broken_without_mqm (
691   struct CadetPeer *target,
692   const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
693   const struct GNUNET_PeerIdentity *failure_at)
694 {
695   struct GNUNET_MQ_Envelope *env;
696   struct GNUNET_CADET_ConnectionBrokenMessage *bm;
697
698   env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
699   bm->cid = *cid;
700   bm->peer1 = my_full_id;
701   if (NULL != failure_at)
702     bm->peer2 = *failure_at;
703   GCP_send_ooo (target, env);
704 }
705
706
707 /**
708  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
709  *
710  * @param cls Closure (CadetPeer for neighbor that sent the message).
711  * @param msg Message itself.
712  */
713 static void
714 handle_connection_create (
715   void *cls,
716   const struct GNUNET_CADET_ConnectionCreateMessage *msg)
717 {
718   struct CadetPeer *sender = cls;
719   struct CadetPeer *next;
720   const struct GNUNET_PeerIdentity *pids =
721     (const struct GNUNET_PeerIdentity *) &msg[1];
722   struct CadetRoute *route;
723   uint16_t size = ntohs (msg->header.size) - sizeof(*msg);
724   unsigned int path_length;
725   unsigned int off;
726   struct CadetTunnel *t;
727
728   path_length = size / sizeof(struct GNUNET_PeerIdentity);
729   if (0 == path_length)
730   {
731     LOG (GNUNET_ERROR_TYPE_DEBUG,
732          "Dropping CADET_CONNECTION_CREATE with empty path\n");
733     GNUNET_break_op (0);
734     return;
735   }
736   LOG (GNUNET_ERROR_TYPE_DEBUG,
737        "Handling CADET_CONNECTION_CREATE from %s for CID %s with %u hops\n",
738        GCP_2s (sender),
739        GNUNET_sh2s (&msg->cid.connection_of_tunnel),
740        path_length);
741   /* Check for loops */
742   {
743     struct GNUNET_CONTAINER_MultiPeerMap *map;
744
745     map = GNUNET_CONTAINER_multipeermap_create (path_length * 2, GNUNET_YES);
746     GNUNET_assert (NULL != map);
747     for (unsigned int i = 0; i < path_length; i++)
748     {
749       LOG (GNUNET_ERROR_TYPE_DEBUG,
750            "CADET_CONNECTION_CREATE has peer %s at offset %u\n",
751            GNUNET_i2s (&pids[i]),
752            i);
753       if (GNUNET_SYSERR == GNUNET_CONTAINER_multipeermap_put (
754             map,
755             &pids[i],
756             NULL,
757             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
758       {
759         /* bogus request */
760         GNUNET_CONTAINER_multipeermap_destroy (map);
761         LOG (GNUNET_ERROR_TYPE_DEBUG,
762              "Dropping CADET_CONNECTION_CREATE with cyclic path\n");
763         GNUNET_break_op (0);
764         return;
765       }
766     }
767     GNUNET_CONTAINER_multipeermap_destroy (map);
768   }
769   /* Initiator is at offset 0, find us */
770   for (off = 1; off < path_length; off++)
771     if (0 == GNUNET_memcmp (&my_full_id, &pids[off]))
772       break;
773   if (off == path_length)
774   {
775     LOG (GNUNET_ERROR_TYPE_DEBUG,
776          "Dropping CADET_CONNECTION_CREATE without us in the path\n");
777     GNUNET_break_op (0);
778     return;
779   }
780   /* Check previous hop */
781   if (sender != GCP_get (&pids[off - 1], GNUNET_NO))
782   {
783     LOG (GNUNET_ERROR_TYPE_DEBUG,
784          "Dropping CADET_CONNECTION_CREATE without sender at previous hop in the path\n");
785     GNUNET_break_op (0);
786     return;
787   }
788   if (NULL != (route = get_route (&msg->cid)))
789   {
790     /* Duplicate CREATE, pass it on, previous one might have been lost! */
791
792     LOG (GNUNET_ERROR_TYPE_DEBUG,
793          "Passing on duplicate CADET_CONNECTION_CREATE message on connection %s\n",
794          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
795     route_message (sender,
796                    &msg->cid,
797                    &msg->header,
798                    GNUNET_MQ_PRIO_CRITICAL_CONTROL
799                    | GNUNET_MQ_PREF_LOW_LATENCY);
800     return;
801   }
802   if (off == path_length - 1)
803   {
804     /* We are the destination, create connection */
805     struct CadetConnection *cc;
806     struct CadetPeerPath *path;
807     struct CadetPeer *origin;
808
809     cc = GCC_lookup (&msg->cid);
810     if (NULL != cc)
811     {
812       LOG (GNUNET_ERROR_TYPE_DEBUG,
813            "Received duplicate CADET_CONNECTION_CREATE message on connection %s\n",
814            GNUNET_sh2s (&msg->cid.connection_of_tunnel));
815       GCC_handle_duplicate_create (cc);
816       return;
817     }
818
819     origin = GCP_get (&pids[0], GNUNET_YES);
820     LOG (GNUNET_ERROR_TYPE_DEBUG,
821          "I am destination for CADET_CONNECTION_CREATE message from %s for connection %s, building inverse path\n",
822          GCP_2s (origin),
823          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
824     path = GCPP_get_path_from_route (path_length - 1, pids);
825     t = GCP_get_tunnel (sender, GNUNET_YES);
826
827     // Check for CADET state in case the other side has lost the tunnel (xrs,t3ss)
828     if ((GNUNET_YES == msg->has_monotime) &&
829         (GNUNET_YES == GCP_check_and_update_monotime(origin, msg->monotime)) &&
830         ( GNUNET_OK == GCP_check_monotime_sig(origin, msg)) &&
831          (CADET_TUNNEL_KEY_OK == GCT_get_estate(t)))
832     {
833       GCT_change_estate (t, CADET_TUNNEL_KEY_UNINITIALIZED);
834     }
835
836     if (GNUNET_OK !=
837         GCT_add_inbound_connection (t,
838                                     &msg->cid,
839                                     path))
840     {
841       /* Send back BROKEN: duplicate connection on the same path,
842          we will use the other one. */
843       LOG (GNUNET_ERROR_TYPE_DEBUG,
844            "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n",
845            GCP_2s (sender),
846            GNUNET_sh2s (&msg->cid.connection_of_tunnel),
847            GCPP_2s (path));
848       send_broken_without_mqm (sender, &msg->cid, NULL);
849       return;
850     }
851     return;
852   }
853   /* We are merely a hop on the way, check if we can support the route */
854   next = GCP_get (&pids[off + 1], GNUNET_NO);
855   if ((NULL == next) || (GNUNET_NO == GCP_has_core_connection (next)))
856   {
857     /* unworkable, send back BROKEN notification */
858     LOG (GNUNET_ERROR_TYPE_DEBUG,
859          "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n",
860          GCP_2s (sender),
861          GNUNET_sh2s (&msg->cid.connection_of_tunnel),
862          GNUNET_i2s (&pids[off + 1]),
863          off + 1);
864     send_broken_without_mqm (sender, &msg->cid, &pids[off + 1]);
865     return;
866   }
867   if (max_routes <= GNUNET_CONTAINER_multishortmap_size (routes))
868   {
869     LOG (GNUNET_ERROR_TYPE_DEBUG,
870          "Received CADET_CONNECTION_CREATE from %s for %s. We have reached our route limit. Sending BROKEN\n",
871          GCP_2s (sender),
872          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
873     send_broken_without_mqm (sender, &msg->cid, &pids[off - 1]);
874     return;
875   }
876
877   /* Workable route, create routing entry */
878   LOG (GNUNET_ERROR_TYPE_DEBUG,
879        "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is up. Creating route\n",
880        GCP_2s (sender),
881        GNUNET_sh2s (&msg->cid.connection_of_tunnel),
882        GNUNET_i2s (&pids[off + 1]),
883        off + 1);
884   route = GNUNET_new (struct CadetRoute);
885   route->cid = msg->cid;
886   route->last_use = GNUNET_TIME_absolute_get ();
887   dir_init (&route->prev, route, sender);
888   dir_init (&route->next, route, next);
889   GNUNET_assert (GNUNET_OK ==
890                  GNUNET_CONTAINER_multishortmap_put (
891                    routes,
892                    &route->cid.connection_of_tunnel,
893                    route,
894                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
895   GNUNET_STATISTICS_set (stats,
896                          "# routes",
897                          GNUNET_CONTAINER_multishortmap_size (routes),
898                          GNUNET_NO);
899   route->hn = GNUNET_CONTAINER_heap_insert (route_heap,
900                                             route,
901                                             route->last_use.abs_value_us);
902   if (NULL == timeout_task)
903     timeout_task =
904       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
905                                       keepalive_period,
906                                       3),
907                                     &timeout_cb,
908                                     NULL);
909   /* also pass CREATE message along to next hop */
910   route_message (sender,
911                  &msg->cid,
912                  &msg->header,
913                  GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY);
914 }
915
916
917 /**
918  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
919  *
920  * @param cls Closure (CadetPeer for neighbor that sent the message).
921  * @param msg Message itself.
922  */
923 static void
924 handle_connection_create_ack (
925   void *cls,
926   const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
927 {
928   struct CadetPeer *peer = cls;
929   struct CadetConnection *cc;
930
931   /* First, check if ACK belongs to a connection that ends here. */
932   cc = GCC_lookup (&msg->cid);
933   if (NULL != cc)
934   {
935     /* verify ACK came from the right direction */
936     unsigned int len;
937     struct CadetPeerPath *path = GCC_get_path (cc, &len);
938
939     if (peer != GCPP_get_peer_at_offset (path, 0))
940     {
941       /* received ACK from unexpected direction, ignore! */
942       GNUNET_break_op (0);
943       return;
944     }
945     LOG (GNUNET_ERROR_TYPE_DEBUG,
946          "Received CONNECTION_CREATE_ACK for connection %s.\n",
947          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
948     GCC_handle_connection_create_ack (cc);
949     return;
950   }
951
952   /* We're just an intermediary peer, route the message along its path */
953   route_message (peer,
954                  &msg->cid,
955                  &msg->header,
956                  GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY);
957 }
958
959
960 /**
961  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
962  *
963  * @param cls Closure (CadetPeer for neighbor that sent the message).
964  * @param msg Message itself.
965  * @deprecated duplicate logic with #handle_destroy(); dedup!
966  */
967 static void
968 handle_connection_broken (
969   void *cls,
970   const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
971 {
972   struct CadetPeer *peer = cls;
973   struct CadetConnection *cc;
974   struct CadetRoute *route;
975
976   /* First, check if message belongs to a connection that ends here. */
977   cc = GCC_lookup (&msg->cid);
978   if (NULL != cc)
979   {
980     /* verify message came from the right direction */
981     unsigned int len;
982     struct CadetPeerPath *path = GCC_get_path (cc, &len);
983
984     if (peer != GCPP_get_peer_at_offset (path, 0))
985     {
986       /* received message from unexpected direction, ignore! */
987       GNUNET_break_op (0);
988       return;
989     }
990     LOG (GNUNET_ERROR_TYPE_DEBUG,
991          "Received CONNECTION_BROKEN for connection %s. Destroying it.\n",
992          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
993     GCC_destroy_without_core (cc);
994
995     /* FIXME: also destroy the path up to the specified link! */
996     return;
997   }
998
999   /* We're just an intermediary peer, route the message along its path */
1000   route_message (peer,
1001                  &msg->cid,
1002                  &msg->header,
1003                  GNUNET_MQ_PREF_LOW_LATENCY | GNUNET_MQ_PRIO_CRITICAL_CONTROL);
1004   route = get_route (&msg->cid);
1005   if (NULL != route)
1006     destroy_route (route);
1007   /* FIXME: also destroy paths we MAY have up to the specified link! */
1008 }
1009
1010
1011 /**
1012  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
1013  *
1014  * @param cls Closure (CadetPeer for neighbor that sent the message).
1015  * @param msg Message itself.
1016  */
1017 static void
1018 handle_connection_destroy (
1019   void *cls,
1020   const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
1021 {
1022   struct CadetPeer *peer = cls;
1023   struct CadetConnection *cc;
1024   struct CadetRoute *route;
1025
1026   /* First, check if message belongs to a connection that ends here. */
1027   cc = GCC_lookup (&msg->cid);
1028   if (NULL != cc)
1029   {
1030     /* verify message came from the right direction */
1031     unsigned int len;
1032     struct CadetPeerPath *path = GCC_get_path (cc, &len);
1033
1034     if (peer != GCPP_get_peer_at_offset (path, 0))
1035     {
1036       /* received message from unexpected direction, ignore! */
1037       GNUNET_break_op (0);
1038       return;
1039     }
1040     LOG (GNUNET_ERROR_TYPE_DEBUG,
1041          "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n",
1042          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
1043
1044     GCC_destroy_without_core (cc);
1045     return;
1046   }
1047
1048   /* We're just an intermediary peer, route the message along its path */
1049   LOG (GNUNET_ERROR_TYPE_DEBUG,
1050        "Received CONNECTION_DESTROY for connection %s. Destroying route.\n",
1051        GNUNET_sh2s (&msg->cid.connection_of_tunnel));
1052   route_message (peer,
1053                  &msg->cid,
1054                  &msg->header,
1055                  GNUNET_MQ_PREF_LOW_LATENCY | GNUNET_MQ_PRIO_CRITICAL_CONTROL);
1056   route = get_route (&msg->cid);
1057   if (NULL != route)
1058     destroy_route (route);
1059 }
1060
1061
1062 /**
1063  * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
1064  *
1065  * @param cls Closure (CadetPeer for neighbor that sent the message).
1066  * @param msg Message itself.
1067  */
1068 static void
1069 handle_tunnel_kx (void *cls,
1070                   const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
1071 {
1072   struct CadetPeer *peer = cls;
1073   struct CadetConnection *cc;
1074
1075   /* First, check if message belongs to a connection that ends here. */
1076   LOG (GNUNET_ERROR_TYPE_DEBUG,
1077        "Routing KX with ephemeral %s on CID %s\n",
1078        GNUNET_e2s (&msg->ephemeral_key),
1079        GNUNET_sh2s (&msg->cid.connection_of_tunnel));
1080
1081
1082   cc = GCC_lookup (&msg->cid);
1083   if (NULL != cc)
1084   {
1085     /* verify message came from the right direction */
1086     unsigned int len;
1087     struct CadetPeerPath *path = GCC_get_path (cc, &len);
1088
1089     if (peer != GCPP_get_peer_at_offset (path, 0))
1090     {
1091       /* received message from unexpected direction, ignore! */
1092       GNUNET_break_op (0);
1093       return;
1094     }
1095     GCC_handle_kx (cc, msg);
1096     return;
1097   }
1098
1099   /* We're just an intermediary peer, route the message along its path */
1100   route_message (peer,
1101                  &msg->cid,
1102                  &msg->header,
1103                  GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY);
1104 }
1105
1106
1107 /**
1108  * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH
1109  *
1110  * @param cls Closure (CadetPeer for neighbor that sent the message).
1111  * @param msg Message itself.
1112  */
1113 static void
1114 handle_tunnel_kx_auth (
1115   void *cls,
1116   const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
1117 {
1118   struct CadetPeer *peer = cls;
1119   struct CadetConnection *cc;
1120
1121   /* First, check if message belongs to a connection that ends here. */
1122   cc = GCC_lookup (&msg->kx.cid);
1123   if (NULL != cc)
1124   {
1125     /* verify message came from the right direction */
1126     unsigned int len;
1127     struct CadetPeerPath *path = GCC_get_path (cc, &len);
1128
1129     if (peer != GCPP_get_peer_at_offset (path, 0))
1130     {
1131       /* received message from unexpected direction, ignore! */
1132       GNUNET_break_op (0);
1133       return;
1134     }
1135     GCC_handle_kx_auth (cc, msg);
1136     return;
1137   }
1138
1139   /* We're just an intermediary peer, route the message along its path */
1140   route_message (peer,
1141                  &msg->kx.cid,
1142                  &msg->kx.header,
1143                  GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY);
1144 }
1145
1146
1147 /**
1148  * Check if the encrypted message has the appropriate size.
1149  *
1150  * @param cls Closure (unused).
1151  * @param msg Message to check.
1152  *
1153  * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
1154  */
1155 static int
1156 check_tunnel_encrypted (void *cls,
1157                         const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
1158 {
1159   return GNUNET_YES;
1160 }
1161
1162
1163 /**
1164  * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
1165  *
1166  * @param cls Closure (CadetPeer for neighbor that sent the message).
1167  * @param msg Message itself.
1168  */
1169 static void
1170 handle_tunnel_encrypted (void *cls,
1171                          const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
1172 {
1173   struct CadetPeer *peer = cls;
1174   struct CadetConnection *cc;
1175
1176   /* First, check if message belongs to a connection that ends here. */
1177   cc = GCC_lookup (&msg->cid);
1178   if (NULL != cc)
1179   {
1180     /* verify message came from the right direction */
1181     unsigned int len;
1182     struct CadetPeerPath *path = GCC_get_path (cc, &len);
1183
1184     if (peer != GCPP_get_peer_at_offset (path, 0))
1185     {
1186       /* received message from unexpected direction, ignore! */
1187       GNUNET_break_op (0);
1188       return;
1189     }
1190     GCC_handle_encrypted (cc, msg);
1191     return;
1192   }
1193   /* We're just an intermediary peer, route the message along its path */
1194   route_message (peer, &msg->cid, &msg->header, GNUNET_MQ_PRIO_BEST_EFFORT);
1195 }
1196
1197
1198 /**
1199  * Function called after #GNUNET_CORE_connect has succeeded (or failed
1200  * for good).  Note that the private key of the peer is intentionally
1201  * not exposed here; if you need it, your process should try to read
1202  * the private key file directly (which should work if you are
1203  * authorized...).  Implementations of this function must not call
1204  * #GNUNET_CORE_disconnect (other than by scheduling a new task to
1205  * do this later).
1206  *
1207  * @param cls closure
1208  * @param my_identity ID of this peer, NULL if we failed
1209  */
1210 static void
1211 core_init_cb (void *cls, const struct GNUNET_PeerIdentity *my_identity)
1212 {
1213   if (NULL == my_identity)
1214   {
1215     GNUNET_break (0);
1216     return;
1217   }
1218   GNUNET_break (0 == GNUNET_memcmp (my_identity, &my_full_id));
1219 }
1220
1221
1222 /**
1223  * Method called whenever a given peer connects.
1224  *
1225  * @param cls closure
1226  * @param peer peer identity this notification is about
1227  */
1228 static void *
1229 core_connect_cb (void *cls,
1230                  const struct GNUNET_PeerIdentity *peer,
1231                  struct GNUNET_MQ_Handle *mq)
1232 {
1233   struct CadetPeer *cp;
1234
1235   LOG (GNUNET_ERROR_TYPE_DEBUG,
1236        "CORE connection to peer %s was established.\n",
1237        GNUNET_i2s (peer));
1238   cp = GCP_get (peer, GNUNET_YES);
1239   GCP_set_mq (cp, mq);
1240   return cp;
1241 }
1242
1243
1244 /**
1245  * Method called whenever a peer disconnects.
1246  *
1247  * @param cls closure
1248  * @param peer peer identity this notification is about
1249  */
1250 static void
1251 core_disconnect_cb (void *cls,
1252                     const struct GNUNET_PeerIdentity *peer,
1253                     void *peer_cls)
1254 {
1255   struct CadetPeer *cp = peer_cls;
1256
1257   LOG (GNUNET_ERROR_TYPE_DEBUG,
1258        "CORE connection to peer %s went down.\n",
1259        GNUNET_i2s (peer));
1260   GCP_set_mq (cp, NULL);
1261 }
1262
1263
1264 /**
1265  * Initialize the CORE subsystem.
1266  *
1267  * @param c Configuration.
1268  */
1269 void
1270 GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
1271 {
1272   struct GNUNET_MQ_MessageHandler handlers[] =
1273   { GNUNET_MQ_hd_var_size (connection_create,
1274                            GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
1275                            struct GNUNET_CADET_ConnectionCreateMessage,
1276                            NULL),
1277     GNUNET_MQ_hd_fixed_size (connection_create_ack,
1278                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
1279                              struct GNUNET_CADET_ConnectionCreateAckMessage,
1280                              NULL),
1281     GNUNET_MQ_hd_fixed_size (connection_broken,
1282                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
1283                              struct GNUNET_CADET_ConnectionBrokenMessage,
1284                              NULL),
1285     GNUNET_MQ_hd_fixed_size (connection_destroy,
1286                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
1287                              struct GNUNET_CADET_ConnectionDestroyMessage,
1288                              NULL),
1289     GNUNET_MQ_hd_fixed_size (tunnel_kx,
1290                              GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
1291                              struct GNUNET_CADET_TunnelKeyExchangeMessage,
1292                              NULL),
1293     GNUNET_MQ_hd_fixed_size (tunnel_kx_auth,
1294                              GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH,
1295                              struct GNUNET_CADET_TunnelKeyExchangeAuthMessage,
1296                              NULL),
1297     GNUNET_MQ_hd_var_size (tunnel_encrypted,
1298                            GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
1299                            struct GNUNET_CADET_TunnelEncryptedMessage,
1300                            NULL),
1301     GNUNET_MQ_handler_end () };
1302
1303   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c,
1304                                                           "CADET",
1305                                                           "MAX_ROUTES",
1306                                                           &max_routes))
1307     max_routes = 5000;
1308   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c,
1309                                                           "CADET",
1310                                                           "MAX_MSGS_QUEUE",
1311                                                           &max_buffers))
1312     max_buffers = 10000;
1313   routes = GNUNET_CONTAINER_multishortmap_create (1024, GNUNET_NO);
1314   route_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1315   core = GNUNET_CORE_connect (c,
1316                               NULL,
1317                               &core_init_cb,
1318                               &core_connect_cb,
1319                               &core_disconnect_cb,
1320                               handlers);
1321 }
1322
1323
1324 /**
1325  * Shut down the CORE subsystem.
1326  */
1327 void
1328 GCO_shutdown ()
1329 {
1330   if (NULL != core)
1331   {
1332     GNUNET_CORE_disconnect (core);
1333     core = NULL;
1334   }
1335   GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
1336   GNUNET_CONTAINER_multishortmap_destroy (routes);
1337   routes = NULL;
1338   GNUNET_CONTAINER_heap_destroy (route_heap);
1339   route_heap = NULL;
1340   if (NULL != timeout_task)
1341   {
1342     GNUNET_SCHEDULER_cancel (timeout_task);
1343     timeout_task = NULL;
1344   }
1345 }
1346
1347
1348 /* end of gnunet-cadet-service_core.c */