aboutsummaryrefslogtreecommitdiff
path: root/src/cadet/gnunet-service-cadet_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cadet/gnunet-service-cadet_core.c')
-rw-r--r--src/cadet/gnunet-service-cadet_core.c1348
1 files changed, 0 insertions, 1348 deletions
diff --git a/src/cadet/gnunet-service-cadet_core.c b/src/cadet/gnunet-service-cadet_core.c
deleted file mode 100644
index 95a5d3f63..000000000
--- a/src/cadet/gnunet-service-cadet_core.c
+++ /dev/null
@@ -1,1348 +0,0 @@
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 */
47struct 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 */
55struct 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 */
93struct 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 */
150struct 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 */
182static struct GNUNET_CORE_Handle *core;
183
184/**
185 * Routes on which this peer is an intermediate.
186 */
187static struct GNUNET_CONTAINER_MultiShortmap *routes;
188
189/**
190 * Heap of routes, MIN-sorted by last activity.
191 */
192static struct GNUNET_CONTAINER_Heap *route_heap;
193
194/**
195 * Rung zero (always pointed to by #rung_head).
196 */
197static 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 */
203static struct Rung *rung_head = &rung_zero;
204
205/**
206 * Tail of the #rung_head DLL.
207 */
208static struct Rung *rung_tail = &rung_zero;
209
210/**
211 * Maximum number of concurrent routes this peer will support.
212 */
213static unsigned long long max_routes;
214
215/**
216 * Maximum number of envelopes we will buffer at this peer.
217 */
218static unsigned long long max_buffers;
219
220/**
221 * Current number of envelopes we have buffered at this peer.
222 */
223static unsigned long long cur_buffers;
224
225/**
226 * Task to timeout routes.
227 */
228static 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 */
235static struct CadetRoute *
236get_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 */
248static void
249lower_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 */
276static void
277discard_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 */
290static void
291discard_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 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 */
321static void
322route_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 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 */
471static int
472check_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 */
491static void
492destroy_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 */
518static void
519destroy_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 */
550static void
551send_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 */
586static void
587timeout_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 */
628static void
629dir_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 */
665static void
666dir_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 */
689static void
690send_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 */
713static void
714handle_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 (origin, 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 */
923static void
924handle_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 */
967static void
968handle_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 */
1017static void
1018handle_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 */
1068static void
1069handle_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 */
1113static void
1114handle_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 */
1155static int
1156check_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 */
1169static void
1170handle_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 */
1210static void
1211core_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 */
1228static void *
1229core_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 */
1250static void
1251core_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 */
1269void
1270GCO_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 */
1327void
1328GCO_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 */