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