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