2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
26 * - figure out how to transmit (selective) ACKs in case of uni-directional
27 * communicators (with/without core? DV-only?) When do we use ACKs?
28 * => communicators use selective ACKs for flow control
29 * => transport uses message-level ACKs for RTT, fragment confirmation
30 * => integrate DV into transport, use neither core nor communicators
31 * but rather give communicators transport-encapsulated messages
32 * (which could be core-data, background-channel traffic, or
33 * transport-to-transport traffic)
36 * - route_message() implementation, including using DV data structures
37 * (but not when routing certain message types, like DV learn,
38 * looks like now like we need two flags (DV/no-DV, confirmed-only,
40 * + NOTE: do NOT use PendingMessage for route_message(), as that is
41 * for fragmentation/reliability and ultimately core flow control!
42 * => route_message() should pick the queue
43 * => in case of DV routing, route_message should BOX the message, too.
44 * - We currently do NEVER tell CORE also about DV-connections (core_visible
45 * of `struct DistanceVector` is simply never set!)
46 * + When? Easy if we initiated the DV and got the challenge; do that NOW
47 * BUT what we passively learned DV (unconfirmed freshness)
48 * => Do we trigger Challenge->Response there as well, or 'wait' for
49 * our own DV initiations to discover?
50 * => What about DV routes that expire? Do we also only count on
51 * our own DV initiations for maintenance here, or do we
52 * try to specifically re-confirm the existence of a particular path?
53 * => OPITMIZATION-FIXME!
54 * + Where do we track what we told core? Careful: need to check
55 * the "core_visible' flag in both neighbours and DV before
56 * sending out notifications to CORE!
57 * - retransmission logic
58 * - track RTT, distance, loss, etc. => requires extra data structures!
61 * - change transport-core API to provide proper flow control in both
62 * directions, allow multiple messages per peer simultaneously (tag
63 * confirmations with unique message ID), and replace quota-out with
64 * proper flow control;
65 * - if messages are below MTU, consider adding ACKs and other stuff
66 * (requires planning at receiver, and additional MST-style demultiplex
68 * - could avoid copying body of message into each fragment and keep
69 * fragments as just pointers into the original message and only
70 * fully build fragments just before transmission (optimization, should
71 * reduce CPU and memory use)
73 * FIXME (without marks in the code!):
74 * - proper use/initialization of timestamps in messages exchanged
76 * - persistence of monotonic time obtained from other peers
77 * in PEERSTORE (by message type)
80 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
81 * against our pending message queue (requires additional per neighbour
82 * hash map to be maintained, avoids possible linear scan on pending msgs)
83 * - queue_send_msg and route_message both by API design have to make copies
84 * of the payload, and route_message on top of that requires a malloc/free.
85 * Change design to approximate "zero" copy better...
87 * Design realizations / discussion:
88 * - communicators do flow control by calling MQ "notify sent"
89 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
90 * or explicitly via backchannel FC ACKs. As long as the
91 * channel is not full, they may 'notify sent' even if the other
92 * peer has not yet confirmed receipt. The other peer confirming
93 * is _only_ for FC, not for more reliable transmission; reliable
94 * transmission (i.e. of fragments) is left to _transport_.
95 * - ACKs sent back in uni-directional communicators are done via
96 * the background channel API; here transport _may_ initially
97 * broadcast (with bounded # hops) if no path is known;
98 * - transport should _integrate_ DV-routing and build a view of
99 * the network; then background channel traffic can be
100 * routed via DV as well as explicit "DV" traffic.
101 * - background channel is also used for ACKs and NAT traversal support
102 * - transport service is responsible for AEAD'ing the background
103 * channel, timestamps and monotonic time are used against replay
104 * of old messages -> peerstore needs to be supplied with
105 * "latest timestamps seen" data
106 * - if transport implements DV, we likely need a 3rd peermap
107 * in addition to ephemerals and (direct) neighbours
108 * ==> check if stuff needs to be moved out of "Neighbour"
109 * - transport should encapsualte core-level messages and do its
110 * own ACKing for RTT/goodput/loss measurements _and_ fragment
113 #include "platform.h"
114 #include "gnunet_util_lib.h"
115 #include "gnunet_statistics_service.h"
116 #include "gnunet_transport_monitor_service.h"
117 #include "gnunet_peerstore_service.h"
118 #include "gnunet_hello_lib.h"
119 #include "gnunet_signatures.h"
120 #include "transport.h"
124 * What is the size we assume for a read operation in the
125 * absence of an MTU for the purpose of flow control?
127 #define IN_PACKET_SIZE_WITHOUT_MTU 128
130 * Minimum number of hops we should forward DV learn messages
131 * even if they are NOT useful for us in hope of looping
132 * back to the initiator?
134 * FIXME: allow initiator some control here instead?
136 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
139 * Maximum DV distance allowed ever.
141 #define MAX_DV_HOPS_ALLOWED 16
144 * Maximum number of DV learning activities we may
145 * have pending at the same time.
147 #define MAX_DV_LEARN_PENDING 64
150 * Maximum number of DV paths we keep simultaneously to the same target.
152 #define MAX_DV_PATHS_TO_TARGET 3
155 * If a queue delays the next message by more than this number
156 * of seconds we log a warning. Note: this is for testing,
157 * the value chosen here might be too aggressively low!
159 #define DELAY_WARN_THRESHOLD \
160 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
163 * We only consider queues as "quality" connections when
164 * suppressing the generation of DV initiation messages if
165 * the latency of the queue is below this threshold.
167 #define DV_QUALITY_RTT_THRESHOLD \
168 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
171 * How long do we consider a DV path valid if we see no
172 * further updates on it? Note: the value chosen here might be too low!
174 #define DV_PATH_VALIDITY_TIMEOUT \
175 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
178 * How long before paths expire would we like to (re)discover DV paths? Should
179 * be below #DV_PATH_VALIDITY_TIMEOUT.
181 #define DV_PATH_DISCOVERY_FREQUENCY \
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
185 * How long are ephemeral keys valid?
187 #define EPHEMERAL_VALIDITY \
188 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
191 * How long do we keep partially reassembled messages around before giving up?
193 #define REASSEMBLY_EXPIRATION \
194 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
197 * What is the fastest rate at which we send challenges *if* we keep learning
198 * an address (gossip, DHT, etc.)?
200 #define FAST_VALIDATION_CHALLENGE_FREQ \
201 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
204 * What is the slowest rate at which we send challenges?
206 #define MAX_VALIDATION_CHALLENGE_FREQ \
207 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
210 * What is the non-randomized base frequency at which we
211 * would initiate DV learn messages?
213 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
216 * How many good connections (confirmed, bi-directional, not DV)
217 * do we need to have to suppress initiating DV learn messages?
219 #define DV_LEARN_QUALITY_THRESHOLD 100
222 * When do we forget an invalid address for sure?
224 #define MAX_ADDRESS_VALID_UNTIL \
225 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
227 * How long do we consider an address valid if we just checked?
229 #define ADDRESS_VALIDATION_LIFETIME \
230 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
233 * What is the maximum frequency at which we do address validation?
234 * A random value between 0 and this value is added when scheduling
235 * the #validation_task (both to ensure we do not validate too often,
236 * and to randomize a bit).
238 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
241 * How many network RTTs before an address validation expires should we begin
242 * trying to revalidate? (Note that the RTT used here is the one that we
243 * experienced during the last validation, not necessarily the latest RTT
246 #define VALIDATION_RTT_BUFFER_FACTOR 3
249 * How many messages can we have pending for a given communicator
250 * process before we start to throttle that communicator?
252 * Used if a communicator might be CPU-bound and cannot handle the traffic.
254 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
257 * How many messages can we have pending for a given queue (queue to
258 * a particular peer via a communicator) process before we start to
259 * throttle that queue?
261 #define QUEUE_LENGTH_LIMIT 32
264 GNUNET_NETWORK_STRUCT_BEGIN
267 * Outer layer of an encapsulated backchannel message.
269 struct TransportBackchannelEncapsulationMessage
272 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
274 struct GNUNET_MessageHeader header;
277 * Distance the backchannel message has traveled, to be updated at
278 * each hop. Used to bound the number of hops in case a backchannel
279 * message is broadcast and thus travels without routing
280 * information (during initial backchannel discovery).
285 * Target's peer identity (as backchannels may be transmitted
286 * indirectly, or even be broadcast).
288 struct GNUNET_PeerIdentity target;
291 * Ephemeral key setup by the sender for @e target, used
292 * to encrypt the payload.
294 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
297 * We use an IV here as the @e ephemeral_key is re-used for
298 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
300 struct GNUNET_ShortHashCode iv;
303 * HMAC over the ciphertext of the encrypted, variable-size
304 * body that follows. Verified via DH of @e target and
307 struct GNUNET_HashCode hmac;
309 /* Followed by encrypted, variable-size payload */
314 * Body by which a peer confirms that it is using an ephemeral key.
316 struct EphemeralConfirmation
320 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
322 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
325 * How long is this signature over the ephemeral key valid?
327 * Note that the receiver MUST IGNORE the absolute time, and only interpret
328 * the value as a mononic time and reject "older" values than the last one
329 * observed. This is necessary as we do not want to require synchronized
330 * clocks and may not have a bidirectional communication channel.
332 * Even with this, there is no real guarantee against replay achieved here,
333 * unless the latest timestamp is persisted. While persistence should be
334 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
335 * communicators must protect against replay attacks when using backchannel
338 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
341 * Target's peer identity.
343 struct GNUNET_PeerIdentity target;
346 * Ephemeral key setup by the sender for @e target, used
347 * to encrypt the payload.
349 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
354 * Plaintext of the variable-size payload that is encrypted
355 * within a `struct TransportBackchannelEncapsulationMessage`
357 struct TransportBackchannelRequestPayload
361 * Sender's peer identity.
363 struct GNUNET_PeerIdentity sender;
366 * Signature of the sender over an
367 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
369 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
372 * How long is this signature over the ephemeral key valid?
374 * Note that the receiver MUST IGNORE the absolute time, and only interpret
375 * the value as a mononic time and reject "older" values than the last one
376 * observed. This is necessary as we do not want to require synchronized
377 * clocks and may not have a bidirectional communication channel.
379 * Even with this, there is no real guarantee against replay achieved here,
380 * unless the latest timestamp is persisted. While persistence should be
381 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
382 * communicators must protect against replay attacks when using backchannel
385 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
388 * Current monotonic time of the sending transport service. Used to
389 * detect replayed messages. Note that the receiver should remember
390 * a list of the recently seen timestamps and only reject messages
391 * if the timestamp is in the list, or the list is "full" and the
392 * timestamp is smaller than the lowest in the list.
394 * Like the @e ephemeral_validity, the list of timestamps per peer should be
395 * persisted to guard against replays after restarts.
397 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
399 /* Followed by a `struct GNUNET_MessageHeader` with a message
400 for a communicator */
402 /* Followed by a 0-termianted string specifying the name of
403 the communicator which is to receive the message */
408 * Outer layer of an encapsulated unfragmented application message sent
409 * over an unreliable channel.
411 struct TransportReliabilityBox
414 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
416 struct GNUNET_MessageHeader header;
419 * Number of messages still to be sent before a commulative
420 * ACK is requested. Zero if an ACK is requested immediately.
421 * In NBO. Note that the receiver may send the ACK faster
422 * if it believes that is reasonable.
424 uint32_t ack_countdown GNUNET_PACKED;
427 * Unique ID of the message used for signalling receipt of
428 * messages sent over possibly unreliable channels. Should
431 struct GNUNET_ShortHashCode msg_uuid;
436 * Confirmation that the receiver got a
437 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
438 * confirmation may be transmitted over a completely different queue,
439 * so ACKs are identified by a combination of PID of sender and
440 * message UUID, without the queue playing any role!
442 struct TransportReliabilityAckMessage
445 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
447 struct GNUNET_MessageHeader header;
452 uint32_t reserved GNUNET_PACKED;
455 * How long was the ACK delayed relative to the average time of
456 * receipt of the messages being acknowledged? Used to calculate
457 * the average RTT by taking the receipt time of the ack minus the
458 * average transmission time of the sender minus this value.
460 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
462 /* followed by any number of `struct GNUNET_ShortHashCode`
463 messages providing ACKs */
468 * Outer layer of an encapsulated fragmented application message.
470 struct TransportFragmentBox
473 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
475 struct GNUNET_MessageHeader header;
478 * Unique ID of this fragment (and fragment transmission!). Will
479 * change even if a fragement is retransmitted to make each
480 * transmission attempt unique! Should be incremented by one for
481 * each fragment transmission. If a client receives a duplicate
482 * fragment (same @e frag_off), it must send
483 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
485 uint32_t frag_uuid GNUNET_PACKED;
488 * Original message ID for of the message that all the1
489 * fragments belong to. Must be the same for all fragments.
491 struct GNUNET_ShortHashCode msg_uuid;
494 * Offset of this fragment in the overall message.
496 uint16_t frag_off GNUNET_PACKED;
499 * Total size of the message that is being fragmented.
501 uint16_t msg_size GNUNET_PACKED;
506 * Outer layer of an fragmented application message sent over a queue
507 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
508 * received, the receiver has two RTTs or 64 further fragments with
509 * the same basic message time to send an acknowledgement, possibly
510 * acknowledging up to 65 fragments in one ACK. ACKs must also be
511 * sent immediately once all fragments were sent.
513 struct TransportFragmentAckMessage
516 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
518 struct GNUNET_MessageHeader header;
521 * Unique ID of the lowest fragment UUID being acknowledged.
523 uint32_t frag_uuid GNUNET_PACKED;
526 * Bitfield of up to 64 additional fragments following the
527 * @e msg_uuid being acknowledged by this message.
529 uint64_t extra_acks GNUNET_PACKED;
532 * Original message ID for of the message that all the
533 * fragments belong to.
535 struct GNUNET_ShortHashCode msg_uuid;
538 * How long was the ACK delayed relative to the average time of
539 * receipt of the fragments being acknowledged? Used to calculate
540 * the average RTT by taking the receipt time of the ack minus the
541 * average transmission time of the sender minus this value.
543 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
546 * How long until the receiver will stop trying reassembly
549 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
554 * Content signed by the initator during DV learning.
556 * The signature is required to prevent DDoS attacks. A peer sending out this
557 * message is potentially generating a lot of traffic that will go back to the
558 * initator, as peers receiving this message will try to let the initiator
559 * know that they got the message.
561 * Without this signature, an attacker could abuse this mechanism for traffic
562 * amplification, sending a lot of traffic to a peer by putting out this type
563 * of message with the victim's peer identity.
565 * Even with just a signature, traffic amplification would be possible via
566 * replay attacks. The @e monotonic_time limits such replay attacks, as every
567 * potential amplificator will check the @e monotonic_time and only respond
568 * (at most) once per message.
573 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
575 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
578 * Time at the initiator when generating the signature.
580 * Note that the receiver MUST IGNORE the absolute time, and only interpret
581 * the value as a mononic time and reject "older" values than the last one
582 * observed. This is necessary as we do not want to require synchronized
583 * clocks and may not have a bidirectional communication channel.
585 * Even with this, there is no real guarantee against replay achieved here,
586 * unless the latest timestamp is persisted. Persistence should be
587 * provided via PEERSTORE if possible.
589 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
592 * Challenge value used by the initiator to re-identify the path.
594 struct GNUNET_ShortHashCode challenge;
599 * Content signed by each peer during DV learning.
601 * This assues the initiator of the DV learning operation that the hop from @e
602 * pred via the signing peer to @e succ actually exists. This makes it
603 * impossible for an adversary to supply the network with bogus routes.
605 * The @e challenge is included to provide replay protection for the
606 * initiator. This way, the initiator knows that the hop existed after the
607 * original @e challenge was first transmitted, providing a freshness metric.
609 * Peers other than the initiator that passively learn paths by observing
610 * these messages do NOT benefit from this. Here, an adversary may indeed
611 * replay old messages. Thus, passively learned paths should always be
612 * immediately marked as "potentially stale".
617 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
619 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
622 * Identity of the previous peer on the path.
624 struct GNUNET_PeerIdentity pred;
627 * Identity of the next peer on the path.
629 struct GNUNET_PeerIdentity succ;
632 * Challenge value used by the initiator to re-identify the path.
634 struct GNUNET_ShortHashCode challenge;
639 * An entry describing a peer on a path in a
640 * `struct TransportDVLearn` message.
645 * Identity of a peer on the path.
647 struct GNUNET_PeerIdentity hop;
650 * Signature of this hop over the path, of purpose
651 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
653 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
658 * Internal message used by transport for distance vector learning.
659 * If @e num_hops does not exceed the threshold, peers should append
660 * themselves to the peer list and flood the message (possibly only
661 * to a subset of their neighbours to limit discoverability of the
662 * network topology). To the extend that the @e bidirectional bits
663 * are set, peers may learn the inverse paths even if they did not
666 * Unless received on a bidirectional queue and @e num_hops just
667 * zero, peers that can forward to the initator should always try to
668 * forward to the initiator.
670 struct TransportDVLearn
673 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
675 struct GNUNET_MessageHeader header;
678 * Number of hops this messages has travelled, in NBO. Zero if
681 uint16_t num_hops GNUNET_PACKED;
684 * Bitmask of the last 16 hops indicating whether they are confirmed
685 * available (without DV) in both directions or not, in NBO. Used
686 * to possibly instantly learn a path in both directions. Each peer
687 * should shift this value by one to the left, and then set the
688 * lowest bit IF the current sender can be reached from it (without
691 uint16_t bidirectional GNUNET_PACKED;
694 * Peers receiving this message and delaying forwarding to other
695 * peers for any reason should increment this value by the non-network
696 * delay created by the peer.
698 struct GNUNET_TIME_RelativeNBO non_network_delay;
701 * Signature of this hop over the path, of purpose
702 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
704 struct GNUNET_CRYPTO_EddsaSignature init_sig;
707 * Identity of the peer that started this learning activity.
709 struct GNUNET_PeerIdentity initiator;
712 * Challenge value used by the initiator to re-identify the path.
714 struct GNUNET_ShortHashCode challenge;
716 /* Followed by @e num_hops `struct DVPathEntryP` values,
717 excluding the initiator of the DV trace; the last entry is the
718 current sender; the current peer must not be included. */
723 * Outer layer of an encapsulated message send over multiple hops.
724 * The path given only includes the identities of the subsequent
725 * peers, i.e. it will be empty if we are the receiver. Each
726 * forwarding peer should scan the list from the end, and if it can,
727 * forward to the respective peer. The list should then be shortened
728 * by all the entries up to and including that peer. Each hop should
729 * also increment @e total_hops to allow the receiver to get a precise
730 * estimate on the number of hops the message travelled. Senders must
731 * provide a learned path that thus should work, but intermediaries
732 * know of a shortcut, they are allowed to send the message via that
735 * If a peer finds itself still on the list, it must drop the message.
737 struct TransportDVBox
740 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
742 struct GNUNET_MessageHeader header;
745 * Number of total hops this messages travelled. In NBO.
746 * @e origin sets this to zero, to be incremented at
749 uint16_t total_hops GNUNET_PACKED;
752 * Number of hops this messages includes. In NBO.
754 uint16_t num_hops GNUNET_PACKED;
757 * Identity of the peer that originated the message.
759 struct GNUNET_PeerIdentity origin;
761 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
762 excluding the @e origin and the current peer, the last must be
763 the ultimate target; if @e num_hops is zero, the receiver of this
764 message is the ultimate target. */
766 /* Followed by the actual message, which itself may be
767 another box, but not a DV_LEARN or DV_BOX message! */
772 * Message send to another peer to validate that it can indeed
773 * receive messages at a particular address.
775 struct TransportValidationChallenge
779 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
781 struct GNUNET_MessageHeader header;
786 uint32_t reserved GNUNET_PACKED;
789 * Challenge to be signed by the receiving peer.
791 struct GNUNET_ShortHashCode challenge;
794 * Timestamp of the sender, to be copied into the reply
795 * to allow sender to calculate RTT.
797 struct GNUNET_TIME_AbsoluteNBO sender_time;
802 * Message signed by a peer to confirm that it can indeed
803 * receive messages at a particular address.
805 struct TransportValidationPS
809 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
811 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
814 * How long does the sender believe the address on
815 * which the challenge was received to remain valid?
817 struct GNUNET_TIME_RelativeNBO validity_duration;
820 * Challenge signed by the receiving peer.
822 struct GNUNET_ShortHashCode challenge;
827 * Message send to a peer to respond to a
828 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
830 struct TransportValidationResponse
834 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
836 struct GNUNET_MessageHeader header;
841 uint32_t reserved GNUNET_PACKED;
844 * The peer's signature matching the
845 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
847 struct GNUNET_CRYPTO_EddsaSignature signature;
850 * The challenge that was signed by the receiving peer.
852 struct GNUNET_ShortHashCode challenge;
855 * Original timestamp of the sender (was @code{sender_time}),
856 * copied into the reply to allow sender to calculate RTT.
858 struct GNUNET_TIME_AbsoluteNBO origin_time;
861 * How long does the sender believe this address to remain
864 struct GNUNET_TIME_RelativeNBO validity_duration;
868 GNUNET_NETWORK_STRUCT_END
872 * What type of client is the `struct TransportClient` about?
877 * We do not know yet (client is fresh).
882 * Is the CORE service, we need to forward traffic to it.
887 * It is a monitor, forward monitor data.
892 * It is a communicator, use for communication.
897 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
904 * When did we launch this DV learning activity?
906 struct LearnLaunchEntry
910 * Kept (also) in a DLL sorted by launch time.
912 struct LearnLaunchEntry *prev;
915 * Kept (also) in a DLL sorted by launch time.
917 struct LearnLaunchEntry *next;
920 * Challenge that uniquely identifies this activity.
922 struct GNUNET_ShortHashCode challenge;
925 * When did we transmit the DV learn message (used to calculate RTT) and
926 * determine freshness of paths learned via this operation.
928 struct GNUNET_TIME_Absolute launch_time;
933 * Entry in our cache of ephemeral keys we currently use. This way, we only
934 * sign an ephemeral once per @e target, and then can re-use it over multiple
935 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
936 * signing is expensive and in some cases we may use backchannel messages a
939 struct EphemeralCacheEntry
943 * Target's peer identity (we don't re-use ephemerals
944 * to limit linkability of messages).
946 struct GNUNET_PeerIdentity target;
949 * Signature affirming @e ephemeral_key of type
950 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
952 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
955 * How long is @e sender_sig valid
957 struct GNUNET_TIME_Absolute ephemeral_validity;
962 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
965 * Our private ephemeral key.
967 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
970 * Node in the ephemeral cache for this entry.
971 * Used for expiration.
973 struct GNUNET_CONTAINER_HeapNode *hn;
978 * Client connected to the transport service.
980 struct TransportClient;
984 * A neighbour that at least one communicator is connected to.
990 * Entry in our #dv_routes table, representing a (set of) distance
991 * vector routes to a particular peer.
993 struct DistanceVector;
996 * One possible hop towards a DV target.
998 struct DistanceVectorHop
1002 * Kept in a MDLL, sorted by @e timeout.
1004 struct DistanceVectorHop *next_dv;
1007 * Kept in a MDLL, sorted by @e timeout.
1009 struct DistanceVectorHop *prev_dv;
1014 struct DistanceVectorHop *next_neighbour;
1019 struct DistanceVectorHop *prev_neighbour;
1022 * What would be the next hop to @e target?
1024 struct Neighbour *next_hop;
1027 * Distance vector entry this hop belongs with.
1029 struct DistanceVector *dv;
1032 * Array of @e distance hops to the target, excluding @e next_hop.
1033 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1034 * at the end of this struct.
1036 const struct GNUNET_PeerIdentity *path;
1039 * At what time do we forget about this path unless we see it again
1042 struct GNUNET_TIME_Absolute timeout;
1045 * After what time do we know for sure that the path must have existed?
1046 * Set to ZERO if the path is learned by snooping on DV learn messages
1047 * initiated by other peers, and to the time at which we generated the
1048 * challenge for DV learn operations this peer initiated.
1050 struct GNUNET_TIME_Absolute freshness;
1053 * How many hops in total to the `target` (excluding @e next_hop and `target`
1054 * itself), thus 0 still means a distance of 2 hops (to @e next_hop and then
1057 unsigned int distance;
1062 * Entry in our #dv_routes table, representing a (set of) distance
1063 * vector routes to a particular peer.
1065 struct DistanceVector
1069 * To which peer is this a route?
1071 struct GNUNET_PeerIdentity target;
1074 * Known paths to @e target.
1076 struct DistanceVectorHop *dv_head;
1079 * Known paths to @e target.
1081 struct DistanceVectorHop *dv_tail;
1084 * Task scheduled to purge expired paths from @e dv_head MDLL.
1086 struct GNUNET_SCHEDULER_Task *timeout_task;
1089 * Is one of the DV paths in this struct 'confirmed' and thus
1090 * the cause for CORE to see this peer as connected? (Note that
1091 * the same may apply to a `struct Neighbour` at the same time.)
1098 * A queue is a message queue provided by a communicator
1099 * via which we can reach a particular neighbour.
1105 * Entry identifying transmission in one of our `struct
1106 * Queue` which still awaits an ACK. This is used to
1107 * ensure we do not overwhelm a communicator and limit the number of
1108 * messages outstanding per communicator (say in case communicator is
1109 * CPU bound) and per queue (in case bandwidth allocation exceeds
1110 * what the communicator can actually provide towards a particular
1119 struct QueueEntry *next;
1124 struct QueueEntry *prev;
1127 * Queue this entry is queued with.
1129 struct Queue *queue;
1132 * Message ID used for this message with the queue used for transmission.
1139 * A queue is a message queue provided by a communicator
1140 * via which we can reach a particular neighbour.
1147 struct Queue *next_neighbour;
1152 struct Queue *prev_neighbour;
1157 struct Queue *prev_client;
1162 struct Queue *next_client;
1165 * Head of DLL of unacked transmission requests.
1167 struct QueueEntry *queue_head;
1170 * End of DLL of unacked transmission requests.
1172 struct QueueEntry *queue_tail;
1175 * Which neighbour is this queue for?
1177 struct Neighbour *neighbour;
1180 * Which communicator offers this queue?
1182 struct TransportClient *tc;
1185 * Address served by the queue.
1187 const char *address;
1190 * Task scheduled for the time when this queue can (likely) transmit the
1191 * next message. Still needs to check with the @e tracker_out to be sure.
1193 struct GNUNET_SCHEDULER_Task *transmit_task;
1196 * Task scheduled to possibly notfiy core that this queue is no longer
1197 * counting as confirmed. Runs the #core_queue_visibility_check().
1199 struct GNUNET_SCHEDULER_Task *visibility_task;
1202 * Our current RTT estimate for this queue.
1204 struct GNUNET_TIME_Relative rtt;
1207 * How long do *we* consider this @e address to be valid? In the past or
1208 * zero if we have not yet validated it. Can be updated based on
1209 * challenge-response validations (via address validation logic), or when we
1210 * receive ACKs that we can definitively map to transmissions via this
1213 struct GNUNET_TIME_Absolute validated_until;
1216 * Message ID generator for transmissions on this queue.
1221 * Unique identifier of this queue with the communicator.
1226 * Maximum transmission unit supported by this queue.
1231 * Distance to the target of this queue.
1232 * FIXME: needed? DV is done differently these days...
1239 uint32_t num_msg_pending;
1244 uint32_t num_bytes_pending;
1247 * Length of the DLL starting at @e queue_head.
1249 unsigned int queue_length;
1252 * Network type offered by this queue.
1254 enum GNUNET_NetworkType nt;
1257 * Connection status for this queue.
1259 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1262 * How much outbound bandwidth do we have available for this queue?
1264 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1267 * How much inbound bandwidth do we have available for this queue?
1269 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1274 * Information we keep for a message that we are reassembling.
1276 struct ReassemblyContext
1280 * Original message ID for of the message that all the
1281 * fragments belong to.
1283 struct GNUNET_ShortHashCode msg_uuid;
1286 * Which neighbour is this context for?
1288 struct Neighbour *neighbour;
1291 * Entry in the reassembly heap (sorted by expiration).
1293 struct GNUNET_CONTAINER_HeapNode *hn;
1296 * Bitfield with @e msg_size bits representing the positions
1297 * where we have received fragments. When we receive a fragment,
1298 * we check the bits in @e bitfield before incrementing @e msg_missing.
1300 * Allocated after the reassembled message.
1305 * Task for sending ACK. We may send ACKs either because of hitting
1306 * the @e extra_acks limit, or based on time and @e num_acks. This
1307 * task is for the latter case.
1309 struct GNUNET_SCHEDULER_Task *ack_task;
1312 * At what time will we give up reassembly of this message?
1314 struct GNUNET_TIME_Absolute reassembly_timeout;
1317 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1318 * Should be reset to zero when @e num_acks is set to 0.
1320 struct GNUNET_TIME_Relative avg_ack_delay;
1323 * Time we received the last fragment. @e avg_ack_delay must be
1324 * incremented by now - @e last_frag multiplied by @e num_acks.
1326 struct GNUNET_TIME_Absolute last_frag;
1329 * Bitfield of up to 64 additional fragments following @e frag_uuid
1330 * to be acknowledged in the next cummulative ACK.
1332 uint64_t extra_acks;
1335 * Unique ID of the lowest fragment UUID to be acknowledged in the
1336 * next cummulative ACK. Only valid if @e num_acks > 0.
1341 * Number of ACKs we have accumulated so far. Reset to 0
1342 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1344 unsigned int num_acks;
1347 * How big is the message we are reassembling in total?
1352 * How many bytes of the message are still missing? Defragmentation
1353 * is complete when @e msg_missing == 0.
1355 uint16_t msg_missing;
1357 /* Followed by @e msg_size bytes of the (partially) defragmented original
1360 /* Followed by @e bitfield data */
1365 * A neighbour that at least one communicator is connected to.
1371 * Which peer is this about?
1373 struct GNUNET_PeerIdentity pid;
1376 * Map with `struct ReassemblyContext` structs for fragments under
1377 * reassembly. May be NULL if we currently have no fragments from
1378 * this @e pid (lazy initialization).
1380 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1383 * Heap with `struct ReassemblyContext` structs for fragments under
1384 * reassembly. May be NULL if we currently have no fragments from
1385 * this @e pid (lazy initialization).
1387 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1390 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1392 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1395 * Head of list of messages pending for this neighbour.
1397 struct PendingMessage *pending_msg_head;
1400 * Tail of list of messages pending for this neighbour.
1402 struct PendingMessage *pending_msg_tail;
1405 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1406 * purged if this neighbour goes down.
1408 struct DistanceVectorHop *dv_head;
1411 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1412 * purged if this neighbour goes down.
1414 struct DistanceVectorHop *dv_tail;
1417 * Head of DLL of queues to this peer.
1419 struct Queue *queue_head;
1422 * Tail of DLL of queues to this peer.
1424 struct Queue *queue_tail;
1427 * Task run to cleanup pending messages that have exceeded their timeout.
1429 struct GNUNET_SCHEDULER_Task *timeout_task;
1432 * Quota at which CORE is allowed to transmit to this peer.
1434 * FIXME: not yet used, tricky to get right given multiple queues!
1435 * (=> Idea: measure???)
1436 * FIXME: how do we set this value initially when we tell CORE?
1437 * Options: start at a minimum value or at literally zero?
1438 * (=> Current thought: clean would be zero!)
1440 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1443 * What is the earliest timeout of any message in @e pending_msg_tail?
1445 struct GNUNET_TIME_Absolute earliest_timeout;
1448 * Do we have a confirmed working queue and are thus visible to
1456 * A peer that an application (client) would like us to talk to directly.
1462 * Which peer is this about?
1464 struct GNUNET_PeerIdentity pid;
1467 * Client responsible for the request.
1469 struct TransportClient *tc;
1472 * Handle for watching the peerstore for HELLOs for this peer.
1474 struct GNUNET_PEERSTORE_WatchContext *wc;
1477 * What kind of performance preference does this @e tc have?
1479 enum GNUNET_MQ_PreferenceKind pk;
1482 * How much bandwidth would this @e tc like to see?
1484 struct GNUNET_BANDWIDTH_Value32NBO bw;
1489 * Types of different pending messages.
1491 enum PendingMessageType
1495 * Ordinary message received from the CORE service.
1502 PMT_FRAGMENT_BOX = 1,
1507 PMT_RELIABILITY_BOX = 2,
1510 * Any type of acknowledgement.
1512 PMT_ACKNOWLEDGEMENT = 3,
1515 * Control traffic generated by the TRANSPORT service itself.
1523 * Transmission request that is awaiting delivery. The original
1524 * transmission requests from CORE may be too big for some queues.
1525 * In this case, a *tree* of fragments is created. At each
1526 * level of the tree, fragments are kept in a DLL ordered by which
1527 * fragment should be sent next (at the head). The tree is searched
1528 * top-down, with the original message at the root.
1530 * To select a node for transmission, first it is checked if the
1531 * current node's message fits with the MTU. If it does not, we
1532 * either calculate the next fragment (based on @e frag_off) from the
1533 * current node, or, if all fragments have already been created,
1534 * descend to the @e head_frag. Even though the node was already
1535 * fragmented, the fragment may be too big if the fragment was
1536 * generated for a queue with a larger MTU. In this case, the node
1537 * may be fragmented again, thus creating a tree.
1539 * When acknowledgements for fragments are received, the tree
1540 * must be pruned, removing those parts that were already
1541 * acknowledged. When fragments are sent over a reliable
1542 * channel, they can be immediately removed.
1544 * If a message is ever fragmented, then the original "full" message
1545 * is never again transmitted (even if it fits below the MTU), and
1546 * only (remaining) fragments are sent.
1548 struct PendingMessage
1551 * Kept in a MDLL of messages for this @a target.
1553 struct PendingMessage *next_neighbour;
1556 * Kept in a MDLL of messages for this @a target.
1558 struct PendingMessage *prev_neighbour;
1561 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1563 struct PendingMessage *next_client;
1566 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1568 struct PendingMessage *prev_client;
1571 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1572 * #PMT_FRAGMENT_BOx)
1574 struct PendingMessage *next_frag;
1577 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1578 * #PMT_FRAGMENT_BOX)
1580 struct PendingMessage *prev_frag;
1583 * This message, reliability boxed. Only possibly available if @e pmt is
1586 struct PendingMessage *bpm;
1589 * Target of the request.
1591 struct Neighbour *target;
1594 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1596 struct TransportClient *client;
1599 * Head of a MDLL of fragments created for this core message.
1601 struct PendingMessage *head_frag;
1604 * Tail of a MDLL of fragments created for this core message.
1606 struct PendingMessage *tail_frag;
1609 * Our parent in the fragmentation tree.
1611 struct PendingMessage *frag_parent;
1614 * At what time should we give up on the transmission (and no longer retry)?
1616 struct GNUNET_TIME_Absolute timeout;
1619 * What is the earliest time for us to retry transmission of this message?
1621 struct GNUNET_TIME_Absolute next_attempt;
1624 * UUID to use for this message (used for reassembly of fragments, only
1625 * initialized if @e msg_uuid_set is #GNUNET_YES).
1627 struct GNUNET_ShortHashCode msg_uuid;
1630 * Counter incremented per generated fragment.
1632 uint32_t frag_uuidgen;
1635 * Type of the pending message.
1637 enum PendingMessageType pmt;
1640 * Size of the original message.
1645 * Offset at which we should generate the next fragment.
1650 * #GNUNET_YES once @e msg_uuid was initialized
1652 int16_t msg_uuid_set;
1654 /* Followed by @e bytes_msg to transmit */
1659 * One of the addresses of this peer.
1661 struct AddressListEntry
1667 struct AddressListEntry *next;
1672 struct AddressListEntry *prev;
1675 * Which communicator provides this address?
1677 struct TransportClient *tc;
1680 * The actual address.
1682 const char *address;
1685 * Current context for storing this address in the peerstore.
1687 struct GNUNET_PEERSTORE_StoreContext *sc;
1690 * Task to periodically do @e st operation.
1692 struct GNUNET_SCHEDULER_Task *st;
1695 * What is a typical lifetime the communicator expects this
1696 * address to have? (Always from now.)
1698 struct GNUNET_TIME_Relative expiration;
1701 * Address identifier used by the communicator.
1706 * Network type offered by this address.
1708 enum GNUNET_NetworkType nt;
1713 * Client connected to the transport service.
1715 struct TransportClient
1721 struct TransportClient *next;
1726 struct TransportClient *prev;
1729 * Handle to the client.
1731 struct GNUNET_SERVICE_Client *client;
1734 * Message queue to the client.
1736 struct GNUNET_MQ_Handle *mq;
1739 * What type of client is this?
1741 enum ClientType type;
1747 * Information for @e type #CT_CORE.
1753 * Head of list of messages pending for this client, sorted by
1754 * transmission time ("next_attempt" + possibly internal prioritization).
1756 struct PendingMessage *pending_msg_head;
1759 * Tail of list of messages pending for this client.
1761 struct PendingMessage *pending_msg_tail;
1766 * Information for @e type #CT_MONITOR.
1772 * Peer identity to monitor the addresses of.
1773 * Zero to monitor all neighbours. Valid if
1774 * @e type is #CT_MONITOR.
1776 struct GNUNET_PeerIdentity peer;
1779 * Is this a one-shot monitor?
1787 * Information for @e type #CT_COMMUNICATOR.
1792 * If @e type is #CT_COMMUNICATOR, this communicator
1793 * supports communicating using these addresses.
1795 char *address_prefix;
1798 * Head of DLL of queues offered by this communicator.
1800 struct Queue *queue_head;
1803 * Tail of DLL of queues offered by this communicator.
1805 struct Queue *queue_tail;
1808 * Head of list of the addresses of this peer offered by this
1811 struct AddressListEntry *addr_head;
1814 * Tail of list of the addresses of this peer offered by this
1817 struct AddressListEntry *addr_tail;
1820 * Number of queue entries in all queues to this communicator. Used
1821 * throttle sending to a communicator if we see that the communicator
1822 * is globally unable to keep up.
1824 unsigned int total_queue_length;
1827 * Characteristics of this communicator.
1829 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1834 * Information for @e type #CT_APPLICATION
1840 * Map of requests for peers the given client application would like to
1841 * see connections for. Maps from PIDs to `struct PeerRequest`.
1843 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1852 * State we keep for validation activities. Each of these
1853 * is both in the #validation_heap and the #validation_map.
1855 struct ValidationState
1859 * For which peer is @a address to be validated (or possibly valid)?
1860 * Serves as key in the #validation_map.
1862 struct GNUNET_PeerIdentity pid;
1865 * How long did the peer claim this @e address to be valid? Capped at
1866 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1867 * were told about the address and the value claimed by the other peer at
1868 * that time. May be updated similarly when validation succeeds.
1870 struct GNUNET_TIME_Absolute valid_until;
1873 * How long do *we* consider this @e address to be valid?
1874 * In the past or zero if we have not yet validated it.
1876 struct GNUNET_TIME_Absolute validated_until;
1879 * When did we FIRST use the current @e challenge in a message?
1880 * Used to sanity-check @code{origin_time} in the response when
1881 * calculating the RTT. If the @code{origin_time} is not in
1882 * the expected range, the response is discarded as malicious.
1884 struct GNUNET_TIME_Absolute first_challenge_use;
1887 * When did we LAST use the current @e challenge in a message?
1888 * Used to sanity-check @code{origin_time} in the response when
1889 * calculating the RTT. If the @code{origin_time} is not in
1890 * the expected range, the response is discarded as malicious.
1892 struct GNUNET_TIME_Absolute last_challenge_use;
1895 * Next time we will send the @e challenge to the peer, if this time is past
1896 * @e valid_until, this validation state is released at this time. If the
1897 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1898 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1899 * to re-validate before the validity actually expires.
1901 struct GNUNET_TIME_Absolute next_challenge;
1904 * Current backoff factor we're applying for sending the @a challenge.
1905 * Reset to 0 if the @a challenge is confirmed upon validation.
1906 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1907 * existing value if we receive an unvalidated address again over
1908 * another channel (and thus should consider the information "fresh").
1909 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1911 struct GNUNET_TIME_Relative challenge_backoff;
1914 * Initially set to "forever". Once @e validated_until is set, this value is
1915 * set to the RTT that tells us how long it took to receive the validation.
1917 struct GNUNET_TIME_Relative validation_rtt;
1920 * The challenge we sent to the peer to get it to validate the address. Note
1921 * that we rotate the challenge whenever we update @e validated_until to
1922 * avoid attacks where a peer simply replays an old challenge in the future.
1923 * (We must not rotate more often as otherwise we may discard valid answers
1924 * due to packet losses, latency and reorderings on the network).
1926 struct GNUNET_ShortHashCode challenge;
1929 * Claimed address of the peer.
1934 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1935 * heap is used to figure out when the next validation activity should be
1938 struct GNUNET_CONTAINER_HeapNode *hn;
1941 * Handle to a PEERSTORE store operation for this @e address. NULL if
1942 * no PEERSTORE operation is pending.
1944 struct GNUNET_PEERSTORE_StoreContext *sc;
1947 * We are technically ready to send the challenge, but we are waiting for
1948 * the respective queue to become available for transmission.
1955 * Head of linked list of all clients to this service.
1957 static struct TransportClient *clients_head;
1960 * Tail of linked list of all clients to this service.
1962 static struct TransportClient *clients_tail;
1965 * Statistics handle.
1967 static struct GNUNET_STATISTICS_Handle *GST_stats;
1970 * Configuration handle.
1972 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1977 static struct GNUNET_PeerIdentity GST_my_identity;
1982 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1985 * Map from PIDs to `struct Neighbour` entries. A peer is
1986 * a neighbour if we have an MQ to it from some communicator.
1988 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1991 * Map from PIDs to `struct DistanceVector` entries describing
1992 * known paths to the peer.
1994 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
1997 * Map from PIDs to `struct ValidationState` entries describing
1998 * addresses we are aware of and their validity state.
2000 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2003 * Map from challenges to `struct LearnLaunchEntry` values.
2005 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2008 * Head of a DLL sorted by launch time.
2010 static struct LearnLaunchEntry *lle_head;
2013 * Tail of a DLL sorted by launch time.
2015 static struct LearnLaunchEntry *lle_tail;
2018 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2019 * sorting addresses we are aware of by when we should next try to (re)validate
2022 static struct GNUNET_CONTAINER_Heap *validation_heap;
2025 * Database for peer's HELLOs.
2027 static struct GNUNET_PEERSTORE_Handle *peerstore;
2030 * Heap sorting `struct EphemeralCacheEntry` by their
2031 * key/signature validity.
2033 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2036 * Hash map for looking up `struct EphemeralCacheEntry`s
2037 * by peer identity. (We may have ephemerals in our
2038 * cache for which we do not have a neighbour entry,
2039 * and similar many neighbours may not need ephemerals,
2040 * so we use a second map.)
2042 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2045 * Task to free expired ephemerals.
2047 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2050 * Task run to initiate DV learning.
2052 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2055 * Task to run address validation.
2057 static struct GNUNET_SCHEDULER_Task *validation_task;
2061 * Free cached ephemeral key.
2063 * @param ece cached signature to free
2066 free_ephemeral (struct EphemeralCacheEntry *ece)
2068 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2069 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2075 * Free validation state.
2077 * @param vs validation state to free
2080 free_validation_state (struct ValidationState *vs)
2082 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2083 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2087 GNUNET_PEERSTORE_store_cancel (vs->sc);
2090 GNUNET_free (vs->address);
2096 * Lookup neighbour record for peer @a pid.
2098 * @param pid neighbour to look for
2099 * @return NULL if we do not have this peer as a neighbour
2101 static struct Neighbour *
2102 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2104 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2109 * Details about what to notify monitors about.
2114 * @deprecated To be discussed if we keep these...
2116 struct GNUNET_TIME_Absolute last_validation;
2117 struct GNUNET_TIME_Absolute valid_until;
2118 struct GNUNET_TIME_Absolute next_validation;
2121 * Current round-trip time estimate.
2123 struct GNUNET_TIME_Relative rtt;
2126 * Connection status.
2128 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2133 uint32_t num_msg_pending;
2138 uint32_t num_bytes_pending;
2143 * Free a @dvh. Callers MAY want to check if this was the last path to the
2144 * `target`, and if so call #free_dv_route to also free the associated DV
2145 * entry in #dv_routes (if not, the associated scheduler job should eventually
2148 * @param dvh hop to free
2151 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2153 struct Neighbour *n = dvh->next_hop;
2154 struct DistanceVector *dv = dvh->dv;
2156 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2157 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2163 * Free entry in #dv_routes. First frees all hops to the target, and
2164 * if there are no entries left, frees @a dv as well.
2166 * @param dv route to free
2169 free_dv_route (struct DistanceVector *dv)
2171 struct DistanceVectorHop *dvh;
2173 while (NULL != (dvh = dv->dv_head))
2174 free_distance_vector_hop (dvh);
2175 if (NULL == dv->dv_head)
2179 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2180 if (NULL != dv->timeout_task)
2181 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2188 * Notify monitor @a tc about an event. That @a tc
2189 * cares about the event has already been checked.
2191 * Send @a tc information in @a me about a @a peer's status with
2192 * respect to some @a address to all monitors that care.
2194 * @param tc monitor to inform
2195 * @param peer peer the information is about
2196 * @param address address the information is about
2197 * @param nt network type associated with @a address
2198 * @param me detailed information to transmit
2201 notify_monitor (struct TransportClient *tc,
2202 const struct GNUNET_PeerIdentity *peer,
2203 const char *address,
2204 enum GNUNET_NetworkType nt,
2205 const struct MonitorEvent *me)
2207 struct GNUNET_MQ_Envelope *env;
2208 struct GNUNET_TRANSPORT_MonitorData *md;
2209 size_t addr_len = strlen (address) + 1;
2211 env = GNUNET_MQ_msg_extra (md,
2213 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2214 md->nt = htonl ((uint32_t) nt);
2216 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2217 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2218 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2219 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2220 md->cs = htonl ((uint32_t) me->cs);
2221 md->num_msg_pending = htonl (me->num_msg_pending);
2222 md->num_bytes_pending = htonl (me->num_bytes_pending);
2223 memcpy (&md[1], address, addr_len);
2224 GNUNET_MQ_send (tc->mq, env);
2229 * Send information in @a me about a @a peer's status with respect
2230 * to some @a address to all monitors that care.
2232 * @param peer peer the information is about
2233 * @param address address the information is about
2234 * @param nt network type associated with @a address
2235 * @param me detailed information to transmit
2238 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2239 const char *address,
2240 enum GNUNET_NetworkType nt,
2241 const struct MonitorEvent *me)
2243 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2245 if (CT_MONITOR != tc->type)
2247 if (tc->details.monitor.one_shot)
2249 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2250 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2252 notify_monitor (tc, peer, address, nt, me);
2258 * Called whenever a client connects. Allocates our
2259 * data structures associated with that client.
2261 * @param cls closure, NULL
2262 * @param client identification of the client
2263 * @param mq message queue for the client
2264 * @return our `struct TransportClient`
2267 client_connect_cb (void *cls,
2268 struct GNUNET_SERVICE_Client *client,
2269 struct GNUNET_MQ_Handle *mq)
2271 struct TransportClient *tc;
2274 tc = GNUNET_new (struct TransportClient);
2275 tc->client = client;
2277 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2286 * @param rc data structure to free
2289 free_reassembly_context (struct ReassemblyContext *rc)
2291 struct Neighbour *n = rc->neighbour;
2293 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2294 GNUNET_assert (GNUNET_OK ==
2295 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2303 * Task run to clean up reassembly context of a neighbour that have expired.
2305 * @param cls a `struct Neighbour`
2308 reassembly_cleanup_task (void *cls)
2310 struct Neighbour *n = cls;
2311 struct ReassemblyContext *rc;
2313 n->reassembly_timeout_task = NULL;
2314 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2316 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2319 free_reassembly_context (rc);
2322 GNUNET_assert (NULL == n->reassembly_timeout_task);
2323 n->reassembly_timeout_task =
2324 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2325 &reassembly_cleanup_task,
2333 * function called to #free_reassembly_context().
2337 * @param value a `struct ReassemblyContext` to free
2338 * @return #GNUNET_OK (continue iteration)
2341 free_reassembly_cb (void *cls,
2342 const struct GNUNET_ShortHashCode *key,
2345 struct ReassemblyContext *rc = value;
2349 free_reassembly_context (rc);
2355 * Release memory used by @a neighbour.
2357 * @param neighbour neighbour entry to free
2360 free_neighbour (struct Neighbour *neighbour)
2362 struct DistanceVectorHop *dvh;
2364 GNUNET_assert (NULL == neighbour->queue_head);
2365 GNUNET_assert (GNUNET_YES ==
2366 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2369 if (NULL != neighbour->timeout_task)
2370 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2371 if (NULL != neighbour->reassembly_map)
2373 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2374 &free_reassembly_cb,
2376 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2377 neighbour->reassembly_map = NULL;
2378 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2379 neighbour->reassembly_heap = NULL;
2381 while (NULL != (dvh = neighbour->dv_head))
2383 struct DistanceVector *dv = dvh->dv;
2385 free_distance_vector_hop (dvh);
2386 if (NULL == dv->dv_head)
2389 if (NULL != neighbour->reassembly_timeout_task)
2390 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2391 GNUNET_free (neighbour);
2396 * Send message to CORE clients that we lost a connection.
2398 * @param tc client to inform (must be CORE client)
2399 * @param pid peer the connection is for
2400 * @param quota_out current quota for the peer
2403 core_send_connect_info (struct TransportClient *tc,
2404 const struct GNUNET_PeerIdentity *pid,
2405 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2407 struct GNUNET_MQ_Envelope *env;
2408 struct ConnectInfoMessage *cim;
2410 GNUNET_assert (CT_CORE == tc->type);
2411 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2412 cim->quota_out = quota_out;
2414 GNUNET_MQ_send (tc->mq, env);
2419 * Send message to CORE clients that we gained a connection
2421 * @param pid peer the queue was for
2422 * @param quota_out current quota for the peer
2425 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2426 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2428 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2430 if (CT_CORE != tc->type)
2432 core_send_connect_info (tc, pid, quota_out);
2438 * Send message to CORE clients that we lost a connection.
2440 * @param pid peer the connection was for
2443 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2445 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2447 struct GNUNET_MQ_Envelope *env;
2448 struct DisconnectInfoMessage *dim;
2450 if (CT_CORE != tc->type)
2452 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2454 GNUNET_MQ_send (tc->mq, env);
2460 * We believe we are ready to transmit a message on a queue. Double-checks
2461 * with the queue's "tracker_out" and then gives the message to the
2462 * communicator for transmission (updating the tracker, and re-scheduling
2463 * itself if applicable).
2465 * @param cls the `struct Queue` to process transmissions for
2468 transmit_on_queue (void *cls);
2472 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2473 * we should run immediately or if the message queue is empty.
2474 * Test for no task being added AND queue not being empty to
2475 * transmit immediately afterwards! This function must only
2476 * be called if the message queue is non-empty!
2478 * @param queue the queue to do scheduling for
2481 schedule_transmit_on_queue (struct Queue *queue)
2483 struct Neighbour *n = queue->neighbour;
2484 struct PendingMessage *pm = n->pending_msg_head;
2485 struct GNUNET_TIME_Relative out_delay;
2488 GNUNET_assert (NULL != pm);
2489 if (queue->tc->details.communicator.total_queue_length >=
2490 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2492 GNUNET_STATISTICS_update (
2494 "# Transmission throttled due to communicator queue limit",
2499 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2501 GNUNET_STATISTICS_update (GST_stats,
2502 "# Transmission throttled due to queue queue limit",
2508 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
2510 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
2511 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
2514 if (0 == out_delay.rel_value_us)
2515 return; /* we should run immediately! */
2516 /* queue has changed since we were scheduled, reschedule again */
2517 queue->transmit_task =
2518 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
2519 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2520 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2521 "Next transmission on queue `%s' in %s (high delay)\n",
2523 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2526 "Next transmission on queue `%s' in %s\n",
2528 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2533 * Check whether the CORE visibility of @a n changed. If so,
2534 * check whether we need to notify CORE.
2536 * @param n neighbour to perform the check for
2539 update_neighbour_core_visibility (struct Neighbour *n);
2545 * @param queue the queue to free
2548 free_queue (struct Queue *queue)
2550 struct Neighbour *neighbour = queue->neighbour;
2551 struct TransportClient *tc = queue->tc;
2552 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
2553 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
2554 struct QueueEntry *qe;
2557 if (NULL != queue->transmit_task)
2559 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2560 queue->transmit_task = NULL;
2562 if (NULL != queue->visibility_task)
2564 GNUNET_SCHEDULER_cancel (queue->visibility_task);
2565 queue->visibility_task = NULL;
2567 GNUNET_CONTAINER_MDLL_remove (neighbour,
2568 neighbour->queue_head,
2569 neighbour->queue_tail,
2571 GNUNET_CONTAINER_MDLL_remove (client,
2572 tc->details.communicator.queue_head,
2573 tc->details.communicator.queue_tail,
2575 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
2576 tc->details.communicator.total_queue_length);
2577 while (NULL != (qe = queue->queue_head))
2579 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
2580 queue->queue_length--;
2581 tc->details.communicator.total_queue_length--;
2584 GNUNET_assert (0 == queue->queue_length);
2585 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
2586 tc->details.communicator.total_queue_length))
2588 /* Communicator dropped below threshold, resume all queues */
2589 GNUNET_STATISTICS_update (
2591 "# Transmission throttled due to communicator queue limit",
2594 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
2596 schedule_transmit_on_queue (s);
2598 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
2599 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2600 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2601 GNUNET_free (queue);
2603 update_neighbour_core_visibility (neighbour);
2604 cores_send_disconnect_info (&neighbour->pid);
2606 if (NULL == neighbour->queue_head)
2608 free_neighbour (neighbour);
2616 * @param ale address list entry to free
2619 free_address_list_entry (struct AddressListEntry *ale)
2621 struct TransportClient *tc = ale->tc;
2623 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2624 tc->details.communicator.addr_tail,
2626 if (NULL != ale->sc)
2628 GNUNET_PEERSTORE_store_cancel (ale->sc);
2631 if (NULL != ale->st)
2633 GNUNET_SCHEDULER_cancel (ale->st);
2641 * Stop the peer request in @a value.
2643 * @param cls a `struct TransportClient` that no longer makes the request
2644 * @param pid the peer's identity
2645 * @param value a `struct PeerRequest`
2646 * @return #GNUNET_YES (always)
2649 stop_peer_request (void *cls,
2650 const struct GNUNET_PeerIdentity *pid,
2653 struct TransportClient *tc = cls;
2654 struct PeerRequest *pr = value;
2656 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2659 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2669 * Called whenever a client is disconnected. Frees our
2670 * resources associated with that client.
2672 * @param cls closure, NULL
2673 * @param client identification of the client
2674 * @param app_ctx our `struct TransportClient`
2677 client_disconnect_cb (void *cls,
2678 struct GNUNET_SERVICE_Client *client,
2681 struct TransportClient *tc = app_ctx;
2684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2685 "Client %p disconnected, cleaning up.\n",
2687 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
2693 struct PendingMessage *pm;
2695 while (NULL != (pm = tc->details.core.pending_msg_head))
2697 GNUNET_CONTAINER_MDLL_remove (client,
2698 tc->details.core.pending_msg_head,
2699 tc->details.core.pending_msg_tail,
2707 case CT_COMMUNICATOR: {
2709 struct AddressListEntry *ale;
2711 while (NULL != (q = tc->details.communicator.queue_head))
2713 while (NULL != (ale = tc->details.communicator.addr_head))
2714 free_address_list_entry (ale);
2715 GNUNET_free (tc->details.communicator.address_prefix);
2718 case CT_APPLICATION:
2719 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2722 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2730 * Iterator telling new CORE client about all existing
2731 * connections to peers.
2733 * @param cls the new `struct TransportClient`
2734 * @param pid a connected peer
2735 * @param value the `struct Neighbour` with more information
2736 * @return #GNUNET_OK (continue to iterate)
2739 notify_client_connect_info (void *cls,
2740 const struct GNUNET_PeerIdentity *pid,
2743 struct TransportClient *tc = cls;
2744 struct Neighbour *neighbour = value;
2746 core_send_connect_info (tc, pid, neighbour->quota_out);
2752 * Initialize a "CORE" client. We got a start message from this
2753 * client, so add it to the list of clients for broadcasting of
2756 * @param cls the client
2757 * @param start the start message that was sent
2760 handle_client_start (void *cls, const struct StartMessage *start)
2762 struct TransportClient *tc = cls;
2765 options = ntohl (start->options);
2766 if ((0 != (1 & options)) &&
2767 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
2769 /* client thinks this is a different peer, reject */
2771 GNUNET_SERVICE_client_drop (tc->client);
2774 if (CT_NONE != tc->type)
2777 GNUNET_SERVICE_client_drop (tc->client);
2781 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2782 ¬ify_client_connect_info,
2784 GNUNET_SERVICE_client_continue (tc->client);
2789 * Client asked for transmission to a peer. Process the request.
2791 * @param cls the client
2792 * @param obm the send message that was sent
2795 check_client_send (void *cls, const struct OutboundMessage *obm)
2797 struct TransportClient *tc = cls;
2799 const struct GNUNET_MessageHeader *obmm;
2801 if (CT_CORE != tc->type)
2804 return GNUNET_SYSERR;
2806 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2807 if (size < sizeof (struct GNUNET_MessageHeader))
2810 return GNUNET_SYSERR;
2812 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2813 if (size != ntohs (obmm->size))
2816 return GNUNET_SYSERR;
2823 * Free fragment tree below @e root, excluding @e root itself.
2825 * @param root root of the tree to free
2828 free_fragment_tree (struct PendingMessage *root)
2830 struct PendingMessage *frag;
2832 while (NULL != (frag = root->head_frag))
2834 free_fragment_tree (frag);
2835 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2842 * Release memory associated with @a pm and remove @a pm from associated
2843 * data structures. @a pm must be a top-level pending message and not
2844 * a fragment in the tree. The entire tree is freed (if applicable).
2846 * @param pm the pending message to free
2849 free_pending_message (struct PendingMessage *pm)
2851 struct TransportClient *tc = pm->client;
2852 struct Neighbour *target = pm->target;
2856 GNUNET_CONTAINER_MDLL_remove (client,
2857 tc->details.core.pending_msg_head,
2858 tc->details.core.pending_msg_tail,
2861 GNUNET_CONTAINER_MDLL_remove (neighbour,
2862 target->pending_msg_head,
2863 target->pending_msg_tail,
2865 free_fragment_tree (pm);
2866 GNUNET_free_non_null (pm->bpm);
2872 * Send a response to the @a pm that we have processed a
2873 * "send" request with status @a success. We
2874 * transmitted @a bytes_physical on the actual wire.
2875 * Sends a confirmation to the "core" client responsible
2876 * for the original request and free's @a pm.
2878 * @param pm handle to the original pending message
2879 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2880 * for transmission failure
2881 * @param bytes_physical amount of bandwidth consumed
2884 client_send_response (struct PendingMessage *pm,
2886 uint32_t bytes_physical)
2888 struct TransportClient *tc = pm->client;
2889 struct Neighbour *target = pm->target;
2890 struct GNUNET_MQ_Envelope *env;
2891 struct SendOkMessage *som;
2895 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2896 som->success = htonl ((uint32_t) success);
2897 som->bytes_msg = htons (pm->bytes_msg);
2898 som->bytes_physical = htonl (bytes_physical);
2899 som->peer = target->pid;
2900 GNUNET_MQ_send (tc->mq, env);
2902 free_pending_message (pm);
2907 * Checks the message queue for a neighbour for messages that have timed
2908 * out and purges them.
2910 * @param cls a `struct Neighbour`
2913 check_queue_timeouts (void *cls)
2915 struct Neighbour *n = cls;
2916 struct PendingMessage *pm;
2917 struct GNUNET_TIME_Absolute now;
2918 struct GNUNET_TIME_Absolute earliest_timeout;
2920 n->timeout_task = NULL;
2921 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2922 now = GNUNET_TIME_absolute_get ();
2923 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
2925 pm = pos->next_neighbour;
2926 if (pos->timeout.abs_value_us <= now.abs_value_us)
2928 GNUNET_STATISTICS_update (GST_stats,
2929 "# messages dropped (timeout before confirmation)",
2932 client_send_response (pm, GNUNET_NO, 0);
2936 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
2938 n->earliest_timeout = earliest_timeout;
2939 if (NULL != n->pending_msg_head)
2941 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
2946 * Client asked for transmission to a peer. Process the request.
2948 * @param cls the client
2949 * @param obm the send message that was sent
2952 handle_client_send (void *cls, const struct OutboundMessage *obm)
2954 struct TransportClient *tc = cls;
2955 struct PendingMessage *pm;
2956 const struct GNUNET_MessageHeader *obmm;
2957 struct Neighbour *target;
2961 GNUNET_assert (CT_CORE == tc->type);
2962 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2963 bytes_msg = ntohs (obmm->size);
2964 target = lookup_neighbour (&obm->peer);
2967 /* Failure: don't have this peer as a neighbour (anymore).
2968 Might have gone down asynchronously, so this is NOT
2969 a protocol violation by CORE. Still count the event,
2970 as this should be rare. */
2971 struct GNUNET_MQ_Envelope *env;
2972 struct SendOkMessage *som;
2974 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2975 som->success = htonl (GNUNET_SYSERR);
2976 som->bytes_msg = htonl (bytes_msg);
2977 som->bytes_physical = htonl (0);
2978 som->peer = obm->peer;
2979 GNUNET_MQ_send (tc->mq, env);
2980 GNUNET_SERVICE_client_continue (tc->client);
2981 GNUNET_STATISTICS_update (GST_stats,
2982 "# messages dropped (neighbour unknown)",
2987 was_empty = (NULL == target->pending_msg_head);
2988 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2990 pm->target = target;
2991 pm->bytes_msg = bytes_msg;
2993 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2994 memcpy (&pm[1], &obm[1], bytes_msg);
2995 GNUNET_CONTAINER_MDLL_insert (neighbour,
2996 target->pending_msg_head,
2997 target->pending_msg_tail,
2999 GNUNET_CONTAINER_MDLL_insert (client,
3000 tc->details.core.pending_msg_head,
3001 tc->details.core.pending_msg_tail,
3003 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3005 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3006 if (NULL != target->timeout_task)
3007 GNUNET_SCHEDULER_cancel (target->timeout_task);
3008 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3009 &check_queue_timeouts,
3013 return; /* all queues must already be busy */
3014 for (struct Queue *queue = target->queue_head; NULL != queue;
3015 queue = queue->next_neighbour)
3017 /* try transmission on any queue that is idle */
3018 if (NULL == queue->transmit_task)
3019 queue->transmit_task =
3020 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3026 * Communicator started. Test message is well-formed.
3028 * @param cls the client
3029 * @param cam the send message that was sent
3032 check_communicator_available (
3034 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3036 struct TransportClient *tc = cls;
3039 if (CT_NONE != tc->type)
3042 return GNUNET_SYSERR;
3044 tc->type = CT_COMMUNICATOR;
3045 size = ntohs (cam->header.size) - sizeof (*cam);
3047 return GNUNET_OK; /* receive-only communicator */
3048 GNUNET_MQ_check_zero_termination (cam);
3054 * Communicator started. Process the request.
3056 * @param cls the client
3057 * @param cam the send message that was sent
3060 handle_communicator_available (
3062 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3064 struct TransportClient *tc = cls;
3067 size = ntohs (cam->header.size) - sizeof (*cam);
3069 return; /* receive-only communicator */
3070 tc->details.communicator.address_prefix =
3071 GNUNET_strdup ((const char *) &cam[1]);
3072 tc->details.communicator.cc =
3073 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3074 GNUNET_SERVICE_client_continue (tc->client);
3079 * Communicator requests backchannel transmission. Check the request.
3081 * @param cls the client
3082 * @param cb the send message that was sent
3083 * @return #GNUNET_OK if message is well-formed
3086 check_communicator_backchannel (
3088 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3090 const struct GNUNET_MessageHeader *inbox;
3096 msize = ntohs (cb->header.size) - sizeof (*cb);
3097 if (UINT16_MAX - msize >
3098 sizeof (struct TransportBackchannelEncapsulationMessage) +
3099 sizeof (struct TransportBackchannelRequestPayload))
3102 return GNUNET_SYSERR;
3104 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3105 isize = ntohs (inbox->size);
3109 return GNUNET_SYSERR;
3111 is = (const char *) inbox;
3114 GNUNET_assert (msize > 0);
3115 if ('\0' != is[msize - 1])
3118 return GNUNET_SYSERR;
3125 * Remove memory used by expired ephemeral keys.
3130 expire_ephemerals (void *cls)
3132 struct EphemeralCacheEntry *ece;
3135 ephemeral_task = NULL;
3136 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3138 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3141 free_ephemeral (ece);
3144 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3153 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3154 * one, cache it and return it.
3156 * @param pid peer to look up ephemeral for
3157 * @param private_key[out] set to the private key
3158 * @param ephemeral_key[out] set to the key
3159 * @param ephemeral_sender_sig[out] set to the signature
3160 * @param ephemeral_validity[out] set to the validity expiration time
3163 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3164 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3165 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3166 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3167 struct GNUNET_TIME_Absolute *ephemeral_validity)
3169 struct EphemeralCacheEntry *ece;
3170 struct EphemeralConfirmation ec;
3172 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3173 if ((NULL != ece) &&
3174 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3177 free_ephemeral (ece);
3182 ece = GNUNET_new (struct EphemeralCacheEntry);
3184 ece->ephemeral_validity =
3185 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3186 EPHEMERAL_VALIDITY);
3187 GNUNET_assert (GNUNET_OK ==
3188 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3189 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3190 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3191 ec.purpose.size = htonl (sizeof (ec));
3193 ec.ephemeral_key = ece->ephemeral_key;
3194 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3198 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3200 ece->ephemeral_validity.abs_value_us);
3201 GNUNET_assert (GNUNET_OK ==
3202 GNUNET_CONTAINER_multipeermap_put (
3206 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3207 if (NULL == ephemeral_task)
3208 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3212 *private_key = ece->private_key;
3213 *ephemeral_key = ece->ephemeral_key;
3214 *ephemeral_sender_sig = ece->sender_sig;
3215 *ephemeral_validity = ece->ephemeral_validity;
3220 * Send the control message @a payload on @a queue.
3222 * @param queue the queue to use for transmission
3223 * @param pm pending message to update once transmission is done, may be NULL!
3224 * @param payload the payload to send (encapsulated in a
3225 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3226 * @param payload_size number of bytes in @a payload
3229 queue_send_msg (struct Queue *queue,
3230 struct PendingMessage *pm,
3231 const void *payload,
3232 size_t payload_size)
3234 struct Neighbour *n = queue->neighbour;
3235 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3236 struct GNUNET_MQ_Envelope *env;
3238 env = GNUNET_MQ_msg_extra (smt,
3240 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3241 smt->qid = queue->qid;
3242 smt->mid = queue->mid_gen;
3243 smt->receiver = n->pid;
3244 memcpy (&smt[1], payload, payload_size);
3246 /* Pass the env to the communicator of queue for transmission. */
3247 struct QueueEntry *qe;
3249 qe = GNUNET_new (struct QueueEntry);
3250 qe->mid = queue->mid_gen++;
3252 // qe->pm = pm; // FIXME: not so easy, reference management on 'free(s)'!
3253 // (also, note that pm may be NULL!)
3254 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3255 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3256 queue->queue_length++;
3257 queue->tc->details.communicator.total_queue_length++;
3258 GNUNET_MQ_send (queue->tc->mq, env);
3264 * Which transmission options are allowable for transmission?
3265 * Interpreted bit-wise!
3267 enum RouteMessageOptions
3270 * Only confirmed, non-DV direct neighbours.
3275 * We are allowed to use DV routing for this @a hdr
3280 * We are allowed to use unconfirmed queues or DV routes for this message
3282 RMO_UNCONFIRMED_ALLOWED = 2,
3285 * Reliable and unreliable, DV and non-DV are all acceptable.
3287 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
3290 * If we have multiple choices, it is OK to send this message
3291 * over multiple channels at the same time to improve loss tolerance.
3292 * (We do at most 2 transmissions.)
3299 * Pick a queue of @a n under constraints @a options and schedule
3300 * transmission of @a hdr.
3302 * @param n neighbour to send to
3303 * @param hdr message to send as payload
3304 * @param options whether queues must be confirmed or not,
3305 * and whether we may pick multiple (2) queues
3308 route_via_neighbour (const struct Neighbour *n,
3309 const struct GNUNET_MessageHeader *hdr,
3310 enum RouteMessageOptions options)
3312 struct GNUNET_TIME_Absolute now;
3313 unsigned int candidates;
3317 /* Pick one or two 'random' queues from n (under constraints of options) */
3318 now = GNUNET_TIME_absolute_get ();
3319 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
3320 weight in the future; weight could be assigned by observed
3321 bandwidth (note: not sure if we should do this for this type
3322 of control traffic though). */
3324 for (struct Queue *pos = n->queue_head; NULL != pos;
3325 pos = pos->next_neighbour)
3327 /* Count the queue with the visibility task in all cases, as
3328 otherwise we may end up with no queues just because the
3329 time for the visibility task just expired but the scheduler
3330 just ran this task first */
3331 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
3332 (pos->validated_until.abs_value_us > now.abs_value_us) ||
3333 (NULL != pos->visibility_task))
3336 if (0 == candidates)
3338 /* Given that we above check for pos->visibility task,
3339 this should be strictly impossible. */
3343 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3344 if (0 == (options & RMO_REDUNDANT))
3345 sel2 = candidates; /* picks none! */
3347 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3349 for (struct Queue *pos = n->queue_head; NULL != pos;
3350 pos = pos->next_neighbour)
3352 /* Count the queue with the visibility task in all cases, as
3353 otherwise we may end up with no queues just because the
3354 time for the visibility task just expired but the scheduler
3355 just ran this task first */
3356 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
3357 (NULL != pos->visibility_task))
3359 if ((sel1 == candidates) || (sel2 == candidates))
3360 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
3368 * Pick a path of @a dv under constraints @a options and schedule
3369 * transmission of @a hdr.
3371 * @param n neighbour to send to
3372 * @param hdr message to send as payload
3373 * @param options whether path must be confirmed or not
3374 * and whether we may pick multiple (2) paths
3377 route_via_dv (const struct DistanceVector *dv,
3378 const struct GNUNET_MessageHeader *hdr,
3379 enum RouteMessageOptions options)
3381 // FIXME: pick on or two 'random' paths (under constraints of options)
3382 // Then add DVBox and enqueue message (possibly using
3383 // route_via_neighbour for 1st hop?)
3388 * We need to transmit @a hdr to @a target. If necessary, this may
3389 * involve DV routing.
3391 * @param target peer to receive @a hdr
3392 * @param hdr header of the message to route and #GNUNET_free()
3393 * @param options which transmission channels are allowed
3396 route_message (const struct GNUNET_PeerIdentity *target,
3397 struct GNUNET_MessageHeader *hdr,
3398 enum RouteMessageOptions options)
3400 struct Neighbour *n;
3401 struct DistanceVector *dv;
3403 n = GNUNET_CONTAINER_multipeermap_get (neighbours, target);
3404 dv = (0 != (options & RMO_DV_ALLOWED))
3405 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
3407 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
3409 /* if confirmed is required, and we do not have anything
3410 confirmed, drop respective options */
3411 if ((NULL != n) && (GNUNET_NO == n->core_visible))
3413 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
3416 if ((NULL == n) && (NULL == dv))
3418 GNUNET_STATISTICS_update (GST_stats,
3419 "# Messages dropped in routing: no acceptable method",
3425 /* If both dv and n are possible and we must choose:
3426 flip a coin for the choice between the two; for now 50/50 */
3427 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
3429 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
3434 if ((NULL != n) && (NULL != dv))
3435 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
3436 enough for redunancy, so clear the flag. */
3439 route_via_neighbour (n, hdr, options);
3443 route_via_dv (dv, hdr, options);
3450 * Structure of the key material used to encrypt backchannel messages.
3452 struct BackchannelKeyState
3455 * State of our block cipher.
3457 gcry_cipher_hd_t cipher;
3460 * Actual key material.
3466 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3468 struct GNUNET_CRYPTO_AuthKey hmac_key;
3471 * Symmetric key to use for encryption.
3473 char aes_key[256 / 8];
3476 * Counter value to use during setup.
3478 char aes_ctr[128 / 8];
3485 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3486 const struct GNUNET_ShortHashCode *iv,
3487 struct BackchannelKeyState *key)
3489 /* must match #dh_key_derive_eph_pub */
3490 GNUNET_assert (GNUNET_YES ==
3491 GNUNET_CRYPTO_kdf (&key->material,
3492 sizeof (key->material),
3493 "transport-backchannel-key",
3494 strlen ("transport-backchannel-key"),
3499 gcry_cipher_open (&key->cipher,
3500 GCRY_CIPHER_AES256 /* low level: go for speed */,
3501 GCRY_CIPHER_MODE_CTR,
3503 gcry_cipher_setkey (key->cipher,
3504 &key->material.aes_key,
3505 sizeof (key->material.aes_key));
3506 gcry_cipher_setctr (key->cipher,
3507 &key->material.aes_ctr,
3508 sizeof (key->material.aes_ctr));
3513 * Derive backchannel encryption key material from @a priv_ephemeral
3514 * and @a target and @a iv.
3516 * @param priv_ephemeral ephemeral private key to use
3517 * @param target the target peer to encrypt to
3518 * @param iv unique IV to use
3519 * @param key[out] set to the key material
3522 dh_key_derive_eph_pid (
3523 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3524 const struct GNUNET_PeerIdentity *target,
3525 const struct GNUNET_ShortHashCode *iv,
3526 struct BackchannelKeyState *key)
3528 struct GNUNET_HashCode km;
3530 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3531 &target->public_key,
3533 bc_setup_key_state_from_km (&km, iv, key);
3538 * Derive backchannel encryption key material from #GST_my_private_key
3539 * and @a pub_ephemeral and @a iv.
3541 * @param priv_ephemeral ephemeral private key to use
3542 * @param target the target peer to encrypt to
3543 * @param iv unique IV to use
3544 * @param key[out] set to the key material
3547 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3548 const struct GNUNET_ShortHashCode *iv,
3549 struct BackchannelKeyState *key)
3551 struct GNUNET_HashCode km;
3553 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3556 bc_setup_key_state_from_km (&km, iv, key);
3561 * Do HMAC calculation for backchannel messages over @a data using key
3562 * material from @a key.
3564 * @param key key material (from DH)
3565 * @param hmac[out] set to the HMAC
3566 * @param data data to perform HMAC calculation over
3567 * @param data_size number of bytes in @a data
3570 bc_hmac (const struct BackchannelKeyState *key,
3571 struct GNUNET_HashCode *hmac,
3575 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
3580 * Perform backchannel encryption using symmetric secret in @a key
3581 * to encrypt data from @a in to @a dst.
3583 * @param key[in,out] key material to use
3584 * @param dst where to write the result
3585 * @param in input data to encrypt (plaintext)
3586 * @param in_size number of bytes of input in @a in and available at @a dst
3589 bc_encrypt (struct BackchannelKeyState *key,
3595 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
3600 * Perform backchannel encryption using symmetric secret in @a key
3601 * to encrypt data from @a in to @a dst.
3603 * @param key[in,out] key material to use
3604 * @param ciph cipher text to decrypt
3605 * @param out[out] output data to generate (plaintext)
3606 * @param out_size number of bytes of input in @a ciph and available in @a out
3609 bc_decrypt (struct BackchannelKeyState *key,
3615 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
3620 * Clean up key material in @a key.
3622 * @param key key material to clean up (memory must not be free'd!)
3625 bc_key_clean (struct BackchannelKeyState *key)
3627 gcry_cipher_close (key->cipher);
3628 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
3633 * Communicator requests backchannel transmission. Process the request.
3635 * @param cls the client
3636 * @param cb the send message that was sent
3639 handle_communicator_backchannel (
3641 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3643 struct TransportClient *tc = cls;
3644 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3645 struct GNUNET_TIME_Absolute ephemeral_validity;
3646 struct TransportBackchannelEncapsulationMessage *enc;
3647 struct TransportBackchannelRequestPayload ppay;
3648 struct BackchannelKeyState key;
3652 /* encapsulate and encrypt message */
3653 msize = ntohs (cb->header.size) - sizeof (*cb) +
3654 sizeof (struct TransportBackchannelRequestPayload);
3655 enc = GNUNET_malloc (sizeof (*enc) + msize);
3657 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3658 enc->header.size = htons (sizeof (*enc) + msize);
3659 enc->target = cb->pid;
3660 lookup_ephemeral (&cb->pid,
3662 &enc->ephemeral_key,
3664 &ephemeral_validity);
3665 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3668 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
3669 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3670 ppay.monotonic_time =
3671 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3672 mpos = (char *) &enc[1];
3673 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
3676 &mpos[sizeof (ppay)],
3677 ntohs (cb->header.size) - sizeof (*cb));
3681 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3682 bc_key_clean (&key);
3683 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
3684 GNUNET_SERVICE_client_continue (tc->client);
3689 * Address of our peer added. Test message is well-formed.
3691 * @param cls the client
3692 * @param aam the send message that was sent
3693 * @return #GNUNET_OK if message is well-formed
3696 check_add_address (void *cls,
3697 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3699 struct TransportClient *tc = cls;
3701 if (CT_COMMUNICATOR != tc->type)
3704 return GNUNET_SYSERR;
3706 GNUNET_MQ_check_zero_termination (aam);
3712 * Ask peerstore to store our address.
3714 * @param cls an `struct AddressListEntry *`
3717 store_pi (void *cls);
3721 * Function called when peerstore is done storing our address.
3723 * @param cls a `struct AddressListEntry`
3724 * @param success #GNUNET_YES if peerstore was successful
3727 peerstore_store_own_cb (void *cls, int success)
3729 struct AddressListEntry *ale = cls;
3732 if (GNUNET_YES != success)
3733 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3734 "Failed to store our own address `%s' in peerstore!\n",
3736 /* refresh period is 1/4 of expiration time, that should be plenty
3737 without being excessive. */
3739 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3747 * Ask peerstore to store our address.
3749 * @param cls an `struct AddressListEntry *`
3752 store_pi (void *cls)
3754 struct AddressListEntry *ale = cls;
3757 struct GNUNET_TIME_Absolute expiration;
3760 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3761 GNUNET_HELLO_sign_address (ale->address,
3767 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3770 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3774 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3775 &peerstore_store_own_cb,
3778 if (NULL == ale->sc)
3780 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3781 "Failed to store our address `%s' with peerstore\n",
3784 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
3790 * Address of our peer added. Process the request.
3792 * @param cls the client
3793 * @param aam the send message that was sent
3796 handle_add_address (void *cls,
3797 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3799 struct TransportClient *tc = cls;
3800 struct AddressListEntry *ale;
3803 slen = ntohs (aam->header.size) - sizeof (*aam);
3804 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3806 ale->address = (const char *) &ale[1];
3807 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3808 ale->aid = aam->aid;
3809 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3810 memcpy (&ale[1], &aam[1], slen);
3811 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3812 tc->details.communicator.addr_tail,
3814 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
3815 GNUNET_SERVICE_client_continue (tc->client);
3820 * Address of our peer deleted. Process the request.
3822 * @param cls the client
3823 * @param dam the send message that was sent
3826 handle_del_address (void *cls,
3827 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3829 struct TransportClient *tc = cls;
3831 if (CT_COMMUNICATOR != tc->type)
3834 GNUNET_SERVICE_client_drop (tc->client);
3837 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3841 if (dam->aid != ale->aid)
3843 GNUNET_assert (ale->tc == tc);
3844 free_address_list_entry (ale);
3845 GNUNET_SERVICE_client_continue (tc->client);
3848 GNUNET_SERVICE_client_drop (tc->client);
3853 * Context from #handle_incoming_msg(). Closure for many
3854 * message handlers below.
3856 struct CommunicatorMessageContext
3859 * Which communicator provided us with the message.
3861 struct TransportClient *tc;
3864 * Additional information for flow control and about the sender.
3866 struct GNUNET_TRANSPORT_IncomingMessage im;
3869 * Number of hops the message has travelled (if DV-routed).
3870 * FIXME: make use of this in ACK handling!
3872 uint16_t total_hops;
3877 * Given an inbound message @a msg from a communicator @a cmc,
3878 * demultiplex it based on the type calling the right handler.
3880 * @param cmc context for demultiplexing
3881 * @param msg message to demultiplex
3884 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3885 const struct GNUNET_MessageHeader *msg);
3889 * Send ACK to communicator (if requested) and free @a cmc.
3891 * @param cmc context for which we are done handling the message
3894 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3896 if (0 != ntohl (cmc->im.fc_on))
3898 /* send ACK when done to communicator for flow control! */
3899 struct GNUNET_MQ_Envelope *env;
3900 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3902 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3903 ack->reserved = htonl (0);
3904 ack->fc_id = cmc->im.fc_id;
3905 ack->sender = cmc->im.sender;
3906 GNUNET_MQ_send (cmc->tc->mq, env);
3908 GNUNET_SERVICE_client_continue (cmc->tc->client);
3914 * Communicator gave us an unencapsulated message to pass as-is to
3915 * CORE. Process the request.
3917 * @param cls a `struct CommunicatorMessageContext` (must call
3918 * #finish_cmc_handling() when done)
3919 * @param mh the message that was received
3922 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
3924 struct CommunicatorMessageContext *cmc = cls;
3925 uint16_t size = ntohs (mh->size);
3927 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
3928 (size < sizeof (struct GNUNET_MessageHeader)))
3930 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3933 finish_cmc_handling (cmc);
3934 GNUNET_SERVICE_client_drop (client);
3937 /* Forward to all CORE clients */
3938 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3940 struct GNUNET_MQ_Envelope *env;
3941 struct InboundMessage *im;
3943 if (CT_CORE != tc->type)
3945 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3946 im->peer = cmc->im.sender;
3947 memcpy (&im[1], mh, size);
3948 GNUNET_MQ_send (tc->mq, env);
3950 /* FIXME: consider doing this _only_ once the message
3951 was drained from the CORE MQs to extend flow control to CORE!
3952 (basically, increment counter in cmc, decrement on MQ send continuation! */
3953 finish_cmc_handling (cmc);
3958 * Communicator gave us a fragment box. Check the message.
3960 * @param cls a `struct CommunicatorMessageContext`
3961 * @param fb the send message that was sent
3962 * @return #GNUNET_YES if message is well-formed
3965 check_fragment_box (void *cls, const struct TransportFragmentBox *fb)
3967 uint16_t size = ntohs (fb->header.size);
3968 uint16_t bsize = size - sizeof (*fb);
3972 GNUNET_break_op (0);
3973 return GNUNET_SYSERR;
3975 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
3977 GNUNET_break_op (0);
3978 return GNUNET_SYSERR;
3980 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
3982 GNUNET_break_op (0);
3983 return GNUNET_SYSERR;
3990 * Generate a fragment acknowledgement for an @a rc.
3992 * @param rc context to generate ACK for, @a rc ACK state is reset
3995 send_fragment_ack (struct ReassemblyContext *rc)
3997 struct TransportFragmentAckMessage *ack;
3999 ack = GNUNET_new (struct TransportFragmentAckMessage);
4000 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
4001 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
4002 ack->frag_uuid = htonl (rc->frag_uuid);
4003 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
4004 ack->msg_uuid = rc->msg_uuid;
4005 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
4006 if (0 == rc->msg_missing)
4007 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4008 GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
4010 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4011 GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
4012 route_message (&rc->neighbour->pid, &ack->header, RMO_DV_ALLOWED);
4013 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
4015 rc->extra_acks = 0LLU;
4020 * Communicator gave us a fragment. Process the request.
4022 * @param cls a `struct CommunicatorMessageContext` (must call
4023 * #finish_cmc_handling() when done)
4024 * @param fb the message that was received
4027 handle_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4029 struct CommunicatorMessageContext *cmc = cls;
4030 struct Neighbour *n;
4031 struct ReassemblyContext *rc;
4032 const struct GNUNET_MessageHeader *msg;
4038 struct GNUNET_TIME_Relative cdelay;
4041 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4044 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4047 finish_cmc_handling (cmc);
4048 GNUNET_SERVICE_client_drop (client);
4051 if (NULL == n->reassembly_map)
4053 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_YES);
4054 n->reassembly_heap =
4055 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4056 n->reassembly_timeout_task =
4057 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4058 &reassembly_cleanup_task,
4061 msize = ntohs (fb->msg_size);
4062 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map, &fb->msg_uuid);
4065 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4066 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4067 rc->msg_uuid = fb->msg_uuid;
4069 rc->msg_size = msize;
4070 rc->reassembly_timeout =
4071 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4072 rc->last_frag = GNUNET_TIME_absolute_get ();
4073 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4075 rc->reassembly_timeout.abs_value_us);
4076 GNUNET_assert (GNUNET_OK ==
4077 GNUNET_CONTAINER_multishortmap_put (
4081 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4082 target = (char *) &rc[1];
4083 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4084 rc->msg_missing = rc->msg_size;
4088 target = (char *) &rc[1];
4090 if (msize != rc->msg_size)
4093 finish_cmc_handling (cmc);
4098 fsize = ntohs (fb->header.size) - sizeof (*fb);
4099 frag_off = ntohs (fb->frag_off);
4100 memcpy (&target[frag_off], &fb[1], fsize);
4101 /* update bitfield and msg_missing */
4102 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4104 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4106 rc->bitfield[i / 8] |= (1 << (i % 8));
4111 /* Compute cummulative ACK */
4112 frag_uuid = ntohl (fb->frag_uuid);
4113 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4114 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->num_acks);
4115 rc->last_frag = GNUNET_TIME_absolute_get ();
4116 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay, cdelay);
4117 ack_now = GNUNET_NO;
4118 if (0 == rc->num_acks)
4120 /* case one: first ack */
4121 rc->frag_uuid = frag_uuid;
4122 rc->extra_acks = 0LLU;
4125 else if ((frag_uuid >= rc->frag_uuid) && (frag_uuid <= rc->frag_uuid + 64))
4127 /* case two: ack fits after existing min UUID */
4128 if ((frag_uuid == rc->frag_uuid) ||
4129 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))))
4131 /* duplicate fragment, ack now! */
4132 ack_now = GNUNET_YES;
4136 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
4140 else if ((rc->frag_uuid > frag_uuid) &&
4141 (((rc->frag_uuid == frag_uuid + 64) && (0 == rc->extra_acks)) ||
4142 ((rc->frag_uuid < frag_uuid + 64) &&
4145 ~((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))))))
4147 /* can fit ack by shifting extra acks and starting at
4148 frag_uid, test above esured that the bits we will
4149 shift 'extra_acks' by are all zero. */
4150 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
4151 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
4152 rc->frag_uuid = frag_uuid;
4155 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very
4157 ack_now = GNUNET_YES; /* maximum acks received */
4158 // FIXME: possibly also ACK based on RTT (but for that we'd need to
4159 // determine the queue used for the ACK first!)
4161 /* is reassembly complete? */
4162 if (0 != rc->msg_missing)
4165 send_fragment_ack (rc);
4166 finish_cmc_handling (cmc);
4169 /* reassembly is complete, verify result */
4170 msg = (const struct GNUNET_MessageHeader *) &rc[1];
4171 if (ntohs (msg->size) != rc->msg_size)
4174 free_reassembly_context (rc);
4175 finish_cmc_handling (cmc);
4178 /* successful reassembly */
4179 send_fragment_ack (rc);
4180 demultiplex_with_cmc (cmc, msg);
4181 /* FIXME: really free here? Might be bad if fragments are still
4182 en-route and we forget that we finished this reassembly immediately!
4183 -> keep around until timeout?
4184 -> shorten timeout based on ACK? */
4185 free_reassembly_context (rc);
4190 * Check the @a fa against the fragments associated with @a pm.
4191 * If it matches, remove the matching fragments from the transmission
4194 * @param pm pending message to check against the ack
4195 * @param fa the ack that was received
4196 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4199 check_ack_against_pm (struct PendingMessage *pm,
4200 const struct TransportFragmentAckMessage *fa)
4203 struct PendingMessage *nxt;
4204 uint32_t fs = ntohl (fa->frag_uuid);
4205 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4208 for (struct PendingMessage *frag = pm->head_frag; NULL != frag; frag = nxt)
4210 const struct TransportFragmentBox *tfb =
4211 (const struct TransportFragmentBox *) &pm[1];
4212 uint32_t fu = ntohl (tfb->frag_uuid);
4214 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4215 nxt = frag->next_frag;
4216 /* Check for exact match or match in the 'xtra' bitmask */
4218 ((fu > fs) && (fu <= fs + 64) && (0 != (1LLU << (fu - fs - 1) & xtra))))
4221 free_fragment_tree (frag);
4229 * Communicator gave us a fragment acknowledgement. Process the request.
4231 * @param cls a `struct CommunicatorMessageContext` (must call
4232 * #finish_cmc_handling() when done)
4233 * @param fa the message that was received
4236 handle_fragment_ack (void *cls, const struct TransportFragmentAckMessage *fa)
4238 struct CommunicatorMessageContext *cmc = cls;
4239 struct Neighbour *n;
4242 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4245 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4248 finish_cmc_handling (cmc);
4249 GNUNET_SERVICE_client_drop (client);
4252 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4253 matched = GNUNET_NO;
4254 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm;
4255 pm = pm->prev_neighbour)
4257 if (0 != GNUNET_memcmp (&fa->msg_uuid, &pm->msg_uuid))
4259 matched = GNUNET_YES;
4260 if (GNUNET_YES == check_ack_against_pm (pm, fa))
4262 struct GNUNET_TIME_Relative avg_ack_delay =
4263 GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4264 // FIXME: update RTT and other reliability data!
4265 // ISSUE: we don't know which of n's queues the message(s)
4266 // took (and in fact the different messages might have gone
4267 // over different queues and possibly over multiple).
4268 // => track queues with PendingMessages, and update RTT only if
4269 // the queue used is unique?
4270 // -> how can we get loss rates?
4271 // -> or, add extra state to Box and ACK to identify queue?
4272 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4273 // the queue with the fragment! (-> this logic must
4274 // be moved into check_ack_against_pm!)
4275 (void) avg_ack_delay;
4279 GNUNET_STATISTICS_update (GST_stats,
4280 "# FRAGMENT_ACKS dropped, no matching fragment",
4284 if (NULL == pm->head_frag)
4286 // if entire message is ACKed, handle that as well.
4287 // => clean up PM, any post actions?
4288 free_pending_message (pm);
4292 struct GNUNET_TIME_Relative reassembly_timeout =
4293 GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4294 // OPTIMIZE-FIXME: adjust retransmission strategy based on
4295 // reassembly_timeout!
4296 (void) reassembly_timeout;
4300 if (GNUNET_NO == matched)
4302 GNUNET_STATISTICS_update (GST_stats,
4303 "# FRAGMENT_ACKS dropped, no matching pending message",
4307 finish_cmc_handling (cmc);
4312 * Communicator gave us a reliability box. Check the message.
4314 * @param cls a `struct CommunicatorMessageContext`
4315 * @param rb the send message that was sent
4316 * @return #GNUNET_YES if message is well-formed
4319 check_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4321 GNUNET_MQ_check_boxed_message (rb);
4327 * Communicator gave us a reliability box. Process the request.
4329 * @param cls a `struct CommunicatorMessageContext` (must call
4330 * #finish_cmc_handling() when done)
4331 * @param rb the message that was received
4334 handle_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4336 struct CommunicatorMessageContext *cmc = cls;
4337 const struct GNUNET_MessageHeader *inbox =
4338 (const struct GNUNET_MessageHeader *) &rb[1];
4340 if (0 == ntohl (rb->ack_countdown))
4342 struct TransportReliabilityAckMessage *ack;
4344 /* FIXME: implement cummulative ACKs and ack_countdown,
4345 then setting the avg_ack_delay field below: */
4346 ack = GNUNET_malloc (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4347 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4349 htons (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4350 memcpy (&ack[1], &rb->msg_uuid, sizeof (struct GNUNET_ShortHashCode));
4351 route_message (&cmc->im.sender, &ack->header, RMO_DV_ALLOWED);
4353 /* continue with inner message */
4354 demultiplex_with_cmc (cmc, inbox);
4359 * Communicator gave us a reliability ack. Process the request.
4361 * @param cls a `struct CommunicatorMessageContext` (must call
4362 * #finish_cmc_handling() when done)
4363 * @param ra the message that was received
4366 handle_reliability_ack (void *cls,
4367 const struct TransportReliabilityAckMessage *ra)
4369 struct CommunicatorMessageContext *cmc = cls;
4370 struct Neighbour *n;
4371 unsigned int n_acks;
4372 const struct GNUNET_ShortHashCode *msg_uuids;
4373 struct PendingMessage *nxt;
4376 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4379 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4382 finish_cmc_handling (cmc);
4383 GNUNET_SERVICE_client_drop (client);
4386 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
4387 sizeof (struct GNUNET_ShortHashCode);
4388 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4390 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4391 matched = GNUNET_NO;
4392 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm; pm = nxt)
4396 nxt = pm->next_neighbour;
4397 in_list = GNUNET_NO;
4398 for (unsigned int i = 0; i < n_acks; i++)
4400 if (0 != GNUNET_memcmp (&msg_uuids[i], &pm->msg_uuid))
4402 in_list = GNUNET_YES;
4405 if (GNUNET_NO == in_list)
4408 /* this pm was acked! */
4409 matched = GNUNET_YES;
4410 free_pending_message (pm);
4413 struct GNUNET_TIME_Relative avg_ack_delay =
4414 GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4415 // FIXME: update RTT and other reliability data!
4416 // ISSUE: we don't know which of n's queues the message(s)
4417 // took (and in fact the different messages might have gone
4418 // over different queues and possibly over multiple).
4419 // => track queues with PendingMessages, and update RTT only if
4420 // the queue used is unique?
4421 // -> how can we get loss rates?
4422 // -> or, add extra state to MSG and ACKs to identify queue?
4423 // -> if we do this, might just do the same for the avg_ack_delay!
4424 (void) avg_ack_delay;
4427 if (GNUNET_NO == matched)
4429 GNUNET_STATISTICS_update (GST_stats,
4430 "# FRAGMENT_ACKS dropped, no matching pending message",
4434 finish_cmc_handling (cmc);
4439 * Communicator gave us a backchannel encapsulation. Check the message.
4441 * @param cls a `struct CommunicatorMessageContext`
4442 * @param be the send message that was sent
4443 * @return #GNUNET_YES if message is well-formed
4446 check_backchannel_encapsulation (
4448 const struct TransportBackchannelEncapsulationMessage *be)
4450 uint16_t size = ntohs (be->header.size);
4453 if ((size - sizeof (*be)) <
4454 (sizeof (struct TransportBackchannelRequestPayload) +
4455 sizeof (struct GNUNET_MessageHeader)))
4457 GNUNET_break_op (0);
4458 return GNUNET_SYSERR;
4465 * Communicator gave us a backchannel encapsulation. Process the request.
4466 * (We are not the origin of the backchannel here, the communicator simply
4467 * received a backchannel message and we are expected to forward it.)
4469 * @param cls a `struct CommunicatorMessageContext` (must call
4470 * #finish_cmc_handling() when done)
4471 * @param be the message that was received
4474 handle_backchannel_encapsulation (
4476 const struct TransportBackchannelEncapsulationMessage *be)
4478 struct CommunicatorMessageContext *cmc = cls;
4479 struct BackchannelKeyState key;
4480 struct GNUNET_HashCode hmac;
4484 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
4486 /* not for me, try to route to target */
4487 /* FIXME: someone needs to update be->distance! */
4488 /* FIXME: BE routing can be special, should we put all of this
4489 on 'route_message'? Maybe at least pass some more arguments? */
4490 route_message (&be->target,
4491 GNUNET_copy_message (&be->header),
4493 finish_cmc_handling (cmc);
4496 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
4497 hdr = (const char *) &be[1];
4498 hdr_len = ntohs (be->header.size) - sizeof (*be);
4499 bc_hmac (&key, &hmac, hdr, hdr_len);
4500 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
4502 /* HMAC missmatch, disard! */
4503 GNUNET_break_op (0);
4504 finish_cmc_handling (cmc);
4507 /* begin actual decryption */
4509 struct TransportBackchannelRequestPayload ppay;
4510 char body[hdr_len - sizeof (ppay)];
4512 GNUNET_assert (hdr_len >=
4513 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4514 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
4515 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
4516 bc_key_clean (&key);
4517 // FIXME: verify signatures in ppay!
4518 // => check if ephemeral key is known & valid, if not
4519 // => verify sig, cache ephemeral key
4520 // => update monotonic_time of sender for replay detection
4522 // FIXME: forward to specified communicator!
4523 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4525 finish_cmc_handling (cmc);
4530 * Task called when we should check if any of the DV paths
4531 * we have learned to a target are due for garbage collection.
4533 * Collects stale paths, and possibly frees the entire DV
4534 * entry if no paths are left. Otherwise re-schedules itself.
4536 * @param cls a `struct DistanceVector`
4539 path_cleanup_cb (void *cls)
4541 struct DistanceVector *dv = cls;
4542 struct DistanceVectorHop *pos;
4544 dv->timeout_task = NULL;
4545 while (NULL != (pos = dv->dv_head))
4547 GNUNET_assert (dv == pos->dv);
4548 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4550 free_distance_vector_hop (pos);
4558 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
4563 * We have learned a @a path through the network to some other peer, add it to
4564 * our DV data structure (returning #GNUNET_YES on success).
4566 * We do not add paths if we have a sufficient number of shorter
4567 * paths to this target already (returning #GNUNET_NO).
4569 * We also do not add problematic paths, like those where we lack the first
4570 * hop in our neighbour list (i.e. due to a topology change) or where some
4571 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4573 * @param path the path we learned, path[0] should be us,
4574 * and then path contains a valid path from us to `path[path_len-1]`
4575 * path[1] should be a direct neighbour (we should check!)
4576 * @param path_len number of entries on the @a path, at least three!
4577 * @param network_latency how long does the message take from us to
4578 * `path[path_len-1]`? set to "forever" if unknown
4579 * @return #GNUNET_YES on success,
4580 * #GNUNET_NO if we have better path(s) to the target
4581 * #GNUNET_SYSERR if the path is useless and/or invalid
4582 * (i.e. path[1] not a direct neighbour
4583 * or path[i+1] is a direct neighbour for i>0)
4586 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4587 unsigned int path_len,
4588 struct GNUNET_TIME_Relative network_latency)
4590 struct DistanceVectorHop *hop;
4591 struct DistanceVector *dv;
4592 struct Neighbour *next_hop;
4593 unsigned int shorter_distance;
4597 /* what a boring path! not allowed! */
4599 return GNUNET_SYSERR;
4601 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
4602 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours, &path[1]);
4603 if (NULL == next_hop)
4605 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4607 return GNUNET_SYSERR;
4609 for (unsigned int i = 2; i < path_len; i++)
4610 if (NULL != GNUNET_CONTAINER_multipeermap_get (neighbours, &path[i]))
4612 /* Useless path, we have a direct connection to some hop
4613 in the middle of the path, so this one doesn't even
4614 seem terribly useful for redundancy */
4615 return GNUNET_SYSERR;
4617 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
4620 dv = GNUNET_new (struct DistanceVector);
4621 dv->target = path[path_len - 1];
4622 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4625 GNUNET_assert (GNUNET_OK ==
4626 GNUNET_CONTAINER_multipeermap_put (
4630 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4632 /* Check if we have this path already! */
4633 shorter_distance = 0;
4634 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4637 if (pos->distance < path_len - 2)
4639 /* Note that the distances in 'pos' excludes us (path[0]) and
4640 the next_hop (path[1]), so we need to subtract two
4641 and check next_hop explicitly */
4642 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
4644 int match = GNUNET_YES;
4646 for (unsigned int i = 0; i < pos->distance; i++)
4648 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
4654 if (GNUNET_YES == match)
4656 struct GNUNET_TIME_Relative last_timeout;
4658 /* Re-discovered known path, update timeout */
4659 GNUNET_STATISTICS_update (GST_stats,
4660 "# Known DV path refreshed",
4663 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4665 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4666 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
4667 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
4668 if (last_timeout.rel_value_us <
4669 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4670 DV_PATH_DISCOVERY_FREQUENCY)
4673 /* Some peer send DV learn messages too often, we are learning
4674 the same path faster than it would be useful; do not forward! */
4681 /* Count how many shorter paths we have (incl. direct
4682 neighbours) before simply giving up on this one! */
4683 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4685 /* We have a shorter path already! */
4688 /* create new DV path entry */
4689 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4690 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4691 hop->next_hop = next_hop;
4693 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4696 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4697 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4698 hop->distance = path_len - 2;
4699 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
4700 GNUNET_CONTAINER_MDLL_insert (neighbour,
4709 * Communicator gave us a DV learn message. Check the message.
4711 * @param cls a `struct CommunicatorMessageContext`
4712 * @param dvl the send message that was sent
4713 * @return #GNUNET_YES if message is well-formed
4716 check_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4718 uint16_t size = ntohs (dvl->header.size);
4719 uint16_t num_hops = ntohs (dvl->num_hops);
4720 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4723 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4725 GNUNET_break_op (0);
4726 return GNUNET_SYSERR;
4728 if (num_hops > MAX_DV_HOPS_ALLOWED)
4730 GNUNET_break_op (0);
4731 return GNUNET_SYSERR;
4733 for (unsigned int i = 0; i < num_hops; i++)
4735 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
4737 GNUNET_break_op (0);
4738 return GNUNET_SYSERR;
4740 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
4742 GNUNET_break_op (0);
4743 return GNUNET_SYSERR;
4751 * Build and forward a DV learn message to @a next_hop.
4753 * @param next_hop peer to send the message to
4754 * @param msg message received
4755 * @param bi_history bitmask specifying hops on path that were bidirectional
4756 * @param nhops length of the @a hops array
4757 * @param hops path the message traversed so far
4758 * @param in_time when did we receive the message, used to calculate network
4762 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4763 const struct TransportDVLearn *msg,
4764 uint16_t bi_history,
4766 const struct DVPathEntryP *hops,
4767 struct GNUNET_TIME_Absolute in_time)
4769 struct DVPathEntryP *dhops;
4770 struct TransportDVLearn *fwd;
4771 struct GNUNET_TIME_Relative nnd;
4773 /* compute message for forwarding */
4774 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4775 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4776 (nhops + 1) * sizeof (struct DVPathEntryP));
4777 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4778 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4779 (nhops + 1) * sizeof (struct DVPathEntryP));
4780 fwd->num_hops = htons (nhops + 1);
4781 fwd->bidirectional = htons (bi_history);
4782 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4783 GNUNET_TIME_relative_ntoh (
4784 msg->non_network_delay));
4785 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4786 fwd->init_sig = msg->init_sig;
4787 fwd->initiator = msg->initiator;
4788 fwd->challenge = msg->challenge;
4789 dhops = (struct DVPathEntryP *) &fwd[1];
4790 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
4791 dhops[nhops].hop = GST_my_identity;
4793 struct DvHopPS dhp = {.purpose.purpose =
4794 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4795 .purpose.size = htonl (sizeof (dhp)),
4796 .pred = dhops[nhops - 1].hop,
4798 .challenge = msg->challenge};
4800 GNUNET_assert (GNUNET_OK ==
4801 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4803 &dhops[nhops].hop_sig));
4805 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
4810 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4812 * @param init the signer
4813 * @param challenge the challenge that was signed
4814 * @param init_sig signature presumably by @a init
4815 * @return #GNUNET_OK if the signature is valid
4818 validate_dv_initiator_signature (
4819 const struct GNUNET_PeerIdentity *init,
4820 const struct GNUNET_ShortHashCode *challenge,
4821 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4823 struct DvInitPS ip = {.purpose.purpose = htonl (
4824 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4825 .purpose.size = htonl (sizeof (ip)),
4826 .challenge = *challenge};
4830 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4835 GNUNET_break_op (0);
4836 return GNUNET_SYSERR;
4843 * Communicator gave us a DV learn message. Process the request.
4845 * @param cls a `struct CommunicatorMessageContext` (must call
4846 * #finish_cmc_handling() when done)
4847 * @param dvl the message that was received
4850 handle_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4852 struct CommunicatorMessageContext *cmc = cls;
4853 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
4856 uint16_t bi_history;
4857 const struct DVPathEntryP *hops;
4860 struct GNUNET_TIME_Absolute in_time;
4862 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
4863 bi_history = ntohs (dvl->bidirectional);
4864 hops = (const struct DVPathEntryP *) &dvl[1];
4868 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
4871 finish_cmc_handling (cmc);
4878 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
4881 finish_cmc_handling (cmc);
4886 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
4887 cc = cmc->tc->details.communicator.cc;
4888 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
4889 cc); // FIXME: add bi-directional flag to cc?
4890 in_time = GNUNET_TIME_absolute_get ();
4892 /* continue communicator here, everything else can happen asynchronous! */
4893 finish_cmc_handling (cmc);
4895 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
4896 the initiator signature if we send the message back to the initiator... */
4897 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
4901 GNUNET_break_op (0);
4904 // FIXME: asynchronously (!) verify hop-by-hop signatures!
4905 // => if signature verification load too high, implement random drop
4908 do_fwd = GNUNET_YES;
4909 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
4911 struct GNUNET_PeerIdentity path[nhops + 1];
4912 struct GNUNET_TIME_Relative host_latency_sum;
4913 struct GNUNET_TIME_Relative latency;
4914 struct GNUNET_TIME_Relative network_latency;
4916 /* We initiated this, learn the forward path! */
4917 path[0] = GST_my_identity;
4918 path[1] = hops[0].hop;
4919 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
4921 // Need also something to lookup initiation time
4922 // to compute RTT! -> add RTT argument here?
4923 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
4924 // (based on dvl->challenge, we can identify time of origin!)
4926 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
4927 /* assumption: latency on all links is the same */
4928 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
4930 for (unsigned int i = 2; i <= nhops; i++)
4932 struct GNUNET_TIME_Relative ilat;
4934 /* assumption: linear latency increase per hop */
4935 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
4936 path[i] = hops[i - 1].hop;
4937 // FIXME: mark ALL of these as *confirmed* (with what timeout?)
4938 // -- and schedule a job for the confirmation to time out! --
4939 // and possibly do #cores_send_connect_info() if
4940 // the respective neighbour is NOT confirmed yet!
4941 learn_dv_path (path, i, ilat);
4943 /* as we initiated, do not forward again (would be circular!) */
4949 /* last hop was bi-directional, we could learn something here! */
4950 struct GNUNET_PeerIdentity path[nhops + 2];
4952 path[0] = GST_my_identity;
4953 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
4954 for (unsigned int i = 0; i < nhops; i++)
4958 if (0 == (bi_history & (1 << i)))
4959 break; /* i-th hop not bi-directional, stop learning! */
4962 path[i + 2] = dvl->initiator;
4966 path[i + 2] = hops[nhops - i - 2].hop;
4969 iret = learn_dv_path (path, i + 2, GNUNET_TIME_UNIT_FOREVER_REL);
4970 if (GNUNET_SYSERR == iret)
4972 /* path invalid or too long to be interesting for US, thus should also
4973 not be interesting to our neighbours, cut path when forwarding to
4974 'i' hops, except of course for the one that goes back to the
4976 GNUNET_STATISTICS_update (GST_stats,
4977 "# DV learn not forwarded due invalidity of path",
4983 if ((GNUNET_NO == iret) && (nhops == i + 1))
4985 /* we have better paths, and this is the longest target,
4986 so there cannot be anything interesting later */
4987 GNUNET_STATISTICS_update (GST_stats,
4988 "# DV learn not forwarded, got better paths",
4997 if (MAX_DV_HOPS_ALLOWED == nhops)
4999 /* At limit, we're out of here! */
5000 finish_cmc_handling (cmc);
5004 /* Forward to initiator, if path non-trivial and possible */
5005 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
5006 did_initiator = GNUNET_NO;
5009 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
5011 /* send back to origin! */
5012 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
5013 did_initiator = GNUNET_YES;
5015 /* We forward under two conditions: either we still learned something
5016 ourselves (do_fwd), or the path was darn short and thus the initiator is
5017 likely to still be very interested in this (and we did NOT already
5018 send it back to the initiator) */
5019 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
5020 (GNUNET_NO == did_initiator)))
5022 /* FIXME: loop over all neighbours, pick those with low
5023 queues AND that are not yet on the path; possibly
5024 adapt threshold to nhops! */
5026 forward_dv_learn (NULL, // fill in peer from iterator here!
5038 * Communicator gave us a DV box. Check the message.
5040 * @param cls a `struct CommunicatorMessageContext`
5041 * @param dvb the send message that was sent
5042 * @return #GNUNET_YES if message is well-formed
5045 check_dv_box (void *cls, const struct TransportDVBox *dvb)
5047 uint16_t size = ntohs (dvb->header.size);
5048 uint16_t num_hops = ntohs (dvb->num_hops);
5049 const struct GNUNET_PeerIdentity *hops =
5050 (const struct GNUNET_PeerIdentity *) &dvb[1];
5051 const struct GNUNET_MessageHeader *inbox =
5052 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5057 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
5058 sizeof (struct GNUNET_MessageHeader))
5060 GNUNET_break_op (0);
5061 return GNUNET_SYSERR;
5063 isize = ntohs (inbox->size);
5065 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
5067 GNUNET_break_op (0);
5068 return GNUNET_SYSERR;
5070 itype = ntohs (inbox->type);
5071 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
5072 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
5074 GNUNET_break_op (0);
5075 return GNUNET_SYSERR;
5077 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
5079 GNUNET_break_op (0);
5080 return GNUNET_SYSERR;
5087 * Create a DV Box message and queue it for transmission to
5090 * @param next_hop peer to receive the message next
5091 * @param total_hops how many hops did the message take so far
5092 * @param num_hops length of the @a hops array
5093 * @param origin origin of the message
5094 * @param hops next peer(s) to the destination, including destination
5095 * @param payload payload of the box
5096 * @param payload_size number of bytes in @a payload
5099 forward_dv_box (struct Neighbour *next_hop,
5100 uint16_t total_hops,
5102 const struct GNUNET_PeerIdentity *origin,
5103 const struct GNUNET_PeerIdentity *hops,
5104 const void *payload,
5105 uint16_t payload_size)
5107 struct TransportDVBox *dvb;
5108 struct GNUNET_PeerIdentity *dhops;
5110 GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBox) +
5111 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5113 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
5114 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5117 htons (sizeof (struct TransportDVBox) +
5118 sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size);
5119 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5120 dvb->total_hops = htons (total_hops);
5121 dvb->num_hops = htons (num_hops);
5122 dvb->origin = *origin;
5123 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5124 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
5125 memcpy (&dhops[num_hops], payload, payload_size);
5126 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
5131 * Communicator gave us a DV box. Process the request.
5133 * @param cls a `struct CommunicatorMessageContext` (must call
5134 * #finish_cmc_handling() when done)
5135 * @param dvb the message that was received
5138 handle_dv_box (void *cls, const struct TransportDVBox *dvb)
5140 struct CommunicatorMessageContext *cmc = cls;
5141 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5142 uint16_t num_hops = ntohs (dvb->num_hops);
5143 const struct GNUNET_PeerIdentity *hops =
5144 (const struct GNUNET_PeerIdentity *) &dvb[1];
5145 const struct GNUNET_MessageHeader *inbox =
5146 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5150 /* We're trying from the end of the hops array, as we may be
5151 able to find a shortcut unknown to the origin that way */
5152 for (int i = num_hops - 1; i >= 0; i--)
5154 struct Neighbour *n;
5156 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
5158 GNUNET_break_op (0);
5159 finish_cmc_handling (cmc);
5162 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &hops[i]);
5166 ntohs (dvb->total_hops) + 1,
5167 num_hops - i - 1, /* number of hops left */
5169 &hops[i + 1], /* remaining hops */
5170 (const void *) &dvb[1],
5172 finish_cmc_handling (cmc);
5175 /* Woopsie, next hop not in neighbours, drop! */
5176 GNUNET_STATISTICS_update (GST_stats,
5177 "# DV Boxes dropped: next hop unknown",
5180 finish_cmc_handling (cmc);
5183 /* We are the target. Unbox and handle message. */
5184 cmc->im.sender = dvb->origin;
5185 cmc->total_hops = ntohs (dvb->total_hops);
5186 demultiplex_with_cmc (cmc, inbox);
5191 * Client notified us about transmission from a peer. Process the request.
5193 * @param cls a `struct TransportClient` which sent us the message
5194 * @param obm the send message that was sent
5195 * @return #GNUNET_YES if message is well-formed
5198 check_incoming_msg (void *cls,
5199 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5201 struct TransportClient *tc = cls;
5203 if (CT_COMMUNICATOR != tc->type)
5206 return GNUNET_SYSERR;
5208 GNUNET_MQ_check_boxed_message (im);
5214 * Communicator gave us a transport address validation challenge. Process the
5217 * @param cls a `struct CommunicatorMessageContext` (must call
5218 * #finish_cmc_handling() when done)
5219 * @param tvc the message that was received
5222 handle_validation_challenge (void *cls,
5223 const struct TransportValidationChallenge *tvc)
5225 struct CommunicatorMessageContext *cmc = cls;
5226 struct TransportValidationResponse *tvr;
5228 if (cmc->total_hops > 0)
5230 /* DV routing is not allowed for validation challenges! */
5231 GNUNET_break_op (0);
5232 finish_cmc_handling (cmc);
5235 tvr = GNUNET_new (struct TransportValidationResponse);
5237 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5238 tvr->header.size = htons (sizeof (*tvr));
5239 tvr->challenge = tvc->challenge;
5240 tvr->origin_time = tvc->sender_time;
5241 tvr->validity_duration = cmc->im.expected_address_validity;
5243 /* create signature */
5244 struct TransportValidationPS tvp =
5245 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5246 .purpose.size = htonl (sizeof (tvp)),
5247 .validity_duration = tvr->validity_duration,
5248 .challenge = tvc->challenge};
5250 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5254 route_message (&cmc->im.sender,
5256 RMO_ANYTHING_GOES | RMO_REDUNDANT);
5257 finish_cmc_handling (cmc);
5262 * Closure for #check_known_challenge.
5264 struct CheckKnownChallengeContext
5267 * Set to the challenge we are looking for.
5269 const struct GNUNET_ShortHashCode *challenge;
5272 * Set to a matching validation state, if one was found.
5274 struct ValidationState *vs;
5279 * Test if the validation state in @a value matches the
5280 * challenge from @a cls.
5282 * @param cls a `struct CheckKnownChallengeContext`
5283 * @param pid unused (must match though)
5284 * @param value a `struct ValidationState`
5285 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5288 check_known_challenge (void *cls,
5289 const struct GNUNET_PeerIdentity *pid,
5292 struct CheckKnownChallengeContext *ckac = cls;
5293 struct ValidationState *vs = value;
5296 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
5304 * Function called when peerstore is done storing a
5305 * validated address.
5307 * @param cls a `struct ValidationState`
5308 * @param success #GNUNET_YES on success
5311 peerstore_store_validation_cb (void *cls, int success)
5313 struct ValidationState *vs = cls;
5316 if (GNUNET_YES == success)
5318 GNUNET_STATISTICS_update (GST_stats,
5319 "# Peerstore failed to store foreign address",
5326 * Task run periodically to validate some address based on #validation_heap.
5331 validation_start_cb (void *cls);
5335 * Set the time for next_challenge of @a vs to @a new_time.
5336 * Updates the heap and if necessary reschedules the job.
5338 * @param vs validation state to update
5339 * @param new_time new time for revalidation
5342 update_next_challenge_time (struct ValidationState *vs,
5343 struct GNUNET_TIME_Absolute new_time)
5345 struct GNUNET_TIME_Relative delta;
5347 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5348 return; /* be lazy */
5349 vs->next_challenge = new_time;
5352 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
5354 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
5355 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5356 (NULL != validation_task))
5358 if (NULL != validation_task)
5359 GNUNET_SCHEDULER_cancel (validation_task);
5360 /* randomize a bit */
5361 delta.rel_value_us =
5362 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5363 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5364 new_time = GNUNET_TIME_absolute_add (new_time, delta);
5366 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
5371 * Find the queue matching @a pid and @a address.
5373 * @param pid peer the queue must go to
5374 * @param address address the queue must use
5375 * @return NULL if no such queue exists
5377 static struct Queue *
5378 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
5380 struct Neighbour *n;
5382 n = GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
5385 for (struct Queue *pos = n->queue_head; NULL != pos;
5386 pos = pos->next_neighbour)
5388 if (0 == strcmp (pos->address, address))
5396 * Task run periodically to check whether the validity of the given queue has
5397 * run its course. If so, finds either another queue to take over, or clears
5398 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
5399 * chance to take over, and if that fails, notifies CORE about the disconnect.
5401 * @param cls a `struct Queue`
5404 core_queue_visibility_check (void *cls)
5406 struct Queue *q = cls;
5408 q->visibility_task = NULL;
5409 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5411 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5412 &core_queue_visibility_check,
5416 update_neighbour_core_visibility (q->neighbour);
5421 * Check whether the CORE visibility of @a n should change. Finds either a
5422 * queue to preserve the visibility, or clears the neighbour's `core_visible`
5423 * flag. In the latter case, gives DV routes a chance to take over, and if
5424 * that fails, notifies CORE about the disconnect. If so, check whether we
5425 * need to notify CORE.
5427 * @param n neighbour to perform the check for
5430 update_neighbour_core_visibility (struct Neighbour *n)
5432 struct DistanceVector *dv;
5434 GNUNET_assert (GNUNET_YES == n->core_visible);
5435 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
5436 the #core_queue_visibility_check() task for that queue */
5437 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
5440 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5442 /* found a valid queue, use this one */
5443 q->visibility_task =
5444 GNUNET_SCHEDULER_add_at (q->validated_until,
5445 &core_queue_visibility_check,
5450 n->core_visible = GNUNET_NO;
5452 /* Check if _any_ DV route to this neighbour is currently
5453 valid, if so, do NOT tell core about the loss of direct
5454 connectivity (DV still counts!) */
5455 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
5456 if (GNUNET_YES == dv->core_visible)
5458 /* Nothing works anymore, need to tell CORE about the loss of
5460 cores_send_disconnect_info (&n->pid);
5465 * Communicator gave us a transport address validation response. Process the
5468 * @param cls a `struct CommunicatorMessageContext` (must call
5469 * #finish_cmc_handling() when done)
5470 * @param tvr the message that was received
5473 handle_validation_response (void *cls,
5474 const struct TransportValidationResponse *tvr)
5476 struct CommunicatorMessageContext *cmc = cls;
5477 struct ValidationState *vs;
5478 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
5480 struct GNUNET_TIME_Absolute origin_time;
5482 struct DistanceVector *dv;
5484 /* check this is one of our challenges */
5485 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5487 &check_known_challenge,
5489 if (NULL == (vs = ckac.vs))
5491 /* This can happen simply if we 'forgot' the challenge by now,
5492 i.e. because we received the validation response twice */
5493 GNUNET_STATISTICS_update (GST_stats,
5494 "# Validations dropped, challenge unknown",
5497 finish_cmc_handling (cmc);
5501 /* sanity check on origin time */
5502 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
5503 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
5504 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
5506 GNUNET_break_op (0);
5507 finish_cmc_handling (cmc);
5512 /* check signature */
5513 struct TransportValidationPS tvp =
5514 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5515 .purpose.size = htonl (sizeof (tvp)),
5516 .validity_duration = tvr->validity_duration,
5517 .challenge = tvr->challenge};
5521 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
5524 &cmc->im.sender.public_key))
5526 GNUNET_break_op (0);
5527 finish_cmc_handling (cmc);
5532 /* validity is capped by our willingness to keep track of the
5533 validation entry and the maximum the other peer allows */
5534 vs->valid_until = GNUNET_TIME_relative_to_absolute (
5535 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
5536 tvr->validity_duration),
5537 MAX_ADDRESS_VALID_UNTIL));
5538 vs->validated_until =
5539 GNUNET_TIME_absolute_min (vs->valid_until,
5540 GNUNET_TIME_relative_to_absolute (
5541 ADDRESS_VALIDATION_LIFETIME));
5542 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
5543 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
5544 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5546 sizeof (vs->challenge));
5547 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
5548 vs->validated_until,
5549 GNUNET_TIME_relative_multiply (vs->validation_rtt,
5550 VALIDATION_RTT_BUFFER_FACTOR));
5551 vs->last_challenge_use =
5552 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
5553 update_next_challenge_time (vs, vs->first_challenge_use);
5554 vs->sc = GNUNET_PEERSTORE_store (peerstore,
5557 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
5559 strlen (vs->address) + 1,
5561 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5562 &peerstore_store_validation_cb,
5564 finish_cmc_handling (cmc);
5566 /* Finally, we now possibly have a confirmed (!) working queue,
5567 update queue status (if queue still is around) */
5568 q = find_queue (&vs->pid, vs->address);
5571 GNUNET_STATISTICS_update (GST_stats,
5572 "# Queues lost at time of successful validation",
5577 q->validated_until = vs->validated_until;
5578 q->rtt = vs->validation_rtt;
5579 if (GNUNET_NO != q->neighbour->core_visible)
5580 return; /* nothing changed, we are done here */
5581 q->neighbour->core_visible = GNUNET_YES;
5582 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5583 &core_queue_visibility_check,
5585 /* Check if _any_ DV route to this neighbour is
5586 currently valid, if so, do NOT tell core anything! */
5587 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &q->neighbour->pid);
5588 if (GNUNET_YES == dv->core_visible)
5589 return; /* nothing changed, done */
5590 /* We lacked a confirmed connection to the neighbour
5591 before, so tell CORE about it (finally!) */
5592 cores_send_connect_info (&q->neighbour->pid, GNUNET_BANDWIDTH_ZERO);
5597 * Incoming meessage. Process the request.
5599 * @param im the send message that was received
5602 handle_incoming_msg (void *cls,
5603 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5605 struct TransportClient *tc = cls;
5606 struct CommunicatorMessageContext *cmc =
5607 GNUNET_new (struct CommunicatorMessageContext);
5611 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
5616 * Given an inbound message @a msg from a communicator @a cmc,
5617 * demultiplex it based on the type calling the right handler.
5619 * @param cmc context for demultiplexing
5620 * @param msg message to demultiplex
5623 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5624 const struct GNUNET_MessageHeader *msg)
5626 struct GNUNET_MQ_MessageHandler handlers[] =
5627 {GNUNET_MQ_hd_var_size (fragment_box,
5628 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
5629 struct TransportFragmentBox,
5631 GNUNET_MQ_hd_fixed_size (fragment_ack,
5632 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
5633 struct TransportFragmentAckMessage,
5635 GNUNET_MQ_hd_var_size (reliability_box,
5636 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5637 struct TransportReliabilityBox,
5639 GNUNET_MQ_hd_fixed_size (reliability_ack,
5640 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5641 struct TransportReliabilityAckMessage,
5643 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5644 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5645 struct TransportBackchannelEncapsulationMessage,
5647 GNUNET_MQ_hd_var_size (dv_learn,
5648 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5649 struct TransportDVLearn,
5651 GNUNET_MQ_hd_var_size (dv_box,
5652 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5653 struct TransportDVBox,
5655 GNUNET_MQ_hd_fixed_size (
5656 validation_challenge,
5657 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5658 struct TransportValidationChallenge,
5660 GNUNET_MQ_hd_fixed_size (
5661 validation_response,
5662 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5663 struct TransportValidationResponse,
5665 GNUNET_MQ_handler_end ()};
5668 ret = GNUNET_MQ_handle_message (handlers, msg);
5669 if (GNUNET_SYSERR == ret)
5672 GNUNET_SERVICE_client_drop (cmc->tc->client);
5676 if (GNUNET_NO == ret)
5678 /* unencapsulated 'raw' message */
5679 handle_raw_message (&cmc, msg);
5685 * New queue became available. Check message.
5687 * @param cls the client
5688 * @param aqm the send message that was sent
5691 check_add_queue_message (void *cls,
5692 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5694 struct TransportClient *tc = cls;
5696 if (CT_COMMUNICATOR != tc->type)
5699 return GNUNET_SYSERR;
5701 GNUNET_MQ_check_zero_termination (aqm);
5707 * Bandwidth tracker informs us that the delay until we should receive
5710 * @param cls a `struct Queue` for which the delay changed
5713 tracker_update_in_cb (void *cls)
5715 struct Queue *queue = cls;
5716 struct GNUNET_TIME_Relative in_delay;
5719 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5720 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
5721 // FIXME: how exactly do we do inbound flow control?
5726 * If necessary, generates the UUID for a @a pm
5728 * @param pm pending message to generate UUID for.
5731 set_pending_message_uuid (struct PendingMessage *pm)
5733 if (pm->msg_uuid_set)
5735 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5737 sizeof (pm->msg_uuid));
5738 pm->msg_uuid_set = GNUNET_YES;
5743 * Fragment the given @a pm to the given @a mtu. Adds
5744 * additional fragments to the neighbour as well. If the
5745 * @a mtu is too small, generates and error for the @a pm
5748 * @param pm pending message to fragment for transmission
5749 * @param mtu MTU to apply
5750 * @return new message to transmit
5752 static struct PendingMessage *
5753 fragment_message (struct PendingMessage *pm, uint16_t mtu)
5755 struct PendingMessage *ff;
5757 set_pending_message_uuid (pm);
5759 /* This invariant is established in #handle_add_queue_message() */
5760 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5762 /* select fragment for transmission, descending the tree if it has
5763 been expanded until we are at a leaf or at a fragment that is small enough
5766 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
5767 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
5769 ff = ff->head_frag; /* descent into fragmented fragments */
5772 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
5774 /* Did not yet calculate all fragments, calculate next fragment */
5775 struct PendingMessage *frag;
5776 struct TransportFragmentBox tfb;
5784 orig = (const char *) &ff[1];
5785 msize = ff->bytes_msg;
5788 const struct TransportFragmentBox *tfbo;
5790 tfbo = (const struct TransportFragmentBox *) orig;
5791 orig += sizeof (struct TransportFragmentBox);
5792 msize -= sizeof (struct TransportFragmentBox);
5793 xoff = ntohs (tfbo->frag_off);
5795 fragmax = mtu - sizeof (struct TransportFragmentBox);
5796 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
5797 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5798 sizeof (struct TransportFragmentBox) + fragsize);
5799 frag->target = pm->target;
5800 frag->frag_parent = ff;
5801 frag->timeout = pm->timeout;
5802 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5803 frag->pmt = PMT_FRAGMENT_BOX;
5804 msg = (char *) &frag[1];
5805 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
5806 tfb.header.size = htons (sizeof (struct TransportFragmentBox) + fragsize);
5807 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
5808 tfb.msg_uuid = pm->msg_uuid;
5809 tfb.frag_off = htons (ff->frag_off + xoff);
5810 tfb.msg_size = htons (pm->bytes_msg);
5811 memcpy (msg, &tfb, sizeof (tfb));
5812 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
5813 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
5814 ff->frag_off += fragsize;
5818 /* Move head to the tail and return it */
5819 GNUNET_CONTAINER_MDLL_remove (frag,
5820 ff->frag_parent->head_frag,
5821 ff->frag_parent->tail_frag,
5823 GNUNET_CONTAINER_MDLL_insert_tail (frag,
5824 ff->frag_parent->head_frag,
5825 ff->frag_parent->tail_frag,
5832 * Reliability-box the given @a pm. On error (can there be any), NULL
5833 * may be returned, otherwise the "replacement" for @a pm (which
5834 * should then be added to the respective neighbour's queue instead of
5835 * @a pm). If the @a pm is already fragmented or reliability boxed,
5836 * or itself an ACK, this function simply returns @a pm.
5838 * @param pm pending message to box for transmission over unreliabile queue
5839 * @return new message to transmit
5841 static struct PendingMessage *
5842 reliability_box_message (struct PendingMessage *pm)
5844 struct TransportReliabilityBox rbox;
5845 struct PendingMessage *bpm;
5848 if (PMT_CORE != pm->pmt)
5849 return pm; /* already fragmented or reliability boxed, or control message:
5851 if (NULL != pm->bpm)
5852 return pm->bpm; /* already computed earlier: do nothing */
5853 GNUNET_assert (NULL == pm->head_frag);
5854 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
5858 client_send_response (pm, GNUNET_NO, 0);
5861 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
5863 bpm->target = pm->target;
5864 bpm->frag_parent = pm;
5865 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
5866 bpm->timeout = pm->timeout;
5867 bpm->pmt = PMT_RELIABILITY_BOX;
5868 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
5869 set_pending_message_uuid (bpm);
5870 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
5871 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
5872 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
5873 rbox.msg_uuid = pm->msg_uuid;
5874 msg = (char *) &bpm[1];
5875 memcpy (msg, &rbox, sizeof (rbox));
5876 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
5883 * We believe we are ready to transmit a message on a queue. Double-checks
5884 * with the queue's "tracker_out" and then gives the message to the
5885 * communicator for transmission (updating the tracker, and re-scheduling
5886 * itself if applicable).
5888 * @param cls the `struct Queue` to process transmissions for
5891 transmit_on_queue (void *cls)
5893 struct Queue *queue = cls;
5894 struct Neighbour *n = queue->neighbour;
5895 struct PendingMessage *pm;
5896 struct PendingMessage *s;
5899 queue->transmit_task = NULL;
5900 if (NULL == (pm = n->pending_msg_head))
5902 /* no message pending, nothing to do here! */
5905 schedule_transmit_on_queue (queue);
5906 if (NULL != queue->transmit_task)
5907 return; /* do it later */
5909 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5910 overhead += sizeof (struct TransportReliabilityBox);
5912 if ( ( (0 != queue->mtu) &&
5913 (pm->bytes_msg + overhead > queue->mtu) ) ||
5914 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
5915 (NULL != pm->head_frag /* fragments already exist, should
5916 respect that even if MTU is 0 for
5918 s = fragment_message (s,
5921 sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
5925 /* Fragmentation failed, try next message... */
5926 schedule_transmit_on_queue (queue);
5929 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5930 s = reliability_box_message (s);
5933 /* Reliability boxing failed, try next message... */
5934 schedule_transmit_on_queue (queue);
5938 /* Pass 's' for transission to the communicator */
5939 queue_send_msg (queue, s, &s[1], s->bytes_msg);
5940 // FIXME: do something similar to the logic below
5941 // in defragmentation / reliability ACK handling!
5943 /* Check if this transmission somehow conclusively finished handing 'pm'
5944 even without any explicit ACKs */
5945 if ((PMT_CORE == s->pmt) &&
5946 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
5948 /* Full message sent, and over reliabile channel */
5949 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
5951 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
5952 queue->tc->details.communicator.cc) &&
5953 (PMT_FRAGMENT_BOX == s->pmt))
5955 struct PendingMessage *pos;
5957 /* Fragment sent over reliabile channel */
5958 free_fragment_tree (s);
5959 pos = s->frag_parent;
5960 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
5962 /* check if subtree is done */
5963 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5967 pos = s->frag_parent;
5968 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
5972 /* Was this the last applicable fragmment? */
5973 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
5974 client_send_response (
5977 pm->bytes_msg /* FIXME: calculate and add overheads! */);
5979 else if (PMT_CORE != pm->pmt)
5981 /* This was an acknowledgement of some type, always free */
5982 free_pending_message (pm);
5986 /* message not finished, waiting for acknowledgement */
5987 struct Neighbour *neighbour = pm->target;
5988 /* Update time by which we might retransmit 's' based on queue
5989 characteristics (i.e. RTT); it takes one RTT for the message to
5990 arrive and the ACK to come back in the best case; but the other
5991 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
5992 retransmitting. Note that in the future this heuristic should
5993 likely be improved further (measure RTT stability, consider
5994 message urgency and size when delaying ACKs, etc.) */
5995 s->next_attempt = GNUNET_TIME_relative_to_absolute (
5996 GNUNET_TIME_relative_multiply (queue->rtt, 4));
5999 struct PendingMessage *pos;
6001 /* re-insert sort in neighbour list */
6002 GNUNET_CONTAINER_MDLL_remove (neighbour,
6003 neighbour->pending_msg_head,
6004 neighbour->pending_msg_tail,
6006 pos = neighbour->pending_msg_tail;
6007 while ((NULL != pos) &&
6008 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6009 pos = pos->prev_neighbour;
6010 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
6011 neighbour->pending_msg_head,
6012 neighbour->pending_msg_tail,
6018 /* re-insert sort in fragment list */
6019 struct PendingMessage *fp = s->frag_parent;
6020 struct PendingMessage *pos;
6022 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, s);
6023 pos = fp->tail_frag;
6024 while ((NULL != pos) &&
6025 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6026 pos = pos->prev_frag;
6027 GNUNET_CONTAINER_MDLL_insert_after (frag,
6035 /* finally, re-schedule queue transmission task itself */
6036 schedule_transmit_on_queue (queue);
6041 * Bandwidth tracker informs us that the delay until we
6042 * can transmit again changed.
6044 * @param cls a `struct Queue` for which the delay changed
6047 tracker_update_out_cb (void *cls)
6049 struct Queue *queue = cls;
6050 struct Neighbour *n = queue->neighbour;
6052 if (NULL == n->pending_msg_head)
6054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6055 "Bandwidth allocation updated for empty transmission queue `%s'\n",
6057 return; /* no message pending, nothing to do here! */
6059 GNUNET_SCHEDULER_cancel (queue->transmit_task);
6060 queue->transmit_task = NULL;
6061 schedule_transmit_on_queue (queue);
6066 * Bandwidth tracker informs us that excessive outbound bandwidth was
6067 * allocated which is not being used.
6069 * @param cls a `struct Queue` for which the excess was noted
6072 tracker_excess_out_cb (void *cls)
6076 /* FIXME: trigger excess bandwidth report to core? Right now,
6077 this is done internally within transport_api2_core already,
6078 but we probably want to change the logic and trigger it
6079 from here via a message instead! */
6080 /* TODO: maybe inform someone at this point? */
6081 GNUNET_STATISTICS_update (GST_stats,
6082 "# Excess outbound bandwidth reported",
6089 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
6090 * which is not being used.
6092 * @param cls a `struct Queue` for which the excess was noted
6095 tracker_excess_in_cb (void *cls)
6099 /* TODO: maybe inform somone at this point? */
6100 GNUNET_STATISTICS_update (GST_stats,
6101 "# Excess inbound bandwidth reported",
6108 * Queue to a peer went down. Process the request.
6110 * @param cls the client
6111 * @param dqm the send message that was sent
6114 handle_del_queue_message (void *cls,
6115 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
6117 struct TransportClient *tc = cls;
6119 if (CT_COMMUNICATOR != tc->type)
6122 GNUNET_SERVICE_client_drop (tc->client);
6125 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6126 queue = queue->next_client)
6128 struct Neighbour *neighbour = queue->neighbour;
6130 if ((dqm->qid != queue->qid) ||
6131 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
6134 GNUNET_SERVICE_client_continue (tc->client);
6138 GNUNET_SERVICE_client_drop (tc->client);
6143 * Message was transmitted. Process the request.
6145 * @param cls the client
6146 * @param sma the send message that was sent
6149 handle_send_message_ack (void *cls,
6150 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
6152 struct TransportClient *tc = cls;
6153 struct QueueEntry *qe;
6155 if (CT_COMMUNICATOR != tc->type)
6158 GNUNET_SERVICE_client_drop (tc->client);
6162 /* find our queue entry matching the ACK */
6164 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6165 queue = queue->next_client)
6167 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
6169 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
6172 if (qep->mid != sma->mid)
6181 /* this should never happen */
6183 GNUNET_SERVICE_client_drop (tc->client);
6186 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6187 qe->queue->queue_tail,
6189 qe->queue->queue_length--;
6190 tc->details.communicator.total_queue_length--;
6191 GNUNET_SERVICE_client_continue (tc->client);
6193 /* if applicable, resume transmissions that waited on ACK */
6194 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
6195 tc->details.communicator.total_queue_length)
6197 /* Communicator dropped below threshold, resume all queues */
6198 GNUNET_STATISTICS_update (
6200 "# Transmission throttled due to communicator queue limit",
6203 for (struct Queue *queue = tc->details.communicator.queue_head;
6205 queue = queue->next_client)
6206 schedule_transmit_on_queue (queue);
6208 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6210 /* queue dropped below threshold; only resume this one queue */
6211 GNUNET_STATISTICS_update (GST_stats,
6212 "# Transmission throttled due to queue queue limit",
6215 schedule_transmit_on_queue (qe->queue);
6218 /* TODO: we also should react on the status! */
6219 // FIXME: this probably requires queue->pm = s assignment!
6220 // FIXME: react to communicator status about transmission request. We got:
6221 sma->status; // OK success, SYSERR failure
6228 * Iterator telling new MONITOR client about all existing
6231 * @param cls the new `struct TransportClient`
6232 * @param pid a connected peer
6233 * @param value the `struct Neighbour` with more information
6234 * @return #GNUNET_OK (continue to iterate)
6237 notify_client_queues (void *cls,
6238 const struct GNUNET_PeerIdentity *pid,
6241 struct TransportClient *tc = cls;
6242 struct Neighbour *neighbour = value;
6244 GNUNET_assert (CT_MONITOR == tc->type);
6245 for (struct Queue *q = neighbour->queue_head; NULL != q;
6246 q = q->next_neighbour)
6248 struct MonitorEvent me = {.rtt = q->rtt,
6250 .num_msg_pending = q->num_msg_pending,
6251 .num_bytes_pending = q->num_bytes_pending};
6253 notify_monitor (tc, pid, q->address, q->nt, &me);
6260 * Initialize a monitor client.
6262 * @param cls the client
6263 * @param start the start message that was sent
6266 handle_monitor_start (void *cls,
6267 const struct GNUNET_TRANSPORT_MonitorStart *start)
6269 struct TransportClient *tc = cls;
6271 if (CT_NONE != tc->type)
6274 GNUNET_SERVICE_client_drop (tc->client);
6277 tc->type = CT_MONITOR;
6278 tc->details.monitor.peer = start->peer;
6279 tc->details.monitor.one_shot = ntohl (start->one_shot);
6280 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
6281 GNUNET_SERVICE_client_mark_monitor (tc->client);
6282 GNUNET_SERVICE_client_continue (tc->client);
6287 * Find transport client providing communication service
6288 * for the protocol @a prefix.
6290 * @param prefix communicator name
6291 * @return NULL if no such transport client is available
6293 static struct TransportClient *
6294 lookup_communicator (const char *prefix)
6296 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6298 if (CT_COMMUNICATOR != tc->type)
6300 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
6304 GNUNET_ERROR_TYPE_WARNING,
6305 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6312 * Signature of a function called with a communicator @a address of a peer
6313 * @a pid that an application wants us to connect to.
6315 * @param pid target peer
6316 * @param address the address to try
6319 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
6321 static uint32_t idgen;
6322 struct TransportClient *tc;
6324 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6325 struct GNUNET_MQ_Envelope *env;
6328 prefix = GNUNET_HELLO_address_to_prefix (address);
6331 GNUNET_break (0); /* We got an invalid address!? */
6334 tc = lookup_communicator (prefix);
6337 GNUNET_STATISTICS_update (GST_stats,
6338 "# Suggestions ignored due to missing communicator",
6343 /* forward suggestion for queue creation to communicator */
6344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6345 "Request #%u for `%s' communicator to create queue to `%s'\n",
6346 (unsigned int) idgen,
6349 alen = strlen (address) + 1;
6351 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6352 cqm->request_id = htonl (idgen++);
6353 cqm->receiver = *pid;
6354 memcpy (&cqm[1], address, alen);
6355 GNUNET_MQ_send (tc->mq, env);
6360 * The queue @a q (which matches the peer and address in @a vs) is
6361 * ready for queueing. We should now queue the validation request.
6363 * @param q queue to send on
6364 * @param vs state to derive validation challenge from
6367 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
6369 struct TransportValidationChallenge tvc;
6371 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6373 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6374 tvc.header.size = htons (sizeof (tvc));
6375 tvc.reserved = htonl (0);
6376 tvc.challenge = vs->challenge;
6377 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6378 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
6383 * Task run periodically to validate some address based on #validation_heap.
6388 validation_start_cb (void *cls)
6390 struct ValidationState *vs;
6394 validation_task = NULL;
6395 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6396 /* drop validations past their expiration */
6399 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
6401 free_validation_state (vs);
6402 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6405 return; /* woopsie, no more addresses known, should only
6406 happen if we're really a lonely peer */
6407 q = find_queue (&vs->pid, vs->address);
6410 vs->awaiting_queue = GNUNET_YES;
6411 suggest_to_connect (&vs->pid, vs->address);
6414 validation_transmit_on_queue (q, vs);
6415 /* Finally, reschedule next attempt */
6416 vs->challenge_backoff =
6417 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
6418 MAX_VALIDATION_CHALLENGE_FREQ);
6419 update_next_challenge_time (vs,
6420 GNUNET_TIME_relative_to_absolute (
6421 vs->challenge_backoff));
6426 * Closure for #check_connection_quality.
6428 struct QueueQualityContext
6431 * Set to the @e k'th queue encountered.
6436 * Set to the number of quality queues encountered.
6438 unsigned int quality_count;
6441 * Set to the total number of queues encountered.
6443 unsigned int num_queues;
6446 * Decremented for each queue, for selection of the
6447 * k-th queue in @e q.
6454 * Check whether any queue to the given neighbour is
6455 * of a good "quality" and if so, increment the counter.
6456 * Also counts the total number of queues, and returns
6457 * the k-th queue found.
6459 * @param cls a `struct QueueQualityContext *` with counters
6460 * @param pid peer this is about
6461 * @param value a `struct Neighbour`
6462 * @return #GNUNET_OK (continue to iterate)
6465 check_connection_quality (void *cls,
6466 const struct GNUNET_PeerIdentity *pid,
6469 struct QueueQualityContext *ctx = cls;
6470 struct Neighbour *n = value;
6475 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6477 if (0 != q->distance)
6478 continue; /* DV does not count */
6482 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
6483 statistics and consider those as well here? */
6484 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
6485 do_inc = GNUNET_YES;
6487 if (GNUNET_YES == do_inc)
6488 ctx->quality_count++;
6494 * Task run when we CONSIDER initiating a DV learn
6495 * process. We first check that sending out a message is
6496 * even possible (queues exist), then that it is desirable
6497 * (if not, reschedule the task for later), and finally
6498 * we may then begin the job. If there are too many
6499 * entries in the #dvlearn_map, we purge the oldest entry
6505 start_dv_learn (void *cls)
6507 struct LearnLaunchEntry *lle;
6508 struct QueueQualityContext qqc;
6509 struct TransportDVLearn dvl;
6512 dvlearn_task = NULL;
6513 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
6514 return; /* lost all connectivity, cannot do learning */
6515 qqc.quality_count = 0;
6517 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6518 &check_connection_quality,
6520 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
6522 struct GNUNET_TIME_Relative delay;
6523 unsigned int factor;
6525 /* scale our retries by how far we are above the threshold */
6526 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6527 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
6528 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
6531 /* remove old entries in #dvlearn_map if it has grown too big */
6532 while (MAX_DV_LEARN_PENDING >=
6533 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6536 GNUNET_assert (GNUNET_YES ==
6537 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6540 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
6543 /* setup data structure for learning */
6544 lle = GNUNET_new (struct LearnLaunchEntry);
6545 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6547 sizeof (lle->challenge));
6548 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
6549 GNUNET_break (GNUNET_YES ==
6550 GNUNET_CONTAINER_multishortmap_put (
6554 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6555 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6556 dvl.header.size = htons (sizeof (dvl));
6557 dvl.num_hops = htons (0);
6558 dvl.bidirectional = htons (0);
6559 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6561 struct DvInitPS dvip = {.purpose.purpose = htonl (
6562 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6563 .purpose.size = htonl (sizeof (dvip)),
6564 .challenge = lle->challenge};
6566 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6570 dvl.initiator = GST_my_identity;
6571 dvl.challenge = lle->challenge;
6573 qqc.quality_count = 0;
6574 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
6577 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6578 &check_connection_quality,
6580 GNUNET_assert (NULL != qqc.q);
6582 /* Do this as close to transmission time as possible! */
6583 lle->launch_time = GNUNET_TIME_absolute_get ();
6585 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
6586 /* reschedule this job, randomizing the time it runs (but no
6588 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
6589 DV_LEARN_BASE_FREQUENCY),
6596 * A new queue has been created, check if any address validation
6597 * requests have been waiting for it.
6599 * @param cls a `struct Queue`
6600 * @param pid peer concerned (unused)
6601 * @param value a `struct ValidationState`
6602 * @return #GNUNET_NO if a match was found and we can stop looking
6605 check_validation_request_pending (void *cls,
6606 const struct GNUNET_PeerIdentity *pid,
6609 struct Queue *q = cls;
6610 struct ValidationState *vs = value;
6613 if ((GNUNET_YES == vs->awaiting_queue) &&
6614 (0 == strcmp (vs->address, q->address)))
6616 vs->awaiting_queue = GNUNET_NO;
6617 validation_transmit_on_queue (q, vs);
6625 * New queue became available. Process the request.
6627 * @param cls the client
6628 * @param aqm the send message that was sent
6631 handle_add_queue_message (void *cls,
6632 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6634 struct TransportClient *tc = cls;
6635 struct Queue *queue;
6636 struct Neighbour *neighbour;
6640 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6642 /* MTU so small as to be useless for transmissions,
6643 required for #fragment_message()! */
6644 GNUNET_break_op (0);
6645 GNUNET_SERVICE_client_drop (tc->client);
6648 neighbour = lookup_neighbour (&aqm->receiver);
6649 if (NULL == neighbour)
6651 neighbour = GNUNET_new (struct Neighbour);
6652 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6653 neighbour->pid = aqm->receiver;
6654 GNUNET_assert (GNUNET_OK ==
6655 GNUNET_CONTAINER_multipeermap_put (
6659 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6661 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6662 addr = (const char *) &aqm[1];
6664 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6666 queue->address = (const char *) &queue[1];
6667 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6668 queue->qid = aqm->qid;
6669 queue->mtu = ntohl (aqm->mtu);
6670 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6671 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6672 queue->neighbour = neighbour;
6673 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6674 &tracker_update_in_cb,
6676 GNUNET_BANDWIDTH_ZERO,
6677 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6678 &tracker_excess_in_cb,
6680 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6681 &tracker_update_out_cb,
6683 GNUNET_BANDWIDTH_ZERO,
6684 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6685 &tracker_excess_out_cb,
6687 memcpy (&queue[1], addr, addr_len);
6688 /* notify monitors about new queue */
6690 struct MonitorEvent me = {.rtt = queue->rtt, .cs = queue->cs};
6692 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
6694 GNUNET_CONTAINER_MDLL_insert (neighbour,
6695 neighbour->queue_head,
6696 neighbour->queue_tail,
6698 GNUNET_CONTAINER_MDLL_insert (client,
6699 tc->details.communicator.queue_head,
6700 tc->details.communicator.queue_tail,
6702 /* check if valdiations are waiting for the queue */
6704 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6706 &check_validation_request_pending,
6708 /* might be our first queue, try launching DV learning */
6709 if (NULL == dvlearn_task)
6710 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
6711 GNUNET_SERVICE_client_continue (tc->client);
6716 * Communicator tells us that our request to create a queue "worked", that
6717 * is setting up the queue is now in process.
6719 * @param cls the `struct TransportClient`
6720 * @param cqr confirmation message
6723 handle_queue_create_ok (void *cls,
6724 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6726 struct TransportClient *tc = cls;
6728 if (CT_COMMUNICATOR != tc->type)
6731 GNUNET_SERVICE_client_drop (tc->client);
6734 GNUNET_STATISTICS_update (GST_stats,
6735 "# Suggestions succeeded at communicator",
6738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6739 "Request #%u for communicator to create queue succeeded\n",
6740 (unsigned int) ntohs (cqr->request_id));
6741 GNUNET_SERVICE_client_continue (tc->client);
6746 * Communicator tells us that our request to create a queue failed. This usually
6747 * indicates that the provided address is simply invalid or that the
6748 * communicator's resources are exhausted.
6750 * @param cls the `struct TransportClient`
6751 * @param cqr failure message
6754 handle_queue_create_fail (
6756 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6758 struct TransportClient *tc = cls;
6760 if (CT_COMMUNICATOR != tc->type)
6763 GNUNET_SERVICE_client_drop (tc->client);
6766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6767 "Request #%u for communicator to create queue failed\n",
6768 (unsigned int) ntohs (cqr->request_id));
6769 GNUNET_STATISTICS_update (GST_stats,
6770 "# Suggestions failed in queue creation at communicator",
6773 GNUNET_SERVICE_client_continue (tc->client);
6778 * We have received a `struct ExpressPreferenceMessage` from an application
6781 * @param cls handle to the client
6782 * @param msg the start message
6785 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
6787 struct TransportClient *tc = cls;
6788 struct PeerRequest *pr;
6790 if (CT_APPLICATION != tc->type)
6793 GNUNET_SERVICE_client_drop (tc->client);
6796 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
6801 GNUNET_SERVICE_client_drop (tc->client);
6804 (void) stop_peer_request (tc, &pr->pid, pr);
6805 GNUNET_SERVICE_client_continue (tc->client);
6810 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
6811 * messages. We do nothing here, real verification is done later.
6813 * @param cls a `struct TransportClient *`
6814 * @param msg message to verify
6815 * @return #GNUNET_OK
6818 check_address_consider_verify (
6820 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6829 * Closure for #check_known_address.
6831 struct CheckKnownAddressContext
6834 * Set to the address we are looking for.
6836 const char *address;
6839 * Set to a matching validation state, if one was found.
6841 struct ValidationState *vs;
6846 * Test if the validation state in @a value matches the
6847 * address from @a cls.
6849 * @param cls a `struct CheckKnownAddressContext`
6850 * @param pid unused (must match though)
6851 * @param value a `struct ValidationState`
6852 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6855 check_known_address (void *cls,
6856 const struct GNUNET_PeerIdentity *pid,
6859 struct CheckKnownAddressContext *ckac = cls;
6860 struct ValidationState *vs = value;
6863 if (0 != strcmp (vs->address, ckac->address))
6871 * Start address validation.
6873 * @param pid peer the @a address is for
6874 * @param address an address to reach @a pid (presumably)
6875 * @param expiration when did @a pid claim @a address will become invalid
6878 start_address_validation (const struct GNUNET_PeerIdentity *pid,
6879 const char *address,
6880 struct GNUNET_TIME_Absolute expiration)
6882 struct GNUNET_TIME_Absolute now;
6883 struct ValidationState *vs;
6884 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
6886 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
6887 return; /* expired */
6888 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6890 &check_known_address,
6892 if (NULL != (vs = ckac.vs))
6894 /* if 'vs' is not currently valid, we need to speed up retrying the
6896 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
6898 /* reduce backoff as we got a fresh advertisement */
6899 vs->challenge_backoff =
6900 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
6901 GNUNET_TIME_relative_divide (vs->challenge_backoff,
6903 update_next_challenge_time (vs,
6904 GNUNET_TIME_relative_to_absolute (
6905 vs->challenge_backoff));
6909 now = GNUNET_TIME_absolute_get ();
6910 vs = GNUNET_new (struct ValidationState);
6912 vs->valid_until = expiration;
6913 vs->first_challenge_use = now;
6914 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6915 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6917 sizeof (vs->challenge));
6918 vs->address = GNUNET_strdup (address);
6919 GNUNET_assert (GNUNET_YES ==
6920 GNUNET_CONTAINER_multipeermap_put (
6924 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6925 update_next_challenge_time (vs, now);
6930 * Function called by PEERSTORE for each matching record.
6932 * @param cls closure
6933 * @param record peerstore record information
6934 * @param emsg error message, or NULL if no errors
6937 handle_hello (void *cls,
6938 const struct GNUNET_PEERSTORE_Record *record,
6941 struct PeerRequest *pr = cls;
6946 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6947 "Got failure from PEERSTORE: %s\n",
6951 val = record->value;
6952 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
6957 start_address_validation (&pr->pid,
6958 (const char *) record->value,
6964 * We have received a `struct ExpressPreferenceMessage` from an application
6967 * @param cls handle to the client
6968 * @param msg the start message
6971 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
6973 struct TransportClient *tc = cls;
6974 struct PeerRequest *pr;
6976 if (CT_NONE == tc->type)
6978 tc->type = CT_APPLICATION;
6979 tc->details.application.requests =
6980 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
6982 if (CT_APPLICATION != tc->type)
6985 GNUNET_SERVICE_client_drop (tc->client);
6988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6989 "Client suggested we talk to %s with preference %d at rate %u\n",
6990 GNUNET_i2s (&msg->peer),
6991 (int) ntohl (msg->pk),
6992 (int) ntohl (msg->bw.value__));
6993 pr = GNUNET_new (struct PeerRequest);
6995 pr->pid = msg->peer;
6997 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
6998 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
6999 tc->details.application.requests,
7002 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
7006 GNUNET_SERVICE_client_drop (tc->client);
7009 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
7012 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7015 GNUNET_SERVICE_client_continue (tc->client);
7020 * Given another peers address, consider checking it for validity
7021 * and then adding it to the Peerstore.
7023 * @param cls a `struct TransportClient`
7024 * @param hdr message containing the raw address data and
7025 * signature in the body, see #GNUNET_HELLO_extract_address()
7028 handle_address_consider_verify (
7030 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7032 struct TransportClient *tc = cls;
7034 enum GNUNET_NetworkType nt;
7035 struct GNUNET_TIME_Absolute expiration;
7038 // OPTIMIZE-FIXME: checking that we know this address already should
7039 // be done BEFORE checking the signature => HELLO API change!
7040 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
7042 GNUNET_HELLO_extract_address (&hdr[1],
7043 ntohs (hdr->header.size) - sizeof (*hdr),
7047 if (NULL == address)
7049 GNUNET_break_op (0);
7052 start_address_validation (&hdr->peer, address, expiration);
7053 GNUNET_free (address);
7054 GNUNET_SERVICE_client_continue (tc->client);
7059 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
7062 * @param cls a `struct TransportClient *`
7063 * @param m message to verify
7064 * @return #GNUNET_OK on success
7067 check_request_hello_validation (void *cls,
7068 const struct RequestHelloValidationMessage *m)
7071 GNUNET_MQ_check_zero_termination (m);
7077 * A client encountered an address of another peer. Consider validating it,
7078 * and if validation succeeds, persist it to PEERSTORE.
7080 * @param cls a `struct TransportClient *`
7081 * @param m message to verify
7084 handle_request_hello_validation (void *cls,
7085 const struct RequestHelloValidationMessage *m)
7087 struct TransportClient *tc = cls;
7089 start_address_validation (&m->peer,
7090 (const char *) &m[1],
7091 GNUNET_TIME_absolute_ntoh (m->expiration));
7092 GNUNET_SERVICE_client_continue (tc->client);
7097 * Free neighbour entry.
7101 * @param value a `struct Neighbour`
7102 * @return #GNUNET_OK (always)
7105 free_neighbour_cb (void *cls,
7106 const struct GNUNET_PeerIdentity *pid,
7109 struct Neighbour *neighbour = value;
7113 GNUNET_break (0); // should this ever happen?
7114 free_neighbour (neighbour);
7121 * Free DV route entry.
7125 * @param value a `struct DistanceVector`
7126 * @return #GNUNET_OK (always)
7129 free_dv_routes_cb (void *cls,
7130 const struct GNUNET_PeerIdentity *pid,
7133 struct DistanceVector *dv = value;
7144 * Free ephemeral entry.
7148 * @param value a `struct EphemeralCacheEntry`
7149 * @return #GNUNET_OK (always)
7152 free_ephemeral_cb (void *cls,
7153 const struct GNUNET_PeerIdentity *pid,
7156 struct EphemeralCacheEntry *ece = value;
7160 free_ephemeral (ece);
7166 * Free validation state.
7170 * @param value a `struct ValidationState`
7171 * @return #GNUNET_OK (always)
7174 free_validation_state_cb (void *cls,
7175 const struct GNUNET_PeerIdentity *pid,
7178 struct ValidationState *vs = value;
7182 free_validation_state (vs);
7188 * Function called when the service shuts down. Unloads our plugins
7189 * and cancels pending validations.
7191 * @param cls closure, unused
7194 do_shutdown (void *cls)
7196 struct LearnLaunchEntry *lle;
7199 if (NULL != ephemeral_task)
7201 GNUNET_SCHEDULER_cancel (ephemeral_task);
7202 ephemeral_task = NULL;
7204 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
7205 if (NULL != peerstore)
7207 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
7210 if (NULL != GST_stats)
7212 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
7215 if (NULL != GST_my_private_key)
7217 GNUNET_free (GST_my_private_key);
7218 GST_my_private_key = NULL;
7220 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7222 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7223 &free_validation_state_cb,
7225 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7226 validation_map = NULL;
7227 while (NULL != (lle = lle_head))
7229 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7232 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7234 GNUNET_CONTAINER_heap_destroy (validation_heap);
7235 validation_heap = NULL;
7236 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
7237 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7239 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7242 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7243 ephemeral_map = NULL;
7244 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7245 ephemeral_heap = NULL;
7250 * Initiate transport service.
7252 * @param cls closure
7253 * @param c configuration to use
7254 * @param service the initialized service
7258 const struct GNUNET_CONFIGURATION_Handle *c,
7259 struct GNUNET_SERVICE_Handle *service)
7265 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7266 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7267 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
7269 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7270 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7272 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7274 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7275 GST_my_private_key =
7276 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7277 if (NULL == GST_my_private_key)
7280 GNUNET_ERROR_TYPE_ERROR,
7282 "Transport service is lacking key configuration settings. Exiting.\n"));
7283 GNUNET_SCHEDULER_shutdown ();
7286 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7287 &GST_my_identity.public_key);
7288 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7289 "My identity is `%s'\n",
7290 GNUNET_i2s_full (&GST_my_identity));
7291 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
7292 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
7293 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7294 if (NULL == peerstore)
7297 GNUNET_SCHEDULER_shutdown ();
7304 * Define "main" method using service macro.
7306 GNUNET_SERVICE_MAIN (
7308 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7311 &client_disconnect_cb,
7313 /* communication with applications */
7314 GNUNET_MQ_hd_fixed_size (suggest,
7315 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7316 struct ExpressPreferenceMessage,
7318 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7319 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7320 struct ExpressPreferenceMessage,
7322 GNUNET_MQ_hd_var_size (request_hello_validation,
7323 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7324 struct RequestHelloValidationMessage,
7326 /* communication with core */
7327 GNUNET_MQ_hd_fixed_size (client_start,
7328 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7329 struct StartMessage,
7331 GNUNET_MQ_hd_var_size (client_send,
7332 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7333 struct OutboundMessage,
7335 /* communication with communicators */
7336 GNUNET_MQ_hd_var_size (communicator_available,
7337 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7338 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7340 GNUNET_MQ_hd_var_size (communicator_backchannel,
7341 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7342 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7344 GNUNET_MQ_hd_var_size (add_address,
7345 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7346 struct GNUNET_TRANSPORT_AddAddressMessage,
7348 GNUNET_MQ_hd_fixed_size (del_address,
7349 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7350 struct GNUNET_TRANSPORT_DelAddressMessage,
7352 GNUNET_MQ_hd_var_size (incoming_msg,
7353 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7354 struct GNUNET_TRANSPORT_IncomingMessage,
7356 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7357 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7358 struct GNUNET_TRANSPORT_CreateQueueResponse,
7360 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7361 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7362 struct GNUNET_TRANSPORT_CreateQueueResponse,
7364 GNUNET_MQ_hd_var_size (add_queue_message,
7365 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7366 struct GNUNET_TRANSPORT_AddQueueMessage,
7368 GNUNET_MQ_hd_var_size (address_consider_verify,
7369 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7370 struct GNUNET_TRANSPORT_AddressToVerify,
7372 GNUNET_MQ_hd_fixed_size (del_queue_message,
7373 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7374 struct GNUNET_TRANSPORT_DelQueueMessage,
7376 GNUNET_MQ_hd_fixed_size (send_message_ack,
7377 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
7378 struct GNUNET_TRANSPORT_SendMessageToAck,
7380 /* communication with monitors */
7381 GNUNET_MQ_hd_fixed_size (monitor_start,
7382 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
7383 struct GNUNET_TRANSPORT_MonitorStart,
7385 GNUNET_MQ_handler_end ());
7388 /* end of file gnunet-service-transport.c */