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