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