summaryrefslogtreecommitdiff
path: root/src/cadet/gnunet-service-cadet-new_peer.c
diff options
context:
space:
mode:
authorSchanzenbach, Martin <mschanzenbach@posteo.de>2017-01-20 07:00:54 +0100
committerSchanzenbach, Martin <mschanzenbach@posteo.de>2017-01-20 07:00:54 +0100
commit3cb90c74c5f591fd2541d154a8e7b05a1c2f4539 (patch)
tree620638f54539749f2a1b27a5991a90880fe7c14d /src/cadet/gnunet-service-cadet-new_peer.c
parent7122f35e2c00c29b1af31bdd294e93e6fcc84498 (diff)
parentaedd5919e802370061850486c96da72b25df7f22 (diff)
downloadgnunet-3cb90c74c5f591fd2541d154a8e7b05a1c2f4539.tar.gz
gnunet-3cb90c74c5f591fd2541d154a8e7b05a1c2f4539.zip
- merge; service API change
Diffstat (limited to 'src/cadet/gnunet-service-cadet-new_peer.c')
-rw-r--r--src/cadet/gnunet-service-cadet-new_peer.c1056
1 files changed, 1056 insertions, 0 deletions
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c
new file mode 100644
index 000000000..47f725e09
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_peer.c
@@ -0,0 +1,1056 @@
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 * TODO:
29 * - implement GCP_set_hello() / do HELLO advertising properly
30 * - optimize stopping/restarting DHT search to situations
31 * where we actually need it (i.e. not if we have a direct connection,
32 * or if we already have plenty of good short ones, or maybe even
33 * to take a break if we have some connections and have searched a lot (?))
34 * - optimize MQM ready scans (O(n) -> O(1))
35 */
36#include "platform.h"
37#include "gnunet_util_lib.h"
38#include "gnunet_signatures.h"
39#include "gnunet_transport_service.h"
40#include "gnunet_ats_service.h"
41#include "gnunet_core_service.h"
42#include "gnunet_statistics_service.h"
43#include "cadet_protocol.h"
44#include "cadet_path.h"
45#include "gnunet-service-cadet-new.h"
46#include "gnunet-service-cadet-new_connection.h"
47#include "gnunet-service-cadet-new_dht.h"
48#include "gnunet-service-cadet-new_peer.h"
49#include "gnunet-service-cadet-new_paths.h"
50#include "gnunet-service-cadet-new_tunnels.h"
51
52/**
53 * How long do we wait until tearing down an idle peer?
54 */
55#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
56
57/**
58 * How long do we keep paths around if we no longer care about the peer?
59 */
60#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
61
62
63
64
65/**
66 * Data structure used to track whom we have to notify about changes
67 * to our message queue.
68 */
69struct GCP_MessageQueueManager
70{
71
72 /**
73 * Kept in a DLL.
74 */
75 struct GCP_MessageQueueManager *next;
76
77 /**
78 * Kept in a DLL.
79 */
80 struct GCP_MessageQueueManager *prev;
81
82 /**
83 * Function to call with updated message queue object.
84 */
85 GCP_MessageQueueNotificationCallback cb;
86
87 /**
88 * Closure for @e cb.
89 */
90 void *cb_cls;
91
92 /**
93 * The peer this is for.
94 */
95 struct CadetPeer *cp;
96
97 /**
98 * Envelope this manager would like to transmit once it is its turn.
99 */
100 struct GNUNET_MQ_Envelope *env;
101
102};
103
104
105/**
106 * Struct containing all information regarding a given peer
107 */
108struct CadetPeer
109{
110 /**
111 * ID of the peer
112 */
113 struct GNUNET_PeerIdentity pid;
114
115 /**
116 * Last time we heard from this peer
117 */
118 struct GNUNET_TIME_Absolute last_contact;
119
120 /**
121 * Array of DLLs of paths traversing the peer, organized by the
122 * offset of the peer on the larger path.
123 */
124 struct CadetPeerPathEntry **path_heads;
125
126 /**
127 * Array of DLL of paths traversing the peer, organized by the
128 * offset of the peer on the larger path.
129 */
130 struct CadetPeerPathEntry **path_tails;
131
132 /**
133 * Notifications to call when @e core_mq changes.
134 */
135 struct GCP_MessageQueueManager *mqm_head;
136
137 /**
138 * Notifications to call when @e core_mq changes.
139 */
140 struct GCP_MessageQueueManager *mqm_tail;
141
142 /**
143 * MIN-heap of paths owned by this peer (they also end at this
144 * peer). Ordered by desirability.
145 */
146 struct GNUNET_CONTAINER_Heap *path_heap;
147
148 /**
149 * Handle to stop the DHT search for paths to this peer
150 */
151 struct GCD_search_handle *search_h;
152
153 /**
154 * Task to stop the DHT search for paths to this peer
155 */
156 struct GNUNET_SCHEDULER_Task *search_delayedXXX;
157
158 /**
159 * Task to destroy this entry.
160 */
161 struct GNUNET_SCHEDULER_Task *destroy_task;
162
163 /**
164 * Tunnel to this peer, if any.
165 */
166 struct CadetTunnel *t;
167
168 /**
169 * Connections that go through this peer; indexed by tid.
170 */
171 struct GNUNET_CONTAINER_MultiShortmap *connections;
172
173 /**
174 * Handle for core transmissions.
175 */
176 struct GNUNET_MQ_Handle *core_mq;
177
178 /**
179 * Hello message of the peer.
180 */
181 struct GNUNET_HELLO_Message *hello;
182
183 /**
184 * Handle to us offering the HELLO to the transport.
185 */
186 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
187
188 /**
189 * Handle to our ATS request asking ATS to suggest an address
190 * to TRANSPORT for this peer (to establish a direct link).
191 */
192 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
193
194 /**
195 * How many messages are in the queue to this peer.
196 */
197 unsigned int queue_n;
198
199 /**
200 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
201 */
202 unsigned int num_paths;
203
204 /**
205 * Number of message queue managers of this peer that have a message in waiting.
206 *
207 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
208 * TODO: could be replaced by another DLL that would then allow us to avoid
209 * the O(n)-scan of the DLL for ready entries!
210 */
211 unsigned int mqm_ready_counter;
212
213 /**
214 * Current length of the @e path_heads and @path_tails arrays.
215 * The arrays should be grown as needed.
216 */
217 unsigned int path_dll_length;
218
219};
220
221
222/**
223 * Get the static string for a peer ID.
224 *
225 * @param peer Peer.
226 *
227 * @return Static string for it's ID.
228 */
229const char *
230GCP_2s (const struct CadetPeer *peer)
231{
232 if (NULL == peer)
233 return "PEER(NULL)";
234 return GNUNET_i2s (&peer->pid);
235}
236
237
238/**
239 * This peer is no longer be needed, clean it up now.
240 *
241 * @param cls peer to clean up
242 */
243static void
244destroy_peer (void *cls)
245{
246 struct CadetPeer *cp = cls;
247
248 cp->destroy_task = NULL;
249 GNUNET_assert (NULL == cp->t);
250 GNUNET_assert (NULL == cp->core_mq);
251 GNUNET_assert (0 == cp->path_dll_length);
252 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
253 GNUNET_assert (GNUNET_YES ==
254 GNUNET_CONTAINER_multipeermap_remove (peers,
255 &cp->pid,
256 cp));
257 GNUNET_free_non_null (cp->path_heads);
258 GNUNET_free_non_null (cp->path_tails);
259 cp->path_dll_length = 0;
260 if (NULL != cp->search_h)
261 {
262 GCD_search_stop (cp->search_h);
263 cp->search_h = NULL;
264 }
265 /* FIXME: clean up search_delayedXXX! */
266
267 if (NULL != cp->hello_offer)
268 {
269 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
270 cp->hello_offer = NULL;
271 }
272 if (NULL != cp->connectivity_suggestion)
273 {
274 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
275 cp->connectivity_suggestion = NULL;
276 }
277 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
278 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
279 GNUNET_free_non_null (cp->hello);
280 /* Peer should not be freed if paths exist; if there are no paths,
281 there ought to be no connections, and without connections, no
282 notifications. Thus we can assert that mqm_head is empty at this
283 point. */
284 GNUNET_assert (NULL == cp->mqm_head);
285 GNUNET_free (cp);
286}
287
288
289/**
290 * Set the message queue to @a mq for peer @a cp and notify watchers.
291 *
292 * @param cp peer to modify
293 * @param mq message queue to set (can be NULL)
294 */
295void
296GCP_set_mq (struct CadetPeer *cp,
297 struct GNUNET_MQ_Handle *mq)
298{
299 cp->core_mq = mq;
300
301 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
302 NULL != mqm;
303 mqm = mqm->next)
304 {
305 if (NULL == mq)
306 {
307 if (NULL != mqm->env)
308 {
309 GNUNET_MQ_discard (mqm->env);
310 mqm->env = NULL;
311 mqm->cb (mqm->cb_cls,
312 GNUNET_SYSERR);
313 }
314 else
315 {
316 mqm->cb (mqm->cb_cls,
317 GNUNET_NO);
318 }
319 }
320 else
321 {
322 GNUNET_assert (NULL == mqm->env);
323 mqm->cb (mqm->cb_cls,
324 GNUNET_YES);
325 }
326 }
327}
328
329
330/**
331 * Transmit current envelope from this @a mqm.
332 *
333 * @param mqm mqm to transmit message for now
334 */
335static void
336mqm_execute (struct GCP_MessageQueueManager *mqm)
337{
338 struct CadetPeer *cp = mqm->cp;
339
340 /* Move entry to the end of the DLL, to be fair. */
341 if (mqm != cp->mqm_tail)
342 {
343 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
344 cp->mqm_tail,
345 mqm);
346 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
347 cp->mqm_tail,
348 mqm);
349 }
350 GNUNET_MQ_send (cp->core_mq,
351 mqm->env);
352 mqm->env = NULL;
353 cp->mqm_ready_counter--;
354}
355
356
357/**
358 * Function called when CORE took one of the messages from
359 * a message queue manager and transmitted it.
360 *
361 * @param cls the `struct CadetPeeer` where we made progress
362 */
363static void
364mqm_send_done (void *cls)
365{
366 struct CadetPeer *cp = cls;
367
368 if (0 == cp->mqm_ready_counter)
369 return; /* nothing to do */
370 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
371 NULL != mqm;
372 mqm = mqm->next)
373 {
374 if (NULL == mqm->env)
375 continue;
376 mqm_execute (mqm);
377 return;
378 }
379}
380
381
382/**
383 * Send the message in @a env to @a cp.
384 *
385 * @param mqm the message queue manager to use for transmission
386 * @param env envelope with the message to send; must NOT
387 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
388 */
389void
390GCP_send (struct GCP_MessageQueueManager *mqm,
391 struct GNUNET_MQ_Envelope *env)
392{
393 struct CadetPeer *cp = mqm->cp;
394
395 GNUNET_assert (NULL != cp->core_mq);
396 GNUNET_assert (NULL == mqm->env);
397 GNUNET_MQ_notify_sent (env,
398 &mqm_send_done,
399 cp);
400 mqm->env = env;
401 cp->mqm_ready_counter++;
402 if (0 != GNUNET_MQ_get_length (cp->core_mq))
403 return;
404 mqm_execute (mqm);
405}
406
407
408/**
409 * Function called to destroy a peer now.
410 *
411 * @param cls NULL
412 * @param pid identity of the peer (unused)
413 * @param value the `struct CadetPeer` to clean up
414 * @return #GNUNET_OK (continue to iterate)
415 */
416static int
417destroy_iterator_cb (void *cls,
418 const struct GNUNET_PeerIdentity *pid,
419 void *value)
420{
421 struct CadetPeer *cp = value;
422
423 if (NULL != cp->destroy_task)
424 {
425 GNUNET_SCHEDULER_cancel (cp->destroy_task);
426 cp->destroy_task = NULL;
427 }
428 destroy_peer (cp);
429 return GNUNET_OK;
430}
431
432
433/**
434 * Clean up all entries about all peers.
435 * Must only be called after all tunnels, CORE-connections and
436 * connections are down.
437 */
438void
439GCP_destroy_all_peers ()
440{
441 GNUNET_CONTAINER_multipeermap_iterate (peers,
442 &destroy_iterator_cb,
443 NULL);
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 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap))
497 {
498 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
499 &drop_paths,
500 cp);
501 return;
502 }
503 if (0 < cp->path_dll_length)
504 return; /* still relevant! */
505 if (NULL != cp->hello)
506 {
507 /* relevant only until HELLO expires */
508 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
509 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
510 &destroy_peer,
511 cp);
512 return;
513 }
514 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
515 &destroy_peer,
516 cp);
517}
518
519
520/**
521 * Add an entry to the DLL of all of the paths that this peer is on.
522 *
523 * @param cp peer to modify
524 * @param entry an entry on a path
525 * @param off offset of this peer on the path
526 */
527void
528GCP_path_entry_add (struct CadetPeer *cp,
529 struct CadetPeerPathEntry *entry,
530 unsigned int off)
531{
532 if (off >= cp->path_dll_length)
533 {
534 unsigned int len = cp->path_dll_length;
535
536 GNUNET_array_grow (cp->path_heads,
537 len,
538 off + 4);
539 GNUNET_array_grow (cp->path_tails,
540 cp->path_dll_length,
541 off + 4);
542 }
543 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
544 cp->path_tails[off],
545 entry);
546 cp->num_paths++;
547
548 /* If we have a tunnel to this peer, tell the tunnel that there is a
549 new path available. */
550 if (NULL != cp->t)
551 GCT_consider_path (cp->t,
552 entry->path,
553 off);
554}
555
556
557/**
558 * Remove an entry from the DLL of all of the paths that this peer is on.
559 *
560 * @param cp peer to modify
561 * @param entry an entry on a path
562 * @param off offset of this peer on the path
563 */
564void
565GCP_path_entry_remove (struct CadetPeer *cp,
566 struct CadetPeerPathEntry *entry,
567 unsigned int off)
568{
569 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
570 cp->path_tails[off],
571 entry);
572 GNUNET_assert (0 < cp->num_paths);
573 cp->num_paths--;
574}
575
576
577/**
578 * Try adding a @a path to this @a peer. If the peer already
579 * has plenty of paths, return NULL.
580 *
581 * @param cp peer to which the @a path leads to
582 * @param path a path looking for an owner; may not be fully initialized yet!
583 * @param off offset of @a cp in @a path
584 * @return NULL if this peer does not care to become a new owner,
585 * otherwise the node in the peer's path heap for the @a path.
586 */
587struct GNUNET_CONTAINER_HeapNode *
588GCP_attach_path (struct CadetPeer *cp,
589 struct CadetPeerPath *path,
590 unsigned int off)
591{
592 GNUNET_CONTAINER_HeapCostType desirability;
593 struct CadetPeerPath *root;
594 GNUNET_CONTAINER_HeapCostType root_desirability;
595 struct GNUNET_CONTAINER_HeapNode *hn;
596
597 /* FIXME: desirability is not yet initialized; tricky! */
598 desirability = GCPP_get_desirability (path);
599 if (GNUNET_NO ==
600 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
601 (void **) &root,
602 &root_desirability))
603 {
604 root = NULL;
605 root_desirability = 0;
606 }
607
608 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
609 (desirability < root_desirability) )
610 return NULL;
611
612 /* Yes, we'd like to add this path, add to our heap */
613 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
614 (void *) cp,
615 desirability);
616
617 /* Consider maybe dropping other paths because of the new one */
618 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
619 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
620 {
621 /* Now we have way too many, drop least desirable UNLESS it is in use!
622 (Note that this intentionally keeps highly desireable, but currently
623 unused paths around in the hope that we might be able to switch, even
624 if the number of paths exceeds the threshold.) */
625 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
626 if (NULL ==
627 GCPP_get_connection (root,
628 cp,
629 GCPP_get_length (root) - 1))
630 {
631 /* Got plenty of paths to this destination, and this is a low-quality
632 one that we don't care, allow it to die. */
633 GNUNET_assert (root ==
634 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
635 GCPP_release (root);
636 }
637 }
638 return hn;
639}
640
641
642/**
643 * This peer can no longer own @a path as the path
644 * has been extended and a peer further down the line
645 * is now the new owner.
646 *
647 * @param cp old owner of the @a path
648 * @param path path where the ownership is lost
649 * @param hn note in @a cp's path heap that must be deleted
650 */
651void
652GCP_detach_path (struct CadetPeer *cp,
653 struct CadetPeerPath *path,
654 struct GNUNET_CONTAINER_HeapNode *hn)
655{
656 GNUNET_assert (path ==
657 GNUNET_CONTAINER_heap_remove_node (hn));
658}
659
660
661/**
662 * Add a @a connection to this @a cp.
663 *
664 * @param cp peer via which the @a connection goes
665 * @param cc the connection to add
666 */
667void
668GCP_add_connection (struct CadetPeer *cp,
669 struct CadetConnection *cc)
670{
671 GNUNET_assert (GNUNET_OK ==
672 GNUNET_CONTAINER_multishortmap_put (cp->connections,
673 &GCC_get_id (cc)->connection_of_tunnel,
674 cc,
675 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
676}
677
678
679/**
680 * Remove a @a connection that went via this @a cp.
681 *
682 * @param cp peer via which the @a connection went
683 * @param cc the connection to remove
684 */
685void
686GCP_remove_connection (struct CadetPeer *cp,
687 struct CadetConnection *cc)
688{
689 GNUNET_assert (GNUNET_YES ==
690 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
691 &GCC_get_id (cc)->connection_of_tunnel,
692 cc));
693}
694
695
696/**
697 * This peer is now on more "active" duty, activate processes related to it.
698 *
699 * @param cp the more-active peer
700 */
701static void
702consider_peer_activate (struct CadetPeer *cp)
703{
704 uint32_t strength;
705
706 if (NULL != cp->destroy_task)
707 {
708 /* It's active, do not destory! */
709 GNUNET_SCHEDULER_cancel (cp->destroy_task);
710 cp->destroy_task = NULL;
711 }
712 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
713 (NULL == cp->t) )
714 {
715 /* We're just on a path or directly connected; don't bother too much */
716 if (NULL != cp->connectivity_suggestion)
717 {
718 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
719 cp->connectivity_suggestion = NULL;
720 }
721 if (NULL != cp->search_h)
722 {
723 GCD_search_stop (cp->search_h);
724 cp->search_h = NULL;
725 }
726 return;
727 }
728 if (NULL == cp->core_mq)
729 {
730 /* Lacks direct connection, try to create one by querying the DHT */
731 if ( (NULL == cp->search_h) &&
732 (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) )
733 cp->search_h
734 = GCD_search (&cp->pid);
735 }
736 else
737 {
738 /* Have direct connection, stop DHT search if active */
739 if (NULL != cp->search_h)
740 {
741 GCD_search_stop (cp->search_h);
742 cp->search_h = NULL;
743 }
744 }
745
746 /* If we have a tunnel, our urge for connections is much bigger */
747 strength = (NULL != cp->t) ? 32 : 1;
748 if (NULL != cp->connectivity_suggestion)
749 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
750 cp->connectivity_suggestion
751 = GNUNET_ATS_connectivity_suggest (ats_ch,
752 &cp->pid,
753 strength);
754}
755
756
757/**
758 * Retrieve the CadetPeer stucture associated with the
759 * peer. Optionally create one and insert it in the appropriate
760 * structures if the peer is not known yet.
761 *
762 * @param peer_id Full identity of the peer.
763 * @param create #GNUNET_YES if a new peer should be created if unknown.
764 * #GNUNET_NO to return NULL if peer is unknown.
765 * @return Existing or newly created peer structure.
766 * NULL if unknown and not requested @a create
767 */
768struct CadetPeer *
769GCP_get (const struct GNUNET_PeerIdentity *peer_id,
770 int create)
771{
772 struct CadetPeer *cp;
773
774 cp = GNUNET_CONTAINER_multipeermap_get (peers,
775 peer_id);
776 if (NULL != cp)
777 return cp;
778 if (GNUNET_NO == create)
779 return NULL;
780 cp = GNUNET_new (struct CadetPeer);
781 cp->pid = *peer_id;
782 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
783 GNUNET_YES);
784 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
785 GNUNET_assert (GNUNET_YES ==
786 GNUNET_CONTAINER_multipeermap_put (peers,
787 &cp->pid,
788 cp,
789 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
790 return cp;
791}
792
793
794/**
795 * Obtain the peer identity for a `struct CadetPeer`.
796 *
797 * @param cp our peer handle
798 * @return the peer identity
799 */
800const struct GNUNET_PeerIdentity *
801GCP_get_id (struct CadetPeer *cp)
802{
803 return &cp->pid;
804}
805
806
807/**
808 * Iterate over all known peers.
809 *
810 * @param iter Iterator.
811 * @param cls Closure for @c iter.
812 */
813void
814GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
815 void *cls)
816{
817 GNUNET_CONTAINER_multipeermap_iterate (peers,
818 iter,
819 cls);
820}
821
822
823/**
824 * Count the number of known paths toward the peer.
825 *
826 * @param peer Peer to get path info.
827 * @return Number of known paths.
828 */
829unsigned int
830GCP_count_paths (const struct CadetPeer *peer)
831{
832 return peer->num_paths;
833}
834
835
836/**
837 * Iterate over the paths to a peer.
838 *
839 * @param peer Peer to get path info.
840 * @param callback Function to call for every path.
841 * @param callback_cls Closure for @a callback.
842 * @return Number of iterated paths.
843 */
844unsigned int
845GCP_iterate_paths (struct CadetPeer *peer,
846 GCP_PathIterator callback,
847 void *callback_cls)
848{
849 unsigned int ret = 0;
850
851 for (unsigned int i=0;i<peer->path_dll_length;i++)
852 {
853 for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
854 NULL != pe;
855 pe = pe->next)
856 {
857 if (GNUNET_NO ==
858 callback (callback_cls,
859 pe->path,
860 i))
861 return ret;
862 ret++;
863 }
864 }
865 return ret;
866}
867
868
869/**
870 * Iterate over the paths to @a peer where
871 * @a peer is at distance @a dist from us.
872 *
873 * @param peer Peer to get path info.
874 * @param dist desired distance of @a peer to us on the path
875 * @param callback Function to call for every path.
876 * @param callback_cls Closure for @a callback.
877 * @return Number of iterated paths.
878 */
879unsigned int
880GCP_iterate_paths_at (struct CadetPeer *peer,
881 unsigned int dist,
882 GCP_PathIterator callback,
883 void *callback_cls)
884{
885 unsigned int ret = 0;
886
887 if (dist<peer->path_dll_length)
888 return 0;
889 for (struct CadetPeerPathEntry *pe = peer->path_heads[dist];
890 NULL != pe;
891 pe = pe->next)
892 {
893 if (GNUNET_NO ==
894 callback (callback_cls,
895 pe->path,
896 dist))
897 return ret;
898 ret++;
899 }
900 return ret;
901}
902
903
904/**
905 * Get the tunnel towards a peer.
906 *
907 * @param peer Peer to get from.
908 * @param create #GNUNET_YES to create a tunnel if we do not have one
909 * @return Tunnel towards peer.
910 */
911struct CadetTunnel *
912GCP_get_tunnel (struct CadetPeer *peer,
913 int create)
914{
915 if (NULL == peer)
916 return NULL;
917 if ( (NULL != peer->t) ||
918 (GNUNET_NO == create) )
919 return peer->t;
920 peer->t = GCT_create_tunnel (peer);
921 consider_peer_activate (peer);
922 return peer->t;
923}
924
925
926/**
927 * We got a HELLO for a @a peer, remember it, and possibly
928 * trigger adequate actions (like trying to connect).
929 *
930 * @param peer the peer we got a HELLO for
931 * @param hello the HELLO to remember
932 */
933void
934GCP_set_hello (struct CadetPeer *peer,
935 const struct GNUNET_HELLO_Message *hello)
936{
937 /* FIXME: keep HELLO, possibly offer to TRANSPORT... */
938
939 consider_peer_destroy (peer);
940}
941
942
943/**
944 * The tunnel to the given peer no longer exists, remove it from our
945 * data structures, and possibly clean up the peer itself.
946 *
947 * @param peer the peer affected
948 * @param t the dead tunnel
949 */
950void
951GCP_drop_tunnel (struct CadetPeer *peer,
952 struct CadetTunnel *t)
953{
954 GNUNET_assert (peer->t == t);
955 peer->t = NULL;
956 consider_peer_destroy (peer);
957}
958
959
960/**
961 * Test if @a cp has a core-level connection
962 *
963 * @param cp peer to test
964 * @return #GNUNET_YES if @a cp has a core-level connection
965 */
966int
967GCP_has_core_connection (struct CadetPeer *cp)
968{
969 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
970}
971
972
973/**
974 * Start message queue change notifications.
975 *
976 * @param cp peer to notify for
977 * @param cb function to call if mq becomes available or unavailable
978 * @param cb_cls closure for @a cb
979 * @return handle to cancel request
980 */
981struct GCP_MessageQueueManager *
982GCP_request_mq (struct CadetPeer *cp,
983 GCP_MessageQueueNotificationCallback cb,
984 void *cb_cls)
985{
986 struct GCP_MessageQueueManager *mqm;
987
988 mqm = GNUNET_new (struct GCP_MessageQueueManager);
989 mqm->cb = cb;
990 mqm->cb_cls = cb_cls;
991 mqm->cp = cp;
992 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
993 cp->mqm_tail,
994 mqm);
995 if (NULL != cp->core_mq)
996 cb (cb_cls,
997 GNUNET_YES);
998 return mqm;
999}
1000
1001
1002/**
1003 * Stops message queue change notifications.
1004 *
1005 * @param mqm handle matching request to cancel
1006 * @param last_env final message to transmit, or NULL
1007 */
1008void
1009GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1010 struct GNUNET_MQ_Envelope *last_env)
1011{
1012 struct CadetPeer *cp = mqm->cp;
1013
1014 if (NULL != mqm->env)
1015 GNUNET_MQ_discard (mqm->env);
1016 if (NULL != last_env)
1017 {
1018 if (NULL != cp->core_mq)
1019 GNUNET_MQ_send (cp->core_mq,
1020 last_env);
1021 else
1022 GNUNET_MQ_discard (last_env);
1023 }
1024 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1025 cp->mqm_tail,
1026 mqm);
1027 GNUNET_free (mqm);
1028}
1029
1030
1031/**
1032 * Send the message in @a env to @a cp, overriding queueing logic.
1033 * This function should only be used to send error messages outside
1034 * of flow and congestion control, similar to ICMP. Note that
1035 * the envelope may be silently discarded as well.
1036 *
1037 * @param cp peer to send the message to
1038 * @param env envelope with the message to send
1039 */
1040void
1041GCP_send_ooo (struct CadetPeer *cp,
1042 struct GNUNET_MQ_Envelope *env)
1043{
1044 if (NULL == cp->core_mq)
1045 {
1046 GNUNET_MQ_discard (env);
1047 return;
1048 }
1049 GNUNET_MQ_send (cp->core_mq,
1050 env);
1051}
1052
1053
1054
1055
1056/* end of gnunet-service-cadet-new_peer.c */