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