aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-tng.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/gnunet-service-tng.c')
-rw-r--r--src/transport/gnunet-service-tng.c11519
1 files changed, 0 insertions, 11519 deletions
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
deleted file mode 100644
index 21aa46947..000000000
--- a/src/transport/gnunet-service-tng.c
+++ /dev/null
@@ -1,11519 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 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 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * Implement next:
27 * - review retransmission logic, right now there is no smartness there!
28 * => congestion control, etc [PERFORMANCE-BASICS]
29 *
30 * Optimizations-Statistics:
31 * - Track ACK losses based on ACK-counter [ROUTING]
32 * - Need to track total bandwidth per VirtualLink and adjust how frequently
33 * we send FC messages based on bandwidth-delay-product (and relation
34 * to the window size!). See OPTIMIZE-FC-BDP.
35 * - Consider more statistics in #check_connection_quality() [FIXME-CONQ-STATISTICS]
36 * - Adapt available_fc_window_size, using larger values for high-bandwidth
37 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
38 * - Set last_window_consum_limit promise properly based on
39 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
40 *
41 * Optimizations-DV:
42 * - When forwarding DV learn messages, if a peer is reached that
43 * has a *bidirectional* link to the origin beyond 1st hop,
44 * do NOT forward it to peers _other_ than the origin, as
45 * there is clearly a better path directly from the origin to
46 * whatever else we could reach.
47 * - When we passively learned DV (with unconfirmed freshness), we
48 * right now add the path to our list but with a zero path_valid_until
49 * time and only use it for unconfirmed routes. However, we could consider
50 * triggering an explicit validation mechanism ourselves, specifically routing
51 * a challenge-response message over the path [ROUTING]
52 * = if available, try to confirm unconfirmed DV paths when trying to establish
53 * virtual link for a `struct IncomingRequest`. (i.e. if DVH is
54 * unconfirmed, incoming requests cause us to try to validate a passively
55 * learned path (requires new message type!))
56 *
57 * Optimizations-Fragmentation:
58 * - Fragments send over a reliable channel could do without the
59 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
60 * (-> have 2nd type of acknowledgment message; low priority, as we
61 * do not have an MTU-limited *reliable* communicator) [FIXME-FRAG-REL-UUID]
62 * - if messages are below MTU, consider adding ACKs and other stuff
63 * to the same transmission to avoid tiny messages (requires planning at
64 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
65 *
66 * Optimizations-internals:
67 * - queue_send_msg by API design has to make a copy
68 * of the payload, and route_message on top of that requires a malloc/free.
69 * Change design to approximate "zero" copy better... [CPU]
70 * - could avoid copying body of message into each fragment and keep
71 * fragments as just pointers into the original message and only
72 * fully build fragments just before transmission (optimization, should
73 * reduce CPU and memory use) [CPU, MEMORY]
74 */
75#include "platform.h"
76#include "gnunet_util_lib.h"
77#include "gnunet_statistics_service.h"
78#include "gnunet_transport_monitor_service.h"
79#include "gnunet_peerstore_service.h"
80#include "gnunet_hello_lib.h"
81#include "gnunet_signatures.h"
82#include "transport.h"
83
84/**
85 * Size of ring buffer to cache CORE and forwarded DVBox messages.
86 */
87#define RING_BUFFER_SIZE 16
88
89/**
90 * Maximum number of FC retransmissions for a running retransmission task.
91 */
92#define MAX_FC_RETRANSMIT_COUNT 1000
93
94/**
95 * Maximum number of messages we acknowledge together in one
96 * cumulative ACK. Larger values may save a bit of bandwidth.
97 */
98#define MAX_CUMMULATIVE_ACKS 64
99
100/**
101 * What is the 1:n chance that we send a Flow control response when
102 * receiving a flow control message that did not change anything for
103 * us? Basically, this is used in the case where both peers are stuck
104 * on flow control (no window changes), but one might continue sending
105 * flow control messages to the other peer as the first FC message
106 * when things stalled got lost, and then subsequently the other peer
107 * does *usually* not respond as nothing changed. So to ensure that
108 * eventually the FC messages stop, we do send with 1/8th probability
109 * an FC message even if nothing changed. That prevents one peer
110 * being stuck in sending (useless) FC messages "forever".
111 */
112#define FC_NO_CHANGE_REPLY_PROBABILITY 8
113
114/**
115 * What is the size we assume for a read operation in the
116 * absence of an MTU for the purpose of flow control?
117 */
118#define IN_PACKET_SIZE_WITHOUT_MTU 128
119
120/**
121 * Number of slots we keep of historic data for computation of
122 * goodput / message loss ratio.
123 */
124#define GOODPUT_AGING_SLOTS 4
125
126/**
127 * How big is the flow control window size by default;
128 * limits per-neighbour RAM utilization.
129 */
130#define DEFAULT_WINDOW_SIZE (128 * 1024)
131
132/**
133 * For how many incoming connections do we try to create a
134 * virtual link for (at the same time!). This does NOT
135 * limit the number of incoming connections, just the number
136 * for which we are actively trying to find working addresses
137 * in the absence (!) of our own applications wanting the
138 * link to go up.
139 */
140#define MAX_INCOMING_REQUEST 16
141
142/**
143 * Maximum number of peers we select for forwarding DVInit
144 * messages at the same time (excluding initiator).
145 */
146#define MAX_DV_DISCOVERY_SELECTION 16
147
148/**
149 * Window size. How many messages to the same target do we pass
150 * to CORE without a RECV_OK in between? Small values limit
151 * thoughput, large values will increase latency.
152 *
153 * FIXME-OPTIMIZE: find out what good values are experimentally,
154 * maybe set adaptively (i.e. to observed available bandwidth).
155 */
156#define RECV_WINDOW_SIZE 4
157
158/**
159 * Minimum number of hops we should forward DV learn messages
160 * even if they are NOT useful for us in hope of looping
161 * back to the initiator?
162 *
163 * FIXME: allow initiator some control here instead?
164 */
165#define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
166
167/**
168 * Maximum DV distance allowed ever.
169 */
170#define MAX_DV_HOPS_ALLOWED 16
171
172/**
173 * Maximum number of DV learning activities we may
174 * have pending at the same time.
175 */
176#define MAX_DV_LEARN_PENDING 64
177
178/**
179 * Maximum number of DV paths we keep simultaneously to the same target.
180 */
181#define MAX_DV_PATHS_TO_TARGET 3
182
183/**
184 * If a queue delays the next message by more than this number
185 * of seconds we log a warning. Note: this is for testing,
186 * the value chosen here might be too aggressively low!
187 */
188#define DELAY_WARN_THRESHOLD \
189 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
190
191/**
192 * If a DVBox could not be forwarded after this number of
193 * seconds we drop it.
194 */
195#define DV_FORWARD_TIMEOUT \
196 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
197
198/**
199 * Default value for how long we wait for reliability ack.
200 */
201#define DEFAULT_ACK_WAIT_DURATION \
202 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
203
204/**
205 * We only consider queues as "quality" connections when
206 * suppressing the generation of DV initiation messages if
207 * the latency of the queue is below this threshold.
208 */
209#define DV_QUALITY_RTT_THRESHOLD \
210 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
211
212/**
213 * How long do we consider a DV path valid if we see no
214 * further updates on it? Note: the value chosen here might be too low!
215 */
216#define DV_PATH_VALIDITY_TIMEOUT \
217 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
218
219/**
220 * How long do we cache backchannel (struct Backtalker) information
221 * after a backchannel goes inactive?
222 */
223#define BACKCHANNEL_INACTIVITY_TIMEOUT \
224 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
225
226/**
227 * How long before paths expire would we like to (re)discover DV paths? Should
228 * be below #DV_PATH_VALIDITY_TIMEOUT.
229 */
230#define DV_PATH_DISCOVERY_FREQUENCY \
231 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
232
233/**
234 * How long are ephemeral keys valid?
235 */
236#define EPHEMERAL_VALIDITY \
237 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
238
239/**
240 * How long do we keep partially reassembled messages around before giving up?
241 */
242#define REASSEMBLY_EXPIRATION \
243 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
244
245/**
246 * What is the fastest rate at which we send challenges *if* we keep learning
247 * an address (gossip, DHT, etc.)?
248 */
249#define FAST_VALIDATION_CHALLENGE_FREQ \
250 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
251
252/**
253 * What is the slowest rate at which we send challenges?
254 */
255#define MAX_VALIDATION_CHALLENGE_FREQ \
256 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
257
258/**
259 * How long until we forget about historic accumulators and thus
260 * reset the ACK counter? Should exceed the maximum time an
261 * active connection experiences without an ACK.
262 */
263#define ACK_CUMMULATOR_TIMEOUT \
264 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
265
266/**
267 * What is the non-randomized base frequency at which we
268 * would initiate DV learn messages?
269 */
270#define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
271
272/**
273 * How many good connections (confirmed, bi-directional, not DV)
274 * do we need to have to suppress initiating DV learn messages?
275 */
276#define DV_LEARN_QUALITY_THRESHOLD 100
277
278/**
279 * When do we forget an invalid address for sure?
280 */
281#define MAX_ADDRESS_VALID_UNTIL \
282 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
283
284/**
285 * How long do we consider an address valid if we just checked?
286 */
287#define ADDRESS_VALIDATION_LIFETIME \
288 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
289
290/**
291 * What is the maximum frequency at which we do address validation?
292 * A random value between 0 and this value is added when scheduling
293 * the #validation_task (both to ensure we do not validate too often,
294 * and to randomize a bit).
295 */
296#define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
297
298/**
299 * How many network RTTs before an address validation expires should we begin
300 * trying to revalidate? (Note that the RTT used here is the one that we
301 * experienced during the last validation, not necessarily the latest RTT
302 * observed).
303 */
304#define VALIDATION_RTT_BUFFER_FACTOR 3
305
306/**
307 * How many messages can we have pending for a given communicator
308 * process before we start to throttle that communicator?
309 *
310 * Used if a communicator might be CPU-bound and cannot handle the traffic.
311 */
312#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
313
314/**
315 * How many messages can we have pending for a given queue (queue to
316 * a particular peer via a communicator) process before we start to
317 * throttle that queue?
318 */
319#define QUEUE_LENGTH_LIMIT 32
320
321
322GNUNET_NETWORK_STRUCT_BEGIN
323
324/**
325 * Unique identifier we attach to a message.
326 */
327struct MessageUUIDP
328{
329 /**
330 * Unique value, generated by incrementing the
331 * `message_uuid_ctr` of `struct Neighbour`.
332 */
333 uint64_t uuid GNUNET_PACKED;
334};
335
336
337/**
338 * Unique identifier to map an acknowledgement to a transmission.
339 */
340struct AcknowledgementUUIDP
341{
342 /**
343 * The UUID value.
344 */
345 struct GNUNET_Uuid value;
346};
347
348/**
349 * Outer layer of an encapsulated backchannel message.
350 */
351struct TransportBackchannelEncapsulationMessage
352{
353 /**
354 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
355 */
356 struct GNUNET_MessageHeader header;
357
358 /* Followed by *another* message header which is the message to
359 the communicator */
360
361 /* Followed by a 0-terminated name of the communicator */
362};
363
364
365/**
366 * Body by which a peer confirms that it is using an ephemeral key.
367 */
368struct EphemeralConfirmationPS
369{
370 /**
371 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
372 */
373 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
374
375 /**
376 * How long is this signature over the ephemeral key valid?
377 *
378 * Note that the receiver MUST IGNORE the absolute time, and only interpret
379 * the value as a mononic time and reject "older" values than the last one
380 * observed. This is necessary as we do not want to require synchronized
381 * clocks and may not have a bidirectional communication channel.
382 *
383 * Even with this, there is no real guarantee against replay achieved here,
384 * unless the latest timestamp is persisted. While persistence should be
385 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
386 * communicators must protect against replay attacks when using backchannel
387 * communication!
388 */
389 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
390
391 /**
392 * Target's peer identity.
393 */
394 struct GNUNET_PeerIdentity target;
395
396 /**
397 * Ephemeral key setup by the sender for @e target, used
398 * to encrypt the payload.
399 */
400 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
401};
402
403
404/**
405 * Plaintext of the variable-size payload that is encrypted
406 * within a `struct TransportBackchannelEncapsulationMessage`
407 */
408struct TransportDVBoxPayloadP
409{
410 /**
411 * Sender's peer identity.
412 */
413 struct GNUNET_PeerIdentity sender;
414
415 /**
416 * Signature of the sender over an
417 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
418 */
419 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
420
421 /**
422 * Current monotonic time of the sending transport service. Used to
423 * detect replayed messages. Note that the receiver should remember
424 * a list of the recently seen timestamps and only reject messages
425 * if the timestamp is in the list, or the list is "full" and the
426 * timestamp is smaller than the lowest in the list.
427 *
428 * Like the @e ephemeral_validity, the list of timestamps per peer should be
429 * persisted to guard against replays after restarts.
430 */
431 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
432
433 /* Followed by a `struct GNUNET_MessageHeader` with a message
434 for the target peer */
435};
436
437
438/**
439 * Outer layer of an encapsulated unfragmented application message sent
440 * over an unreliable channel.
441 */
442struct TransportReliabilityBoxMessage
443{
444 /**
445 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
446 */
447 struct GNUNET_MessageHeader header;
448
449 /**
450 * Number of messages still to be sent before a commulative
451 * ACK is requested. Zero if an ACK is requested immediately.
452 * In NBO. Note that the receiver may send the ACK faster
453 * if it believes that is reasonable.
454 */
455 uint32_t ack_countdown GNUNET_PACKED;
456
457 /**
458 * Unique ID of the message used for signalling receipt of
459 * messages sent over possibly unreliable channels. Should
460 * be a random.
461 */
462 struct AcknowledgementUUIDP ack_uuid;
463};
464
465
466/**
467 * Acknowledgement payload.
468 */
469struct TransportCummulativeAckPayloadP
470{
471 /**
472 * How long was the ACK delayed for generating cumulative ACKs?
473 * Used to calculate the correct network RTT by taking the receipt
474 * time of the ack minus the transmission time of the sender minus
475 * this value.
476 */
477 struct GNUNET_TIME_RelativeNBO ack_delay;
478
479 /**
480 * UUID of a message being acknowledged.
481 */
482 struct AcknowledgementUUIDP ack_uuid;
483};
484
485
486/**
487 * Confirmation that the receiver got a
488 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
489 * confirmation may be transmitted over a completely different queue,
490 * so ACKs are identified by a combination of PID of sender and
491 * message UUID, without the queue playing any role!
492 */
493struct TransportReliabilityAckMessage
494{
495 /**
496 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
497 */
498 struct GNUNET_MessageHeader header;
499
500 /**
501 * Counter of ACKs transmitted by the sender to us. Incremented
502 * by one for each ACK, used to detect how many ACKs were lost.
503 */
504 uint32_t ack_counter GNUNET_PACKED;
505
506 /* followed by any number of `struct TransportCummulativeAckPayloadP`
507 messages providing ACKs */
508};
509
510
511/**
512 * Outer layer of an encapsulated fragmented application message.
513 */
514struct TransportFragmentBoxMessage
515{
516 /**
517 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
518 */
519 struct GNUNET_MessageHeader header;
520
521 /**
522 * Offset of this fragment in the overall message.
523 */
524 uint16_t frag_off GNUNET_PACKED;
525
526 /**
527 * Total size of the message that is being fragmented.
528 */
529 uint16_t msg_size GNUNET_PACKED;
530
531 /**
532 * Unique ID of this fragment (and fragment transmission!). Will
533 * change even if a fragment is retransmitted to make each
534 * transmission attempt unique! If a client receives a duplicate
535 * fragment (same @e frag_off for same @a msg_uuid, it must send
536 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
537 */
538 struct AcknowledgementUUIDP ack_uuid;
539
540 /**
541 * Original message ID for of the message that all the fragments
542 * belong to. Must be the same for all fragments.
543 */
544 struct MessageUUIDP msg_uuid;
545};
546
547
548/**
549 * Content signed by the initator during DV learning.
550 *
551 * The signature is required to prevent DDoS attacks. A peer sending out this
552 * message is potentially generating a lot of traffic that will go back to the
553 * initator, as peers receiving this message will try to let the initiator
554 * know that they got the message.
555 *
556 * Without this signature, an attacker could abuse this mechanism for traffic
557 * amplification, sending a lot of traffic to a peer by putting out this type
558 * of message with the victim's peer identity.
559 *
560 * Even with just a signature, traffic amplification would be possible via
561 * replay attacks. The @e monotonic_time limits such replay attacks, as every
562 * potential amplificator will check the @e monotonic_time and only respond
563 * (at most) once per message.
564 */
565struct DvInitPS
566{
567 /**
568 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
569 */
570 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
571
572 /**
573 * Time at the initiator when generating the signature.
574 *
575 * Note that the receiver MUST IGNORE the absolute time, and only interpret
576 * the value as a mononic time and reject "older" values than the last one
577 * observed. This is necessary as we do not want to require synchronized
578 * clocks and may not have a bidirectional communication channel.
579 *
580 * Even with this, there is no real guarantee against replay achieved here,
581 * unless the latest timestamp is persisted. Persistence should be
582 * provided via PEERSTORE if possible.
583 */
584 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
585
586 /**
587 * Challenge value used by the initiator to re-identify the path.
588 */
589 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
590};
591
592
593/**
594 * Content signed by each peer during DV learning.
595 *
596 * This assues the initiator of the DV learning operation that the hop from @e
597 * pred via the signing peer to @e succ actually exists. This makes it
598 * impossible for an adversary to supply the network with bogus routes.
599 *
600 * The @e challenge is included to provide replay protection for the
601 * initiator. This way, the initiator knows that the hop existed after the
602 * original @e challenge was first transmitted, providing a freshness metric.
603 *
604 * Peers other than the initiator that passively learn paths by observing
605 * these messages do NOT benefit from this. Here, an adversary may indeed
606 * replay old messages. Thus, passively learned paths should always be
607 * immediately marked as "potentially stale".
608 */
609struct DvHopPS
610{
611 /**
612 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
613 */
614 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
615
616 /**
617 * Identity of the previous peer on the path.
618 */
619 struct GNUNET_PeerIdentity pred;
620
621 /**
622 * Identity of the next peer on the path.
623 */
624 struct GNUNET_PeerIdentity succ;
625
626 /**
627 * Challenge value used by the initiator to re-identify the path.
628 */
629 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
630};
631
632
633/**
634 * An entry describing a peer on a path in a
635 * `struct TransportDVLearnMessage` message.
636 */
637struct DVPathEntryP
638{
639 /**
640 * Identity of a peer on the path.
641 */
642 struct GNUNET_PeerIdentity hop;
643
644 /**
645 * Signature of this hop over the path, of purpose
646 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
647 */
648 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
649};
650
651
652/**
653 * Internal message used by transport for distance vector learning.
654 * If @e num_hops does not exceed the threshold, peers should append
655 * themselves to the peer list and flood the message (possibly only
656 * to a subset of their neighbours to limit discoverability of the
657 * network topology). To the extend that the @e bidirectional bits
658 * are set, peers may learn the inverse paths even if they did not
659 * initiate.
660 *
661 * Unless received on a bidirectional queue and @e num_hops just
662 * zero, peers that can forward to the initator should always try to
663 * forward to the initiator.
664 */
665struct TransportDVLearnMessage
666{
667 /**
668 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
669 */
670 struct GNUNET_MessageHeader header;
671
672 /**
673 * Number of hops this messages has travelled, in NBO. Zero if
674 * sent by initiator.
675 */
676 uint16_t num_hops GNUNET_PACKED;
677
678 /**
679 * Bitmask of the last 16 hops indicating whether they are confirmed
680 * available (without DV) in both directions or not, in NBO. Used
681 * to possibly instantly learn a path in both directions. Each peer
682 * should shift this value by one to the left, and then set the
683 * lowest bit IF the current sender can be reached from it (without
684 * DV routing).
685 */
686 uint16_t bidirectional GNUNET_PACKED;
687
688 /**
689 * Peers receiving this message and delaying forwarding to other
690 * peers for any reason should increment this value by the non-network
691 * delay created by the peer.
692 */
693 struct GNUNET_TIME_RelativeNBO non_network_delay;
694
695 /**
696 * Time at the initiator when generating the signature.
697 *
698 * Note that the receiver MUST IGNORE the absolute time, and only interpret
699 * the value as a mononic time and reject "older" values than the last one
700 * observed. This is necessary as we do not want to require synchronized
701 * clocks and may not have a bidirectional communication channel.
702 *
703 * Even with this, there is no real guarantee against replay achieved here,
704 * unless the latest timestamp is persisted. Persistence should be
705 * provided via PEERSTORE if possible.
706 */
707 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
708
709 /**
710 * Signature of this hop over the path, of purpose
711 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
712 */
713 struct GNUNET_CRYPTO_EddsaSignature init_sig;
714
715 /**
716 * Identity of the peer that started this learning activity.
717 */
718 struct GNUNET_PeerIdentity initiator;
719
720 /**
721 * Challenge value used by the initiator to re-identify the path.
722 */
723 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
724
725 /* Followed by @e num_hops `struct DVPathEntryP` values,
726 excluding the initiator of the DV trace; the last entry is the
727 current sender; the current peer must not be included. */
728};
729
730
731/**
732 * Outer layer of an encapsulated message send over multiple hops.
733 * The path given only includes the identities of the subsequent
734 * peers, i.e. it will be empty if we are the receiver. Each
735 * forwarding peer should scan the list from the end, and if it can,
736 * forward to the respective peer. The list should then be shortened
737 * by all the entries up to and including that peer. Each hop should
738 * also increment @e total_hops to allow the receiver to get a precise
739 * estimate on the number of hops the message travelled. Senders must
740 * provide a learned path that thus should work, but intermediaries
741 * know of a shortcut, they are allowed to send the message via that
742 * shortcut.
743 *
744 * If a peer finds itself still on the list, it must drop the message.
745 *
746 * The payload of the box can only be decrypted and verified by the
747 * ultimate receiver. Intermediaries do not learn the sender's
748 * identity and the path the message has taken. However, the first
749 * hop does learn the sender as @e total_hops would be zero and thus
750 * the predecessor must be the origin (so this is not really useful
751 * for anonymization).
752 */
753struct TransportDVBoxMessage
754{
755 /**
756 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
757 */
758 struct GNUNET_MessageHeader header;
759
760 /**
761 * Flag if the payload is a control message. In NBO.
762 */
763 unsigned int without_fc;
764
765 /**
766 * Number of total hops this messages travelled. In NBO.
767 * @e origin sets this to zero, to be incremented at
768 * each hop. Peers should limit the @e total_hops value
769 * they accept from other peers.
770 */
771 uint16_t total_hops GNUNET_PACKED;
772
773 /**
774 * Number of hops this messages includes. In NBO. Reduced by one
775 * or more at each hop. Peers should limit the @e num_hops value
776 * they accept from other peers.
777 */
778 uint16_t num_hops GNUNET_PACKED;
779
780 /**
781 * Ephemeral key setup by the sender for target, used to encrypt the
782 * payload. Intermediaries must not change this value.
783 */
784 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
785
786 /**
787 * We use an IV here as the @e ephemeral_key is re-used for
788 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
789 * Intermediaries must not change this value.
790 */
791 struct GNUNET_ShortHashCode iv;
792
793 /**
794 * HMAC over the ciphertext of the encrypted, variable-size body
795 * that follows. Verified via DH of target and @e ephemeral_key.
796 * Intermediaries must not change this value.
797 */
798 struct GNUNET_HashCode hmac;
799
800 /**
801 * Size this msg had initially. This is needed to calculate the hmac at the target.
802 * The header size can not be used for that, because the box size is getting smaller at each hop.
803 *
804 */
805 uint16_t orig_size GNUNET_PACKED;
806
807 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
808 excluding the @e origin and the current peer, the last must be
809 the ultimate target; if @e num_hops is zero, the receiver of this
810 message is the ultimate target. */
811
812 /* Followed by encrypted, variable-size payload, which
813 must begin with a `struct TransportDVBoxPayloadP` */
814
815 /* Followed by the actual message, which itself must not be a
816 a DV_LEARN or DV_BOX message! */
817};
818
819
820/**
821 * Message send to another peer to validate that it can indeed
822 * receive messages at a particular address.
823 */
824struct TransportValidationChallengeMessage
825{
826 /**
827 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
828 */
829 struct GNUNET_MessageHeader header;
830
831 /**
832 * Always zero.
833 */
834 uint32_t reserved GNUNET_PACKED;
835
836 /**
837 * Challenge to be signed by the receiving peer.
838 */
839 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
840
841 /**
842 * Timestamp of the sender, to be copied into the reply to allow
843 * sender to calculate RTT. Must be monotonically increasing!
844 */
845 struct GNUNET_TIME_AbsoluteNBO sender_time;
846};
847
848
849/**
850 * Message signed by a peer to confirm that it can indeed
851 * receive messages at a particular address.
852 */
853struct TransportValidationPS
854{
855 /**
856 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
857 */
858 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
859
860 /**
861 * How long does the sender believe the address on
862 * which the challenge was received to remain valid?
863 */
864 struct GNUNET_TIME_RelativeNBO validity_duration;
865
866 /**
867 * Challenge signed by the receiving peer.
868 */
869 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
870};
871
872
873/**
874 * Message send to a peer to respond to a
875 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
876 */
877struct TransportValidationResponseMessage
878{
879 /**
880 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
881 */
882 struct GNUNET_MessageHeader header;
883
884 /**
885 * Always zero.
886 */
887 uint32_t reserved GNUNET_PACKED;
888
889 /**
890 * The peer's signature matching the
891 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
892 */
893 struct GNUNET_CRYPTO_EddsaSignature signature;
894
895 /**
896 * The challenge that was signed by the receiving peer.
897 */
898 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
899
900 /**
901 * Original timestamp of the sender (was @code{sender_time}),
902 * copied into the reply to allow sender to calculate RTT.
903 */
904 struct GNUNET_TIME_AbsoluteNBO origin_time;
905
906 /**
907 * How long does the sender believe this address to remain
908 * valid?
909 */
910 struct GNUNET_TIME_RelativeNBO validity_duration;
911};
912
913
914/**
915 * Message for Transport-to-Transport Flow control. Specifies the size
916 * of the flow control window, including how much we believe to have
917 * consumed (at transmission time), how much we believe to be allowed
918 * (at transmission time), and how much the other peer is allowed to
919 * send to us, and how much data we already received from the other
920 * peer.
921 */
922struct TransportFlowControlMessage
923{
924 /**
925 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
926 */
927 struct GNUNET_MessageHeader header;
928
929 /**
930 * Sequence number of the flow control message. Incremented by one
931 * for each message. Starts at zero when a virtual link goes up.
932 * Used to detect one-sided connection drops. On wrap-around, the
933 * flow control counters will be reset as if the connection had
934 * dropped.
935 */
936 uint32_t seq GNUNET_PACKED;
937
938 /**
939 * Flow control window size in bytes, in NBO.
940 * The receiver can send this many bytes at most.
941 */
942 uint64_t inbound_window_size GNUNET_PACKED;
943
944 /**
945 * How many bytes has the sender sent that count for flow control at
946 * this time. Used to allow the receiver to estimate the packet
947 * loss rate.
948 */
949 uint64_t outbound_sent GNUNET_PACKED;
950
951 /**
952 * Latest flow control window size we learned from the other peer,
953 * in bytes, in NBO. We are limited to sending at most this many
954 * bytes to the other peer. May help the other peer detect when
955 * flow control messages were lost and should thus be retransmitted.
956 * In particular, if the delta to @e outbound_sent is too small,
957 * this signals that we are stalled.
958 */
959 uint64_t outbound_window_size GNUNET_PACKED;
960
961 /**
962 * Timestamp of the sender. Must be monotonically increasing!
963 * Used to enable receiver to ignore out-of-order packets in
964 * combination with the @e seq. Note that @e seq will go down
965 * (back to zero) whenever either side believes the connection
966 * was dropped, allowing the peers to detect that they need to
967 * reset the counters for the number of bytes sent!
968 */
969 struct GNUNET_TIME_AbsoluteNBO sender_time;
970};
971
972
973GNUNET_NETWORK_STRUCT_END
974
975
976/**
977 * What type of client is the `struct TransportClient` about?
978 */
979enum ClientType
980{
981 /**
982 * We do not know yet (client is fresh).
983 */
984 CT_NONE = 0,
985
986 /**
987 * Is the CORE service, we need to forward traffic to it.
988 */
989 CT_CORE = 1,
990
991 /**
992 * It is a monitor, forward monitor data.
993 */
994 CT_MONITOR = 2,
995
996 /**
997 * It is a communicator, use for communication.
998 */
999 CT_COMMUNICATOR = 3,
1000
1001 /**
1002 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
1003 */
1004 CT_APPLICATION = 4
1005};
1006
1007
1008/**
1009 * Which transmission options are allowable for transmission?
1010 * Interpreted bit-wise!
1011 */
1012enum RouteMessageOptions
1013{
1014 /**
1015 * Only confirmed, non-DV direct neighbours.
1016 */
1017 RMO_NONE = 0,
1018
1019 /**
1020 * We are allowed to use DV routing for this @a hdr
1021 */
1022 RMO_DV_ALLOWED = 1,
1023
1024 /**
1025 * We are allowed to use unconfirmed queues or DV routes for this message
1026 */
1027 RMO_UNCONFIRMED_ALLOWED = 2,
1028
1029 /**
1030 * Reliable and unreliable, DV and non-DV are all acceptable.
1031 */
1032 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1033
1034 /**
1035 * If we have multiple choices, it is OK to send this message
1036 * over multiple channels at the same time to improve loss tolerance.
1037 * (We do at most 2 transmissions.)
1038 */
1039 RMO_REDUNDANT = 4
1040};
1041
1042
1043/**
1044 * When did we launch this DV learning activity?
1045 */
1046struct LearnLaunchEntry
1047{
1048 /**
1049 * Kept (also) in a DLL sorted by launch time.
1050 */
1051 struct LearnLaunchEntry *prev;
1052
1053 /**
1054 * Kept (also) in a DLL sorted by launch time.
1055 */
1056 struct LearnLaunchEntry *next;
1057
1058 /**
1059 * Challenge that uniquely identifies this activity.
1060 */
1061 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
1062
1063 /**
1064 * When did we transmit the DV learn message (used to calculate RTT) and
1065 * determine freshness of paths learned via this operation.
1066 */
1067 struct GNUNET_TIME_Absolute launch_time;
1068};
1069
1070
1071/**
1072 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1073 * (or current) transmission performance.
1074 */
1075struct TransmissionHistoryEntry
1076{
1077 /**
1078 * Number of bytes actually sent in the interval.
1079 */
1080 uint64_t bytes_sent;
1081
1082 /**
1083 * Number of bytes received and acknowledged by the other peer in
1084 * the interval.
1085 */
1086 uint64_t bytes_received;
1087};
1088
1089
1090/**
1091 * Performance data for a transmission possibility.
1092 */
1093struct PerformanceData
1094{
1095 /**
1096 * Weighted average for the RTT.
1097 */
1098 struct GNUNET_TIME_Relative aged_rtt;
1099
1100 /**
1101 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1102 * entries.
1103 */
1104 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1105
1106 /**
1107 * What was the last age when we wrote to @e the? Used to clear
1108 * old entries when the age advances.
1109 */
1110 unsigned int last_age;
1111};
1112
1113
1114/**
1115 * Client connected to the transport service.
1116 */
1117struct TransportClient;
1118
1119/**
1120 * A neighbour that at least one communicator is connected to.
1121 */
1122struct Neighbour;
1123
1124/**
1125 * Entry in our #dv_routes table, representing a (set of) distance
1126 * vector routes to a particular peer.
1127 */
1128struct DistanceVector;
1129
1130/**
1131 * A queue is a message queue provided by a communicator
1132 * via which we can reach a particular neighbour.
1133 */
1134struct Queue;
1135
1136/**
1137 * Message awaiting transmission. See detailed comments below.
1138 */
1139struct PendingMessage;
1140
1141/**
1142 * One possible hop towards a DV target.
1143 */
1144struct DistanceVectorHop;
1145
1146/**
1147 * A virtual link is another reachable peer that is known to CORE. It
1148 * can be either a `struct Neighbour` with at least one confirmed
1149 * `struct Queue`, or a `struct DistanceVector` with at least one
1150 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1151 * data that is per neighbour that is not specific to how the
1152 * connectivity is established.
1153 */
1154struct VirtualLink;
1155
1156
1157/**
1158 * Context from #handle_incoming_msg(). Closure for many
1159 * message handlers below.
1160 */
1161struct CommunicatorMessageContext
1162{
1163 /**
1164 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1165 * flow control to unchoke.
1166 */
1167 struct CommunicatorMessageContext *next;
1168
1169 /**
1170 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1171 * flow control to unchoke.
1172 */
1173 struct CommunicatorMessageContext *prev;
1174
1175 /**
1176 * Which communicator provided us with the message.
1177 */
1178 struct TransportClient *tc;
1179
1180 /**
1181 * Additional information for flow control and about the sender.
1182 */
1183 struct GNUNET_TRANSPORT_IncomingMessage im;
1184
1185 /**
1186 * The message to demultiplex.
1187 */
1188 const struct GNUNET_MessageHeader *mh;
1189
1190 /**
1191 * Number of hops the message has travelled (if DV-routed).
1192 * FIXME: make use of this in ACK handling!
1193 */
1194 uint16_t total_hops;
1195};
1196
1197
1198/**
1199 * Entry for the ring buffer caching messages send to core, when virtual link is avaliable.
1200 **/
1201struct RingBufferEntry
1202{
1203 /**
1204 * Communicator context for this ring buffer entry.
1205 **/
1206 struct CommunicatorMessageContext *cmc;
1207
1208 /**
1209 * The message in this entry.
1210 **/
1211 struct GNUNET_MessageHeader *mh;
1212};
1213
1214
1215/**
1216 * Closure for #core_env_sent_cb.
1217 */
1218struct CoreSentContext
1219{
1220 /**
1221 * Kept in a DLL to clear @e vl in case @e vl is lost.
1222 */
1223 struct CoreSentContext *next;
1224
1225 /**
1226 * Kept in a DLL to clear @e vl in case @e vl is lost.
1227 */
1228 struct CoreSentContext *prev;
1229
1230 /**
1231 * Virtual link this is about.
1232 */
1233 struct VirtualLink *vl;
1234
1235 /**
1236 * How big was the message.
1237 */
1238 uint16_t size;
1239
1240 /**
1241 * By how much should we increment @e vl's
1242 * incoming_fc_window_size_used once we are done sending to CORE?
1243 * Use to ensure we do not increment twice if there is more than one
1244 * CORE client.
1245 */
1246 uint16_t isize;
1247};
1248
1249
1250/**
1251 * Information we keep for a message that we are reassembling.
1252 */
1253struct ReassemblyContext
1254{
1255 /**
1256 * Original message ID for of the message that all the fragments
1257 * belong to.
1258 */
1259 struct MessageUUIDP msg_uuid;
1260
1261 /**
1262 * Which neighbour is this context for?
1263 */
1264 struct VirtualLink *virtual_link;
1265
1266 /**
1267 * Entry in the reassembly heap (sorted by expiration).
1268 */
1269 struct GNUNET_CONTAINER_HeapNode *hn;
1270
1271 /**
1272 * Bitfield with @e msg_size bits representing the positions
1273 * where we have received fragments. When we receive a fragment,
1274 * we check the bits in @e bitfield before incrementing @e msg_missing.
1275 *
1276 * Allocated after the reassembled message.
1277 */
1278 uint8_t *bitfield;
1279
1280 /**
1281 * At what time will we give up reassembly of this message?
1282 */
1283 struct GNUNET_TIME_Absolute reassembly_timeout;
1284
1285 /**
1286 * Time we received the last fragment. @e avg_ack_delay must be
1287 * incremented by now - @e last_frag multiplied by @e num_acks.
1288 */
1289 struct GNUNET_TIME_Absolute last_frag;
1290
1291 /**
1292 * How big is the message we are reassembling in total?
1293 */
1294 uint16_t msg_size;
1295
1296 /**
1297 * How many bytes of the message are still missing? Defragmentation
1298 * is complete when @e msg_missing == 0.
1299 */
1300 uint16_t msg_missing;
1301
1302 /* Followed by @e msg_size bytes of the (partially) defragmented original
1303 * message */
1304
1305 /* Followed by @e bitfield data */
1306};
1307
1308
1309/**
1310 * A virtual link is another reachable peer that is known to CORE. It
1311 * can be either a `struct Neighbour` with at least one confirmed
1312 * `struct Queue`, or a `struct DistanceVector` with at least one
1313 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1314 * data that is per neighbour that is not specific to how the
1315 * connectivity is established.
1316 */
1317struct VirtualLink
1318{
1319 /**
1320 * Identity of the peer at the other end of the link.
1321 */
1322 struct GNUNET_PeerIdentity target;
1323
1324 /**
1325 * Map with `struct ReassemblyContext` structs for fragments under
1326 * reassembly. May be NULL if we currently have no fragments from
1327 * this @e pid (lazy initialization).
1328 */
1329 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1330
1331 /**
1332 * Heap with `struct ReassemblyContext` structs for fragments under
1333 * reassembly. May be NULL if we currently have no fragments from
1334 * this @e pid (lazy initialization).
1335 */
1336 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1337
1338 /**
1339 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1340 */
1341 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1342
1343 /**
1344 * Communicators blocked for receiving on @e target as we are waiting
1345 * on the @e core_recv_window to increase.
1346 */
1347 struct CommunicatorMessageContext *cmc_head;
1348
1349 /**
1350 * Communicators blocked for receiving on @e target as we are waiting
1351 * on the @e core_recv_window to increase.
1352 */
1353 struct CommunicatorMessageContext *cmc_tail;
1354
1355 /**
1356 * Head of list of messages pending for this VL.
1357 */
1358 struct PendingMessage *pending_msg_head;
1359
1360 /**
1361 * Tail of list of messages pending for this VL.
1362 */
1363 struct PendingMessage *pending_msg_tail;
1364
1365 /**
1366 * Kept in a DLL to clear @e vl in case @e vl is lost.
1367 */
1368 struct CoreSentContext *csc_tail;
1369
1370 /**
1371 * Kept in a DLL to clear @e vl in case @e vl is lost.
1372 */
1373 struct CoreSentContext *csc_head;
1374
1375 /**
1376 * Task scheduled to possibly notfiy core that this peer is no
1377 * longer counting as confirmed. Runs the #core_visibility_check(),
1378 * which checks that some DV-path or a queue exists that is still
1379 * considered confirmed.
1380 */
1381 struct GNUNET_SCHEDULER_Task *visibility_task;
1382
1383 /**
1384 * Task scheduled to periodically retransmit FC messages (in
1385 * case one got lost).
1386 */
1387 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1388
1389 /**
1390 * Number of FC retransmissions for this running task.
1391 */
1392 unsigned int fc_retransmit_count;
1393
1394 /**
1395 * Is this VirtualLink confirmed.
1396 * A unconfirmed VirtualLink might exist, if we got a FC from that target.
1397 */
1398 unsigned int confirmed;
1399
1400 /**
1401 * Neighbour used by this virtual link, NULL if @e dv is used.
1402 */
1403 struct Neighbour *n;
1404
1405 /**
1406 * Distance vector used by this virtual link, NULL if @e n is used.
1407 */
1408 struct DistanceVector *dv;
1409
1410 /**
1411 * Sender timestamp of @e n_challenge, used to generate out-of-order
1412 * challenges (as sender's timestamps must be monotonically
1413 * increasing). FIXME: where do we need this?
1414 */
1415 struct GNUNET_TIME_Absolute n_challenge_time;
1416
1417 /**
1418 * When did we last send a
1419 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1420 * Used to determine whether it is time to re-transmit the message.
1421 */
1422 struct GNUNET_TIME_Absolute last_fc_transmission;
1423
1424 /**
1425 * Sender timestamp of the last
1426 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1427 * received. Note that we do not persist this monotonic time as we
1428 * do not really have to worry about ancient flow control window
1429 * sizes after restarts.
1430 */
1431 struct GNUNET_TIME_Absolute last_fc_timestamp;
1432
1433 /**
1434 * Expected RTT from the last FC transmission. (Zero if the last
1435 * attempt failed, but could theoretically be zero even on success.)
1436 */
1437 struct GNUNET_TIME_Relative last_fc_rtt;
1438
1439 /**
1440 * Used to generate unique UUIDs for messages that are being
1441 * fragmented.
1442 */
1443 uint64_t message_uuid_ctr;
1444
1445 /**
1446 * Memory allocated for this virtual link. Expresses how much RAM
1447 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1448 * Can be adapted to dedicate more RAM to links that need it, while
1449 * sticking to some overall RAM limit. For now, set to
1450 * #DEFAULT_WINDOW_SIZE.
1451 */
1452 uint64_t available_fc_window_size;
1453
1454 /**
1455 * Memory actually used to buffer packets on this virtual link.
1456 * Expresses how much RAM we are currently using for virtual link.
1457 * Note that once CORE is done with a packet, we decrement the value
1458 * here.
1459 */
1460 uint64_t incoming_fc_window_size_ram;
1461
1462 /**
1463 * Last flow control window size we provided to the other peer, in
1464 * bytes. We are allowing the other peer to send this
1465 * many bytes.
1466 */
1467 uint64_t incoming_fc_window_size;
1468
1469 /**
1470 * How much of the window did the other peer successfully use (and
1471 * we already passed it on to CORE)? Must be below @e
1472 * incoming_fc_window_size. We should effectively signal the
1473 * other peer that the window is this much bigger at the next
1474 * opportunity / challenge.
1475 */
1476 uint64_t incoming_fc_window_size_used;
1477
1478 /**
1479 * What is our current estimate on the message loss rate for the sender?
1480 * Based on the difference between how much the sender sent according
1481 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1482 * (@e outbound_sent field) and how much we actually received at that
1483 * time (@e incoming_fc_window_size_used). This delta is then
1484 * added onto the @e incoming_fc_window_size when determining the
1485 * @e outbound_window_size we send to the other peer. Initially zero.
1486 * May be negative if we (due to out-of-order delivery) actually received
1487 * more than the sender claims to have sent in its last FC message.
1488 */
1489 int64_t incoming_fc_window_size_loss;
1490
1491 /**
1492 * Our current flow control window size in bytes. We
1493 * are allowed to transmit this many bytes to @a n.
1494 */
1495 uint64_t outbound_fc_window_size;
1496
1497 /**
1498 * How much of our current flow control window size have we
1499 * used (in bytes). Must be below
1500 * @e outbound_fc_window_size.
1501 */
1502 uint64_t outbound_fc_window_size_used;
1503
1504 /**
1505 * What is the most recent FC window the other peer sent us
1506 * in `outbound_window_size`? This is basically the window
1507 * size value the other peer has definitively received from
1508 * us. If it matches @e incoming_fc_window_size, we should
1509 * not send a FC message to increase the FC window. However,
1510 * we may still send an FC message to notify the other peer
1511 * that we received the other peer's FC message.
1512 */
1513 uint64_t last_outbound_window_size_received;
1514
1515 /**
1516 * Generator for the sequence numbers of
1517 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1518 */
1519 uint32_t fc_seq_gen;
1520
1521 /**
1522 * Last sequence number of a
1523 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1524 * received.
1525 */
1526 uint32_t last_fc_seq;
1527
1528 /**
1529 * How many more messages can we send to CORE before we exhaust
1530 * the receive window of CORE for this peer? If this hits zero,
1531 * we must tell communicators to stop providing us more messages
1532 * for this peer. In fact, the window can go negative as we
1533 * have multiple communicators, so per communicator we can go
1534 * down by one into the negative range. Furthermore, we count
1535 * delivery per CORE client, so if we had multiple cores, that
1536 * might also cause a negative window size here (as one message
1537 * would decrement the window by one per CORE client).
1538 */
1539 int core_recv_window;
1540};
1541
1542
1543/**
1544 * Data structure kept when we are waiting for an acknowledgement.
1545 */
1546struct PendingAcknowledgement
1547{
1548 /**
1549 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1550 * is kept in relation to its pending message.
1551 */
1552 struct PendingAcknowledgement *next_pm;
1553
1554 /**
1555 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1556 * is kept in relation to its pending message.
1557 */
1558 struct PendingAcknowledgement *prev_pm;
1559
1560 /**
1561 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1562 * is kept in relation to the queue that was used to transmit the
1563 * @a pm.
1564 */
1565 struct PendingAcknowledgement *next_queue;
1566
1567 /**
1568 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1569 * is kept in relation to the queue that was used to transmit the
1570 * @a pm.
1571 */
1572 struct PendingAcknowledgement *prev_queue;
1573
1574 /**
1575 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1576 * is kept in relation to the DVH that was used to transmit the
1577 * @a pm.
1578 */
1579 struct PendingAcknowledgement *next_dvh;
1580
1581 /**
1582 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1583 * is kept in relation to the DVH that was used to transmit the
1584 * @a pm.
1585 */
1586 struct PendingAcknowledgement *prev_dvh;
1587
1588 /**
1589 * Pointers for the DLL of all pending acknowledgements.
1590 * This list is sorted by @e transmission time. If the list gets too
1591 * long, the oldest entries are discarded.
1592 */
1593 struct PendingAcknowledgement *next_pa;
1594
1595 /**
1596 * Pointers for the DLL of all pending acknowledgements.
1597 * This list is sorted by @e transmission time. If the list gets too
1598 * long, the oldest entries are discarded.
1599 */
1600 struct PendingAcknowledgement *prev_pa;
1601
1602 /**
1603 * Unique identifier for this transmission operation.
1604 */
1605 struct AcknowledgementUUIDP ack_uuid;
1606
1607 /**
1608 * Message that was transmitted, may be NULL if the message was ACKed
1609 * via another channel.
1610 */
1611 struct PendingMessage *pm;
1612
1613 /**
1614 * Distance vector path chosen for this transmission, NULL if transmission
1615 * was to a direct neighbour OR if the path was forgotten in the meantime.
1616 */
1617 struct DistanceVectorHop *dvh;
1618
1619 /**
1620 * Queue used for transmission, NULL if the queue has been destroyed
1621 * (which may happen before we get an acknowledgement).
1622 */
1623 struct Queue *queue;
1624
1625 /**
1626 * Time of the transmission, for RTT calculation.
1627 */
1628 struct GNUNET_TIME_Absolute transmission_time;
1629
1630 /**
1631 * Number of bytes of the original message (to calculate bandwidth).
1632 */
1633 uint16_t message_size;
1634};
1635
1636
1637/**
1638 * One possible hop towards a DV target.
1639 */
1640struct DistanceVectorHop
1641{
1642 /**
1643 * Kept in a MDLL, sorted by @e timeout.
1644 */
1645 struct DistanceVectorHop *next_dv;
1646
1647 /**
1648 * Kept in a MDLL, sorted by @e timeout.
1649 */
1650 struct DistanceVectorHop *prev_dv;
1651
1652 /**
1653 * Kept in a MDLL.
1654 */
1655 struct DistanceVectorHop *next_neighbour;
1656
1657 /**
1658 * Kept in a MDLL.
1659 */
1660 struct DistanceVectorHop *prev_neighbour;
1661
1662 /**
1663 * Head of DLL of PAs that used our @a path.
1664 */
1665 struct PendingAcknowledgement *pa_head;
1666
1667 /**
1668 * Tail of DLL of PAs that used our @a path.
1669 */
1670 struct PendingAcknowledgement *pa_tail;
1671
1672 /**
1673 * What would be the next hop to @e target?
1674 */
1675 struct Neighbour *next_hop;
1676
1677 /**
1678 * Distance vector entry this hop belongs with.
1679 */
1680 struct DistanceVector *dv;
1681
1682 /**
1683 * Array of @e distance hops to the target, excluding @e next_hop.
1684 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1685 * at the end of this struct. Excludes the target itself!
1686 */
1687 const struct GNUNET_PeerIdentity *path;
1688
1689 /**
1690 * At what time do we forget about this path unless we see it again
1691 * while learning?
1692 */
1693 struct GNUNET_TIME_Absolute timeout;
1694
1695 /**
1696 * For how long is the validation of this path considered
1697 * valid?
1698 * Set to ZERO if the path is learned by snooping on DV learn messages
1699 * initiated by other peers, and to the time at which we generated the
1700 * challenge for DV learn operations this peer initiated.
1701 */
1702 struct GNUNET_TIME_Absolute path_valid_until;
1703
1704 /**
1705 * Performance data for this transmission possibility.
1706 */
1707 struct PerformanceData pd;
1708
1709 /**
1710 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1711 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1712 * to `target`).
1713 */
1714 unsigned int distance;
1715};
1716
1717
1718/**
1719 * Entry in our #dv_routes table, representing a (set of) distance
1720 * vector routes to a particular peer.
1721 */
1722struct DistanceVector
1723{
1724 /**
1725 * To which peer is this a route?
1726 */
1727 struct GNUNET_PeerIdentity target;
1728
1729 /**
1730 * Known paths to @e target.
1731 */
1732 struct DistanceVectorHop *dv_head;
1733
1734 /**
1735 * Known paths to @e target.
1736 */
1737 struct DistanceVectorHop *dv_tail;
1738
1739 /**
1740 * Task scheduled to purge expired paths from @e dv_head MDLL.
1741 */
1742 struct GNUNET_SCHEDULER_Task *timeout_task;
1743
1744 /**
1745 * Do we have a confirmed working queue and are thus visible to
1746 * CORE? If so, this is the virtual link, otherwise NULL.
1747 */
1748 struct VirtualLink *vl;
1749
1750 /**
1751 * Signature affirming @e ephemeral_key of type
1752 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1753 */
1754 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1755
1756 /**
1757 * How long is @e sender_sig valid
1758 */
1759 struct GNUNET_TIME_Absolute ephemeral_validity;
1760
1761 /**
1762 * What time was @e sender_sig created
1763 */
1764 struct GNUNET_TIME_Absolute monotime;
1765
1766 /**
1767 * Our ephemeral key.
1768 */
1769 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1770
1771 /**
1772 * Our private ephemeral key.
1773 */
1774 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1775};
1776
1777
1778/**
1779 * Entry identifying transmission in one of our `struct
1780 * Queue` which still awaits an ACK. This is used to
1781 * ensure we do not overwhelm a communicator and limit the number of
1782 * messages outstanding per communicator (say in case communicator is
1783 * CPU bound) and per queue (in case bandwidth allocation exceeds
1784 * what the communicator can actually provide towards a particular
1785 * peer/target).
1786 */
1787struct QueueEntry
1788{
1789 /**
1790 * Kept as a DLL.
1791 */
1792 struct QueueEntry *next;
1793
1794 /**
1795 * Kept as a DLL.
1796 */
1797 struct QueueEntry *prev;
1798
1799 /**
1800 * Queue this entry is queued with.
1801 */
1802 struct Queue *queue;
1803
1804 /**
1805 * Pending message this entry is for, or NULL for none.
1806 */
1807 struct PendingMessage *pm;
1808
1809 /**
1810 * Message ID used for this message with the queue used for transmission.
1811 */
1812 uint64_t mid;
1813};
1814
1815
1816/**
1817 * A queue is a message queue provided by a communicator
1818 * via which we can reach a particular neighbour.
1819 */
1820struct Queue
1821{
1822 /**
1823 * Kept in a MDLL.
1824 */
1825 struct Queue *next_neighbour;
1826
1827 /**
1828 * Kept in a MDLL.
1829 */
1830 struct Queue *prev_neighbour;
1831
1832 /**
1833 * Kept in a MDLL.
1834 */
1835 struct Queue *prev_client;
1836
1837 /**
1838 * Kept in a MDLL.
1839 */
1840 struct Queue *next_client;
1841
1842 /**
1843 * Head of DLL of PAs that used this queue.
1844 */
1845 struct PendingAcknowledgement *pa_head;
1846
1847 /**
1848 * Tail of DLL of PAs that used this queue.
1849 */
1850 struct PendingAcknowledgement *pa_tail;
1851
1852 /**
1853 * Head of DLL of unacked transmission requests.
1854 */
1855 struct QueueEntry *queue_head;
1856
1857 /**
1858 * End of DLL of unacked transmission requests.
1859 */
1860 struct QueueEntry *queue_tail;
1861
1862 /**
1863 * Which neighbour is this queue for?
1864 */
1865 struct Neighbour *neighbour;
1866
1867 /**
1868 * Which communicator offers this queue?
1869 */
1870 struct TransportClient *tc;
1871
1872 /**
1873 * Address served by the queue.
1874 */
1875 const char *address;
1876
1877 /**
1878 * Is this queue of unlimited length.
1879 */
1880 unsigned int unlimited_length;
1881
1882 /**
1883 * Task scheduled for the time when this queue can (likely) transmit the
1884 * next message.
1885 */
1886 struct GNUNET_SCHEDULER_Task *transmit_task;
1887
1888 /**
1889 * How long do *we* consider this @e address to be valid? In the past or
1890 * zero if we have not yet validated it. Can be updated based on
1891 * challenge-response validations (via address validation logic), or when we
1892 * receive ACKs that we can definitively map to transmissions via this
1893 * queue.
1894 */
1895 struct GNUNET_TIME_Absolute validated_until;
1896
1897 /**
1898 * Performance data for this queue.
1899 */
1900 struct PerformanceData pd;
1901
1902 /**
1903 * Message ID generator for transmissions on this queue to the
1904 * communicator.
1905 */
1906 uint64_t mid_gen;
1907
1908 /**
1909 * Unique identifier of this queue with the communicator.
1910 */
1911 uint32_t qid;
1912
1913 /**
1914 * Maximum transmission unit supported by this queue.
1915 */
1916 uint32_t mtu;
1917
1918 /**
1919 * Messages pending.
1920 */
1921 uint32_t num_msg_pending;
1922
1923 /**
1924 * Bytes pending.
1925 */
1926 uint32_t num_bytes_pending;
1927
1928 /**
1929 * Length of the DLL starting at @e queue_head.
1930 */
1931 unsigned int queue_length;
1932
1933 /**
1934 * Capacity of the queue.
1935 */
1936 uint64_t q_capacity;
1937
1938 /**
1939 * Queue priority
1940 */
1941 uint32_t priority;
1942
1943 /**
1944 * Network type offered by this queue.
1945 */
1946 enum GNUNET_NetworkType nt;
1947
1948 /**
1949 * Connection status for this queue.
1950 */
1951 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1952
1953 /**
1954 * Set to #GNUNET_YES if this queue is idle waiting for some
1955 * virtual link to give it a pending message.
1956 */
1957 int idle;
1958};
1959
1960
1961/**
1962 * A neighbour that at least one communicator is connected to.
1963 */
1964struct Neighbour
1965{
1966 /**
1967 * Which peer is this about?
1968 */
1969 struct GNUNET_PeerIdentity pid;
1970
1971 /**
1972 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1973 * purged if this neighbour goes down.
1974 */
1975 struct DistanceVectorHop *dv_head;
1976
1977 /**
1978 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1979 * purged if this neighbour goes down.
1980 */
1981 struct DistanceVectorHop *dv_tail;
1982
1983 /**
1984 * Head of DLL of queues to this peer.
1985 */
1986 struct Queue *queue_head;
1987
1988 /**
1989 * Tail of DLL of queues to this peer.
1990 */
1991 struct Queue *queue_tail;
1992
1993 /**
1994 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1995 * the PEERSTORE, or NULL.
1996 */
1997 struct GNUNET_PEERSTORE_IterateContext *get;
1998
1999 /**
2000 * Handle to a PEERSTORE store operation to store this @e pid's @e
2001 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
2002 */
2003 struct GNUNET_PEERSTORE_StoreContext *sc;
2004
2005 /**
2006 * Do we have a confirmed working queue and are thus visible to
2007 * CORE? If so, this is the virtual link, otherwise NULL.
2008 */
2009 struct VirtualLink *vl;
2010
2011 /**
2012 * Latest DVLearn monotonic time seen from this peer. Initialized only
2013 * if @e dl_monotime_available is #GNUNET_YES.
2014 */
2015 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
2016
2017 /**
2018 * Do we have the latest value for @e last_dv_learn_monotime from
2019 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
2020 */
2021 int dv_monotime_available;
2022};
2023
2024
2025/**
2026 * Another peer attempted to talk to us, we should try to establish
2027 * a connection in the other direction.
2028 */
2029struct IncomingRequest
2030{
2031 /**
2032 * Kept in a DLL.
2033 */
2034 struct IncomingRequest *next;
2035
2036 /**
2037 * Kept in a DLL.
2038 */
2039 struct IncomingRequest *prev;
2040
2041 /**
2042 * Handle for watching the peerstore for HELLOs for this peer.
2043 */
2044 struct GNUNET_PEERSTORE_WatchContext *wc;
2045
2046 /**
2047 * Which peer is this about?
2048 */
2049 struct GNUNET_PeerIdentity pid;
2050};
2051
2052
2053/**
2054 * A peer that an application (client) would like us to talk to directly.
2055 */
2056struct PeerRequest
2057{
2058 /**
2059 * Which peer is this about?
2060 */
2061 struct GNUNET_PeerIdentity pid;
2062
2063 /**
2064 * Client responsible for the request.
2065 */
2066 struct TransportClient *tc;
2067
2068 /**
2069 * Handle for watching the peerstore for HELLOs for this peer.
2070 */
2071 struct GNUNET_PEERSTORE_WatchContext *wc;
2072
2073 /**
2074 * What kind of performance preference does this @e tc have?
2075 *
2076 * TODO: use this!
2077 */
2078 enum GNUNET_MQ_PriorityPreferences pk;
2079
2080 /**
2081 * How much bandwidth would this @e tc like to see?
2082 */
2083 struct GNUNET_BANDWIDTH_Value32NBO bw;
2084};
2085
2086
2087/**
2088 * Types of different pending messages.
2089 */
2090enum PendingMessageType
2091{
2092 /**
2093 * Ordinary message received from the CORE service.
2094 */
2095 PMT_CORE = 0,
2096
2097 /**
2098 * Fragment box.
2099 */
2100 PMT_FRAGMENT_BOX = 1,
2101
2102 /**
2103 * Reliability box.
2104 */
2105 PMT_RELIABILITY_BOX = 2,
2106
2107 /**
2108 * Pending message created during #forward_dv_box().
2109 */
2110 PMT_DV_BOX = 3
2111};
2112
2113
2114/**
2115 * Transmission request that is awaiting delivery. The original
2116 * transmission requests from CORE may be too big for some queues.
2117 * In this case, a *tree* of fragments is created. At each
2118 * level of the tree, fragments are kept in a DLL ordered by which
2119 * fragment should be sent next (at the head). The tree is searched
2120 * top-down, with the original message at the root.
2121 *
2122 * To select a node for transmission, first it is checked if the
2123 * current node's message fits with the MTU. If it does not, we
2124 * either calculate the next fragment (based on @e frag_off) from the
2125 * current node, or, if all fragments have already been created,
2126 * descend to the @e head_frag. Even though the node was already
2127 * fragmented, the fragment may be too big if the fragment was
2128 * generated for a queue with a larger MTU. In this case, the node
2129 * may be fragmented again, thus creating a tree.
2130 *
2131 * When acknowledgements for fragments are received, the tree
2132 * must be pruned, removing those parts that were already
2133 * acknowledged. When fragments are sent over a reliable
2134 * channel, they can be immediately removed.
2135 *
2136 * If a message is ever fragmented, then the original "full" message
2137 * is never again transmitted (even if it fits below the MTU), and
2138 * only (remaining) fragments are sent.
2139 */
2140struct PendingMessage
2141{
2142 /**
2143 * Kept in a MDLL of messages for this @a vl.
2144 */
2145 struct PendingMessage *next_vl;
2146
2147 /**
2148 * Kept in a MDLL of messages for this @a vl.
2149 */
2150 struct PendingMessage *prev_vl;
2151
2152 /**
2153 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2154 */
2155 struct PendingMessage *next_client;
2156
2157 /**
2158 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2159 */
2160 struct PendingMessage *prev_client;
2161
2162 /**
2163 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2164 * #PMT_FRAGMENT_BOx)
2165 */
2166 struct PendingMessage *next_frag;
2167
2168 /**
2169 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2170 * #PMT_FRAGMENT_BOX)
2171 */
2172 struct PendingMessage *prev_frag;
2173
2174 /**
2175 * Head of DLL of PAs for this pending message.
2176 */
2177 struct PendingAcknowledgement *pa_head;
2178
2179 /**
2180 * Tail of DLL of PAs for this pending message.
2181 */
2182 struct PendingAcknowledgement *pa_tail;
2183
2184 /**
2185 * This message, reliability *or* DV-boxed. Only possibly available
2186 * if @e pmt is #PMT_CORE.
2187 */
2188 struct PendingMessage *bpm;
2189
2190 /**
2191 * Target of the request (always the ultimate destination!).
2192 * Might be NULL in case of a forwarded DVBox we have no validated neighbour.
2193 */
2194 struct VirtualLink *vl;
2195
2196 /**
2197 * In case of a not validated neighbour, we store the target peer.
2198 **/
2199 struct GNUNET_PeerIdentity target;
2200
2201 /**
2202 * Set to non-NULL value if this message is currently being given to a
2203 * communicator and we are awaiting that communicator's acknowledgement.
2204 * Note that we must not retransmit a pending message while we're still
2205 * in the process of giving it to a communicator. If a pending message
2206 * is free'd while this entry is non-NULL, the @e qe reference to us
2207 * should simply be set to NULL.
2208 */
2209 struct QueueEntry *qe;
2210
2211 /**
2212 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2213 */
2214 struct TransportClient *client;
2215
2216 /**
2217 * Head of a MDLL of fragments created for this core message.
2218 */
2219 struct PendingMessage *head_frag;
2220
2221 /**
2222 * Tail of a MDLL of fragments created for this core message.
2223 */
2224 struct PendingMessage *tail_frag;
2225
2226 /**
2227 * Our parent in the fragmentation tree.
2228 */
2229 struct PendingMessage *frag_parent;
2230
2231 /**
2232 * At what time should we give up on the transmission (and no longer retry)?
2233 */
2234 struct GNUNET_TIME_Absolute timeout;
2235
2236 /**
2237 * What is the earliest time for us to retry transmission of this message?
2238 */
2239 struct GNUNET_TIME_Absolute next_attempt;
2240
2241 /**
2242 * UUID to use for this message (used for reassembly of fragments, only
2243 * initialized if @e msg_uuid_set is #GNUNET_YES).
2244 */
2245 struct MessageUUIDP msg_uuid;
2246
2247 /**
2248 * UUID we use to identify this message in our logs.
2249 * Generated by incrementing the "logging_uuid_gen".
2250 */
2251 unsigned long long logging_uuid;
2252
2253 /**
2254 * Type of the pending message.
2255 */
2256 enum PendingMessageType pmt;
2257
2258 /**
2259 * Preferences for this message.
2260 * TODO: actually use this!
2261 */
2262 enum GNUNET_MQ_PriorityPreferences prefs;
2263
2264 /**
2265 * If pmt is of type PMT_DV_BOX we store the used path here.
2266 */
2267 struct DistanceVectorHop *used_dvh;
2268
2269 /**
2270 * Size of the original message.
2271 */
2272 uint16_t bytes_msg;
2273
2274 /**
2275 * Offset at which we should generate the next fragment.
2276 */
2277 uint16_t frag_off;
2278
2279 /**
2280 * #GNUNET_YES once @e msg_uuid was initialized
2281 */
2282 int16_t msg_uuid_set;
2283
2284 /* Followed by @e bytes_msg to transmit */
2285};
2286
2287
2288/**
2289 * Acknowledgement payload.
2290 */
2291struct TransportCummulativeAckPayload
2292{
2293 /**
2294 * When did we receive the message we are ACKing? Used to calculate
2295 * the delay we introduced by cummulating ACKs.
2296 */
2297 struct GNUNET_TIME_Absolute receive_time;
2298
2299 /**
2300 * UUID of a message being acknowledged.
2301 */
2302 struct AcknowledgementUUIDP ack_uuid;
2303};
2304
2305
2306/**
2307 * Data structure in which we track acknowledgements still to
2308 * be sent to the
2309 */
2310struct AcknowledgementCummulator
2311{
2312 /**
2313 * Target peer for which we are accumulating ACKs here.
2314 */
2315 struct GNUNET_PeerIdentity target;
2316
2317 /**
2318 * ACK data being accumulated. Only @e num_acks slots are valid.
2319 */
2320 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2321
2322 /**
2323 * Task scheduled either to transmit the cumulative ACK message,
2324 * or to clean up this data structure after extended periods of
2325 * inactivity (if @e num_acks is zero).
2326 */
2327 struct GNUNET_SCHEDULER_Task *task;
2328
2329 /**
2330 * When is @e task run (only used if @e num_acks is non-zero)?
2331 */
2332 struct GNUNET_TIME_Absolute min_transmission_time;
2333
2334 /**
2335 * Counter to produce the `ack_counter` in the `struct
2336 * TransportReliabilityAckMessage`. Allows the receiver to detect
2337 * lost ACK messages. Incremented by @e num_acks upon transmission.
2338 */
2339 uint32_t ack_counter;
2340
2341 /**
2342 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2343 */
2344 unsigned int num_acks;
2345};
2346
2347
2348/**
2349 * One of the addresses of this peer.
2350 */
2351struct AddressListEntry
2352{
2353 /**
2354 * Kept in a DLL.
2355 */
2356 struct AddressListEntry *next;
2357
2358 /**
2359 * Kept in a DLL.
2360 */
2361 struct AddressListEntry *prev;
2362
2363 /**
2364 * Which communicator provides this address?
2365 */
2366 struct TransportClient *tc;
2367
2368 /**
2369 * The actual address.
2370 */
2371 const char *address;
2372
2373 /**
2374 * Current context for storing this address in the peerstore.
2375 */
2376 struct GNUNET_PEERSTORE_StoreContext *sc;
2377
2378 /**
2379 * Task to periodically do @e st operation.
2380 */
2381 struct GNUNET_SCHEDULER_Task *st;
2382
2383 /**
2384 * What is a typical lifetime the communicator expects this
2385 * address to have? (Always from now.)
2386 */
2387 struct GNUNET_TIME_Relative expiration;
2388
2389 /**
2390 * Address identifier used by the communicator.
2391 */
2392 uint32_t aid;
2393
2394 /**
2395 * Network type offered by this address.
2396 */
2397 enum GNUNET_NetworkType nt;
2398};
2399
2400
2401/**
2402 * Client connected to the transport service.
2403 */
2404struct TransportClient
2405{
2406 /**
2407 * Kept in a DLL.
2408 */
2409 struct TransportClient *next;
2410
2411 /**
2412 * Kept in a DLL.
2413 */
2414 struct TransportClient *prev;
2415
2416 /**
2417 * Handle to the client.
2418 */
2419 struct GNUNET_SERVICE_Client *client;
2420
2421 /**
2422 * Message queue to the client.
2423 */
2424 struct GNUNET_MQ_Handle *mq;
2425
2426 /**
2427 * What type of client is this?
2428 */
2429 enum ClientType type;
2430
2431 union
2432 {
2433 /**
2434 * Information for @e type #CT_CORE.
2435 */
2436 struct
2437 {
2438 /**
2439 * Head of list of messages pending for this client, sorted by
2440 * transmission time ("next_attempt" + possibly internal prioritization).
2441 */
2442 struct PendingMessage *pending_msg_head;
2443
2444 /**
2445 * Tail of list of messages pending for this client.
2446 */
2447 struct PendingMessage *pending_msg_tail;
2448 } core;
2449
2450 /**
2451 * Information for @e type #CT_MONITOR.
2452 */
2453 struct
2454 {
2455 /**
2456 * Peer identity to monitor the addresses of.
2457 * Zero to monitor all neighbours. Valid if
2458 * @e type is #CT_MONITOR.
2459 */
2460 struct GNUNET_PeerIdentity peer;
2461
2462 /**
2463 * Is this a one-shot monitor?
2464 */
2465 int one_shot;
2466 } monitor;
2467
2468
2469 /**
2470 * Information for @e type #CT_COMMUNICATOR.
2471 */
2472 struct
2473 {
2474 /**
2475 * If @e type is #CT_COMMUNICATOR, this communicator
2476 * supports communicating using these addresses.
2477 */
2478 char *address_prefix;
2479
2480 /**
2481 * Head of DLL of queues offered by this communicator.
2482 */
2483 struct Queue *queue_head;
2484
2485 /**
2486 * Tail of DLL of queues offered by this communicator.
2487 */
2488 struct Queue *queue_tail;
2489
2490 /**
2491 * Head of list of the addresses of this peer offered by this
2492 * communicator.
2493 */
2494 struct AddressListEntry *addr_head;
2495
2496 /**
2497 * Tail of list of the addresses of this peer offered by this
2498 * communicator.
2499 */
2500 struct AddressListEntry *addr_tail;
2501
2502 /**
2503 * Number of queue entries in all queues to this communicator. Used
2504 * throttle sending to a communicator if we see that the communicator
2505 * is globally unable to keep up.
2506 */
2507 unsigned int total_queue_length;
2508
2509 /**
2510 * Characteristics of this communicator.
2511 */
2512 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2513 } communicator;
2514
2515 /**
2516 * Information for @e type #CT_APPLICATION
2517 */
2518 struct
2519 {
2520 /**
2521 * Map of requests for peers the given client application would like to
2522 * see connections for. Maps from PIDs to `struct PeerRequest`.
2523 */
2524 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2525 } application;
2526 } details;
2527};
2528
2529
2530/**
2531 * State we keep for validation activities. Each of these
2532 * is both in the #validation_heap and the #validation_map.
2533 */
2534struct ValidationState
2535{
2536 /**
2537 * For which peer is @a address to be validated (or possibly valid)?
2538 * Serves as key in the #validation_map.
2539 */
2540 struct GNUNET_PeerIdentity pid;
2541
2542 /**
2543 * How long did the peer claim this @e address to be valid? Capped at
2544 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2545 * were told about the address and the value claimed by the other peer at
2546 * that time. May be updated similarly when validation succeeds.
2547 */
2548 struct GNUNET_TIME_Absolute valid_until;
2549
2550 /**
2551 * How long do *we* consider this @e address to be valid?
2552 * In the past or zero if we have not yet validated it.
2553 */
2554 struct GNUNET_TIME_Absolute validated_until;
2555
2556 /**
2557 * When did we FIRST use the current @e challenge in a message?
2558 * Used to sanity-check @code{origin_time} in the response when
2559 * calculating the RTT. If the @code{origin_time} is not in
2560 * the expected range, the response is discarded as malicious.
2561 */
2562 struct GNUNET_TIME_Absolute first_challenge_use;
2563
2564 /**
2565 * When did we LAST use the current @e challenge in a message?
2566 * Used to sanity-check @code{origin_time} in the response when
2567 * calculating the RTT. If the @code{origin_time} is not in
2568 * the expected range, the response is discarded as malicious.
2569 */
2570 struct GNUNET_TIME_Absolute last_challenge_use;
2571
2572 /**
2573 * Next time we will send the @e challenge to the peer, if this time is past
2574 * @e valid_until, this validation state is released at this time. If the
2575 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2576 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2577 * to re-validate before the validity actually expires.
2578 */
2579 struct GNUNET_TIME_Absolute next_challenge;
2580
2581 /**
2582 * Current backoff factor we're applying for sending the @a challenge.
2583 * Reset to 0 if the @a challenge is confirmed upon validation.
2584 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2585 * existing value if we receive an unvalidated address again over
2586 * another channel (and thus should consider the information "fresh").
2587 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2588 */
2589 struct GNUNET_TIME_Relative challenge_backoff;
2590
2591 /**
2592 * Initially set to "forever". Once @e validated_until is set, this value is
2593 * set to the RTT that tells us how long it took to receive the validation.
2594 */
2595 struct GNUNET_TIME_Relative validation_rtt;
2596
2597 /**
2598 * The challenge we sent to the peer to get it to validate the address. Note
2599 * that we rotate the challenge whenever we update @e validated_until to
2600 * avoid attacks where a peer simply replays an old challenge in the future.
2601 * (We must not rotate more often as otherwise we may discard valid answers
2602 * due to packet losses, latency and reorderings on the network).
2603 */
2604 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
2605
2606 /**
2607 * Claimed address of the peer.
2608 */
2609 char *address;
2610
2611 /**
2612 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2613 * heap is used to figure out when the next validation activity should be
2614 * run.
2615 */
2616 struct GNUNET_CONTAINER_HeapNode *hn;
2617
2618 /**
2619 * Handle to a PEERSTORE store operation for this @e address. NULL if
2620 * no PEERSTORE operation is pending.
2621 */
2622 struct GNUNET_PEERSTORE_StoreContext *sc;
2623
2624 /**
2625 * Self-imposed limit on the previous flow control window. (May be zero,
2626 * if we never used data from the previous window or are establishing the
2627 * connection for the first time).
2628 */
2629 uint32_t last_window_consum_limit;
2630
2631 /**
2632 * We are technically ready to send the challenge, but we are waiting for
2633 * the respective queue to become available for transmission.
2634 */
2635 int awaiting_queue;
2636};
2637
2638
2639/**
2640 * A Backtalker is a peer sending us backchannel messages. We use this
2641 * struct to detect monotonic time violations, cache ephemeral key
2642 * material (to avoid repeatedly checking signatures), and to synchronize
2643 * monotonic time with the PEERSTORE.
2644 */
2645struct Backtalker
2646{
2647 /**
2648 * Peer this is about.
2649 */
2650 struct GNUNET_PeerIdentity pid;
2651
2652 /**
2653 * Last (valid) monotonic time received from this sender.
2654 */
2655 struct GNUNET_TIME_Absolute monotonic_time;
2656
2657 /**
2658 * When will this entry time out?
2659 */
2660 struct GNUNET_TIME_Absolute timeout;
2661
2662 /**
2663 * Last (valid) ephemeral key received from this sender.
2664 */
2665 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2666
2667 /**
2668 * Task associated with this backtalker. Can be for timeout,
2669 * or other asynchronous operations.
2670 */
2671 struct GNUNET_SCHEDULER_Task *task;
2672
2673 /**
2674 * Communicator context waiting on this backchannel's @e get, or NULL.
2675 */
2676 struct CommunicatorMessageContext *cmc;
2677
2678 /**
2679 * Handle for an operation to fetch @e monotonic_time information from the
2680 * PEERSTORE, or NULL.
2681 */
2682 struct GNUNET_PEERSTORE_IterateContext *get;
2683
2684 /**
2685 * Handle to a PEERSTORE store operation for this @e pid's @e
2686 * monotonic_time. NULL if no PEERSTORE operation is pending.
2687 */
2688 struct GNUNET_PEERSTORE_StoreContext *sc;
2689
2690 /**
2691 * Number of bytes of the original message body that follows after this
2692 * struct.
2693 */
2694 size_t body_size;
2695};
2696
2697
2698/**
2699 * Ring buffer for a CORE message we did not deliver to CORE, because of missing virtual link to sender.
2700 */
2701static struct RingBufferEntry *ring_buffer[RING_BUFFER_SIZE];
2702
2703/**
2704 * Head of the ring buffer.
2705 */
2706static unsigned int ring_buffer_head;
2707
2708/**
2709 * Is the ring buffer filled up to RING_BUFFER_SIZE.
2710 */
2711static unsigned int is_ring_buffer_full;
2712
2713/**
2714 * Ring buffer for a forwarded DVBox message we did not deliver to the next hop, because of missing virtual link that hop.
2715 */
2716static struct PendingMessage *ring_buffer_dv[RING_BUFFER_SIZE];
2717
2718/**
2719 * Head of the ring buffer.
2720 */
2721static unsigned int ring_buffer_dv_head;
2722
2723/**
2724 * Is the ring buffer filled up to RING_BUFFER_SIZE.
2725 */
2726static unsigned int is_ring_buffer_dv_full;
2727
2728/**
2729 * Head of linked list of all clients to this service.
2730 */
2731static struct TransportClient *clients_head;
2732
2733/**
2734 * Tail of linked list of all clients to this service.
2735 */
2736static struct TransportClient *clients_tail;
2737
2738/**
2739 * Statistics handle.
2740 */
2741static struct GNUNET_STATISTICS_Handle *GST_stats;
2742
2743/**
2744 * Configuration handle.
2745 */
2746static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2747
2748/**
2749 * Our public key.
2750 */
2751static struct GNUNET_PeerIdentity GST_my_identity;
2752
2753/**
2754 * Our private key.
2755 */
2756static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2757
2758/**
2759 * Map from PIDs to `struct Neighbour` entries. A peer is
2760 * a neighbour if we have an MQ to it from some communicator.
2761 */
2762static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2763
2764/**
2765 * Map from PIDs to `struct Backtalker` entries. A peer is
2766 * a backtalker if it recently send us backchannel messages.
2767 */
2768static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2769
2770/**
2771 * Map from PIDs to `struct AcknowledgementCummulator`s.
2772 * Here we track the cumulative ACKs for transmission.
2773 */
2774static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2775
2776/**
2777 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2778 * a `struct PendingAcknowledgement`.
2779 */
2780static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2781
2782/**
2783 * Map from PIDs to `struct DistanceVector` entries describing
2784 * known paths to the peer.
2785 */
2786static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2787
2788/**
2789 * Map from PIDs to `struct ValidationState` entries describing
2790 * addresses we are aware of and their validity state.
2791 */
2792static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2793
2794/**
2795 * Map from PIDs to `struct VirtualLink` entries describing
2796 * links CORE knows to exist.
2797 */
2798static struct GNUNET_CONTAINER_MultiPeerMap *links;
2799
2800/**
2801 * Map from challenges to `struct LearnLaunchEntry` values.
2802 */
2803static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2804
2805/**
2806 * Head of a DLL sorted by launch time.
2807 */
2808static struct LearnLaunchEntry *lle_head = NULL;
2809
2810/**
2811 * Tail of a DLL sorted by launch time.
2812 */
2813static struct LearnLaunchEntry *lle_tail = NULL;
2814
2815/**
2816 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2817 * sorting addresses we are aware of by when we should next try to (re)validate
2818 * (or expire) them.
2819 */
2820static struct GNUNET_CONTAINER_Heap *validation_heap;
2821
2822/**
2823 * Database for peer's HELLOs.
2824 */
2825static struct GNUNET_PEERSTORE_Handle *peerstore;
2826
2827/**
2828 * Task run to initiate DV learning.
2829 */
2830static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2831
2832/**
2833 * Task to run address validation.
2834 */
2835static struct GNUNET_SCHEDULER_Task *validation_task;
2836
2837/**
2838 * List of incoming connections where we are trying
2839 * to get a connection back established. Length
2840 * kept in #ir_total.
2841 */
2842static struct IncomingRequest *ir_head;
2843
2844/**
2845 * Tail of DLL starting at #ir_head.
2846 */
2847static struct IncomingRequest *ir_tail;
2848
2849/**
2850 * Length of the DLL starting at #ir_head.
2851 */
2852static unsigned int ir_total;
2853
2854/**
2855 * Generator of `logging_uuid` in `struct PendingMessage`.
2856 */
2857static unsigned long long logging_uuid_gen;
2858
2859/**
2860 * Monotonic time we use for HELLOs generated at this time. TODO: we
2861 * should increase this value from time to time (i.e. whenever a
2862 * `struct AddressListEntry` actually expires), but IF we do this, we
2863 * must also update *all* (remaining) addresses in the PEERSTORE at
2864 * that time! (So for now only increased when the peer is restarted,
2865 * which hopefully roughly matches whenever our addresses change.)
2866 */
2867static struct GNUNET_TIME_Absolute hello_mono_time;
2868
2869/**
2870 * Indication if we have received a shutdown signal
2871 * and are in the process of cleaning up.
2872 */
2873static int in_shutdown;
2874
2875/**
2876 * Get an offset into the transmission history buffer for `struct
2877 * PerformanceData`. Note that the caller must perform the required
2878 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2879 * array!
2880 *
2881 * An 'age' lasts 15 minute slots.
2882 *
2883 * @return current age of the world
2884 */
2885static unsigned int
2886get_age ()
2887{
2888 struct GNUNET_TIME_Absolute now;
2889
2890 now = GNUNET_TIME_absolute_get ();
2891 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2892}
2893
2894
2895/**
2896 * Release @a ir data structure.
2897 *
2898 * @param ir data structure to release
2899 */
2900static void
2901free_incoming_request (struct IncomingRequest *ir)
2902{
2903 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2904 GNUNET_assert (ir_total > 0);
2905 ir_total--;
2906 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2907 ir->wc = NULL;
2908 GNUNET_free (ir);
2909}
2910
2911
2912/**
2913 * Release @a pa data structure.
2914 *
2915 * @param pa data structure to release
2916 */
2917static void
2918free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2919{
2920 struct Queue *q = pa->queue;
2921 struct PendingMessage *pm = pa->pm;
2922 struct DistanceVectorHop *dvh = pa->dvh;
2923
2924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2925 "free_pending_acknowledgement\n");
2926 if (NULL != q)
2927 {
2928 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2929 pa->queue = NULL;
2930 }
2931 if (NULL != pm)
2932 {
2933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2934 "remove pa from message\n");
2935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2936 "remove pa from message %llu\n",
2937 pm->logging_uuid);
2938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2939 "remove pa from message %u\n",
2940 pm->pmt);
2941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2942 "remove pa from message %s\n",
2943 GNUNET_uuid2s (&pa->ack_uuid.value));
2944 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2945 pa->pm = NULL;
2946 }
2947 if (NULL != dvh)
2948 {
2949 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2950 pa->queue = NULL;
2951 }
2952 GNUNET_assert (GNUNET_YES ==
2953 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
2954 &pa->ack_uuid.value,
2955 pa));
2956 GNUNET_free (pa);
2957}
2958
2959
2960/**
2961 * Free fragment tree below @e root, excluding @e root itself.
2962 * FIXME: this does NOT seem to have the intended semantics
2963 * based on how this is called. Seems we generally DO expect
2964 * @a root to be free'ed itself as well!
2965 *
2966 * @param root root of the tree to free
2967 */
2968static void
2969free_fragment_tree (struct PendingMessage *root)
2970{
2971 struct PendingMessage *frag;
2972
2973 while (NULL != (frag = root->head_frag))
2974 {
2975 struct PendingAcknowledgement *pa;
2976
2977 free_fragment_tree (frag);
2978 while (NULL != (pa = frag->pa_head))
2979 {
2980 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2981 pa->pm = NULL;
2982 }
2983 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2984 if (NULL != frag->qe)
2985 {
2986 GNUNET_assert (frag == frag->qe->pm);
2987 frag->qe->pm = NULL;
2988 GNUNET_CONTAINER_DLL_remove (frag->qe->queue->queue_head,
2989 frag->qe->queue->queue_tail,
2990 frag->qe);
2991 frag->qe->queue->queue_length--;
2992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2993 "Removing QueueEntry MID %lu from queue\n",
2994 frag->qe->mid);
2995 GNUNET_free (frag->qe);
2996 }
2997 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2998 "Free frag %p\n",
2999 frag);
3000 GNUNET_free (frag);
3001 }
3002}
3003
3004
3005/**
3006 * Release memory associated with @a pm and remove @a pm from associated
3007 * data structures. @a pm must be a top-level pending message and not
3008 * a fragment in the tree. The entire tree is freed (if applicable).
3009 *
3010 * @param pm the pending message to free
3011 */
3012static void
3013free_pending_message (struct PendingMessage *pm)
3014{
3015 struct TransportClient *tc = pm->client;
3016 struct VirtualLink *vl = pm->vl;
3017 struct PendingAcknowledgement *pa;
3018
3019 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3020 "Freeing pm %p\n",
3021 pm);
3022 if (NULL != tc)
3023 {
3024 GNUNET_CONTAINER_MDLL_remove (client,
3025 tc->details.core.pending_msg_head,
3026 tc->details.core.pending_msg_tail,
3027 pm);
3028 }
3029 if ((NULL != vl) && (NULL == pm->frag_parent))
3030 {
3031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3032 "Removing pm %llu\n",
3033 pm->logging_uuid);
3034 GNUNET_CONTAINER_MDLL_remove (vl,
3035 vl->pending_msg_head,
3036 vl->pending_msg_tail,
3037 pm);
3038 }
3039 while (NULL != (pa = pm->pa_head))
3040 {
3041 if (NULL == pa)
3042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3043 "free pending pa null\n");
3044 if (NULL == pm->pa_tail)
3045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3046 "free pending pa_tail null\n");
3047 if (NULL == pa->prev_pa)
3048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3049 "free pending pa prev null\n");
3050 if (NULL == pa->next_pa)
3051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3052 "free pending pa next null\n");
3053 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3054 pa->pm = NULL;
3055 }
3056
3057 free_fragment_tree (pm);
3058 if (NULL != pm->qe)
3059 {
3060 GNUNET_assert (pm == pm->qe->pm);
3061 pm->qe->pm = NULL;
3062 GNUNET_CONTAINER_DLL_remove (pm->qe->queue->queue_head,
3063 pm->qe->queue->queue_tail,
3064 pm->qe);
3065 pm->qe->queue->queue_length--;
3066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3067 "Removing QueueEntry MID %lu from queue\n",
3068 pm->qe->mid);
3069 GNUNET_free (pm->qe);
3070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3071 "QueueEntry MID freed\n");
3072 }
3073 if (NULL != pm->bpm)
3074 {
3075 free_fragment_tree (pm->bpm);
3076 GNUNET_free (pm->bpm);
3077 }
3078
3079 GNUNET_free (pm);
3080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3081 "Freeing pm done\n");
3082}
3083
3084
3085/**
3086 * Free @a rc
3087 *
3088 * @param rc data structure to free
3089 */
3090static void
3091free_reassembly_context (struct ReassemblyContext *rc)
3092{
3093 struct VirtualLink *vl = rc->virtual_link;
3094
3095 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3096 GNUNET_assert (GNUNET_OK ==
3097 GNUNET_CONTAINER_multihashmap32_remove (vl->reassembly_map,
3098 rc->msg_uuid.uuid,
3099 rc));
3100 GNUNET_free (rc);
3101}
3102
3103
3104/**
3105 * Task run to clean up reassembly context of a neighbour that have expired.
3106 *
3107 * @param cls a `struct Neighbour`
3108 */
3109static void
3110reassembly_cleanup_task (void *cls)
3111{
3112 struct VirtualLink *vl = cls;
3113 struct ReassemblyContext *rc;
3114
3115 vl->reassembly_timeout_task = NULL;
3116 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3117 {
3118 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3119 .rel_value_us)
3120 {
3121 free_reassembly_context (rc);
3122 continue;
3123 }
3124 GNUNET_assert (NULL == vl->reassembly_timeout_task);
3125 vl->reassembly_timeout_task =
3126 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3127 &reassembly_cleanup_task,
3128 vl);
3129 return;
3130 }
3131}
3132
3133
3134/**
3135 * function called to #free_reassembly_context().
3136 *
3137 * @param cls NULL
3138 * @param key unused
3139 * @param value a `struct ReassemblyContext` to free
3140 * @return #GNUNET_OK (continue iteration)
3141 */
3142static int
3143free_reassembly_cb (void *cls, uint32_t key, void *value)
3144{
3145 struct ReassemblyContext *rc = value;
3146
3147 (void) cls;
3148 (void) key;
3149 free_reassembly_context (rc);
3150 return GNUNET_OK;
3151}
3152
3153
3154/**
3155 * Free virtual link.
3156 *
3157 * @param vl link data to free
3158 */
3159static void
3160free_virtual_link (struct VirtualLink *vl)
3161{
3162 struct PendingMessage *pm;
3163 struct CoreSentContext *csc;
3164
3165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3166 "free virtual link %p\n",
3167 vl);
3168
3169 if (NULL != vl->reassembly_map)
3170 {
3171 GNUNET_CONTAINER_multihashmap32_iterate (vl->reassembly_map,
3172 &free_reassembly_cb,
3173 NULL);
3174 GNUNET_CONTAINER_multihashmap32_destroy (vl->reassembly_map);
3175 vl->reassembly_map = NULL;
3176 GNUNET_CONTAINER_heap_destroy (vl->reassembly_heap);
3177 vl->reassembly_heap = NULL;
3178 }
3179 if (NULL != vl->reassembly_timeout_task)
3180 {
3181 GNUNET_SCHEDULER_cancel (vl->reassembly_timeout_task);
3182 vl->reassembly_timeout_task = NULL;
3183 }
3184 while (NULL != (pm = vl->pending_msg_head))
3185 free_pending_message (pm);
3186 GNUNET_assert (GNUNET_YES ==
3187 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
3188 if (NULL != vl->visibility_task)
3189 {
3190 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3191 vl->visibility_task = NULL;
3192 }
3193 if (NULL != vl->fc_retransmit_task)
3194 {
3195 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
3196 vl->fc_retransmit_task = NULL;
3197 }
3198 while (NULL != (csc = vl->csc_head))
3199 {
3200 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
3201 GNUNET_assert (vl == csc->vl);
3202 csc->vl = NULL;
3203 }
3204 GNUNET_break (NULL == vl->n);
3205 GNUNET_break (NULL == vl->dv);
3206 GNUNET_free (vl);
3207}
3208
3209
3210/**
3211 * Free validation state.
3212 *
3213 * @param vs validation state to free
3214 */
3215static void
3216free_validation_state (struct ValidationState *vs)
3217{
3218 GNUNET_assert (
3219 GNUNET_YES ==
3220 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
3221 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3222 vs->hn = NULL;
3223 if (NULL != vs->sc)
3224 {
3225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3226 "store cancel\n");
3227 GNUNET_PEERSTORE_store_cancel (vs->sc);
3228 vs->sc = NULL;
3229 }
3230 GNUNET_free (vs->address);
3231 GNUNET_free (vs);
3232}
3233
3234
3235/**
3236 * Lookup neighbour for peer @a pid.
3237 *
3238 * @param pid neighbour to look for
3239 * @return NULL if we do not have this peer as a neighbour
3240 */
3241static struct Neighbour *
3242lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3243{
3244 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3245}
3246
3247
3248/**
3249 * Lookup virtual link for peer @a pid.
3250 *
3251 * @param pid virtual link to look for
3252 * @return NULL if we do not have this peer as a virtual link
3253 */
3254static struct VirtualLink *
3255lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3256{
3257 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3258}
3259
3260
3261/**
3262 * Details about what to notify monitors about.
3263 */
3264struct MonitorEvent
3265{
3266 /**
3267 * @deprecated To be discussed if we keep these...
3268 */
3269 struct GNUNET_TIME_Absolute last_validation;
3270 struct GNUNET_TIME_Absolute valid_until;
3271 struct GNUNET_TIME_Absolute next_validation;
3272
3273 /**
3274 * Current round-trip time estimate.
3275 */
3276 struct GNUNET_TIME_Relative rtt;
3277
3278 /**
3279 * Connection status.
3280 */
3281 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3282
3283 /**
3284 * Messages pending.
3285 */
3286 uint32_t num_msg_pending;
3287
3288 /**
3289 * Bytes pending.
3290 */
3291 uint32_t num_bytes_pending;
3292};
3293
3294
3295/**
3296 * Free a @a dvh. Callers MAY want to check if this was the last path to the
3297 * `target`, and if so call #free_dv_route to also free the associated DV
3298 * entry in #dv_routes (if not, the associated scheduler job should eventually
3299 * take care of it).
3300 *
3301 * @param dvh hop to free
3302 */
3303static void
3304free_distance_vector_hop (struct DistanceVectorHop *dvh)
3305{
3306 struct Neighbour *n = dvh->next_hop;
3307 struct DistanceVector *dv = dvh->dv;
3308 struct PendingAcknowledgement *pa;
3309
3310 while (NULL != (pa = dvh->pa_head))
3311 {
3312 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3313 pa->dvh = NULL;
3314 }
3315 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3316 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3317 GNUNET_free (dvh);
3318}
3319
3320
3321/**
3322 * Task run to check whether the hops of the @a cls still
3323 * are validated, or if we need to core about disconnection.
3324 *
3325 * @param cls a `struct VirtualLink`
3326 */
3327static void
3328check_link_down (void *cls);
3329
3330
3331/**
3332 * Send message to CORE clients that we lost a connection.
3333 *
3334 * @param pid peer the connection was for
3335 */
3336static void
3337cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3338{
3339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3340 "Informing CORE clients about disconnect from %s\n",
3341 GNUNET_i2s (pid));
3342 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3343 {
3344 struct GNUNET_MQ_Envelope *env;
3345 struct DisconnectInfoMessage *dim;
3346
3347 if (CT_CORE != tc->type)
3348 continue;
3349 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3350 dim->peer = *pid;
3351 GNUNET_MQ_send (tc->mq, env);
3352 }
3353}
3354
3355
3356/**
3357 * Free entry in #dv_routes. First frees all hops to the target, and
3358 * if there are no entries left, frees @a dv as well.
3359 *
3360 * @param dv route to free
3361 */
3362static void
3363free_dv_route (struct DistanceVector *dv)
3364{
3365 struct DistanceVectorHop *dvh;
3366
3367 while (NULL != (dvh = dv->dv_head))
3368 free_distance_vector_hop (dvh);
3369 if (NULL == dv->dv_head)
3370 {
3371 struct VirtualLink *vl;
3372
3373 GNUNET_assert (
3374 GNUNET_YES ==
3375 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3376 if (NULL != (vl = dv->vl))
3377 {
3378 GNUNET_assert (dv == vl->dv);
3379 vl->dv = NULL;
3380 if (NULL == vl->n)
3381 {
3382 cores_send_disconnect_info (&dv->target);
3383 free_virtual_link (vl);
3384 }
3385 else
3386 {
3387 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3388 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3389 }
3390 dv->vl = NULL;
3391 }
3392
3393 if (NULL != dv->timeout_task)
3394 {
3395 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3396 dv->timeout_task = NULL;
3397 }
3398 GNUNET_free (dv);
3399 }
3400}
3401
3402
3403/**
3404 * Notify monitor @a tc about an event. That @a tc
3405 * cares about the event has already been checked.
3406 *
3407 * Send @a tc information in @a me about a @a peer's status with
3408 * respect to some @a address to all monitors that care.
3409 *
3410 * @param tc monitor to inform
3411 * @param peer peer the information is about
3412 * @param address address the information is about
3413 * @param nt network type associated with @a address
3414 * @param me detailed information to transmit
3415 */
3416static void
3417notify_monitor (struct TransportClient *tc,
3418 const struct GNUNET_PeerIdentity *peer,
3419 const char *address,
3420 enum GNUNET_NetworkType nt,
3421 const struct MonitorEvent *me)
3422{
3423 struct GNUNET_MQ_Envelope *env;
3424 struct GNUNET_TRANSPORT_MonitorData *md;
3425 size_t addr_len = strlen (address) + 1;
3426
3427 env = GNUNET_MQ_msg_extra (md,
3428 addr_len,
3429 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3430 md->nt = htonl ((uint32_t) nt);
3431 md->peer = *peer;
3432 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3433 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3434 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3435 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3436 md->cs = htonl ((uint32_t) me->cs);
3437 md->num_msg_pending = htonl (me->num_msg_pending);
3438 md->num_bytes_pending = htonl (me->num_bytes_pending);
3439 memcpy (&md[1], address, addr_len);
3440 GNUNET_MQ_send (tc->mq, env);
3441}
3442
3443
3444/**
3445 * Send information in @a me about a @a peer's status with respect
3446 * to some @a address to all monitors that care.
3447 *
3448 * @param peer peer the information is about
3449 * @param address address the information is about
3450 * @param nt network type associated with @a address
3451 * @param me detailed information to transmit
3452 */
3453static void
3454notify_monitors (const struct GNUNET_PeerIdentity *peer,
3455 const char *address,
3456 enum GNUNET_NetworkType nt,
3457 const struct MonitorEvent *me)
3458{
3459 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3460 {
3461 if (CT_MONITOR != tc->type)
3462 continue;
3463 if (tc->details.monitor.one_shot)
3464 continue;
3465 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
3466 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3467 continue;
3468 notify_monitor (tc, peer, address, nt, me);
3469 }
3470}
3471
3472
3473/**
3474 * Called whenever a client connects. Allocates our
3475 * data structures associated with that client.
3476 *
3477 * @param cls closure, NULL
3478 * @param client identification of the client
3479 * @param mq message queue for the client
3480 * @return our `struct TransportClient`
3481 */
3482static void *
3483client_connect_cb (void *cls,
3484 struct GNUNET_SERVICE_Client *client,
3485 struct GNUNET_MQ_Handle *mq)
3486{
3487 struct TransportClient *tc;
3488
3489 (void) cls;
3490 tc = GNUNET_new (struct TransportClient);
3491 tc->client = client;
3492 tc->mq = mq;
3493 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3495 "Client %p of type %u connected\n",
3496 tc,
3497 tc->type);
3498 return tc;
3499}
3500
3501
3502/**
3503 * Release memory used by @a neighbour.
3504 *
3505 * @param neighbour neighbour entry to free
3506 */
3507static void
3508free_neighbour (struct Neighbour *neighbour)
3509{
3510 struct DistanceVectorHop *dvh;
3511 struct VirtualLink *vl;
3512
3513 GNUNET_assert (NULL == neighbour->queue_head);
3514 GNUNET_assert (GNUNET_YES ==
3515 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3516 &neighbour->pid,
3517 neighbour));
3518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3519 "Freeing neighbour\n");
3520 while (NULL != (dvh = neighbour->dv_head))
3521 {
3522 struct DistanceVector *dv = dvh->dv;
3523
3524 free_distance_vector_hop (dvh);
3525 if (NULL == dv->dv_head)
3526 free_dv_route (dv);
3527 }
3528 if (NULL != neighbour->get)
3529 {
3530 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3531 neighbour->get = NULL;
3532 }
3533 if (NULL != neighbour->sc)
3534 {
3535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3536 "store cancel\n");
3537 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3538 neighbour->sc = NULL;
3539 }
3540 if (NULL != (vl = neighbour->vl))
3541 {
3542 GNUNET_assert (neighbour == vl->n);
3543 vl->n = NULL;
3544 if (NULL == vl->dv)
3545 {
3546 cores_send_disconnect_info (&vl->target);
3547 free_virtual_link (vl);
3548 }
3549 else
3550 {
3551 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3552 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3553 }
3554 neighbour->vl = NULL;
3555 }
3556 GNUNET_free (neighbour);
3557}
3558
3559
3560/**
3561 * Send message to CORE clients that we lost a connection.
3562 *
3563 * @param tc client to inform (must be CORE client)
3564 * @param pid peer the connection is for
3565 */
3566static void
3567core_send_connect_info (struct TransportClient *tc,
3568 const struct GNUNET_PeerIdentity *pid)
3569{
3570 struct GNUNET_MQ_Envelope *env;
3571 struct ConnectInfoMessage *cim;
3572
3573 GNUNET_assert (CT_CORE == tc->type);
3574 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3575 cim->id = *pid;
3576 GNUNET_MQ_send (tc->mq, env);
3577}
3578
3579
3580/**
3581 * Send message to CORE clients that we gained a connection
3582 *
3583 * @param pid peer the queue was for
3584 */
3585static void
3586cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3587{
3588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3589 "Informing CORE clients about connection to %s\n",
3590 GNUNET_i2s (pid));
3591 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3592 {
3593 if (CT_CORE != tc->type)
3594 continue;
3595 core_send_connect_info (tc, pid);
3596 }
3597}
3598
3599
3600/**
3601 * We believe we are ready to transmit a message on a queue. Gives the
3602 * message to the communicator for transmission (updating the tracker,
3603 * and re-scheduling itself if applicable).
3604 *
3605 * @param cls the `struct Queue` to process transmissions for
3606 */
3607static void
3608transmit_on_queue (void *cls);
3609
3610
3611/**
3612 * Check if the communicator has another queue with higher prio ready for sending.
3613 */
3614static unsigned int
3615check_for_queue_with_higher_prio (struct Queue *queue, struct Queue *queue_head)
3616{
3617 for (struct Queue *s = queue_head; NULL != s;
3618 s = s->next_client)
3619 {
3620 if (s->tc->details.communicator.address_prefix !=
3621 queue->tc->details.communicator.address_prefix)
3622 {
3623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3624 "queue address %s qid %u compare with queue: address %s qid %u\n",
3625 queue->address,
3626 queue->qid,
3627 s->address,
3628 s->qid);
3629 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
3630 (QUEUE_LENGTH_LIMIT > s->queue_length) )
3631 return GNUNET_YES;
3632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3633 "Lower prio\n");
3634 }
3635 }
3636 return GNUNET_NO;
3637}
3638
3639
3640/**
3641 * Called whenever something changed that might effect when we
3642 * try to do the next transmission on @a queue using #transmit_on_queue().
3643 *
3644 * @param queue the queue to do scheduling for
3645 * @param p task priority to use, if @a queue is scheduled
3646 */
3647static void
3648schedule_transmit_on_queue (struct GNUNET_TIME_Relative delay,
3649 struct Queue *queue,
3650 enum GNUNET_SCHEDULER_Priority p)
3651{
3652 if (check_for_queue_with_higher_prio (queue,
3653 queue->tc->details.communicator.
3654 queue_head))
3655 return;
3656
3657 if (queue->tc->details.communicator.total_queue_length >=
3658 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3659 {
3660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3661 "Transmission throttled due to communicator queue limit\n");
3662 GNUNET_STATISTICS_update (
3663 GST_stats,
3664 "# Transmission throttled due to communicator queue limit",
3665 1,
3666 GNUNET_NO);
3667 queue->idle = GNUNET_NO;
3668 return;
3669 }
3670 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3671 {
3672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3673 "Transmission throttled due to communicator queue length limit\n");
3674 GNUNET_STATISTICS_update (GST_stats,
3675 "# Transmission throttled due to queue queue limit",
3676 1,
3677 GNUNET_NO);
3678 queue->idle = GNUNET_NO;
3679 return;
3680 }
3681 if (0 == queue->q_capacity)
3682 {
3683 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3684 "Transmission throttled due to communicator message queue qid %u has capacity %lu.\n",
3685 queue->qid,
3686 queue->q_capacity);
3687 GNUNET_STATISTICS_update (GST_stats,
3688 "# Transmission throttled due to message queue capacity",
3689 1,
3690 GNUNET_NO);
3691 queue->idle = GNUNET_NO;
3692 return;
3693 }
3694 /* queue might indeed be ready, schedule it */
3695 if (NULL != queue->transmit_task)
3696 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3697 queue->transmit_task =
3698 GNUNET_SCHEDULER_add_delayed_with_priority (delay, p, &transmit_on_queue,
3699 queue);
3700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3701 "Considering transmission on queue `%s' QID %llu to %s\n",
3702 queue->address,
3703 (unsigned long long) queue->qid,
3704 GNUNET_i2s (&queue->neighbour->pid));
3705}
3706
3707
3708/**
3709 * Task run to check whether the hops of the @a cls still
3710 * are validated, or if we need to core about disconnection.
3711 *
3712 * @param cls a `struct VirtualLink`
3713 */
3714static void
3715check_link_down (void *cls)
3716{
3717 struct VirtualLink *vl = cls;
3718 struct DistanceVector *dv = vl->dv;
3719 struct Neighbour *n = vl->n;
3720 struct GNUNET_TIME_Absolute dvh_timeout;
3721 struct GNUNET_TIME_Absolute q_timeout;
3722
3723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3724 "Checking if link is down\n");
3725 vl->visibility_task = NULL;
3726 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3727 if (NULL != dv)
3728 {
3729 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3730 pos = pos->next_dv)
3731 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
3732 pos->path_valid_until);
3733 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3734 {
3735 vl->dv->vl = NULL;
3736 vl->dv = NULL;
3737 }
3738 }
3739 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3740 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3741 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3742 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3743 {
3744 vl->n->vl = NULL;
3745 vl->n = NULL;
3746 }
3747 if ((NULL == vl->n) && (NULL == vl->dv))
3748 {
3749 cores_send_disconnect_info (&vl->target);
3750 free_virtual_link (vl);
3751 return;
3752 }
3753 vl->visibility_task =
3754 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3755 &check_link_down,
3756 vl);
3757}
3758
3759
3760/**
3761 * Free @a queue.
3762 *
3763 * @param queue the queue to free
3764 */
3765static void
3766free_queue (struct Queue *queue)
3767{
3768 struct Neighbour *neighbour = queue->neighbour;
3769 struct TransportClient *tc = queue->tc;
3770 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3771 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3772 struct QueueEntry *qe;
3773 int maxxed;
3774 struct PendingAcknowledgement *pa;
3775 struct VirtualLink *vl;
3776
3777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3778 "Cleaning up queue %u\n", queue->qid);
3779 if (NULL != queue->transmit_task)
3780 {
3781 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3782 queue->transmit_task = NULL;
3783 }
3784 while (NULL != (pa = queue->pa_head))
3785 {
3786 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3787 pa->queue = NULL;
3788 }
3789
3790 GNUNET_CONTAINER_MDLL_remove (neighbour,
3791 neighbour->queue_head,
3792 neighbour->queue_tail,
3793 queue);
3794 GNUNET_CONTAINER_MDLL_remove (client,
3795 tc->details.communicator.queue_head,
3796 tc->details.communicator.queue_tail,
3797 queue);
3798 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT <=
3799 tc->details.communicator.
3800 total_queue_length);
3801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3802 "Cleaning up queue with length %u\n",
3803 queue->queue_length);
3804 while (NULL != (qe = queue->queue_head))
3805 {
3806 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3807 queue->queue_length--;
3808 tc->details.communicator.total_queue_length--;
3809 if (NULL != qe->pm)
3810 {
3811 GNUNET_assert (qe == qe->pm->qe);
3812 qe->pm->qe = NULL;
3813 }
3814 GNUNET_free (qe);
3815 }
3816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3817 "Cleaning up queue with length %u\n",
3818 queue->queue_length);
3819 GNUNET_assert (0 == queue->queue_length);
3820 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
3821 tc->details.communicator.total_queue_length))
3822 {
3823 /* Communicator dropped below threshold, resume all _other_ queues */
3824 GNUNET_STATISTICS_update (
3825 GST_stats,
3826 "# Transmission throttled due to communicator queue limit",
3827 -1,
3828 GNUNET_NO);
3829 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3830 s = s->next_client)
3831 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
3832 s,
3833 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3834 }
3835 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3836 GNUNET_free (queue);
3837
3838 vl = lookup_virtual_link (&neighbour->pid);
3839 if ((NULL != vl) && (neighbour == vl->n))
3840 {
3841 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3842 check_link_down (vl);
3843 }
3844 if (NULL == neighbour->queue_head)
3845 {
3846 free_neighbour (neighbour);
3847 }
3848}
3849
3850
3851/**
3852 * Free @a ale
3853 *
3854 * @param ale address list entry to free
3855 */
3856static void
3857free_address_list_entry (struct AddressListEntry *ale)
3858{
3859 struct TransportClient *tc = ale->tc;
3860
3861 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3862 tc->details.communicator.addr_tail,
3863 ale);
3864 if (NULL != ale->sc)
3865 {
3866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3867 "store cancel\n");
3868 GNUNET_PEERSTORE_store_cancel (ale->sc);
3869 ale->sc = NULL;
3870 }
3871 if (NULL != ale->st)
3872 {
3873 GNUNET_SCHEDULER_cancel (ale->st);
3874 ale->st = NULL;
3875 }
3876 GNUNET_free (ale);
3877}
3878
3879
3880/**
3881 * Stop the peer request in @a value.
3882 *
3883 * @param cls a `struct TransportClient` that no longer makes the request
3884 * @param pid the peer's identity
3885 * @param value a `struct PeerRequest`
3886 * @return #GNUNET_YES (always)
3887 */
3888static int
3889stop_peer_request (void *cls,
3890 const struct GNUNET_PeerIdentity *pid,
3891 void *value)
3892{
3893 struct TransportClient *tc = cls;
3894 struct PeerRequest *pr = value;
3895
3896 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3897 pr->wc = NULL;
3898 GNUNET_assert (
3899 GNUNET_YES ==
3900 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3901 pid,
3902 pr));
3903 GNUNET_free (pr);
3904
3905 return GNUNET_OK;
3906}
3907
3908
3909static void
3910do_shutdown (void *cls);
3911
3912/**
3913 * Called whenever a client is disconnected. Frees our
3914 * resources associated with that client.
3915 *
3916 * @param cls closure, NULL
3917 * @param client identification of the client
3918 * @param app_ctx our `struct TransportClient`
3919 */
3920static void
3921client_disconnect_cb (void *cls,
3922 struct GNUNET_SERVICE_Client *client,
3923 void *app_ctx)
3924{
3925 struct TransportClient *tc = app_ctx;
3926
3927 (void) cls;
3928 (void) client;
3929 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3930 switch (tc->type)
3931 {
3932 case CT_NONE:
3933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3934 "Unknown Client %p disconnected, cleaning up.\n",
3935 tc);
3936 break;
3937
3938 case CT_CORE: {
3939 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3940 "CORE Client %p disconnected, cleaning up.\n",
3941 tc);
3942
3943 struct PendingMessage *pm;
3944
3945 while (NULL != (pm = tc->details.core.pending_msg_head))
3946 {
3947 GNUNET_CONTAINER_MDLL_remove (client,
3948 tc->details.core.pending_msg_head,
3949 tc->details.core.pending_msg_tail,
3950 pm);
3951 pm->client = NULL;
3952 }
3953 }
3954 break;
3955
3956 case CT_MONITOR:
3957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3958 "MONITOR Client %p disconnected, cleaning up.\n",
3959 tc);
3960
3961 break;
3962
3963 case CT_COMMUNICATOR: {
3964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3965 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
3966 tc);
3967
3968 struct Queue *q;
3969 struct AddressListEntry *ale;
3970
3971 while (NULL != (q = tc->details.communicator.queue_head))
3972 free_queue (q);
3973 while (NULL != (ale = tc->details.communicator.addr_head))
3974 free_address_list_entry (ale);
3975 GNUNET_free (tc->details.communicator.address_prefix);
3976 }
3977 break;
3978
3979 case CT_APPLICATION:
3980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3981 "APPLICATION Client %p disconnected, cleaning up.\n",
3982 tc);
3983
3984 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3985 &stop_peer_request,
3986 tc);
3987 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3988 break;
3989 }
3990 GNUNET_free (tc);
3991 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
3992 {
3993 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3994 "Our last client disconnected\n");
3995 do_shutdown (cls);
3996 }
3997}
3998
3999
4000/**
4001 * Iterator telling new CORE client about all existing
4002 * connections to peers.
4003 *
4004 * @param cls the new `struct TransportClient`
4005 * @param pid a connected peer
4006 * @param value the `struct Neighbour` with more information
4007 * @return #GNUNET_OK (continue to iterate)
4008 */
4009static int
4010notify_client_connect_info (void *cls,
4011 const struct GNUNET_PeerIdentity *pid,
4012 void *value)
4013{
4014 struct TransportClient *tc = cls;
4015
4016 (void) value;
4017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4018 "Telling new CORE client about existing connection to %s\n",
4019 GNUNET_i2s (pid));
4020 core_send_connect_info (tc, pid);
4021 return GNUNET_OK;
4022}
4023
4024
4025/**
4026 * Initialize a "CORE" client. We got a start message from this
4027 * client, so add it to the list of clients for broadcasting of
4028 * inbound messages.
4029 *
4030 * @param cls the client
4031 * @param start the start message that was sent
4032 */
4033static void
4034handle_client_start (void *cls, const struct StartMessage *start)
4035{
4036 struct TransportClient *tc = cls;
4037 uint32_t options;
4038
4039 options = ntohl (start->options);
4040 if ((0 != (1 & options)) &&
4041 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
4042 {
4043 /* client thinks this is a different peer, reject */
4044 GNUNET_break (0);
4045 GNUNET_SERVICE_client_drop (tc->client);
4046 return;
4047 }
4048 if (CT_NONE != tc->type)
4049 {
4050 GNUNET_break (0);
4051 GNUNET_SERVICE_client_drop (tc->client);
4052 return;
4053 }
4054 tc->type = CT_CORE;
4055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4056 "New CORE client with PID %s registered\n",
4057 GNUNET_i2s (&start->self));
4058 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
4059 &notify_client_connect_info,
4060 tc);
4061 GNUNET_SERVICE_client_continue (tc->client);
4062}
4063
4064
4065/**
4066 * Client asked for transmission to a peer. Process the request.
4067 *
4068 * @param cls the client
4069 * @param obm the send message that was sent
4070 */
4071static int
4072check_client_send (void *cls, const struct OutboundMessage *obm)
4073{
4074 struct TransportClient *tc = cls;
4075 uint16_t size;
4076 const struct GNUNET_MessageHeader *obmm;
4077
4078 if (CT_CORE != tc->type)
4079 {
4080 GNUNET_break (0);
4081 return GNUNET_SYSERR;
4082 }
4083 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4084 if (size < sizeof(struct GNUNET_MessageHeader))
4085 {
4086 GNUNET_break (0);
4087 return GNUNET_SYSERR;
4088 }
4089 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4090 if (size != ntohs (obmm->size))
4091 {
4092 GNUNET_break (0);
4093 return GNUNET_SYSERR;
4094 }
4095 return GNUNET_OK;
4096}
4097
4098
4099/**
4100 * Send a response to the @a pm that we have processed a "send"
4101 * request. Sends a confirmation to the "core" client responsible for
4102 * the original request and free's @a pm.
4103 *
4104 * @param pm handle to the original pending message
4105 */
4106static void
4107client_send_response (struct PendingMessage *pm)
4108{
4109 struct TransportClient *tc = pm->client;
4110 struct VirtualLink *vl = pm->vl;
4111
4112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4113 "client send response\n");
4114 if (NULL != tc)
4115 {
4116 struct GNUNET_MQ_Envelope *env;
4117 struct SendOkMessage *so_msg;
4118
4119 env = GNUNET_MQ_msg (so_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
4120 so_msg->peer = vl->target;
4121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4122 "Confirming transmission of <%llu> to %s\n",
4123 pm->logging_uuid,
4124 GNUNET_i2s (&vl->target));
4125 GNUNET_MQ_send (tc->mq, env);
4126 }
4127 free_pending_message (pm);
4128}
4129
4130
4131/**
4132 * Pick @a hops_array_length random DV paths satisfying @a options
4133 *
4134 * @param dv data structure to pick paths from
4135 * @param options constraints to satisfy
4136 * @param[out] hops_array set to the result
4137 * @param hops_array_length length of the @a hops_array
4138 * @return number of entries set in @a hops_array
4139 */
4140static unsigned int
4141pick_random_dv_hops (const struct DistanceVector *dv,
4142 enum RouteMessageOptions options,
4143 struct DistanceVectorHop **hops_array,
4144 unsigned int hops_array_length)
4145{
4146 uint64_t choices[hops_array_length];
4147 uint64_t num_dv;
4148 unsigned int dv_count;
4149
4150 /* Pick random vectors, but weighted by distance, giving more weight
4151 to shorter vectors */
4152 num_dv = 0;
4153 dv_count = 0;
4154 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4155 pos = pos->next_dv)
4156 {
4157 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4158 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4159 .rel_value_us == 0))
4160 continue; /* pos unconfirmed and confirmed required */
4161 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
4162 dv_count++;
4163 }
4164 if (0 == dv_count)
4165 return 0;
4166 if (dv_count <= hops_array_length)
4167 {
4168 dv_count = 0;
4169 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4170 pos = pos->next_dv)
4171 hops_array[dv_count++] = pos;
4172 return dv_count;
4173 }
4174 for (unsigned int i = 0; i < hops_array_length; i++)
4175 {
4176 int ok = GNUNET_NO;
4177 while (GNUNET_NO == ok)
4178 {
4179 choices[i] =
4180 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
4181 ok = GNUNET_YES;
4182 for (unsigned int j = 0; j < i; j++)
4183 if (choices[i] == choices[j])
4184 {
4185 ok = GNUNET_NO;
4186 break;
4187 }
4188 }
4189 }
4190 dv_count = 0;
4191 num_dv = 0;
4192 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4193 pos = pos->next_dv)
4194 {
4195 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
4196
4197 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4198 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4199 .rel_value_us == 0))
4200 continue; /* pos unconfirmed and confirmed required */
4201 for (unsigned int i = 0; i < hops_array_length; i++)
4202 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
4203 hops_array[dv_count++] = pos;
4204 num_dv += delta;
4205 }
4206 return dv_count;
4207}
4208
4209
4210/**
4211 * Communicator started. Test message is well-formed.
4212 *
4213 * @param cls the client
4214 * @param cam the send message that was sent
4215 */
4216static int
4217check_communicator_available (
4218 void *cls,
4219 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4220{
4221 struct TransportClient *tc = cls;
4222 uint16_t size;
4223
4224 if (CT_NONE != tc->type)
4225 {
4226 GNUNET_break (0);
4227 return GNUNET_SYSERR;
4228 }
4229 tc->type = CT_COMMUNICATOR;
4230 size = ntohs (cam->header.size) - sizeof(*cam);
4231 if (0 == size)
4232 return GNUNET_OK; /* receive-only communicator */
4233 GNUNET_MQ_check_zero_termination (cam);
4234 return GNUNET_OK;
4235}
4236
4237
4238/**
4239 * Send ACK to communicator (if requested) and free @a cmc.
4240 *
4241 * @param cmc context for which we are done handling the message
4242 */
4243static void
4244finish_cmc_handling_with_continue (struct CommunicatorMessageContext *cmc,
4245 unsigned
4246 int continue_client)
4247{
4248 if (0 != ntohl (cmc->im.fc_on))
4249 {
4250 /* send ACK when done to communicator for flow control! */
4251 struct GNUNET_MQ_Envelope *env;
4252 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4253
4254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4255 "Acknowledge message with flow control id %lu\n",
4256 cmc->im.fc_id);
4257 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4258 ack->reserved = htonl (0);
4259 ack->fc_id = cmc->im.fc_id;
4260 ack->sender = cmc->im.neighbour_sender;
4261 GNUNET_MQ_send (cmc->tc->mq, env);
4262 }
4263
4264 if (GNUNET_YES == continue_client)
4265 {
4266 GNUNET_SERVICE_client_continue (cmc->tc->client);
4267 }
4268 GNUNET_free (cmc);
4269}
4270
4271
4272static void
4273finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4274{
4275 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
4276}
4277
4278
4279/**
4280 * Client confirms that it is done handling message(s) to a particular
4281 * peer. We may now provide more messages to CORE for this peer.
4282 *
4283 * Notifies the respective queues that more messages can now be received.
4284 *
4285 * @param cls the client
4286 * @param rom the message that was sent
4287 */
4288static void
4289handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4290{
4291 struct TransportClient *tc = cls;
4292 struct VirtualLink *vl;
4293 uint32_t delta;
4294 struct CommunicatorMessageContext *cmc;
4295
4296 if (CT_CORE != tc->type)
4297 {
4298 GNUNET_break (0);
4299 GNUNET_SERVICE_client_drop (tc->client);
4300 return;
4301 }
4302 vl = lookup_virtual_link (&rom->peer);
4303 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4304 {
4305 GNUNET_STATISTICS_update (GST_stats,
4306 "# RECV_OK dropped: virtual link unknown",
4307 1,
4308 GNUNET_NO);
4309 GNUNET_SERVICE_client_continue (tc->client);
4310 return;
4311 }
4312 delta = ntohl (rom->increase_window_delta);
4313 vl->core_recv_window += delta;
4314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4315 "CORE ack receiving message, increased CORE recv window to %u\n",
4316 vl->core_recv_window);
4317 if (vl->core_recv_window <= 0)
4318 return;
4319 /* resume communicators */
4320 while (NULL != (cmc = vl->cmc_tail))
4321 {
4322 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4323 finish_cmc_handling (cmc);
4324 }
4325 GNUNET_SERVICE_client_continue (tc->client);
4326}
4327
4328
4329/**
4330 * Communicator started. Process the request.
4331 *
4332 * @param cls the client
4333 * @param cam the send message that was sent
4334 */
4335static void
4336handle_communicator_available (
4337 void *cls,
4338 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4339{
4340 struct TransportClient *tc = cls;
4341 uint16_t size;
4342
4343 size = ntohs (cam->header.size) - sizeof(*cam);
4344 if (0 == size)
4345 {
4346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4347 "Receive-only communicator connected\n");
4348 return; /* receive-only communicator */
4349 }
4350 tc->details.communicator.address_prefix =
4351 GNUNET_strdup ((const char *) &cam[1]);
4352 tc->details.communicator.cc =
4353 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4355 "Communicator with prefix `%s' connected\n",
4356 tc->details.communicator.address_prefix);
4357 GNUNET_SERVICE_client_continue (tc->client);
4358}
4359
4360
4361/**
4362 * Communicator requests backchannel transmission. Check the request.
4363 *
4364 * @param cls the client
4365 * @param cb the send message that was sent
4366 * @return #GNUNET_OK if message is well-formed
4367 */
4368static int
4369check_communicator_backchannel (
4370 void *cls,
4371 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4372{
4373 const struct GNUNET_MessageHeader *inbox;
4374 const char *is;
4375 uint16_t msize;
4376 uint16_t isize;
4377
4378 (void) cls;
4379 msize = ntohs (cb->header.size) - sizeof(*cb);
4380 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4381 isize = ntohs (inbox->size);
4382 if (isize >= msize)
4383 {
4384 GNUNET_break (0);
4385 return GNUNET_SYSERR;
4386 }
4387 is = (const char *) inbox;
4388 is += isize;
4389 msize -= isize;
4390 GNUNET_assert (0 < msize);
4391 if ('\0' != is[msize - 1])
4392 {
4393 GNUNET_break (0);
4394 return GNUNET_SYSERR;
4395 }
4396 return GNUNET_OK;
4397}
4398
4399
4400/**
4401 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4402 * set it up.
4403 *
4404 * @param[in,out] dv virtual link to update ephemeral for
4405 */
4406static void
4407update_ephemeral (struct DistanceVector *dv)
4408{
4409 struct EphemeralConfirmationPS ec;
4410
4411 if (0 !=
4412 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4413 return;
4414 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4415 dv->ephemeral_validity =
4416 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4417 GNUNET_CRYPTO_ecdhe_key_create (&dv->private_key);
4418 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4419 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4420 ec.target = dv->target;
4421 ec.ephemeral_key = dv->ephemeral_key;
4422 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4423 ec.purpose.size = htonl (sizeof(ec));
4424 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4425 &ec,
4426 &dv->sender_sig);
4427}
4428
4429
4430/**
4431 * Send the message @a payload on @a queue.
4432 *
4433 * @param queue the queue to use for transmission
4434 * @param pm pending message to update once transmission is done, may be NULL!
4435 * @param payload the payload to send (encapsulated in a
4436 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4437 * @param payload_size number of bytes in @a payload
4438 */
4439static void
4440queue_send_msg (struct Queue *queue,
4441 struct PendingMessage *pm,
4442 const void *payload,
4443 size_t payload_size)
4444{
4445 struct Neighbour *n = queue->neighbour;
4446 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4447 struct GNUNET_MQ_Envelope *env;
4448
4449 GNUNET_log (
4450 GNUNET_ERROR_TYPE_DEBUG,
4451 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4452 (unsigned int) payload_size,
4453 (NULL == pm) ? 0 : pm->logging_uuid,
4454 (unsigned long long) queue->qid,
4455 GNUNET_i2s (&queue->neighbour->pid));
4456 env = GNUNET_MQ_msg_extra (smt,
4457 payload_size,
4458 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4459 smt->qid = queue->qid;
4460 smt->mid = queue->mid_gen;
4461 smt->receiver = n->pid;
4462 memcpy (&smt[1], payload, payload_size);
4463 {
4464 /* Pass the env to the communicator of queue for transmission. */
4465 struct QueueEntry *qe;
4466
4467 qe = GNUNET_new (struct QueueEntry);
4468 qe->mid = queue->mid_gen++;
4469 qe->queue = queue;
4470 if (NULL != pm)
4471 {
4472 qe->pm = pm;
4473 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
4474 // GNUNET_assert (NULL == pm->qe);
4475 if (NULL != pm->qe)
4476 {
4477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4478 "Retransmitting message <%llu> remove pm from qe with MID: %llu \n",
4479 pm->logging_uuid,
4480 (unsigned long long) pm->qe->mid);
4481 // pm->qe->pm = NULL;
4482 }
4483 pm->qe = qe;
4484 }
4485 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4486 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4487 queue->queue_length++;
4488 queue->tc->details.communicator.total_queue_length++;
4489 //FIXME Probably this if statement here is completely wrong in this method,
4490 // and only fixed a symptom, but not an actual bug.
4491 if (0 == queue->q_capacity)
4492 {
4493 GNUNET_free (env);
4494 return;
4495 }
4496 if (GNUNET_NO == queue->unlimited_length)
4497 queue->q_capacity--;
4498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4499 "Queue %s with qid %u has capacity %lu\n",
4500 queue->address,
4501 queue->qid,
4502 queue->q_capacity);
4503 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4504 queue->tc->details.communicator.total_queue_length)
4505 queue->idle = GNUNET_NO;
4506 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4507 queue->idle = GNUNET_NO;
4508 if (0 == queue->q_capacity)
4509 queue->idle = GNUNET_NO;
4510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4511 "Sending message MID %lu of type %u (%u) and size %lu with MQ %p\n",
4512 smt->mid,
4513 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
4514 ntohs (smt->header.size),
4515 payload_size,
4516 queue->tc->mq);
4517 GNUNET_MQ_send (queue->tc->mq, env);
4518 }
4519}
4520
4521
4522/**
4523 * Pick a queue of @a n under constraints @a options and schedule
4524 * transmission of @a hdr.
4525 *
4526 * @param n neighbour to send to
4527 * @param hdr message to send as payload
4528 * @param options whether queues must be confirmed or not,
4529 * and whether we may pick multiple (2) queues
4530 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4531 */
4532static struct GNUNET_TIME_Relative
4533route_via_neighbour (const struct Neighbour *n,
4534 const struct GNUNET_MessageHeader *hdr,
4535 enum RouteMessageOptions options)
4536{
4537 struct GNUNET_TIME_Absolute now;
4538 unsigned int candidates;
4539 unsigned int sel1;
4540 unsigned int sel2;
4541 struct GNUNET_TIME_Relative rtt;
4542
4543 /* Pick one or two 'random' queues from n (under constraints of options) */
4544 now = GNUNET_TIME_absolute_get ();
4545 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4546 weight in the future; weight could be assigned by observed
4547 bandwidth (note: not sure if we should do this for this type
4548 of control traffic though). */
4549 candidates = 0;
4550 for (struct Queue *pos = n->queue_head; NULL != pos;
4551 pos = pos->next_neighbour)
4552 {
4553 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4554 (pos->validated_until.abs_value_us > now.abs_value_us))
4555 candidates++;
4556 }
4557 if (0 == candidates)
4558 {
4559 /* This can happen rarely if the last confirmed queue timed
4560 out just as we were beginning to process this message. */
4561 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4562 "Could not route message of type %u to %s: no valid queue\n",
4563 ntohs (hdr->type),
4564 GNUNET_i2s (&n->pid));
4565 GNUNET_STATISTICS_update (GST_stats,
4566 "# route selection failed (all no valid queue)",
4567 1,
4568 GNUNET_NO);
4569 return GNUNET_TIME_UNIT_FOREVER_REL;
4570 }
4571
4572 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4573 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4574 if (0 == (options & RMO_REDUNDANT))
4575 sel2 = candidates; /* picks none! */
4576 else
4577 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4578 candidates = 0;
4579 for (struct Queue *pos = n->queue_head; NULL != pos;
4580 pos = pos->next_neighbour)
4581 {
4582 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4583 (pos->validated_until.abs_value_us > now.abs_value_us))
4584 {
4585 if ((sel1 == candidates) || (sel2 == candidates))
4586 {
4587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4588 "Routing message of type %u to %s using %s (#%u)\n",
4589 ntohs (hdr->type),
4590 GNUNET_i2s (&n->pid),
4591 pos->address,
4592 (sel1 == candidates) ? 1 : 2);
4593 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4594 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4595 }
4596 candidates++;
4597 }
4598 }
4599 return rtt;
4600}
4601
4602
4603/**
4604 * Structure of the key material used to encrypt backchannel messages.
4605 */
4606struct DVKeyState
4607{
4608 /**
4609 * State of our block cipher.
4610 */
4611 gcry_cipher_hd_t cipher;
4612
4613 /**
4614 * Actual key material.
4615 */
4616 struct
4617 {
4618 /**
4619 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4620 */
4621 struct GNUNET_CRYPTO_AuthKey hmac_key;
4622
4623 /**
4624 * Symmetric key to use for encryption.
4625 */
4626 char aes_key[256 / 8];
4627
4628 /**
4629 * Counter value to use during setup.
4630 */
4631 char aes_ctr[128 / 8];
4632 } material;
4633};
4634
4635
4636/**
4637 * Given the key material in @a km and the initialization vector
4638 * @a iv, setup the key material for the backchannel in @a key.
4639 *
4640 * @param km raw master secret
4641 * @param iv initialization vector
4642 * @param[out] key symmetric cipher and HMAC state to generate
4643 */
4644static void
4645dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4646 const struct GNUNET_ShortHashCode *iv,
4647 struct DVKeyState *key)
4648{
4649 /* must match #dh_key_derive_eph_pub */
4650 GNUNET_assert (GNUNET_YES ==
4651 GNUNET_CRYPTO_kdf (&key->material,
4652 sizeof(key->material),
4653 "transport-backchannel-key",
4654 strlen ("transport-backchannel-key"),
4655 km,
4656 sizeof(*km),
4657 iv,
4658 sizeof(*iv),
4659 NULL));
4660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4661 "Deriving backchannel key based on KM %s and IV %s\n",
4662 GNUNET_h2s (km),
4663 GNUNET_sh2s (iv));
4664 GNUNET_assert (0 == gcry_cipher_open (&key->cipher,
4665 GCRY_CIPHER_AES256 /* low level: go for speed */,
4666 GCRY_CIPHER_MODE_CTR,
4667 0 /* flags */));
4668 GNUNET_assert (0 == gcry_cipher_setkey (key->cipher,
4669 &key->material.aes_key,
4670 sizeof(key->material.aes_key)));
4671 gcry_cipher_setctr (key->cipher,
4672 &key->material.aes_ctr,
4673 sizeof(key->material.aes_ctr));
4674}
4675
4676
4677/**
4678 * Derive backchannel encryption key material from @a priv_ephemeral
4679 * and @a target and @a iv.
4680 *
4681 * @param priv_ephemeral ephemeral private key to use
4682 * @param target the target peer to encrypt to
4683 * @param iv unique IV to use
4684 * @param[out] key set to the key material
4685 * @return GNUNET_OK on success
4686 */
4687static enum GNUNET_GenericReturnValue
4688dh_key_derive_eph_pid (
4689 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4690 const struct GNUNET_PeerIdentity *target,
4691 const struct GNUNET_ShortHashCode *iv,
4692 struct DVKeyState *key)
4693{
4694 struct GNUNET_HashCode km;
4695
4696 if (GNUNET_YES != GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4697 &target->public_key,
4698 &km))
4699 return GNUNET_SYSERR;
4700 // FIXME: Possibly also add return values here. We are processing
4701 // Input from other peers...
4702 dv_setup_key_state_from_km (&km, iv, key);
4703 return GNUNET_OK;
4704}
4705
4706
4707/**
4708 * Derive backchannel encryption key material from #GST_my_private_key
4709 * and @a pub_ephemeral and @a iv.
4710 *
4711 * @param priv_ephemeral ephemeral private key to use
4712 * @param target the target peer to encrypt to
4713 * @param iv unique IV to use
4714 * @param[out] key set to the key material
4715 * @return GNUNET_OK on success
4716 */
4717static enum GNUNET_GenericReturnValue
4718dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4719 const struct GNUNET_ShortHashCode *iv,
4720 struct DVKeyState *key)
4721{
4722 struct GNUNET_HashCode km;
4723
4724 if (GNUNET_YES != GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4725 pub_ephemeral,
4726 &km))
4727 return GNUNET_SYSERR;
4728 dv_setup_key_state_from_km (&km, iv, key);
4729 return GNUNET_OK;
4730}
4731
4732
4733/**
4734 * Do HMAC calculation for backchannel messages over @a data using key
4735 * material from @a key.
4736 *
4737 * @param key key material (from DH)
4738 * @param[out] hmac set to the HMAC
4739 * @param data data to perform HMAC calculation over
4740 * @param data_size number of bytes in @a data
4741 */
4742static void
4743dv_hmac (const struct DVKeyState *key,
4744 struct GNUNET_HashCode *hmac,
4745 const void *data,
4746 size_t data_size)
4747{
4748 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4749}
4750
4751
4752/**
4753 * Perform backchannel encryption using symmetric secret in @a key
4754 * to encrypt data from @a in to @a dst.
4755 *
4756 * @param[in,out] key key material to use
4757 * @param dst where to write the result
4758 * @param in input data to encrypt (plaintext)
4759 * @param in_size number of bytes of input in @a in and available at @a dst
4760 */
4761static void
4762dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4763{
4764 GNUNET_assert (0 ==
4765 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4766}
4767
4768
4769/**
4770 * Perform backchannel encryption using symmetric secret in @a key
4771 * to encrypt data from @a in to @a dst.
4772 *
4773 * @param[in,out] key key material to use
4774 * @param ciph cipher text to decrypt
4775 * @param[out] out output data to generate (plaintext)
4776 * @param out_size number of bytes of input in @a ciph and available in @a out
4777 * @return GNUNET_OK on success
4778 */
4779static enum GNUNET_GenericReturnValue
4780dv_decrypt (struct DVKeyState *key,
4781 void *out,
4782 const void *ciph,
4783 size_t out_size)
4784{
4785 return (0 ==
4786 gcry_cipher_decrypt (key->cipher,
4787 out, out_size,
4788 ciph, out_size)) ? GNUNET_OK : GNUNET_SYSERR;
4789}
4790
4791
4792/**
4793 * Clean up key material in @a key.
4794 *
4795 * @param key key material to clean up (memory must not be free'd!)
4796 */
4797static void
4798dv_key_clean (struct DVKeyState *key)
4799{
4800 gcry_cipher_close (key->cipher);
4801 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
4802}
4803
4804
4805/**
4806 * Function to call to further operate on the now DV encapsulated
4807 * message @a hdr, forwarding it via @a next_hop under respect of
4808 * @a options.
4809 *
4810 * @param cls closure
4811 * @param next_hop next hop of the DV path
4812 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4813 * @param options options of the original message
4814 */
4815typedef void (*DVMessageHandler) (void *cls,
4816 struct Neighbour *next_hop,
4817 const struct GNUNET_MessageHeader *hdr,
4818 enum RouteMessageOptions options);
4819
4820/**
4821 * Pick a path of @a dv under constraints @a options and schedule
4822 * transmission of @a hdr.
4823 *
4824 * @param target neighbour to ultimately send to
4825 * @param num_dvhs length of the @a dvhs array
4826 * @param dvhs array of hops to send the message to
4827 * @param hdr message to send as payload
4828 * @param use function to call with the encapsulated message
4829 * @param use_cls closure for @a use
4830 * @param options whether path must be confirmed or not, to be passed to @a use
4831 * @param without_fc shall this TransportDVBoxMessage be forwarded without flow control.
4832 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4833 */
4834static struct GNUNET_TIME_Relative
4835encapsulate_for_dv (struct DistanceVector *dv,
4836 unsigned int num_dvhs,
4837 struct DistanceVectorHop **dvhs,
4838 const struct GNUNET_MessageHeader *hdr,
4839 DVMessageHandler use,
4840 void *use_cls,
4841 enum RouteMessageOptions options,
4842 enum GNUNET_GenericReturnValue without_fc)
4843{
4844 struct TransportDVBoxMessage box_hdr;
4845 struct TransportDVBoxPayloadP payload_hdr;
4846 uint16_t enc_body_size = ntohs (hdr->size);
4847 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4848 struct DVKeyState *key;
4849 struct GNUNET_TIME_Relative rtt;
4850
4851 key = GNUNET_new (struct DVKeyState);
4852 /* Encrypt payload */
4853 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4854 box_hdr.total_hops = htons (0);
4855 box_hdr.without_fc = htons (without_fc);
4856 update_ephemeral (dv);
4857 box_hdr.ephemeral_key = dv->ephemeral_key;
4858 payload_hdr.sender_sig = dv->sender_sig;
4859
4860 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4861 &box_hdr.iv,
4862 sizeof(box_hdr.iv));
4863 // We are creating this key, so this must work.
4864 GNUNET_assert (GNUNET_OK ==
4865 dh_key_derive_eph_pid (&dv->private_key,
4866 &dv->target,
4867 &box_hdr.iv, key));
4868 payload_hdr.sender = GST_my_identity;
4869 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4870 dv_encrypt (key, &payload_hdr, enc, sizeof(payload_hdr));
4871 dv_encrypt (key,
4872 hdr,
4873 &enc[sizeof(struct TransportDVBoxPayloadP)],
4874 enc_body_size);
4875 dv_hmac (key, &box_hdr.hmac, enc, sizeof(enc));
4876 dv_key_clean (key);
4877 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4878 /* For each selected path, take the pre-computed header and body
4879 and add the path in the middle of the message; then send it. */
4880 for (unsigned int i = 0; i < num_dvhs; i++)
4881 {
4882 struct DistanceVectorHop *dvh = dvhs[i];
4883 unsigned int num_hops = dvh->distance + 1;
4884 char buf[sizeof(struct TransportDVBoxMessage)
4885 + sizeof(struct GNUNET_PeerIdentity) * num_hops
4886 + sizeof(struct TransportDVBoxPayloadP)
4887 + enc_body_size] GNUNET_ALIGN;
4888 struct GNUNET_PeerIdentity *dhops;
4889
4890 box_hdr.header.size = htons (sizeof(buf));
4891 box_hdr.orig_size = htons (sizeof(buf));
4892 box_hdr.num_hops = htons (num_hops);
4893 memcpy (buf, &box_hdr, sizeof(box_hdr));
4894 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
4895 memcpy (dhops,
4896 dvh->path,
4897 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
4898 dhops[dvh->distance] = dv->target;
4899 if (GNUNET_EXTRA_LOGGING > 0)
4900 {
4901 char *path;
4902
4903 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4904 for (unsigned int j = 0; j < num_hops; j++)
4905 {
4906 char *tmp;
4907
4908 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
4909 GNUNET_free (path);
4910 path = tmp;
4911 }
4912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4913 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4914 ntohs (hdr->type),
4915 GNUNET_i2s (&dv->target),
4916 i + 1,
4917 num_dvhs,
4918 path);
4919 GNUNET_free (path);
4920 }
4921 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4922 memcpy (&dhops[num_hops], enc, sizeof(enc));
4923 use (use_cls,
4924 dvh->next_hop,
4925 (const struct GNUNET_MessageHeader *) buf,
4926 options);
4927 GNUNET_free (key);
4928 }
4929 return rtt;
4930}
4931
4932
4933/**
4934 * Wrapper around #route_via_neighbour() that matches the
4935 * #DVMessageHandler structure.
4936 *
4937 * @param cls unused
4938 * @param next_hop where to send next
4939 * @param hdr header of the message to send
4940 * @param options message options for queue selection
4941 */
4942static void
4943send_dv_to_neighbour (void *cls,
4944 struct Neighbour *next_hop,
4945 const struct GNUNET_MessageHeader *hdr,
4946 enum RouteMessageOptions options)
4947{
4948 (void) cls;
4949 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
4950}
4951
4952
4953/**
4954 * We need to transmit @a hdr to @a target. If necessary, this may
4955 * involve DV routing. This function routes without applying flow
4956 * control or congestion control and should only be used for control
4957 * traffic.
4958 *
4959 * @param target peer to receive @a hdr
4960 * @param hdr header of the message to route and #GNUNET_free()
4961 * @param options which transmission channels are allowed
4962 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4963 */
4964static struct GNUNET_TIME_Relative
4965route_control_message_without_fc (struct VirtualLink *vl,
4966// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4967 const struct GNUNET_MessageHeader *hdr,
4968 enum RouteMessageOptions options)
4969{
4970 // struct VirtualLink *vl;
4971 struct Neighbour *n;
4972 struct DistanceVector *dv;
4973 struct GNUNET_TIME_Relative rtt1;
4974 struct GNUNET_TIME_Relative rtt2;
4975 const struct GNUNET_PeerIdentity *target = &vl->target;
4976
4977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4978 "Trying to route message of type %u to %s without fc\n",
4979 ntohs (hdr->type),
4980 GNUNET_i2s (target));
4981
4982 // TODO Do this elsewhere. vl should be given as parameter to method.
4983 // vl = lookup_virtual_link (target);
4984 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
4985 if (NULL == vl)
4986 return GNUNET_TIME_UNIT_FOREVER_REL;
4987 n = vl->n;
4988 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4989 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4990 {
4991 /* if confirmed is required, and we do not have anything
4992 confirmed, drop respective options */
4993 if (NULL == n)
4994 n = lookup_neighbour (target);
4995 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4996 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4997 }
4998 if ((NULL == n) && (NULL == dv))
4999 {
5000 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5001 "Cannot route message of type %u to %s: no route\n",
5002 ntohs (hdr->type),
5003 GNUNET_i2s (target));
5004 GNUNET_STATISTICS_update (GST_stats,
5005 "# Messages dropped in routing: no acceptable method",
5006 1,
5007 GNUNET_NO);
5008 return GNUNET_TIME_UNIT_FOREVER_REL;
5009 }
5010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5011 "Routing message of type %u to %s with options %X\n",
5012 ntohs (hdr->type),
5013 GNUNET_i2s (target),
5014 (unsigned int) options);
5015 /* If both dv and n are possible and we must choose:
5016 flip a coin for the choice between the two; for now 50/50 */
5017 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
5018 {
5019 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
5020 n = NULL;
5021 else
5022 dv = NULL;
5023 }
5024 if ((NULL != n) && (NULL != dv))
5025 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
5026 enough for redundancy, so clear the flag. */
5027 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
5028 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
5029 if (NULL != n)
5030 {
5031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5032 "Try to route message of type %u to %s without fc via neighbour\n",
5033 ntohs (hdr->type),
5034 GNUNET_i2s (target));
5035 rtt1 = route_via_neighbour (n, hdr, options);
5036 }
5037 if (NULL != dv)
5038 {
5039 struct DistanceVectorHop *hops[2];
5040 unsigned int res;
5041
5042 res = pick_random_dv_hops (dv,
5043 options,
5044 hops,
5045 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
5046 if (0 == res)
5047 {
5048 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5049 "Failed to route message, could not determine DV path\n");
5050 return rtt1;
5051 }
5052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5053 "encapsulate_for_dv 1\n");
5054 rtt2 = encapsulate_for_dv (dv,
5055 res,
5056 hops,
5057 hdr,
5058 &send_dv_to_neighbour,
5059 NULL,
5060 options & (~RMO_REDUNDANT),
5061 GNUNET_YES);
5062 }
5063 return GNUNET_TIME_relative_min (rtt1, rtt2);
5064}
5065
5066
5067static void
5068consider_sending_fc (void *cls);
5069
5070/**
5071 * Something changed on the virtual link with respect to flow
5072 * control. Consider retransmitting the FC window size.
5073 *
5074 * @param cls a `struct VirtualLink` to work with
5075 */
5076static void
5077task_consider_sending_fc (void *cls)
5078{
5079 struct VirtualLink *vl = cls;
5080 vl->fc_retransmit_task = NULL;
5081 consider_sending_fc (cls);
5082}
5083
5084
5085/**
5086 * Something changed on the virtual link with respect to flow
5087 * control. Consider retransmitting the FC window size.
5088 *
5089 * @param cls a `struct VirtualLink` to work with
5090 */
5091static void
5092consider_sending_fc (void *cls)
5093{
5094 struct VirtualLink *vl = cls;
5095 struct GNUNET_TIME_Absolute monotime;
5096 struct TransportFlowControlMessage fc;
5097 struct GNUNET_TIME_Relative duration;
5098 struct GNUNET_TIME_Relative rtt;
5099
5100 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
5101 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
5102 it always! */
5103 /* For example, we should probably ONLY do this if a bit more than
5104 an RTT has passed, or if the window changed "significantly" since
5105 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
5106 need an estimate for the bandwidth-delay-product for the entire
5107 VL, as that determines "significantly". We have the delay, but
5108 the bandwidth statistics need to be added for the VL!*/(void) duration;
5109
5110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5111 "Sending FC seq %u to %s with new window %llu\n",
5112 (unsigned int) vl->fc_seq_gen,
5113 GNUNET_i2s (&vl->target),
5114 (unsigned long long) vl->incoming_fc_window_size);
5115 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
5116 vl->last_fc_transmission = monotime;
5117 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
5118 fc.header.size = htons (sizeof(fc));
5119 fc.seq = htonl (vl->fc_seq_gen++);
5120 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
5121 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
5122 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
5123 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
5124 rtt = route_control_message_without_fc (vl, &fc.header, RMO_DV_ALLOWED);
5125 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
5126 {
5127 rtt = GNUNET_TIME_UNIT_SECONDS;
5128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5129 "FC retransmission to %s failed, will retry in %s\n",
5130 GNUNET_i2s (&vl->target),
5131 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
5132 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
5133 }
5134 else
5135 {
5136 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
5137 vl->last_fc_rtt = rtt;
5138 }
5139 if (NULL != vl->fc_retransmit_task)
5140 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
5141 if (MAX_FC_RETRANSMIT_COUNT == vl->fc_retransmit_count)
5142 {
5143 rtt = GNUNET_TIME_UNIT_MINUTES;
5144 vl->fc_retransmit_count = 0;
5145 }
5146 vl->fc_retransmit_task =
5147 GNUNET_SCHEDULER_add_delayed (rtt, &task_consider_sending_fc, vl);
5148 vl->fc_retransmit_count++;
5149}
5150
5151
5152/**
5153 * There is a message at the head of the pending messages for @a vl
5154 * which may be ready for transmission. Check if a queue is ready to
5155 * take it.
5156 *
5157 * This function must (1) check for flow control to ensure that we can
5158 * right now send to @a vl, (2) check that the pending message in the
5159 * queue is actually eligible, (3) determine if any applicable queue
5160 * (direct neighbour or DVH path) is ready to accept messages, and
5161 * (4) prioritize based on the preferences associated with the
5162 * pending message.
5163 *
5164 * So yeah, easy.
5165 *
5166 * @param vl virtual link where we should check for transmission
5167 */
5168static void
5169check_vl_transmission (struct VirtualLink *vl)
5170{
5171 struct Neighbour *n = vl->n;
5172 struct DistanceVector *dv = vl->dv;
5173 struct GNUNET_TIME_Absolute now;
5174 struct VirtualLink *vl_next_hop;
5175 int elig;
5176
5177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5178 "check_vl_transmission to target %s\n",
5179 GNUNET_i2s (&vl->target));
5180 /* Check that we have an eligible pending message!
5181 (cheaper than having #transmit_on_queue() find out!) */
5182 elig = GNUNET_NO;
5183 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
5184 pm = pm->next_vl)
5185 {
5186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5187 "check_vl_transmission loop\n");
5188 if (NULL != pm->qe)
5189 continue; /* not eligible, is in a queue! */
5190 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
5191 vl->outbound_fc_window_size)
5192 {
5193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5194 "Stalled message %llu transmission on VL %s due to flow control: %llu < %llu\n",
5195 pm->logging_uuid,
5196 GNUNET_i2s (&vl->target),
5197 (unsigned long long) vl->outbound_fc_window_size,
5198 (unsigned long long) (pm->bytes_msg
5199 + vl->outbound_fc_window_size_used));
5200 consider_sending_fc (vl);
5201 return; /* We have a message, but flow control says "nope" */
5202 }
5203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5204 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
5205 GNUNET_i2s (&vl->target));
5206 /* Notify queues at direct neighbours that we are interested */
5207 now = GNUNET_TIME_absolute_get ();
5208 if (NULL != n)
5209 {
5210 for (struct Queue *queue = n->queue_head; NULL != queue;
5211 queue = queue->next_neighbour)
5212 {
5213 if ((GNUNET_YES == queue->idle) &&
5214 (queue->validated_until.abs_value_us > now.abs_value_us))
5215 {
5216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5217 "Direct neighbour %s not stalled\n",
5218 GNUNET_i2s (&n->pid));
5219 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5220 queue,
5221 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
5222 elig = GNUNET_YES;
5223 }
5224 else
5225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5226 "Neighbour Queue QID: %u (%u) busy or invalid\n",
5227 queue->qid,
5228 queue->idle);
5229 }
5230 }
5231 /* Notify queues via DV that we are interested */
5232 if (NULL != dv)
5233 {
5234 /* Do DV with lower scheduler priority, which effectively means that
5235 IF a neighbour exists and is available, we prefer it. */
5236 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5237 pos = pos->next_dv)
5238 {
5239 struct Neighbour *nh = pos->next_hop;
5240
5241
5242 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
5243 continue; /* skip this one: path not validated */
5244 else
5245 {
5246 vl_next_hop = lookup_virtual_link (&nh->pid);
5247 GNUNET_assert (NULL != vl_next_hop);
5248 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
5249 vl_next_hop->outbound_fc_window_size)
5250 {
5251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5252 "Stalled message %llu transmission on next hop %s due to flow control: %llu < %llu\n",
5253 pm->logging_uuid,
5254 GNUNET_i2s (&vl_next_hop->target),
5255 (unsigned long
5256 long) vl_next_hop->outbound_fc_window_size,
5257 (unsigned long long) (pm->bytes_msg
5258 + vl_next_hop->
5259 outbound_fc_window_size_used));
5260 consider_sending_fc (vl_next_hop);
5261 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
5262 }
5263 for (struct Queue *queue = nh->queue_head; NULL != queue;
5264 queue = queue->next_neighbour)
5265 if ((GNUNET_YES == queue->idle) &&
5266 (queue->validated_until.abs_value_us > now.abs_value_us))
5267 {
5268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5269 "Next hop neighbour %s not stalled\n",
5270 GNUNET_i2s (&nh->pid));
5271 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5272 queue,
5273 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
5274 elig = GNUNET_YES;
5275 }
5276 else
5277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5278 "DV Queue QID: %u (%u) busy or invalid\n",
5279 queue->qid,
5280 queue->idle);
5281 }
5282 }
5283 }
5284 if (GNUNET_YES == elig)
5285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5286 "Eligible message %llu of size %u to %s: %llu/%llu\n",
5287 pm->logging_uuid,
5288 pm->bytes_msg,
5289 GNUNET_i2s (&vl->target),
5290 (unsigned long long) vl->outbound_fc_window_size,
5291 (unsigned long long) (pm->bytes_msg
5292 + vl->outbound_fc_window_size_used));
5293 break;
5294 }
5295}
5296
5297
5298/**
5299 * Client asked for transmission to a peer. Process the request.
5300 *
5301 * @param cls the client
5302 * @param obm the send message that was sent
5303 */
5304static void
5305handle_client_send (void *cls, const struct OutboundMessage *obm)
5306{
5307 struct TransportClient *tc = cls;
5308 struct PendingMessage *pm;
5309 const struct GNUNET_MessageHeader *obmm;
5310 uint32_t bytes_msg;
5311 struct VirtualLink *vl;
5312 enum GNUNET_MQ_PriorityPreferences pp;
5313
5314 GNUNET_assert (CT_CORE == tc->type);
5315 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5316 bytes_msg = ntohs (obmm->size);
5317 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
5318 vl = lookup_virtual_link (&obm->peer);
5319 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5320 {
5321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5322 "Don't have %s as a neighbour (anymore).\n",
5323 GNUNET_i2s (&obm->peer));
5324 /* Failure: don't have this peer as a neighbour (anymore).
5325 Might have gone down asynchronously, so this is NOT
5326 a protocol violation by CORE. Still count the event,
5327 as this should be rare. */
5328 GNUNET_SERVICE_client_continue (tc->client);
5329 GNUNET_STATISTICS_update (GST_stats,
5330 "# messages dropped (neighbour unknown)",
5331 1,
5332 GNUNET_NO);
5333 return;
5334 }
5335
5336 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
5337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5338 "1 created pm %p storing vl %p\n",
5339 pm,
5340 vl);
5341 pm->logging_uuid = logging_uuid_gen++;
5342 pm->prefs = pp;
5343 pm->client = tc;
5344 pm->vl = vl;
5345 pm->bytes_msg = bytes_msg;
5346 memcpy (&pm[1], obmm, bytes_msg);
5347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5348 "Sending %u bytes as <%llu> to %s\n",
5349 bytes_msg,
5350 pm->logging_uuid,
5351 GNUNET_i2s (&obm->peer));
5352 GNUNET_CONTAINER_MDLL_insert (client,
5353 tc->details.core.pending_msg_head,
5354 tc->details.core.pending_msg_tail,
5355 pm);
5356 GNUNET_CONTAINER_MDLL_insert (vl,
5357 vl->pending_msg_head,
5358 vl->pending_msg_tail,
5359 pm);
5360 check_vl_transmission (vl);
5361 GNUNET_SERVICE_client_continue (tc->client);
5362}
5363
5364
5365/**
5366 * Communicator requests backchannel transmission. Process the request.
5367 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
5368 * (which for now has exactly the same format, only a different message type)
5369 * and passes it on for routing.
5370 *
5371 * @param cls the client
5372 * @param cb the send message that was sent
5373 */
5374static void
5375handle_communicator_backchannel (
5376 void *cls,
5377 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
5378{
5379 struct Neighbour *n;
5380 struct VirtualLink *vl;
5381 struct TransportClient *tc = cls;
5382 const struct GNUNET_MessageHeader *inbox =
5383 (const struct GNUNET_MessageHeader *) &cb[1];
5384 uint16_t isize = ntohs (inbox->size);
5385 const char *is = ((const char *) &cb[1]) + isize;
5386 size_t slen = strlen (is) + 1;
5387 char
5388 mbuf[slen + isize
5389 + sizeof(struct
5390 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
5391 struct TransportBackchannelEncapsulationMessage *be =
5392 (struct TransportBackchannelEncapsulationMessage *) mbuf;
5393
5394 /* 0-termination of 'is' was checked already in
5395 #check_communicator_backchannel() */
5396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5397 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
5398 GNUNET_i2s (&cb->pid),
5399 is,
5400 ntohs (inbox->type),
5401 ntohs (inbox->size));
5402 /* encapsulate and encrypt message */
5403 be->header.type =
5404 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
5405 be->header.size = htons (sizeof(mbuf));
5406 memcpy (&be[1], inbox, isize);
5407 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
5408 + isize],
5409 is,
5410 strlen (is) + 1);
5411 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
5412 vl = lookup_virtual_link (&cb->pid);
5413 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5414 {
5415 route_control_message_without_fc (vl, &be->header, RMO_DV_ALLOWED);
5416 }
5417 else
5418 {
5419 /* Use route via neighbour */
5420 n = lookup_neighbour (&cb->pid);
5421 if (NULL != n)
5422 route_via_neighbour (
5423 n,
5424 &be->header,
5425 RMO_NONE);
5426 }
5427 GNUNET_SERVICE_client_continue (tc->client);
5428}
5429
5430
5431/**
5432 * Address of our peer added. Test message is well-formed.
5433 *
5434 * @param cls the client
5435 * @param aam the send message that was sent
5436 * @return #GNUNET_OK if message is well-formed
5437 */
5438static int
5439check_add_address (void *cls,
5440 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5441{
5442 struct TransportClient *tc = cls;
5443
5444 if (CT_COMMUNICATOR != tc->type)
5445 {
5446 GNUNET_break (0);
5447 return GNUNET_SYSERR;
5448 }
5449 GNUNET_MQ_check_zero_termination (aam);
5450 return GNUNET_OK;
5451}
5452
5453
5454/**
5455 * Ask peerstore to store our address.
5456 *
5457 * @param cls an `struct AddressListEntry *`
5458 */
5459static void
5460store_pi (void *cls);
5461
5462
5463/**
5464 * Function called when peerstore is done storing our address.
5465 *
5466 * @param cls a `struct AddressListEntry`
5467 * @param success #GNUNET_YES if peerstore was successful
5468 */
5469static void
5470peerstore_store_own_cb (void *cls, int success)
5471{
5472 struct AddressListEntry *ale = cls;
5473
5474 ale->sc = NULL;
5475 if (GNUNET_YES != success)
5476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5477 "Failed to store our own address `%s' in peerstore!\n",
5478 ale->address);
5479 else
5480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5481 "Successfully stored our own address `%s' in peerstore!\n",
5482 ale->address);
5483 /* refresh period is 1/4 of expiration time, that should be plenty
5484 without being excessive. */
5485 ale->st =
5486 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5487 4ULL),
5488 &store_pi,
5489 ale);
5490}
5491
5492
5493/**
5494 * Ask peerstore to store our address.
5495 *
5496 * @param cls an `struct AddressListEntry *`
5497 */
5498static void
5499store_pi (void *cls)
5500{
5501 struct AddressListEntry *ale = cls;
5502 void *addr;
5503 size_t addr_len;
5504 struct GNUNET_TIME_Absolute expiration;
5505
5506 ale->st = NULL;
5507 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5509 "Storing our address `%s' in peerstore until %s!\n",
5510 ale->address,
5511 GNUNET_STRINGS_absolute_time_to_string (expiration));
5512 GNUNET_HELLO_sign_address (ale->address,
5513 ale->nt,
5514 hello_mono_time,
5515 GST_my_private_key,
5516 &addr,
5517 &addr_len);
5518 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5519 "transport",
5520 &GST_my_identity,
5521 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5522 addr,
5523 addr_len,
5524 expiration,
5525 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5526 &peerstore_store_own_cb,
5527 ale);
5528 GNUNET_free (addr);
5529 if (NULL == ale->sc)
5530 {
5531 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5532 "Failed to store our address `%s' with peerstore\n",
5533 ale->address);
5534 ale->st =
5535 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5536 }
5537}
5538
5539
5540/**
5541 * Address of our peer added. Process the request.
5542 *
5543 * @param cls the client
5544 * @param aam the send message that was sent
5545 */
5546static void
5547handle_add_address (void *cls,
5548 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5549{
5550 struct TransportClient *tc = cls;
5551 struct AddressListEntry *ale;
5552 size_t slen;
5553
5554 /* 0-termination of &aam[1] was checked in #check_add_address */
5555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5556 "Communicator added address `%s'!\n",
5557 (const char *) &aam[1]);
5558 slen = ntohs (aam->header.size) - sizeof(*aam);
5559 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5560 ale->tc = tc;
5561 ale->address = (const char *) &ale[1];
5562 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5563 ale->aid = aam->aid;
5564 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5565 memcpy (&ale[1], &aam[1], slen);
5566 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5567 tc->details.communicator.addr_tail,
5568 ale);
5569 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5570 GNUNET_SERVICE_client_continue (tc->client);
5571}
5572
5573
5574/**
5575 * Address of our peer deleted. Process the request.
5576 *
5577 * @param cls the client
5578 * @param dam the send message that was sent
5579 */
5580static void
5581handle_del_address (void *cls,
5582 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5583{
5584 struct TransportClient *tc = cls;
5585 struct AddressListEntry *alen;
5586
5587 if (CT_COMMUNICATOR != tc->type)
5588 {
5589 GNUNET_break (0);
5590 GNUNET_SERVICE_client_drop (tc->client);
5591 return;
5592 }
5593 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5594 NULL != ale;
5595 ale = alen)
5596 {
5597 alen = ale->next;
5598 if (dam->aid != ale->aid)
5599 continue;
5600 GNUNET_assert (ale->tc == tc);
5601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5602 "Communicator deleted address `%s'!\n",
5603 ale->address);
5604 free_address_list_entry (ale);
5605 GNUNET_SERVICE_client_continue (tc->client);
5606 return;
5607 }
5608 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5609 "Communicator removed address we did not even have.\n");
5610 GNUNET_SERVICE_client_continue (tc->client);
5611 // GNUNET_SERVICE_client_drop (tc->client);
5612}
5613
5614
5615/**
5616 * Given an inbound message @a msg from a communicator @a cmc,
5617 * demultiplex it based on the type calling the right handler.
5618 *
5619 * @param cmc context for demultiplexing
5620 * @param msg message to demultiplex
5621 */
5622static void
5623demultiplex_with_cmc (struct CommunicatorMessageContext *cmc);
5624
5625
5626/**
5627 * Function called when we are done giving a message of a certain
5628 * size to CORE and should thus decrement the number of bytes of
5629 * RAM reserved for that peer's MQ.
5630 *
5631 * @param cls a `struct CoreSentContext`
5632 */
5633static void
5634core_env_sent_cb (void *cls)
5635{
5636 struct CoreSentContext *ctx = cls;
5637 struct VirtualLink *vl = ctx->vl;
5638
5639 if (NULL == vl)
5640 {
5641 /* lost the link in the meantime, ignore */
5642 GNUNET_free (ctx);
5643 return;
5644 }
5645 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5646 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5647 vl->incoming_fc_window_size_ram -= ctx->size;
5648 vl->incoming_fc_window_size_used += ctx->isize;
5649 consider_sending_fc (vl);
5650 GNUNET_free (ctx);
5651}
5652
5653
5654static void
5655finish_handling_raw_message (struct VirtualLink *vl,
5656 const struct GNUNET_MessageHeader *mh,
5657 struct CommunicatorMessageContext *cmc,
5658 unsigned int continue_client)
5659{
5660 uint16_t size = ntohs (mh->size);
5661 int have_core;
5662
5663 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5664 {
5665 GNUNET_STATISTICS_update (GST_stats,
5666 "# CORE messages dropped (FC arithmetic overflow)",
5667 1,
5668 GNUNET_NO);
5669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5670 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
5671 (unsigned int) ntohs (mh->type),
5672 (unsigned int) ntohs (mh->size));
5673 finish_cmc_handling_with_continue (cmc, continue_client);
5674 return;
5675 }
5676 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5677 {
5678 GNUNET_STATISTICS_update (GST_stats,
5679 "# CORE messages dropped (FC window overflow)",
5680 1,
5681 GNUNET_NO);
5682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5683 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
5684 (unsigned int) ntohs (mh->type),
5685 (unsigned int) ntohs (mh->size));
5686 finish_cmc_handling_with_continue (cmc, continue_client);
5687 return;
5688 }
5689
5690 /* Forward to all CORE clients */
5691 have_core = GNUNET_NO;
5692 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5693 {
5694 struct GNUNET_MQ_Envelope *env;
5695 struct InboundMessage *im;
5696 struct CoreSentContext *ctx;
5697
5698 if (CT_CORE != tc->type)
5699 continue;
5700 vl->incoming_fc_window_size_ram += size;
5701 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5702 ctx = GNUNET_new (struct CoreSentContext);
5703 ctx->vl = vl;
5704 ctx->size = size;
5705 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5706 have_core = GNUNET_YES;
5707 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5708 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5709 im->peer = cmc->im.sender;
5710 memcpy (&im[1], mh, size);
5711 GNUNET_MQ_send (tc->mq, env);
5712 vl->core_recv_window--;
5713 }
5714 if (GNUNET_NO == have_core)
5715 {
5716 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5717 "Dropped message to CORE: no CORE client connected!\n");
5718 /* Nevertheless, count window as used, as it is from the
5719 perspective of the other peer! */
5720 vl->incoming_fc_window_size_used += size;
5721 /* TODO-M1 */
5722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5723 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
5724 (unsigned int) ntohs (mh->type),
5725 (unsigned int) ntohs (mh->size));
5726 finish_cmc_handling_with_continue (cmc, continue_client);
5727 return;
5728 }
5729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5730 "Delivered message from %s of type %u to CORE recv window %u\n",
5731 GNUNET_i2s (&cmc->im.sender),
5732 ntohs (mh->type),
5733 vl->core_recv_window);
5734 if (vl->core_recv_window > 0)
5735 {
5736 finish_cmc_handling_with_continue (cmc, continue_client);
5737 return;
5738 }
5739 /* Wait with calling #finish_cmc_handling(cmc) until the message
5740 was processed by CORE MQs (for CORE flow control)! */
5741 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5742}
5743
5744
5745
5746/**
5747 * Communicator gave us an unencapsulated message to pass as-is to
5748 * CORE. Process the request.
5749 *
5750 * @param cls a `struct CommunicatorMessageContext` (must call
5751 * #finish_cmc_handling() when done)
5752 * @param mh the message that was received
5753 */
5754static void
5755handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5756{
5757 struct CommunicatorMessageContext *cmc = cls;
5758 // struct CommunicatorMessageContext *cmc_copy =
5759 // GNUNET_new (struct CommunicatorMessageContext);
5760 struct GNUNET_MessageHeader *mh_copy;
5761 struct RingBufferEntry *rbe;
5762 struct VirtualLink *vl;
5763 uint16_t size = ntohs (mh->size);
5764
5765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5766 "Handling raw message of type %u with %u bytes\n",
5767 (unsigned int) ntohs (mh->type),
5768 (unsigned int) ntohs (mh->size));
5769
5770 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5771 (size < sizeof(struct GNUNET_MessageHeader)))
5772 {
5773 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5774
5775 GNUNET_break (0);
5776 finish_cmc_handling (cmc);
5777 GNUNET_SERVICE_client_drop (client);
5778 return;
5779 }
5780 vl = lookup_virtual_link (&cmc->im.sender);
5781 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5782 {
5783 /* FIXME: sender is giving us messages for CORE but we don't have
5784 the link up yet! I *suspect* this can happen right now (i.e.
5785 sender has verified us, but we didn't verify sender), but if
5786 we pass this on, CORE would be confused (link down, messages
5787 arrive). We should investigate more if this happens often,
5788 or in a persistent manner, and possibly do "something" about
5789 it. Thus logging as error for now. */
5790
5791 mh_copy = GNUNET_malloc (size);
5792 rbe = GNUNET_new (struct RingBufferEntry);
5793 rbe->cmc = cmc;
5794 /*cmc_copy->tc = cmc->tc;
5795 cmc_copy->im = cmc->im;*/
5796 GNUNET_memcpy (mh_copy, mh, size);
5797
5798 rbe->mh = mh_copy;
5799
5800 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
5801 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
5802 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
5803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5804 "Storing message for %s and type %u (%u) in ring buffer\n",
5805 GNUNET_i2s (&cmc->im.sender),
5806 (unsigned int) ntohs (mh->type),
5807 (unsigned int) ntohs (mh_copy->type));
5808 if (RING_BUFFER_SIZE - 1 == ring_buffer_head)
5809 {
5810 ring_buffer_head = 0;
5811 is_ring_buffer_full = GNUNET_YES;
5812 }
5813 else
5814 ring_buffer_head++;
5815
5816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5817 "%u items stored in ring buffer\n",
5818 ring_buffer_head);
5819
5820 /*GNUNET_break_op (0);
5821 GNUNET_STATISTICS_update (GST_stats,
5822 "# CORE messages dropped (virtual link still down)",
5823 1,
5824 GNUNET_NO);
5825
5826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5827 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
5828 (unsigned int) ntohs (mh->type),
5829 (unsigned int) ntohs (mh->size));
5830 finish_cmc_handling (cmc);*/
5831 GNUNET_SERVICE_client_continue (cmc->tc->client);
5832 // GNUNET_free (cmc);
5833 return;
5834 }
5835 finish_handling_raw_message (vl, mh, cmc, GNUNET_YES);
5836}
5837
5838
5839/**
5840 * Communicator gave us a fragment box. Check the message.
5841 *
5842 * @param cls a `struct CommunicatorMessageContext`
5843 * @param fb the send message that was sent
5844 * @return #GNUNET_YES if message is well-formed
5845 */
5846static int
5847check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5848{
5849 uint16_t size = ntohs (fb->header.size);
5850 uint16_t bsize = size - sizeof(*fb);
5851
5852 (void) cls;
5853 if (0 == bsize)
5854 {
5855 GNUNET_break_op (0);
5856 return GNUNET_SYSERR;
5857 }
5858 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5859 {
5860 GNUNET_break_op (0);
5861 return GNUNET_SYSERR;
5862 }
5863 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5864 {
5865 GNUNET_break_op (0);
5866 return GNUNET_SYSERR;
5867 }
5868 return GNUNET_YES;
5869}
5870
5871
5872/**
5873 * Clean up an idle cumulative acknowledgement data structure.
5874 *
5875 * @param cls a `struct AcknowledgementCummulator *`
5876 */
5877static void
5878destroy_ack_cummulator (void *cls)
5879{
5880 struct AcknowledgementCummulator *ac = cls;
5881
5882 ac->task = NULL;
5883 GNUNET_assert (0 == ac->num_acks);
5884 GNUNET_assert (
5885 GNUNET_YES ==
5886 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5887 GNUNET_free (ac);
5888}
5889
5890
5891/**
5892 * Do the transmission of a cumulative acknowledgement now.
5893 *
5894 * @param cls a `struct AcknowledgementCummulator *`
5895 */
5896static void
5897transmit_cummulative_ack_cb (void *cls)
5898{
5899 struct Neighbour *n;
5900 struct VirtualLink *vl;
5901 struct AcknowledgementCummulator *ac = cls;
5902 char buf[sizeof(struct TransportReliabilityAckMessage)
5903 + ac->num_acks
5904 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5905 struct TransportReliabilityAckMessage *ack =
5906 (struct TransportReliabilityAckMessage *) buf;
5907 struct TransportCummulativeAckPayloadP *ap;
5908
5909 ac->task = NULL;
5910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5911 "Sending ACK with %u components to %s\n",
5912 ac->num_acks,
5913 GNUNET_i2s (&ac->target));
5914 GNUNET_assert (0 < ac->num_acks);
5915 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5916 ack->header.size =
5917 htons (sizeof(*ack)
5918 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
5919 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
5920 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5921 for (unsigned int i = 0; i < ac->num_acks; i++)
5922 {
5923 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5924 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5925 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5926 }
5927 /*route_control_message_without_fc (
5928 &ac->target,
5929 &ack->header,
5930 RMO_DV_ALLOWED);*/
5931 vl = lookup_virtual_link (&ac->target);
5932 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5933 {
5934 route_control_message_without_fc (
5935 vl,
5936 &ack->header,
5937 RMO_DV_ALLOWED);
5938 }
5939 else
5940 {
5941 /* Use route via neighbour */
5942 n = lookup_neighbour (&ac->target);
5943 if (NULL != n)
5944 route_via_neighbour (
5945 n,
5946 &ack->header,
5947 RMO_NONE);
5948 }
5949 ac->num_acks = 0;
5950 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5951 &destroy_ack_cummulator,
5952 ac);
5953}
5954
5955
5956/**
5957 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5958 * transmission by at most @a ack_delay.
5959 *
5960 * @param pid target peer
5961 * @param ack_uuid UUID to ack
5962 * @param max_delay how long can the ACK wait
5963 */
5964static void
5965cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5966 const struct AcknowledgementUUIDP *ack_uuid,
5967 struct GNUNET_TIME_Absolute max_delay)
5968{
5969 struct AcknowledgementCummulator *ac;
5970
5971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5972 "Scheduling ACK %s for transmission to %s\n",
5973 GNUNET_uuid2s (&ack_uuid->value),
5974 GNUNET_i2s (pid));
5975 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5976 if (NULL == ac)
5977 {
5978 ac = GNUNET_new (struct AcknowledgementCummulator);
5979 ac->target = *pid;
5980 ac->min_transmission_time = max_delay;
5981 GNUNET_assert (GNUNET_YES ==
5982 GNUNET_CONTAINER_multipeermap_put (
5983 ack_cummulators,
5984 &ac->target,
5985 ac,
5986 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5987 }
5988 else
5989 {
5990 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5991 {
5992 /* must run immediately, ack buffer full! */
5993 transmit_cummulative_ack_cb (ac);
5994 }
5995 GNUNET_SCHEDULER_cancel (ac->task);
5996 ac->min_transmission_time =
5997 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5998 }
5999 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
6000 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
6001 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
6002 ac->num_acks++;
6003 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
6004 &transmit_cummulative_ack_cb,
6005 ac);
6006}
6007
6008
6009/**
6010 * Closure for #find_by_message_uuid.
6011 */
6012struct FindByMessageUuidContext
6013{
6014 /**
6015 * UUID to look for.
6016 */
6017 struct MessageUUIDP message_uuid;
6018
6019 /**
6020 * Set to the reassembly context if found.
6021 */
6022 struct ReassemblyContext *rc;
6023};
6024
6025
6026/**
6027 * Iterator called to find a reassembly context by the message UUID in the
6028 * multihashmap32.
6029 *
6030 * @param cls a `struct FindByMessageUuidContext`
6031 * @param key a key (unused)
6032 * @param value a `struct ReassemblyContext`
6033 * @return #GNUNET_YES if not found, #GNUNET_NO if found
6034 */
6035static int
6036find_by_message_uuid (void *cls, uint32_t key, void *value)
6037{
6038 struct FindByMessageUuidContext *fc = cls;
6039 struct ReassemblyContext *rc = value;
6040
6041 (void) key;
6042 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
6043 {
6044 fc->rc = rc;
6045 return GNUNET_NO;
6046 }
6047 return GNUNET_YES;
6048}
6049
6050
6051/**
6052 * Communicator gave us a fragment. Process the request.
6053 *
6054 * @param cls a `struct CommunicatorMessageContext` (must call
6055 * #finish_cmc_handling() when done)
6056 * @param fb the message that was received
6057 */
6058static void
6059handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
6060{
6061 struct CommunicatorMessageContext *cmc = cls;
6062 struct VirtualLink *vl;
6063 struct ReassemblyContext *rc;
6064 const struct GNUNET_MessageHeader *msg;
6065 uint16_t msize;
6066 uint16_t fsize;
6067 uint16_t frag_off;
6068 char *target;
6069 struct GNUNET_TIME_Relative cdelay;
6070 struct FindByMessageUuidContext fc;
6071
6072 vl = lookup_virtual_link (&cmc->im.sender);
6073 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6074 {
6075 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
6076
6077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6078 "No virtual link for %s to handle fragment\n",
6079 GNUNET_i2s (&cmc->im.sender));
6080 GNUNET_break (0);
6081 finish_cmc_handling (cmc);
6082 GNUNET_SERVICE_client_drop (client);
6083 return;
6084 }
6085 if (NULL == vl->reassembly_map)
6086 {
6087 vl->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
6088 vl->reassembly_heap =
6089 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
6090 vl->reassembly_timeout_task =
6091 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
6092 &reassembly_cleanup_task,
6093 vl);
6094 }
6095 msize = ntohs (fb->msg_size);
6096 fc.message_uuid = fb->msg_uuid;
6097 fc.rc = NULL;
6098 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (vl->reassembly_map,
6099 fb->msg_uuid.uuid,
6100 &find_by_message_uuid,
6101 &fc);
6102 fsize = ntohs (fb->header.size) - sizeof(*fb);
6103 if (NULL == (rc = fc.rc))
6104 {
6105 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
6106 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
6107 rc->msg_uuid = fb->msg_uuid;
6108 rc->virtual_link = vl;
6109 rc->msg_size = msize;
6110 rc->reassembly_timeout =
6111 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
6112 rc->last_frag = GNUNET_TIME_absolute_get ();
6113 rc->hn = GNUNET_CONTAINER_heap_insert (vl->reassembly_heap,
6114 rc,
6115 rc->reassembly_timeout.abs_value_us);
6116 GNUNET_assert (GNUNET_OK ==
6117 GNUNET_CONTAINER_multihashmap32_put (
6118 vl->reassembly_map,
6119 rc->msg_uuid.uuid,
6120 rc,
6121 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
6122 target = (char *) &rc[1];
6123 rc->bitfield = (uint8_t *) (target + rc->msg_size);
6124 if (fsize != rc->msg_size)
6125 rc->msg_missing = rc->msg_size;
6126 else
6127 rc->msg_missing = 0;
6128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6129 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %u\n",
6130 fsize,
6131 ntohs (fb->frag_off),
6132 msize,
6133 rc->msg_missing,
6134 GNUNET_i2s (&cmc->im.sender),
6135 (unsigned int) fb->msg_uuid.uuid);
6136 }
6137 else
6138 {
6139 target = (char *) &rc[1];
6140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6141 "Received fragment at offset %u/%u from %s for message %u\n",
6142 ntohs (fb->frag_off),
6143 msize,
6144 GNUNET_i2s (&cmc->im.sender),
6145 (unsigned int) fb->msg_uuid.uuid);
6146 }
6147 if (msize != rc->msg_size)
6148 {
6149 GNUNET_break (0);
6150 finish_cmc_handling (cmc);
6151 return;
6152 }
6153
6154 /* reassemble */
6155 if (0 == fsize)
6156 {
6157 GNUNET_break (0);
6158 finish_cmc_handling (cmc);
6159 return;
6160 }
6161 frag_off = ntohs (fb->frag_off);
6162 if (frag_off + fsize > msize)
6163 {
6164 /* Fragment (plus fragment size) exceeds message size! */
6165 GNUNET_break_op (0);
6166 finish_cmc_handling (cmc);
6167 return;
6168 }
6169 memcpy (&target[frag_off], &fb[1], fsize);
6170 /* update bitfield and msg_missing */
6171 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
6172 {
6173 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
6174 {
6175 rc->bitfield[i / 8] |= (1 << (i % 8));
6176 rc->msg_missing--;
6177 }
6178 }
6179
6180 /* Compute cumulative ACK */
6181 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
6182 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
6183 if (0 == rc->msg_missing)
6184 cdelay = GNUNET_TIME_UNIT_ZERO;
6185 cummulative_ack (&cmc->im.sender,
6186 &fb->ack_uuid,
6187 GNUNET_TIME_relative_to_absolute (cdelay));
6188 rc->last_frag = GNUNET_TIME_absolute_get ();
6189 /* is reassembly complete? */
6190 if (0 != rc->msg_missing)
6191 {
6192 finish_cmc_handling (cmc);
6193 return;
6194 }
6195 /* reassembly is complete, verify result */
6196 msg = (const struct GNUNET_MessageHeader *) &rc[1];
6197 if (ntohs (msg->size) != rc->msg_size)
6198 {
6199 GNUNET_break (0);
6200 free_reassembly_context (rc);
6201 finish_cmc_handling (cmc);
6202 return;
6203 }
6204 /* successful reassembly */
6205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6206 "Fragment reassembly complete for message %u\n",
6207 (unsigned int) fb->msg_uuid.uuid);
6208 /* FIXME: check that the resulting msg is NOT a
6209 DV Box or Reliability Box, as that is NOT allowed! */
6210 cmc->mh = msg;
6211 demultiplex_with_cmc (cmc);
6212 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
6213 en-route and we forget that we finished this reassembly immediately!
6214 -> keep around until timeout?
6215 -> shorten timeout based on ACK? */
6216 free_reassembly_context (rc);
6217}
6218
6219
6220/**
6221 * Communicator gave us a reliability box. Check the message.
6222 *
6223 * @param cls a `struct CommunicatorMessageContext`
6224 * @param rb the send message that was sent
6225 * @return #GNUNET_YES if message is well-formed
6226 */
6227static int
6228check_reliability_box (void *cls,
6229 const struct TransportReliabilityBoxMessage *rb)
6230{
6231 (void) cls;
6232 const struct GNUNET_MessageHeader *inbox = (const struct
6233 GNUNET_MessageHeader *) &rb[1];
6234
6235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6236 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
6237 ntohs (rb->header.size),
6238 ntohs (inbox->type),
6239 ntohs (inbox->size),
6240 sizeof (struct TransportReliabilityBoxMessage),
6241 sizeof (struct GNUNET_MessageHeader));
6242 GNUNET_MQ_check_boxed_message (rb);
6243 return GNUNET_YES;
6244}
6245
6246
6247/**
6248 * Communicator gave us a reliability box. Process the request.
6249 *
6250 * @param cls a `struct CommunicatorMessageContext` (must call
6251 * #finish_cmc_handling() when done)
6252 * @param rb the message that was received
6253 */
6254static void
6255handle_reliability_box (void *cls,
6256 const struct TransportReliabilityBoxMessage *rb)
6257{
6258 struct CommunicatorMessageContext *cmc = cls;
6259 const struct GNUNET_MessageHeader *inbox =
6260 (const struct GNUNET_MessageHeader *) &rb[1];
6261 struct GNUNET_TIME_Relative rtt;
6262
6263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6264 "Received reliability box from %s with UUID %s of type %u\n",
6265 GNUNET_i2s (&cmc->im.sender),
6266 GNUNET_uuid2s (&rb->ack_uuid.value),
6267 (unsigned int) ntohs (inbox->type));
6268 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
6269 do not really have an RTT for the
6270 * incoming* queue (should we have
6271 the sender add it to the rb message?) */
6272 cummulative_ack (
6273 &cmc->im.sender,
6274 &rb->ack_uuid,
6275 (0 == ntohl (rb->ack_countdown))
6276 ? GNUNET_TIME_UNIT_ZERO_ABS
6277 : GNUNET_TIME_relative_to_absolute (
6278 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
6279 /* continue with inner message */
6280 /* FIXME: check that inbox is NOT a DV Box, fragment or another
6281 reliability box (not allowed!) */
6282 cmc->mh = inbox;
6283 demultiplex_with_cmc (cmc);
6284}
6285
6286
6287/**
6288 * Check if we have advanced to another age since the last time. If
6289 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
6290 * the current age)
6291 *
6292 * @param[in,out] pd data to update
6293 * @param age current age
6294 */
6295static void
6296update_pd_age (struct PerformanceData *pd, unsigned int age)
6297{
6298 unsigned int sage;
6299
6300 if (age == pd->last_age)
6301 return; /* nothing to do */
6302 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
6303 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
6304 {
6305 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
6306
6307 the->bytes_sent = 0;
6308 the->bytes_received = 0;
6309 }
6310 pd->last_age = age;
6311}
6312
6313
6314/**
6315 * Update @a pd based on the latest @a rtt and the number of bytes
6316 * that were confirmed to be successfully transmitted.
6317 *
6318 * @param[in,out] pd data to update
6319 * @param rtt latest round-trip time
6320 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
6321 */
6322static void
6323update_performance_data (struct PerformanceData *pd,
6324 struct GNUNET_TIME_Relative rtt,
6325 uint16_t bytes_transmitted_ok)
6326{
6327 uint64_t nval = rtt.rel_value_us;
6328 uint64_t oval = pd->aged_rtt.rel_value_us;
6329 unsigned int age = get_age ();
6330 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
6331
6332 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
6333 pd->aged_rtt = rtt;
6334 else
6335 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
6336 update_pd_age (pd, age);
6337 the->bytes_received += bytes_transmitted_ok;
6338}
6339
6340
6341/**
6342 * We have successfully transmitted data via @a q, update metrics.
6343 *
6344 * @param q queue to update
6345 * @param rtt round trip time observed
6346 * @param bytes_transmitted_ok number of bytes successfully transmitted
6347 */
6348static void
6349update_queue_performance (struct Queue *q,
6350 struct GNUNET_TIME_Relative rtt,
6351 uint16_t bytes_transmitted_ok)
6352{
6353 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
6354}
6355
6356
6357/**
6358 * We have successfully transmitted data via @a dvh, update metrics.
6359 *
6360 * @param dvh distance vector path data to update
6361 * @param rtt round trip time observed
6362 * @param bytes_transmitted_ok number of bytes successfully transmitted
6363 */
6364static void
6365update_dvh_performance (struct DistanceVectorHop *dvh,
6366 struct GNUNET_TIME_Relative rtt,
6367 uint16_t bytes_transmitted_ok)
6368{
6369 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
6370}
6371
6372
6373/**
6374 * We have completed transmission of @a pm, remove it from
6375 * the transmission queues (and if it is a fragment, continue
6376 * up the tree as necessary).
6377 *
6378 * @param pm pending message that was transmitted
6379 */
6380static void
6381completed_pending_message (struct PendingMessage *pm)
6382{
6383 struct PendingMessage *pos;
6384
6385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6386 "Complete transmission of message %llu %u\n",
6387 pm->logging_uuid,
6388 pm->pmt);
6389 switch (pm->pmt)
6390 {
6391 case PMT_CORE:
6392 case PMT_RELIABILITY_BOX:
6393 /* Full message sent, we are done */
6394 client_send_response (pm);
6395 return;
6396
6397 case PMT_FRAGMENT_BOX:
6398 /* Fragment sent over reliable channel */
6399 pos = pm->frag_parent;
6400 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6401 free_pending_message (pm);
6402 /* check if subtree is done */
6403 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6404 (NULL != pos->frag_parent))
6405 {
6406 pm = pos;
6407 pos = pm->frag_parent;
6408 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
6409 {
6410 client_send_response (pm);
6411 return;
6412 }
6413 else if (PMT_DV_BOX == pm->pmt)
6414 {
6415 client_send_response (pos);
6416 return;
6417 }
6418 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6419 free_pending_message (pm);
6420 }
6421
6422 /* Was this the last applicable fragment? */
6423 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
6424 (pos->frag_off == pos->bytes_msg))
6425 client_send_response (pos);
6426 return;
6427
6428 case PMT_DV_BOX:
6429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6430 "Completed transmission of message %llu (DV Box)\n",
6431 pm->logging_uuid);
6432 if (NULL != pm->frag_parent)
6433 {
6434 if (NULL != pm->bpm)
6435 {
6436 GNUNET_free (pm->bpm);
6437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6438 "Freed bpm\n");
6439 }
6440 pos = pm->frag_parent;
6441 free_pending_message (pm);
6442 pos->bpm = NULL;
6443 client_send_response (pos);
6444 }
6445 else
6446 client_send_response (pm);
6447 return;
6448 }
6449}
6450
6451
6452/**
6453 * The @a pa was acknowledged, process the acknowledgement.
6454 *
6455 * @param pa the pending acknowledgement that was satisfied
6456 * @param ack_delay artificial delay from cumulative acks created by the
6457 * other peer
6458 */
6459static void
6460handle_acknowledged (struct PendingAcknowledgement *pa,
6461 struct GNUNET_TIME_Relative ack_delay)
6462{
6463 struct GNUNET_TIME_Relative delay;
6464
6465 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
6466 if (delay.rel_value_us > ack_delay.rel_value_us)
6467 delay = GNUNET_TIME_UNIT_ZERO;
6468 else
6469 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
6470 if (NULL != pa->queue)
6471 update_queue_performance (pa->queue, delay, pa->message_size);
6472 if (NULL != pa->dvh)
6473 update_dvh_performance (pa->dvh, delay, pa->message_size);
6474 if (NULL != pa->pm)
6475 completed_pending_message (pa->pm);
6476 free_pending_acknowledgement (pa);
6477}
6478
6479
6480/**
6481 * Communicator gave us a reliability ack. Check it is well-formed.
6482 *
6483 * @param cls a `struct CommunicatorMessageContext` (unused)
6484 * @param ra the message that was received
6485 * @return #GNUNET_Ok if @a ra is well-formed
6486 */
6487static int
6488check_reliability_ack (void *cls,
6489 const struct TransportReliabilityAckMessage *ra)
6490{
6491 unsigned int n_acks;
6492
6493 (void) cls;
6494 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6495 / sizeof(struct TransportCummulativeAckPayloadP);
6496 if (0 == n_acks)
6497 {
6498 GNUNET_break_op (0);
6499 return GNUNET_SYSERR;
6500 }
6501 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
6502 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
6503 {
6504 GNUNET_break_op (0);
6505 return GNUNET_SYSERR;
6506 }
6507 return GNUNET_OK;
6508}
6509
6510
6511/**
6512 * Communicator gave us a reliability ack. Process the request.
6513 *
6514 * @param cls a `struct CommunicatorMessageContext` (must call
6515 * #finish_cmc_handling() when done)
6516 * @param ra the message that was received
6517 */
6518static void
6519handle_reliability_ack (void *cls,
6520 const struct TransportReliabilityAckMessage *ra)
6521{
6522 struct CommunicatorMessageContext *cmc = cls;
6523 const struct TransportCummulativeAckPayloadP *ack;
6524 unsigned int n_acks;
6525 uint32_t ack_counter;
6526
6527 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6528 / sizeof(struct TransportCummulativeAckPayloadP);
6529 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
6530 for (unsigned int i = 0; i < n_acks; i++)
6531 {
6532 struct PendingAcknowledgement *pa =
6533 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
6534 if (NULL == pa)
6535 {
6536 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6537 "Received ACK from %s with UUID %s which is unknown to us!\n",
6538 GNUNET_i2s (&cmc->im.sender),
6539 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6540 GNUNET_STATISTICS_update (
6541 GST_stats,
6542 "# FRAGMENT_ACKS dropped, no matching pending message",
6543 1,
6544 GNUNET_NO);
6545 continue;
6546 }
6547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6548 "Received ACK from %s with UUID %s\n",
6549 GNUNET_i2s (&cmc->im.sender),
6550 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6551 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
6552 }
6553
6554 ack_counter = htonl (ra->ack_counter);
6555 (void) ack_counter; /* silence compiler warning for now */
6556 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
6557 // (DV and/or Neighbour?)
6558 finish_cmc_handling (cmc);
6559}
6560
6561
6562/**
6563 * Communicator gave us a backchannel encapsulation. Check the message.
6564 *
6565 * @param cls a `struct CommunicatorMessageContext`
6566 * @param be the send message that was sent
6567 * @return #GNUNET_YES if message is well-formed
6568 */
6569static int
6570check_backchannel_encapsulation (
6571 void *cls,
6572 const struct TransportBackchannelEncapsulationMessage *be)
6573{
6574 uint16_t size = ntohs (be->header.size) - sizeof(*be);
6575 const struct GNUNET_MessageHeader *inbox =
6576 (const struct GNUNET_MessageHeader *) &be[1];
6577 const char *is;
6578 uint16_t isize;
6579
6580 (void) cls;
6581 if (ntohs (inbox->size) >= size)
6582 {
6583 GNUNET_break_op (0);
6584 return GNUNET_SYSERR;
6585 }
6586 isize = ntohs (inbox->size);
6587 is = ((const char *) inbox) + isize;
6588 size -= isize;
6589 if ('\0' != is[size - 1])
6590 {
6591 GNUNET_break_op (0);
6592 return GNUNET_SYSERR;
6593 }
6594 return GNUNET_YES;
6595}
6596
6597
6598/**
6599 * Communicator gave us a backchannel encapsulation. Process the request.
6600 * (We are the destination of the backchannel here.)
6601 *
6602 * @param cls a `struct CommunicatorMessageContext` (must call
6603 * #finish_cmc_handling() when done)
6604 * @param be the message that was received
6605 */
6606static void
6607handle_backchannel_encapsulation (
6608 void *cls,
6609 const struct TransportBackchannelEncapsulationMessage *be)
6610{
6611 struct CommunicatorMessageContext *cmc = cls;
6612 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6613 struct GNUNET_MQ_Envelope *env;
6614 struct TransportClient *tc;
6615 const struct GNUNET_MessageHeader *inbox =
6616 (const struct GNUNET_MessageHeader *) &be[1];
6617 uint16_t isize = ntohs (inbox->size);
6618 const char *target_communicator = ((const char *) inbox) + isize;
6619 char *sender;
6620 char *self;
6621
6622 GNUNET_asprintf (&sender,
6623 "%s",
6624 GNUNET_i2s (&cmc->im.sender));
6625 GNUNET_asprintf (&self,
6626 "%s",
6627 GNUNET_i2s (&GST_my_identity));
6628
6629 /* Find client providing this communicator */
6630 for (tc = clients_head; NULL != tc; tc = tc->next)
6631 if ((CT_COMMUNICATOR == tc->type) &&
6632 (0 ==
6633 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6634 break;
6635 if (NULL == tc)
6636 {
6637 char *stastr;
6638
6639 GNUNET_asprintf (
6640 &stastr,
6641 "# Backchannel message dropped: target communicator `%s' unknown",
6642 target_communicator);
6643 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6644 GNUNET_free (stastr);
6645 finish_cmc_handling (cmc);
6646 return;
6647 }
6648 /* Finally, deliver backchannel message to communicator */
6649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6650 "Delivering backchannel message from %s to %s of type %u to %s\n",
6651 sender,
6652 self,
6653 ntohs (inbox->type),
6654 target_communicator);
6655 env = GNUNET_MQ_msg_extra (
6656 cbi,
6657 isize,
6658 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6659 cbi->pid = cmc->im.sender;
6660 memcpy (&cbi[1], inbox, isize);
6661 GNUNET_MQ_send (tc->mq, env);
6662 finish_cmc_handling (cmc);
6663}
6664
6665
6666/**
6667 * Task called when we should check if any of the DV paths
6668 * we have learned to a target are due for garbage collection.
6669 *
6670 * Collects stale paths, and possibly frees the entire DV
6671 * entry if no paths are left. Otherwise re-schedules itself.
6672 *
6673 * @param cls a `struct DistanceVector`
6674 */
6675static void
6676path_cleanup_cb (void *cls)
6677{
6678 struct DistanceVector *dv = cls;
6679 struct DistanceVectorHop *pos;
6680
6681 dv->timeout_task = NULL;
6682 while (NULL != (pos = dv->dv_head))
6683 {
6684 GNUNET_assert (dv == pos->dv);
6685 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6686 break;
6687 free_distance_vector_hop (pos);
6688 }
6689 if (NULL == pos)
6690 {
6691 free_dv_route (dv);
6692 return;
6693 }
6694 dv->timeout_task =
6695 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6696}
6697
6698
6699static void send_msg_from_cache (struct VirtualLink *vl)
6700{
6701
6702 const struct GNUNET_PeerIdentity target = vl->target;
6703
6704
6705 if ((GNUNET_YES == is_ring_buffer_full) || (0 < ring_buffer_head))
6706 {
6707 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
6708 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
6709 0;
6710 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
6711 ring_buffer_head;
6712 struct GNUNET_TRANSPORT_IncomingMessage im;
6713 struct CommunicatorMessageContext *cmc;
6714 struct RingBufferEntry *rbe;
6715 struct GNUNET_MessageHeader *mh;
6716
6717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6718 "Sending from ring buffer, which has %u items\n",
6719 ring_buffer_head);
6720
6721 ring_buffer_head = 0;
6722 for (unsigned int i = 0; i < head; i++)
6723 {
6724 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
6725 cmc = rbe->cmc;
6726 mh = rbe->mh;
6727
6728 im = cmc->im;
6729 // mh = cmc->mh;
6730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6731 "Sending to ring buffer target %s using vl target %s\n",
6732 GNUNET_i2s (&im.sender),
6733 GNUNET_i2s2 (&target));
6734 if (0 == GNUNET_memcmp (&target, &im.sender))
6735 {
6736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6737 "Finish handling message of type %u and size %u\n",
6738 (unsigned int) ntohs (mh->type),
6739 (unsigned int) ntohs (mh->size));
6740 finish_handling_raw_message (vl, mh, cmc, GNUNET_NO);
6741 GNUNET_free (mh);
6742 }
6743 else
6744 {
6745 ring_buffer_copy[i] = rbe;
6746 ring_buffer_head++;
6747 }
6748 }
6749
6750 if ((GNUNET_YES == is_ring_buffer_full) && (RING_BUFFER_SIZE - 1 >
6751 ring_buffer_head))
6752 {
6753 is_ring_buffer_full = GNUNET_NO;
6754 }
6755
6756 for (unsigned int i = 0; i < ring_buffer_head; i++)
6757 {
6758 ring_buffer[i] = ring_buffer_copy[i];
6759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6760 "ring_buffer_copy[i]->mh->type for i %u %u\n",
6761 i,
6762 ring_buffer_copy[i]->mh->type);
6763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6764 "ring_buffer[i]->mh->type for i %u %u\n",
6765 i,
6766 ring_buffer[i]->mh->type);
6767 }
6768
6769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6770 "%u items still in ring buffer\n",
6771 ring_buffer_head);
6772 }
6773
6774 if ((GNUNET_YES == is_ring_buffer_full) || (0 < ring_buffer_dv_head))
6775 {
6776 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
6777 struct PendingMessage *pm;
6778 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
6779 ring_buffer_dv_head :
6780 0;
6781 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
6782 RING_BUFFER_SIZE :
6783 ring_buffer_dv_head;
6784
6785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6786 "Sending from ring buffer dv, which has %u items\n",
6787 ring_buffer_dv_head);
6788
6789 ring_buffer_dv_head = 0;
6790 for (unsigned int i = 0; i < head; i++)
6791 {
6792 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
6793
6794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6795 "Sending to ring buffer target %s using vl target %s\n",
6796 GNUNET_i2s (&pm->target),
6797 GNUNET_i2s2 (&target));
6798 if (0 == GNUNET_memcmp (&target, &pm->target))
6799 {
6800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6801 "Adding PendingMessage to vl, checking transmission.\n");
6802 pm->vl = vl;
6803 GNUNET_CONTAINER_MDLL_insert (vl,
6804 vl->pending_msg_head,
6805 vl->pending_msg_tail,
6806 pm);
6807
6808 check_vl_transmission (vl);
6809 }
6810 else
6811 {
6812 ring_buffer_dv_copy[i] = pm;
6813 ring_buffer_dv_head++;
6814 }
6815 }
6816
6817 if (is_ring_buffer_dv_full && (RING_BUFFER_SIZE - 1 > ring_buffer_dv_head))
6818 {
6819 is_ring_buffer_dv_full = GNUNET_NO;
6820 }
6821
6822 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
6823 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
6824
6825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6826 "%u items still in ring buffer dv.\n",
6827 ring_buffer_dv_head);
6828
6829 }
6830}
6831
6832
6833/**
6834 * The @a hop is a validated path to the respective target
6835 * peer and we should tell core about it -- and schedule
6836 * a job to revoke the state.
6837 *
6838 * @param hop a path to some peer that is the reason for activation
6839 */
6840static void
6841activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6842{
6843 struct DistanceVector *dv = hop->dv;
6844 struct VirtualLink *vl;
6845
6846 vl = lookup_virtual_link (&dv->target);
6847 if (NULL == vl)
6848 {
6849
6850 vl = GNUNET_new (struct VirtualLink);
6851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6852 "Creating new virtual link %p to %s using DV!\n",
6853 vl,
6854 GNUNET_i2s (&dv->target));
6855 vl->confirmed = GNUNET_YES;
6856 vl->message_uuid_ctr =
6857 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6858 vl->target = dv->target;
6859 vl->core_recv_window = RECV_WINDOW_SIZE;
6860 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6861 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
6862 GNUNET_break (GNUNET_YES ==
6863 GNUNET_CONTAINER_multipeermap_put (
6864 links,
6865 &vl->target,
6866 vl,
6867 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6868 vl->dv = dv;
6869 dv->vl = vl;
6870 vl->visibility_task =
6871 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6872 consider_sending_fc (vl);
6873 /* We lacked a confirmed connection to the target
6874 before, so tell CORE about it (finally!) */
6875 cores_send_connect_info (&dv->target);
6876 send_msg_from_cache (vl);
6877 }
6878 else
6879 {
6880 /* Link was already up, remember dv is also now available and we are done */
6881 vl->dv = dv;
6882 dv->vl = vl;
6883 if (GNUNET_NO == vl->confirmed)
6884 {
6885 vl->confirmed = GNUNET_YES;
6886 vl->visibility_task =
6887 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6888 consider_sending_fc (vl);
6889 /* We lacked a confirmed connection to the target
6890 before, so tell CORE about it (finally!) */
6891 cores_send_connect_info (&dv->target);
6892 send_msg_from_cache (vl);
6893 }
6894 else
6895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6896 "Virtual link to %s could now also use DV!\n",
6897 GNUNET_i2s (&dv->target));
6898 }
6899}
6900
6901
6902/**
6903 * We have learned a @a path through the network to some other peer, add it to
6904 * our DV data structure (returning #GNUNET_YES on success).
6905 *
6906 * We do not add paths if we have a sufficient number of shorter
6907 * paths to this target already (returning #GNUNET_NO).
6908 *
6909 * We also do not add problematic paths, like those where we lack the first
6910 * hop in our neighbour list (i.e. due to a topology change) or where some
6911 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6912 *
6913 * @param path the path we learned, path[0] should be us,
6914 * and then path contains a valid path from us to
6915 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6916 * @param path_len number of entries on the @a path, at least three!
6917 * @param network_latency how long does the message take from us to
6918 * `path[path_len-1]`? set to "forever" if unknown
6919 * @param path_valid_until how long is this path considered validated? Maybe
6920 * be zero.
6921 * @return #GNUNET_YES on success,
6922 * #GNUNET_NO if we have better path(s) to the target
6923 * #GNUNET_SYSERR if the path is useless and/or invalid
6924 * (i.e. path[1] not a direct neighbour
6925 * or path[i+1] is a direct neighbour for i>0)
6926 */
6927static int
6928learn_dv_path (const struct GNUNET_PeerIdentity *path,
6929 unsigned int path_len,
6930 struct GNUNET_TIME_Relative network_latency,
6931 struct GNUNET_TIME_Absolute path_valid_until)
6932{
6933 struct DistanceVectorHop *hop;
6934 struct DistanceVector *dv;
6935 struct Neighbour *next_hop;
6936 unsigned int shorter_distance;
6937
6938 if (path_len < 3)
6939 {
6940 /* what a boring path! not allowed! */
6941 GNUNET_break (0);
6942 return GNUNET_SYSERR;
6943 }
6944 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6945 next_hop = lookup_neighbour (&path[1]);
6946 if (NULL == next_hop)
6947 {
6948 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6949 GNUNET_break (0);
6950 return GNUNET_SYSERR;
6951 }
6952 for (unsigned int i = 2; i < path_len; i++)
6953 if (NULL != lookup_neighbour (&path[i]))
6954 {
6955 /* Useless path: we have a direct connection to some hop
6956 in the middle of the path, so this one is not even
6957 terribly useful for redundancy */
6958 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6959 "Path of %u hops useless: directly link to hop %u (%s)\n",
6960 path_len,
6961 i,
6962 GNUNET_i2s (&path[i]));
6963 GNUNET_STATISTICS_update (GST_stats,
6964 "# Useless DV path ignored: hop is neighbour",
6965 1,
6966 GNUNET_NO);
6967 return GNUNET_SYSERR;
6968 }
6969 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6970 if (NULL == dv)
6971 {
6972 dv = GNUNET_new (struct DistanceVector);
6973 dv->target = path[path_len - 1];
6974 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6975 &path_cleanup_cb,
6976 dv);
6977 GNUNET_assert (GNUNET_OK ==
6978 GNUNET_CONTAINER_multipeermap_put (
6979 dv_routes,
6980 &dv->target,
6981 dv,
6982 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6983 }
6984 /* Check if we have this path already! */
6985 shorter_distance = 0;
6986 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6987 pos = pos->next_dv)
6988 {
6989 if (pos->distance < path_len - 3)
6990 shorter_distance++;
6991 /* Note that the distances in 'pos' excludes us (path[0]),
6992 the next_hop (path[1]) and the target so we need to subtract three
6993 and check next_hop explicitly */
6994 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
6995 {
6996 int match = GNUNET_YES;
6997
6998 for (unsigned int i = 0; i < pos->distance; i++)
6999 {
7000 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
7001 {
7002 match = GNUNET_NO;
7003 break;
7004 }
7005 }
7006 if (GNUNET_YES == match)
7007 {
7008 struct GNUNET_TIME_Relative last_timeout;
7009
7010 /* Re-discovered known path, update timeout */
7011 GNUNET_STATISTICS_update (GST_stats,
7012 "# Known DV path refreshed",
7013 1,
7014 GNUNET_NO);
7015 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
7016 pos->timeout =
7017 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
7018 pos->path_valid_until =
7019 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
7020 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
7021 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
7022 if (0 <
7023 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
7024 activate_core_visible_dv_path (pos);
7025 if (last_timeout.rel_value_us <
7026 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
7027 DV_PATH_DISCOVERY_FREQUENCY)
7028 .rel_value_us)
7029 {
7030 /* Some peer send DV learn messages too often, we are learning
7031 the same path faster than it would be useful; do not forward! */
7032 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7033 "Rediscovered path too quickly, not forwarding further\n");
7034 return GNUNET_NO;
7035 }
7036 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7037 "Refreshed known path to %s valid until %s, forwarding further\n",
7038 GNUNET_i2s (&dv->target),
7039 GNUNET_STRINGS_absolute_time_to_string (
7040 pos->path_valid_until));
7041 return GNUNET_YES;
7042 }
7043 }
7044 }
7045 /* Count how many shorter paths we have (incl. direct
7046 neighbours) before simply giving up on this one! */
7047 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
7048 {
7049 /* We have a shorter path already! */
7050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7051 "Have many shorter DV paths %s, not forwarding further\n",
7052 GNUNET_i2s (&dv->target));
7053 return GNUNET_NO;
7054 }
7055 /* create new DV path entry */
7056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7057 "Discovered new DV path to %s valid until %s\n",
7058 GNUNET_i2s (&dv->target),
7059 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
7060 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
7061 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
7062 hop->next_hop = next_hop;
7063 hop->dv = dv;
7064 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
7065 memcpy (&hop[1],
7066 &path[2],
7067 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
7068 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
7069 hop->path_valid_until = path_valid_until;
7070 hop->distance = path_len - 3;
7071 hop->pd.aged_rtt = network_latency;
7072 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
7073 GNUNET_CONTAINER_MDLL_insert (neighbour,
7074 next_hop->dv_head,
7075 next_hop->dv_tail,
7076 hop);
7077 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
7078 activate_core_visible_dv_path (hop);
7079 return GNUNET_YES;
7080}
7081
7082
7083/**
7084 * Communicator gave us a DV learn message. Check the message.
7085 *
7086 * @param cls a `struct CommunicatorMessageContext`
7087 * @param dvl the send message that was sent
7088 * @return #GNUNET_YES if message is well-formed
7089 */
7090static int
7091check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7092{
7093 uint16_t size = ntohs (dvl->header.size);
7094 uint16_t num_hops = ntohs (dvl->num_hops);
7095 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
7096
7097 (void) cls;
7098 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
7099 {
7100 GNUNET_break_op (0);
7101 return GNUNET_SYSERR;
7102 }
7103 if (num_hops > MAX_DV_HOPS_ALLOWED)
7104 {
7105 GNUNET_break_op (0);
7106 return GNUNET_SYSERR;
7107 }
7108 for (unsigned int i = 0; i < num_hops; i++)
7109 {
7110 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
7111 {
7112 GNUNET_break_op (0);
7113 return GNUNET_SYSERR;
7114 }
7115 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
7116 {
7117 GNUNET_break_op (0);
7118 return GNUNET_SYSERR;
7119 }
7120 }
7121 return GNUNET_YES;
7122}
7123
7124
7125/**
7126 * Build and forward a DV learn message to @a next_hop.
7127 *
7128 * @param next_hop peer to send the message to
7129 * @param msg message received
7130 * @param bi_history bitmask specifying hops on path that were bidirectional
7131 * @param nhops length of the @a hops array
7132 * @param hops path the message traversed so far
7133 * @param in_time when did we receive the message, used to calculate network
7134 * delay
7135 */
7136static void
7137forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
7138 const struct TransportDVLearnMessage *msg,
7139 uint16_t bi_history,
7140 uint16_t nhops,
7141 const struct DVPathEntryP *hops,
7142 struct GNUNET_TIME_Absolute in_time)
7143{
7144 struct Neighbour *n;
7145 struct VirtualLink *vl;
7146 struct DVPathEntryP *dhops;
7147 char buf[sizeof(struct TransportDVLearnMessage)
7148 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
7149 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
7150 struct GNUNET_TIME_Relative nnd;
7151
7152 /* compute message for forwarding */
7153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7154 "Forwarding DV learn message originating from %s to %s\n",
7155 GNUNET_i2s (&msg->initiator),
7156 GNUNET_i2s2 (next_hop));
7157 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
7158 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
7159 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
7160 + (nhops + 1) * sizeof(struct DVPathEntryP));
7161 fwd->num_hops = htons (nhops + 1);
7162 fwd->bidirectional = htons (bi_history);
7163 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
7164 GNUNET_TIME_relative_ntoh (
7165 msg->non_network_delay));
7166 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
7167 fwd->init_sig = msg->init_sig;
7168 fwd->initiator = msg->initiator;
7169 fwd->challenge = msg->challenge;
7170 fwd->monotonic_time = msg->monotonic_time;
7171 dhops = (struct DVPathEntryP *) &fwd[1];
7172 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
7173 dhops[nhops].hop = GST_my_identity;
7174 {
7175 struct DvHopPS dhp = {
7176 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7177 .purpose.size = htonl (sizeof(dhp)),
7178 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
7179 .succ = *next_hop,
7180 .challenge = msg->challenge
7181 };
7182 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7183 &dhp,
7184 &dhops[nhops].hop_sig);
7185 }
7186 /*route_control_message_without_fc (next_hop,
7187 &fwd->header,
7188 RMO_UNCONFIRMED_ALLOWED);*/
7189 vl = lookup_virtual_link (next_hop);
7190 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7191 {
7192 route_control_message_without_fc (vl,
7193 &fwd->header,
7194 RMO_UNCONFIRMED_ALLOWED);
7195 }
7196 else
7197 {
7198 /* Use route via neighbour */
7199 n = lookup_neighbour (next_hop);
7200 if (NULL != n)
7201 route_via_neighbour (
7202 n,
7203 &fwd->header,
7204 RMO_UNCONFIRMED_ALLOWED);
7205 }
7206}
7207
7208
7209/**
7210 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
7211 *
7212 * @param sender_monotonic_time monotonic time of the initiator
7213 * @param init the signer
7214 * @param challenge the challenge that was signed
7215 * @param init_sig signature presumably by @a init
7216 * @return #GNUNET_OK if the signature is valid
7217 */
7218static int
7219validate_dv_initiator_signature (
7220 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
7221 const struct GNUNET_PeerIdentity *init,
7222 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge,
7223 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
7224{
7225 struct DvInitPS ip = { .purpose.purpose = htonl (
7226 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
7227 .purpose.size = htonl (sizeof(ip)),
7228 .monotonic_time = sender_monotonic_time,
7229 .challenge = *challenge };
7230
7231 if (
7232 GNUNET_OK !=
7233 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
7234 &ip,
7235 init_sig,
7236 &init->public_key))
7237 {
7238 GNUNET_break_op (0);
7239 return GNUNET_SYSERR;
7240 }
7241 return GNUNET_OK;
7242}
7243
7244
7245/**
7246 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
7247 */
7248struct NeighbourSelectionContext
7249{
7250 /**
7251 * Original message we received.
7252 */
7253 const struct TransportDVLearnMessage *dvl;
7254
7255 /**
7256 * The hops taken.
7257 */
7258 const struct DVPathEntryP *hops;
7259
7260 /**
7261 * Time we received the message.
7262 */
7263 struct GNUNET_TIME_Absolute in_time;
7264
7265 /**
7266 * Offsets of the selected peers.
7267 */
7268 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
7269
7270 /**
7271 * Number of peers eligible for selection.
7272 */
7273 unsigned int num_eligible;
7274
7275 /**
7276 * Number of peers that were selected for forwarding.
7277 */
7278 unsigned int num_selections;
7279
7280 /**
7281 * Number of hops in @e hops
7282 */
7283 uint16_t nhops;
7284
7285 /**
7286 * Bitmap of bidirectional connections encountered.
7287 */
7288 uint16_t bi_history;
7289};
7290
7291
7292/**
7293 * Function called for each neighbour during #handle_dv_learn.
7294 *
7295 * @param cls a `struct NeighbourSelectionContext *`
7296 * @param pid identity of the peer
7297 * @param value a `struct Neighbour`
7298 * @return #GNUNET_YES (always)
7299 */
7300static int
7301dv_neighbour_selection (void *cls,
7302 const struct GNUNET_PeerIdentity *pid,
7303 void *value)
7304{
7305 struct NeighbourSelectionContext *nsc = cls;
7306
7307 (void) value;
7308 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7309 return GNUNET_YES; /* skip initiator */
7310 for (unsigned int i = 0; i < nsc->nhops; i++)
7311 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7312 return GNUNET_YES;
7313 /* skip peers on path */
7314 nsc->num_eligible++;
7315 return GNUNET_YES;
7316}
7317
7318
7319/**
7320 * Function called for each neighbour during #handle_dv_learn.
7321 * We call #forward_dv_learn() on the neighbour(s) selected
7322 * during #dv_neighbour_selection().
7323 *
7324 * @param cls a `struct NeighbourSelectionContext *`
7325 * @param pid identity of the peer
7326 * @param value a `struct Neighbour`
7327 * @return #GNUNET_YES (always)
7328 */
7329static int
7330dv_neighbour_transmission (void *cls,
7331 const struct GNUNET_PeerIdentity *pid,
7332 void *value)
7333{
7334 struct NeighbourSelectionContext *nsc = cls;
7335
7336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7337 "transmission %s\n",
7338 GNUNET_i2s (pid));
7339 (void) value;
7340 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7341 return GNUNET_YES; /* skip initiator */
7342 for (unsigned int i = 0; i < nsc->nhops; i++)
7343 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7344 return GNUNET_YES;
7345 /* skip peers on path */
7346 for (unsigned int i = 0; i < nsc->num_selections; i++)
7347 {
7348 if (nsc->selections[i] == nsc->num_eligible)
7349 {
7350 forward_dv_learn (pid,
7351 nsc->dvl,
7352 nsc->bi_history,
7353 nsc->nhops,
7354 nsc->hops,
7355 nsc->in_time);
7356 break;
7357 }
7358 }
7359 nsc->num_eligible++;
7360 return GNUNET_YES;
7361}
7362
7363
7364/**
7365 * Computes the number of neighbours we should forward a DVInit
7366 * message to given that it has so far taken @a hops_taken hops
7367 * though the network and that the number of neighbours we have
7368 * in total is @a neighbour_count, out of which @a eligible_count
7369 * are not yet on the path.
7370 *
7371 * NOTE: technically we might want to include NSE in the formula to
7372 * get a better grip on the overall network size. However, for now
7373 * using NSE here would create a dependency issue in the build system.
7374 * => Left for later, hardcoded to 50 for now.
7375 *
7376 * The goal of the fomula is that we want to reach a total of LOG(NSE)
7377 * peers via DV (`target_total`). We want the reach to be spread out
7378 * over various distances to the origin, with a bias towards shorter
7379 * distances.
7380 *
7381 * We make the strong assumption that the network topology looks
7382 * "similar" at other hops, in particular the @a neighbour_count
7383 * should be comparable at other hops.
7384 *
7385 * If the local neighbourhood is densely connected, we expect that @a
7386 * eligible_count is close to @a neighbour_count minus @a hops_taken
7387 * as a lot of the path is already known. In that case, we should
7388 * forward to few(er) peers to try to find a path out of the
7389 * neighbourhood. OTOH, if @a eligible_count is close to @a
7390 * neighbour_count, we should forward to many peers as we are either
7391 * still close to the origin (i.e. @a hops_taken is small) or because
7392 * we managed to get beyond a local cluster. We express this as
7393 * the `boost_factor` using the square of the fraction of eligible
7394 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
7395 * 99% are eligible, the 'boost' will be almost 1).
7396 *
7397 * Second, the more hops we have taken, the larger the problem of an
7398 * exponential traffic explosion gets. So we take the `target_total`,
7399 * and compute our degree such that at each distance d 2^{-d} peers
7400 * are selected (corrected by the `boost_factor`).
7401 *
7402 * @param hops_taken number of hops DVInit has travelled so far
7403 * @param neighbour_count number of neighbours we have in total
7404 * @param eligible_count number of neighbours we could in
7405 * theory forward to
7406 */
7407static unsigned int
7408calculate_fork_degree (unsigned int hops_taken,
7409 unsigned int neighbour_count,
7410 unsigned int eligible_count)
7411{
7412 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
7413 double eligible_ratio =
7414 ((double) eligible_count) / ((double) neighbour_count);
7415 double boost_factor = eligible_ratio * eligible_ratio;
7416 unsigned int rnd;
7417 double left;
7418
7419 if (hops_taken >= 64)
7420 {
7421 GNUNET_break (0);
7422 return 0; /* precaution given bitshift below */
7423 }
7424 for (unsigned int i = 1; i < hops_taken; i++)
7425 {
7426 /* For each hop, subtract the expected number of targets
7427 reached at distance d (so what remains divided by 2^d) */
7428 target_total -= (target_total * boost_factor / (1LLU << i));
7429 }
7430 rnd =
7431 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
7432 /* round up or down probabilistically depending on how close we were
7433 when floor()ing to rnd */
7434 left = target_total - (double) rnd;
7435 if (UINT32_MAX * left >
7436 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
7437 rnd++; /* round up */
7438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7439 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
7440 hops_taken,
7441 rnd,
7442 eligible_count,
7443 neighbour_count);
7444 return rnd;
7445}
7446
7447
7448/**
7449 * Function called when peerstore is done storing a DV monotonic time.
7450 *
7451 * @param cls a `struct Neighbour`
7452 * @param success #GNUNET_YES if peerstore was successful
7453 */
7454static void
7455neighbour_store_dvmono_cb (void *cls, int success)
7456{
7457 struct Neighbour *n = cls;
7458
7459 n->sc = NULL;
7460 if (GNUNET_YES != success)
7461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7462 "Failed to store other peer's monotonic time in peerstore!\n");
7463}
7464
7465
7466/**
7467 * Communicator gave us a DV learn message. Process the request.
7468 *
7469 * @param cls a `struct CommunicatorMessageContext` (must call
7470 * #finish_cmc_handling() when done)
7471 * @param dvl the message that was received
7472 */
7473static void
7474handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7475{
7476 struct CommunicatorMessageContext *cmc = cls;
7477 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
7478 int bi_hop;
7479 uint16_t nhops;
7480 uint16_t bi_history;
7481 const struct DVPathEntryP *hops;
7482 int do_fwd;
7483 int did_initiator;
7484 struct GNUNET_TIME_Absolute in_time;
7485 struct Neighbour *n;
7486
7487 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
7488 bi_history = ntohs (dvl->bidirectional);
7489 hops = (const struct DVPathEntryP *) &dvl[1];
7490 if (0 == nhops)
7491 {
7492 /* sanity check */
7493 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
7494 {
7495 GNUNET_break (0);
7496 finish_cmc_handling (cmc);
7497 return;
7498 }
7499 }
7500 else
7501 {
7502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7503 "handle dv learn message last hop %s\n",
7504 GNUNET_i2s (&hops[nhops - 1].hop));
7505 /* sanity check */
7506 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
7507 {
7508 GNUNET_break (0);
7509 finish_cmc_handling (cmc);
7510 return;
7511 }
7512 }
7513
7514 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
7515 cc = cmc->tc->details.communicator.cc;
7516 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
7517 cc); // FIXME: add bi-directional flag to cc?
7518 in_time = GNUNET_TIME_absolute_get ();
7519
7520 /* continue communicator here, everything else can happen asynchronous! */
7521 finish_cmc_handling (cmc);
7522
7523 n = lookup_neighbour (&dvl->initiator);
7524 if (NULL != n)
7525 {
7526 if ((n->dv_monotime_available == GNUNET_YES) &&
7527 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
7528 n->last_dv_learn_monotime.abs_value_us))
7529 {
7530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7531 "DV learn from %s discarded due to time travel",
7532 GNUNET_i2s (&dvl->initiator));
7533 GNUNET_STATISTICS_update (GST_stats,
7534 "# DV learn discarded due to time travel",
7535 1,
7536 GNUNET_NO);
7537 return;
7538 }
7539 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
7540 &dvl->initiator,
7541 &dvl->challenge,
7542 &dvl->init_sig))
7543 {
7544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7545 "DV learn signature from %s invalid\n",
7546 GNUNET_i2s (&dvl->initiator));
7547 GNUNET_break_op (0);
7548 return;
7549 }
7550 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
7551 if (GNUNET_YES == n->dv_monotime_available)
7552 {
7553 if (NULL != n->sc)
7554 {
7555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7556 "store cancel\n");
7557 GNUNET_PEERSTORE_store_cancel (n->sc);
7558 }
7559 n->sc =
7560 GNUNET_PEERSTORE_store (peerstore,
7561 "transport",
7562 &dvl->initiator,
7563 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
7564 &dvl->monotonic_time,
7565 sizeof(dvl->monotonic_time),
7566 GNUNET_TIME_UNIT_FOREVER_ABS,
7567 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7568 &neighbour_store_dvmono_cb,
7569 n);
7570 }
7571 }
7572 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
7573 If signature verification load too high, implement random drop strategy */
7574 for (unsigned int i = 0; i < nhops; i++)
7575 {
7576 struct DvHopPS dhp = { .purpose.purpose =
7577 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7578 .purpose.size = htonl (sizeof(dhp)),
7579 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
7580 .succ = (nhops == i + 1) ? GST_my_identity
7581 : hops[i + 1].hop,
7582 .challenge = dvl->challenge };
7583
7584 if (GNUNET_OK !=
7585 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
7586 &dhp,
7587 &hops[i].hop_sig,
7588 &hops[i].hop.public_key))
7589 {
7590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7591 "DV learn from %s signature of hop %u invalid\n",
7592 GNUNET_i2s (&dvl->initiator),
7593 i);
7594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7595 "signature of hop %s invalid\n",
7596 GNUNET_i2s (&hops[i].hop));
7597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7598 "pred %s\n",
7599 GNUNET_i2s (&dhp.pred));
7600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7601 "succ %s\n",
7602 GNUNET_i2s (&dhp.succ));
7603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7604 "hash %s\n",
7605 GNUNET_sh2s (&dhp.challenge.value));
7606 GNUNET_break_op (0);
7607 return;
7608 }
7609 }
7610 if (GNUNET_EXTRA_LOGGING > 0)
7611 {
7612 char *path;
7613
7614 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
7615 for (unsigned int i = 0; i < nhops; i++)
7616 {
7617 char *tmp;
7618
7619 GNUNET_asprintf (&tmp,
7620 "%s%s%s",
7621 path,
7622 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
7623 GNUNET_i2s (&hops[i].hop));
7624 GNUNET_free (path);
7625 path = tmp;
7626 }
7627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7628 "Received DVInit via %s%s%s\n",
7629 path,
7630 bi_hop ? "<->" : "-->",
7631 GNUNET_i2s (&GST_my_identity));
7632 GNUNET_free (path);
7633 }
7634 do_fwd = GNUNET_YES;
7635 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
7636 {
7637 struct GNUNET_PeerIdentity path[nhops + 1];
7638 struct GNUNET_TIME_Relative host_latency_sum;
7639 struct GNUNET_TIME_Relative latency;
7640 struct GNUNET_TIME_Relative network_latency;
7641
7642 /* We initiated this, learn the forward path! */
7643 path[0] = GST_my_identity;
7644 path[1] = hops[0].hop;
7645 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
7646
7647 // Need also something to lookup initiation time
7648 // to compute RTT! -> add RTT argument here?
7649 latency = GNUNET_TIME_absolute_get_duration (GNUNET_TIME_absolute_ntoh (
7650 dvl->monotonic_time));
7651 GNUNET_assert (latency.rel_value_us >= host_latency_sum.rel_value_us);
7652 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
7653 // (based on dvl->challenge, we can identify time of origin!)
7654
7655 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
7656 /* assumption: latency on all links is the same */
7657 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
7658
7659 for (unsigned int i = 2; i <= nhops; i++)
7660 {
7661 struct GNUNET_TIME_Relative ilat;
7662
7663 /* assumption: linear latency increase per hop */
7664 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
7665 path[i] = hops[i - 1].hop;
7666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7667 "Learned path with %u hops to %s with latency %s\n",
7668 i,
7669 GNUNET_i2s (&path[i]),
7670 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
7671 learn_dv_path (path,
7672 i + 1,
7673 ilat,
7674 GNUNET_TIME_relative_to_absolute (
7675 ADDRESS_VALIDATION_LIFETIME));
7676 }
7677 /* as we initiated, do not forward again (would be circular!) */
7678 do_fwd = GNUNET_NO;
7679 return;
7680 }
7681 if (bi_hop)
7682 {
7683 /* last hop was bi-directional, we could learn something here! */
7684 struct GNUNET_PeerIdentity path[nhops + 2];
7685
7686 path[0] = GST_my_identity;
7687 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
7688 for (unsigned int i = 0; i < nhops; i++)
7689 {
7690 int iret;
7691
7692 if (0 == (bi_history & (1 << i)))
7693 break; /* i-th hop not bi-directional, stop learning! */
7694 if (i == nhops - 1)
7695 {
7696 path[i + 2] = dvl->initiator;
7697 }
7698 else
7699 {
7700 path[i + 2] = hops[nhops - i - 2].hop;
7701 }
7702
7703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7704 "Learned inverse path with %u hops to %s\n",
7705 i + 2,
7706 GNUNET_i2s (&path[i + 2]));
7707 iret = learn_dv_path (path,
7708 i + 3,
7709 GNUNET_TIME_UNIT_FOREVER_REL,
7710 GNUNET_TIME_relative_to_absolute (
7711 ADDRESS_VALIDATION_LIFETIME));
7712 if (GNUNET_SYSERR == iret)
7713 {
7714 /* path invalid or too long to be interesting for US, thus should also
7715 not be interesting to our neighbours, cut path when forwarding to
7716 'i' hops, except of course for the one that goes back to the
7717 initiator */
7718 GNUNET_STATISTICS_update (GST_stats,
7719 "# DV learn not forwarded due invalidity of path",
7720 1,
7721 GNUNET_NO);
7722 do_fwd = GNUNET_NO;
7723 break;
7724 }
7725 if ((GNUNET_NO == iret) && (nhops == i + 1))
7726 {
7727 /* we have better paths, and this is the longest target,
7728 so there cannot be anything interesting later */
7729 GNUNET_STATISTICS_update (GST_stats,
7730 "# DV learn not forwarded, got better paths",
7731 1,
7732 GNUNET_NO);
7733 do_fwd = GNUNET_NO;
7734 break;
7735 }
7736 }
7737 }
7738 if (MAX_DV_HOPS_ALLOWED == nhops)
7739 {
7740 /* At limit, we're out of here! */
7741 return;
7742 }
7743
7744 /* Forward to initiator, if path non-trivial and possible */
7745 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
7746 did_initiator = GNUNET_NO;
7747 if ((1 <= nhops) &&
7748 (GNUNET_YES ==
7749 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
7750 {
7751 /* send back to origin! */
7752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7753 "Sending DVL back to initiator %s\n",
7754 GNUNET_i2s (&dvl->initiator));
7755 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
7756 did_initiator = GNUNET_YES;
7757 }
7758 /* We forward under two conditions: either we still learned something
7759 ourselves (do_fwd), or the path was darn short and thus the initiator is
7760 likely to still be very interested in this (and we did NOT already
7761 send it back to the initiator) */
7762 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
7763 (GNUNET_NO == did_initiator)))
7764 {
7765 /* Pick random neighbours that are not yet on the path */
7766 struct NeighbourSelectionContext nsc;
7767 unsigned int n_cnt;
7768
7769 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
7770 nsc.nhops = nhops;
7771 nsc.dvl = dvl;
7772 nsc.bi_history = bi_history;
7773 nsc.hops = hops;
7774 nsc.in_time = in_time;
7775 nsc.num_eligible = 0;
7776 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7777 &dv_neighbour_selection,
7778 &nsc);
7779 if (0 == nsc.num_eligible)
7780 return; /* done here, cannot forward to anyone else */
7781 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
7782 nsc.num_selections =
7783 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
7784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7785 "Forwarding DVL to %u other peers\n",
7786 nsc.num_selections);
7787 for (unsigned int i = 0; i < nsc.num_selections; i++)
7788 nsc.selections[i] =
7789 (nsc.num_selections == n_cnt)
7790 ? i /* all were selected, avoid collisions by chance */
7791 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
7792 nsc.num_eligible = 0;
7793 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7794 &dv_neighbour_transmission,
7795 &nsc);
7796 }
7797}
7798
7799
7800/**
7801 * Communicator gave us a DV box. Check the message.
7802 *
7803 * @param cls a `struct CommunicatorMessageContext`
7804 * @param dvb the send message that was sent
7805 * @return #GNUNET_YES if message is well-formed
7806 */
7807static int
7808check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7809{
7810 uint16_t size = ntohs (dvb->header.size);
7811 uint16_t num_hops = ntohs (dvb->num_hops);
7812 const struct GNUNET_PeerIdentity *hops =
7813 (const struct GNUNET_PeerIdentity *) &dvb[1];
7814
7815 (void) cls;
7816 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
7817 + sizeof(struct GNUNET_MessageHeader))
7818 {
7819 GNUNET_break_op (0);
7820 return GNUNET_SYSERR;
7821 }
7822 /* This peer must not be on the path */
7823 for (unsigned int i = 0; i < num_hops; i++)
7824 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7825 {
7826 GNUNET_break_op (0);
7827 return GNUNET_SYSERR;
7828 }
7829 return GNUNET_YES;
7830}
7831
7832
7833/**
7834 * Create a DV Box message and queue it for transmission to
7835 * @a next_hop.
7836 *
7837 * @param next_hop peer to receive the message next
7838 * @param total_hops how many hops did the message take so far
7839 * @param num_hops length of the @a hops array
7840 * @param origin origin of the message
7841 * @param hops next peer(s) to the destination, including destination
7842 * @param payload payload of the box
7843 * @param payload_size number of bytes in @a payload
7844 */
7845static void
7846forward_dv_box (struct Neighbour *next_hop,
7847 struct TransportDVBoxMessage *hdr,
7848 uint16_t total_hops,
7849 uint16_t num_hops,
7850 const struct GNUNET_PeerIdentity *hops,
7851 const void *enc_payload,
7852 uint16_t enc_payload_size)
7853{
7854 struct VirtualLink *vl = next_hop->vl;
7855 struct PendingMessage *pm;
7856 size_t msg_size = sizeof(struct TransportDVBoxMessage)
7857 + num_hops * sizeof(struct GNUNET_PeerIdentity)
7858 + enc_payload_size;
7859 char *buf;
7860 char msg_buf[msg_size] GNUNET_ALIGN;
7861 struct GNUNET_PeerIdentity *dhops;
7862
7863 hdr->num_hops = htons (num_hops);
7864 hdr->total_hops = htons (total_hops);
7865 hdr->header.size = htons (msg_size);
7866 memcpy (msg_buf, hdr, sizeof(*hdr));
7867 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
7868 TransportDVBoxMessage)];
7869 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7870 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7871
7872 if (GNUNET_YES == ntohs (hdr->without_fc))
7873 {
7874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7875 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
7876 enc_payload_size,
7877 GNUNET_i2s (&next_hop->pid),
7878 (unsigned int) num_hops,
7879 (unsigned int) total_hops);
7880 route_via_neighbour (next_hop, (const struct
7881 GNUNET_MessageHeader *) msg_buf,
7882 RMO_ANYTHING_GOES);
7883 }
7884 else
7885 {
7886 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7888 "2 created pm %p storing vl %p \n",
7889 pm,
7890 vl);
7891 pm->pmt = PMT_DV_BOX;
7892 pm->vl = vl;
7893 pm->target = next_hop->pid;
7894 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7895 pm->logging_uuid = logging_uuid_gen++;
7896 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7897 pm->bytes_msg = msg_size;
7898 buf = (char *) &pm[1];
7899 memcpy (buf, msg_buf, msg_size);
7900
7901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7902 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7903 pm->logging_uuid,
7904 GNUNET_i2s (&next_hop->pid),
7905 (unsigned int) num_hops,
7906 (unsigned int) total_hops);
7907
7908 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7909 {
7910 GNUNET_CONTAINER_MDLL_insert (vl,
7911 vl->pending_msg_head,
7912 vl->pending_msg_tail,
7913 pm);
7914
7915 check_vl_transmission (vl);
7916 }
7917 else
7918 {
7919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7920 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
7921
7922 ring_buffer_dv[ring_buffer_dv_head] = pm;
7923 if (RING_BUFFER_SIZE - 1 == ring_buffer_dv_head)
7924 {
7925 ring_buffer_dv_head = 0;
7926 is_ring_buffer_dv_full = GNUNET_YES;
7927 }
7928 else
7929 ring_buffer_dv_head++;
7930
7931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7932 "%u items stored in DV ring buffer\n",
7933 ring_buffer_dv_head);
7934 }
7935 }
7936}
7937
7938
7939/**
7940 * Free data structures associated with @a b.
7941 *
7942 * @param b data structure to release
7943 */
7944static void
7945free_backtalker (struct Backtalker *b)
7946{
7947 if (NULL != b->get)
7948 {
7949 GNUNET_PEERSTORE_iterate_cancel (b->get);
7950 b->get = NULL;
7951 GNUNET_assert (NULL != b->cmc);
7952 finish_cmc_handling (b->cmc);
7953 b->cmc = NULL;
7954 }
7955 if (NULL != b->task)
7956 {
7957 GNUNET_SCHEDULER_cancel (b->task);
7958 b->task = NULL;
7959 }
7960 if (NULL != b->sc)
7961 {
7962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7963 "store cancel\n");
7964 GNUNET_PEERSTORE_store_cancel (b->sc);
7965 b->sc = NULL;
7966 }
7967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7968 "Removing backtalker for %s\n",
7969 GNUNET_i2s (&b->pid));
7970 GNUNET_assert (
7971 GNUNET_YES ==
7972 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7973 GNUNET_free (b);
7974}
7975
7976
7977/**
7978 * Callback to free backtalker records.
7979 *
7980 * @param cls NULL
7981 * @param pid unused
7982 * @param value a `struct Backtalker`
7983 * @return #GNUNET_OK (always)
7984 */
7985static int
7986free_backtalker_cb (void *cls,
7987 const struct GNUNET_PeerIdentity *pid,
7988 void *value)
7989{
7990 struct Backtalker *b = value;
7991
7992 (void) cls;
7993 (void) pid;
7994 free_backtalker (b);
7995 return GNUNET_OK;
7996}
7997
7998
7999/**
8000 * Function called when it is time to clean up a backtalker.
8001 *
8002 * @param cls a `struct Backtalker`
8003 */
8004static void
8005backtalker_timeout_cb (void *cls)
8006{
8007 struct Backtalker *b = cls;
8008
8009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8010 "backtalker timeout.\n");
8011 b->task = NULL;
8012 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
8013 {
8014 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8015 return;
8016 }
8017 GNUNET_assert (NULL == b->sc);
8018 free_backtalker (b);
8019}
8020
8021
8022/**
8023 * Function called with the monotonic time of a backtalker
8024 * by PEERSTORE. Updates the time and continues processing.
8025 *
8026 * @param cls a `struct Backtalker`
8027 * @param record the information found, NULL for the last call
8028 * @param emsg error message
8029 */
8030static void
8031backtalker_monotime_cb (void *cls,
8032 const struct GNUNET_PEERSTORE_Record *record,
8033 const char *emsg)
8034{
8035 struct Backtalker *b = cls;
8036 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8037 struct GNUNET_TIME_Absolute mt;
8038
8039 (void) emsg;
8040 if (NULL == record)
8041 {
8042 /* we're done with #backtalker_monotime_cb() invocations,
8043 continue normal processing */
8044 b->get = NULL;
8045 GNUNET_assert (NULL != b->cmc);
8046 b->cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
8047 if (0 != b->body_size)
8048 demultiplex_with_cmc (b->cmc);
8049 else
8050 finish_cmc_handling (b->cmc);
8051 b->cmc = NULL;
8052 return;
8053 }
8054 if (sizeof(*mtbe) != record->value_size)
8055 {
8056 GNUNET_break (0);
8057 return;
8058 }
8059 mtbe = record->value;
8060 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
8061 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
8062 {
8063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8064 "Backtalker message from %s dropped, monotime in the past\n",
8065 GNUNET_i2s (&b->pid));
8066 GNUNET_STATISTICS_update (
8067 GST_stats,
8068 "# Backchannel messages dropped: monotonic time not increasing",
8069 1,
8070 GNUNET_NO);
8071 b->monotonic_time = mt;
8072 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
8073 */
8074 b->body_size = 0;
8075 return;
8076 }
8077}
8078
8079
8080/**
8081 * Function called by PEERSTORE when the store operation of
8082 * a backtalker's monotonic time is complete.
8083 *
8084 * @param cls the `struct Backtalker`
8085 * @param success #GNUNET_OK on success
8086 */
8087static void
8088backtalker_monotime_store_cb (void *cls, int success)
8089{
8090 struct Backtalker *b = cls;
8091
8092 if (GNUNET_OK != success)
8093 {
8094 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8095 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
8096 }
8097 b->sc = NULL;
8098 if (NULL != b->task)
8099 {
8100 GNUNET_SCHEDULER_cancel (b->task);
8101 b->task = NULL;
8102 }
8103 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8104}
8105
8106
8107/**
8108 * The backtalker @a b monotonic time changed. Update PEERSTORE.
8109 *
8110 * @param b a backtalker with updated monotonic time
8111 */
8112static void
8113update_backtalker_monotime (struct Backtalker *b)
8114{
8115 struct GNUNET_TIME_AbsoluteNBO mtbe;
8116
8117 if (NULL != b->sc)
8118 {
8119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8120 "store cancel before store with sc %p\n",
8121 b->sc);
8122 /*GNUNET_PEERSTORE_store_cancel (b->sc);
8123 b->sc = NULL;*/
8124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8125 "store cancel before store with sc %p is null\n",
8126 b->sc);
8127 }
8128 else
8129 {
8130 GNUNET_SCHEDULER_cancel (b->task);
8131 b->task = NULL;
8132 }
8133 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
8134 b->sc =
8135 GNUNET_PEERSTORE_store (peerstore,
8136 "transport",
8137 &b->pid,
8138 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8139 &mtbe,
8140 sizeof(mtbe),
8141 GNUNET_TIME_UNIT_FOREVER_ABS,
8142 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
8143 &backtalker_monotime_store_cb,
8144 b);
8145}
8146
8147
8148/**
8149 * Communicator gave us a DV box. Process the request.
8150 *
8151 * @param cls a `struct CommunicatorMessageContext` (must call
8152 * #finish_cmc_handling() when done)
8153 * @param dvb the message that was received
8154 */
8155static void
8156handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
8157{
8158 struct CommunicatorMessageContext *cmc = cls;
8159 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
8160 uint16_t num_hops = ntohs (dvb->num_hops);
8161 const struct GNUNET_PeerIdentity *hops =
8162 (const struct GNUNET_PeerIdentity *) &dvb[1];
8163 const char *enc_payload = (const char *) &hops[num_hops];
8164 uint16_t enc_payload_size =
8165 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
8166 struct DVKeyState key;
8167 struct GNUNET_HashCode hmac;
8168 const char *hdr;
8169 size_t hdr_len;
8170
8171 if (GNUNET_EXTRA_LOGGING > 0)
8172 {
8173 char *path;
8174
8175 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
8176 for (unsigned int i = 0; i < num_hops; i++)
8177 {
8178 char *tmp;
8179
8180 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
8181 GNUNET_free (path);
8182 path = tmp;
8183 }
8184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8185 "Received DVBox with remaining path %s\n",
8186 path);
8187 GNUNET_free (path);
8188 }
8189
8190 if (num_hops > 0)
8191 {
8192 /* We're trying from the end of the hops array, as we may be
8193 able to find a shortcut unknown to the origin that way */
8194 for (int i = num_hops - 1; i >= 0; i--)
8195 {
8196 struct Neighbour *n;
8197
8198 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
8199 {
8200 GNUNET_break_op (0);
8201 finish_cmc_handling (cmc);
8202 return;
8203 }
8204 n = lookup_neighbour (&hops[i]);
8205 if (NULL == n)
8206 continue;
8207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8208 "Skipping %u/%u hops ahead while routing DV Box\n",
8209 i,
8210 num_hops);
8211
8212 forward_dv_box (n,
8213 (struct TransportDVBoxMessage *) dvb,
8214 ntohs (dvb->total_hops) + 1,
8215 num_hops - i - 1, /* number of hops left */
8216 &hops[i + 1], /* remaining hops */
8217 enc_payload,
8218 enc_payload_size);
8219 GNUNET_STATISTICS_update (GST_stats,
8220 "# DV hops skipped routing boxes",
8221 i,
8222 GNUNET_NO);
8223 GNUNET_STATISTICS_update (GST_stats,
8224 "# DV boxes routed (total)",
8225 1,
8226 GNUNET_NO);
8227 finish_cmc_handling (cmc);
8228 return;
8229 }
8230 /* Woopsie, next hop not in neighbours, drop! */
8231 GNUNET_STATISTICS_update (GST_stats,
8232 "# DV Boxes dropped: next hop unknown",
8233 1,
8234 GNUNET_NO);
8235 finish_cmc_handling (cmc);
8236 return;
8237 }
8238 /* We are the target. Unbox and handle message. */
8239 GNUNET_STATISTICS_update (GST_stats,
8240 "# DV boxes opened (ultimate target)",
8241 1,
8242 GNUNET_NO);
8243 cmc->total_hops = ntohs (dvb->total_hops);
8244
8245 // DH key derivation with received DV, could be garbage.
8246 if (GNUNET_OK !=
8247 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key))
8248 {
8249 GNUNET_break_op (0);
8250 finish_cmc_handling (cmc);
8251 return;
8252 }
8253 hdr = (const char *) &dvb[1];
8254 hdr_len = ntohs (dvb->orig_size) - sizeof(*dvb) - sizeof(struct
8255 GNUNET_PeerIdentity)
8256 * ntohs (dvb->total_hops);
8257
8258 dv_hmac (&key, &hmac, hdr, hdr_len);
8259 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
8260 {
8261 /* HMAC mismatch, discard! */
8262 GNUNET_break_op (0);
8263 finish_cmc_handling (cmc);
8264 return;
8265 }
8266 /* begin actual decryption */
8267 {
8268 struct Backtalker *b;
8269 struct GNUNET_TIME_Absolute monotime;
8270 struct TransportDVBoxPayloadP ppay;
8271 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
8272 const struct GNUNET_MessageHeader *mh;
8273
8274 GNUNET_assert (hdr_len >=
8275 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
8276 if (GNUNET_OK != dv_decrypt (&key, &ppay, hdr, sizeof(ppay)))
8277 {
8278 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8279 "Error decrypting DV payload header\n");
8280 GNUNET_break_op (0);
8281 finish_cmc_handling (cmc);
8282 return;
8283 }
8284 if (GNUNET_OK != dv_decrypt (&key, body,
8285 &hdr[sizeof(ppay)], hdr_len - sizeof(ppay)))
8286 {
8287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8288 "Error decrypting DV payload\n");
8289 GNUNET_break_op (0);
8290 finish_cmc_handling (cmc);
8291 return;
8292 }
8293 mh = (const struct GNUNET_MessageHeader *) body;
8294 dv_key_clean (&key);
8295 if (ntohs (mh->size) != sizeof(body))
8296 {
8297 GNUNET_break_op (0);
8298 finish_cmc_handling (cmc);
8299 return;
8300 }
8301 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
8302 switch (ntohs (mh->type))
8303 {
8304 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
8305 GNUNET_break_op (0);
8306 finish_cmc_handling (cmc);
8307 return;
8308
8309 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
8310 GNUNET_break_op (0);
8311 finish_cmc_handling (cmc);
8312 return;
8313
8314 default:
8315 /* permitted, continue */
8316 break;
8317 }
8318 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
8319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8320 "Decrypted backtalk from %s\n",
8321 GNUNET_i2s (&ppay.sender));
8322 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
8323 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
8324 {
8325 GNUNET_STATISTICS_update (
8326 GST_stats,
8327 "# Backchannel messages dropped: monotonic time not increasing",
8328 1,
8329 GNUNET_NO);
8330 finish_cmc_handling (cmc);
8331 return;
8332 }
8333 if ((NULL == b) ||
8334 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
8335 {
8336 /* Check signature */
8337 struct EphemeralConfirmationPS ec;
8338
8339 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
8340 ec.target = GST_my_identity;
8341 ec.ephemeral_key = dvb->ephemeral_key;
8342 ec.purpose.size = htonl (sizeof(ec));
8343 ec.sender_monotonic_time = ppay.monotonic_time;
8344 if (
8345 GNUNET_OK !=
8346 GNUNET_CRYPTO_eddsa_verify (
8347 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
8348 &ec,
8349 &ppay.sender_sig,
8350 &ppay.sender.public_key))
8351 {
8352 /* Signature invalid, discard! */
8353 GNUNET_break_op (0);
8354 finish_cmc_handling (cmc);
8355 return;
8356 }
8357 }
8358 /* Update sender, we now know the real origin! */
8359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8360 "DVBox received for me from %s via %s\n",
8361 GNUNET_i2s2 (&ppay.sender),
8362 GNUNET_i2s (&cmc->im.sender));
8363 cmc->im.sender = ppay.sender;
8364
8365 if (NULL != b)
8366 {
8367 /* update key cache and mono time */
8368 b->last_ephemeral = dvb->ephemeral_key;
8369 b->monotonic_time = monotime;
8370 update_backtalker_monotime (b);
8371 b->timeout =
8372 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8373 cmc->mh = mh;
8374 demultiplex_with_cmc (cmc);
8375 return;
8376 }
8377 /* setup data structure to cache signature AND check
8378 monotonic time with PEERSTORE before forwarding backchannel payload */
8379 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
8380 b->pid = ppay.sender;
8381 b->body_size = sizeof(body);
8382 memcpy (&b[1], body, sizeof(body));
8383 GNUNET_assert (GNUNET_YES ==
8384 GNUNET_CONTAINER_multipeermap_put (
8385 backtalkers,
8386 &b->pid,
8387 b,
8388 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8389 b->monotonic_time = monotime; /* NOTE: to be checked still! */
8390 b->cmc = cmc;
8391 b->timeout =
8392 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8393 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8394 b->get =
8395 GNUNET_PEERSTORE_iterate (peerstore,
8396 "transport",
8397 &b->pid,
8398 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8399 &backtalker_monotime_cb,
8400 b);
8401 } /* end actual decryption */
8402}
8403
8404
8405/**
8406 * Client notified us about transmission from a peer. Process the request.
8407 *
8408 * @param cls a `struct TransportClient` which sent us the message
8409 * @param im the send message that was sent
8410 * @return #GNUNET_YES if message is well-formed
8411 */
8412static int
8413check_incoming_msg (void *cls,
8414 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8415{
8416 struct TransportClient *tc = cls;
8417
8418 if (CT_COMMUNICATOR != tc->type)
8419 {
8420 GNUNET_break (0);
8421 return GNUNET_SYSERR;
8422 }
8423 GNUNET_MQ_check_boxed_message (im);
8424 return GNUNET_OK;
8425}
8426
8427
8428/**
8429 * Closure for #check_known_address.
8430 */
8431struct CheckKnownAddressContext
8432{
8433 /**
8434 * Set to the address we are looking for.
8435 */
8436 const char *address;
8437
8438 /**
8439 * Set to a matching validation state, if one was found.
8440 */
8441 struct ValidationState *vs;
8442};
8443
8444
8445/**
8446 * Test if the validation state in @a value matches the
8447 * address from @a cls.
8448 *
8449 * @param cls a `struct CheckKnownAddressContext`
8450 * @param pid unused (must match though)
8451 * @param value a `struct ValidationState`
8452 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8453 */
8454static int
8455check_known_address (void *cls,
8456 const struct GNUNET_PeerIdentity *pid,
8457 void *value)
8458{
8459 struct CheckKnownAddressContext *ckac = cls;
8460 struct ValidationState *vs = value;
8461
8462 (void) pid;
8463 if (0 != strcmp (vs->address, ckac->address))
8464 return GNUNET_OK;
8465 ckac->vs = vs;
8466 return GNUNET_NO;
8467}
8468
8469
8470/**
8471 * Task run periodically to validate some address based on #validation_heap.
8472 *
8473 * @param cls NULL
8474 */
8475static void
8476validation_start_cb (void *cls);
8477
8478
8479/**
8480 * Set the time for next_challenge of @a vs to @a new_time.
8481 * Updates the heap and if necessary reschedules the job.
8482 *
8483 * @param vs validation state to update
8484 * @param new_time new time for revalidation
8485 */
8486static void
8487update_next_challenge_time (struct ValidationState *vs,
8488 struct GNUNET_TIME_Absolute new_time)
8489{
8490 struct GNUNET_TIME_Relative delta;
8491
8492 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
8493 return; /* be lazy */
8494 vs->next_challenge = new_time;
8495 if (NULL == vs->hn)
8496 vs->hn =
8497 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
8498 else
8499 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
8500 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
8501 (NULL != validation_task))
8502 return;
8503 if (NULL != validation_task)
8504 GNUNET_SCHEDULER_cancel (validation_task);
8505 /* randomize a bit */
8506 delta.rel_value_us =
8507 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
8508 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
8509 new_time = GNUNET_TIME_absolute_add (new_time, delta);
8510 validation_task =
8511 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
8512}
8513
8514
8515/**
8516 * Start address validation.
8517 *
8518 * @param pid peer the @a address is for
8519 * @param address an address to reach @a pid (presumably)
8520 */
8521static void
8522start_address_validation (const struct GNUNET_PeerIdentity *pid,
8523 const char *address)
8524{
8525 struct GNUNET_TIME_Absolute now;
8526 struct ValidationState *vs;
8527 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
8528
8529 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8530 pid,
8531 &check_known_address,
8532 &ckac);
8533 if (NULL != (vs = ckac.vs))
8534 {
8535 /* if 'vs' is not currently valid, we need to speed up retrying the
8536 * validation */
8537 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8538 {
8539 /* reduce backoff as we got a fresh advertisement */
8540 vs->challenge_backoff =
8541 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8542 GNUNET_TIME_relative_divide (
8543 vs->challenge_backoff,
8544 2));
8545 update_next_challenge_time (vs,
8546 GNUNET_TIME_relative_to_absolute (
8547 vs->challenge_backoff));
8548 }
8549 return;
8550 }
8551 now = GNUNET_TIME_absolute_get ();
8552 vs = GNUNET_new (struct ValidationState);
8553 vs->pid = *pid;
8554 vs->valid_until =
8555 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8556 vs->first_challenge_use = now;
8557 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8558 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8559 &vs->challenge,
8560 sizeof(vs->challenge));
8561 vs->address = GNUNET_strdup (address);
8562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8563 "Starting address validation `%s' of peer %s using challenge %s\n",
8564 address,
8565 GNUNET_i2s (pid),
8566 GNUNET_sh2s (&vs->challenge.value));
8567 GNUNET_assert (GNUNET_YES ==
8568 GNUNET_CONTAINER_multipeermap_put (
8569 validation_map,
8570 &vs->pid,
8571 vs,
8572 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
8573 update_next_challenge_time (vs, now);
8574}
8575
8576
8577/**
8578 * Function called by PEERSTORE for each matching record.
8579 *
8580 * @param cls closure, a `struct IncomingRequest`
8581 * @param record peerstore record information
8582 * @param emsg error message, or NULL if no errors
8583 */
8584static void
8585handle_hello_for_incoming (void *cls,
8586 const struct GNUNET_PEERSTORE_Record *record,
8587 const char *emsg)
8588{
8589 struct IncomingRequest *ir = cls;
8590 const char *val;
8591
8592 if (NULL != emsg)
8593 {
8594 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8595 "Got failure from PEERSTORE: %s\n",
8596 emsg);
8597 return;
8598 }
8599 val = record->value;
8600 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8601 {
8602 GNUNET_break (0);
8603 return;
8604 }
8605 start_address_validation (&ir->pid, (const char *) record->value);
8606}
8607
8608
8609/**
8610 * Communicator gave us a transport address validation challenge. Process the
8611 * request.
8612 *
8613 * @param cls a `struct CommunicatorMessageContext` (must call
8614 * #finish_cmc_handling() when done)
8615 * @param tvc the message that was received
8616 */
8617static void
8618handle_validation_challenge (
8619 void *cls,
8620 const struct TransportValidationChallengeMessage *tvc)
8621{
8622 struct CommunicatorMessageContext *cmc = cls;
8623 struct TransportValidationResponseMessage tvr;
8624 struct VirtualLink *vl;
8625 struct GNUNET_TIME_RelativeNBO validity_duration;
8626 struct IncomingRequest *ir;
8627 struct Neighbour *n;
8628 struct GNUNET_PeerIdentity sender;
8629
8630 /* DV-routed messages are not allowed for validation challenges */
8631 if (cmc->total_hops > 0)
8632 {
8633 GNUNET_break_op (0);
8634 finish_cmc_handling (cmc);
8635 return;
8636 }
8637 validity_duration = cmc->im.expected_address_validity;
8638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8639 "Received address validation challenge %s\n",
8640 GNUNET_sh2s (&tvc->challenge.value));
8641 /* If we have a virtual link, we use this mechanism to signal the
8642 size of the flow control window, and to allow the sender
8643 to ask for increases. If for us the virtual link is still down,
8644 we will always give a window size of zero. */
8645 tvr.header.type =
8646 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
8647 tvr.header.size = htons (sizeof(tvr));
8648 tvr.reserved = htonl (0);
8649 tvr.challenge = tvc->challenge;
8650 tvr.origin_time = tvc->sender_time;
8651 tvr.validity_duration = validity_duration;
8652 {
8653 /* create signature */
8654 struct TransportValidationPS tvp = {
8655 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8656 .purpose.size = htonl (sizeof(tvp)),
8657 .validity_duration = validity_duration,
8658 .challenge = tvc->challenge
8659 };
8660
8661 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8662 &tvp,
8663 &tvr.signature);
8664 }
8665 sender = cmc->im.sender;
8666 vl = lookup_virtual_link (&sender);
8667 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8668 {
8669 // route_control_message_without_fc (&cmc->im.sender,
8670 route_control_message_without_fc (vl,
8671 &tvr.header,
8672 RMO_ANYTHING_GOES | RMO_REDUNDANT);
8673 }
8674 else
8675 {
8676 /* Use route via neighbour */
8677 n = lookup_neighbour (&sender);
8678 if (NULL != n)
8679 route_via_neighbour (n, &tvr.header,
8680 RMO_ANYTHING_GOES | RMO_REDUNDANT
8681 | RMO_UNCONFIRMED_ALLOWED);
8682 }
8683
8684 finish_cmc_handling (cmc);
8685 if (NULL != vl)
8686 return;
8687
8688 /* For us, the link is still down, but we need bi-directional
8689 connections (for flow-control and for this to be useful for
8690 CORE), so we must try to bring the link up! */
8691
8692 /* (1) Check existing queues, if any, we may be lucky! */
8693 n = lookup_neighbour (&sender);
8694 if (NULL != n)
8695 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8696 start_address_validation (&sender, q->address);
8697 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
8698 we could use */
8699 for (ir = ir_head; NULL != ir; ir = ir->next)
8700 if (0 == GNUNET_memcmp (&ir->pid, &sender))
8701 return;
8702 /* we are already trying */
8703 ir = GNUNET_new (struct IncomingRequest);
8704 ir->pid = sender;
8705 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
8706 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
8707 "transport",
8708 &ir->pid,
8709 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8710 &handle_hello_for_incoming,
8711 ir);
8712 ir_total++;
8713 /* Bound attempts we do in parallel here, might otherwise get excessive */
8714 while (ir_total > MAX_INCOMING_REQUEST)
8715 free_incoming_request (ir_head);
8716}
8717
8718
8719/**
8720 * Closure for #check_known_challenge.
8721 */
8722struct CheckKnownChallengeContext
8723{
8724 /**
8725 * Set to the challenge we are looking for.
8726 */
8727 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge;
8728
8729 /**
8730 * Set to a matching validation state, if one was found.
8731 */
8732 struct ValidationState *vs;
8733};
8734
8735
8736/**
8737 * Test if the validation state in @a value matches the
8738 * challenge from @a cls.
8739 *
8740 * @param cls a `struct CheckKnownChallengeContext`
8741 * @param pid unused (must match though)
8742 * @param value a `struct ValidationState`
8743 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8744 */
8745static int
8746check_known_challenge (void *cls,
8747 const struct GNUNET_PeerIdentity *pid,
8748 void *value)
8749{
8750 struct CheckKnownChallengeContext *ckac = cls;
8751 struct ValidationState *vs = value;
8752
8753 (void) pid;
8754 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
8755 return GNUNET_OK;
8756 ckac->vs = vs;
8757 return GNUNET_NO;
8758}
8759
8760
8761/**
8762 * Function called when peerstore is done storing a
8763 * validated address.
8764 *
8765 * @param cls a `struct ValidationState`
8766 * @param success #GNUNET_YES on success
8767 */
8768static void
8769peerstore_store_validation_cb (void *cls, int success)
8770{
8771 struct ValidationState *vs = cls;
8772
8773 vs->sc = NULL;
8774 if (GNUNET_YES == success)
8775 return;
8776 GNUNET_STATISTICS_update (GST_stats,
8777 "# Peerstore failed to store foreign address",
8778 1,
8779 GNUNET_NO);
8780}
8781
8782
8783/**
8784 * Find the queue matching @a pid and @a address.
8785 *
8786 * @param pid peer the queue must go to
8787 * @param address address the queue must use
8788 * @return NULL if no such queue exists
8789 */
8790static struct Queue *
8791find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
8792{
8793 struct Neighbour *n;
8794
8795 n = lookup_neighbour (pid);
8796 if (NULL == n)
8797 return NULL;
8798 for (struct Queue *pos = n->queue_head; NULL != pos;
8799 pos = pos->next_neighbour)
8800 {
8801 if (0 == strcmp (pos->address, address))
8802 return pos;
8803 }
8804 return NULL;
8805}
8806
8807
8808/**
8809 * Communicator gave us a transport address validation response. Process the
8810 * request.
8811 *
8812 * @param cls a `struct CommunicatorMessageContext` (must call
8813 * #finish_cmc_handling() when done)
8814 * @param tvr the message that was received
8815 */
8816static void
8817handle_validation_response (
8818 void *cls,
8819 const struct TransportValidationResponseMessage *tvr)
8820{
8821 struct CommunicatorMessageContext *cmc = cls;
8822 struct ValidationState *vs;
8823 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
8824 .vs = NULL };
8825 struct GNUNET_TIME_Absolute origin_time;
8826 struct Queue *q;
8827 struct Neighbour *n;
8828 struct VirtualLink *vl;
8829
8830 /* check this is one of our challenges */
8831 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8832 &cmc->im.sender,
8833 &check_known_challenge,
8834 &ckac);
8835 if (NULL == (vs = ckac.vs))
8836 {
8837 /* This can happen simply if we 'forgot' the challenge by now,
8838 i.e. because we received the validation response twice */
8839 GNUNET_STATISTICS_update (GST_stats,
8840 "# Validations dropped, challenge unknown",
8841 1,
8842 GNUNET_NO);
8843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8844 "Validation response %s dropped, challenge unknown\n",
8845 GNUNET_sh2s (&tvr->challenge.value));
8846 finish_cmc_handling (cmc);
8847 return;
8848 }
8849
8850 /* sanity check on origin time */
8851 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
8852 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
8853 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
8854 {
8855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8856 "Diff first use %lu and last use %lu\n",
8857 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
8858 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
8859 GNUNET_break_op (0);
8860 finish_cmc_handling (cmc);
8861 return;
8862 }
8863
8864 {
8865 /* check signature */
8866 struct TransportValidationPS tvp = {
8867 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8868 .purpose.size = htonl (sizeof(tvp)),
8869 .validity_duration = tvr->validity_duration,
8870 .challenge = tvr->challenge
8871 };
8872
8873 if (
8874 GNUNET_OK !=
8875 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
8876 &tvp,
8877 &tvr->signature,
8878 &cmc->im.sender.public_key))
8879 {
8880 GNUNET_break_op (0);
8881 finish_cmc_handling (cmc);
8882 return;
8883 }
8884 }
8885
8886 /* validity is capped by our willingness to keep track of the
8887 validation entry and the maximum the other peer allows */
8888 vs->valid_until = GNUNET_TIME_relative_to_absolute (
8889 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
8890 tvr->validity_duration),
8891 MAX_ADDRESS_VALID_UNTIL));
8892 vs->validated_until =
8893 GNUNET_TIME_absolute_min (vs->valid_until,
8894 GNUNET_TIME_relative_to_absolute (
8895 ADDRESS_VALIDATION_LIFETIME));
8896 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
8897 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
8898 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8899 &vs->challenge,
8900 sizeof(vs->challenge));
8901 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
8902 vs->validated_until,
8903 GNUNET_TIME_relative_multiply (vs->validation_rtt,
8904 VALIDATION_RTT_BUFFER_FACTOR));
8905 vs->last_challenge_use =
8906 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
8907 update_next_challenge_time (vs, vs->first_challenge_use);
8908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8909 "Validation response %s from %s accepted, address valid until %s\n",
8910 GNUNET_sh2s (&tvr->challenge.value),
8911 GNUNET_i2s (&cmc->im.sender),
8912 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
8913 vs->sc = GNUNET_PEERSTORE_store (peerstore,
8914 "transport",
8915 &cmc->im.sender,
8916 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8917 vs->address,
8918 strlen (vs->address) + 1,
8919 vs->valid_until,
8920 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
8921 &peerstore_store_validation_cb,
8922 vs);
8923 finish_cmc_handling (cmc);
8924
8925 /* Finally, we now possibly have a confirmed (!) working queue,
8926 update queue status (if queue still is around) */
8927 q = find_queue (&vs->pid, vs->address);
8928 if (NULL == q)
8929 {
8930 GNUNET_STATISTICS_update (GST_stats,
8931 "# Queues lost at time of successful validation",
8932 1,
8933 GNUNET_NO);
8934 return;
8935 }
8936 q->validated_until = vs->validated_until;
8937 q->pd.aged_rtt = vs->validation_rtt;
8938 n = q->neighbour;
8939 vl = lookup_virtual_link (&vs->pid);
8940 if (NULL == vl)
8941 {
8942 vl = GNUNET_new (struct VirtualLink);
8943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8944 "Creating new virtual link %p to %s using direct neighbour!\n",
8945 vl,
8946 GNUNET_i2s (&vs->pid));
8947 vl->confirmed = GNUNET_YES;
8948 vl->message_uuid_ctr =
8949 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8950 vl->target = n->pid;
8951 vl->core_recv_window = RECV_WINDOW_SIZE;
8952 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8953 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8954 GNUNET_break (GNUNET_YES ==
8955 GNUNET_CONTAINER_multipeermap_put (
8956 links,
8957 &vl->target,
8958 vl,
8959 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8960 vl->n = n;
8961 n->vl = vl;
8962 q->idle = GNUNET_YES;
8963 vl->visibility_task =
8964 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8965 consider_sending_fc (vl);
8966 /* We lacked a confirmed connection to the target
8967 before, so tell CORE about it (finally!) */
8968 cores_send_connect_info (&n->pid);
8969 send_msg_from_cache (vl);
8970 }
8971 else
8972 {
8973 /* Link was already up, remember n is also now available and we are done */
8974 if (NULL == vl->n)
8975 {
8976 vl->n = n;
8977 n->vl = vl;
8978 if (GNUNET_YES == vl->confirmed)
8979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8980 "Virtual link to %s could now also use direct neighbour!\n",
8981 GNUNET_i2s (&vs->pid));
8982 }
8983 else
8984 {
8985 GNUNET_assert (n == vl->n);
8986 }
8987 if (GNUNET_NO == vl->confirmed)
8988 {
8989 vl->confirmed = GNUNET_YES;
8990 q->idle = GNUNET_YES;
8991 vl->visibility_task =
8992 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8993 consider_sending_fc (vl);
8994 /* We lacked a confirmed connection to the target
8995 before, so tell CORE about it (finally!) */
8996 cores_send_connect_info (&n->pid);
8997 send_msg_from_cache (vl);
8998 }
8999 }
9000}
9001
9002
9003/**
9004 * Incoming meessage. Process the request.
9005 *
9006 * @param im the send message that was received
9007 */
9008static void
9009handle_incoming_msg (void *cls,
9010 const struct GNUNET_TRANSPORT_IncomingMessage *im)
9011{
9012 struct TransportClient *tc = cls;
9013 struct CommunicatorMessageContext *cmc =
9014 GNUNET_new (struct CommunicatorMessageContext);
9015
9016 cmc->tc = tc;
9017 cmc->im = *im;
9018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9019 "Received message with size %u and flow control id %lu via communicator from peer %s\n",
9020 ntohs (im->header.size),
9021 im->fc_id,
9022 GNUNET_i2s (&im->sender));
9023 cmc->im.neighbour_sender = cmc->im.sender;
9024 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
9025 demultiplex_with_cmc (cmc);
9026}
9027
9028
9029/**
9030 * Communicator gave us a transport address validation response. Process the
9031 * request.
9032 *
9033 * @param cls a `struct CommunicatorMessageContext` (must call
9034 * #finish_cmc_handling() when done)
9035 * @param fc the message that was received
9036 */
9037static void
9038handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
9039{
9040 struct CommunicatorMessageContext *cmc = cls;
9041 struct VirtualLink *vl;
9042 uint32_t seq;
9043 struct GNUNET_TIME_Absolute st;
9044 uint64_t os;
9045 uint64_t wnd;
9046 uint32_t random;
9047
9048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9049 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
9050 vl = lookup_virtual_link (&cmc->im.sender);
9051 if (NULL == vl)
9052 {
9053 vl = GNUNET_new (struct VirtualLink);
9054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9055 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
9056 vl,
9057 GNUNET_i2s (&cmc->im.sender));
9058 vl->confirmed = GNUNET_NO;
9059 vl->message_uuid_ctr =
9060 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
9061 vl->target = cmc->im.sender;
9062 vl->core_recv_window = RECV_WINDOW_SIZE;
9063 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
9064 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
9065 GNUNET_break (GNUNET_YES ==
9066 GNUNET_CONTAINER_multipeermap_put (
9067 links,
9068 &vl->target,
9069 vl,
9070 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9071 }
9072 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
9073 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
9074 {
9075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9076 "FC dropped: Message out of order\n");
9077 /* out of order, drop */
9078 GNUNET_STATISTICS_update (GST_stats,
9079 "# FC dropped: message out of order",
9080 1,
9081 GNUNET_NO);
9082 finish_cmc_handling (cmc);
9083 return;
9084 }
9085 seq = ntohl (fc->seq);
9086 if (seq < vl->last_fc_seq)
9087 {
9088 /* Wrap-around/reset of other peer; start all counters from zero */
9089 vl->outbound_fc_window_size_used = 0;
9090 }
9091 vl->last_fc_seq = seq;
9092 vl->last_fc_timestamp = st;
9093 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
9094 os = GNUNET_ntohll (fc->outbound_sent);
9095 vl->incoming_fc_window_size_loss =
9096 (int64_t) (os - vl->incoming_fc_window_size_used);
9097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9098 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
9099 GNUNET_i2s (&vl->target),
9100 (unsigned int) seq,
9101 (unsigned long long) vl->outbound_fc_window_size,
9102 (long long) vl->incoming_fc_window_size_loss);
9103 wnd = GNUNET_ntohll (fc->outbound_window_size);
9104 random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
9105 UINT32_MAX);
9106 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size) ||
9107 (vl->last_outbound_window_size_received
9108 != wnd) ||
9109 (0 == random
9110 % FC_NO_CHANGE_REPLY_PROBABILITY)))
9111 {
9112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9113 "Consider re-sending our FC message, as clearly the other peer's idea of the window is not up-to-date (%llu vs %llu) or %llu last received differs, or random reply %u\n",
9114 (unsigned long long) wnd,
9115 (unsigned long long) vl->incoming_fc_window_size,
9116 (unsigned long long) vl->last_outbound_window_size_received,
9117 random % FC_NO_CHANGE_REPLY_PROBABILITY);
9118 consider_sending_fc (vl);
9119 }
9120 if ((wnd == vl->incoming_fc_window_size) &&
9121 (vl->last_outbound_window_size_received == wnd) &&
9122 (NULL != vl->fc_retransmit_task))
9123 {
9124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9125 "Stopping FC retransmission to %s: peer is current at window %llu\n",
9126 GNUNET_i2s (&vl->target),
9127 (unsigned long long) wnd);
9128 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
9129 vl->fc_retransmit_task = NULL;
9130 vl->fc_retransmit_count = 0;
9131 }
9132 vl->last_outbound_window_size_received = wnd;
9133 /* FC window likely increased, check transmission possibilities! */
9134 check_vl_transmission (vl);
9135 finish_cmc_handling (cmc);
9136}
9137
9138
9139/**
9140 * Given an inbound message @a msg from a communicator @a cmc,
9141 * demultiplex it based on the type calling the right handler.
9142 *
9143 * @param cmc context for demultiplexing
9144 * @param msg message to demultiplex
9145 */
9146static void
9147demultiplex_with_cmc (struct CommunicatorMessageContext *cmc)
9148{
9149 struct GNUNET_MQ_MessageHandler handlers[] =
9150 { GNUNET_MQ_hd_var_size (fragment_box,
9151 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
9152 struct TransportFragmentBoxMessage,
9153 cmc),
9154 GNUNET_MQ_hd_var_size (reliability_box,
9155 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
9156 struct TransportReliabilityBoxMessage,
9157 cmc),
9158 GNUNET_MQ_hd_var_size (reliability_ack,
9159 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
9160 struct TransportReliabilityAckMessage,
9161 cmc),
9162 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
9163 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
9164 struct TransportBackchannelEncapsulationMessage,
9165 cmc),
9166 GNUNET_MQ_hd_var_size (dv_learn,
9167 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
9168 struct TransportDVLearnMessage,
9169 cmc),
9170 GNUNET_MQ_hd_var_size (dv_box,
9171 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
9172 struct TransportDVBoxMessage,
9173 cmc),
9174 GNUNET_MQ_hd_fixed_size (
9175 validation_challenge,
9176 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
9177 struct TransportValidationChallengeMessage,
9178 cmc),
9179 GNUNET_MQ_hd_fixed_size (flow_control,
9180 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
9181 struct TransportFlowControlMessage,
9182 cmc),
9183 GNUNET_MQ_hd_fixed_size (
9184 validation_response,
9185 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
9186 struct TransportValidationResponseMessage,
9187 cmc),
9188 GNUNET_MQ_handler_end () };
9189 int ret;
9190 const struct GNUNET_MessageHeader *msg = cmc->mh;
9191
9192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9193 "Handling message of type %u with %u bytes\n",
9194 (unsigned int) ntohs (msg->type),
9195 (unsigned int) ntohs (msg->size));
9196 ret = GNUNET_MQ_handle_message (handlers, msg);
9197 if (GNUNET_SYSERR == ret)
9198 {
9199 GNUNET_break (0);
9200 GNUNET_SERVICE_client_drop (cmc->tc->client);
9201 GNUNET_free (cmc);
9202 return;
9203 }
9204 if (GNUNET_NO == ret)
9205 {
9206 /* unencapsulated 'raw' message */
9207 handle_raw_message (cmc, msg);
9208 }
9209}
9210
9211
9212/**
9213 * New queue became available. Check message.
9214 *
9215 * @param cls the client
9216 * @param aqm the send message that was sent
9217 */
9218static int
9219check_add_queue_message (void *cls,
9220 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9221{
9222 struct TransportClient *tc = cls;
9223
9224 if (CT_COMMUNICATOR != tc->type)
9225 {
9226 GNUNET_break (0);
9227 return GNUNET_SYSERR;
9228 }
9229 GNUNET_MQ_check_zero_termination (aqm);
9230 return GNUNET_OK;
9231}
9232
9233
9234/**
9235 * If necessary, generates the UUID for a @a pm
9236 *
9237 * @param pm pending message to generate UUID for.
9238 */
9239static void
9240set_pending_message_uuid (struct PendingMessage *pm)
9241{
9242 if (pm->msg_uuid_set)
9243 return;
9244 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
9245 pm->msg_uuid_set = GNUNET_YES;
9246}
9247
9248
9249/**
9250 * Setup data structure waiting for acknowledgements.
9251 *
9252 * @param queue queue the @a pm will be sent over
9253 * @param dvh path the message will take, may be NULL
9254 * @param pm the pending message for transmission
9255 * @return corresponding fresh pending acknowledgement
9256 */
9257static struct PendingAcknowledgement *
9258prepare_pending_acknowledgement (struct Queue *queue,
9259 struct DistanceVectorHop *dvh,
9260 struct PendingMessage *pm)
9261{
9262 struct PendingAcknowledgement *pa;
9263
9264 pa = GNUNET_new (struct PendingAcknowledgement);
9265 pa->queue = queue;
9266 pa->dvh = dvh;
9267 pa->pm = pm;
9268 do
9269 {
9270 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9271 &pa->ack_uuid,
9272 sizeof(pa->ack_uuid));
9273 }
9274 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
9275 pending_acks,
9276 &pa->ack_uuid.value,
9277 pa,
9278 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9279 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
9280 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
9281 if (NULL != dvh)
9282 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
9283 pa->transmission_time = GNUNET_TIME_absolute_get ();
9284 pa->message_size = pm->bytes_msg;
9285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9286 "Waiting for ACKnowledgment `%s' for <%llu>\n",
9287 GNUNET_uuid2s (&pa->ack_uuid.value),
9288 pm->logging_uuid);
9289 return pa;
9290}
9291
9292
9293/**
9294 * Fragment the given @a pm to the given @a mtu. Adds
9295 * additional fragments to the neighbour as well. If the
9296 * @a mtu is too small, generates and error for the @a pm
9297 * and returns NULL.
9298 *
9299 * @param queue which queue to fragment for
9300 * @param dvh path the message will take, or NULL
9301 * @param pm pending message to fragment for transmission
9302 * @return new message to transmit
9303 */
9304static struct PendingMessage *
9305fragment_message (struct Queue *queue,
9306 struct DistanceVectorHop *dvh,
9307 struct PendingMessage *pm)
9308{
9309 struct PendingAcknowledgement *pa;
9310 struct PendingMessage *ff;
9311 uint16_t mtu;
9312
9313 mtu = (UINT16_MAX == queue->mtu)
9314 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
9315 : queue->mtu;
9316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9317 "Fragmenting message <%llu> with size %u to %s for MTU %u\n",
9318 pm->logging_uuid,
9319 pm->bytes_msg,
9320 GNUNET_i2s (&pm->vl->target),
9321 (unsigned int) mtu);
9322 set_pending_message_uuid (pm);
9323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9324 "Fragmenting message %llu <%llu> with size %u to %s for MTU %u\n",
9325 (unsigned long long) pm->msg_uuid.uuid,
9326 pm->logging_uuid,
9327 pm->bytes_msg,
9328 GNUNET_i2s (&pm->vl->target),
9329 (unsigned int) mtu);
9330
9331 /* This invariant is established in #handle_add_queue_message() */
9332 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
9333
9334 /* select fragment for transmission, descending the tree if it has
9335 been expanded until we are at a leaf or at a fragment that is small
9336 enough
9337 */
9338 ff = pm;
9339 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
9340 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
9341 {
9342 ff = ff->head_frag; /* descent into fragmented fragments */
9343 }
9344
9345 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < ff->bytes_msg))
9346 {
9347 /* Did not yet calculate all fragments, calculate next fragment */
9348 struct PendingMessage *frag;
9349 struct TransportFragmentBoxMessage tfb;
9350 const char *orig;
9351 char *msg;
9352 uint16_t fragmax;
9353 uint16_t fragsize;
9354 uint16_t msize;
9355 uint16_t xoff = 0;
9356
9357 orig = (const char *) &ff[1];
9358 msize = ff->bytes_msg;
9359 if (pm != ff)
9360 {
9361 const struct TransportFragmentBoxMessage *tfbo;
9362
9363 tfbo = (const struct TransportFragmentBoxMessage *) orig;
9364 orig += sizeof(struct TransportFragmentBoxMessage);
9365 msize -= sizeof(struct TransportFragmentBoxMessage);
9366 xoff = ntohs (tfbo->frag_off);
9367 }
9368 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
9369 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
9370 frag =
9371 GNUNET_malloc (sizeof(struct PendingMessage)
9372 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
9373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9374 "3 created pm %p from pm %p storing vl %p from pm %p\n",
9375 frag,
9376 ff,
9377 pm->vl,
9378 pm);
9379 frag->logging_uuid = logging_uuid_gen++;
9380 frag->vl = pm->vl;
9381 frag->frag_parent = ff;
9382 frag->timeout = pm->timeout;
9383 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
9384 frag->pmt = PMT_FRAGMENT_BOX;
9385 msg = (char *) &frag[1];
9386 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
9387 tfb.header.size =
9388 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
9389 pa = prepare_pending_acknowledgement (queue, dvh, frag);
9390 tfb.ack_uuid = pa->ack_uuid;
9391 tfb.msg_uuid = pm->msg_uuid;
9392 tfb.frag_off = htons (ff->frag_off + xoff);
9393 tfb.msg_size = htons (pm->bytes_msg);
9394 memcpy (msg, &tfb, sizeof(tfb));
9395 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
9396 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag,
9397 ff->tail_frag, frag);
9398 ff->frag_off += fragsize;
9399 ff = frag;
9400 }
9401
9402 /* Move head to the tail and return it */
9403 GNUNET_CONTAINER_MDLL_remove (frag,
9404 ff->frag_parent->head_frag,
9405 ff->frag_parent->tail_frag,
9406 ff);
9407 GNUNET_CONTAINER_MDLL_insert_tail (frag,
9408 ff->frag_parent->head_frag,
9409 ff->frag_parent->tail_frag,
9410 ff);
9411
9412 return ff;
9413}
9414
9415
9416/**
9417 * Reliability-box the given @a pm. On error (can there be any), NULL
9418 * may be returned, otherwise the "replacement" for @a pm (which
9419 * should then be added to the respective neighbour's queue instead of
9420 * @a pm). If the @a pm is already fragmented or reliability boxed,
9421 * or itself an ACK, this function simply returns @a pm.
9422 *
9423 * @param queue which queue to prepare transmission for
9424 * @param dvh path the message will take, or NULL
9425 * @param pm pending message to box for transmission over unreliabile queue
9426 * @return new message to transmit
9427 */
9428static struct PendingMessage *
9429reliability_box_message (struct Queue *queue,
9430 struct DistanceVectorHop *dvh,
9431 struct PendingMessage *pm)
9432{
9433 struct TransportReliabilityBoxMessage rbox;
9434 struct PendingAcknowledgement *pa;
9435 struct PendingMessage *bpm;
9436 char *msg;
9437
9438 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
9439 return pm; /* already fragmented or reliability boxed, or control message:
9440 do nothing */
9441 if (NULL != pm->bpm)
9442 return pm->bpm; /* already computed earlier: do nothing */
9443 // TODO I guess we do not need this assertion. We might have a DLL with
9444 // fragments, because the MTU changed, and we do not need to fragment anymore.
9445 // But we should keep the fragments until message was completed, because
9446 // the MTU might change again.
9447 // GNUNET_assert (NULL == pm->head_frag);
9448 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
9449 {
9450 /* failed hard */
9451 GNUNET_break (0);
9452 client_send_response (pm);
9453 return NULL;
9454 }
9455
9456 pa = prepare_pending_acknowledgement (queue, dvh, pm);
9457
9458 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
9459 + pm->bytes_msg);
9460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9461 "4 created pm %p storing vl %p from pm %p\n",
9462 bpm,
9463 pm->vl,
9464 pm);
9465 bpm->logging_uuid = logging_uuid_gen++;
9466 bpm->vl = pm->vl;
9467 bpm->frag_parent = pm;
9468 // Why was this needed?
9469 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
9470 bpm->timeout = pm->timeout;
9471 bpm->pmt = PMT_RELIABILITY_BOX;
9472 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
9473 set_pending_message_uuid (bpm);
9474 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
9475 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
9476 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
9477
9478 rbox.ack_uuid = pa->ack_uuid;
9479 msg = (char *) &bpm[1];
9480 memcpy (msg, &rbox, sizeof(rbox));
9481 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
9482 pm->bpm = bpm;
9483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9484 "Preparing reliability box for message <%llu> of size %d (%d) to %s on queue %s\n",
9485 pm->logging_uuid,
9486 pm->bytes_msg,
9487 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
9488 GNUNET_i2s (&pm->vl->target),
9489 queue->address);
9490 return bpm;
9491}
9492
9493
9494static void
9495reorder_root_pm (struct PendingMessage *pm,
9496 struct GNUNET_TIME_Absolute next_attempt)
9497{
9498 struct VirtualLink *vl = pm->vl;
9499 struct PendingMessage *pos;
9500
9501 /* re-insert sort in neighbour list */
9502 GNUNET_CONTAINER_MDLL_remove (vl,
9503 vl->pending_msg_head,
9504 vl->pending_msg_tail,
9505 pm);
9506 pos = vl->pending_msg_tail;
9507 while ((NULL != pos) &&
9508 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9509 pos = pos->prev_vl;
9510 GNUNET_CONTAINER_MDLL_insert_after (vl,
9511 vl->pending_msg_head,
9512 vl->pending_msg_tail,
9513 pos,
9514 pm);
9515}
9516
9517
9518/**
9519 * Change the value of the `next_attempt` field of @a pm
9520 * to @a next_attempt and re-order @a pm in the transmission
9521 * list as required by the new timestamp.
9522 *
9523 * @param pm a pending message to update
9524 * @param next_attempt timestamp to use
9525 */
9526static void
9527update_pm_next_attempt (struct PendingMessage *pm,
9528 struct GNUNET_TIME_Absolute next_attempt)
9529{
9530
9531 // TODO Do we really need a next_attempt value for PendingMessage other than the root Pending Message?
9532 pm->next_attempt = next_attempt;
9533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9534 "Next attempt for message <%llu> set to %s\n",
9535 pm->logging_uuid,
9536 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
9537
9538 if (NULL == pm->frag_parent)
9539 {
9540 reorder_root_pm (pm, next_attempt);
9541 }
9542 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))
9543 {
9544 struct PendingMessage *root = pm->frag_parent;
9545
9546 while (NULL != root->frag_parent)
9547 root = root->frag_parent;
9548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9549 "Next attempt for root message <%llu> set to %s\n",
9550 root->logging_uuid,
9551 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
9552 root->next_attempt = next_attempt;
9553 reorder_root_pm (root, next_attempt);
9554 }
9555 else
9556 {
9557 /* re-insert sort in fragment list */
9558 struct PendingMessage *fp = pm->frag_parent;
9559 struct PendingMessage *pos;
9560
9561 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
9562 pos = fp->tail_frag;
9563 while ((NULL != pos) &&
9564 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9565 pos = pos->prev_frag;
9566 GNUNET_CONTAINER_MDLL_insert_after (frag,
9567 fp->head_frag,
9568 fp->tail_frag,
9569 pos,
9570 pm);
9571 if (NULL == pos)
9572 {
9573 pos = fp;
9574 // Get the root pm
9575 while (NULL != pos->frag_parent)
9576 pos = pos->frag_parent;
9577 pos->next_attempt = next_attempt;
9578 reorder_root_pm (pos, next_attempt);
9579 }
9580 }
9581}
9582
9583
9584/**
9585 * Context for #select_best_pending_from_link().
9586 */
9587struct PendingMessageScoreContext
9588{
9589 /**
9590 * Set to the best message that was found, NULL for none.
9591 */
9592 struct PendingMessage *best;
9593
9594 /**
9595 * DVH that @e best should take, or NULL for direct transmission.
9596 */
9597 struct DistanceVectorHop *dvh;
9598
9599 /**
9600 * What is the estimated total overhead for this message?
9601 */
9602 size_t real_overhead;
9603
9604 /**
9605 * Number of pending messages we seriously considered this time.
9606 */
9607 unsigned int consideration_counter;
9608
9609 /**
9610 * Did we have to fragment?
9611 */
9612 int frag;
9613
9614 /**
9615 * Did we have to reliability box?
9616 */
9617 int relb;
9618
9619 /**
9620 * There are pending messages, but it was to early to send one of them.
9621 */
9622 int to_early;
9623
9624 /**
9625 * When will we try to transmit the message again for which it was to early to retry.
9626 */
9627 struct GNUNET_TIME_Relative to_early_retry_delay;
9628};
9629
9630
9631/**
9632 * Select the best pending message from @a vl for transmission
9633 * via @a queue.
9634 *
9635 * @param[in,out] sc best message so far (NULL for none), plus scoring data
9636 * @param queue the queue that will be used for transmission
9637 * @param vl the virtual link providing the messages
9638 * @param dvh path we are currently considering, or NULL for none
9639 * @param overhead number of bytes of overhead to be expected
9640 * from DV encapsulation (0 for without DV)
9641 */
9642static void
9643select_best_pending_from_link (struct PendingMessageScoreContext *sc,
9644 struct Queue *queue,
9645 struct VirtualLink *vl,
9646 struct DistanceVectorHop *dvh,
9647 size_t overhead)
9648{
9649 struct GNUNET_TIME_Absolute now;
9650
9651 now = GNUNET_TIME_absolute_get ();
9652 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
9653 pos = pos->next_vl)
9654 {
9655 size_t real_overhead = overhead;
9656 int frag;
9657 int relb;
9658
9659 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
9660 {
9661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9662 "DV messages must not be DV-routed to next hop!\n");
9663 continue; /* DV messages must not be DV-routed to next hop! */
9664 }
9665 if (pos->next_attempt.abs_value_us > now.abs_value_us)
9666 {
9667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9668 "too early for all messages, they are sorted by next_attempt\n");
9669 sc->to_early = GNUNET_YES;
9670 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
9671 pos->next_attempt);
9672
9673 break; /* too early for all messages, they are sorted by next_attempt */
9674 }
9675 sc->to_early = GNUNET_NO;
9676 if (NULL != pos->qe)
9677 {
9678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9679 "not eligible\n");
9680 continue; /* not eligible */
9681 }
9682 sc->consideration_counter++;
9683 /* determine if we have to fragment, if so add fragmentation
9684 overhead! */
9685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9686 "check %llu for sc->best\n",
9687 pos->logging_uuid);
9688 frag = GNUNET_NO;
9689 if (((0 != queue->mtu) &&
9690 (pos->bytes_msg + real_overhead > queue->mtu)) ||
9691 (pos->bytes_msg > UINT16_MAX - sizeof(struct
9692 GNUNET_TRANSPORT_SendMessageTo))
9693 ||
9694 (NULL != pos->head_frag /* fragments already exist, should
9695 respect that even if MTU is UINT16_MAX for
9696 this queue */))
9697 {
9698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9699 "fragment msg with size %u, realoverhead is %lu\n",
9700 pos->bytes_msg,
9701 real_overhead);
9702 frag = GNUNET_YES;
9703 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
9704 {
9705 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
9706 header without the ACK UUID when using a *reliable* channel! */
9707 }
9708 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9709 }
9710 /* determine if we have to reliability-box, if so add reliability box
9711 overhead */
9712 relb = GNUNET_NO;
9713 if ((GNUNET_NO == frag) &&
9714 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
9715 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
9716 {
9717 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
9718
9719 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
9720 {
9721 frag = GNUNET_YES;
9722 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9723 }
9724 else
9725 {
9726 relb = GNUNET_YES;
9727 }
9728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9729 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
9730 pos->bytes_msg,
9731 real_overhead,
9732 queue->mtu,
9733 frag,
9734 relb);
9735 }
9736
9737 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
9738 message would beat it! */
9739 if (NULL != sc->best)
9740 {
9741 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
9742 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
9743 experimentally validated. There may be some huge potential for
9744 improvement here. Also, we right now only compare how well the
9745 given message fits _this_ queue, and do not consider how well other
9746 queues might suit the message. Taking other queues into consideration
9747 may further improve the result, but could also be expensive
9748 in terms of CPU time. */
9749 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
9750 long long pm_score = frag * 40 + relb * 20 + real_overhead;
9751 long long time_delta =
9752 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
9753 / 1000LL;
9754
9755 /* "time_delta" considers which message has been 'ready' for transmission
9756 for longer, if a message has a preference for low latency, increase
9757 the weight of the time_delta by 10x if it is favorable for that message */
9758 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9759 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
9760 time_delta *= 10; /* increase weight (always, both are low latency) */
9761 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9762 (time_delta > 0))
9763 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
9764 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9765 (time_delta < 0))
9766 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
9767 if (0 != queue->mtu)
9768 {
9769 /* Grant bonus if we are below MTU, larger bonus the closer we will
9770 be to the MTU */
9771 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
9772 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
9773 if (queue->mtu > real_overhead + pos->bytes_msg)
9774 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
9775 }
9776 if (sc_score + time_delta > pm_score)
9777 {
9778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9779 "sc_score of %llu larger, keep sc->best %llu\n",
9780 pos->logging_uuid,
9781 sc->best->logging_uuid);
9782 continue; /* sc_score larger, keep sc->best */
9783 }
9784 }
9785 sc->best = pos;
9786 sc->dvh = dvh;
9787 sc->frag = frag;
9788 sc->relb = relb;
9789 sc->real_overhead = real_overhead;
9790 }
9791}
9792
9793
9794/**
9795 * Function to call to further operate on the now DV encapsulated
9796 * message @a hdr, forwarding it via @a next_hop under respect of
9797 * @a options.
9798 *
9799 * @param cls a `struct PendingMessageScoreContext`
9800 * @param next_hop next hop of the DV path
9801 * @param hdr encapsulated message, technically a `struct TransportDVBoxMessage`
9802 * @param options options of the original message
9803 */
9804static void
9805extract_box_cb (void *cls,
9806 struct Neighbour *next_hop,
9807 const struct GNUNET_MessageHeader *hdr,
9808 enum RouteMessageOptions options)
9809{
9810 struct PendingMessageScoreContext *sc = cls;
9811 struct PendingMessage *pm = sc->best;
9812 struct PendingMessage *bpm;
9813 uint16_t bsize = ntohs (hdr->size);
9814
9815 GNUNET_assert (NULL == pm->bpm);
9816 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
9817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9818 "5 created pm %p storing vl %p from pm %p\n",
9819 bpm,
9820 pm->vl,
9821 pm);
9822 bpm->logging_uuid = logging_uuid_gen++;
9823 bpm->pmt = PMT_DV_BOX;
9824 bpm->vl = pm->vl;
9825 bpm->timeout = pm->timeout;
9826 bpm->bytes_msg = bsize;
9827 bpm->frag_parent = pm;
9828 set_pending_message_uuid (bpm);
9829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9830 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
9831 bpm->logging_uuid,
9832 pm->logging_uuid,
9833 GNUNET_i2s (&next_hop->pid));
9834 memcpy (&bpm[1], hdr, bsize);
9835 pm->bpm = bpm;
9836}
9837
9838
9839/**
9840 * We believe we are ready to transmit a `struct PendingMessage` on a
9841 * queue, the big question is which one! We need to see if there is
9842 * one pending that is allowed by flow control and congestion control
9843 * and (ideally) matches our queue's performance profile.
9844 *
9845 * If such a message is found, we give the message to the communicator
9846 * for transmission (updating the tracker, and re-scheduling ourselves
9847 * if applicable).
9848 *
9849 * If no such message is found, the queue's `idle` field must be set
9850 * to #GNUNET_YES.
9851 *
9852 * @param cls the `struct Queue` to process transmissions for
9853 */
9854static void
9855transmit_on_queue (void *cls)
9856{
9857 struct Queue *queue = cls;
9858 struct Neighbour *n = queue->neighbour;
9859 struct PendingMessageScoreContext sc;
9860 struct PendingMessage *pm;
9861
9862 queue->transmit_task = NULL;
9863 if (NULL == n->vl)
9864 {
9865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9866 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
9867 GNUNET_i2s (&n->pid),
9868 queue->address);
9869 queue->idle = GNUNET_YES;
9870 return;
9871 }
9872 memset (&sc, 0, sizeof(sc));
9873 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
9874 if (NULL == sc.best)
9875 {
9876 /* Also look at DVH that have the n as first hop! */
9877 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
9878 dvh = dvh->next_neighbour)
9879 {
9880 select_best_pending_from_link (&sc,
9881 queue,
9882 dvh->dv->vl,
9883 dvh,
9884 sizeof(struct GNUNET_PeerIdentity)
9885 * (1 + dvh->distance)
9886 + sizeof(struct TransportDVBoxMessage)
9887 + sizeof(struct TransportDVBoxPayloadP));
9888 }
9889 }
9890 if (NULL == sc.best)
9891 {
9892 /* no message pending, nothing to do here! */
9893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9894 "No pending messages, queue `%s' to %s now idle\n",
9895 queue->address,
9896 GNUNET_i2s (&n->pid));
9897 if (GNUNET_YES == sc.to_early)
9898 schedule_transmit_on_queue (sc.to_early_retry_delay,
9899 queue,
9900 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9901 queue->idle = GNUNET_YES;
9902 return;
9903 }
9904 /* There is a message pending, we are certainly not idle */
9905 queue->idle = GNUNET_NO;
9906
9907 /* Given selection in `sc`, do transmission */
9908 pm = sc.best;
9909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9910 "Selected message <%llu>\n",
9911 pm->logging_uuid);
9912 if (NULL != sc.dvh)
9913 {
9914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9915 "Is this %u a DV box?\n",
9916 pm->pmt);
9917 GNUNET_assert (PMT_DV_BOX != pm->pmt);
9918 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
9919 {
9920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9921 "Discard old box, because we have a new DV path.\n");
9922 free_pending_message (sc.best->bpm);
9923 sc.best->bpm = NULL;
9924 }
9925
9926 if (NULL == sc.best->bpm)
9927 {
9928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9929 "encapsulate_for_dv 2\n");
9930 encapsulate_for_dv (sc.dvh->dv,
9931 1,
9932 &sc.dvh,
9933 (const struct GNUNET_MessageHeader *) &sc.best[1],
9934 &extract_box_cb,
9935 &sc,
9936 RMO_NONE,
9937 GNUNET_NO);
9938 GNUNET_assert (NULL != sc.best->bpm);
9939 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9940 "%lu %lu %lu %lu %u\n",
9941 sizeof(struct GNUNET_PeerIdentity),
9942 sizeof(struct TransportDVBoxMessage),
9943 sizeof(struct TransportDVBoxPayloadP),
9944 sizeof(struct TransportFragmentBoxMessage),
9945 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
9946 sc.best->bpm->used_dvh = sc.dvh;
9947 }
9948 pm = sc.best->bpm;
9949 }
9950 if (GNUNET_YES == sc.frag)
9951 {
9952 pm = fragment_message (queue, sc.dvh, pm);
9953 if (NULL == pm)
9954 {
9955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9956 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
9957 queue->address,
9958 GNUNET_i2s (&n->pid),
9959 sc.best->logging_uuid);
9960 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9961 queue,
9962 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9963 return;
9964 }
9965 }
9966 else if (GNUNET_YES == sc.relb)
9967 {
9968 pm = reliability_box_message (queue, sc.dvh, pm);
9969 if (NULL == pm)
9970 {
9971 /* Reliability boxing failed, try next message... */
9972 GNUNET_log (
9973 GNUNET_ERROR_TYPE_DEBUG,
9974 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
9975 queue->address,
9976 GNUNET_i2s (&n->pid),
9977 sc.best->logging_uuid);
9978 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9979 queue,
9980 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9981 return;
9982 }
9983 }
9984
9985 /* Pass 'pm' for transission to the communicator */
9986 GNUNET_log (
9987 GNUNET_ERROR_TYPE_DEBUG,
9988 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
9989 pm->logging_uuid,
9990 queue->address,
9991 GNUNET_i2s (&n->pid),
9992 sc.consideration_counter);
9993
9994 /* Flow control: increment amount of traffic sent; if we are routing
9995 via DV (and thus the ultimate target of the pending message is for
9996 a different virtual link than the one of the queue), then we need
9997 to use up not only the window of the direct link but also the
9998 flow control window for the DV link! */
9999 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
10000
10001 if (pm->vl != queue->neighbour->vl)
10002 {
10003 /* If the virtual link of the queue differs, this better be distance
10004 vector routing! */
10005 GNUNET_assert (NULL != sc.dvh);
10006 /* If we do distance vector routing, we better not do this for a
10007 message that was itself DV-routed */
10008 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
10009 /* We use the size of the unboxed message here, to avoid counting
10010 the DV-Box header which is eaten up on the way by intermediaries */
10011 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
10012 }
10013 else
10014 {
10015 GNUNET_assert (NULL == sc.dvh);
10016 }
10017
10018 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
10019
10020 /* Check if this transmission somehow conclusively finished handing 'pm'
10021 even without any explicit ACKs */
10022 if ((PMT_CORE == pm->pmt) ||
10023 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
10024 {
10025 completed_pending_message (pm);
10026 }
10027 else
10028 {
10029 struct GNUNET_TIME_Relative wait_duration;
10030
10031 /* Message not finished, waiting for acknowledgement.
10032 Update time by which we might retransmit 's' based on queue
10033 characteristics (i.e. RTT); it takes one RTT for the message to
10034 arrive and the ACK to come back in the best case; but the other
10035 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
10036 retransmitting.
10037
10038 OPTIMIZE: Note that in the future this heuristic should likely
10039 be improved further (measure RTT stability, consider message
10040 urgency and size when delaying ACKs, etc.) */
10041
10042 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
10043 queue->pd.aged_rtt.rel_value_us)
10044 wait_duration = queue->pd.aged_rtt;
10045 else
10046 wait_duration = DEFAULT_ACK_WAIT_DURATION;
10047 struct GNUNET_TIME_Absolute next = GNUNET_TIME_relative_to_absolute (
10048 GNUNET_TIME_relative_multiply (
10049 wait_duration, 4));
10050 struct GNUNET_TIME_Relative plus = GNUNET_TIME_relative_multiply (
10051 wait_duration, 4);
10052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10053 "Waiting %s (%s) for ACK until %s\n",
10054 GNUNET_STRINGS_relative_time_to_string (
10055 GNUNET_TIME_relative_multiply (
10056 queue->pd.aged_rtt, 4), GNUNET_NO),
10057 GNUNET_STRINGS_relative_time_to_string (plus, GNUNET_YES),
10058 GNUNET_STRINGS_absolute_time_to_string (next));
10059 update_pm_next_attempt (pm,
10060 GNUNET_TIME_relative_to_absolute (
10061 GNUNET_TIME_relative_multiply (wait_duration,
10062 4)));
10063 }
10064 /* finally, re-schedule queue transmission task itself */
10065 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10066 queue,
10067 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10068}
10069
10070
10071/**
10072 * Queue to a peer went down. Process the request.
10073 *
10074 * @param cls the client
10075 * @param dqm the send message that was sent
10076 */
10077static void
10078handle_del_queue_message (void *cls,
10079 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
10080{
10081 struct TransportClient *tc = cls;
10082
10083 if (CT_COMMUNICATOR != tc->type)
10084 {
10085 GNUNET_break (0);
10086 GNUNET_SERVICE_client_drop (tc->client);
10087 return;
10088 }
10089 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
10090 queue = queue->next_client)
10091 {
10092 struct Neighbour *neighbour = queue->neighbour;
10093
10094 if ((dqm->qid != queue->qid) ||
10095 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
10096 continue;
10097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10098 "Dropped queue %s to peer %s\n",
10099 queue->address,
10100 GNUNET_i2s (&neighbour->pid));
10101 free_queue (queue);
10102 GNUNET_SERVICE_client_continue (tc->client);
10103 return;
10104 }
10105 GNUNET_break (0);
10106 GNUNET_SERVICE_client_drop (tc->client);
10107}
10108
10109
10110/**
10111 * Message was transmitted. Process the request.
10112 *
10113 * @param cls the client
10114 * @param sma the send message that was sent
10115 */
10116static void
10117handle_send_message_ack (void *cls,
10118 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
10119{
10120 struct TransportClient *tc = cls;
10121 struct QueueEntry *qe;
10122 struct PendingMessage *pm;
10123
10124 if (CT_COMMUNICATOR != tc->type)
10125 {
10126 GNUNET_break (0);
10127 GNUNET_SERVICE_client_drop (tc->client);
10128 return;
10129 }
10130
10131 /* find our queue entry matching the ACK */
10132 qe = NULL;
10133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10134 "Looking for queue for PID %s\n",
10135 GNUNET_i2s (&sma->receiver));
10136 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
10137 queue = queue->next_client)
10138 {
10139 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
10140 continue;
10141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10142 "Found PID %s\n",
10143 GNUNET_i2s (&queue->neighbour->pid));
10144
10145
10146 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
10147 qep = qep->next)
10148 {
10149 if (qep->mid != sma->mid)
10150 continue;
10151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10152 "QueueEntry MID: %llu on queue QID: %llu, Ack MID: %llu\n",
10153 (unsigned long long) qep->mid,
10154 (unsigned long long) queue->qid,
10155 (unsigned long long) sma->mid);
10156 qe = qep;
10157 if ((NULL != qe->pm) && (qe->pm->qe != qe))
10158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10159 "For pending message %llu we had retransmissions.\n",
10160 qe->pm->logging_uuid);
10161 break;
10162 }
10163 }
10164 if (NULL == qe)
10165 {
10166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10167 "No QueueEntry found for Ack MID %llu\n",
10168 (unsigned long long) sma->mid);
10169 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
10170 /* this should never happen */
10171 /*GNUNET_break (0);
10172 GNUNET_SERVICE_client_drop (tc->client);*/
10173 GNUNET_SERVICE_client_continue (tc->client);
10174 return;
10175 }
10176 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
10177 qe->queue->queue_tail,
10178 qe);
10179 qe->queue->queue_length--;
10180 tc->details.communicator.total_queue_length--;
10181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10182 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
10183 qe->queue->address,
10184 GNUNET_i2s (&qe->queue->neighbour->pid),
10185 qe->queue->queue_length,
10186 tc->details.communicator.total_queue_length);
10187 GNUNET_SERVICE_client_continue (tc->client);
10188
10189 /* if applicable, resume transmissions that waited on ACK */
10190 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
10191 tc->details.communicator.total_queue_length)
10192 {
10193 /* Communicator dropped below threshold, resume all queues
10194 incident with this client! */
10195 GNUNET_STATISTICS_update (
10196 GST_stats,
10197 "# Transmission throttled due to communicator queue limit",
10198 -1,
10199 GNUNET_NO);
10200 for (struct Queue *queue = tc->details.communicator.queue_head;
10201 NULL != queue;
10202 queue = queue->next_client)
10203 {
10204 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10205 queue,
10206 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10207 }
10208 }
10209 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
10210 {
10211 /* queue dropped below threshold; only resume this one queue */
10212 GNUNET_STATISTICS_update (GST_stats,
10213 "# Transmission throttled due to queue queue limit",
10214 -1,
10215 GNUNET_NO);
10216 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10217 qe->queue,
10218 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10219 }
10220 else if (1 == qe->queue->q_capacity)
10221 {
10222 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
10223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10224 "Transmission rescheduled due to communicator message queue with qid %u has capacity %lu.\n",
10225 qe->queue->qid,
10226 qe->queue->q_capacity);
10227 /* message queue has capacity; only resume this one queue */
10228 /* queue dropped below threshold; only resume this one queue */
10229 GNUNET_STATISTICS_update (GST_stats,
10230 "# Transmission throttled due to message queue capacity",
10231 -1,
10232 GNUNET_NO);
10233 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10234 qe->queue,
10235 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10236 }
10237
10238 if (NULL != (pm = qe->pm))
10239 {
10240 struct VirtualLink *vl;
10241
10242 // GNUNET_assert (qe == pm->qe);
10243 pm->qe = NULL;
10244 /* If waiting for this communicator may have blocked transmission
10245 of pm on other queues for this neighbour, force schedule
10246 transmit on queue for queues of the neighbour */
10247 if (NULL == pm->frag_parent)
10248 {
10249 vl = pm->vl;
10250 if ((NULL != vl) &&
10251 (NULL != vl->pending_msg_head) &&
10252 (vl->pending_msg_head == pm))
10253 check_vl_transmission (vl);
10254 }
10255 }
10256 GNUNET_free (qe);
10257}
10258
10259
10260/**
10261 * Iterator telling new MONITOR client about all existing
10262 * queues to peers.
10263 *
10264 * @param cls the new `struct TransportClient`
10265 * @param pid a connected peer
10266 * @param value the `struct Neighbour` with more information
10267 * @return #GNUNET_OK (continue to iterate)
10268 */
10269static int
10270notify_client_queues (void *cls,
10271 const struct GNUNET_PeerIdentity *pid,
10272 void *value)
10273{
10274 struct TransportClient *tc = cls;
10275 struct Neighbour *neighbour = value;
10276
10277 GNUNET_assert (CT_MONITOR == tc->type);
10278 for (struct Queue *q = neighbour->queue_head; NULL != q;
10279 q = q->next_neighbour)
10280 {
10281 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
10282 .cs = q->cs,
10283 .num_msg_pending = q->num_msg_pending,
10284 .num_bytes_pending = q->num_bytes_pending };
10285
10286 notify_monitor (tc, pid, q->address, q->nt, &me);
10287 }
10288 return GNUNET_OK;
10289}
10290
10291
10292/**
10293 * Initialize a monitor client.
10294 *
10295 * @param cls the client
10296 * @param start the start message that was sent
10297 */
10298static void
10299handle_monitor_start (void *cls,
10300 const struct GNUNET_TRANSPORT_MonitorStart *start)
10301{
10302 struct TransportClient *tc = cls;
10303
10304 if (CT_NONE != tc->type)
10305 {
10306 GNUNET_break (0);
10307 GNUNET_SERVICE_client_drop (tc->client);
10308 return;
10309 }
10310 tc->type = CT_MONITOR;
10311 tc->details.monitor.peer = start->peer;
10312 tc->details.monitor.one_shot = ntohl (start->one_shot);
10313 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &notify_client_queues, tc);
10314 GNUNET_SERVICE_client_mark_monitor (tc->client);
10315 GNUNET_SERVICE_client_continue (tc->client);
10316}
10317
10318
10319/**
10320 * Find transport client providing communication service
10321 * for the protocol @a prefix.
10322 *
10323 * @param prefix communicator name
10324 * @return NULL if no such transport client is available
10325 */
10326static struct TransportClient *
10327lookup_communicator (const char *prefix)
10328{
10329 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
10330 {
10331 if (CT_COMMUNICATOR != tc->type)
10332 continue;
10333 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
10334 return tc;
10335 }
10336 GNUNET_log (
10337 GNUNET_ERROR_TYPE_WARNING,
10338 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
10339 prefix);
10340 return NULL;
10341}
10342
10343
10344/**
10345 * Signature of a function called with a communicator @a address of a peer
10346 * @a pid that an application wants us to connect to.
10347 *
10348 * @param pid target peer
10349 * @param address the address to try
10350 */
10351static void
10352suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
10353{
10354 static uint32_t idgen;
10355 struct TransportClient *tc;
10356 char *prefix;
10357 struct GNUNET_TRANSPORT_CreateQueue *cqm;
10358 struct GNUNET_MQ_Envelope *env;
10359 size_t alen;
10360
10361 prefix = GNUNET_HELLO_address_to_prefix (address);
10362 if (NULL == prefix)
10363 {
10364 GNUNET_break (0); /* We got an invalid address!? */
10365 return;
10366 }
10367 tc = lookup_communicator (prefix);
10368 if (NULL == tc)
10369 {
10370 GNUNET_STATISTICS_update (GST_stats,
10371 "# Suggestions ignored due to missing communicator",
10372 1,
10373 GNUNET_NO);
10374 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10375 "Cannot connect to %s at `%s', no matching communicator present\n",
10376 GNUNET_i2s (pid),
10377 address);
10378 GNUNET_free (prefix);
10379 return;
10380 }
10381 /* forward suggestion for queue creation to communicator */
10382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10383 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
10384 (unsigned int) idgen,
10385 prefix,
10386 GNUNET_i2s (pid),
10387 address);
10388 GNUNET_free (prefix);
10389 alen = strlen (address) + 1;
10390 env =
10391 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
10392 cqm->request_id = htonl (idgen++);
10393 cqm->receiver = *pid;
10394 memcpy (&cqm[1], address, alen);
10395 GNUNET_MQ_send (tc->mq, env);
10396}
10397
10398
10399/**
10400 * The queue @a q (which matches the peer and address in @a vs) is
10401 * ready for queueing. We should now queue the validation request.
10402 *
10403 * @param q queue to send on
10404 * @param vs state to derive validation challenge from
10405 */
10406static void
10407validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
10408{
10409 struct TransportValidationChallengeMessage tvc;
10410
10411 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
10412 tvc.header.type =
10413 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
10414 tvc.header.size = htons (sizeof(tvc));
10415 tvc.reserved = htonl (0);
10416 tvc.challenge = vs->challenge;
10417 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
10418 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10419 "Sending address validation challenge %s to %s\n",
10420 GNUNET_sh2s (&tvc.challenge.value),
10421 GNUNET_i2s (&q->neighbour->pid));
10422 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
10423}
10424
10425
10426/**
10427 * Task run periodically to validate some address based on #validation_heap.
10428 *
10429 * @param cls NULL
10430 */
10431static void
10432validation_start_cb (void *cls)
10433{
10434 struct ValidationState *vs;
10435 struct Queue *q;
10436
10437 (void) cls;
10438 validation_task = NULL;
10439 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10440 /* drop validations past their expiration */
10441 while (
10442 (NULL != vs) &&
10443 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
10444 {
10445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10446 "Validation response %s cleaned up\n",
10447 GNUNET_sh2s (&vs->challenge.value));
10448 free_validation_state (vs);
10449 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10450 }
10451 if (NULL == vs)
10452 {
10453 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10454 "Address validation task not scheduled anymore, nothing to do\n");
10455 return; /* woopsie, no more addresses known, should only
10456 happen if we're really a lonely peer */
10457 }
10458 q = find_queue (&vs->pid, vs->address);
10459 if (NULL == q)
10460 {
10461 vs->awaiting_queue = GNUNET_YES;
10462 suggest_to_connect (&vs->pid, vs->address);
10463 }
10464 else
10465 validation_transmit_on_queue (q, vs);
10466 /* Finally, reschedule next attempt */
10467 vs->challenge_backoff =
10468 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
10469 MAX_VALIDATION_CHALLENGE_FREQ);
10470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10471 "Address validation task will run again in %s\n",
10472 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
10473 GNUNET_YES));
10474 update_next_challenge_time (vs,
10475 GNUNET_TIME_relative_to_absolute (
10476 vs->challenge_backoff));
10477}
10478
10479
10480/**
10481 * Closure for #check_connection_quality.
10482 */
10483struct QueueQualityContext
10484{
10485 /**
10486 * Set to the @e k'th queue encountered.
10487 */
10488 struct Queue *q;
10489
10490 /**
10491 * Set to the number of quality queues encountered.
10492 */
10493 unsigned int quality_count;
10494
10495 /**
10496 * Set to the total number of queues encountered.
10497 */
10498 unsigned int num_queues;
10499
10500 /**
10501 * Decremented for each queue, for selection of the
10502 * k-th queue in @e q.
10503 */
10504 unsigned int k;
10505};
10506
10507
10508/**
10509 * Check whether any queue to the given neighbour is
10510 * of a good "quality" and if so, increment the counter.
10511 * Also counts the total number of queues, and returns
10512 * the k-th queue found.
10513 *
10514 * @param cls a `struct QueueQualityContext *` with counters
10515 * @param pid peer this is about
10516 * @param value a `struct Neighbour`
10517 * @return #GNUNET_OK (continue to iterate)
10518 */
10519static int
10520check_connection_quality (void *cls,
10521 const struct GNUNET_PeerIdentity *pid,
10522 void *value)
10523{
10524 struct QueueQualityContext *ctx = cls;
10525 struct Neighbour *n = value;
10526 int do_inc;
10527
10528 (void) pid;
10529 do_inc = GNUNET_NO;
10530 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10531 {
10532 ctx->num_queues++;
10533 if (0 == ctx->k--)
10534 ctx->q = q;
10535 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
10536 statistics and consider those as well here? */
10537 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
10538 do_inc = GNUNET_YES;
10539 }
10540 if (GNUNET_YES == do_inc)
10541 ctx->quality_count++;
10542 return GNUNET_OK;
10543}
10544
10545
10546/**
10547 * Task run when we CONSIDER initiating a DV learn
10548 * process. We first check that sending out a message is
10549 * even possible (queues exist), then that it is desirable
10550 * (if not, reschedule the task for later), and finally
10551 * we may then begin the job. If there are too many
10552 * entries in the #dvlearn_map, we purge the oldest entry
10553 * using #lle_tail.
10554 *
10555 * @param cls NULL
10556 */
10557static void
10558start_dv_learn (void *cls)
10559{
10560 struct LearnLaunchEntry *lle;
10561 struct QueueQualityContext qqc;
10562 struct TransportDVLearnMessage dvl;
10563
10564 (void) cls;
10565 dvlearn_task = NULL;
10566 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
10567 return; /* lost all connectivity, cannot do learning */
10568 qqc.quality_count = 0;
10569 qqc.num_queues = 0;
10570 qqc.k = GNUNET_CONTAINER_multipeermap_size (neighbours);
10571 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10572 &check_connection_quality,
10573 &qqc);
10574 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
10575 {
10576 struct GNUNET_TIME_Relative delay;
10577 unsigned int factor;
10578
10579 /* scale our retries by how far we are above the threshold */
10580 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
10581 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
10582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10583 "At connection quality %u, will launch DV learn in %s\n",
10584 qqc.quality_count,
10585 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
10586 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
10587 return;
10588 }
10589 /* remove old entries in #dvlearn_map if it has grown too big */
10590 while (MAX_DV_LEARN_PENDING <=
10591 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
10592 {
10593 lle = lle_tail;
10594 GNUNET_assert (GNUNET_YES ==
10595 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
10596 &lle->challenge.value,
10597 lle));
10598 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10599 GNUNET_free (lle);
10600 }
10601 /* setup data structure for learning */
10602 lle = GNUNET_new (struct LearnLaunchEntry);
10603 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
10604 &lle->challenge,
10605 sizeof(lle->challenge));
10606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10607 "Starting launch DV learn with challenge %s\n",
10608 GNUNET_sh2s (&lle->challenge.value));
10609 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
10610 GNUNET_break (GNUNET_YES ==
10611 GNUNET_CONTAINER_multishortmap_put (
10612 dvlearn_map,
10613 &lle->challenge.value,
10614 lle,
10615 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10616 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
10617 dvl.header.size = htons (sizeof(dvl));
10618 dvl.num_hops = htons (0);
10619 dvl.bidirectional = htons (0);
10620 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
10621 dvl.monotonic_time =
10622 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
10623 {
10624 struct DvInitPS dvip = {
10625 .purpose.purpose = htonl (
10626 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
10627 .purpose.size = htonl (sizeof(dvip)),
10628 .monotonic_time = dvl.monotonic_time,
10629 .challenge = lle->challenge
10630 };
10631
10632 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
10633 &dvip,
10634 &dvl.init_sig);
10635 }
10636 dvl.initiator = GST_my_identity;
10637 dvl.challenge = lle->challenge;
10638
10639 qqc.quality_count = 0;
10640 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
10641 qqc.num_queues = 0;
10642 qqc.q = NULL;
10643 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10644 &check_connection_quality,
10645 &qqc);
10646 GNUNET_assert (NULL != qqc.q);
10647
10648 /* Do this as close to transmission time as possible! */
10649 lle->launch_time = GNUNET_TIME_absolute_get ();
10650
10651 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
10652 /* reschedule this job, randomizing the time it runs (but no
10653 actual backoff!) */
10654 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
10655 DV_LEARN_BASE_FREQUENCY),
10656 &start_dv_learn,
10657 NULL);
10658}
10659
10660
10661/**
10662 * Get the IP address without the port number.
10663 *
10664 * @param address The string contains a communicator prefix, IP address and port
10665 * like this 'tcp-92.68.150.1:55452'.
10666 * @return String with IP address only.
10667 */
10668static char *
10669get_address_without_port (const char *address)
10670{
10671 const char *colon;
10672 char *colon_rest;
10673 size_t colon_rest_length;
10674 char *address_without_port;
10675
10676 colon = strchr (address,':');
10677 colon_rest = GNUNET_strndup (address, colon - address);
10678 colon_rest_length = strlen (colon_rest);
10679 address_without_port = GNUNET_strndup (&colon_rest[4], colon_rest_length - 4);
10680 GNUNET_free (colon_rest);
10681
10682 return address_without_port;
10683}
10684
10685/**
10686 * A new queue has been created, check if any address validation
10687 * requests have been waiting for it.
10688 *
10689 * @param cls a `struct Queue`
10690 * @param pid peer concerned (unused)
10691 * @param value a `struct ValidationState`
10692 * @return #GNUNET_NO if a match was found and we can stop looking
10693 */
10694static int
10695check_validation_request_pending (void *cls,
10696 const struct GNUNET_PeerIdentity *pid,
10697 void *value)
10698{
10699 struct Queue *q = cls;
10700 struct ValidationState *vs = value;
10701 char *address_without_port_vs;
10702 char *address_without_port_q;
10703 int success = GNUNET_YES;
10704
10705 address_without_port_vs = get_address_without_port (vs->address);
10706 address_without_port_q = get_address_without_port (q->address);
10707
10708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10709 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
10710 GNUNET_i2s (pid),
10711 address_without_port_vs,
10712 address_without_port_q);
10713 (void) pid;
10714 if ((GNUNET_YES == vs->awaiting_queue) &&
10715 (0 == strcmp (address_without_port_vs, address_without_port_q)))
10716 {
10717
10718 vs->awaiting_queue = GNUNET_NO;
10719 validation_transmit_on_queue (q, vs);
10720 success = GNUNET_NO;
10721 }
10722
10723 GNUNET_free (address_without_port_vs);
10724 GNUNET_free (address_without_port_q);
10725 return success;
10726}
10727
10728
10729/**
10730 * Function called with the monotonic time of a DV initiator
10731 * by PEERSTORE. Updates the time.
10732 *
10733 * @param cls a `struct Neighbour`
10734 * @param record the information found, NULL for the last call
10735 * @param emsg error message
10736 */
10737static void
10738neighbour_dv_monotime_cb (void *cls,
10739 const struct GNUNET_PEERSTORE_Record *record,
10740 const char *emsg)
10741{
10742 struct Neighbour *n = cls;
10743 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10744
10745 (void) emsg;
10746 if (NULL == record)
10747 {
10748 /* we're done with #neighbour_dv_monotime_cb() invocations,
10749 continue normal processing */
10750 n->get = NULL;
10751 n->dv_monotime_available = GNUNET_YES;
10752 return;
10753 }
10754 if (sizeof(*mtbe) != record->value_size)
10755 {
10756 GNUNET_break (0);
10757 return;
10758 }
10759 mtbe = record->value;
10760 n->last_dv_learn_monotime =
10761 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
10762 GNUNET_TIME_absolute_ntoh (*mtbe));
10763}
10764
10765
10766/**
10767 * New queue became available. Process the request.
10768 *
10769 * @param cls the client
10770 * @param aqm the send message that was sent
10771 */
10772static void
10773handle_add_queue_message (void *cls,
10774 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
10775{
10776 struct TransportClient *tc = cls;
10777 struct Queue *queue;
10778 struct Neighbour *neighbour;
10779 const char *addr;
10780 uint16_t addr_len;
10781
10782 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
10783 {
10784 /* MTU so small as to be useless for transmissions,
10785 required for #fragment_message()! */
10786 GNUNET_break_op (0);
10787 GNUNET_SERVICE_client_drop (tc->client);
10788 return;
10789 }
10790 /* This may simply be a queue update */
10791 for (queue = tc->details.communicator.queue_head;
10792 NULL != queue;
10793 queue = queue->next_client)
10794 {
10795 if (queue->qid != aqm->qid)
10796 continue;
10797 break;
10798 }
10799
10800 if (NULL != queue)
10801 {
10802 neighbour = queue->neighbour;
10803 }
10804 else
10805 {
10806 neighbour = lookup_neighbour (&aqm->receiver);
10807 if (NULL == neighbour)
10808 {
10809 neighbour = GNUNET_new (struct Neighbour);
10810 neighbour->pid = aqm->receiver;
10811 GNUNET_assert (GNUNET_OK ==
10812 GNUNET_CONTAINER_multipeermap_put (
10813 neighbours,
10814 &neighbour->pid,
10815 neighbour,
10816 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10817 neighbour->get =
10818 GNUNET_PEERSTORE_iterate (peerstore,
10819 "transport",
10820 &neighbour->pid,
10821 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
10822 &neighbour_dv_monotime_cb,
10823 neighbour);
10824 }
10825 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
10826 addr = (const char *) &aqm[1];
10827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10828 "New queue %s to %s available with QID %llu and q_len %lu and mtu %u\n",
10829 addr,
10830 GNUNET_i2s (&aqm->receiver),
10831 (unsigned long long) aqm->qid,
10832 GNUNET_ntohll (aqm->q_len),
10833 ntohl (aqm->mtu));
10834 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
10835 queue->tc = tc;
10836 queue->address = (const char *) &queue[1];
10837 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10838 queue->qid = aqm->qid;
10839 queue->neighbour = neighbour;
10840 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (aqm->q_len))
10841 queue->unlimited_length = GNUNET_YES;
10842 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
10843 memcpy (&queue[1], addr, addr_len);
10844 /* notify monitors about new queue */
10845 {
10846 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
10847
10848 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
10849 }
10850 GNUNET_CONTAINER_MDLL_insert (neighbour,
10851 neighbour->queue_head,
10852 neighbour->queue_tail,
10853 queue);
10854 GNUNET_CONTAINER_MDLL_insert (client,
10855 tc->details.communicator.queue_head,
10856 tc->details.communicator.queue_tail,
10857 queue);
10858
10859 }
10860 queue->mtu = ntohl (aqm->mtu);
10861 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
10862 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
10863 queue->idle = GNUNET_YES;
10864 /* check if valdiations are waiting for the queue */
10865 (void)
10866 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
10867 &aqm->receiver,
10868 &check_validation_request_pending,
10869 queue);
10870 /* look for traffic for this queue */
10871 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10872 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10873 /* might be our first queue, try launching DV learning */
10874 if (NULL == dvlearn_task)
10875 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
10876 GNUNET_SERVICE_client_continue (tc->client);
10877}
10878
10879
10880/**
10881 * @brief Handle updates to queues.
10882 *
10883 * @param cls the transport client.
10884 * @param msg Message struct.
10885 */
10886static void
10887handle_update_queue_message (void *cls,
10888 const struct
10889 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
10890{
10891 struct TransportClient *tc = cls;
10892 struct Queue *target_queue = NULL;
10893
10894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10895 "Received queue update message for %u with q_len %llu and mtu %u\n",
10896 msg->qid,
10897 (unsigned long long) GNUNET_ntohll (msg->q_len),
10898 ntohl (msg->mtu));
10899 for (target_queue = tc->details.communicator.queue_head;
10900 NULL != target_queue;
10901 target_queue = target_queue->next_client)
10902 {
10903 if (msg->qid == target_queue->qid)
10904 break;
10905 }
10906 if (NULL == target_queue)
10907 {
10908 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
10909 "Queue to update no longer exists! Discarding update.\n");
10910 return;
10911 }
10912
10913 target_queue->nt = msg->nt;
10914 target_queue->mtu = ntohl (msg->mtu);
10915 target_queue->cs = msg->cs;
10916 target_queue->priority = ntohl (msg->priority);
10917 /* The update message indicates how many messages
10918 * the queue should be able to handle.
10919 */
10920 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (msg->q_len))
10921 target_queue->unlimited_length = GNUNET_YES;
10922 else
10923 target_queue->unlimited_length = GNUNET_NO;
10924 target_queue->q_capacity = GNUNET_ntohll (msg->q_len);
10925 if (0 < target_queue->q_capacity)
10926 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10927 target_queue,
10928 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10929 GNUNET_SERVICE_client_continue (tc->client);
10930}
10931
10932
10933/**
10934 * Communicator tells us that our request to create a queue "worked", that
10935 * is setting up the queue is now in process.
10936 *
10937 * @param cls the `struct TransportClient`
10938 * @param cqr confirmation message
10939 */
10940static void
10941handle_queue_create_ok (void *cls,
10942 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10943{
10944 struct TransportClient *tc = cls;
10945
10946 if (CT_COMMUNICATOR != tc->type)
10947 {
10948 GNUNET_break (0);
10949 GNUNET_SERVICE_client_drop (tc->client);
10950 return;
10951 }
10952 GNUNET_STATISTICS_update (GST_stats,
10953 "# Suggestions succeeded at communicator",
10954 1,
10955 GNUNET_NO);
10956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10957 "Request #%u for communicator to create queue succeeded\n",
10958 (unsigned int) ntohs (cqr->request_id));
10959 GNUNET_SERVICE_client_continue (tc->client);
10960}
10961
10962
10963/**
10964 * Communicator tells us that our request to create a queue failed. This
10965 * usually indicates that the provided address is simply invalid or that the
10966 * communicator's resources are exhausted.
10967 *
10968 * @param cls the `struct TransportClient`
10969 * @param cqr failure message
10970 */
10971static void
10972handle_queue_create_fail (
10973 void *cls,
10974 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10975{
10976 struct TransportClient *tc = cls;
10977
10978 if (CT_COMMUNICATOR != tc->type)
10979 {
10980 GNUNET_break (0);
10981 GNUNET_SERVICE_client_drop (tc->client);
10982 return;
10983 }
10984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10985 "Request #%u for communicator to create queue failed\n",
10986 (unsigned int) ntohs (cqr->request_id));
10987 GNUNET_STATISTICS_update (GST_stats,
10988 "# Suggestions failed in queue creation at communicator",
10989 1,
10990 GNUNET_NO);
10991 GNUNET_SERVICE_client_continue (tc->client);
10992}
10993
10994
10995/**
10996 * We have received a `struct ExpressPreferenceMessage` from an application
10997 * client.
10998 *
10999 * @param cls handle to the client
11000 * @param msg the start message
11001 */
11002static void
11003handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
11004{
11005 struct TransportClient *tc = cls;
11006 struct PeerRequest *pr;
11007
11008 if (CT_APPLICATION != tc->type)
11009 {
11010 GNUNET_break (0);
11011 GNUNET_SERVICE_client_drop (tc->client);
11012 return;
11013 }
11014 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
11015 &msg->peer);
11016 if (NULL == pr)
11017 {
11018 GNUNET_break (0);
11019 GNUNET_SERVICE_client_drop (tc->client);
11020 return;
11021 }
11022 (void) stop_peer_request (tc, &pr->pid, pr);
11023 GNUNET_SERVICE_client_continue (tc->client);
11024}
11025
11026
11027/**
11028 * Function called by PEERSTORE for each matching record.
11029 *
11030 * @param cls closure, a `struct PeerRequest`
11031 * @param record peerstore record information
11032 * @param emsg error message, or NULL if no errors
11033 */
11034static void
11035handle_hello_for_client (void *cls,
11036 const struct GNUNET_PEERSTORE_Record *record,
11037 const char *emsg)
11038{
11039 struct PeerRequest *pr = cls;
11040 const char *val;
11041
11042 if (NULL != emsg)
11043 {
11044 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11045 "Got failure from PEERSTORE: %s\n",
11046 emsg);
11047 return;
11048 }
11049 val = record->value;
11050 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
11051 {
11052 GNUNET_break (0);
11053 return;
11054 }
11055 start_address_validation (&pr->pid, (const char *) record->value);
11056}
11057
11058
11059/**
11060 * We have received a `struct ExpressPreferenceMessage` from an application
11061 * client.
11062 *
11063 * @param cls handle to the client
11064 * @param msg the start message
11065 */
11066static void
11067handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
11068{
11069 struct TransportClient *tc = cls;
11070 struct PeerRequest *pr;
11071
11072 if (CT_NONE == tc->type)
11073 {
11074 tc->type = CT_APPLICATION;
11075 tc->details.application.requests =
11076 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
11077 }
11078 if (CT_APPLICATION != tc->type)
11079 {
11080 GNUNET_break (0);
11081 GNUNET_SERVICE_client_drop (tc->client);
11082 return;
11083 }
11084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11085 "Client suggested we talk to %s with preference %d at rate %u\n",
11086 GNUNET_i2s (&msg->peer),
11087 (int) ntohl (msg->pk),
11088 (int) ntohl (msg->bw.value__));
11089 pr = GNUNET_new (struct PeerRequest);
11090 pr->tc = tc;
11091 pr->pid = msg->peer;
11092 pr->bw = msg->bw;
11093 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
11094 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
11095 tc->details.application.requests,
11096 &pr->pid,
11097 pr,
11098 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
11099 {
11100 GNUNET_break (0);
11101 GNUNET_free (pr);
11102 GNUNET_SERVICE_client_drop (tc->client);
11103 return;
11104 }
11105 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
11106 "transport",
11107 &pr->pid,
11108 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
11109 &handle_hello_for_client,
11110 pr);
11111 GNUNET_SERVICE_client_continue (tc->client);
11112}
11113
11114
11115/**
11116 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
11117 * messages.
11118 *
11119 * @param cls a `struct TransportClient *`
11120 * @param m message to verify
11121 * @return #GNUNET_OK on success
11122 */
11123static int
11124check_request_hello_validation (void *cls,
11125 const struct RequestHelloValidationMessage *m)
11126{
11127 (void) cls;
11128 GNUNET_MQ_check_zero_termination (m);
11129 return GNUNET_OK;
11130}
11131
11132
11133/**
11134 * A client encountered an address of another peer. Consider validating it,
11135 * and if validation succeeds, persist it to PEERSTORE.
11136 *
11137 * @param cls a `struct TransportClient *`
11138 * @param m message to verify
11139 */
11140static void
11141handle_request_hello_validation (void *cls,
11142 const struct RequestHelloValidationMessage *m)
11143{
11144 struct TransportClient *tc = cls;
11145
11146 start_address_validation (&m->peer, (const char *) &m[1]);
11147 GNUNET_SERVICE_client_continue (tc->client);
11148}
11149
11150
11151/**
11152 * Free neighbour entry.
11153 *
11154 * @param cls NULL
11155 * @param pid unused
11156 * @param value a `struct Neighbour`
11157 * @return #GNUNET_OK (always)
11158 */
11159static int
11160free_neighbour_cb (void *cls,
11161 const struct GNUNET_PeerIdentity *pid,
11162 void *value)
11163{
11164 struct Neighbour *neighbour = value;
11165
11166 (void) cls;
11167 (void) pid;
11168 GNUNET_break (0); // should this ever happen?
11169 free_neighbour (neighbour);
11170
11171 return GNUNET_OK;
11172}
11173
11174
11175/**
11176 * Free DV route entry.
11177 *
11178 * @param cls NULL
11179 * @param pid unused
11180 * @param value a `struct DistanceVector`
11181 * @return #GNUNET_OK (always)
11182 */
11183static int
11184free_dv_routes_cb (void *cls,
11185 const struct GNUNET_PeerIdentity *pid,
11186 void *value)
11187{
11188 struct DistanceVector *dv = value;
11189
11190 (void) cls;
11191 (void) pid;
11192 free_dv_route (dv);
11193
11194 return GNUNET_OK;
11195}
11196
11197
11198/**
11199 * Free validation state.
11200 *
11201 * @param cls NULL
11202 * @param pid unused
11203 * @param value a `struct ValidationState`
11204 * @return #GNUNET_OK (always)
11205 */
11206static int
11207free_validation_state_cb (void *cls,
11208 const struct GNUNET_PeerIdentity *pid,
11209 void *value)
11210{
11211 struct ValidationState *vs = value;
11212
11213 (void) cls;
11214 (void) pid;
11215 free_validation_state (vs);
11216 return GNUNET_OK;
11217}
11218
11219
11220/**
11221 * Free pending acknowledgement.
11222 *
11223 * @param cls NULL
11224 * @param key unused
11225 * @param value a `struct PendingAcknowledgement`
11226 * @return #GNUNET_OK (always)
11227 */
11228static int
11229free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
11230{
11231 struct PendingAcknowledgement *pa = value;
11232
11233 (void) cls;
11234 (void) key;
11235 free_pending_acknowledgement (pa);
11236 return GNUNET_OK;
11237}
11238
11239
11240/**
11241 * Free acknowledgement cummulator.
11242 *
11243 * @param cls NULL
11244 * @param pid unused
11245 * @param value a `struct AcknowledgementCummulator`
11246 * @return #GNUNET_OK (always)
11247 */
11248static int
11249free_ack_cummulator_cb (void *cls,
11250 const struct GNUNET_PeerIdentity *pid,
11251 void *value)
11252{
11253 struct AcknowledgementCummulator *ac = value;
11254
11255 (void) cls;
11256 (void) pid;
11257 GNUNET_SCHEDULER_cancel (ac->task);
11258 GNUNET_free (ac);
11259 return GNUNET_OK;
11260}
11261
11262
11263/**
11264 * Function called when the service shuts down. Unloads our plugins
11265 * and cancels pending validations.
11266 *
11267 * @param cls closure, unused
11268 */
11269static void
11270do_shutdown (void *cls)
11271{
11272 struct LearnLaunchEntry *lle;
11273
11274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11275 "shutdown logic\n");
11276 (void) cls;
11277 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
11278 &free_neighbour_cb, NULL);
11279 if (NULL != validation_task)
11280 {
11281 GNUNET_SCHEDULER_cancel (validation_task);
11282 validation_task = NULL;
11283 }
11284 if (NULL != dvlearn_task)
11285 {
11286 GNUNET_SCHEDULER_cancel (dvlearn_task);
11287 dvlearn_task = NULL;
11288 }
11289 if (NULL != GST_stats)
11290 {
11291 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
11292 GST_stats = NULL;
11293 }
11294 if (NULL != GST_my_private_key)
11295 {
11296 GNUNET_free (GST_my_private_key);
11297 GST_my_private_key = NULL;
11298 }
11299 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
11300 &free_ack_cummulator_cb,
11301 NULL);
11302 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
11303 ack_cummulators = NULL;
11304 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
11305 &free_pending_ack_cb,
11306 NULL);
11307 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
11308 pending_acks = NULL;
11309 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
11310 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
11311 neighbours = NULL;
11312 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
11313 GNUNET_CONTAINER_multipeermap_destroy (links);
11314 links = NULL;
11315 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
11316 &free_backtalker_cb,
11317 NULL);
11318 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
11319 backtalkers = NULL;
11320 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
11321 &free_validation_state_cb,
11322 NULL);
11323 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
11324 validation_map = NULL;
11325 while (NULL != ir_head)
11326 free_incoming_request (ir_head);
11327 GNUNET_assert (0 == ir_total);
11328 while (NULL != (lle = lle_head))
11329 {
11330 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
11331 GNUNET_free (lle);
11332 }
11333 if (NULL != peerstore)
11334 {
11335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11336 "Disconnecting from PEERSTORE service\n");
11337 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
11338 peerstore = NULL;
11339 }
11340 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
11341 dvlearn_map = NULL;
11342 GNUNET_CONTAINER_heap_destroy (validation_heap);
11343 validation_heap = NULL;
11344 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
11345 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
11346 dv_routes = NULL;
11347 GNUNET_SCHEDULER_shutdown ();
11348}
11349
11350
11351static void
11352shutdown_task (void *cls)
11353{
11354 in_shutdown = GNUNET_YES;
11355
11356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11357 "Shutdown task executed\n");
11358 if (NULL != clients_head)
11359 {
11360 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11361 {
11362 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
11363 "client still connected: %u\n",
11364 tc->type);
11365 }
11366 }
11367 else
11368 do_shutdown (cls);
11369
11370}
11371
11372
11373/**
11374 * Initiate transport service.
11375 *
11376 * @param cls closure
11377 * @param c configuration to use
11378 * @param service the initialized service
11379 */
11380static void
11381run (void *cls,
11382 const struct GNUNET_CONFIGURATION_Handle *c,
11383 struct GNUNET_SERVICE_Handle *service)
11384{
11385 (void) cls;
11386 (void) service;
11387 /* setup globals */
11388 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
11389 in_shutdown = GNUNET_NO;
11390 GST_cfg = c;
11391 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
11392 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
11393 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
11394 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11395 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
11396 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11397 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
11398 GNUNET_YES);
11399 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11400 validation_heap =
11401 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
11402 GST_my_private_key =
11403 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
11404 if (NULL == GST_my_private_key)
11405 {
11406 GNUNET_log (
11407 GNUNET_ERROR_TYPE_ERROR,
11408 _ (
11409 "Transport service is lacking key configuration settings. Exiting.\n"));
11410 GNUNET_SCHEDULER_shutdown ();
11411 return;
11412 }
11413 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
11414 &GST_my_identity.public_key);
11415 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11416 "My identity is `%s'\n",
11417 GNUNET_i2s_full (&GST_my_identity));
11418 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
11419 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
11420 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
11421 if (NULL == peerstore)
11422 {
11423 GNUNET_break (0);
11424 GNUNET_SCHEDULER_shutdown ();
11425 return;
11426 }
11427}
11428
11429
11430/**
11431 * Define "main" method using service macro.
11432 */
11433GNUNET_SERVICE_MAIN (
11434 "transport",
11435 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
11436 &run,
11437 &client_connect_cb,
11438 &client_disconnect_cb,
11439 NULL,
11440 /* communication with applications */
11441 GNUNET_MQ_hd_fixed_size (suggest,
11442 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
11443 struct ExpressPreferenceMessage,
11444 NULL),
11445 GNUNET_MQ_hd_fixed_size (suggest_cancel,
11446 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
11447 struct ExpressPreferenceMessage,
11448 NULL),
11449 GNUNET_MQ_hd_var_size (request_hello_validation,
11450 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
11451 struct RequestHelloValidationMessage,
11452 NULL),
11453 /* communication with core */
11454 GNUNET_MQ_hd_fixed_size (client_start,
11455 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
11456 struct StartMessage,
11457 NULL),
11458 GNUNET_MQ_hd_var_size (client_send,
11459 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
11460 struct OutboundMessage,
11461 NULL),
11462 GNUNET_MQ_hd_fixed_size (client_recv_ok,
11463 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
11464 struct RecvOkMessage,
11465 NULL),
11466 /* communication with communicators */
11467 GNUNET_MQ_hd_var_size (communicator_available,
11468 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
11469 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
11470 NULL),
11471 GNUNET_MQ_hd_var_size (communicator_backchannel,
11472 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
11473 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
11474 NULL),
11475 GNUNET_MQ_hd_var_size (add_address,
11476 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
11477 struct GNUNET_TRANSPORT_AddAddressMessage,
11478 NULL),
11479 GNUNET_MQ_hd_fixed_size (del_address,
11480 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
11481 struct GNUNET_TRANSPORT_DelAddressMessage,
11482 NULL),
11483 GNUNET_MQ_hd_var_size (incoming_msg,
11484 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
11485 struct GNUNET_TRANSPORT_IncomingMessage,
11486 NULL),
11487 GNUNET_MQ_hd_fixed_size (queue_create_ok,
11488 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
11489 struct GNUNET_TRANSPORT_CreateQueueResponse,
11490 NULL),
11491 GNUNET_MQ_hd_fixed_size (queue_create_fail,
11492 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
11493 struct GNUNET_TRANSPORT_CreateQueueResponse,
11494 NULL),
11495 GNUNET_MQ_hd_var_size (add_queue_message,
11496 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
11497 struct GNUNET_TRANSPORT_AddQueueMessage,
11498 NULL),
11499 GNUNET_MQ_hd_fixed_size (update_queue_message,
11500 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
11501 struct GNUNET_TRANSPORT_UpdateQueueMessage,
11502 NULL),
11503 GNUNET_MQ_hd_fixed_size (del_queue_message,
11504 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
11505 struct GNUNET_TRANSPORT_DelQueueMessage,
11506 NULL),
11507 GNUNET_MQ_hd_fixed_size (send_message_ack,
11508 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
11509 struct GNUNET_TRANSPORT_SendMessageToAck,
11510 NULL),
11511 /* communication with monitors */
11512 GNUNET_MQ_hd_fixed_size (monitor_start,
11513 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
11514 struct GNUNET_TRANSPORT_MonitorStart,
11515 NULL),
11516 GNUNET_MQ_handler_end ());
11517
11518
11519/* end of file gnunet-service-transport.c */