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