more work on new CADET
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_peer.c
1
2 /*
3      This file is part of GNUnet.
4      Copyright (C) 2001-2017 GNUnet e.V.
5
6      GNUnet is free software; you can redistribute it and/or modify
7      it under the terms of the GNU General Public License as published
8      by the Free Software Foundation; either version 3, or (at your
9      option) any later version.
10
11      GNUnet is distributed in the hope that it will be useful, but
12      WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      General Public License for more details.
15
16      You should have received a copy of the GNU General Public License
17      along with GNUnet; see the file COPYING.  If not, write to the
18      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19      Boston, MA 02110-1301, USA.
20 */
21
22 /**
23  * @file cadet/gnunet-service-cadet-new_peer.c
24  * @brief Information we track per peer.
25  * @author Bartlomiej Polot
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_signatures.h"
31 #include "gnunet_transport_service.h"
32 #include "gnunet_ats_service.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_statistics_service.h"
35 #include "cadet_protocol.h"
36 #include "cadet_path.h"
37 #include "gnunet-service-cadet-new.h"
38 #include "gnunet-service-cadet-new_connection.h"
39 #include "gnunet-service-cadet-new_dht.h"
40 #include "gnunet-service-cadet-new_peer.h"
41 #include "gnunet-service-cadet-new_paths.h"
42 #include "gnunet-service-cadet-new_tunnels.h"
43
44 /**
45  * How long do we wait until tearing down an idle peer?
46  */
47 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
48
49 /**
50  * How long do we keep paths around if we no longer care about the peer?
51  */
52 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
53
54
55
56
57 /**
58  * Data structure used to track whom we have to notify about changes
59  * to our message queue.
60  */
61 struct GCP_MessageQueueManager
62 {
63
64   /**
65    * Kept in a DLL.
66    */
67   struct GCP_MessageQueueManager *next;
68
69   /**
70    * Kept in a DLL.
71    */
72   struct GCP_MessageQueueManager *prev;
73
74   /**
75    * Function to call with updated message queue object.
76    */
77   GCP_MessageQueueNotificationCallback cb;
78
79   /**
80    * Closure for @e cb.
81    */
82   void *cb_cls;
83
84   /**
85    * The peer this is for.
86    */
87   struct CadetPeer *cp;
88
89 };
90
91
92 /**
93  * Struct containing all information regarding a given peer
94  */
95 struct CadetPeer
96 {
97   /**
98    * ID of the peer
99    */
100   struct GNUNET_PeerIdentity pid;
101
102   /**
103    * Last time we heard from this peer
104    */
105   struct GNUNET_TIME_Absolute last_contact;
106
107   /**
108    * Array of DLLs of paths traversing the peer, organized by the
109    * offset of the peer on the larger path.
110    */
111   struct CadetPeerPathEntry **path_heads;
112
113   /**
114    * Array of DLL of paths traversing the peer, organized by the
115    * offset of the peer on the larger path.
116    */
117   struct CadetPeerPathEntry **path_tails;
118
119   /**
120    * Notifications to call when @e core_mq changes.
121    */
122   struct GCP_MessageQueueManager *mqm_head;
123
124   /**
125    * Notifications to call when @e core_mq changes.
126    */
127   struct GCP_MessageQueueManager *mqm_tail;
128
129   /**
130    * MIN-heap of paths owned by this peer (they also end at this
131    * peer).  Ordered by desirability.
132    */
133   struct GNUNET_CONTAINER_Heap *path_heap;
134
135   /**
136    * Handle to stop the DHT search for paths to this peer
137    */
138   struct GCD_search_handle *search_h;
139
140   /**
141    * Task to stop the DHT search for paths to this peer
142    */
143   struct GNUNET_SCHEDULER_Task *search_delayedXXX;
144
145   /**
146    * Task to destroy this entry.
147    */
148   struct GNUNET_SCHEDULER_Task *destroy_task;
149
150   /**
151    * Tunnel to this peer, if any.
152    */
153   struct CadetTunnel *t;
154
155   /**
156    * Connections that go through this peer; indexed by tid.
157    */
158   struct GNUNET_CONTAINER_MultiHashMap *connections;
159
160   /**
161    * Handle for core transmissions.
162    */
163   struct GNUNET_MQ_Handle *core_mq;
164
165   /**
166    * Hello message of the peer.
167    */
168   struct GNUNET_HELLO_Message *hello;
169
170   /**
171    * Handle to us offering the HELLO to the transport.
172    */
173   struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
174
175   /**
176    * Handle to our ATS request asking ATS to suggest an address
177    * to TRANSPORT for this peer (to establish a direct link).
178    */
179   struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
180
181   /**
182    * How many messages are in the queue to this peer.
183    */
184   unsigned int queue_n;
185
186   /**
187    * How many paths do we have to this peer (in all @e path_heads DLLs combined).
188    */
189   unsigned int num_paths;
190
191   /**
192    * Current length of the @e path_heads and @path_tails arrays.
193    * The arrays should be grown as needed.
194    */
195   unsigned int path_dll_length;
196
197 };
198
199
200 /**
201  * Get the static string for a peer ID.
202  *
203  * @param peer Peer.
204  *
205  * @return Static string for it's ID.
206  */
207 const char *
208 GCP_2s (const struct CadetPeer *peer)
209 {
210   if (NULL == peer)
211     return "PEER(NULL)";
212   return GNUNET_i2s (&peer->pid);
213 }
214
215
216 /**
217  * This peer is no longer be needed, clean it up now.
218  *
219  * @param cls peer to clean up
220  */
221 static void
222 destroy_peer (void *cls)
223 {
224   struct CadetPeer *cp = cls;
225
226   cp->destroy_task = NULL;
227   GNUNET_assert (NULL == cp->t);
228   GNUNET_assert (NULL == cp->core_mq);
229   GNUNET_assert (0 == cp->path_dll_length);
230   GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections));
231   GNUNET_assert (GNUNET_YES ==
232                  GNUNET_CONTAINER_multipeermap_remove (peers,
233                                                        &cp->pid,
234                                                        cp));
235   GNUNET_free_non_null (cp->path_heads);
236   GNUNET_free_non_null (cp->path_tails);
237   cp->path_dll_length = 0;
238   if (NULL != cp->search_h)
239   {
240     GCD_search_stop (cp->search_h);
241     cp->search_h = NULL;
242   }
243   /* FIXME: clean up search_delayedXXX! */
244
245   if (NULL != cp->hello_offer)
246   {
247     GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
248     cp->hello_offer = NULL;
249   }
250   if (NULL != cp->connectivity_suggestion)
251   {
252     GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
253     cp->connectivity_suggestion = NULL;
254   }
255   GNUNET_CONTAINER_multihashmap_destroy (cp->connections);
256   GNUNET_CONTAINER_heap_destroy (cp->path_heap);
257   GNUNET_free_non_null (cp->hello);
258   /* Peer should not be freed if paths exist; if there are no paths,
259      there ought to be no connections, and without connections, no
260      notifications. Thus we can assert that mqm_head is empty at this
261      point. */
262   GNUNET_assert (NULL == cp->mqm_head);
263   GNUNET_free (cp);
264 }
265
266
267 /**
268  * Set the message queue to @a mq for peer @a cp and notify watchers.
269  *
270  * @param cp peer to modify
271  * @param mq message queue to set (can be NULL)
272  */
273 void
274 GCP_set_mq (struct CadetPeer *cp,
275             struct GNUNET_MQ_Handle *mq)
276 {
277   cp->core_mq = mq;
278   for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
279        NULL != mqm;
280        mqm = mqm->next)
281     mqm->cb (mqm->cb_cls,
282              mq);
283 }
284
285
286 /**
287  * Function called to destroy a peer now.
288  *
289  * @param cls NULL
290  * @param pid identity of the peer (unused)
291  * @param value the `struct CadetPeer` to clean up
292  * @return #GNUNET_OK (continue to iterate)
293  */
294 static int
295 destroy_iterator_cb (void *cls,
296                      const struct GNUNET_PeerIdentity *pid,
297                      void *value)
298 {
299   struct CadetPeer *cp = value;
300
301   if (NULL != cp->destroy_task)
302   {
303     GNUNET_SCHEDULER_cancel (cp->destroy_task);
304     cp->destroy_task = NULL;
305   }
306   destroy_peer (cp);
307   return GNUNET_OK;
308 }
309
310
311 /**
312  * Clean up all entries about all peers.
313  * Must only be called after all tunnels, CORE-connections and
314  * connections are down.
315  */
316 void
317 GCP_destroy_all_peers ()
318 {
319   GNUNET_CONTAINER_multipeermap_iterate (peers,
320                                          &destroy_iterator_cb,
321                                          NULL);
322 }
323
324
325 /**
326  * This peer may no longer be needed, consider cleaning it up.
327  *
328  * @param cp peer to clean up
329  */
330 static void
331 consider_peer_destroy (struct CadetPeer *cp);
332
333
334 /**
335  * We really no longere care about a peer, stop hogging memory with paths to it.
336  * Afterwards, see if there is more to be cleaned up about this peer.
337  *
338  * @param cls a `struct CadetPeer`.
339  */
340 static void
341 drop_paths (void *cls)
342 {
343   struct CadetPeer *cp = cls;
344   struct CadetPeerPath *path;
345
346   cp->destroy_task = NULL;
347   while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
348     GCPP_release (path);
349   consider_peer_destroy (cp);
350 }
351
352
353 /**
354  * This peer may no longer be needed, consider cleaning it up.
355  *
356  * @param cp peer to clean up
357  */
358 static void
359 consider_peer_destroy (struct CadetPeer *cp)
360 {
361   struct GNUNET_TIME_Relative exp;
362
363   if (NULL != cp->destroy_task)
364   {
365     GNUNET_SCHEDULER_cancel (cp->destroy_task);
366     cp->destroy_task = NULL;
367   }
368   if (NULL != cp->t)
369     return; /* still relevant! */
370   if (NULL != cp->core_mq)
371     return; /* still relevant! */
372   if (0 != GNUNET_CONTAINER_multihashmap_size (cp->connections))
373     return; /* still relevant! */
374   if (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap))
375   {
376     cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
377                                                      &drop_paths,
378                                                      cp);
379     return;
380   }
381   if (0 < cp->path_dll_length)
382     return; /* still relevant! */
383   if (NULL != cp->hello)
384   {
385     /* relevant only until HELLO expires */
386     exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
387     cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
388                                                      &destroy_peer,
389                                                      cp);
390     return;
391   }
392   cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
393                                                    &destroy_peer,
394                                                    cp);
395 }
396
397
398 /**
399  * Add an entry to the DLL of all of the paths that this peer is on.
400  *
401  * @param cp peer to modify
402  * @param entry an entry on a path
403  * @param off offset of this peer on the path
404  */
405 void
406 GCP_path_entry_add (struct CadetPeer *cp,
407                     struct CadetPeerPathEntry *entry,
408                     unsigned int off)
409 {
410   if (off >= cp->path_dll_length)
411   {
412     unsigned int len = cp->path_dll_length;
413
414     GNUNET_array_grow (cp->path_heads,
415                        len,
416                        off + 4);
417     GNUNET_array_grow (cp->path_tails,
418                        cp->path_dll_length,
419                        off + 4);
420   }
421   GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
422                                cp->path_tails[off],
423                                entry);
424   cp->num_paths++;
425
426   /* If we have a tunnel to this peer, tell the tunnel that there is a
427      new path available. */
428   if (NULL != cp->t)
429     GCT_consider_path (cp->t,
430                        entry->path,
431                        off);
432 }
433
434
435 /**
436  * Remove an entry from the DLL of all of the paths that this peer is on.
437  *
438  * @param cp peer to modify
439  * @param entry an entry on a path
440  * @param off offset of this peer on the path
441  */
442 void
443 GCP_path_entry_remove (struct CadetPeer *cp,
444                        struct CadetPeerPathEntry *entry,
445                        unsigned int off)
446 {
447   GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
448                                cp->path_tails[off],
449                                entry);
450   GNUNET_assert (0 < cp->num_paths);
451   cp->num_paths--;
452 }
453
454
455 /**
456  * Try adding a @a path to this @a peer.  If the peer already
457  * has plenty of paths, return NULL.
458  *
459  * @param cp peer to which the @a path leads to
460  * @param path a path looking for an owner; may not be fully initialized yet!
461  * @param off offset of @a cp in @a path
462  * @return NULL if this peer does not care to become a new owner,
463  *         otherwise the node in the peer's path heap for the @a path.
464  */
465 struct GNUNET_CONTAINER_HeapNode *
466 GCP_attach_path (struct CadetPeer *cp,
467                  struct CadetPeerPath *path,
468                  unsigned int off)
469 {
470   GNUNET_CONTAINER_HeapCostType desirability;
471   struct CadetPeerPath *root;
472   GNUNET_CONTAINER_HeapCostType root_desirability;
473   struct GNUNET_CONTAINER_HeapNode *hn;
474
475   /* FIXME: desirability is not yet initialized; tricky! */
476   desirability = GCPP_get_desirability (path);
477   if (GNUNET_NO ==
478       GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
479                                    (void **) &root,
480                                    &root_desirability))
481   {
482     root = NULL;
483     root_desirability = 0;
484   }
485
486   if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
487        (desirability < root_desirability) )
488     return NULL;
489
490   /* Yes, we'd like to add this path, add to our heap */
491   hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
492                                      (void *) cp,
493                                      desirability);
494
495   /* Consider maybe dropping other paths because of the new one */
496   if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
497       2 * DESIRED_CONNECTIONS_PER_TUNNEL)
498   {
499     /* Now we have way too many, drop least desirable UNLESS it is in use!
500        (Note that this intentionally keeps highly desireable, but currently
501        unused paths around in the hope that we might be able to switch, even
502        if the number of paths exceeds the threshold.) */
503     root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
504     if (NULL ==
505         GCPP_get_connection (root,
506                              cp,
507                              GCPP_get_length (root) - 1))
508     {
509       /* Got plenty of paths to this destination, and this is a low-quality
510          one that we don't care, allow it to die. */
511       GNUNET_assert (root ==
512                      GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
513       GCPP_release (root);
514     }
515   }
516   return hn;
517 }
518
519
520 /**
521  * This peer can no longer own @a path as the path
522  * has been extended and a peer further down the line
523  * is now the new owner.
524  *
525  * @param cp old owner of the @a path
526  * @param path path where the ownership is lost
527  * @param hn note in @a cp's path heap that must be deleted
528  */
529 void
530 GCP_detach_path (struct CadetPeer *cp,
531                  struct CadetPeerPath *path,
532                  struct GNUNET_CONTAINER_HeapNode *hn)
533 {
534   GNUNET_assert (path ==
535                  GNUNET_CONTAINER_heap_remove_node (hn));
536 }
537
538
539 /**
540  * Add a @a connection to this @a cp.
541  *
542  * @param cp peer via which the @a connection goes
543  * @param cc the connection to add
544  */
545 void
546 GCP_add_connection (struct CadetPeer *cp,
547                     struct CadetConnection *cc)
548 {
549   GNUNET_assert (GNUNET_OK ==
550                  GNUNET_CONTAINER_multihashmap_put (cp->connections,
551                                                     GCC_get_h (cc),
552                                                     cc,
553                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
554 }
555
556
557 /**
558  * Remove a @a connection that went via this @a cp.
559  *
560  * @param cp peer via which the @a connection went
561  * @param cc the connection to remove
562  */
563 void
564 GCP_remove_connection (struct CadetPeer *cp,
565                        struct CadetConnection *cc)
566 {
567   GNUNET_assert (GNUNET_YES ==
568                  GNUNET_CONTAINER_multihashmap_remove (cp->connections,
569                                                        GCC_get_h (cc),
570                                                        cc));
571 }
572
573
574 /**
575  * This peer is now on more "active" duty, activate processes related to it.
576  *
577  * @param cp the more-active peer
578  */
579 static void
580 consider_peer_activate (struct CadetPeer *cp)
581 {
582   uint32_t strength;
583
584   if (NULL != cp->destroy_task)
585   {
586     /* It's active, do not destory! */
587     GNUNET_SCHEDULER_cancel (cp->destroy_task);
588     cp->destroy_task = NULL;
589   }
590   if ( (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections)) &&
591        (NULL == cp->t) )
592   {
593     /* We're just on a path or directly connected; don't bother too much */
594     if (NULL != cp->connectivity_suggestion)
595     {
596       GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
597       cp->connectivity_suggestion = NULL;
598     }
599     if (NULL != cp->search_h)
600     {
601       GCD_search_stop (cp->search_h);
602       cp->search_h = NULL;
603     }
604     return;
605   }
606   if (NULL == cp->core_mq)
607   {
608     /* Lacks direct connection, try to create one by querying the DHT */
609     if ( (NULL == cp->search_h) &&
610          (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) )
611       cp->search_h
612         = GCD_search (&cp->pid);
613   }
614   else
615   {
616     /* Have direct connection, stop DHT search if active */
617     if (NULL != cp->search_h)
618     {
619       GCD_search_stop (cp->search_h);
620       cp->search_h = NULL;
621     }
622   }
623
624   /* If we have a tunnel, our urge for connections is much bigger */
625   strength = (NULL != cp->t) ? 32 : 1;
626   if (NULL != cp->connectivity_suggestion)
627     GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
628   cp->connectivity_suggestion
629     = GNUNET_ATS_connectivity_suggest (ats_ch,
630                                        &cp->pid,
631                                        strength);
632 }
633
634
635 /**
636  * Retrieve the CadetPeer stucture associated with the
637  * peer. Optionally create one and insert it in the appropriate
638  * structures if the peer is not known yet.
639  *
640  * @param peer_id Full identity of the peer.
641  * @param create #GNUNET_YES if a new peer should be created if unknown.
642  *               #GNUNET_NO to return NULL if peer is unknown.
643  * @return Existing or newly created peer structure.
644  *         NULL if unknown and not requested @a create
645  */
646 struct CadetPeer *
647 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
648          int create)
649 {
650   struct CadetPeer *cp;
651
652   cp = GNUNET_CONTAINER_multipeermap_get (peers,
653                                           peer_id);
654   if (NULL != cp)
655     return cp;
656   if (GNUNET_NO == create)
657     return NULL;
658   cp = GNUNET_new (struct CadetPeer);
659   cp->pid = *peer_id;
660   cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
661                                                           GNUNET_YES);
662   cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
663   GNUNET_assert (GNUNET_YES ==
664                  GNUNET_CONTAINER_multipeermap_put (peers,
665                                                     &cp->pid,
666                                                     cp,
667                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
668   return cp;
669 }
670
671
672 /**
673  * Obtain the peer identity for a `struct CadetPeer`.
674  *
675  * @param cp our peer handle
676  * @return the peer identity
677  */
678 const struct GNUNET_PeerIdentity *
679 GCP_get_id (struct CadetPeer *cp)
680 {
681   return &cp->pid;
682 }
683
684
685 /**
686  * Iterate over all known peers.
687  *
688  * @param iter Iterator.
689  * @param cls Closure for @c iter.
690  */
691 void
692 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
693                  void *cls)
694 {
695   GNUNET_CONTAINER_multipeermap_iterate (peers,
696                                          iter,
697                                          cls);
698 }
699
700
701 /**
702  * Count the number of known paths toward the peer.
703  *
704  * @param peer Peer to get path info.
705  * @return Number of known paths.
706  */
707 unsigned int
708 GCP_count_paths (const struct CadetPeer *peer)
709 {
710   return peer->num_paths;
711 }
712
713
714 /**
715  * Iterate over the paths to a peer.
716  *
717  * @param peer Peer to get path info.
718  * @param callback Function to call for every path.
719  * @param callback_cls Closure for @a callback.
720  * @return Number of iterated paths.
721  */
722 unsigned int
723 GCP_iterate_paths (struct CadetPeer *peer,
724                    GCP_PathIterator callback,
725                    void *callback_cls)
726 {
727   unsigned int ret = 0;
728
729   for (unsigned int i=0;i<peer->path_dll_length;i++)
730   {
731     for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
732          NULL != pe;
733          pe = pe->next)
734     {
735       if (GNUNET_NO ==
736           callback (callback_cls,
737                     pe->path,
738                     i))
739         return ret;
740       ret++;
741     }
742   }
743   return ret;
744 }
745
746
747 /**
748  * Iterate over the paths to @a peer where
749  * @a peer is at distance @a dist from us.
750  *
751  * @param peer Peer to get path info.
752  * @param dist desired distance of @a peer to us on the path
753  * @param callback Function to call for every path.
754  * @param callback_cls Closure for @a callback.
755  * @return Number of iterated paths.
756  */
757 unsigned int
758 GCP_iterate_paths_at (struct CadetPeer *peer,
759                       unsigned int dist,
760                       GCP_PathIterator callback,
761                       void *callback_cls)
762 {
763   unsigned int ret = 0;
764
765   if (dist<peer->path_dll_length)
766     return 0;
767   for (struct CadetPeerPathEntry *pe = peer->path_heads[dist];
768        NULL != pe;
769        pe = pe->next)
770   {
771     if (GNUNET_NO ==
772         callback (callback_cls,
773                   pe->path,
774                   dist))
775       return ret;
776     ret++;
777   }
778   return ret;
779 }
780
781
782 /**
783  * Get the tunnel towards a peer.
784  *
785  * @param peer Peer to get from.
786  * @param create #GNUNET_YES to create a tunnel if we do not have one
787  * @return Tunnel towards peer.
788  */
789 struct CadetTunnel *
790 GCP_get_tunnel (struct CadetPeer *peer,
791                 int create)
792 {
793   if (NULL == peer)
794     return NULL;
795   if ( (NULL != peer->t) ||
796        (GNUNET_NO == create) )
797     return peer->t;
798   peer->t = GCT_create_tunnel (peer);
799   consider_peer_activate (peer);
800   return peer->t;
801 }
802
803
804 /**
805  * We got a HELLO for a @a peer, remember it, and possibly
806  * trigger adequate actions (like trying to connect).
807  *
808  * @param peer the peer we got a HELLO for
809  * @param hello the HELLO to remember
810  */
811 void
812 GCP_set_hello (struct CadetPeer *peer,
813                const struct GNUNET_HELLO_Message *hello)
814 {
815   /* FIXME: keep HELLO, possibly offer to TRANSPORT... */
816
817   consider_peer_destroy (peer);
818 }
819
820
821 /**
822  * The tunnel to the given peer no longer exists, remove it from our
823  * data structures, and possibly clean up the peer itself.
824  *
825  * @param peer the peer affected
826  * @param t the dead tunnel
827  */
828 void
829 GCP_drop_tunnel (struct CadetPeer *peer,
830                  struct CadetTunnel *t)
831 {
832   GNUNET_assert (peer->t == t);
833   peer->t = NULL;
834   consider_peer_destroy (peer);
835 }
836
837
838 /**
839  * Start message queue change notifications.
840  *
841  * @param cp peer to notify for
842  * @param cb function to call if mq becomes available or unavailable
843  * @param cb_cls closure for @a cb
844  * @return handle to cancel request
845  */
846 struct GCP_MessageQueueManager *
847 GCP_request_mq (struct CadetPeer *cp,
848                 GCP_MessageQueueNotificationCallback cb,
849                 void *cb_cls)
850 {
851   struct GCP_MessageQueueManager *mqm;
852
853   mqm = GNUNET_new (struct GCP_MessageQueueManager);
854   mqm->cb = cb;
855   mqm->cb_cls = cb_cls;
856   mqm->cp = cp;
857   GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
858                                cp->mqm_tail,
859                                mqm);
860   if (NULL != cp->core_mq)
861     cb (cb_cls,
862         cp->core_mq);
863   return mqm;
864 }
865
866
867 /**
868  * Stops message queue change notifications.
869  *
870  * @param mqm handle matching request to cancel
871  */
872 void
873 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm)
874 {
875   struct CadetPeer *cp = mqm->cp;
876
877   GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
878                                cp->mqm_tail,
879                                mqm);
880   GNUNET_free (mqm);
881 }
882
883
884
885 /* end of gnunet-service-cadet-new_peer.c */