Fix use-after-free in loop over modified list
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_peer.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001-2017 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file cadet/gnunet-service-cadet_peer.c
23  * @brief Information we track per peer.
24  * @author Bartlomiej Polot
25  * @author Christian Grothoff
26  *
27  * TODO:
28  * - optimize stopping/restarting DHT search to situations
29  *   where we actually need it (i.e. not if we have a direct connection,
30  *   or if we already have plenty of good short ones, or maybe even
31  *   to take a break if we have some connections and have searched a lot (?))
32  */
33 #include "platform.h"
34 #include "gnunet_util_lib.h"
35 #include "gnunet_hello_lib.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_transport_service.h"
38 #include "gnunet_ats_service.h"
39 #include "gnunet_core_service.h"
40 #include "gnunet_statistics_service.h"
41 #include "cadet_protocol.h"
42 #include "gnunet-service-cadet_connection.h"
43 #include "gnunet-service-cadet_dht.h"
44 #include "gnunet-service-cadet_peer.h"
45 #include "gnunet-service-cadet_paths.h"
46 #include "gnunet-service-cadet_tunnels.h"
47
48
49 #define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
50
51
52 /**
53  * How long do we wait until tearing down an idle peer?
54  */
55 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
56
57 /**
58  * How long do we keep paths around if we no longer care about the peer?
59  */
60 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
61
62
63
64
65 /**
66  * Data structure used to track whom we have to notify about changes
67  * to our message queue.
68  */
69 struct GCP_MessageQueueManager
70 {
71
72   /**
73    * Kept in a DLL.
74    */
75   struct GCP_MessageQueueManager *next;
76
77   /**
78    * Kept in a DLL.
79    */
80   struct GCP_MessageQueueManager *prev;
81
82   /**
83    * Function to call with updated message queue object.
84    */
85   GCP_MessageQueueNotificationCallback cb;
86
87   /**
88    * Closure for @e cb.
89    */
90   void *cb_cls;
91
92   /**
93    * The peer this is for.
94    */
95   struct CadetPeer *cp;
96
97   /**
98    * Envelope this manager would like to transmit once it is its turn.
99    */
100   struct GNUNET_MQ_Envelope *env;
101
102 };
103
104
105 /**
106  * Struct containing all information regarding a given peer
107  */
108 struct CadetPeer
109 {
110   /**
111    * ID of the peer
112    */
113   struct GNUNET_PeerIdentity pid;
114
115   /**
116    * Last time we heard from this peer (currently not used!)
117    */
118   struct GNUNET_TIME_Absolute last_contactXXX;
119
120   /**
121    * Array of DLLs of paths traversing the peer, organized by the
122    * offset of the peer on the larger path.
123    */
124   struct CadetPeerPathEntry **path_heads;
125
126   /**
127    * Array of DLL of paths traversing the peer, organized by the
128    * offset of the peer on the larger path.
129    */
130   struct CadetPeerPathEntry **path_tails;
131
132   /**
133    * Notifications to call when @e core_mq changes.
134    */
135   struct GCP_MessageQueueManager *mqm_head;
136
137   /**
138    * Notifications to call when @e core_mq changes.
139    */
140   struct GCP_MessageQueueManager *mqm_tail;
141
142   /**
143    * Pointer to first "ready" entry in @e mqm_head.
144    */
145   struct GCP_MessageQueueManager *mqm_ready_ptr;
146
147   /**
148    * MIN-heap of paths owned by this peer (they also end at this
149    * peer).  Ordered by desirability.
150    */
151   struct GNUNET_CONTAINER_Heap *path_heap;
152
153   /**
154    * Handle to stop the DHT search for paths to this peer
155    */
156   struct GCD_search_handle *search_h;
157
158   /**
159    * Task to clean up @e path_heap asynchronously.
160    */
161   struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
162
163   /**
164    * Task to destroy this entry.
165    */
166   struct GNUNET_SCHEDULER_Task *destroy_task;
167
168   /**
169    * Tunnel to this peer, if any.
170    */
171   struct CadetTunnel *t;
172
173   /**
174    * Connections that go through this peer; indexed by tid.
175    */
176   struct GNUNET_CONTAINER_MultiShortmap *connections;
177
178   /**
179    * Handle for core transmissions.
180    */
181   struct GNUNET_MQ_Handle *core_mq;
182
183   /**
184    * Hello message of the peer.
185    */
186   struct GNUNET_HELLO_Message *hello;
187
188   /**
189    * Handle to us offering the HELLO to the transport.
190    */
191   struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
192
193   /**
194    * Handle to our ATS request asking ATS to suggest an address
195    * to TRANSPORT for this peer (to establish a direct link).
196    */
197   struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
198
199   /**
200    * How many messages are in the queue to this peer.
201    */
202   unsigned int queue_n;
203
204   /**
205    * How many paths do we have to this peer (in all @e path_heads DLLs combined).
206    */
207   unsigned int num_paths;
208
209   /**
210    * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
211    * Used to speed-up @GCP_get_desirability_of_path() calculation.
212    */
213   unsigned int off_sum;
214
215   /**
216    * Number of message queue managers of this peer that have a message in waiting.
217    *
218    * Used to quickly see if we need to bother scanning the @e msm_head DLL.
219    * TODO: could be replaced by another DLL that would then allow us to avoid
220    * the O(n)-scan of the DLL for ready entries!
221    */
222   unsigned int mqm_ready_counter;
223
224   /**
225    * Current length of the @e path_heads and @path_tails arrays.
226    * The arrays should be grown as needed.
227    */
228   unsigned int path_dll_length;
229
230 };
231
232
233 /**
234  * Get the static string for a peer ID.
235  *
236  * @param cp Peer.
237  * @return Static string for it's ID.
238  */
239 const char *
240 GCP_2s (const struct CadetPeer *cp)
241 {
242   static char buf[32];
243
244   GNUNET_snprintf (buf,
245                    sizeof (buf),
246                    "P(%s)",
247                    GNUNET_i2s (&cp->pid));
248   return buf;
249 }
250
251
252 /**
253  * Calculate how desirable a path is for @a cp if @a cp
254  * is at offset @a off.
255  *
256  * The 'desirability_table.c' program can be used to compute a list of
257  * sample outputs for different scenarios.  Basically, we score paths
258  * lower if there are many alternatives, and higher if they are
259  * shorter than average, and very high if they are much shorter than
260  * average and without many alternatives.
261  *
262  * @param cp a peer reachable via a path
263  * @param off offset of @a cp in the path
264  * @return score how useful a path is to reach @a cp,
265  *         positive scores mean path is more desirable
266  */
267 double
268 GCP_get_desirability_of_path (struct CadetPeer *cp,
269                               unsigned int off)
270 {
271   unsigned int num_alts = cp->num_paths;
272   unsigned int off_sum;
273   double avg_sum;
274   double path_delta;
275   double weight_alts;
276
277   GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
278   GNUNET_assert (0 != cp->path_dll_length);
279
280   /* We maintain 'off_sum' in 'peer' and thereby
281      avoid the SLOW recalculation each time. Kept here
282      just to document what is going on. */
283 #if SLOW
284   off_sum = 0;
285   for (unsigned int j=0;j<cp->path_dll_length;j++)
286     for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
287          NULL != pe;
288          pe = pe->next)
289       off_sum += j;
290   GNUNET_assert (off_sum == cp->off_sum);
291 #else
292   off_sum = cp->off_sum;
293 #endif
294   avg_sum = off_sum * 1.0 / cp->path_dll_length;
295   path_delta = off - avg_sum;
296   /* path_delta positiv: path off of peer above average (bad path for peer),
297      path_delta negativ: path off of peer below average (good path for peer) */
298   if (path_delta <= - 1.0)
299     weight_alts = - num_alts / path_delta; /* discount alternative paths */
300   else if (path_delta >= 1.0)
301     weight_alts = num_alts * path_delta; /* overcount alternative paths */
302   else
303     weight_alts = num_alts; /* count alternative paths normally */
304
305
306   /* off+1: long paths are generally harder to find and thus count
307      a bit more as they get longer.  However, above-average paths
308      still need to count less, hence the squaring of that factor. */
309   return (off + 1.0) / (weight_alts * weight_alts);
310 }
311
312
313 /**
314  * This peer is no longer be needed, clean it up now.
315  *
316  * @param cls peer to clean up
317  */
318 static void
319 destroy_peer (void *cls)
320 {
321   struct CadetPeer *cp = cls;
322
323   LOG (GNUNET_ERROR_TYPE_DEBUG,
324        "Destroying state about peer %s\n",
325        GCP_2s (cp));
326   cp->destroy_task = NULL;
327   GNUNET_assert (NULL == cp->t);
328   GNUNET_assert (NULL == cp->core_mq);
329   GNUNET_assert (0 == cp->num_paths);
330   for (unsigned int i=0;i<cp->path_dll_length;i++)
331     GNUNET_assert (NULL == cp->path_heads[i]);
332   GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
333   GNUNET_assert (GNUNET_YES ==
334                  GNUNET_CONTAINER_multipeermap_remove (peers,
335                                                        &cp->pid,
336                                                        cp));
337   GNUNET_free_non_null (cp->path_heads);
338   GNUNET_free_non_null (cp->path_tails);
339   cp->path_dll_length = 0;
340   if (NULL != cp->search_h)
341   {
342     GCD_search_stop (cp->search_h);
343     cp->search_h = NULL;
344   }
345   /* FIXME: clean up search_delayedXXX! */
346
347   if (NULL != cp->hello_offer)
348   {
349     GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
350     cp->hello_offer = NULL;
351   }
352   if (NULL != cp->connectivity_suggestion)
353   {
354     GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
355     cp->connectivity_suggestion = NULL;
356   }
357   GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
358   if (NULL != cp->path_heap)
359   {
360     GNUNET_CONTAINER_heap_destroy (cp->path_heap);
361     cp->path_heap = NULL;
362   }
363   if (NULL != cp->heap_cleanup_task)
364   {
365     GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
366     cp->heap_cleanup_task = NULL;
367   }
368   GNUNET_free_non_null (cp->hello);
369   /* Peer should not be freed if paths exist; if there are no paths,
370      there ought to be no connections, and without connections, no
371      notifications. Thus we can assert that mqm_head is empty at this
372      point. */
373   GNUNET_assert (NULL == cp->mqm_head);
374   GNUNET_assert (NULL == cp->mqm_ready_ptr);
375   GNUNET_free (cp);
376 }
377
378
379 /**
380  * This peer is now on more "active" duty, activate processes related to it.
381  *
382  * @param cp the more-active peer
383  */
384 static void
385 consider_peer_activate (struct CadetPeer *cp)
386 {
387   uint32_t strength;
388
389   LOG (GNUNET_ERROR_TYPE_DEBUG,
390        "Updating peer %s activation state (%u connections)%s%s\n",
391        GCP_2s (cp),
392        GNUNET_CONTAINER_multishortmap_size (cp->connections),
393        (NULL == cp->t) ? "" : " with tunnel",
394        (NULL == cp->core_mq) ? "" : " with CORE link");
395   if (NULL != cp->destroy_task)
396   {
397     /* It's active, do not destory! */
398     GNUNET_SCHEDULER_cancel (cp->destroy_task);
399     cp->destroy_task = NULL;
400   }
401   if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
402        (NULL == cp->t) )
403   {
404     /* We're just on a path or directly connected; don't bother too much */
405     if (NULL != cp->connectivity_suggestion)
406     {
407       GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
408       cp->connectivity_suggestion = NULL;
409     }
410     if (NULL != cp->search_h)
411     {
412       GCD_search_stop (cp->search_h);
413       cp->search_h = NULL;
414     }
415     return;
416   }
417   if (NULL == cp->core_mq)
418   {
419     /* Lacks direct connection, try to create one by querying the DHT */
420     if ( (NULL == cp->search_h) &&
421          (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
422       cp->search_h
423         = GCD_search (&cp->pid);
424   }
425   else
426   {
427     /* Have direct connection, stop DHT search if active */
428     if (NULL != cp->search_h)
429     {
430       GCD_search_stop (cp->search_h);
431       cp->search_h = NULL;
432     }
433   }
434
435   /* If we have a tunnel, our urge for connections is much bigger */
436   strength = (NULL != cp->t) ? 32 : 1;
437   if (NULL != cp->connectivity_suggestion)
438     GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
439   cp->connectivity_suggestion
440     = GNUNET_ATS_connectivity_suggest (ats_ch,
441                                        &cp->pid,
442                                        strength);
443 }
444
445
446 /**
447  * This peer may no longer be needed, consider cleaning it up.
448  *
449  * @param cp peer to clean up
450  */
451 static void
452 consider_peer_destroy (struct CadetPeer *cp);
453
454
455 /**
456  * We really no longere care about a peer, stop hogging memory with paths to it.
457  * Afterwards, see if there is more to be cleaned up about this peer.
458  *
459  * @param cls a `struct CadetPeer`.
460  */
461 static void
462 drop_paths (void *cls)
463 {
464   struct CadetPeer *cp = cls;
465   struct CadetPeerPath *path;
466
467   cp->destroy_task = NULL;
468   while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
469     GCPP_release (path);
470   consider_peer_destroy (cp);
471 }
472
473
474 /**
475  * This peer may no longer be needed, consider cleaning it up.
476  *
477  * @param cp peer to clean up
478  */
479 static void
480 consider_peer_destroy (struct CadetPeer *cp)
481 {
482   struct GNUNET_TIME_Relative exp;
483
484   if (NULL != cp->destroy_task)
485   {
486     GNUNET_SCHEDULER_cancel (cp->destroy_task);
487     cp->destroy_task = NULL;
488   }
489   if (NULL != cp->t)
490     return; /* still relevant! */
491   if (NULL != cp->core_mq)
492     return; /* still relevant! */
493   if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
494     return; /* still relevant! */
495   if ( (NULL != cp->path_heap) &&
496        (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
497   {
498     cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
499                                                      &drop_paths,
500                                                      cp);
501     return;
502   }
503   if (0 != cp->num_paths)
504     return; /* still relevant! */
505   if (NULL != cp->hello)
506   {
507     /* relevant only until HELLO expires */
508     exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
509     cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
510                                                      &destroy_peer,
511                                                      cp);
512     return;
513   }
514   cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
515                                                    &destroy_peer,
516                                                    cp);
517 }
518
519
520 /**
521  * Set the message queue to @a mq for peer @a cp and notify watchers.
522  *
523  * @param cp peer to modify
524  * @param mq message queue to set (can be NULL)
525  */
526 void
527 GCP_set_mq (struct CadetPeer *cp,
528             struct GNUNET_MQ_Handle *mq)
529 {
530   LOG (GNUNET_ERROR_TYPE_DEBUG,
531        "Message queue for peer %s is now %p\n",
532        GCP_2s (cp),
533        mq);
534   cp->core_mq = mq;
535   /* Since these callbacks can remove any items from this list, we must take a
536    * snapshot and then test each one to see if it's still in the list. */
537   int count = 0;
538   for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
539        NULL != mqm;
540        mqm = mqm->next)
541     ++count;
542   struct GCP_MessageQueueManager *mqms[count];
543   int i = 0;
544   for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
545        NULL != mqm;
546        mqm = mqm->next)
547     mqms[i++] = mqm;
548   for (i = 0; i < count; ++i)
549   {
550     for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
551          NULL != mqm;
552          mqm = mqm->next)
553     {
554       if (mqms[i] != mqm)
555         continue;
556       if (NULL == mq)
557       {
558         if (NULL != mqm->env)
559         {
560           GNUNET_MQ_discard (mqm->env);
561           mqm->env = NULL;
562           mqm->cb (mqm->cb_cls,
563                    GNUNET_SYSERR);
564         }
565         else
566         {
567           mqm->cb (mqm->cb_cls,
568                    GNUNET_NO);
569         }
570       }
571       else
572       {
573         GNUNET_assert (NULL == mqm->env);
574         mqm->cb (mqm->cb_cls,
575                  GNUNET_YES);
576       }
577       break;
578     }
579   }
580   if ( (NULL != mq) ||
581        (NULL != cp->t) )
582     consider_peer_activate (cp);
583   else
584     consider_peer_destroy (cp);
585
586   if ( (NULL != mq) &&
587        (NULL != cp->t) )
588   {
589     /* have a new, direct path to the target, notify tunnel */
590     struct CadetPeerPath *path;
591
592     path = GCPP_get_path_from_route (1,
593                                      &cp->pid);
594     GCT_consider_path (cp->t,
595                        path,
596                        0);
597   }
598 }
599
600
601 /**
602  * Debug function should NEVER return true in production code, useful to
603  * simulate losses for testcases.
604  *
605  * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
606  */
607 static int
608 should_I_drop (void)
609 {
610   if (0 == drop_percent)
611     return GNUNET_NO;
612   if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
613                                 101) < drop_percent)
614     return GNUNET_YES;
615   return GNUNET_NO;
616 }
617
618
619 /**
620  * Function called when CORE took one of the messages from
621  * a message queue manager and transmitted it.
622  *
623  * @param cls the `struct CadetPeeer` where we made progress
624  */
625 static void
626 mqm_send_done (void *cls);
627
628
629 /**
630  * Transmit current envelope from this @a mqm.
631  *
632  * @param mqm mqm to transmit message for now
633  */
634 static void
635 mqm_execute (struct GCP_MessageQueueManager *mqm)
636 {
637   struct CadetPeer *cp = mqm->cp;
638
639   /* Move ready pointer to the next entry that might be ready. */
640   if ( (mqm == cp->mqm_ready_ptr) &&
641        (NULL != mqm->next) )
642     cp->mqm_ready_ptr = mqm->next;
643   /* Move entry to the end of the DLL, to be fair. */
644   if (mqm != cp->mqm_tail)
645   {
646     GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
647                                  cp->mqm_tail,
648                                  mqm);
649     GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
650                                       cp->mqm_tail,
651                                       mqm);
652   }
653   cp->mqm_ready_counter--;
654   if (GNUNET_YES == should_I_drop ())
655   {
656     LOG (GNUNET_ERROR_TYPE_DEBUG,
657          "DROPPING message to peer %s from MQM %p\n",
658          GCP_2s (cp),
659          mqm);
660     GNUNET_MQ_discard (mqm->env);
661     mqm->env = NULL;
662     mqm_send_done (cp);
663   }
664   else
665   {
666     LOG (GNUNET_ERROR_TYPE_DEBUG,
667          "Sending to peer %s from MQM %p\n",
668          GCP_2s (cp),
669          mqm);
670     GNUNET_MQ_send (cp->core_mq,
671                     mqm->env);
672     mqm->env = NULL;
673   }
674   mqm->cb (mqm->cb_cls,
675            GNUNET_YES);
676 }
677
678
679 /**
680  * Find the next ready message in the queue (starting
681  * the search from the `cp->mqm_ready_ptr`) and if possible
682  * execute the transmission.
683  *
684  * @param cp peer to try to send the next ready message to
685  */
686 static void
687 send_next_ready (struct CadetPeer *cp)
688 {
689   struct GCP_MessageQueueManager *mqm;
690
691   if (0 == cp->mqm_ready_counter)
692     return;
693   while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
694           (NULL == mqm->env) )
695     cp->mqm_ready_ptr = mqm->next;
696   if (NULL == mqm)
697     return; /* nothing to do */
698   mqm_execute (mqm);
699 }
700
701
702 /**
703  * Function called when CORE took one of the messages from
704  * a message queue manager and transmitted it.
705  *
706  * @param cls the `struct CadetPeeer` where we made progress
707  */
708 static void
709 mqm_send_done (void *cls)
710 {
711   struct CadetPeer *cp = cls;
712
713   LOG (GNUNET_ERROR_TYPE_DEBUG,
714        "Sending to peer %s completed\n",
715        GCP_2s (cp));
716   send_next_ready (cp);
717 }
718
719
720 /**
721  * Send the message in @a env to @a cp.
722  *
723  * @param mqm the message queue manager to use for transmission
724  * @param env envelope with the message to send; must NOT
725  *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
726  */
727 void
728 GCP_send (struct GCP_MessageQueueManager *mqm,
729           struct GNUNET_MQ_Envelope *env)
730 {
731   struct CadetPeer *cp = mqm->cp;
732
733   GNUNET_assert (NULL != env);
734   LOG (GNUNET_ERROR_TYPE_DEBUG,
735        "Queueing message to peer %s in MQM %p\n",
736        GCP_2s (cp),
737        mqm);
738   GNUNET_assert (NULL != cp->core_mq);
739   GNUNET_assert (NULL == mqm->env);
740   GNUNET_MQ_notify_sent (env,
741                          &mqm_send_done,
742                          cp);
743   mqm->env = env;
744   cp->mqm_ready_counter++;
745   if (mqm != cp->mqm_ready_ptr)
746     cp->mqm_ready_ptr = cp->mqm_head;
747   if (1 == cp->mqm_ready_counter)
748     cp->mqm_ready_ptr = mqm;
749   if (0 != GNUNET_MQ_get_length (cp->core_mq))
750     return;
751   send_next_ready (cp);
752 }
753
754
755 /**
756  * Function called to destroy a peer now.
757  *
758  * @param cls NULL
759  * @param pid identity of the peer (unused)
760  * @param value the `struct CadetPeer` to clean up
761  * @return #GNUNET_OK (continue to iterate)
762  */
763 static int
764 destroy_iterator_cb (void *cls,
765                      const struct GNUNET_PeerIdentity *pid,
766                      void *value)
767 {
768   struct CadetPeer *cp = value;
769
770   if (NULL != cp->destroy_task)
771   {
772     GNUNET_SCHEDULER_cancel (cp->destroy_task);
773     cp->destroy_task = NULL;
774   }
775   destroy_peer (cp);
776   return GNUNET_OK;
777 }
778
779
780 /**
781  * Clean up all entries about all peers.
782  * Must only be called after all tunnels, CORE-connections and
783  * connections are down.
784  */
785 void
786 GCP_destroy_all_peers ()
787 {
788   LOG (GNUNET_ERROR_TYPE_DEBUG,
789        "Destroying all peers now\n");
790   GNUNET_CONTAINER_multipeermap_iterate (peers,
791                                          &destroy_iterator_cb,
792                                          NULL);
793 }
794
795
796 /**
797  * Drop all paths owned by this peer, and do not
798  * allow new ones to be added: We are shutting down.
799  *
800  * @param cp peer to drop paths to
801  */
802 void
803 GCP_drop_owned_paths (struct CadetPeer *cp)
804 {
805   struct CadetPeerPath *path;
806
807   LOG (GNUNET_ERROR_TYPE_DEBUG,
808        "Destroying all paths to %s\n",
809        GCP_2s (cp));
810   while (NULL != (path =
811                   GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
812     GCPP_release (path);
813   GNUNET_CONTAINER_heap_destroy (cp->path_heap);
814   cp->path_heap = NULL;
815 }
816
817
818 /**
819  * Add an entry to the DLL of all of the paths that this peer is on.
820  *
821  * @param cp peer to modify
822  * @param entry an entry on a path
823  * @param off offset of this peer on the path
824  */
825 void
826 GCP_path_entry_add (struct CadetPeer *cp,
827                     struct CadetPeerPathEntry *entry,
828                     unsigned int off)
829 {
830   GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
831                                                 off));
832   LOG (GNUNET_ERROR_TYPE_DEBUG,
833        "Discovered that peer %s is on path %s at offset %u\n",
834        GCP_2s (cp),
835        GCPP_2s (entry->path),
836        off);
837   if (off >= cp->path_dll_length)
838   {
839     unsigned int len = cp->path_dll_length;
840
841     GNUNET_array_grow (cp->path_heads,
842                        len,
843                        off + 4);
844     GNUNET_array_grow (cp->path_tails,
845                        cp->path_dll_length,
846                        off + 4);
847   }
848   GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
849                                cp->path_tails[off],
850                                entry);
851   cp->off_sum += off;
852   cp->num_paths++;
853
854   /* If we have a tunnel to this peer, tell the tunnel that there is a
855      new path available. */
856   if (NULL != cp->t)
857     GCT_consider_path (cp->t,
858                        entry->path,
859                        off);
860
861   if ( (NULL != cp->search_h) &&
862        (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
863   {
864     /* Now I have enough paths, stop search */
865     GCD_search_stop (cp->search_h);
866     cp->search_h = NULL;
867   }
868   if (NULL != cp->destroy_task)
869   {
870     /* paths changed, this resets the destroy timeout counter
871        and aborts a destroy task that may no longer be valid
872        to have (as we now have more paths via this peer). */
873     consider_peer_destroy (cp);
874   }
875 }
876
877
878 /**
879  * Remove an entry from the DLL of all of the paths that this peer is on.
880  *
881  * @param cp peer to modify
882  * @param entry an entry on a path
883  * @param off offset of this peer on the path
884  */
885 void
886 GCP_path_entry_remove (struct CadetPeer *cp,
887                        struct CadetPeerPathEntry *entry,
888                        unsigned int off)
889 {
890   LOG (GNUNET_ERROR_TYPE_DEBUG,
891        "Removing knowledge about peer %s beging on path %s at offset %u\n",
892        GCP_2s (cp),
893        GCPP_2s (entry->path),
894        off);
895   GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
896                                cp->path_tails[off],
897                                entry);
898   GNUNET_assert (0 < cp->num_paths);
899   cp->off_sum -= off;
900   cp->num_paths--;
901   if ( (NULL == cp->core_mq) &&
902        (NULL != cp->t) &&
903        (NULL == cp->search_h) &&
904        (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
905     cp->search_h
906       = GCD_search (&cp->pid);
907   if (NULL == cp->destroy_task)
908   {
909     /* paths changed, we might now be ready for destruction, check again */
910     consider_peer_destroy (cp);
911   }
912 }
913
914
915 /**
916  * Prune down the number of paths to this peer, we seem to
917  * have way too many.
918  *
919  * @param cls the `struct CadetPeer` to maintain the path heap for
920  */
921 static void
922 path_heap_cleanup (void *cls)
923 {
924   struct CadetPeer *cp = cls;
925   struct CadetPeerPath *root;
926
927   cp->heap_cleanup_task = NULL;
928   while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
929          2 * DESIRED_CONNECTIONS_PER_TUNNEL)
930   {
931     /* Now we have way too many, drop least desirable UNLESS it is in use!
932        (Note that this intentionally keeps highly desireable, but currently
933        unused paths around in the hope that we might be able to switch, even
934        if the number of paths exceeds the threshold.) */
935     root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
936     GNUNET_assert (NULL != root);
937     if (NULL !=
938         GCPP_get_connection (root,
939                              cp,
940                              GCPP_get_length (root) - 1))
941       break; /* can't fix */
942     /* Got plenty of paths to this destination, and this is a low-quality
943        one that we don't care about. Allow it to die. */
944     GNUNET_assert (root ==
945                    GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
946     GCPP_release (root);
947   }
948 }
949
950
951 /**
952  * Try adding a @a path to this @a peer.  If the peer already
953  * has plenty of paths, return NULL.
954  *
955  * @param cp peer to which the @a path leads to
956  * @param path a path looking for an owner; may not be fully initialized yet!
957  * @param off offset of @a cp in @a path
958  * @param force force attaching the path
959  * @return NULL if this peer does not care to become a new owner,
960  *         otherwise the node in the peer's path heap for the @a path.
961  */
962 struct GNUNET_CONTAINER_HeapNode *
963 GCP_attach_path (struct CadetPeer *cp,
964                  struct CadetPeerPath *path,
965                  unsigned int off,
966                  int force)
967 {
968   GNUNET_CONTAINER_HeapCostType desirability;
969   struct CadetPeerPath *root;
970   GNUNET_CONTAINER_HeapCostType root_desirability;
971   struct GNUNET_CONTAINER_HeapNode *hn;
972
973   GNUNET_assert (off == GCPP_get_length (path) - 1);
974   GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
975                                                 off));
976   if (NULL == cp->path_heap)
977   {
978     /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
979     GNUNET_assert (GNUNET_NO == force);
980     return NULL;
981   }
982   desirability = GCPP_get_desirability (path);
983   if (GNUNET_NO == force)
984   {
985     /* FIXME: desirability is not yet initialized; tricky! */
986     if (GNUNET_NO ==
987         GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
988                                      (void **) &root,
989                                      &root_desirability))
990     {
991       root = NULL;
992       root_desirability = 0;
993     }
994
995     if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
996          (desirability < root_desirability) )
997     {
998       LOG (GNUNET_ERROR_TYPE_DEBUG,
999            "Decided to not attach path %p to peer %s due to undesirability\n",
1000            GCPP_2s (path),
1001            GCP_2s (cp));
1002       return NULL;
1003     }
1004   }
1005
1006   LOG (GNUNET_ERROR_TYPE_DEBUG,
1007        "Attaching path %s to peer %s (%s)\n",
1008        GCPP_2s (path),
1009        GCP_2s (cp),
1010        (GNUNET_NO == force) ? "desirable" : "forced");
1011
1012   /* Yes, we'd like to add this path, add to our heap */
1013   hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1014                                      path,
1015                                      desirability);
1016
1017   /* Consider maybe dropping other paths because of the new one */
1018   if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1019         2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1020        (NULL != cp->heap_cleanup_task) )
1021     cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1022                                                       cp);
1023   return hn;
1024 }
1025
1026
1027 /**
1028  * This peer can no longer own @a path as the path
1029  * has been extended and a peer further down the line
1030  * is now the new owner.
1031  *
1032  * @param cp old owner of the @a path
1033  * @param path path where the ownership is lost
1034  * @param hn note in @a cp's path heap that must be deleted
1035  */
1036 void
1037 GCP_detach_path (struct CadetPeer *cp,
1038                  struct CadetPeerPath *path,
1039                  struct GNUNET_CONTAINER_HeapNode *hn)
1040 {
1041   LOG (GNUNET_ERROR_TYPE_DEBUG,
1042        "Detatching path %s from peer %s\n",
1043        GCPP_2s (path),
1044        GCP_2s (cp));
1045   GNUNET_assert (path ==
1046                  GNUNET_CONTAINER_heap_remove_node (hn));
1047 }
1048
1049
1050 /**
1051  * Add a @a connection to this @a cp.
1052  *
1053  * @param cp peer via which the @a connection goes
1054  * @param cc the connection to add
1055  */
1056 void
1057 GCP_add_connection (struct CadetPeer *cp,
1058                     struct CadetConnection *cc)
1059 {
1060   LOG (GNUNET_ERROR_TYPE_DEBUG,
1061        "Adding connection %s to peer %s\n",
1062        GCC_2s (cc),
1063        GCP_2s (cp));
1064   GNUNET_assert (GNUNET_OK ==
1065                  GNUNET_CONTAINER_multishortmap_put (cp->connections,
1066                                                      &GCC_get_id (cc)->connection_of_tunnel,
1067                                                      cc,
1068                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1069   if (NULL != cp->destroy_task)
1070   {
1071     GNUNET_SCHEDULER_cancel (cp->destroy_task);
1072     cp->destroy_task = NULL;
1073   }
1074 }
1075
1076
1077 /**
1078  * Remove a @a connection that went via this @a cp.
1079  *
1080  * @param cp peer via which the @a connection went
1081  * @param cc the connection to remove
1082  */
1083 void
1084 GCP_remove_connection (struct CadetPeer *cp,
1085                        struct CadetConnection *cc)
1086 {
1087   LOG (GNUNET_ERROR_TYPE_DEBUG,
1088        "Removing connection %s from peer %s\n",
1089        GCC_2s (cc),
1090        GCP_2s (cp));
1091   GNUNET_assert (GNUNET_YES ==
1092                  GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1093                                                         &GCC_get_id (cc)->connection_of_tunnel,
1094                                                         cc));
1095   consider_peer_destroy (cp);
1096 }
1097
1098
1099 /**
1100  * Retrieve the CadetPeer stucture associated with the
1101  * peer. Optionally create one and insert it in the appropriate
1102  * structures if the peer is not known yet.
1103  *
1104  * @param peer_id Full identity of the peer.
1105  * @param create #GNUNET_YES if a new peer should be created if unknown.
1106  *               #GNUNET_NO to return NULL if peer is unknown.
1107  * @return Existing or newly created peer structure.
1108  *         NULL if unknown and not requested @a create
1109  */
1110 struct CadetPeer *
1111 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1112          int create)
1113 {
1114   struct CadetPeer *cp;
1115
1116   cp = GNUNET_CONTAINER_multipeermap_get (peers,
1117                                           peer_id);
1118   if (NULL != cp)
1119     return cp;
1120   if (GNUNET_NO == create)
1121     return NULL;
1122   cp = GNUNET_new (struct CadetPeer);
1123   cp->pid = *peer_id;
1124   cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1125                                                            GNUNET_YES);
1126   cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1127   GNUNET_assert (GNUNET_YES ==
1128                  GNUNET_CONTAINER_multipeermap_put (peers,
1129                                                     &cp->pid,
1130                                                     cp,
1131                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1132   LOG (GNUNET_ERROR_TYPE_DEBUG,
1133        "Creating peer %s\n",
1134        GCP_2s (cp));
1135   return cp;
1136 }
1137
1138
1139 /**
1140  * Obtain the peer identity for a `struct CadetPeer`.
1141  *
1142  * @param cp our peer handle
1143  * @return the peer identity
1144  */
1145 const struct GNUNET_PeerIdentity *
1146 GCP_get_id (struct CadetPeer *cp)
1147 {
1148   return &cp->pid;
1149 }
1150
1151
1152 /**
1153  * Iterate over all known peers.
1154  *
1155  * @param iter Iterator.
1156  * @param cls Closure for @c iter.
1157  */
1158 void
1159 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1160                  void *cls)
1161 {
1162   GNUNET_CONTAINER_multipeermap_iterate (peers,
1163                                          iter,
1164                                          cls);
1165 }
1166
1167
1168 /**
1169  * Count the number of known paths toward the peer.
1170  *
1171  * @param cp Peer to get path info.
1172  * @return Number of known paths.
1173  */
1174 unsigned int
1175 GCP_count_paths (const struct CadetPeer *cp)
1176 {
1177   return cp->num_paths;
1178 }
1179
1180
1181 /**
1182  * Iterate over the paths to a peer.
1183  *
1184  * @param cp Peer to get path info.
1185  * @param callback Function to call for every path.
1186  * @param callback_cls Closure for @a callback.
1187  * @return Number of iterated paths.
1188  */
1189 unsigned int
1190 GCP_iterate_paths (struct CadetPeer *cp,
1191                    GCP_PathIterator callback,
1192                    void *callback_cls)
1193 {
1194   unsigned int ret = 0;
1195
1196   LOG (GNUNET_ERROR_TYPE_DEBUG,
1197        "Iterating over paths to peer %s%s\n",
1198        GCP_2s (cp),
1199        (NULL == cp->core_mq) ? "" : " including direct link");
1200   if (NULL != cp->core_mq)
1201   {
1202     struct CadetPeerPath *path;
1203
1204     path = GCPP_get_path_from_route (1,
1205                                      &cp->pid);
1206     ret++;
1207     if (GNUNET_NO ==
1208         callback (callback_cls,
1209                   path,
1210                   0))
1211       return ret;
1212   }
1213   for (unsigned int i=0;i<cp->path_dll_length;i++)
1214   {
1215     for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1216          NULL != pe;
1217          pe = pe->next)
1218     {
1219       ret++;
1220       if (GNUNET_NO ==
1221           callback (callback_cls,
1222                     pe->path,
1223                     i))
1224         return ret;
1225     }
1226   }
1227   return ret;
1228 }
1229
1230
1231 /**
1232  * Iterate over the paths to @a cp where
1233  * @a cp is at distance @a dist from us.
1234  *
1235  * @param cp Peer to get path info.
1236  * @param dist desired distance of @a cp to us on the path
1237  * @param callback Function to call for every path.
1238  * @param callback_cls Closure for @a callback.
1239  * @return Number of iterated paths.
1240  */
1241 unsigned int
1242 GCP_iterate_paths_at (struct CadetPeer *cp,
1243                       unsigned int dist,
1244                       GCP_PathIterator callback,
1245                       void *callback_cls)
1246 {
1247   unsigned int ret = 0;
1248
1249   if (dist >= cp->path_dll_length)
1250   {
1251     LOG (GNUNET_ERROR_TYPE_DEBUG,
1252          "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1253          dist,
1254          cp->path_dll_length);
1255     return 0;
1256   }
1257   for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1258        NULL != pe;
1259        pe = pe->next)
1260   {
1261     if (GNUNET_NO ==
1262         callback (callback_cls,
1263                   pe->path,
1264                   dist))
1265       return ret;
1266     ret++;
1267   }
1268   return ret;
1269 }
1270
1271
1272 /**
1273  * Get the tunnel towards a peer.
1274  *
1275  * @param cp Peer to get from.
1276  * @param create #GNUNET_YES to create a tunnel if we do not have one
1277  * @return Tunnel towards peer.
1278  */
1279 struct CadetTunnel *
1280 GCP_get_tunnel (struct CadetPeer *cp,
1281                 int create)
1282 {
1283   if (NULL == cp)
1284     return NULL;
1285   if ( (NULL != cp->t) ||
1286        (GNUNET_NO == create) )
1287     return cp->t;
1288   cp->t = GCT_create_tunnel (cp);
1289   consider_peer_activate (cp);
1290   return cp->t;
1291 }
1292
1293
1294 /**
1295  * Hello offer was passed to the transport service. Mark it
1296  * as done.
1297  *
1298  * @param cls the `struct CadetPeer` where the offer completed
1299  */
1300 static void
1301 hello_offer_done (void *cls)
1302 {
1303   struct CadetPeer *cp = cls;
1304
1305   cp->hello_offer = NULL;
1306 }
1307
1308
1309 /**
1310  * We got a HELLO for a @a peer, remember it, and possibly
1311  * trigger adequate actions (like trying to connect).
1312  *
1313  * @param cp the peer we got a HELLO for
1314  * @param hello the HELLO to remember
1315  */
1316 void
1317 GCP_set_hello (struct CadetPeer *cp,
1318                const struct GNUNET_HELLO_Message *hello)
1319 {
1320   struct GNUNET_HELLO_Message *mrg;
1321
1322   LOG (GNUNET_ERROR_TYPE_DEBUG,
1323        "Got %u byte HELLO for peer %s\n",
1324        (unsigned int) GNUNET_HELLO_size (hello),
1325        GCP_2s (cp));
1326   if (NULL != cp->hello_offer)
1327   {
1328     GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1329     cp->hello_offer = NULL;
1330   }
1331   if (NULL != cp->hello)
1332   {
1333     mrg = GNUNET_HELLO_merge (hello,
1334                               cp->hello);
1335     GNUNET_free (cp->hello);
1336     cp->hello = mrg;
1337   }
1338   else
1339   {
1340     cp->hello = GNUNET_memdup (hello,
1341                                GNUNET_HELLO_size (hello));
1342   }
1343   cp->hello_offer
1344     = GNUNET_TRANSPORT_offer_hello (cfg,
1345                                     GNUNET_HELLO_get_header (cp->hello) ,
1346                                     &hello_offer_done,
1347                                     cp);
1348   /* New HELLO means cp's destruction time may change... */
1349   consider_peer_destroy (cp);
1350 }
1351
1352
1353 /**
1354  * The tunnel to the given peer no longer exists, remove it from our
1355  * data structures, and possibly clean up the peer itself.
1356  *
1357  * @param cp the peer affected
1358  * @param t the dead tunnel
1359  */
1360 void
1361 GCP_drop_tunnel (struct CadetPeer *cp,
1362                  struct CadetTunnel *t)
1363 {
1364   LOG (GNUNET_ERROR_TYPE_DEBUG,
1365        "Dropping tunnel %s to peer %s\n",
1366        GCT_2s (t),
1367        GCP_2s (cp));
1368   GNUNET_assert (cp->t == t);
1369   cp->t = NULL;
1370   consider_peer_destroy (cp);
1371 }
1372
1373
1374 /**
1375  * Test if @a cp has a core-level connection
1376  *
1377  * @param cp peer to test
1378  * @return #GNUNET_YES if @a cp has a core-level connection
1379  */
1380 int
1381 GCP_has_core_connection (struct CadetPeer *cp)
1382 {
1383   return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1384 }
1385
1386
1387 /**
1388  * Start message queue change notifications.
1389  *
1390  * @param cp peer to notify for
1391  * @param cb function to call if mq becomes available or unavailable
1392  * @param cb_cls closure for @a cb
1393  * @return handle to cancel request
1394  */
1395 struct GCP_MessageQueueManager *
1396 GCP_request_mq (struct CadetPeer *cp,
1397                 GCP_MessageQueueNotificationCallback cb,
1398                 void *cb_cls)
1399 {
1400   struct GCP_MessageQueueManager *mqm;
1401
1402   mqm = GNUNET_new (struct GCP_MessageQueueManager);
1403   mqm->cb = cb;
1404   mqm->cb_cls = cb_cls;
1405   mqm->cp = cp;
1406   GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1407                                cp->mqm_tail,
1408                                mqm);
1409   LOG (GNUNET_ERROR_TYPE_DEBUG,
1410        "Creating MQM %p for peer %s\n",
1411        mqm,
1412        GCP_2s (cp));
1413   if (NULL != cp->core_mq)
1414     cb (cb_cls,
1415         GNUNET_YES);
1416   return mqm;
1417 }
1418
1419
1420 /**
1421  * Stops message queue change notifications.
1422  *
1423  * @param mqm handle matching request to cancel
1424  * @param last_env final message to transmit, or NULL
1425  */
1426 void
1427 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1428                        struct GNUNET_MQ_Envelope *last_env)
1429 {
1430   struct CadetPeer *cp = mqm->cp;
1431
1432   LOG (GNUNET_ERROR_TYPE_DEBUG,
1433        "Destroying MQM %p for peer %s%s\n",
1434        mqm,
1435        GCP_2s (cp),
1436        (NULL == last_env) ? "" : " with last ditch transmission");
1437   if (NULL != mqm->env)
1438     GNUNET_MQ_discard (mqm->env);
1439   if (NULL != last_env)
1440   {
1441     if (NULL != cp->core_mq)
1442     {
1443       GNUNET_MQ_notify_sent (last_env,
1444                              &mqm_send_done,
1445                              cp);
1446       GNUNET_MQ_send (cp->core_mq,
1447                       last_env);
1448     }
1449     else
1450     {
1451       GNUNET_MQ_discard (last_env);
1452     }
1453   }
1454   if (cp->mqm_ready_ptr == mqm)
1455     cp->mqm_ready_ptr = mqm->next;
1456   GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1457                                cp->mqm_tail,
1458                                mqm);
1459   GNUNET_free (mqm);
1460 }
1461
1462
1463 /**
1464  * Send the message in @a env to @a cp, overriding queueing logic.
1465  * This function should only be used to send error messages outside
1466  * of flow and congestion control, similar to ICMP.  Note that
1467  * the envelope may be silently discarded as well.
1468  *
1469  * @param cp peer to send the message to
1470  * @param env envelope with the message to send
1471  */
1472 void
1473 GCP_send_ooo (struct CadetPeer *cp,
1474               struct GNUNET_MQ_Envelope *env)
1475 {
1476   LOG (GNUNET_ERROR_TYPE_DEBUG,
1477        "Sending message to %s out of management\n",
1478        GCP_2s (cp));
1479   if (NULL == cp->core_mq)
1480   {
1481     GNUNET_MQ_discard (env);
1482     return;
1483   }
1484   GNUNET_MQ_notify_sent (env,
1485                          &mqm_send_done,
1486                          cp);
1487   GNUNET_MQ_send (cp->core_mq,
1488                   env);
1489 }
1490
1491
1492
1493
1494 /* end of gnunet-service-cadet-new_peer.c */