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 * - retransmission logic
37 * - track RTT, distance, loss, etc. => requires extra data structures!
40 * - change transport-core API to provide proper flow control in both
41 * directions, allow multiple messages per peer simultaneously (tag
42 * confirmations with unique message ID), and replace quota-out with
43 * proper flow control;
44 * - if messages are below MTU, consider adding ACKs and other stuff
45 * (requires planning at receiver, and additional MST-style demultiplex
47 * - could avoid copying body of message into each fragment and keep
48 * fragments as just pointers into the original message and only
49 * fully build fragments just before transmission (optimization, should
50 * reduce CPU and memory use)
51 * - When we passively learned DV (with unconfirmed freshness), we
52 * right now add the path to our list but with a zero path_valid_until
53 * time and only use it for unconfirmed routes. However, we could consider
54 * triggering an explicit validation mechansim ourselves, specifically routing
55 * a challenge-response message over the path (OPTIMIZATION-FIXME).
57 * FIXME (without marks in the code!):
58 * - proper use/initialization of timestamps in messages exchanged
60 * - persistence of monotonic time obtained from other peers
61 * in PEERSTORE (by message type)
64 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
65 * against our pending message queue (requires additional per neighbour
66 * hash map to be maintained, avoids possible linear scan on pending msgs)
67 * - queue_send_msg and route_message both by API design have to make copies
68 * of the payload, and route_message on top of that requires a malloc/free.
69 * Change design to approximate "zero" copy better...
71 * Design realizations / discussion:
72 * - communicators do flow control by calling MQ "notify sent"
73 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
74 * or explicitly via backchannel FC ACKs. As long as the
75 * channel is not full, they may 'notify sent' even if the other
76 * peer has not yet confirmed receipt. The other peer confirming
77 * is _only_ for FC, not for more reliable transmission; reliable
78 * transmission (i.e. of fragments) is left to _transport_.
79 * - ACKs sent back in uni-directional communicators are done via
80 * the background channel API; here transport _may_ initially
81 * broadcast (with bounded # hops) if no path is known;
82 * - transport should _integrate_ DV-routing and build a view of
83 * the network; then background channel traffic can be
84 * routed via DV as well as explicit "DV" traffic.
85 * - background channel is also used for ACKs and NAT traversal support
86 * - transport service is responsible for AEAD'ing the background
87 * channel, timestamps and monotonic time are used against replay
88 * of old messages -> peerstore needs to be supplied with
89 * "latest timestamps seen" data
90 * - if transport implements DV, we likely need a 3rd peermap
91 * in addition to ephemerals and (direct) neighbours
92 * ==> check if stuff needs to be moved out of "Neighbour"
93 * - transport should encapsualte core-level messages and do its
94 * own ACKing for RTT/goodput/loss measurements _and_ fragment
98 #include "gnunet_util_lib.h"
99 #include "gnunet_statistics_service.h"
100 #include "gnunet_transport_monitor_service.h"
101 #include "gnunet_peerstore_service.h"
102 #include "gnunet_hello_lib.h"
103 #include "gnunet_signatures.h"
104 #include "transport.h"
108 * What is the size we assume for a read operation in the
109 * absence of an MTU for the purpose of flow control?
111 #define IN_PACKET_SIZE_WITHOUT_MTU 128
114 * Minimum number of hops we should forward DV learn messages
115 * even if they are NOT useful for us in hope of looping
116 * back to the initiator?
118 * FIXME: allow initiator some control here instead?
120 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
123 * Maximum DV distance allowed ever.
125 #define MAX_DV_HOPS_ALLOWED 16
128 * Maximum number of DV learning activities we may
129 * have pending at the same time.
131 #define MAX_DV_LEARN_PENDING 64
134 * Maximum number of DV paths we keep simultaneously to the same target.
136 #define MAX_DV_PATHS_TO_TARGET 3
139 * If a queue delays the next message by more than this number
140 * of seconds we log a warning. Note: this is for testing,
141 * the value chosen here might be too aggressively low!
143 #define DELAY_WARN_THRESHOLD \
144 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
147 * We only consider queues as "quality" connections when
148 * suppressing the generation of DV initiation messages if
149 * the latency of the queue is below this threshold.
151 #define DV_QUALITY_RTT_THRESHOLD \
152 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
155 * How long do we consider a DV path valid if we see no
156 * further updates on it? Note: the value chosen here might be too low!
158 #define DV_PATH_VALIDITY_TIMEOUT \
159 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
162 * How long before paths expire would we like to (re)discover DV paths? Should
163 * be below #DV_PATH_VALIDITY_TIMEOUT.
165 #define DV_PATH_DISCOVERY_FREQUENCY \
166 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
169 * How long are ephemeral keys valid?
171 #define EPHEMERAL_VALIDITY \
172 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
175 * How long do we keep partially reassembled messages around before giving up?
177 #define REASSEMBLY_EXPIRATION \
178 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
181 * What is the fastest rate at which we send challenges *if* we keep learning
182 * an address (gossip, DHT, etc.)?
184 #define FAST_VALIDATION_CHALLENGE_FREQ \
185 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
188 * What is the slowest rate at which we send challenges?
190 #define MAX_VALIDATION_CHALLENGE_FREQ \
191 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
194 * What is the non-randomized base frequency at which we
195 * would initiate DV learn messages?
197 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
200 * How many good connections (confirmed, bi-directional, not DV)
201 * do we need to have to suppress initiating DV learn messages?
203 #define DV_LEARN_QUALITY_THRESHOLD 100
206 * When do we forget an invalid address for sure?
208 #define MAX_ADDRESS_VALID_UNTIL \
209 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
212 * How long do we consider an address valid if we just checked?
214 #define ADDRESS_VALIDATION_LIFETIME \
215 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
218 * What is the maximum frequency at which we do address validation?
219 * A random value between 0 and this value is added when scheduling
220 * the #validation_task (both to ensure we do not validate too often,
221 * and to randomize a bit).
223 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
226 * How many network RTTs before an address validation expires should we begin
227 * trying to revalidate? (Note that the RTT used here is the one that we
228 * experienced during the last validation, not necessarily the latest RTT
231 #define VALIDATION_RTT_BUFFER_FACTOR 3
234 * How many messages can we have pending for a given communicator
235 * process before we start to throttle that communicator?
237 * Used if a communicator might be CPU-bound and cannot handle the traffic.
239 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
242 * How many messages can we have pending for a given queue (queue to
243 * a particular peer via a communicator) process before we start to
244 * throttle that queue?
246 #define QUEUE_LENGTH_LIMIT 32
249 GNUNET_NETWORK_STRUCT_BEGIN
252 * Outer layer of an encapsulated backchannel message.
254 struct TransportBackchannelEncapsulationMessage
257 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
259 struct GNUNET_MessageHeader header;
262 * Distance the backchannel message has traveled, to be updated at
263 * each hop. Used to bound the number of hops in case a backchannel
264 * message is broadcast and thus travels without routing
265 * information (during initial backchannel discovery).
270 * Target's peer identity (as backchannels may be transmitted
271 * indirectly, or even be broadcast).
273 struct GNUNET_PeerIdentity target;
276 * Ephemeral key setup by the sender for @e target, used
277 * to encrypt the payload.
279 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
282 * We use an IV here as the @e ephemeral_key is re-used for
283 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
285 struct GNUNET_ShortHashCode iv;
288 * HMAC over the ciphertext of the encrypted, variable-size
289 * body that follows. Verified via DH of @e target and
292 struct GNUNET_HashCode hmac;
294 /* Followed by encrypted, variable-size payload */
299 * Body by which a peer confirms that it is using an ephemeral key.
301 struct EphemeralConfirmation
305 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
307 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
310 * How long is this signature over the ephemeral key valid?
312 * Note that the receiver MUST IGNORE the absolute time, and only interpret
313 * the value as a mononic time and reject "older" values than the last one
314 * observed. This is necessary as we do not want to require synchronized
315 * clocks and may not have a bidirectional communication channel.
317 * Even with this, there is no real guarantee against replay achieved here,
318 * unless the latest timestamp is persisted. While persistence should be
319 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
320 * communicators must protect against replay attacks when using backchannel
323 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
326 * Target's peer identity.
328 struct GNUNET_PeerIdentity target;
331 * Ephemeral key setup by the sender for @e target, used
332 * to encrypt the payload.
334 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
339 * Plaintext of the variable-size payload that is encrypted
340 * within a `struct TransportBackchannelEncapsulationMessage`
342 struct TransportBackchannelRequestPayload
346 * Sender's peer identity.
348 struct GNUNET_PeerIdentity sender;
351 * Signature of the sender over an
352 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
354 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
357 * How long is this signature over the ephemeral key valid?
359 * Note that the receiver MUST IGNORE the absolute time, and only interpret
360 * the value as a mononic time and reject "older" values than the last one
361 * observed. This is necessary as we do not want to require synchronized
362 * clocks and may not have a bidirectional communication channel.
364 * Even with this, there is no real guarantee against replay achieved here,
365 * unless the latest timestamp is persisted. While persistence should be
366 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
367 * communicators must protect against replay attacks when using backchannel
370 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
373 * Current monotonic time of the sending transport service. Used to
374 * detect replayed messages. Note that the receiver should remember
375 * a list of the recently seen timestamps and only reject messages
376 * if the timestamp is in the list, or the list is "full" and the
377 * timestamp is smaller than the lowest in the list.
379 * Like the @e ephemeral_validity, the list of timestamps per peer should be
380 * persisted to guard against replays after restarts.
382 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
384 /* Followed by a `struct GNUNET_MessageHeader` with a message
385 for a communicator */
387 /* Followed by a 0-termianted string specifying the name of
388 the communicator which is to receive the message */
393 * Outer layer of an encapsulated unfragmented application message sent
394 * over an unreliable channel.
396 struct TransportReliabilityBox
399 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
401 struct GNUNET_MessageHeader header;
404 * Number of messages still to be sent before a commulative
405 * ACK is requested. Zero if an ACK is requested immediately.
406 * In NBO. Note that the receiver may send the ACK faster
407 * if it believes that is reasonable.
409 uint32_t ack_countdown GNUNET_PACKED;
412 * Unique ID of the message used for signalling receipt of
413 * messages sent over possibly unreliable channels. Should
416 struct GNUNET_ShortHashCode msg_uuid;
421 * Confirmation that the receiver got a
422 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
423 * confirmation may be transmitted over a completely different queue,
424 * so ACKs are identified by a combination of PID of sender and
425 * message UUID, without the queue playing any role!
427 struct TransportReliabilityAckMessage
430 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
432 struct GNUNET_MessageHeader header;
437 uint32_t reserved GNUNET_PACKED;
440 * How long was the ACK delayed relative to the average time of
441 * receipt of the messages being acknowledged? Used to calculate
442 * the average RTT by taking the receipt time of the ack minus the
443 * average transmission time of the sender minus this value.
445 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
447 /* followed by any number of `struct GNUNET_ShortHashCode`
448 messages providing ACKs */
453 * Outer layer of an encapsulated fragmented application message.
455 struct TransportFragmentBox
458 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
460 struct GNUNET_MessageHeader header;
463 * Unique ID of this fragment (and fragment transmission!). Will
464 * change even if a fragement is retransmitted to make each
465 * transmission attempt unique! Should be incremented by one for
466 * each fragment transmission. If a client receives a duplicate
467 * fragment (same @e frag_off), it must send
468 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
470 uint32_t frag_uuid GNUNET_PACKED;
473 * Original message ID for of the message that all the1
474 * fragments belong to. Must be the same for all fragments.
476 struct GNUNET_ShortHashCode msg_uuid;
479 * Offset of this fragment in the overall message.
481 uint16_t frag_off GNUNET_PACKED;
484 * Total size of the message that is being fragmented.
486 uint16_t msg_size GNUNET_PACKED;
491 * Outer layer of an fragmented application message sent over a queue
492 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
493 * received, the receiver has two RTTs or 64 further fragments with
494 * the same basic message time to send an acknowledgement, possibly
495 * acknowledging up to 65 fragments in one ACK. ACKs must also be
496 * sent immediately once all fragments were sent.
498 struct TransportFragmentAckMessage
501 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
503 struct GNUNET_MessageHeader header;
506 * Unique ID of the lowest fragment UUID being acknowledged.
508 uint32_t frag_uuid GNUNET_PACKED;
511 * Bitfield of up to 64 additional fragments following the
512 * @e msg_uuid being acknowledged by this message.
514 uint64_t extra_acks GNUNET_PACKED;
517 * Original message ID for of the message that all the
518 * fragments belong to.
520 struct GNUNET_ShortHashCode msg_uuid;
523 * How long was the ACK delayed relative to the average time of
524 * receipt of the fragments being acknowledged? Used to calculate
525 * the average RTT by taking the receipt time of the ack minus the
526 * average transmission time of the sender minus this value.
528 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
531 * How long until the receiver will stop trying reassembly
534 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
539 * Content signed by the initator during DV learning.
541 * The signature is required to prevent DDoS attacks. A peer sending out this
542 * message is potentially generating a lot of traffic that will go back to the
543 * initator, as peers receiving this message will try to let the initiator
544 * know that they got the message.
546 * Without this signature, an attacker could abuse this mechanism for traffic
547 * amplification, sending a lot of traffic to a peer by putting out this type
548 * of message with the victim's peer identity.
550 * Even with just a signature, traffic amplification would be possible via
551 * replay attacks. The @e monotonic_time limits such replay attacks, as every
552 * potential amplificator will check the @e monotonic_time and only respond
553 * (at most) once per message.
558 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
560 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
563 * Time at the initiator when generating the signature.
565 * Note that the receiver MUST IGNORE the absolute time, and only interpret
566 * the value as a mononic time and reject "older" values than the last one
567 * observed. This is necessary as we do not want to require synchronized
568 * clocks and may not have a bidirectional communication channel.
570 * Even with this, there is no real guarantee against replay achieved here,
571 * unless the latest timestamp is persisted. Persistence should be
572 * provided via PEERSTORE if possible.
574 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
577 * Challenge value used by the initiator to re-identify the path.
579 struct GNUNET_ShortHashCode challenge;
584 * Content signed by each peer during DV learning.
586 * This assues the initiator of the DV learning operation that the hop from @e
587 * pred via the signing peer to @e succ actually exists. This makes it
588 * impossible for an adversary to supply the network with bogus routes.
590 * The @e challenge is included to provide replay protection for the
591 * initiator. This way, the initiator knows that the hop existed after the
592 * original @e challenge was first transmitted, providing a freshness metric.
594 * Peers other than the initiator that passively learn paths by observing
595 * these messages do NOT benefit from this. Here, an adversary may indeed
596 * replay old messages. Thus, passively learned paths should always be
597 * immediately marked as "potentially stale".
602 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
604 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
607 * Identity of the previous peer on the path.
609 struct GNUNET_PeerIdentity pred;
612 * Identity of the next peer on the path.
614 struct GNUNET_PeerIdentity succ;
617 * Challenge value used by the initiator to re-identify the path.
619 struct GNUNET_ShortHashCode challenge;
624 * An entry describing a peer on a path in a
625 * `struct TransportDVLearn` message.
630 * Identity of a peer on the path.
632 struct GNUNET_PeerIdentity hop;
635 * Signature of this hop over the path, of purpose
636 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
638 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
643 * Internal message used by transport for distance vector learning.
644 * If @e num_hops does not exceed the threshold, peers should append
645 * themselves to the peer list and flood the message (possibly only
646 * to a subset of their neighbours to limit discoverability of the
647 * network topology). To the extend that the @e bidirectional bits
648 * are set, peers may learn the inverse paths even if they did not
651 * Unless received on a bidirectional queue and @e num_hops just
652 * zero, peers that can forward to the initator should always try to
653 * forward to the initiator.
655 struct TransportDVLearn
658 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
660 struct GNUNET_MessageHeader header;
663 * Number of hops this messages has travelled, in NBO. Zero if
666 uint16_t num_hops GNUNET_PACKED;
669 * Bitmask of the last 16 hops indicating whether they are confirmed
670 * available (without DV) in both directions or not, in NBO. Used
671 * to possibly instantly learn a path in both directions. Each peer
672 * should shift this value by one to the left, and then set the
673 * lowest bit IF the current sender can be reached from it (without
676 uint16_t bidirectional GNUNET_PACKED;
679 * Peers receiving this message and delaying forwarding to other
680 * peers for any reason should increment this value by the non-network
681 * delay created by the peer.
683 struct GNUNET_TIME_RelativeNBO non_network_delay;
686 * Signature of this hop over the path, of purpose
687 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
689 struct GNUNET_CRYPTO_EddsaSignature init_sig;
692 * Identity of the peer that started this learning activity.
694 struct GNUNET_PeerIdentity initiator;
697 * Challenge value used by the initiator to re-identify the path.
699 struct GNUNET_ShortHashCode challenge;
701 /* Followed by @e num_hops `struct DVPathEntryP` values,
702 excluding the initiator of the DV trace; the last entry is the
703 current sender; the current peer must not be included. */
708 * Outer layer of an encapsulated message send over multiple hops.
709 * The path given only includes the identities of the subsequent
710 * peers, i.e. it will be empty if we are the receiver. Each
711 * forwarding peer should scan the list from the end, and if it can,
712 * forward to the respective peer. The list should then be shortened
713 * by all the entries up to and including that peer. Each hop should
714 * also increment @e total_hops to allow the receiver to get a precise
715 * estimate on the number of hops the message travelled. Senders must
716 * provide a learned path that thus should work, but intermediaries
717 * know of a shortcut, they are allowed to send the message via that
720 * If a peer finds itself still on the list, it must drop the message.
722 struct TransportDVBox
725 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
727 struct GNUNET_MessageHeader header;
730 * Number of total hops this messages travelled. In NBO.
731 * @e origin sets this to zero, to be incremented at
734 uint16_t total_hops GNUNET_PACKED;
737 * Number of hops this messages includes. In NBO.
739 uint16_t num_hops GNUNET_PACKED;
742 * Identity of the peer that originated the message.
744 struct GNUNET_PeerIdentity origin;
746 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
747 excluding the @e origin and the current peer, the last must be
748 the ultimate target; if @e num_hops is zero, the receiver of this
749 message is the ultimate target. */
751 /* Followed by the actual message, which itself may be
752 another box, but not a DV_LEARN or DV_BOX message! */
757 * Message send to another peer to validate that it can indeed
758 * receive messages at a particular address.
760 struct TransportValidationChallenge
764 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
766 struct GNUNET_MessageHeader header;
771 uint32_t reserved GNUNET_PACKED;
774 * Challenge to be signed by the receiving peer.
776 struct GNUNET_ShortHashCode challenge;
779 * Timestamp of the sender, to be copied into the reply
780 * to allow sender to calculate RTT.
782 struct GNUNET_TIME_AbsoluteNBO sender_time;
787 * Message signed by a peer to confirm that it can indeed
788 * receive messages at a particular address.
790 struct TransportValidationPS
794 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
796 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
799 * How long does the sender believe the address on
800 * which the challenge was received to remain valid?
802 struct GNUNET_TIME_RelativeNBO validity_duration;
805 * Challenge signed by the receiving peer.
807 struct GNUNET_ShortHashCode challenge;
812 * Message send to a peer to respond to a
813 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
815 struct TransportValidationResponse
819 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
821 struct GNUNET_MessageHeader header;
826 uint32_t reserved GNUNET_PACKED;
829 * The peer's signature matching the
830 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
832 struct GNUNET_CRYPTO_EddsaSignature signature;
835 * The challenge that was signed by the receiving peer.
837 struct GNUNET_ShortHashCode challenge;
840 * Original timestamp of the sender (was @code{sender_time}),
841 * copied into the reply to allow sender to calculate RTT.
843 struct GNUNET_TIME_AbsoluteNBO origin_time;
846 * How long does the sender believe this address to remain
849 struct GNUNET_TIME_RelativeNBO validity_duration;
853 GNUNET_NETWORK_STRUCT_END
857 * What type of client is the `struct TransportClient` about?
862 * We do not know yet (client is fresh).
867 * Is the CORE service, we need to forward traffic to it.
872 * It is a monitor, forward monitor data.
877 * It is a communicator, use for communication.
882 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
889 * When did we launch this DV learning activity?
891 struct LearnLaunchEntry
895 * Kept (also) in a DLL sorted by launch time.
897 struct LearnLaunchEntry *prev;
900 * Kept (also) in a DLL sorted by launch time.
902 struct LearnLaunchEntry *next;
905 * Challenge that uniquely identifies this activity.
907 struct GNUNET_ShortHashCode challenge;
910 * When did we transmit the DV learn message (used to calculate RTT) and
911 * determine freshness of paths learned via this operation.
913 struct GNUNET_TIME_Absolute launch_time;
918 * Entry in our cache of ephemeral keys we currently use. This way, we only
919 * sign an ephemeral once per @e target, and then can re-use it over multiple
920 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
921 * signing is expensive and in some cases we may use backchannel messages a
924 struct EphemeralCacheEntry
928 * Target's peer identity (we don't re-use ephemerals
929 * to limit linkability of messages).
931 struct GNUNET_PeerIdentity target;
934 * Signature affirming @e ephemeral_key of type
935 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
937 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
940 * How long is @e sender_sig valid
942 struct GNUNET_TIME_Absolute ephemeral_validity;
947 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
950 * Our private ephemeral key.
952 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
955 * Node in the ephemeral cache for this entry.
956 * Used for expiration.
958 struct GNUNET_CONTAINER_HeapNode *hn;
963 * Client connected to the transport service.
965 struct TransportClient;
969 * A neighbour that at least one communicator is connected to.
975 * Entry in our #dv_routes table, representing a (set of) distance
976 * vector routes to a particular peer.
978 struct DistanceVector;
981 * One possible hop towards a DV target.
983 struct DistanceVectorHop
987 * Kept in a MDLL, sorted by @e timeout.
989 struct DistanceVectorHop *next_dv;
992 * Kept in a MDLL, sorted by @e timeout.
994 struct DistanceVectorHop *prev_dv;
999 struct DistanceVectorHop *next_neighbour;
1004 struct DistanceVectorHop *prev_neighbour;
1007 * What would be the next hop to @e target?
1009 struct Neighbour *next_hop;
1012 * Distance vector entry this hop belongs with.
1014 struct DistanceVector *dv;
1017 * Array of @e distance hops to the target, excluding @e next_hop.
1018 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1019 * at the end of this struct. Excludes the target itself!
1021 const struct GNUNET_PeerIdentity *path;
1024 * At what time do we forget about this path unless we see it again
1027 struct GNUNET_TIME_Absolute timeout;
1030 * For how long is the validation of this path considered
1032 * Set to ZERO if the path is learned by snooping on DV learn messages
1033 * initiated by other peers, and to the time at which we generated the
1034 * challenge for DV learn operations this peer initiated.
1036 struct GNUNET_TIME_Absolute path_valid_until;
1039 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1040 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1043 unsigned int distance;
1048 * Entry in our #dv_routes table, representing a (set of) distance
1049 * vector routes to a particular peer.
1051 struct DistanceVector
1055 * To which peer is this a route?
1057 struct GNUNET_PeerIdentity target;
1060 * Known paths to @e target.
1062 struct DistanceVectorHop *dv_head;
1065 * Known paths to @e target.
1067 struct DistanceVectorHop *dv_tail;
1070 * Task scheduled to purge expired paths from @e dv_head MDLL.
1072 struct GNUNET_SCHEDULER_Task *timeout_task;
1075 * Task scheduled to possibly notfiy core that this queue is no longer
1076 * counting as confirmed. Runs the #core_queue_visibility_check().
1078 struct GNUNET_SCHEDULER_Task *visibility_task;
1081 * Is one of the DV paths in this struct 'confirmed' and thus
1082 * the cause for CORE to see this peer as connected? (Note that
1083 * the same may apply to a `struct Neighbour` at the same time.)
1090 * A queue is a message queue provided by a communicator
1091 * via which we can reach a particular neighbour.
1097 * Entry identifying transmission in one of our `struct
1098 * Queue` which still awaits an ACK. This is used to
1099 * ensure we do not overwhelm a communicator and limit the number of
1100 * messages outstanding per communicator (say in case communicator is
1101 * CPU bound) and per queue (in case bandwidth allocation exceeds
1102 * what the communicator can actually provide towards a particular
1111 struct QueueEntry *next;
1116 struct QueueEntry *prev;
1119 * Queue this entry is queued with.
1121 struct Queue *queue;
1124 * Message ID used for this message with the queue used for transmission.
1131 * A queue is a message queue provided by a communicator
1132 * via which we can reach a particular neighbour.
1139 struct Queue *next_neighbour;
1144 struct Queue *prev_neighbour;
1149 struct Queue *prev_client;
1154 struct Queue *next_client;
1157 * Head of DLL of unacked transmission requests.
1159 struct QueueEntry *queue_head;
1162 * End of DLL of unacked transmission requests.
1164 struct QueueEntry *queue_tail;
1167 * Which neighbour is this queue for?
1169 struct Neighbour *neighbour;
1172 * Which communicator offers this queue?
1174 struct TransportClient *tc;
1177 * Address served by the queue.
1179 const char *address;
1182 * Task scheduled for the time when this queue can (likely) transmit the
1183 * next message. Still needs to check with the @e tracker_out to be sure.
1185 struct GNUNET_SCHEDULER_Task *transmit_task;
1188 * Task scheduled to possibly notfiy core that this queue is no longer
1189 * counting as confirmed. Runs the #core_queue_visibility_check().
1191 struct GNUNET_SCHEDULER_Task *visibility_task;
1194 * Our current RTT estimate for this queue.
1196 struct GNUNET_TIME_Relative rtt;
1199 * How long do *we* consider this @e address to be valid? In the past or
1200 * zero if we have not yet validated it. Can be updated based on
1201 * challenge-response validations (via address validation logic), or when we
1202 * receive ACKs that we can definitively map to transmissions via this
1205 struct GNUNET_TIME_Absolute validated_until;
1208 * Message ID generator for transmissions on this queue.
1213 * Unique identifier of this queue with the communicator.
1218 * Maximum transmission unit supported by this queue.
1223 * Distance to the target of this queue.
1224 * FIXME: needed? DV is done differently these days...
1231 uint32_t num_msg_pending;
1236 uint32_t num_bytes_pending;
1239 * Length of the DLL starting at @e queue_head.
1241 unsigned int queue_length;
1244 * Network type offered by this queue.
1246 enum GNUNET_NetworkType nt;
1249 * Connection status for this queue.
1251 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1254 * How much outbound bandwidth do we have available for this queue?
1256 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1259 * How much inbound bandwidth do we have available for this queue?
1261 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1266 * Information we keep for a message that we are reassembling.
1268 struct ReassemblyContext
1272 * Original message ID for of the message that all the
1273 * fragments belong to.
1275 struct GNUNET_ShortHashCode msg_uuid;
1278 * Which neighbour is this context for?
1280 struct Neighbour *neighbour;
1283 * Entry in the reassembly heap (sorted by expiration).
1285 struct GNUNET_CONTAINER_HeapNode *hn;
1288 * Bitfield with @e msg_size bits representing the positions
1289 * where we have received fragments. When we receive a fragment,
1290 * we check the bits in @e bitfield before incrementing @e msg_missing.
1292 * Allocated after the reassembled message.
1297 * Task for sending ACK. We may send ACKs either because of hitting
1298 * the @e extra_acks limit, or based on time and @e num_acks. This
1299 * task is for the latter case.
1301 struct GNUNET_SCHEDULER_Task *ack_task;
1304 * At what time will we give up reassembly of this message?
1306 struct GNUNET_TIME_Absolute reassembly_timeout;
1309 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1310 * Should be reset to zero when @e num_acks is set to 0.
1312 struct GNUNET_TIME_Relative avg_ack_delay;
1315 * Time we received the last fragment. @e avg_ack_delay must be
1316 * incremented by now - @e last_frag multiplied by @e num_acks.
1318 struct GNUNET_TIME_Absolute last_frag;
1321 * Bitfield of up to 64 additional fragments following @e frag_uuid
1322 * to be acknowledged in the next cummulative ACK.
1324 uint64_t extra_acks;
1327 * Unique ID of the lowest fragment UUID to be acknowledged in the
1328 * next cummulative ACK. Only valid if @e num_acks > 0.
1333 * Number of ACKs we have accumulated so far. Reset to 0
1334 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1336 unsigned int num_acks;
1339 * How big is the message we are reassembling in total?
1344 * How many bytes of the message are still missing? Defragmentation
1345 * is complete when @e msg_missing == 0.
1347 uint16_t msg_missing;
1349 /* Followed by @e msg_size bytes of the (partially) defragmented original
1352 /* Followed by @e bitfield data */
1357 * A neighbour that at least one communicator is connected to.
1363 * Which peer is this about?
1365 struct GNUNET_PeerIdentity pid;
1368 * Map with `struct ReassemblyContext` structs for fragments under
1369 * reassembly. May be NULL if we currently have no fragments from
1370 * this @e pid (lazy initialization).
1372 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1375 * Heap with `struct ReassemblyContext` structs for fragments under
1376 * reassembly. May be NULL if we currently have no fragments from
1377 * this @e pid (lazy initialization).
1379 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1382 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1384 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1387 * Head of list of messages pending for this neighbour.
1389 struct PendingMessage *pending_msg_head;
1392 * Tail of list of messages pending for this neighbour.
1394 struct PendingMessage *pending_msg_tail;
1397 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1398 * purged if this neighbour goes down.
1400 struct DistanceVectorHop *dv_head;
1403 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1404 * purged if this neighbour goes down.
1406 struct DistanceVectorHop *dv_tail;
1409 * Head of DLL of queues to this peer.
1411 struct Queue *queue_head;
1414 * Tail of DLL of queues to this peer.
1416 struct Queue *queue_tail;
1419 * Task run to cleanup pending messages that have exceeded their timeout.
1421 struct GNUNET_SCHEDULER_Task *timeout_task;
1424 * Quota at which CORE is allowed to transmit to this peer.
1426 * FIXME: not yet used, tricky to get right given multiple queues!
1427 * (=> Idea: measure???)
1428 * FIXME: how do we set this value initially when we tell CORE?
1429 * Options: start at a minimum value or at literally zero?
1430 * (=> Current thought: clean would be zero!)
1432 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1435 * What is the earliest timeout of any message in @e pending_msg_tail?
1437 struct GNUNET_TIME_Absolute earliest_timeout;
1440 * Do we have a confirmed working queue and are thus visible to
1448 * A peer that an application (client) would like us to talk to directly.
1454 * Which peer is this about?
1456 struct GNUNET_PeerIdentity pid;
1459 * Client responsible for the request.
1461 struct TransportClient *tc;
1464 * Handle for watching the peerstore for HELLOs for this peer.
1466 struct GNUNET_PEERSTORE_WatchContext *wc;
1469 * What kind of performance preference does this @e tc have?
1471 enum GNUNET_MQ_PreferenceKind pk;
1474 * How much bandwidth would this @e tc like to see?
1476 struct GNUNET_BANDWIDTH_Value32NBO bw;
1481 * Types of different pending messages.
1483 enum PendingMessageType
1487 * Ordinary message received from the CORE service.
1494 PMT_FRAGMENT_BOX = 1,
1499 PMT_RELIABILITY_BOX = 2,
1502 * Any type of acknowledgement.
1504 PMT_ACKNOWLEDGEMENT = 3,
1507 * Control traffic generated by the TRANSPORT service itself.
1515 * Transmission request that is awaiting delivery. The original
1516 * transmission requests from CORE may be too big for some queues.
1517 * In this case, a *tree* of fragments is created. At each
1518 * level of the tree, fragments are kept in a DLL ordered by which
1519 * fragment should be sent next (at the head). The tree is searched
1520 * top-down, with the original message at the root.
1522 * To select a node for transmission, first it is checked if the
1523 * current node's message fits with the MTU. If it does not, we
1524 * either calculate the next fragment (based on @e frag_off) from the
1525 * current node, or, if all fragments have already been created,
1526 * descend to the @e head_frag. Even though the node was already
1527 * fragmented, the fragment may be too big if the fragment was
1528 * generated for a queue with a larger MTU. In this case, the node
1529 * may be fragmented again, thus creating a tree.
1531 * When acknowledgements for fragments are received, the tree
1532 * must be pruned, removing those parts that were already
1533 * acknowledged. When fragments are sent over a reliable
1534 * channel, they can be immediately removed.
1536 * If a message is ever fragmented, then the original "full" message
1537 * is never again transmitted (even if it fits below the MTU), and
1538 * only (remaining) fragments are sent.
1540 struct PendingMessage
1543 * Kept in a MDLL of messages for this @a target.
1545 struct PendingMessage *next_neighbour;
1548 * Kept in a MDLL of messages for this @a target.
1550 struct PendingMessage *prev_neighbour;
1553 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1555 struct PendingMessage *next_client;
1558 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1560 struct PendingMessage *prev_client;
1563 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1564 * #PMT_FRAGMENT_BOx)
1566 struct PendingMessage *next_frag;
1569 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1570 * #PMT_FRAGMENT_BOX)
1572 struct PendingMessage *prev_frag;
1575 * This message, reliability boxed. Only possibly available if @e pmt is
1578 struct PendingMessage *bpm;
1581 * Target of the request.
1583 struct Neighbour *target;
1586 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1588 struct TransportClient *client;
1591 * Head of a MDLL of fragments created for this core message.
1593 struct PendingMessage *head_frag;
1596 * Tail of a MDLL of fragments created for this core message.
1598 struct PendingMessage *tail_frag;
1601 * Our parent in the fragmentation tree.
1603 struct PendingMessage *frag_parent;
1606 * At what time should we give up on the transmission (and no longer retry)?
1608 struct GNUNET_TIME_Absolute timeout;
1611 * What is the earliest time for us to retry transmission of this message?
1613 struct GNUNET_TIME_Absolute next_attempt;
1616 * UUID to use for this message (used for reassembly of fragments, only
1617 * initialized if @e msg_uuid_set is #GNUNET_YES).
1619 struct GNUNET_ShortHashCode msg_uuid;
1622 * Counter incremented per generated fragment.
1624 uint32_t frag_uuidgen;
1627 * Type of the pending message.
1629 enum PendingMessageType pmt;
1632 * Size of the original message.
1637 * Offset at which we should generate the next fragment.
1642 * #GNUNET_YES once @e msg_uuid was initialized
1644 int16_t msg_uuid_set;
1646 /* Followed by @e bytes_msg to transmit */
1651 * One of the addresses of this peer.
1653 struct AddressListEntry
1659 struct AddressListEntry *next;
1664 struct AddressListEntry *prev;
1667 * Which communicator provides this address?
1669 struct TransportClient *tc;
1672 * The actual address.
1674 const char *address;
1677 * Current context for storing this address in the peerstore.
1679 struct GNUNET_PEERSTORE_StoreContext *sc;
1682 * Task to periodically do @e st operation.
1684 struct GNUNET_SCHEDULER_Task *st;
1687 * What is a typical lifetime the communicator expects this
1688 * address to have? (Always from now.)
1690 struct GNUNET_TIME_Relative expiration;
1693 * Address identifier used by the communicator.
1698 * Network type offered by this address.
1700 enum GNUNET_NetworkType nt;
1705 * Client connected to the transport service.
1707 struct TransportClient
1713 struct TransportClient *next;
1718 struct TransportClient *prev;
1721 * Handle to the client.
1723 struct GNUNET_SERVICE_Client *client;
1726 * Message queue to the client.
1728 struct GNUNET_MQ_Handle *mq;
1731 * What type of client is this?
1733 enum ClientType type;
1739 * Information for @e type #CT_CORE.
1745 * Head of list of messages pending for this client, sorted by
1746 * transmission time ("next_attempt" + possibly internal prioritization).
1748 struct PendingMessage *pending_msg_head;
1751 * Tail of list of messages pending for this client.
1753 struct PendingMessage *pending_msg_tail;
1758 * Information for @e type #CT_MONITOR.
1764 * Peer identity to monitor the addresses of.
1765 * Zero to monitor all neighbours. Valid if
1766 * @e type is #CT_MONITOR.
1768 struct GNUNET_PeerIdentity peer;
1771 * Is this a one-shot monitor?
1779 * Information for @e type #CT_COMMUNICATOR.
1784 * If @e type is #CT_COMMUNICATOR, this communicator
1785 * supports communicating using these addresses.
1787 char *address_prefix;
1790 * Head of DLL of queues offered by this communicator.
1792 struct Queue *queue_head;
1795 * Tail of DLL of queues offered by this communicator.
1797 struct Queue *queue_tail;
1800 * Head of list of the addresses of this peer offered by this
1803 struct AddressListEntry *addr_head;
1806 * Tail of list of the addresses of this peer offered by this
1809 struct AddressListEntry *addr_tail;
1812 * Number of queue entries in all queues to this communicator. Used
1813 * throttle sending to a communicator if we see that the communicator
1814 * is globally unable to keep up.
1816 unsigned int total_queue_length;
1819 * Characteristics of this communicator.
1821 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1826 * Information for @e type #CT_APPLICATION
1832 * Map of requests for peers the given client application would like to
1833 * see connections for. Maps from PIDs to `struct PeerRequest`.
1835 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1844 * State we keep for validation activities. Each of these
1845 * is both in the #validation_heap and the #validation_map.
1847 struct ValidationState
1851 * For which peer is @a address to be validated (or possibly valid)?
1852 * Serves as key in the #validation_map.
1854 struct GNUNET_PeerIdentity pid;
1857 * How long did the peer claim this @e address to be valid? Capped at
1858 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1859 * were told about the address and the value claimed by the other peer at
1860 * that time. May be updated similarly when validation succeeds.
1862 struct GNUNET_TIME_Absolute valid_until;
1865 * How long do *we* consider this @e address to be valid?
1866 * In the past or zero if we have not yet validated it.
1868 struct GNUNET_TIME_Absolute validated_until;
1871 * When did we FIRST use the current @e challenge in a message?
1872 * Used to sanity-check @code{origin_time} in the response when
1873 * calculating the RTT. If the @code{origin_time} is not in
1874 * the expected range, the response is discarded as malicious.
1876 struct GNUNET_TIME_Absolute first_challenge_use;
1879 * When did we LAST 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 last_challenge_use;
1887 * Next time we will send the @e challenge to the peer, if this time is past
1888 * @e valid_until, this validation state is released at this time. If the
1889 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1890 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1891 * to re-validate before the validity actually expires.
1893 struct GNUNET_TIME_Absolute next_challenge;
1896 * Current backoff factor we're applying for sending the @a challenge.
1897 * Reset to 0 if the @a challenge is confirmed upon validation.
1898 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1899 * existing value if we receive an unvalidated address again over
1900 * another channel (and thus should consider the information "fresh").
1901 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1903 struct GNUNET_TIME_Relative challenge_backoff;
1906 * Initially set to "forever". Once @e validated_until is set, this value is
1907 * set to the RTT that tells us how long it took to receive the validation.
1909 struct GNUNET_TIME_Relative validation_rtt;
1912 * The challenge we sent to the peer to get it to validate the address. Note
1913 * that we rotate the challenge whenever we update @e validated_until to
1914 * avoid attacks where a peer simply replays an old challenge in the future.
1915 * (We must not rotate more often as otherwise we may discard valid answers
1916 * due to packet losses, latency and reorderings on the network).
1918 struct GNUNET_ShortHashCode challenge;
1921 * Claimed address of the peer.
1926 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1927 * heap is used to figure out when the next validation activity should be
1930 struct GNUNET_CONTAINER_HeapNode *hn;
1933 * Handle to a PEERSTORE store operation for this @e address. NULL if
1934 * no PEERSTORE operation is pending.
1936 struct GNUNET_PEERSTORE_StoreContext *sc;
1939 * We are technically ready to send the challenge, but we are waiting for
1940 * the respective queue to become available for transmission.
1947 * Head of linked list of all clients to this service.
1949 static struct TransportClient *clients_head;
1952 * Tail of linked list of all clients to this service.
1954 static struct TransportClient *clients_tail;
1957 * Statistics handle.
1959 static struct GNUNET_STATISTICS_Handle *GST_stats;
1962 * Configuration handle.
1964 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1969 static struct GNUNET_PeerIdentity GST_my_identity;
1974 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1977 * Map from PIDs to `struct Neighbour` entries. A peer is
1978 * a neighbour if we have an MQ to it from some communicator.
1980 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1983 * Map from PIDs to `struct DistanceVector` entries describing
1984 * known paths to the peer.
1986 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
1989 * Map from PIDs to `struct ValidationState` entries describing
1990 * addresses we are aware of and their validity state.
1992 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
1995 * Map from challenges to `struct LearnLaunchEntry` values.
1997 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2000 * Head of a DLL sorted by launch time.
2002 static struct LearnLaunchEntry *lle_head;
2005 * Tail of a DLL sorted by launch time.
2007 static struct LearnLaunchEntry *lle_tail;
2010 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2011 * sorting addresses we are aware of by when we should next try to (re)validate
2014 static struct GNUNET_CONTAINER_Heap *validation_heap;
2017 * Database for peer's HELLOs.
2019 static struct GNUNET_PEERSTORE_Handle *peerstore;
2022 * Heap sorting `struct EphemeralCacheEntry` by their
2023 * key/signature validity.
2025 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2028 * Hash map for looking up `struct EphemeralCacheEntry`s
2029 * by peer identity. (We may have ephemerals in our
2030 * cache for which we do not have a neighbour entry,
2031 * and similar many neighbours may not need ephemerals,
2032 * so we use a second map.)
2034 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2037 * Task to free expired ephemerals.
2039 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2042 * Task run to initiate DV learning.
2044 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2047 * Task to run address validation.
2049 static struct GNUNET_SCHEDULER_Task *validation_task;
2053 * Free cached ephemeral key.
2055 * @param ece cached signature to free
2058 free_ephemeral (struct EphemeralCacheEntry *ece)
2060 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2061 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2067 * Free validation state.
2069 * @param vs validation state to free
2072 free_validation_state (struct ValidationState *vs)
2074 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2075 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2079 GNUNET_PEERSTORE_store_cancel (vs->sc);
2082 GNUNET_free (vs->address);
2088 * Lookup neighbour record for peer @a pid.
2090 * @param pid neighbour to look for
2091 * @return NULL if we do not have this peer as a neighbour
2093 static struct Neighbour *
2094 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2096 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2101 * Details about what to notify monitors about.
2106 * @deprecated To be discussed if we keep these...
2108 struct GNUNET_TIME_Absolute last_validation;
2109 struct GNUNET_TIME_Absolute valid_until;
2110 struct GNUNET_TIME_Absolute next_validation;
2113 * Current round-trip time estimate.
2115 struct GNUNET_TIME_Relative rtt;
2118 * Connection status.
2120 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2125 uint32_t num_msg_pending;
2130 uint32_t num_bytes_pending;
2135 * Free a @dvh. Callers MAY want to check if this was the last path to the
2136 * `target`, and if so call #free_dv_route to also free the associated DV
2137 * entry in #dv_routes (if not, the associated scheduler job should eventually
2140 * @param dvh hop to free
2143 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2145 struct Neighbour *n = dvh->next_hop;
2146 struct DistanceVector *dv = dvh->dv;
2148 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2149 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2155 * Free entry in #dv_routes. First frees all hops to the target, and
2156 * if there are no entries left, frees @a dv as well.
2158 * @param dv route to free
2161 free_dv_route (struct DistanceVector *dv)
2163 struct DistanceVectorHop *dvh;
2165 while (NULL != (dvh = dv->dv_head))
2166 free_distance_vector_hop (dvh);
2167 if (NULL == dv->dv_head)
2171 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2172 if (NULL != dv->visibility_task)
2173 GNUNET_SCHEDULER_cancel (dv->visibility_task);
2174 if (NULL != dv->timeout_task)
2175 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2182 * Notify monitor @a tc about an event. That @a tc
2183 * cares about the event has already been checked.
2185 * Send @a tc information in @a me about a @a peer's status with
2186 * respect to some @a address to all monitors that care.
2188 * @param tc monitor to inform
2189 * @param peer peer the information is about
2190 * @param address address the information is about
2191 * @param nt network type associated with @a address
2192 * @param me detailed information to transmit
2195 notify_monitor (struct TransportClient *tc,
2196 const struct GNUNET_PeerIdentity *peer,
2197 const char *address,
2198 enum GNUNET_NetworkType nt,
2199 const struct MonitorEvent *me)
2201 struct GNUNET_MQ_Envelope *env;
2202 struct GNUNET_TRANSPORT_MonitorData *md;
2203 size_t addr_len = strlen (address) + 1;
2205 env = GNUNET_MQ_msg_extra (md,
2207 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2208 md->nt = htonl ((uint32_t) nt);
2210 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2211 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2212 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2213 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2214 md->cs = htonl ((uint32_t) me->cs);
2215 md->num_msg_pending = htonl (me->num_msg_pending);
2216 md->num_bytes_pending = htonl (me->num_bytes_pending);
2217 memcpy (&md[1], address, addr_len);
2218 GNUNET_MQ_send (tc->mq, env);
2223 * Send information in @a me about a @a peer's status with respect
2224 * to some @a address to all monitors that care.
2226 * @param peer peer the information is about
2227 * @param address address the information is about
2228 * @param nt network type associated with @a address
2229 * @param me detailed information to transmit
2232 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2233 const char *address,
2234 enum GNUNET_NetworkType nt,
2235 const struct MonitorEvent *me)
2237 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2239 if (CT_MONITOR != tc->type)
2241 if (tc->details.monitor.one_shot)
2243 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2244 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2246 notify_monitor (tc, peer, address, nt, me);
2252 * Called whenever a client connects. Allocates our
2253 * data structures associated with that client.
2255 * @param cls closure, NULL
2256 * @param client identification of the client
2257 * @param mq message queue for the client
2258 * @return our `struct TransportClient`
2261 client_connect_cb (void *cls,
2262 struct GNUNET_SERVICE_Client *client,
2263 struct GNUNET_MQ_Handle *mq)
2265 struct TransportClient *tc;
2268 tc = GNUNET_new (struct TransportClient);
2269 tc->client = client;
2271 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2280 * @param rc data structure to free
2283 free_reassembly_context (struct ReassemblyContext *rc)
2285 struct Neighbour *n = rc->neighbour;
2287 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2288 GNUNET_assert (GNUNET_OK ==
2289 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2297 * Task run to clean up reassembly context of a neighbour that have expired.
2299 * @param cls a `struct Neighbour`
2302 reassembly_cleanup_task (void *cls)
2304 struct Neighbour *n = cls;
2305 struct ReassemblyContext *rc;
2307 n->reassembly_timeout_task = NULL;
2308 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2310 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2313 free_reassembly_context (rc);
2316 GNUNET_assert (NULL == n->reassembly_timeout_task);
2317 n->reassembly_timeout_task =
2318 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2319 &reassembly_cleanup_task,
2327 * function called to #free_reassembly_context().
2331 * @param value a `struct ReassemblyContext` to free
2332 * @return #GNUNET_OK (continue iteration)
2335 free_reassembly_cb (void *cls,
2336 const struct GNUNET_ShortHashCode *key,
2339 struct ReassemblyContext *rc = value;
2343 free_reassembly_context (rc);
2349 * Release memory used by @a neighbour.
2351 * @param neighbour neighbour entry to free
2354 free_neighbour (struct Neighbour *neighbour)
2356 struct DistanceVectorHop *dvh;
2358 GNUNET_assert (NULL == neighbour->queue_head);
2359 GNUNET_assert (GNUNET_YES ==
2360 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2363 if (NULL != neighbour->timeout_task)
2364 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2365 if (NULL != neighbour->reassembly_map)
2367 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2368 &free_reassembly_cb,
2370 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2371 neighbour->reassembly_map = NULL;
2372 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2373 neighbour->reassembly_heap = NULL;
2375 while (NULL != (dvh = neighbour->dv_head))
2377 struct DistanceVector *dv = dvh->dv;
2379 free_distance_vector_hop (dvh);
2380 if (NULL == dv->dv_head)
2383 if (NULL != neighbour->reassembly_timeout_task)
2384 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2385 GNUNET_free (neighbour);
2390 * Send message to CORE clients that we lost a connection.
2392 * @param tc client to inform (must be CORE client)
2393 * @param pid peer the connection is for
2394 * @param quota_out current quota for the peer
2397 core_send_connect_info (struct TransportClient *tc,
2398 const struct GNUNET_PeerIdentity *pid,
2399 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2401 struct GNUNET_MQ_Envelope *env;
2402 struct ConnectInfoMessage *cim;
2404 GNUNET_assert (CT_CORE == tc->type);
2405 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2406 cim->quota_out = quota_out;
2408 GNUNET_MQ_send (tc->mq, env);
2413 * Send message to CORE clients that we gained a connection
2415 * @param pid peer the queue was for
2416 * @param quota_out current quota for the peer
2419 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2420 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2422 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2424 if (CT_CORE != tc->type)
2426 core_send_connect_info (tc, pid, quota_out);
2432 * Send message to CORE clients that we lost a connection.
2434 * @param pid peer the connection was for
2437 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2439 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2441 struct GNUNET_MQ_Envelope *env;
2442 struct DisconnectInfoMessage *dim;
2444 if (CT_CORE != tc->type)
2446 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2448 GNUNET_MQ_send (tc->mq, env);
2454 * We believe we are ready to transmit a message on a queue. Double-checks
2455 * with the queue's "tracker_out" and then gives the message to the
2456 * communicator for transmission (updating the tracker, and re-scheduling
2457 * itself if applicable).
2459 * @param cls the `struct Queue` to process transmissions for
2462 transmit_on_queue (void *cls);
2466 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2467 * we should run immediately or if the message queue is empty.
2468 * Test for no task being added AND queue not being empty to
2469 * transmit immediately afterwards! This function must only
2470 * be called if the message queue is non-empty!
2472 * @param queue the queue to do scheduling for
2475 schedule_transmit_on_queue (struct Queue *queue)
2477 struct Neighbour *n = queue->neighbour;
2478 struct PendingMessage *pm = n->pending_msg_head;
2479 struct GNUNET_TIME_Relative out_delay;
2482 GNUNET_assert (NULL != pm);
2483 if (queue->tc->details.communicator.total_queue_length >=
2484 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2486 GNUNET_STATISTICS_update (
2488 "# Transmission throttled due to communicator queue limit",
2493 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2495 GNUNET_STATISTICS_update (GST_stats,
2496 "# Transmission throttled due to queue queue limit",
2502 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
2504 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
2505 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
2508 if (0 == out_delay.rel_value_us)
2509 return; /* we should run immediately! */
2510 /* queue has changed since we were scheduled, reschedule again */
2511 queue->transmit_task =
2512 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
2513 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2514 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2515 "Next transmission on queue `%s' in %s (high delay)\n",
2517 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2520 "Next transmission on queue `%s' in %s\n",
2522 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2527 * Check whether the CORE visibility of @a n changed. If so,
2528 * check whether we need to notify CORE.
2530 * @param n neighbour to perform the check for
2533 update_neighbour_core_visibility (struct Neighbour *n);
2539 * @param queue the queue to free
2542 free_queue (struct Queue *queue)
2544 struct Neighbour *neighbour = queue->neighbour;
2545 struct TransportClient *tc = queue->tc;
2546 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
2547 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
2548 struct QueueEntry *qe;
2551 if (NULL != queue->transmit_task)
2553 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2554 queue->transmit_task = NULL;
2556 if (NULL != queue->visibility_task)
2558 GNUNET_SCHEDULER_cancel (queue->visibility_task);
2559 queue->visibility_task = NULL;
2561 GNUNET_CONTAINER_MDLL_remove (neighbour,
2562 neighbour->queue_head,
2563 neighbour->queue_tail,
2565 GNUNET_CONTAINER_MDLL_remove (client,
2566 tc->details.communicator.queue_head,
2567 tc->details.communicator.queue_tail,
2569 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
2570 tc->details.communicator.total_queue_length);
2571 while (NULL != (qe = queue->queue_head))
2573 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
2574 queue->queue_length--;
2575 tc->details.communicator.total_queue_length--;
2578 GNUNET_assert (0 == queue->queue_length);
2579 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
2580 tc->details.communicator.total_queue_length))
2582 /* Communicator dropped below threshold, resume all queues */
2583 GNUNET_STATISTICS_update (
2585 "# Transmission throttled due to communicator queue limit",
2588 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
2590 schedule_transmit_on_queue (s);
2592 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
2593 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2594 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2595 GNUNET_free (queue);
2597 update_neighbour_core_visibility (neighbour);
2598 cores_send_disconnect_info (&neighbour->pid);
2600 if (NULL == neighbour->queue_head)
2602 free_neighbour (neighbour);
2610 * @param ale address list entry to free
2613 free_address_list_entry (struct AddressListEntry *ale)
2615 struct TransportClient *tc = ale->tc;
2617 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2618 tc->details.communicator.addr_tail,
2620 if (NULL != ale->sc)
2622 GNUNET_PEERSTORE_store_cancel (ale->sc);
2625 if (NULL != ale->st)
2627 GNUNET_SCHEDULER_cancel (ale->st);
2635 * Stop the peer request in @a value.
2637 * @param cls a `struct TransportClient` that no longer makes the request
2638 * @param pid the peer's identity
2639 * @param value a `struct PeerRequest`
2640 * @return #GNUNET_YES (always)
2643 stop_peer_request (void *cls,
2644 const struct GNUNET_PeerIdentity *pid,
2647 struct TransportClient *tc = cls;
2648 struct PeerRequest *pr = value;
2650 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2653 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2663 * Called whenever a client is disconnected. Frees our
2664 * resources associated with that client.
2666 * @param cls closure, NULL
2667 * @param client identification of the client
2668 * @param app_ctx our `struct TransportClient`
2671 client_disconnect_cb (void *cls,
2672 struct GNUNET_SERVICE_Client *client,
2675 struct TransportClient *tc = app_ctx;
2678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2679 "Client %p disconnected, cleaning up.\n",
2681 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
2687 struct PendingMessage *pm;
2689 while (NULL != (pm = tc->details.core.pending_msg_head))
2691 GNUNET_CONTAINER_MDLL_remove (client,
2692 tc->details.core.pending_msg_head,
2693 tc->details.core.pending_msg_tail,
2701 case CT_COMMUNICATOR: {
2703 struct AddressListEntry *ale;
2705 while (NULL != (q = tc->details.communicator.queue_head))
2707 while (NULL != (ale = tc->details.communicator.addr_head))
2708 free_address_list_entry (ale);
2709 GNUNET_free (tc->details.communicator.address_prefix);
2712 case CT_APPLICATION:
2713 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2716 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2724 * Iterator telling new CORE client about all existing
2725 * connections to peers.
2727 * @param cls the new `struct TransportClient`
2728 * @param pid a connected peer
2729 * @param value the `struct Neighbour` with more information
2730 * @return #GNUNET_OK (continue to iterate)
2733 notify_client_connect_info (void *cls,
2734 const struct GNUNET_PeerIdentity *pid,
2737 struct TransportClient *tc = cls;
2738 struct Neighbour *neighbour = value;
2740 core_send_connect_info (tc, pid, neighbour->quota_out);
2746 * Initialize a "CORE" client. We got a start message from this
2747 * client, so add it to the list of clients for broadcasting of
2750 * @param cls the client
2751 * @param start the start message that was sent
2754 handle_client_start (void *cls, const struct StartMessage *start)
2756 struct TransportClient *tc = cls;
2759 options = ntohl (start->options);
2760 if ((0 != (1 & options)) &&
2761 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
2763 /* client thinks this is a different peer, reject */
2765 GNUNET_SERVICE_client_drop (tc->client);
2768 if (CT_NONE != tc->type)
2771 GNUNET_SERVICE_client_drop (tc->client);
2775 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2776 ¬ify_client_connect_info,
2778 GNUNET_SERVICE_client_continue (tc->client);
2783 * Client asked for transmission to a peer. Process the request.
2785 * @param cls the client
2786 * @param obm the send message that was sent
2789 check_client_send (void *cls, const struct OutboundMessage *obm)
2791 struct TransportClient *tc = cls;
2793 const struct GNUNET_MessageHeader *obmm;
2795 if (CT_CORE != tc->type)
2798 return GNUNET_SYSERR;
2800 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2801 if (size < sizeof (struct GNUNET_MessageHeader))
2804 return GNUNET_SYSERR;
2806 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2807 if (size != ntohs (obmm->size))
2810 return GNUNET_SYSERR;
2817 * Free fragment tree below @e root, excluding @e root itself.
2819 * @param root root of the tree to free
2822 free_fragment_tree (struct PendingMessage *root)
2824 struct PendingMessage *frag;
2826 while (NULL != (frag = root->head_frag))
2828 free_fragment_tree (frag);
2829 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2836 * Release memory associated with @a pm and remove @a pm from associated
2837 * data structures. @a pm must be a top-level pending message and not
2838 * a fragment in the tree. The entire tree is freed (if applicable).
2840 * @param pm the pending message to free
2843 free_pending_message (struct PendingMessage *pm)
2845 struct TransportClient *tc = pm->client;
2846 struct Neighbour *target = pm->target;
2850 GNUNET_CONTAINER_MDLL_remove (client,
2851 tc->details.core.pending_msg_head,
2852 tc->details.core.pending_msg_tail,
2855 GNUNET_CONTAINER_MDLL_remove (neighbour,
2856 target->pending_msg_head,
2857 target->pending_msg_tail,
2859 free_fragment_tree (pm);
2860 GNUNET_free_non_null (pm->bpm);
2866 * Send a response to the @a pm that we have processed a
2867 * "send" request with status @a success. We
2868 * transmitted @a bytes_physical on the actual wire.
2869 * Sends a confirmation to the "core" client responsible
2870 * for the original request and free's @a pm.
2872 * @param pm handle to the original pending message
2873 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2874 * for transmission failure
2875 * @param bytes_physical amount of bandwidth consumed
2878 client_send_response (struct PendingMessage *pm,
2880 uint32_t bytes_physical)
2882 struct TransportClient *tc = pm->client;
2883 struct Neighbour *target = pm->target;
2884 struct GNUNET_MQ_Envelope *env;
2885 struct SendOkMessage *som;
2889 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2890 som->success = htonl ((uint32_t) success);
2891 som->bytes_msg = htons (pm->bytes_msg);
2892 som->bytes_physical = htonl (bytes_physical);
2893 som->peer = target->pid;
2894 GNUNET_MQ_send (tc->mq, env);
2896 free_pending_message (pm);
2901 * Checks the message queue for a neighbour for messages that have timed
2902 * out and purges them.
2904 * @param cls a `struct Neighbour`
2907 check_queue_timeouts (void *cls)
2909 struct Neighbour *n = cls;
2910 struct PendingMessage *pm;
2911 struct GNUNET_TIME_Absolute now;
2912 struct GNUNET_TIME_Absolute earliest_timeout;
2914 n->timeout_task = NULL;
2915 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2916 now = GNUNET_TIME_absolute_get ();
2917 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
2919 pm = pos->next_neighbour;
2920 if (pos->timeout.abs_value_us <= now.abs_value_us)
2922 GNUNET_STATISTICS_update (GST_stats,
2923 "# messages dropped (timeout before confirmation)",
2926 client_send_response (pm, GNUNET_NO, 0);
2930 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
2932 n->earliest_timeout = earliest_timeout;
2933 if (NULL != n->pending_msg_head)
2935 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
2940 * Client asked for transmission to a peer. Process the request.
2942 * @param cls the client
2943 * @param obm the send message that was sent
2946 handle_client_send (void *cls, const struct OutboundMessage *obm)
2948 struct TransportClient *tc = cls;
2949 struct PendingMessage *pm;
2950 const struct GNUNET_MessageHeader *obmm;
2951 struct Neighbour *target;
2955 GNUNET_assert (CT_CORE == tc->type);
2956 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2957 bytes_msg = ntohs (obmm->size);
2958 target = lookup_neighbour (&obm->peer);
2961 /* Failure: don't have this peer as a neighbour (anymore).
2962 Might have gone down asynchronously, so this is NOT
2963 a protocol violation by CORE. Still count the event,
2964 as this should be rare. */
2965 struct GNUNET_MQ_Envelope *env;
2966 struct SendOkMessage *som;
2968 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2969 som->success = htonl (GNUNET_SYSERR);
2970 som->bytes_msg = htonl (bytes_msg);
2971 som->bytes_physical = htonl (0);
2972 som->peer = obm->peer;
2973 GNUNET_MQ_send (tc->mq, env);
2974 GNUNET_SERVICE_client_continue (tc->client);
2975 GNUNET_STATISTICS_update (GST_stats,
2976 "# messages dropped (neighbour unknown)",
2981 was_empty = (NULL == target->pending_msg_head);
2982 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2984 pm->target = target;
2985 pm->bytes_msg = bytes_msg;
2987 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2988 memcpy (&pm[1], &obm[1], bytes_msg);
2989 GNUNET_CONTAINER_MDLL_insert (neighbour,
2990 target->pending_msg_head,
2991 target->pending_msg_tail,
2993 GNUNET_CONTAINER_MDLL_insert (client,
2994 tc->details.core.pending_msg_head,
2995 tc->details.core.pending_msg_tail,
2997 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
2999 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3000 if (NULL != target->timeout_task)
3001 GNUNET_SCHEDULER_cancel (target->timeout_task);
3002 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3003 &check_queue_timeouts,
3007 return; /* all queues must already be busy */
3008 for (struct Queue *queue = target->queue_head; NULL != queue;
3009 queue = queue->next_neighbour)
3011 /* try transmission on any queue that is idle */
3012 if (NULL == queue->transmit_task)
3013 queue->transmit_task =
3014 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3020 * Communicator started. Test message is well-formed.
3022 * @param cls the client
3023 * @param cam the send message that was sent
3026 check_communicator_available (
3028 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3030 struct TransportClient *tc = cls;
3033 if (CT_NONE != tc->type)
3036 return GNUNET_SYSERR;
3038 tc->type = CT_COMMUNICATOR;
3039 size = ntohs (cam->header.size) - sizeof (*cam);
3041 return GNUNET_OK; /* receive-only communicator */
3042 GNUNET_MQ_check_zero_termination (cam);
3048 * Communicator started. Process the request.
3050 * @param cls the client
3051 * @param cam the send message that was sent
3054 handle_communicator_available (
3056 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3058 struct TransportClient *tc = cls;
3061 size = ntohs (cam->header.size) - sizeof (*cam);
3063 return; /* receive-only communicator */
3064 tc->details.communicator.address_prefix =
3065 GNUNET_strdup ((const char *) &cam[1]);
3066 tc->details.communicator.cc =
3067 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3068 GNUNET_SERVICE_client_continue (tc->client);
3073 * Communicator requests backchannel transmission. Check the request.
3075 * @param cls the client
3076 * @param cb the send message that was sent
3077 * @return #GNUNET_OK if message is well-formed
3080 check_communicator_backchannel (
3082 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3084 const struct GNUNET_MessageHeader *inbox;
3090 msize = ntohs (cb->header.size) - sizeof (*cb);
3091 if (UINT16_MAX - msize >
3092 sizeof (struct TransportBackchannelEncapsulationMessage) +
3093 sizeof (struct TransportBackchannelRequestPayload))
3096 return GNUNET_SYSERR;
3098 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3099 isize = ntohs (inbox->size);
3103 return GNUNET_SYSERR;
3105 is = (const char *) inbox;
3108 GNUNET_assert (msize > 0);
3109 if ('\0' != is[msize - 1])
3112 return GNUNET_SYSERR;
3119 * Remove memory used by expired ephemeral keys.
3124 expire_ephemerals (void *cls)
3126 struct EphemeralCacheEntry *ece;
3129 ephemeral_task = NULL;
3130 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3132 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3135 free_ephemeral (ece);
3138 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3147 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3148 * one, cache it and return it.
3150 * @param pid peer to look up ephemeral for
3151 * @param private_key[out] set to the private key
3152 * @param ephemeral_key[out] set to the key
3153 * @param ephemeral_sender_sig[out] set to the signature
3154 * @param ephemeral_validity[out] set to the validity expiration time
3157 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3158 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3159 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3160 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3161 struct GNUNET_TIME_Absolute *ephemeral_validity)
3163 struct EphemeralCacheEntry *ece;
3164 struct EphemeralConfirmation ec;
3166 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3167 if ((NULL != ece) &&
3168 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3171 free_ephemeral (ece);
3176 ece = GNUNET_new (struct EphemeralCacheEntry);
3178 ece->ephemeral_validity =
3179 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3180 EPHEMERAL_VALIDITY);
3181 GNUNET_assert (GNUNET_OK ==
3182 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3183 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3184 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3185 ec.purpose.size = htonl (sizeof (ec));
3187 ec.ephemeral_key = ece->ephemeral_key;
3188 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3192 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3194 ece->ephemeral_validity.abs_value_us);
3195 GNUNET_assert (GNUNET_OK ==
3196 GNUNET_CONTAINER_multipeermap_put (
3200 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3201 if (NULL == ephemeral_task)
3202 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3206 *private_key = ece->private_key;
3207 *ephemeral_key = ece->ephemeral_key;
3208 *ephemeral_sender_sig = ece->sender_sig;
3209 *ephemeral_validity = ece->ephemeral_validity;
3214 * Send the control message @a payload on @a queue.
3216 * @param queue the queue to use for transmission
3217 * @param pm pending message to update once transmission is done, may be NULL!
3218 * @param payload the payload to send (encapsulated in a
3219 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3220 * @param payload_size number of bytes in @a payload
3223 queue_send_msg (struct Queue *queue,
3224 struct PendingMessage *pm,
3225 const void *payload,
3226 size_t payload_size)
3228 struct Neighbour *n = queue->neighbour;
3229 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3230 struct GNUNET_MQ_Envelope *env;
3232 env = GNUNET_MQ_msg_extra (smt,
3234 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3235 smt->qid = queue->qid;
3236 smt->mid = queue->mid_gen;
3237 smt->receiver = n->pid;
3238 memcpy (&smt[1], payload, payload_size);
3240 /* Pass the env to the communicator of queue for transmission. */
3241 struct QueueEntry *qe;
3243 qe = GNUNET_new (struct QueueEntry);
3244 qe->mid = queue->mid_gen++;
3246 // qe->pm = pm; // FIXME: not so easy, reference management on 'free(s)'!
3247 // (also, note that pm may be NULL!)
3248 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3249 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3250 queue->queue_length++;
3251 queue->tc->details.communicator.total_queue_length++;
3252 GNUNET_MQ_send (queue->tc->mq, env);
3258 * Which transmission options are allowable for transmission?
3259 * Interpreted bit-wise!
3261 enum RouteMessageOptions
3264 * Only confirmed, non-DV direct neighbours.
3269 * We are allowed to use DV routing for this @a hdr
3274 * We are allowed to use unconfirmed queues or DV routes for this message
3276 RMO_UNCONFIRMED_ALLOWED = 2,
3279 * Reliable and unreliable, DV and non-DV are all acceptable.
3281 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
3284 * If we have multiple choices, it is OK to send this message
3285 * over multiple channels at the same time to improve loss tolerance.
3286 * (We do at most 2 transmissions.)
3293 * Pick a queue of @a n under constraints @a options and schedule
3294 * transmission of @a hdr.
3296 * @param n neighbour to send to
3297 * @param hdr message to send as payload
3298 * @param options whether queues must be confirmed or not,
3299 * and whether we may pick multiple (2) queues
3302 route_via_neighbour (const struct Neighbour *n,
3303 const struct GNUNET_MessageHeader *hdr,
3304 enum RouteMessageOptions options)
3306 struct GNUNET_TIME_Absolute now;
3307 unsigned int candidates;
3311 /* Pick one or two 'random' queues from n (under constraints of options) */
3312 now = GNUNET_TIME_absolute_get ();
3313 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
3314 weight in the future; weight could be assigned by observed
3315 bandwidth (note: not sure if we should do this for this type
3316 of control traffic though). */
3318 for (struct Queue *pos = n->queue_head; NULL != pos;
3319 pos = pos->next_neighbour)
3321 /* Count the queue with the visibility task in all cases, as
3322 otherwise we may end up with no queues just because the
3323 time for the visibility task just expired but the scheduler
3324 just ran this task first */
3325 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
3326 (pos->validated_until.abs_value_us > now.abs_value_us) ||
3327 (NULL != pos->visibility_task))
3330 if (0 == candidates)
3332 /* Given that we above check for pos->visibility task,
3333 this should be strictly impossible. */
3337 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3338 if (0 == (options & RMO_REDUNDANT))
3339 sel2 = candidates; /* picks none! */
3341 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3343 for (struct Queue *pos = n->queue_head; NULL != pos;
3344 pos = pos->next_neighbour)
3346 /* Count the queue with the visibility task in all cases, as
3347 otherwise we may end up with no queues just because the
3348 time for the visibility task just expired but the scheduler
3349 just ran this task first */
3350 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
3351 (NULL != pos->visibility_task))
3353 if ((sel1 == candidates) || (sel2 == candidates))
3354 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
3362 * Given a distance vector path @a dvh route @a payload to
3363 * the ultimate destination respecting @a options.
3364 * Sets up the boxed message and queues it at the next hop.
3366 * @param dvh choice of the path for the message
3367 * @param payload body to transmit
3368 * @param options options to use for control
3371 forward_via_dvh (const struct DistanceVectorHop *dvh,
3372 const struct GNUNET_MessageHeader *payload,
3373 enum RouteMessageOptions options)
3375 uint16_t mlen = ntohs (payload->size);
3376 char boxram[sizeof (struct TransportDVBox) +
3377 (dvh->distance + 1) * sizeof (struct GNUNET_PeerIdentity) +
3379 struct TransportDVBox *box = (struct TransportDVBox *) boxram;
3380 struct GNUNET_PeerIdentity *path = (struct GNUNET_PeerIdentity *) &box[1];
3382 box->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3383 box->header.size = htons (sizeof (boxram));
3384 box->total_hops = htons (0);
3385 box->num_hops = htons (dvh->distance + 1);
3386 box->origin = GST_my_identity;
3387 memcpy (path, dvh->path, dvh->distance * sizeof (struct GNUNET_PeerIdentity));
3388 path[dvh->distance] = dvh->dv->target;
3389 memcpy (&path[dvh->distance + 1], payload, mlen);
3390 route_via_neighbour (dvh->next_hop, &box->header, options);
3395 * Pick a path of @a dv under constraints @a options and schedule
3396 * transmission of @a hdr.
3398 * @param n neighbour to send to
3399 * @param hdr message to send as payload
3400 * @param options whether path must be confirmed or not
3401 * and whether we may pick multiple (2) paths
3404 route_via_dv (const struct DistanceVector *dv,
3405 const struct GNUNET_MessageHeader *hdr,
3406 enum RouteMessageOptions options)
3408 struct DistanceVectorHop *h1;
3409 struct DistanceVectorHop *h2;
3414 /* Pick random vectors, but weighted by distance, giving more weight
3415 to shorter vectors */
3417 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3420 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3421 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3422 .rel_value_us == 0))
3423 continue; /* pos unconfirmed and confirmed required */
3424 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3431 choice1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3432 choice2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3436 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3439 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3441 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3442 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3443 .rel_value_us == 0))
3444 continue; /* pos unconfirmed and confirmed required */
3445 if ((num_dv <= choice1) && (num_dv + delta > choice1))
3447 if ((num_dv <= choice2) && (num_dv + delta > choice2))
3451 forward_via_dvh (h1, hdr, options & (~RMO_REDUNDANT));
3452 if (0 == (options & RMO_REDUNDANT))
3453 forward_via_dvh (h2, hdr, options & (~RMO_REDUNDANT));
3458 * We need to transmit @a hdr to @a target. If necessary, this may
3459 * involve DV routing.
3461 * @param target peer to receive @a hdr
3462 * @param hdr header of the message to route and #GNUNET_free()
3463 * @param options which transmission channels are allowed
3466 route_message (const struct GNUNET_PeerIdentity *target,
3467 struct GNUNET_MessageHeader *hdr,
3468 enum RouteMessageOptions options)
3470 struct Neighbour *n;
3471 struct DistanceVector *dv;
3473 n = GNUNET_CONTAINER_multipeermap_get (neighbours, target);
3474 dv = (0 != (options & RMO_DV_ALLOWED))
3475 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
3477 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
3479 /* if confirmed is required, and we do not have anything
3480 confirmed, drop respective options */
3481 if ((NULL != n) && (GNUNET_NO == n->core_visible))
3483 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
3486 if ((NULL == n) && (NULL == dv))
3488 GNUNET_STATISTICS_update (GST_stats,
3489 "# Messages dropped in routing: no acceptable method",
3495 /* If both dv and n are possible and we must choose:
3496 flip a coin for the choice between the two; for now 50/50 */
3497 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
3499 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
3504 if ((NULL != n) && (NULL != dv))
3505 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
3506 enough for redunancy, so clear the flag. */
3509 route_via_neighbour (n, hdr, options);
3513 route_via_dv (dv, hdr, options);
3520 * Structure of the key material used to encrypt backchannel messages.
3522 struct BackchannelKeyState
3525 * State of our block cipher.
3527 gcry_cipher_hd_t cipher;
3530 * Actual key material.
3536 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3538 struct GNUNET_CRYPTO_AuthKey hmac_key;
3541 * Symmetric key to use for encryption.
3543 char aes_key[256 / 8];
3546 * Counter value to use during setup.
3548 char aes_ctr[128 / 8];
3555 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3556 const struct GNUNET_ShortHashCode *iv,
3557 struct BackchannelKeyState *key)
3559 /* must match #dh_key_derive_eph_pub */
3560 GNUNET_assert (GNUNET_YES ==
3561 GNUNET_CRYPTO_kdf (&key->material,
3562 sizeof (key->material),
3563 "transport-backchannel-key",
3564 strlen ("transport-backchannel-key"),
3569 gcry_cipher_open (&key->cipher,
3570 GCRY_CIPHER_AES256 /* low level: go for speed */,
3571 GCRY_CIPHER_MODE_CTR,
3573 gcry_cipher_setkey (key->cipher,
3574 &key->material.aes_key,
3575 sizeof (key->material.aes_key));
3576 gcry_cipher_setctr (key->cipher,
3577 &key->material.aes_ctr,
3578 sizeof (key->material.aes_ctr));
3583 * Derive backchannel encryption key material from @a priv_ephemeral
3584 * and @a target and @a iv.
3586 * @param priv_ephemeral ephemeral private key to use
3587 * @param target the target peer to encrypt to
3588 * @param iv unique IV to use
3589 * @param key[out] set to the key material
3592 dh_key_derive_eph_pid (
3593 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3594 const struct GNUNET_PeerIdentity *target,
3595 const struct GNUNET_ShortHashCode *iv,
3596 struct BackchannelKeyState *key)
3598 struct GNUNET_HashCode km;
3600 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3601 &target->public_key,
3603 bc_setup_key_state_from_km (&km, iv, key);
3608 * Derive backchannel encryption key material from #GST_my_private_key
3609 * and @a pub_ephemeral and @a iv.
3611 * @param priv_ephemeral ephemeral private key to use
3612 * @param target the target peer to encrypt to
3613 * @param iv unique IV to use
3614 * @param key[out] set to the key material
3617 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3618 const struct GNUNET_ShortHashCode *iv,
3619 struct BackchannelKeyState *key)
3621 struct GNUNET_HashCode km;
3623 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3626 bc_setup_key_state_from_km (&km, iv, key);
3631 * Do HMAC calculation for backchannel messages over @a data using key
3632 * material from @a key.
3634 * @param key key material (from DH)
3635 * @param hmac[out] set to the HMAC
3636 * @param data data to perform HMAC calculation over
3637 * @param data_size number of bytes in @a data
3640 bc_hmac (const struct BackchannelKeyState *key,
3641 struct GNUNET_HashCode *hmac,
3645 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
3650 * Perform backchannel encryption using symmetric secret in @a key
3651 * to encrypt data from @a in to @a dst.
3653 * @param key[in,out] key material to use
3654 * @param dst where to write the result
3655 * @param in input data to encrypt (plaintext)
3656 * @param in_size number of bytes of input in @a in and available at @a dst
3659 bc_encrypt (struct BackchannelKeyState *key,
3665 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
3670 * Perform backchannel encryption using symmetric secret in @a key
3671 * to encrypt data from @a in to @a dst.
3673 * @param key[in,out] key material to use
3674 * @param ciph cipher text to decrypt
3675 * @param out[out] output data to generate (plaintext)
3676 * @param out_size number of bytes of input in @a ciph and available in @a out
3679 bc_decrypt (struct BackchannelKeyState *key,
3685 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
3690 * Clean up key material in @a key.
3692 * @param key key material to clean up (memory must not be free'd!)
3695 bc_key_clean (struct BackchannelKeyState *key)
3697 gcry_cipher_close (key->cipher);
3698 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
3703 * Communicator requests backchannel transmission. Process the request.
3705 * @param cls the client
3706 * @param cb the send message that was sent
3709 handle_communicator_backchannel (
3711 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3713 struct TransportClient *tc = cls;
3714 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3715 struct GNUNET_TIME_Absolute ephemeral_validity;
3716 struct TransportBackchannelEncapsulationMessage *enc;
3717 struct TransportBackchannelRequestPayload ppay;
3718 struct BackchannelKeyState key;
3722 /* encapsulate and encrypt message */
3723 msize = ntohs (cb->header.size) - sizeof (*cb) +
3724 sizeof (struct TransportBackchannelRequestPayload);
3725 enc = GNUNET_malloc (sizeof (*enc) + msize);
3727 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3728 enc->header.size = htons (sizeof (*enc) + msize);
3729 enc->target = cb->pid;
3730 lookup_ephemeral (&cb->pid,
3732 &enc->ephemeral_key,
3734 &ephemeral_validity);
3735 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3738 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
3739 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3740 ppay.monotonic_time =
3741 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3742 mpos = (char *) &enc[1];
3743 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
3746 &mpos[sizeof (ppay)],
3747 ntohs (cb->header.size) - sizeof (*cb));
3751 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3752 bc_key_clean (&key);
3753 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
3754 GNUNET_SERVICE_client_continue (tc->client);
3759 * Address of our peer added. Test message is well-formed.
3761 * @param cls the client
3762 * @param aam the send message that was sent
3763 * @return #GNUNET_OK if message is well-formed
3766 check_add_address (void *cls,
3767 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3769 struct TransportClient *tc = cls;
3771 if (CT_COMMUNICATOR != tc->type)
3774 return GNUNET_SYSERR;
3776 GNUNET_MQ_check_zero_termination (aam);
3782 * Ask peerstore to store our address.
3784 * @param cls an `struct AddressListEntry *`
3787 store_pi (void *cls);
3791 * Function called when peerstore is done storing our address.
3793 * @param cls a `struct AddressListEntry`
3794 * @param success #GNUNET_YES if peerstore was successful
3797 peerstore_store_own_cb (void *cls, int success)
3799 struct AddressListEntry *ale = cls;
3802 if (GNUNET_YES != success)
3803 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3804 "Failed to store our own address `%s' in peerstore!\n",
3806 /* refresh period is 1/4 of expiration time, that should be plenty
3807 without being excessive. */
3809 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3817 * Ask peerstore to store our address.
3819 * @param cls an `struct AddressListEntry *`
3822 store_pi (void *cls)
3824 struct AddressListEntry *ale = cls;
3827 struct GNUNET_TIME_Absolute expiration;
3830 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3831 GNUNET_HELLO_sign_address (ale->address,
3837 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3840 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3844 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3845 &peerstore_store_own_cb,
3848 if (NULL == ale->sc)
3850 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3851 "Failed to store our address `%s' with peerstore\n",
3854 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
3860 * Address of our peer added. Process the request.
3862 * @param cls the client
3863 * @param aam the send message that was sent
3866 handle_add_address (void *cls,
3867 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3869 struct TransportClient *tc = cls;
3870 struct AddressListEntry *ale;
3873 slen = ntohs (aam->header.size) - sizeof (*aam);
3874 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3876 ale->address = (const char *) &ale[1];
3877 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3878 ale->aid = aam->aid;
3879 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3880 memcpy (&ale[1], &aam[1], slen);
3881 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3882 tc->details.communicator.addr_tail,
3884 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
3885 GNUNET_SERVICE_client_continue (tc->client);
3890 * Address of our peer deleted. Process the request.
3892 * @param cls the client
3893 * @param dam the send message that was sent
3896 handle_del_address (void *cls,
3897 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3899 struct TransportClient *tc = cls;
3901 if (CT_COMMUNICATOR != tc->type)
3904 GNUNET_SERVICE_client_drop (tc->client);
3907 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3911 if (dam->aid != ale->aid)
3913 GNUNET_assert (ale->tc == tc);
3914 free_address_list_entry (ale);
3915 GNUNET_SERVICE_client_continue (tc->client);
3918 GNUNET_SERVICE_client_drop (tc->client);
3923 * Context from #handle_incoming_msg(). Closure for many
3924 * message handlers below.
3926 struct CommunicatorMessageContext
3929 * Which communicator provided us with the message.
3931 struct TransportClient *tc;
3934 * Additional information for flow control and about the sender.
3936 struct GNUNET_TRANSPORT_IncomingMessage im;
3939 * Number of hops the message has travelled (if DV-routed).
3940 * FIXME: make use of this in ACK handling!
3942 uint16_t total_hops;
3947 * Given an inbound message @a msg from a communicator @a cmc,
3948 * demultiplex it based on the type calling the right handler.
3950 * @param cmc context for demultiplexing
3951 * @param msg message to demultiplex
3954 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3955 const struct GNUNET_MessageHeader *msg);
3959 * Send ACK to communicator (if requested) and free @a cmc.
3961 * @param cmc context for which we are done handling the message
3964 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3966 if (0 != ntohl (cmc->im.fc_on))
3968 /* send ACK when done to communicator for flow control! */
3969 struct GNUNET_MQ_Envelope *env;
3970 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3972 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3973 ack->reserved = htonl (0);
3974 ack->fc_id = cmc->im.fc_id;
3975 ack->sender = cmc->im.sender;
3976 GNUNET_MQ_send (cmc->tc->mq, env);
3978 GNUNET_SERVICE_client_continue (cmc->tc->client);
3984 * Communicator gave us an unencapsulated message to pass as-is to
3985 * CORE. Process the request.
3987 * @param cls a `struct CommunicatorMessageContext` (must call
3988 * #finish_cmc_handling() when done)
3989 * @param mh the message that was received
3992 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
3994 struct CommunicatorMessageContext *cmc = cls;
3995 uint16_t size = ntohs (mh->size);
3997 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
3998 (size < sizeof (struct GNUNET_MessageHeader)))
4000 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4003 finish_cmc_handling (cmc);
4004 GNUNET_SERVICE_client_drop (client);
4007 /* Forward to all CORE clients */
4008 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4010 struct GNUNET_MQ_Envelope *env;
4011 struct InboundMessage *im;
4013 if (CT_CORE != tc->type)
4015 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4016 im->peer = cmc->im.sender;
4017 memcpy (&im[1], mh, size);
4018 GNUNET_MQ_send (tc->mq, env);
4020 /* FIXME: consider doing this _only_ once the message
4021 was drained from the CORE MQs to extend flow control to CORE!
4022 (basically, increment counter in cmc, decrement on MQ send continuation! */
4023 finish_cmc_handling (cmc);
4028 * Communicator gave us a fragment box. Check the message.
4030 * @param cls a `struct CommunicatorMessageContext`
4031 * @param fb the send message that was sent
4032 * @return #GNUNET_YES if message is well-formed
4035 check_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4037 uint16_t size = ntohs (fb->header.size);
4038 uint16_t bsize = size - sizeof (*fb);
4042 GNUNET_break_op (0);
4043 return GNUNET_SYSERR;
4045 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4047 GNUNET_break_op (0);
4048 return GNUNET_SYSERR;
4050 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4052 GNUNET_break_op (0);
4053 return GNUNET_SYSERR;
4060 * Generate a fragment acknowledgement for an @a rc.
4062 * @param rc context to generate ACK for, @a rc ACK state is reset
4065 send_fragment_ack (struct ReassemblyContext *rc)
4067 struct TransportFragmentAckMessage *ack;
4069 ack = GNUNET_new (struct TransportFragmentAckMessage);
4070 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
4071 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
4072 ack->frag_uuid = htonl (rc->frag_uuid);
4073 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
4074 ack->msg_uuid = rc->msg_uuid;
4075 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
4076 if (0 == rc->msg_missing)
4077 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4078 GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
4080 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4081 GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
4082 route_message (&rc->neighbour->pid, &ack->header, RMO_DV_ALLOWED);
4083 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
4085 rc->extra_acks = 0LLU;
4090 * Communicator gave us a fragment. Process the request.
4092 * @param cls a `struct CommunicatorMessageContext` (must call
4093 * #finish_cmc_handling() when done)
4094 * @param fb the message that was received
4097 handle_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4099 struct CommunicatorMessageContext *cmc = cls;
4100 struct Neighbour *n;
4101 struct ReassemblyContext *rc;
4102 const struct GNUNET_MessageHeader *msg;
4108 struct GNUNET_TIME_Relative cdelay;
4111 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4114 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4117 finish_cmc_handling (cmc);
4118 GNUNET_SERVICE_client_drop (client);
4121 if (NULL == n->reassembly_map)
4123 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_YES);
4124 n->reassembly_heap =
4125 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4126 n->reassembly_timeout_task =
4127 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4128 &reassembly_cleanup_task,
4131 msize = ntohs (fb->msg_size);
4132 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map, &fb->msg_uuid);
4135 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4136 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4137 rc->msg_uuid = fb->msg_uuid;
4139 rc->msg_size = msize;
4140 rc->reassembly_timeout =
4141 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4142 rc->last_frag = GNUNET_TIME_absolute_get ();
4143 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4145 rc->reassembly_timeout.abs_value_us);
4146 GNUNET_assert (GNUNET_OK ==
4147 GNUNET_CONTAINER_multishortmap_put (
4151 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4152 target = (char *) &rc[1];
4153 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4154 rc->msg_missing = rc->msg_size;
4158 target = (char *) &rc[1];
4160 if (msize != rc->msg_size)
4163 finish_cmc_handling (cmc);
4168 fsize = ntohs (fb->header.size) - sizeof (*fb);
4169 frag_off = ntohs (fb->frag_off);
4170 memcpy (&target[frag_off], &fb[1], fsize);
4171 /* update bitfield and msg_missing */
4172 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4174 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4176 rc->bitfield[i / 8] |= (1 << (i % 8));
4181 /* Compute cummulative ACK */
4182 frag_uuid = ntohl (fb->frag_uuid);
4183 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4184 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->num_acks);
4185 rc->last_frag = GNUNET_TIME_absolute_get ();
4186 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay, cdelay);
4187 ack_now = GNUNET_NO;
4188 if (0 == rc->num_acks)
4190 /* case one: first ack */
4191 rc->frag_uuid = frag_uuid;
4192 rc->extra_acks = 0LLU;
4195 else if ((frag_uuid >= rc->frag_uuid) && (frag_uuid <= rc->frag_uuid + 64))
4197 /* case two: ack fits after existing min UUID */
4198 if ((frag_uuid == rc->frag_uuid) ||
4199 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))))
4201 /* duplicate fragment, ack now! */
4202 ack_now = GNUNET_YES;
4206 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
4210 else if ((rc->frag_uuid > frag_uuid) &&
4211 (((rc->frag_uuid == frag_uuid + 64) && (0 == rc->extra_acks)) ||
4212 ((rc->frag_uuid < frag_uuid + 64) &&
4215 ~((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))))))
4217 /* can fit ack by shifting extra acks and starting at
4218 frag_uid, test above esured that the bits we will
4219 shift 'extra_acks' by are all zero. */
4220 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
4221 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
4222 rc->frag_uuid = frag_uuid;
4225 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very
4227 ack_now = GNUNET_YES; /* maximum acks received */
4228 // FIXME: possibly also ACK based on RTT (but for that we'd need to
4229 // determine the queue used for the ACK first!)
4231 /* is reassembly complete? */
4232 if (0 != rc->msg_missing)
4235 send_fragment_ack (rc);
4236 finish_cmc_handling (cmc);
4239 /* reassembly is complete, verify result */
4240 msg = (const struct GNUNET_MessageHeader *) &rc[1];
4241 if (ntohs (msg->size) != rc->msg_size)
4244 free_reassembly_context (rc);
4245 finish_cmc_handling (cmc);
4248 /* successful reassembly */
4249 send_fragment_ack (rc);
4250 demultiplex_with_cmc (cmc, msg);
4251 /* FIXME: really free here? Might be bad if fragments are still
4252 en-route and we forget that we finished this reassembly immediately!
4253 -> keep around until timeout?
4254 -> shorten timeout based on ACK? */
4255 free_reassembly_context (rc);
4260 * Check the @a fa against the fragments associated with @a pm.
4261 * If it matches, remove the matching fragments from the transmission
4264 * @param pm pending message to check against the ack
4265 * @param fa the ack that was received
4266 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4269 check_ack_against_pm (struct PendingMessage *pm,
4270 const struct TransportFragmentAckMessage *fa)
4273 struct PendingMessage *nxt;
4274 uint32_t fs = ntohl (fa->frag_uuid);
4275 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4278 for (struct PendingMessage *frag = pm->head_frag; NULL != frag; frag = nxt)
4280 const struct TransportFragmentBox *tfb =
4281 (const struct TransportFragmentBox *) &pm[1];
4282 uint32_t fu = ntohl (tfb->frag_uuid);
4284 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4285 nxt = frag->next_frag;
4286 /* Check for exact match or match in the 'xtra' bitmask */
4288 ((fu > fs) && (fu <= fs + 64) && (0 != (1LLU << (fu - fs - 1) & xtra))))
4291 free_fragment_tree (frag);
4299 * Communicator gave us a fragment acknowledgement. Process the request.
4301 * @param cls a `struct CommunicatorMessageContext` (must call
4302 * #finish_cmc_handling() when done)
4303 * @param fa the message that was received
4306 handle_fragment_ack (void *cls, const struct TransportFragmentAckMessage *fa)
4308 struct CommunicatorMessageContext *cmc = cls;
4309 struct Neighbour *n;
4312 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4315 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4318 finish_cmc_handling (cmc);
4319 GNUNET_SERVICE_client_drop (client);
4322 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4323 matched = GNUNET_NO;
4324 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm;
4325 pm = pm->prev_neighbour)
4327 if (0 != GNUNET_memcmp (&fa->msg_uuid, &pm->msg_uuid))
4329 matched = GNUNET_YES;
4330 if (GNUNET_YES == check_ack_against_pm (pm, fa))
4332 struct GNUNET_TIME_Relative avg_ack_delay =
4333 GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4334 // FIXME: update RTT and other reliability data!
4335 // ISSUE: we don't know which of n's queues the message(s)
4336 // took (and in fact the different messages might have gone
4337 // over different queues and possibly over multiple).
4338 // => track queues with PendingMessages, and update RTT only if
4339 // the queue used is unique?
4340 // -> how can we get loss rates?
4341 // -> or, add extra state to Box and ACK to identify queue?
4342 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4343 // the queue with the fragment! (-> this logic must
4344 // be moved into check_ack_against_pm!)
4345 (void) avg_ack_delay;
4349 GNUNET_STATISTICS_update (GST_stats,
4350 "# FRAGMENT_ACKS dropped, no matching fragment",
4354 if (NULL == pm->head_frag)
4356 // if entire message is ACKed, handle that as well.
4357 // => clean up PM, any post actions?
4358 free_pending_message (pm);
4362 struct GNUNET_TIME_Relative reassembly_timeout =
4363 GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4364 // OPTIMIZE-FIXME: adjust retransmission strategy based on
4365 // reassembly_timeout!
4366 (void) reassembly_timeout;
4370 if (GNUNET_NO == matched)
4372 GNUNET_STATISTICS_update (GST_stats,
4373 "# FRAGMENT_ACKS dropped, no matching pending message",
4377 finish_cmc_handling (cmc);
4382 * Communicator gave us a reliability box. Check the message.
4384 * @param cls a `struct CommunicatorMessageContext`
4385 * @param rb the send message that was sent
4386 * @return #GNUNET_YES if message is well-formed
4389 check_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4391 GNUNET_MQ_check_boxed_message (rb);
4397 * Communicator gave us a reliability box. Process the request.
4399 * @param cls a `struct CommunicatorMessageContext` (must call
4400 * #finish_cmc_handling() when done)
4401 * @param rb the message that was received
4404 handle_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4406 struct CommunicatorMessageContext *cmc = cls;
4407 const struct GNUNET_MessageHeader *inbox =
4408 (const struct GNUNET_MessageHeader *) &rb[1];
4410 if (0 == ntohl (rb->ack_countdown))
4412 struct TransportReliabilityAckMessage *ack;
4414 /* FIXME: implement cummulative ACKs and ack_countdown,
4415 then setting the avg_ack_delay field below: */
4416 ack = GNUNET_malloc (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4417 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4419 htons (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4420 memcpy (&ack[1], &rb->msg_uuid, sizeof (struct GNUNET_ShortHashCode));
4421 route_message (&cmc->im.sender, &ack->header, RMO_DV_ALLOWED);
4423 /* continue with inner message */
4424 demultiplex_with_cmc (cmc, inbox);
4429 * Communicator gave us a reliability ack. Process the request.
4431 * @param cls a `struct CommunicatorMessageContext` (must call
4432 * #finish_cmc_handling() when done)
4433 * @param ra the message that was received
4436 handle_reliability_ack (void *cls,
4437 const struct TransportReliabilityAckMessage *ra)
4439 struct CommunicatorMessageContext *cmc = cls;
4440 struct Neighbour *n;
4441 unsigned int n_acks;
4442 const struct GNUNET_ShortHashCode *msg_uuids;
4443 struct PendingMessage *nxt;
4446 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4449 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4452 finish_cmc_handling (cmc);
4453 GNUNET_SERVICE_client_drop (client);
4456 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
4457 sizeof (struct GNUNET_ShortHashCode);
4458 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4460 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4461 matched = GNUNET_NO;
4462 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm; pm = nxt)
4466 nxt = pm->next_neighbour;
4467 in_list = GNUNET_NO;
4468 for (unsigned int i = 0; i < n_acks; i++)
4470 if (0 != GNUNET_memcmp (&msg_uuids[i], &pm->msg_uuid))
4472 in_list = GNUNET_YES;
4475 if (GNUNET_NO == in_list)
4478 /* this pm was acked! */
4479 matched = GNUNET_YES;
4480 free_pending_message (pm);
4483 struct GNUNET_TIME_Relative avg_ack_delay =
4484 GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4485 // FIXME: update RTT and other reliability data!
4486 // ISSUE: we don't know which of n's queues the message(s)
4487 // took (and in fact the different messages might have gone
4488 // over different queues and possibly over multiple).
4489 // => track queues with PendingMessages, and update RTT only if
4490 // the queue used is unique?
4491 // -> how can we get loss rates?
4492 // -> or, add extra state to MSG and ACKs to identify queue?
4493 // -> if we do this, might just do the same for the avg_ack_delay!
4494 (void) avg_ack_delay;
4497 if (GNUNET_NO == matched)
4499 GNUNET_STATISTICS_update (GST_stats,
4500 "# FRAGMENT_ACKS dropped, no matching pending message",
4504 finish_cmc_handling (cmc);
4509 * Communicator gave us a backchannel encapsulation. Check the message.
4511 * @param cls a `struct CommunicatorMessageContext`
4512 * @param be the send message that was sent
4513 * @return #GNUNET_YES if message is well-formed
4516 check_backchannel_encapsulation (
4518 const struct TransportBackchannelEncapsulationMessage *be)
4520 uint16_t size = ntohs (be->header.size);
4523 if ((size - sizeof (*be)) <
4524 (sizeof (struct TransportBackchannelRequestPayload) +
4525 sizeof (struct GNUNET_MessageHeader)))
4527 GNUNET_break_op (0);
4528 return GNUNET_SYSERR;
4535 * Communicator gave us a backchannel encapsulation. Process the request.
4536 * (We are not the origin of the backchannel here, the communicator simply
4537 * received a backchannel message and we are expected to forward it.)
4539 * @param cls a `struct CommunicatorMessageContext` (must call
4540 * #finish_cmc_handling() when done)
4541 * @param be the message that was received
4544 handle_backchannel_encapsulation (
4546 const struct TransportBackchannelEncapsulationMessage *be)
4548 struct CommunicatorMessageContext *cmc = cls;
4549 struct BackchannelKeyState key;
4550 struct GNUNET_HashCode hmac;
4554 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
4556 /* not for me, try to route to target */
4557 /* FIXME: someone needs to update be->distance! */
4558 /* FIXME: BE routing can be special, should we put all of this
4559 on 'route_message'? Maybe at least pass some more arguments? */
4560 route_message (&be->target,
4561 GNUNET_copy_message (&be->header),
4563 finish_cmc_handling (cmc);
4566 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
4567 hdr = (const char *) &be[1];
4568 hdr_len = ntohs (be->header.size) - sizeof (*be);
4569 bc_hmac (&key, &hmac, hdr, hdr_len);
4570 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
4572 /* HMAC missmatch, disard! */
4573 GNUNET_break_op (0);
4574 finish_cmc_handling (cmc);
4577 /* begin actual decryption */
4579 struct TransportBackchannelRequestPayload ppay;
4580 char body[hdr_len - sizeof (ppay)];
4582 GNUNET_assert (hdr_len >=
4583 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4584 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
4585 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
4586 bc_key_clean (&key);
4587 // FIXME: verify signatures in ppay!
4588 // => check if ephemeral key is known & valid, if not
4589 // => verify sig, cache ephemeral key
4590 // => update monotonic_time of sender for replay detection
4592 // FIXME: forward to specified communicator!
4593 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4595 finish_cmc_handling (cmc);
4600 * Task called when we should check if any of the DV paths
4601 * we have learned to a target are due for garbage collection.
4603 * Collects stale paths, and possibly frees the entire DV
4604 * entry if no paths are left. Otherwise re-schedules itself.
4606 * @param cls a `struct DistanceVector`
4609 path_cleanup_cb (void *cls)
4611 struct DistanceVector *dv = cls;
4612 struct DistanceVectorHop *pos;
4614 dv->timeout_task = NULL;
4615 while (NULL != (pos = dv->dv_head))
4617 GNUNET_assert (dv == pos->dv);
4618 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4620 free_distance_vector_hop (pos);
4628 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
4632 * Task run to check whether the hops of the @a cls still
4633 * are validated, or if we need to core about disconnection.
4635 * @param cls a `struct DistanceVector` (with core_visible set!)
4638 check_dv_path_down (void *cls)
4640 struct DistanceVector *dv = cls;
4641 struct Neighbour *n;
4643 dv->visibility_task = NULL;
4644 GNUNET_assert (GNUNET_YES == dv->core_visible);
4645 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4649 GNUNET_TIME_absolute_get_remaining (pos->path_valid_until).rel_value_us)
4651 dv->visibility_task = GNUNET_SCHEDULER_add_at (pos->path_valid_until,
4652 &check_dv_path_down,
4657 /* all paths invalid, make dv core-invisible */
4658 dv->core_visible = GNUNET_NO;
4659 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
4660 if ((NULL != n) && (GNUNET_YES == n->core_visible))
4661 return; /* no need to tell core, connection still up! */
4662 cores_send_disconnect_info (&dv->target);
4667 * The @a hop is a validated path to the respective target
4668 * peer and we should tell core about it -- and schedule
4669 * a job to revoke the state.
4671 * @param hop a path to some peer that is the reason for activation
4674 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
4676 struct DistanceVector *dv = hop->dv;
4677 struct Neighbour *n;
4679 GNUNET_assert (GNUNET_NO == dv->core_visible);
4680 GNUNET_assert (NULL == dv->visibility_task);
4682 dv->core_visible = GNUNET_YES;
4683 dv->visibility_task =
4684 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_dv_path_down, dv);
4685 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
4686 if ((NULL != n) && (GNUNET_YES == n->core_visible))
4687 return; /* no need to tell core, connection already up! */
4688 cores_send_connect_info (&dv->target, GNUNET_BANDWIDTH_ZERO);
4693 * We have learned a @a path through the network to some other peer, add it to
4694 * our DV data structure (returning #GNUNET_YES on success).
4696 * We do not add paths if we have a sufficient number of shorter
4697 * paths to this target already (returning #GNUNET_NO).
4699 * We also do not add problematic paths, like those where we lack the first
4700 * hop in our neighbour list (i.e. due to a topology change) or where some
4701 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4703 * @param path the path we learned, path[0] should be us,
4704 * and then path contains a valid path from us to `path[path_len-1]`
4705 * path[1] should be a direct neighbour (we should check!)
4706 * @param path_len number of entries on the @a path, at least three!
4707 * @param network_latency how long does the message take from us to
4708 * `path[path_len-1]`? set to "forever" if unknown
4709 * @param path_valid_until how long is this path considered validated? Maybe be
4711 * @return #GNUNET_YES on success,
4712 * #GNUNET_NO if we have better path(s) to the target
4713 * #GNUNET_SYSERR if the path is useless and/or invalid
4714 * (i.e. path[1] not a direct neighbour
4715 * or path[i+1] is a direct neighbour for i>0)
4718 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4719 unsigned int path_len,
4720 struct GNUNET_TIME_Relative network_latency,
4721 struct GNUNET_TIME_Absolute path_valid_until)
4723 struct DistanceVectorHop *hop;
4724 struct DistanceVector *dv;
4725 struct Neighbour *next_hop;
4726 unsigned int shorter_distance;
4730 /* what a boring path! not allowed! */
4732 return GNUNET_SYSERR;
4734 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
4735 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours, &path[1]);
4736 if (NULL == next_hop)
4738 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4740 return GNUNET_SYSERR;
4742 for (unsigned int i = 2; i < path_len; i++)
4743 if (NULL != GNUNET_CONTAINER_multipeermap_get (neighbours, &path[i]))
4745 /* Useless path, we have a direct connection to some hop
4746 in the middle of the path, so this one doesn't even
4747 seem terribly useful for redundancy */
4748 return GNUNET_SYSERR;
4750 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
4753 dv = GNUNET_new (struct DistanceVector);
4754 dv->target = path[path_len - 1];
4755 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4758 GNUNET_assert (GNUNET_OK ==
4759 GNUNET_CONTAINER_multipeermap_put (
4763 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4765 /* Check if we have this path already! */
4766 shorter_distance = 0;
4767 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4770 if (pos->distance < path_len - 2)
4772 /* Note that the distances in 'pos' excludes us (path[0]) and
4773 the next_hop (path[1]), so we need to subtract two
4774 and check next_hop explicitly */
4775 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
4777 int match = GNUNET_YES;
4779 for (unsigned int i = 0; i < pos->distance; i++)
4781 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
4787 if (GNUNET_YES == match)
4789 struct GNUNET_TIME_Relative last_timeout;
4791 /* Re-discovered known path, update timeout */
4792 GNUNET_STATISTICS_update (GST_stats,
4793 "# Known DV path refreshed",
4796 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4798 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4799 pos->path_valid_until =
4800 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
4801 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
4802 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
4803 if ((GNUNET_NO == dv->core_visible) &&
4804 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until)
4806 activate_core_visible_dv_path (pos);
4807 if (last_timeout.rel_value_us <
4808 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4809 DV_PATH_DISCOVERY_FREQUENCY)
4812 /* Some peer send DV learn messages too often, we are learning
4813 the same path faster than it would be useful; do not forward! */
4820 /* Count how many shorter paths we have (incl. direct
4821 neighbours) before simply giving up on this one! */
4822 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4824 /* We have a shorter path already! */
4827 /* create new DV path entry */
4828 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4829 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4830 hop->next_hop = next_hop;
4832 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4835 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4836 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4837 hop->path_valid_until = path_valid_until;
4838 hop->distance = path_len - 2;
4839 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
4840 GNUNET_CONTAINER_MDLL_insert (neighbour,
4844 if ((GNUNET_NO == dv->core_visible) &&
4845 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us))
4846 activate_core_visible_dv_path (hop);
4852 * Communicator gave us a DV learn message. Check the message.
4854 * @param cls a `struct CommunicatorMessageContext`
4855 * @param dvl the send message that was sent
4856 * @return #GNUNET_YES if message is well-formed
4859 check_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4861 uint16_t size = ntohs (dvl->header.size);
4862 uint16_t num_hops = ntohs (dvl->num_hops);
4863 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4866 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4868 GNUNET_break_op (0);
4869 return GNUNET_SYSERR;
4871 if (num_hops > MAX_DV_HOPS_ALLOWED)
4873 GNUNET_break_op (0);
4874 return GNUNET_SYSERR;
4876 for (unsigned int i = 0; i < num_hops; i++)
4878 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
4880 GNUNET_break_op (0);
4881 return GNUNET_SYSERR;
4883 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
4885 GNUNET_break_op (0);
4886 return GNUNET_SYSERR;
4894 * Build and forward a DV learn message to @a next_hop.
4896 * @param next_hop peer to send the message to
4897 * @param msg message received
4898 * @param bi_history bitmask specifying hops on path that were bidirectional
4899 * @param nhops length of the @a hops array
4900 * @param hops path the message traversed so far
4901 * @param in_time when did we receive the message, used to calculate network
4905 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4906 const struct TransportDVLearn *msg,
4907 uint16_t bi_history,
4909 const struct DVPathEntryP *hops,
4910 struct GNUNET_TIME_Absolute in_time)
4912 struct DVPathEntryP *dhops;
4913 struct TransportDVLearn *fwd;
4914 struct GNUNET_TIME_Relative nnd;
4916 /* compute message for forwarding */
4917 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4918 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4919 (nhops + 1) * sizeof (struct DVPathEntryP));
4920 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4921 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4922 (nhops + 1) * sizeof (struct DVPathEntryP));
4923 fwd->num_hops = htons (nhops + 1);
4924 fwd->bidirectional = htons (bi_history);
4925 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4926 GNUNET_TIME_relative_ntoh (
4927 msg->non_network_delay));
4928 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4929 fwd->init_sig = msg->init_sig;
4930 fwd->initiator = msg->initiator;
4931 fwd->challenge = msg->challenge;
4932 dhops = (struct DVPathEntryP *) &fwd[1];
4933 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
4934 dhops[nhops].hop = GST_my_identity;
4936 struct DvHopPS dhp = {.purpose.purpose =
4937 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4938 .purpose.size = htonl (sizeof (dhp)),
4939 .pred = dhops[nhops - 1].hop,
4941 .challenge = msg->challenge};
4943 GNUNET_assert (GNUNET_OK ==
4944 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4946 &dhops[nhops].hop_sig));
4948 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
4953 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4955 * @param init the signer
4956 * @param challenge the challenge that was signed
4957 * @param init_sig signature presumably by @a init
4958 * @return #GNUNET_OK if the signature is valid
4961 validate_dv_initiator_signature (
4962 const struct GNUNET_PeerIdentity *init,
4963 const struct GNUNET_ShortHashCode *challenge,
4964 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4966 struct DvInitPS ip = {.purpose.purpose = htonl (
4967 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4968 .purpose.size = htonl (sizeof (ip)),
4969 .challenge = *challenge};
4973 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4978 GNUNET_break_op (0);
4979 return GNUNET_SYSERR;
4986 * Communicator gave us a DV learn message. Process the request.
4988 * @param cls a `struct CommunicatorMessageContext` (must call
4989 * #finish_cmc_handling() when done)
4990 * @param dvl the message that was received
4993 handle_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4995 struct CommunicatorMessageContext *cmc = cls;
4996 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
4999 uint16_t bi_history;
5000 const struct DVPathEntryP *hops;
5003 struct GNUNET_TIME_Absolute in_time;
5005 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
5006 bi_history = ntohs (dvl->bidirectional);
5007 hops = (const struct DVPathEntryP *) &dvl[1];
5011 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
5014 finish_cmc_handling (cmc);
5021 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
5024 finish_cmc_handling (cmc);
5029 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
5030 cc = cmc->tc->details.communicator.cc;
5031 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
5032 cc); // FIXME: add bi-directional flag to cc?
5033 in_time = GNUNET_TIME_absolute_get ();
5035 /* continue communicator here, everything else can happen asynchronous! */
5036 finish_cmc_handling (cmc);
5038 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
5039 the initiator signature if we send the message back to the initiator... */
5040 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
5044 GNUNET_break_op (0);
5047 // FIXME: asynchronously (!) verify hop-by-hop signatures!
5048 // => if signature verification load too high, implement random drop
5051 do_fwd = GNUNET_YES;
5052 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
5054 struct GNUNET_PeerIdentity path[nhops + 1];
5055 struct GNUNET_TIME_Relative host_latency_sum;
5056 struct GNUNET_TIME_Relative latency;
5057 struct GNUNET_TIME_Relative network_latency;
5059 /* We initiated this, learn the forward path! */
5060 path[0] = GST_my_identity;
5061 path[1] = hops[0].hop;
5062 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
5064 // Need also something to lookup initiation time
5065 // to compute RTT! -> add RTT argument here?
5066 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
5067 // (based on dvl->challenge, we can identify time of origin!)
5069 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
5070 /* assumption: latency on all links is the same */
5071 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
5073 for (unsigned int i = 2; i <= nhops; i++)
5075 struct GNUNET_TIME_Relative ilat;
5077 /* assumption: linear latency increase per hop */
5078 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
5079 path[i] = hops[i - 1].hop;
5080 learn_dv_path (path,
5083 GNUNET_TIME_relative_to_absolute (
5084 ADDRESS_VALIDATION_LIFETIME));
5086 /* as we initiated, do not forward again (would be circular!) */
5092 /* last hop was bi-directional, we could learn something here! */
5093 struct GNUNET_PeerIdentity path[nhops + 2];
5095 path[0] = GST_my_identity;
5096 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
5097 for (unsigned int i = 0; i < nhops; i++)
5101 if (0 == (bi_history & (1 << i)))
5102 break; /* i-th hop not bi-directional, stop learning! */
5105 path[i + 2] = dvl->initiator;
5109 path[i + 2] = hops[nhops - i - 2].hop;
5112 iret = learn_dv_path (path,
5114 GNUNET_TIME_UNIT_FOREVER_REL,
5115 GNUNET_TIME_UNIT_ZERO_ABS);
5116 if (GNUNET_SYSERR == iret)
5118 /* path invalid or too long to be interesting for US, thus should also
5119 not be interesting to our neighbours, cut path when forwarding to
5120 'i' hops, except of course for the one that goes back to the
5122 GNUNET_STATISTICS_update (GST_stats,
5123 "# DV learn not forwarded due invalidity of path",
5129 if ((GNUNET_NO == iret) && (nhops == i + 1))
5131 /* we have better paths, and this is the longest target,
5132 so there cannot be anything interesting later */
5133 GNUNET_STATISTICS_update (GST_stats,
5134 "# DV learn not forwarded, got better paths",
5143 if (MAX_DV_HOPS_ALLOWED == nhops)
5145 /* At limit, we're out of here! */
5146 finish_cmc_handling (cmc);
5150 /* Forward to initiator, if path non-trivial and possible */
5151 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
5152 did_initiator = GNUNET_NO;
5155 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
5157 /* send back to origin! */
5158 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
5159 did_initiator = GNUNET_YES;
5161 /* We forward under two conditions: either we still learned something
5162 ourselves (do_fwd), or the path was darn short and thus the initiator is
5163 likely to still be very interested in this (and we did NOT already
5164 send it back to the initiator) */
5165 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
5166 (GNUNET_NO == did_initiator)))
5168 /* FIXME: loop over all neighbours, pick those with low
5169 queues AND that are not yet on the path; possibly
5170 adapt threshold to nhops! */
5172 forward_dv_learn (NULL, // fill in peer from iterator here!
5184 * Communicator gave us a DV box. Check the message.
5186 * @param cls a `struct CommunicatorMessageContext`
5187 * @param dvb the send message that was sent
5188 * @return #GNUNET_YES if message is well-formed
5191 check_dv_box (void *cls, const struct TransportDVBox *dvb)
5193 uint16_t size = ntohs (dvb->header.size);
5194 uint16_t num_hops = ntohs (dvb->num_hops);
5195 const struct GNUNET_PeerIdentity *hops =
5196 (const struct GNUNET_PeerIdentity *) &dvb[1];
5197 const struct GNUNET_MessageHeader *inbox =
5198 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5203 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
5204 sizeof (struct GNUNET_MessageHeader))
5206 GNUNET_break_op (0);
5207 return GNUNET_SYSERR;
5209 isize = ntohs (inbox->size);
5211 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
5213 GNUNET_break_op (0);
5214 return GNUNET_SYSERR;
5216 itype = ntohs (inbox->type);
5217 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
5218 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
5220 GNUNET_break_op (0);
5221 return GNUNET_SYSERR;
5223 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
5225 GNUNET_break_op (0);
5226 return GNUNET_SYSERR;
5233 * Create a DV Box message and queue it for transmission to
5236 * @param next_hop peer to receive the message next
5237 * @param total_hops how many hops did the message take so far
5238 * @param num_hops length of the @a hops array
5239 * @param origin origin of the message
5240 * @param hops next peer(s) to the destination, including destination
5241 * @param payload payload of the box
5242 * @param payload_size number of bytes in @a payload
5245 forward_dv_box (struct Neighbour *next_hop,
5246 uint16_t total_hops,
5248 const struct GNUNET_PeerIdentity *origin,
5249 const struct GNUNET_PeerIdentity *hops,
5250 const void *payload,
5251 uint16_t payload_size)
5253 struct TransportDVBox *dvb;
5254 struct GNUNET_PeerIdentity *dhops;
5256 GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBox) +
5257 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5259 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
5260 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5263 htons (sizeof (struct TransportDVBox) +
5264 sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size);
5265 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5266 dvb->total_hops = htons (total_hops);
5267 dvb->num_hops = htons (num_hops);
5268 dvb->origin = *origin;
5269 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5270 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
5271 memcpy (&dhops[num_hops], payload, payload_size);
5272 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
5277 * Communicator gave us a DV box. Process the request.
5279 * @param cls a `struct CommunicatorMessageContext` (must call
5280 * #finish_cmc_handling() when done)
5281 * @param dvb the message that was received
5284 handle_dv_box (void *cls, const struct TransportDVBox *dvb)
5286 struct CommunicatorMessageContext *cmc = cls;
5287 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5288 uint16_t num_hops = ntohs (dvb->num_hops);
5289 const struct GNUNET_PeerIdentity *hops =
5290 (const struct GNUNET_PeerIdentity *) &dvb[1];
5291 const struct GNUNET_MessageHeader *inbox =
5292 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5296 /* We're trying from the end of the hops array, as we may be
5297 able to find a shortcut unknown to the origin that way */
5298 for (int i = num_hops - 1; i >= 0; i--)
5300 struct Neighbour *n;
5302 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
5304 GNUNET_break_op (0);
5305 finish_cmc_handling (cmc);
5308 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &hops[i]);
5312 ntohs (dvb->total_hops) + 1,
5313 num_hops - i - 1, /* number of hops left */
5315 &hops[i + 1], /* remaining hops */
5316 (const void *) &dvb[1],
5318 finish_cmc_handling (cmc);
5321 /* Woopsie, next hop not in neighbours, drop! */
5322 GNUNET_STATISTICS_update (GST_stats,
5323 "# DV Boxes dropped: next hop unknown",
5326 finish_cmc_handling (cmc);
5329 /* We are the target. Unbox and handle message. */
5330 cmc->im.sender = dvb->origin;
5331 cmc->total_hops = ntohs (dvb->total_hops);
5332 demultiplex_with_cmc (cmc, inbox);
5337 * Client notified us about transmission from a peer. Process the request.
5339 * @param cls a `struct TransportClient` which sent us the message
5340 * @param obm the send message that was sent
5341 * @return #GNUNET_YES if message is well-formed
5344 check_incoming_msg (void *cls,
5345 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5347 struct TransportClient *tc = cls;
5349 if (CT_COMMUNICATOR != tc->type)
5352 return GNUNET_SYSERR;
5354 GNUNET_MQ_check_boxed_message (im);
5360 * Communicator gave us a transport address validation challenge. Process the
5363 * @param cls a `struct CommunicatorMessageContext` (must call
5364 * #finish_cmc_handling() when done)
5365 * @param tvc the message that was received
5368 handle_validation_challenge (void *cls,
5369 const struct TransportValidationChallenge *tvc)
5371 struct CommunicatorMessageContext *cmc = cls;
5372 struct TransportValidationResponse *tvr;
5374 if (cmc->total_hops > 0)
5376 /* DV routing is not allowed for validation challenges! */
5377 GNUNET_break_op (0);
5378 finish_cmc_handling (cmc);
5381 tvr = GNUNET_new (struct TransportValidationResponse);
5383 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5384 tvr->header.size = htons (sizeof (*tvr));
5385 tvr->challenge = tvc->challenge;
5386 tvr->origin_time = tvc->sender_time;
5387 tvr->validity_duration = cmc->im.expected_address_validity;
5389 /* create signature */
5390 struct TransportValidationPS tvp =
5391 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5392 .purpose.size = htonl (sizeof (tvp)),
5393 .validity_duration = tvr->validity_duration,
5394 .challenge = tvc->challenge};
5396 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5400 route_message (&cmc->im.sender,
5402 RMO_ANYTHING_GOES | RMO_REDUNDANT);
5403 finish_cmc_handling (cmc);
5408 * Closure for #check_known_challenge.
5410 struct CheckKnownChallengeContext
5413 * Set to the challenge we are looking for.
5415 const struct GNUNET_ShortHashCode *challenge;
5418 * Set to a matching validation state, if one was found.
5420 struct ValidationState *vs;
5425 * Test if the validation state in @a value matches the
5426 * challenge from @a cls.
5428 * @param cls a `struct CheckKnownChallengeContext`
5429 * @param pid unused (must match though)
5430 * @param value a `struct ValidationState`
5431 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5434 check_known_challenge (void *cls,
5435 const struct GNUNET_PeerIdentity *pid,
5438 struct CheckKnownChallengeContext *ckac = cls;
5439 struct ValidationState *vs = value;
5442 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
5450 * Function called when peerstore is done storing a
5451 * validated address.
5453 * @param cls a `struct ValidationState`
5454 * @param success #GNUNET_YES on success
5457 peerstore_store_validation_cb (void *cls, int success)
5459 struct ValidationState *vs = cls;
5462 if (GNUNET_YES == success)
5464 GNUNET_STATISTICS_update (GST_stats,
5465 "# Peerstore failed to store foreign address",
5472 * Task run periodically to validate some address based on #validation_heap.
5477 validation_start_cb (void *cls);
5481 * Set the time for next_challenge of @a vs to @a new_time.
5482 * Updates the heap and if necessary reschedules the job.
5484 * @param vs validation state to update
5485 * @param new_time new time for revalidation
5488 update_next_challenge_time (struct ValidationState *vs,
5489 struct GNUNET_TIME_Absolute new_time)
5491 struct GNUNET_TIME_Relative delta;
5493 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5494 return; /* be lazy */
5495 vs->next_challenge = new_time;
5498 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
5500 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
5501 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5502 (NULL != validation_task))
5504 if (NULL != validation_task)
5505 GNUNET_SCHEDULER_cancel (validation_task);
5506 /* randomize a bit */
5507 delta.rel_value_us =
5508 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5509 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5510 new_time = GNUNET_TIME_absolute_add (new_time, delta);
5512 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
5517 * Find the queue matching @a pid and @a address.
5519 * @param pid peer the queue must go to
5520 * @param address address the queue must use
5521 * @return NULL if no such queue exists
5523 static struct Queue *
5524 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
5526 struct Neighbour *n;
5528 n = GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
5531 for (struct Queue *pos = n->queue_head; NULL != pos;
5532 pos = pos->next_neighbour)
5534 if (0 == strcmp (pos->address, address))
5542 * Task run periodically to check whether the validity of the given queue has
5543 * run its course. If so, finds either another queue to take over, or clears
5544 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
5545 * chance to take over, and if that fails, notifies CORE about the disconnect.
5547 * @param cls a `struct Queue`
5550 core_queue_visibility_check (void *cls)
5552 struct Queue *q = cls;
5554 q->visibility_task = NULL;
5555 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5557 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5558 &core_queue_visibility_check,
5562 update_neighbour_core_visibility (q->neighbour);
5567 * Check whether the CORE visibility of @a n should change. Finds either a
5568 * queue to preserve the visibility, or clears the neighbour's `core_visible`
5569 * flag. In the latter case, gives DV routes a chance to take over, and if
5570 * that fails, notifies CORE about the disconnect. If so, check whether we
5571 * need to notify CORE.
5573 * @param n neighbour to perform the check for
5576 update_neighbour_core_visibility (struct Neighbour *n)
5578 struct DistanceVector *dv;
5580 GNUNET_assert (GNUNET_YES == n->core_visible);
5581 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
5582 the #core_queue_visibility_check() task for that queue */
5583 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
5586 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5588 /* found a valid queue, use this one */
5589 q->visibility_task =
5590 GNUNET_SCHEDULER_add_at (q->validated_until,
5591 &core_queue_visibility_check,
5596 n->core_visible = GNUNET_NO;
5598 /* Check if _any_ DV route to this neighbour is currently
5599 valid, if so, do NOT tell core about the loss of direct
5600 connectivity (DV still counts!) */
5601 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
5602 if (GNUNET_YES == dv->core_visible)
5604 /* Nothing works anymore, need to tell CORE about the loss of
5606 cores_send_disconnect_info (&n->pid);
5611 * Communicator gave us a transport address validation response. Process the
5614 * @param cls a `struct CommunicatorMessageContext` (must call
5615 * #finish_cmc_handling() when done)
5616 * @param tvr the message that was received
5619 handle_validation_response (void *cls,
5620 const struct TransportValidationResponse *tvr)
5622 struct CommunicatorMessageContext *cmc = cls;
5623 struct ValidationState *vs;
5624 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
5626 struct GNUNET_TIME_Absolute origin_time;
5628 struct DistanceVector *dv;
5630 /* check this is one of our challenges */
5631 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5633 &check_known_challenge,
5635 if (NULL == (vs = ckac.vs))
5637 /* This can happen simply if we 'forgot' the challenge by now,
5638 i.e. because we received the validation response twice */
5639 GNUNET_STATISTICS_update (GST_stats,
5640 "# Validations dropped, challenge unknown",
5643 finish_cmc_handling (cmc);
5647 /* sanity check on origin time */
5648 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
5649 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
5650 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
5652 GNUNET_break_op (0);
5653 finish_cmc_handling (cmc);
5658 /* check signature */
5659 struct TransportValidationPS tvp =
5660 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5661 .purpose.size = htonl (sizeof (tvp)),
5662 .validity_duration = tvr->validity_duration,
5663 .challenge = tvr->challenge};
5667 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
5670 &cmc->im.sender.public_key))
5672 GNUNET_break_op (0);
5673 finish_cmc_handling (cmc);
5678 /* validity is capped by our willingness to keep track of the
5679 validation entry and the maximum the other peer allows */
5680 vs->valid_until = GNUNET_TIME_relative_to_absolute (
5681 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
5682 tvr->validity_duration),
5683 MAX_ADDRESS_VALID_UNTIL));
5684 vs->validated_until =
5685 GNUNET_TIME_absolute_min (vs->valid_until,
5686 GNUNET_TIME_relative_to_absolute (
5687 ADDRESS_VALIDATION_LIFETIME));
5688 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
5689 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
5690 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5692 sizeof (vs->challenge));
5693 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
5694 vs->validated_until,
5695 GNUNET_TIME_relative_multiply (vs->validation_rtt,
5696 VALIDATION_RTT_BUFFER_FACTOR));
5697 vs->last_challenge_use =
5698 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
5699 update_next_challenge_time (vs, vs->first_challenge_use);
5700 vs->sc = GNUNET_PEERSTORE_store (peerstore,
5703 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
5705 strlen (vs->address) + 1,
5707 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5708 &peerstore_store_validation_cb,
5710 finish_cmc_handling (cmc);
5712 /* Finally, we now possibly have a confirmed (!) working queue,
5713 update queue status (if queue still is around) */
5714 q = find_queue (&vs->pid, vs->address);
5717 GNUNET_STATISTICS_update (GST_stats,
5718 "# Queues lost at time of successful validation",
5723 q->validated_until = vs->validated_until;
5724 q->rtt = vs->validation_rtt;
5725 if (GNUNET_NO != q->neighbour->core_visible)
5726 return; /* nothing changed, we are done here */
5727 q->neighbour->core_visible = GNUNET_YES;
5728 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5729 &core_queue_visibility_check,
5731 /* Check if _any_ DV route to this neighbour is
5732 currently valid, if so, do NOT tell core anything! */
5733 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &q->neighbour->pid);
5734 if (GNUNET_YES == dv->core_visible)
5735 return; /* nothing changed, done */
5736 /* We lacked a confirmed connection to the neighbour
5737 before, so tell CORE about it (finally!) */
5738 cores_send_connect_info (&q->neighbour->pid, GNUNET_BANDWIDTH_ZERO);
5743 * Incoming meessage. Process the request.
5745 * @param im the send message that was received
5748 handle_incoming_msg (void *cls,
5749 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5751 struct TransportClient *tc = cls;
5752 struct CommunicatorMessageContext *cmc =
5753 GNUNET_new (struct CommunicatorMessageContext);
5757 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
5762 * Given an inbound message @a msg from a communicator @a cmc,
5763 * demultiplex it based on the type calling the right handler.
5765 * @param cmc context for demultiplexing
5766 * @param msg message to demultiplex
5769 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5770 const struct GNUNET_MessageHeader *msg)
5772 struct GNUNET_MQ_MessageHandler handlers[] =
5773 {GNUNET_MQ_hd_var_size (fragment_box,
5774 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
5775 struct TransportFragmentBox,
5777 GNUNET_MQ_hd_fixed_size (fragment_ack,
5778 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
5779 struct TransportFragmentAckMessage,
5781 GNUNET_MQ_hd_var_size (reliability_box,
5782 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5783 struct TransportReliabilityBox,
5785 GNUNET_MQ_hd_fixed_size (reliability_ack,
5786 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5787 struct TransportReliabilityAckMessage,
5789 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5790 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5791 struct TransportBackchannelEncapsulationMessage,
5793 GNUNET_MQ_hd_var_size (dv_learn,
5794 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5795 struct TransportDVLearn,
5797 GNUNET_MQ_hd_var_size (dv_box,
5798 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5799 struct TransportDVBox,
5801 GNUNET_MQ_hd_fixed_size (
5802 validation_challenge,
5803 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5804 struct TransportValidationChallenge,
5806 GNUNET_MQ_hd_fixed_size (
5807 validation_response,
5808 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5809 struct TransportValidationResponse,
5811 GNUNET_MQ_handler_end ()};
5814 ret = GNUNET_MQ_handle_message (handlers, msg);
5815 if (GNUNET_SYSERR == ret)
5818 GNUNET_SERVICE_client_drop (cmc->tc->client);
5822 if (GNUNET_NO == ret)
5824 /* unencapsulated 'raw' message */
5825 handle_raw_message (&cmc, msg);
5831 * New queue became available. Check message.
5833 * @param cls the client
5834 * @param aqm the send message that was sent
5837 check_add_queue_message (void *cls,
5838 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5840 struct TransportClient *tc = cls;
5842 if (CT_COMMUNICATOR != tc->type)
5845 return GNUNET_SYSERR;
5847 GNUNET_MQ_check_zero_termination (aqm);
5853 * Bandwidth tracker informs us that the delay until we should receive
5856 * @param cls a `struct Queue` for which the delay changed
5859 tracker_update_in_cb (void *cls)
5861 struct Queue *queue = cls;
5862 struct GNUNET_TIME_Relative in_delay;
5865 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5866 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
5867 // FIXME: how exactly do we do inbound flow control?
5872 * If necessary, generates the UUID for a @a pm
5874 * @param pm pending message to generate UUID for.
5877 set_pending_message_uuid (struct PendingMessage *pm)
5879 if (pm->msg_uuid_set)
5881 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5883 sizeof (pm->msg_uuid));
5884 pm->msg_uuid_set = GNUNET_YES;
5889 * Fragment the given @a pm to the given @a mtu. Adds
5890 * additional fragments to the neighbour as well. If the
5891 * @a mtu is too small, generates and error for the @a pm
5894 * @param pm pending message to fragment for transmission
5895 * @param mtu MTU to apply
5896 * @return new message to transmit
5898 static struct PendingMessage *
5899 fragment_message (struct PendingMessage *pm, uint16_t mtu)
5901 struct PendingMessage *ff;
5903 set_pending_message_uuid (pm);
5905 /* This invariant is established in #handle_add_queue_message() */
5906 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5908 /* select fragment for transmission, descending the tree if it has
5909 been expanded until we are at a leaf or at a fragment that is small enough
5912 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
5913 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
5915 ff = ff->head_frag; /* descent into fragmented fragments */
5918 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
5920 /* Did not yet calculate all fragments, calculate next fragment */
5921 struct PendingMessage *frag;
5922 struct TransportFragmentBox tfb;
5930 orig = (const char *) &ff[1];
5931 msize = ff->bytes_msg;
5934 const struct TransportFragmentBox *tfbo;
5936 tfbo = (const struct TransportFragmentBox *) orig;
5937 orig += sizeof (struct TransportFragmentBox);
5938 msize -= sizeof (struct TransportFragmentBox);
5939 xoff = ntohs (tfbo->frag_off);
5941 fragmax = mtu - sizeof (struct TransportFragmentBox);
5942 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
5943 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5944 sizeof (struct TransportFragmentBox) + fragsize);
5945 frag->target = pm->target;
5946 frag->frag_parent = ff;
5947 frag->timeout = pm->timeout;
5948 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5949 frag->pmt = PMT_FRAGMENT_BOX;
5950 msg = (char *) &frag[1];
5951 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
5952 tfb.header.size = htons (sizeof (struct TransportFragmentBox) + fragsize);
5953 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
5954 tfb.msg_uuid = pm->msg_uuid;
5955 tfb.frag_off = htons (ff->frag_off + xoff);
5956 tfb.msg_size = htons (pm->bytes_msg);
5957 memcpy (msg, &tfb, sizeof (tfb));
5958 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
5959 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
5960 ff->frag_off += fragsize;
5964 /* Move head to the tail and return it */
5965 GNUNET_CONTAINER_MDLL_remove (frag,
5966 ff->frag_parent->head_frag,
5967 ff->frag_parent->tail_frag,
5969 GNUNET_CONTAINER_MDLL_insert_tail (frag,
5970 ff->frag_parent->head_frag,
5971 ff->frag_parent->tail_frag,
5978 * Reliability-box the given @a pm. On error (can there be any), NULL
5979 * may be returned, otherwise the "replacement" for @a pm (which
5980 * should then be added to the respective neighbour's queue instead of
5981 * @a pm). If the @a pm is already fragmented or reliability boxed,
5982 * or itself an ACK, this function simply returns @a pm.
5984 * @param pm pending message to box for transmission over unreliabile queue
5985 * @return new message to transmit
5987 static struct PendingMessage *
5988 reliability_box_message (struct PendingMessage *pm)
5990 struct TransportReliabilityBox rbox;
5991 struct PendingMessage *bpm;
5994 if (PMT_CORE != pm->pmt)
5995 return pm; /* already fragmented or reliability boxed, or control message:
5997 if (NULL != pm->bpm)
5998 return pm->bpm; /* already computed earlier: do nothing */
5999 GNUNET_assert (NULL == pm->head_frag);
6000 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
6004 client_send_response (pm, GNUNET_NO, 0);
6007 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
6009 bpm->target = pm->target;
6010 bpm->frag_parent = pm;
6011 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
6012 bpm->timeout = pm->timeout;
6013 bpm->pmt = PMT_RELIABILITY_BOX;
6014 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
6015 set_pending_message_uuid (bpm);
6016 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
6017 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
6018 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
6019 rbox.msg_uuid = pm->msg_uuid;
6020 msg = (char *) &bpm[1];
6021 memcpy (msg, &rbox, sizeof (rbox));
6022 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
6029 * We believe we are ready to transmit a message on a queue. Double-checks
6030 * with the queue's "tracker_out" and then gives the message to the
6031 * communicator for transmission (updating the tracker, and re-scheduling
6032 * itself if applicable).
6034 * @param cls the `struct Queue` to process transmissions for
6037 transmit_on_queue (void *cls)
6039 struct Queue *queue = cls;
6040 struct Neighbour *n = queue->neighbour;
6041 struct PendingMessage *pm;
6042 struct PendingMessage *s;
6045 queue->transmit_task = NULL;
6046 if (NULL == (pm = n->pending_msg_head))
6048 /* no message pending, nothing to do here! */
6051 schedule_transmit_on_queue (queue);
6052 if (NULL != queue->transmit_task)
6053 return; /* do it later */
6055 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6056 overhead += sizeof (struct TransportReliabilityBox);
6058 if ( ( (0 != queue->mtu) &&
6059 (pm->bytes_msg + overhead > queue->mtu) ) ||
6060 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
6061 (NULL != pm->head_frag /* fragments already exist, should
6062 respect that even if MTU is 0 for
6064 s = fragment_message (s,
6067 sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
6071 /* Fragmentation failed, try next message... */
6072 schedule_transmit_on_queue (queue);
6075 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6076 s = reliability_box_message (s);
6079 /* Reliability boxing failed, try next message... */
6080 schedule_transmit_on_queue (queue);
6084 /* Pass 's' for transission to the communicator */
6085 queue_send_msg (queue, s, &s[1], s->bytes_msg);
6086 // FIXME: do something similar to the logic below
6087 // in defragmentation / reliability ACK handling!
6089 /* Check if this transmission somehow conclusively finished handing 'pm'
6090 even without any explicit ACKs */
6091 if ((PMT_CORE == s->pmt) &&
6092 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
6094 /* Full message sent, and over reliabile channel */
6095 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
6097 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
6098 queue->tc->details.communicator.cc) &&
6099 (PMT_FRAGMENT_BOX == s->pmt))
6101 struct PendingMessage *pos;
6103 /* Fragment sent over reliabile channel */
6104 free_fragment_tree (s);
6105 pos = s->frag_parent;
6106 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6108 /* check if subtree is done */
6109 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6113 pos = s->frag_parent;
6114 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6118 /* Was this the last applicable fragmment? */
6119 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
6120 client_send_response (
6123 pm->bytes_msg /* FIXME: calculate and add overheads! */);
6125 else if (PMT_CORE != pm->pmt)
6127 /* This was an acknowledgement of some type, always free */
6128 free_pending_message (pm);
6132 /* message not finished, waiting for acknowledgement */
6133 struct Neighbour *neighbour = pm->target;
6134 /* Update time by which we might retransmit 's' based on queue
6135 characteristics (i.e. RTT); it takes one RTT for the message to
6136 arrive and the ACK to come back in the best case; but the other
6137 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
6138 retransmitting. Note that in the future this heuristic should
6139 likely be improved further (measure RTT stability, consider
6140 message urgency and size when delaying ACKs, etc.) */
6141 s->next_attempt = GNUNET_TIME_relative_to_absolute (
6142 GNUNET_TIME_relative_multiply (queue->rtt, 4));
6145 struct PendingMessage *pos;
6147 /* re-insert sort in neighbour list */
6148 GNUNET_CONTAINER_MDLL_remove (neighbour,
6149 neighbour->pending_msg_head,
6150 neighbour->pending_msg_tail,
6152 pos = neighbour->pending_msg_tail;
6153 while ((NULL != pos) &&
6154 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6155 pos = pos->prev_neighbour;
6156 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
6157 neighbour->pending_msg_head,
6158 neighbour->pending_msg_tail,
6164 /* re-insert sort in fragment list */
6165 struct PendingMessage *fp = s->frag_parent;
6166 struct PendingMessage *pos;
6168 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, s);
6169 pos = fp->tail_frag;
6170 while ((NULL != pos) &&
6171 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6172 pos = pos->prev_frag;
6173 GNUNET_CONTAINER_MDLL_insert_after (frag,
6181 /* finally, re-schedule queue transmission task itself */
6182 schedule_transmit_on_queue (queue);
6187 * Bandwidth tracker informs us that the delay until we
6188 * can transmit again changed.
6190 * @param cls a `struct Queue` for which the delay changed
6193 tracker_update_out_cb (void *cls)
6195 struct Queue *queue = cls;
6196 struct Neighbour *n = queue->neighbour;
6198 if (NULL == n->pending_msg_head)
6200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6201 "Bandwidth allocation updated for empty transmission queue `%s'\n",
6203 return; /* no message pending, nothing to do here! */
6205 GNUNET_SCHEDULER_cancel (queue->transmit_task);
6206 queue->transmit_task = NULL;
6207 schedule_transmit_on_queue (queue);
6212 * Bandwidth tracker informs us that excessive outbound bandwidth was
6213 * allocated which is not being used.
6215 * @param cls a `struct Queue` for which the excess was noted
6218 tracker_excess_out_cb (void *cls)
6222 /* FIXME: trigger excess bandwidth report to core? Right now,
6223 this is done internally within transport_api2_core already,
6224 but we probably want to change the logic and trigger it
6225 from here via a message instead! */
6226 /* TODO: maybe inform someone at this point? */
6227 GNUNET_STATISTICS_update (GST_stats,
6228 "# Excess outbound bandwidth reported",
6235 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
6236 * which is not being used.
6238 * @param cls a `struct Queue` for which the excess was noted
6241 tracker_excess_in_cb (void *cls)
6245 /* TODO: maybe inform somone at this point? */
6246 GNUNET_STATISTICS_update (GST_stats,
6247 "# Excess inbound bandwidth reported",
6254 * Queue to a peer went down. Process the request.
6256 * @param cls the client
6257 * @param dqm the send message that was sent
6260 handle_del_queue_message (void *cls,
6261 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
6263 struct TransportClient *tc = cls;
6265 if (CT_COMMUNICATOR != tc->type)
6268 GNUNET_SERVICE_client_drop (tc->client);
6271 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6272 queue = queue->next_client)
6274 struct Neighbour *neighbour = queue->neighbour;
6276 if ((dqm->qid != queue->qid) ||
6277 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
6280 GNUNET_SERVICE_client_continue (tc->client);
6284 GNUNET_SERVICE_client_drop (tc->client);
6289 * Message was transmitted. Process the request.
6291 * @param cls the client
6292 * @param sma the send message that was sent
6295 handle_send_message_ack (void *cls,
6296 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
6298 struct TransportClient *tc = cls;
6299 struct QueueEntry *qe;
6301 if (CT_COMMUNICATOR != tc->type)
6304 GNUNET_SERVICE_client_drop (tc->client);
6308 /* find our queue entry matching the ACK */
6310 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6311 queue = queue->next_client)
6313 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
6315 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
6318 if (qep->mid != sma->mid)
6327 /* this should never happen */
6329 GNUNET_SERVICE_client_drop (tc->client);
6332 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6333 qe->queue->queue_tail,
6335 qe->queue->queue_length--;
6336 tc->details.communicator.total_queue_length--;
6337 GNUNET_SERVICE_client_continue (tc->client);
6339 /* if applicable, resume transmissions that waited on ACK */
6340 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
6341 tc->details.communicator.total_queue_length)
6343 /* Communicator dropped below threshold, resume all queues */
6344 GNUNET_STATISTICS_update (
6346 "# Transmission throttled due to communicator queue limit",
6349 for (struct Queue *queue = tc->details.communicator.queue_head;
6351 queue = queue->next_client)
6352 schedule_transmit_on_queue (queue);
6354 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6356 /* queue dropped below threshold; only resume this one queue */
6357 GNUNET_STATISTICS_update (GST_stats,
6358 "# Transmission throttled due to queue queue limit",
6361 schedule_transmit_on_queue (qe->queue);
6364 /* TODO: we also should react on the status! */
6365 // FIXME: this probably requires queue->pm = s assignment!
6366 // FIXME: react to communicator status about transmission request. We got:
6367 sma->status; // OK success, SYSERR failure
6374 * Iterator telling new MONITOR client about all existing
6377 * @param cls the new `struct TransportClient`
6378 * @param pid a connected peer
6379 * @param value the `struct Neighbour` with more information
6380 * @return #GNUNET_OK (continue to iterate)
6383 notify_client_queues (void *cls,
6384 const struct GNUNET_PeerIdentity *pid,
6387 struct TransportClient *tc = cls;
6388 struct Neighbour *neighbour = value;
6390 GNUNET_assert (CT_MONITOR == tc->type);
6391 for (struct Queue *q = neighbour->queue_head; NULL != q;
6392 q = q->next_neighbour)
6394 struct MonitorEvent me = {.rtt = q->rtt,
6396 .num_msg_pending = q->num_msg_pending,
6397 .num_bytes_pending = q->num_bytes_pending};
6399 notify_monitor (tc, pid, q->address, q->nt, &me);
6406 * Initialize a monitor client.
6408 * @param cls the client
6409 * @param start the start message that was sent
6412 handle_monitor_start (void *cls,
6413 const struct GNUNET_TRANSPORT_MonitorStart *start)
6415 struct TransportClient *tc = cls;
6417 if (CT_NONE != tc->type)
6420 GNUNET_SERVICE_client_drop (tc->client);
6423 tc->type = CT_MONITOR;
6424 tc->details.monitor.peer = start->peer;
6425 tc->details.monitor.one_shot = ntohl (start->one_shot);
6426 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
6427 GNUNET_SERVICE_client_mark_monitor (tc->client);
6428 GNUNET_SERVICE_client_continue (tc->client);
6433 * Find transport client providing communication service
6434 * for the protocol @a prefix.
6436 * @param prefix communicator name
6437 * @return NULL if no such transport client is available
6439 static struct TransportClient *
6440 lookup_communicator (const char *prefix)
6442 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6444 if (CT_COMMUNICATOR != tc->type)
6446 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
6450 GNUNET_ERROR_TYPE_WARNING,
6451 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6458 * Signature of a function called with a communicator @a address of a peer
6459 * @a pid that an application wants us to connect to.
6461 * @param pid target peer
6462 * @param address the address to try
6465 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
6467 static uint32_t idgen;
6468 struct TransportClient *tc;
6470 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6471 struct GNUNET_MQ_Envelope *env;
6474 prefix = GNUNET_HELLO_address_to_prefix (address);
6477 GNUNET_break (0); /* We got an invalid address!? */
6480 tc = lookup_communicator (prefix);
6483 GNUNET_STATISTICS_update (GST_stats,
6484 "# Suggestions ignored due to missing communicator",
6489 /* forward suggestion for queue creation to communicator */
6490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6491 "Request #%u for `%s' communicator to create queue to `%s'\n",
6492 (unsigned int) idgen,
6495 alen = strlen (address) + 1;
6497 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6498 cqm->request_id = htonl (idgen++);
6499 cqm->receiver = *pid;
6500 memcpy (&cqm[1], address, alen);
6501 GNUNET_MQ_send (tc->mq, env);
6506 * The queue @a q (which matches the peer and address in @a vs) is
6507 * ready for queueing. We should now queue the validation request.
6509 * @param q queue to send on
6510 * @param vs state to derive validation challenge from
6513 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
6515 struct TransportValidationChallenge tvc;
6517 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6519 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6520 tvc.header.size = htons (sizeof (tvc));
6521 tvc.reserved = htonl (0);
6522 tvc.challenge = vs->challenge;
6523 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6524 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
6529 * Task run periodically to validate some address based on #validation_heap.
6534 validation_start_cb (void *cls)
6536 struct ValidationState *vs;
6540 validation_task = NULL;
6541 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6542 /* drop validations past their expiration */
6545 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
6547 free_validation_state (vs);
6548 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6551 return; /* woopsie, no more addresses known, should only
6552 happen if we're really a lonely peer */
6553 q = find_queue (&vs->pid, vs->address);
6556 vs->awaiting_queue = GNUNET_YES;
6557 suggest_to_connect (&vs->pid, vs->address);
6560 validation_transmit_on_queue (q, vs);
6561 /* Finally, reschedule next attempt */
6562 vs->challenge_backoff =
6563 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
6564 MAX_VALIDATION_CHALLENGE_FREQ);
6565 update_next_challenge_time (vs,
6566 GNUNET_TIME_relative_to_absolute (
6567 vs->challenge_backoff));
6572 * Closure for #check_connection_quality.
6574 struct QueueQualityContext
6577 * Set to the @e k'th queue encountered.
6582 * Set to the number of quality queues encountered.
6584 unsigned int quality_count;
6587 * Set to the total number of queues encountered.
6589 unsigned int num_queues;
6592 * Decremented for each queue, for selection of the
6593 * k-th queue in @e q.
6600 * Check whether any queue to the given neighbour is
6601 * of a good "quality" and if so, increment the counter.
6602 * Also counts the total number of queues, and returns
6603 * the k-th queue found.
6605 * @param cls a `struct QueueQualityContext *` with counters
6606 * @param pid peer this is about
6607 * @param value a `struct Neighbour`
6608 * @return #GNUNET_OK (continue to iterate)
6611 check_connection_quality (void *cls,
6612 const struct GNUNET_PeerIdentity *pid,
6615 struct QueueQualityContext *ctx = cls;
6616 struct Neighbour *n = value;
6621 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6623 if (0 != q->distance)
6624 continue; /* DV does not count */
6628 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
6629 statistics and consider those as well here? */
6630 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
6631 do_inc = GNUNET_YES;
6633 if (GNUNET_YES == do_inc)
6634 ctx->quality_count++;
6640 * Task run when we CONSIDER initiating a DV learn
6641 * process. We first check that sending out a message is
6642 * even possible (queues exist), then that it is desirable
6643 * (if not, reschedule the task for later), and finally
6644 * we may then begin the job. If there are too many
6645 * entries in the #dvlearn_map, we purge the oldest entry
6651 start_dv_learn (void *cls)
6653 struct LearnLaunchEntry *lle;
6654 struct QueueQualityContext qqc;
6655 struct TransportDVLearn dvl;
6658 dvlearn_task = NULL;
6659 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
6660 return; /* lost all connectivity, cannot do learning */
6661 qqc.quality_count = 0;
6663 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6664 &check_connection_quality,
6666 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
6668 struct GNUNET_TIME_Relative delay;
6669 unsigned int factor;
6671 /* scale our retries by how far we are above the threshold */
6672 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6673 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
6674 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
6677 /* remove old entries in #dvlearn_map if it has grown too big */
6678 while (MAX_DV_LEARN_PENDING >=
6679 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6682 GNUNET_assert (GNUNET_YES ==
6683 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6686 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
6689 /* setup data structure for learning */
6690 lle = GNUNET_new (struct LearnLaunchEntry);
6691 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6693 sizeof (lle->challenge));
6694 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
6695 GNUNET_break (GNUNET_YES ==
6696 GNUNET_CONTAINER_multishortmap_put (
6700 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6701 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6702 dvl.header.size = htons (sizeof (dvl));
6703 dvl.num_hops = htons (0);
6704 dvl.bidirectional = htons (0);
6705 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6707 struct DvInitPS dvip = {.purpose.purpose = htonl (
6708 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6709 .purpose.size = htonl (sizeof (dvip)),
6710 .challenge = lle->challenge};
6712 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6716 dvl.initiator = GST_my_identity;
6717 dvl.challenge = lle->challenge;
6719 qqc.quality_count = 0;
6720 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
6723 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6724 &check_connection_quality,
6726 GNUNET_assert (NULL != qqc.q);
6728 /* Do this as close to transmission time as possible! */
6729 lle->launch_time = GNUNET_TIME_absolute_get ();
6731 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
6732 /* reschedule this job, randomizing the time it runs (but no
6734 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
6735 DV_LEARN_BASE_FREQUENCY),
6742 * A new queue has been created, check if any address validation
6743 * requests have been waiting for it.
6745 * @param cls a `struct Queue`
6746 * @param pid peer concerned (unused)
6747 * @param value a `struct ValidationState`
6748 * @return #GNUNET_NO if a match was found and we can stop looking
6751 check_validation_request_pending (void *cls,
6752 const struct GNUNET_PeerIdentity *pid,
6755 struct Queue *q = cls;
6756 struct ValidationState *vs = value;
6759 if ((GNUNET_YES == vs->awaiting_queue) &&
6760 (0 == strcmp (vs->address, q->address)))
6762 vs->awaiting_queue = GNUNET_NO;
6763 validation_transmit_on_queue (q, vs);
6771 * New queue became available. Process the request.
6773 * @param cls the client
6774 * @param aqm the send message that was sent
6777 handle_add_queue_message (void *cls,
6778 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6780 struct TransportClient *tc = cls;
6781 struct Queue *queue;
6782 struct Neighbour *neighbour;
6786 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6788 /* MTU so small as to be useless for transmissions,
6789 required for #fragment_message()! */
6790 GNUNET_break_op (0);
6791 GNUNET_SERVICE_client_drop (tc->client);
6794 neighbour = lookup_neighbour (&aqm->receiver);
6795 if (NULL == neighbour)
6797 neighbour = GNUNET_new (struct Neighbour);
6798 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6799 neighbour->pid = aqm->receiver;
6800 GNUNET_assert (GNUNET_OK ==
6801 GNUNET_CONTAINER_multipeermap_put (
6805 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6807 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6808 addr = (const char *) &aqm[1];
6810 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6812 queue->address = (const char *) &queue[1];
6813 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6814 queue->qid = aqm->qid;
6815 queue->mtu = ntohl (aqm->mtu);
6816 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6817 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6818 queue->neighbour = neighbour;
6819 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6820 &tracker_update_in_cb,
6822 GNUNET_BANDWIDTH_ZERO,
6823 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6824 &tracker_excess_in_cb,
6826 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6827 &tracker_update_out_cb,
6829 GNUNET_BANDWIDTH_ZERO,
6830 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6831 &tracker_excess_out_cb,
6833 memcpy (&queue[1], addr, addr_len);
6834 /* notify monitors about new queue */
6836 struct MonitorEvent me = {.rtt = queue->rtt, .cs = queue->cs};
6838 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
6840 GNUNET_CONTAINER_MDLL_insert (neighbour,
6841 neighbour->queue_head,
6842 neighbour->queue_tail,
6844 GNUNET_CONTAINER_MDLL_insert (client,
6845 tc->details.communicator.queue_head,
6846 tc->details.communicator.queue_tail,
6848 /* check if valdiations are waiting for the queue */
6850 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6852 &check_validation_request_pending,
6854 /* might be our first queue, try launching DV learning */
6855 if (NULL == dvlearn_task)
6856 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
6857 GNUNET_SERVICE_client_continue (tc->client);
6862 * Communicator tells us that our request to create a queue "worked", that
6863 * is setting up the queue is now in process.
6865 * @param cls the `struct TransportClient`
6866 * @param cqr confirmation message
6869 handle_queue_create_ok (void *cls,
6870 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6872 struct TransportClient *tc = cls;
6874 if (CT_COMMUNICATOR != tc->type)
6877 GNUNET_SERVICE_client_drop (tc->client);
6880 GNUNET_STATISTICS_update (GST_stats,
6881 "# Suggestions succeeded at communicator",
6884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6885 "Request #%u for communicator to create queue succeeded\n",
6886 (unsigned int) ntohs (cqr->request_id));
6887 GNUNET_SERVICE_client_continue (tc->client);
6892 * Communicator tells us that our request to create a queue failed. This usually
6893 * indicates that the provided address is simply invalid or that the
6894 * communicator's resources are exhausted.
6896 * @param cls the `struct TransportClient`
6897 * @param cqr failure message
6900 handle_queue_create_fail (
6902 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6904 struct TransportClient *tc = cls;
6906 if (CT_COMMUNICATOR != tc->type)
6909 GNUNET_SERVICE_client_drop (tc->client);
6912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6913 "Request #%u for communicator to create queue failed\n",
6914 (unsigned int) ntohs (cqr->request_id));
6915 GNUNET_STATISTICS_update (GST_stats,
6916 "# Suggestions failed in queue creation at communicator",
6919 GNUNET_SERVICE_client_continue (tc->client);
6924 * We have received a `struct ExpressPreferenceMessage` from an application
6927 * @param cls handle to the client
6928 * @param msg the start message
6931 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
6933 struct TransportClient *tc = cls;
6934 struct PeerRequest *pr;
6936 if (CT_APPLICATION != tc->type)
6939 GNUNET_SERVICE_client_drop (tc->client);
6942 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
6947 GNUNET_SERVICE_client_drop (tc->client);
6950 (void) stop_peer_request (tc, &pr->pid, pr);
6951 GNUNET_SERVICE_client_continue (tc->client);
6956 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
6957 * messages. We do nothing here, real verification is done later.
6959 * @param cls a `struct TransportClient *`
6960 * @param msg message to verify
6961 * @return #GNUNET_OK
6964 check_address_consider_verify (
6966 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6975 * Closure for #check_known_address.
6977 struct CheckKnownAddressContext
6980 * Set to the address we are looking for.
6982 const char *address;
6985 * Set to a matching validation state, if one was found.
6987 struct ValidationState *vs;
6992 * Test if the validation state in @a value matches the
6993 * address from @a cls.
6995 * @param cls a `struct CheckKnownAddressContext`
6996 * @param pid unused (must match though)
6997 * @param value a `struct ValidationState`
6998 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7001 check_known_address (void *cls,
7002 const struct GNUNET_PeerIdentity *pid,
7005 struct CheckKnownAddressContext *ckac = cls;
7006 struct ValidationState *vs = value;
7009 if (0 != strcmp (vs->address, ckac->address))
7017 * Start address validation.
7019 * @param pid peer the @a address is for
7020 * @param address an address to reach @a pid (presumably)
7021 * @param expiration when did @a pid claim @a address will become invalid
7024 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7025 const char *address,
7026 struct GNUNET_TIME_Absolute expiration)
7028 struct GNUNET_TIME_Absolute now;
7029 struct ValidationState *vs;
7030 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7032 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
7033 return; /* expired */
7034 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7036 &check_known_address,
7038 if (NULL != (vs = ckac.vs))
7040 /* if 'vs' is not currently valid, we need to speed up retrying the
7042 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7044 /* reduce backoff as we got a fresh advertisement */
7045 vs->challenge_backoff =
7046 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7047 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7049 update_next_challenge_time (vs,
7050 GNUNET_TIME_relative_to_absolute (
7051 vs->challenge_backoff));
7055 now = GNUNET_TIME_absolute_get ();
7056 vs = GNUNET_new (struct ValidationState);
7058 vs->valid_until = expiration;
7059 vs->first_challenge_use = now;
7060 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7061 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7063 sizeof (vs->challenge));
7064 vs->address = GNUNET_strdup (address);
7065 GNUNET_assert (GNUNET_YES ==
7066 GNUNET_CONTAINER_multipeermap_put (
7070 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7071 update_next_challenge_time (vs, now);
7076 * Function called by PEERSTORE for each matching record.
7078 * @param cls closure
7079 * @param record peerstore record information
7080 * @param emsg error message, or NULL if no errors
7083 handle_hello (void *cls,
7084 const struct GNUNET_PEERSTORE_Record *record,
7087 struct PeerRequest *pr = cls;
7092 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7093 "Got failure from PEERSTORE: %s\n",
7097 val = record->value;
7098 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7103 start_address_validation (&pr->pid,
7104 (const char *) record->value,
7110 * We have received a `struct ExpressPreferenceMessage` from an application
7113 * @param cls handle to the client
7114 * @param msg the start message
7117 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
7119 struct TransportClient *tc = cls;
7120 struct PeerRequest *pr;
7122 if (CT_NONE == tc->type)
7124 tc->type = CT_APPLICATION;
7125 tc->details.application.requests =
7126 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
7128 if (CT_APPLICATION != tc->type)
7131 GNUNET_SERVICE_client_drop (tc->client);
7134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7135 "Client suggested we talk to %s with preference %d at rate %u\n",
7136 GNUNET_i2s (&msg->peer),
7137 (int) ntohl (msg->pk),
7138 (int) ntohl (msg->bw.value__));
7139 pr = GNUNET_new (struct PeerRequest);
7141 pr->pid = msg->peer;
7143 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
7144 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
7145 tc->details.application.requests,
7148 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
7152 GNUNET_SERVICE_client_drop (tc->client);
7155 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
7158 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7161 GNUNET_SERVICE_client_continue (tc->client);
7166 * Given another peers address, consider checking it for validity
7167 * and then adding it to the Peerstore.
7169 * @param cls a `struct TransportClient`
7170 * @param hdr message containing the raw address data and
7171 * signature in the body, see #GNUNET_HELLO_extract_address()
7174 handle_address_consider_verify (
7176 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7178 struct TransportClient *tc = cls;
7180 enum GNUNET_NetworkType nt;
7181 struct GNUNET_TIME_Absolute expiration;
7184 // OPTIMIZE-FIXME: checking that we know this address already should
7185 // be done BEFORE checking the signature => HELLO API change!
7186 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
7188 GNUNET_HELLO_extract_address (&hdr[1],
7189 ntohs (hdr->header.size) - sizeof (*hdr),
7193 if (NULL == address)
7195 GNUNET_break_op (0);
7198 start_address_validation (&hdr->peer, address, expiration);
7199 GNUNET_free (address);
7200 GNUNET_SERVICE_client_continue (tc->client);
7205 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
7208 * @param cls a `struct TransportClient *`
7209 * @param m message to verify
7210 * @return #GNUNET_OK on success
7213 check_request_hello_validation (void *cls,
7214 const struct RequestHelloValidationMessage *m)
7217 GNUNET_MQ_check_zero_termination (m);
7223 * A client encountered an address of another peer. Consider validating it,
7224 * and if validation succeeds, persist it to PEERSTORE.
7226 * @param cls a `struct TransportClient *`
7227 * @param m message to verify
7230 handle_request_hello_validation (void *cls,
7231 const struct RequestHelloValidationMessage *m)
7233 struct TransportClient *tc = cls;
7235 start_address_validation (&m->peer,
7236 (const char *) &m[1],
7237 GNUNET_TIME_absolute_ntoh (m->expiration));
7238 GNUNET_SERVICE_client_continue (tc->client);
7243 * Free neighbour entry.
7247 * @param value a `struct Neighbour`
7248 * @return #GNUNET_OK (always)
7251 free_neighbour_cb (void *cls,
7252 const struct GNUNET_PeerIdentity *pid,
7255 struct Neighbour *neighbour = value;
7259 GNUNET_break (0); // should this ever happen?
7260 free_neighbour (neighbour);
7267 * Free DV route entry.
7271 * @param value a `struct DistanceVector`
7272 * @return #GNUNET_OK (always)
7275 free_dv_routes_cb (void *cls,
7276 const struct GNUNET_PeerIdentity *pid,
7279 struct DistanceVector *dv = value;
7290 * Free ephemeral entry.
7294 * @param value a `struct EphemeralCacheEntry`
7295 * @return #GNUNET_OK (always)
7298 free_ephemeral_cb (void *cls,
7299 const struct GNUNET_PeerIdentity *pid,
7302 struct EphemeralCacheEntry *ece = value;
7306 free_ephemeral (ece);
7312 * Free validation state.
7316 * @param value a `struct ValidationState`
7317 * @return #GNUNET_OK (always)
7320 free_validation_state_cb (void *cls,
7321 const struct GNUNET_PeerIdentity *pid,
7324 struct ValidationState *vs = value;
7328 free_validation_state (vs);
7334 * Function called when the service shuts down. Unloads our plugins
7335 * and cancels pending validations.
7337 * @param cls closure, unused
7340 do_shutdown (void *cls)
7342 struct LearnLaunchEntry *lle;
7345 if (NULL != ephemeral_task)
7347 GNUNET_SCHEDULER_cancel (ephemeral_task);
7348 ephemeral_task = NULL;
7350 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
7351 if (NULL != peerstore)
7353 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
7356 if (NULL != GST_stats)
7358 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
7361 if (NULL != GST_my_private_key)
7363 GNUNET_free (GST_my_private_key);
7364 GST_my_private_key = NULL;
7366 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7368 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7369 &free_validation_state_cb,
7371 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7372 validation_map = NULL;
7373 while (NULL != (lle = lle_head))
7375 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7378 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7380 GNUNET_CONTAINER_heap_destroy (validation_heap);
7381 validation_heap = NULL;
7382 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
7383 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7385 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7388 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7389 ephemeral_map = NULL;
7390 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7391 ephemeral_heap = NULL;
7396 * Initiate transport service.
7398 * @param cls closure
7399 * @param c configuration to use
7400 * @param service the initialized service
7404 const struct GNUNET_CONFIGURATION_Handle *c,
7405 struct GNUNET_SERVICE_Handle *service)
7411 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7412 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7413 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
7415 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7416 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7418 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7420 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7421 GST_my_private_key =
7422 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7423 if (NULL == GST_my_private_key)
7426 GNUNET_ERROR_TYPE_ERROR,
7428 "Transport service is lacking key configuration settings. Exiting.\n"));
7429 GNUNET_SCHEDULER_shutdown ();
7432 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7433 &GST_my_identity.public_key);
7434 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7435 "My identity is `%s'\n",
7436 GNUNET_i2s_full (&GST_my_identity));
7437 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
7438 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
7439 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7440 if (NULL == peerstore)
7443 GNUNET_SCHEDULER_shutdown ();
7450 * Define "main" method using service macro.
7452 GNUNET_SERVICE_MAIN (
7454 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7457 &client_disconnect_cb,
7459 /* communication with applications */
7460 GNUNET_MQ_hd_fixed_size (suggest,
7461 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7462 struct ExpressPreferenceMessage,
7464 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7465 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7466 struct ExpressPreferenceMessage,
7468 GNUNET_MQ_hd_var_size (request_hello_validation,
7469 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7470 struct RequestHelloValidationMessage,
7472 /* communication with core */
7473 GNUNET_MQ_hd_fixed_size (client_start,
7474 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7475 struct StartMessage,
7477 GNUNET_MQ_hd_var_size (client_send,
7478 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7479 struct OutboundMessage,
7481 /* communication with communicators */
7482 GNUNET_MQ_hd_var_size (communicator_available,
7483 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7484 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7486 GNUNET_MQ_hd_var_size (communicator_backchannel,
7487 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7488 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7490 GNUNET_MQ_hd_var_size (add_address,
7491 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7492 struct GNUNET_TRANSPORT_AddAddressMessage,
7494 GNUNET_MQ_hd_fixed_size (del_address,
7495 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7496 struct GNUNET_TRANSPORT_DelAddressMessage,
7498 GNUNET_MQ_hd_var_size (incoming_msg,
7499 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7500 struct GNUNET_TRANSPORT_IncomingMessage,
7502 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7503 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7504 struct GNUNET_TRANSPORT_CreateQueueResponse,
7506 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7507 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7508 struct GNUNET_TRANSPORT_CreateQueueResponse,
7510 GNUNET_MQ_hd_var_size (add_queue_message,
7511 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7512 struct GNUNET_TRANSPORT_AddQueueMessage,
7514 GNUNET_MQ_hd_var_size (address_consider_verify,
7515 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7516 struct GNUNET_TRANSPORT_AddressToVerify,
7518 GNUNET_MQ_hd_fixed_size (del_queue_message,
7519 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7520 struct GNUNET_TRANSPORT_DelQueueMessage,
7522 GNUNET_MQ_hd_fixed_size (send_message_ack,
7523 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
7524 struct GNUNET_TRANSPORT_SendMessageToAck,
7526 /* communication with monitors */
7527 GNUNET_MQ_hd_fixed_size (monitor_start,
7528 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
7529 struct GNUNET_TRANSPORT_MonitorStart,
7531 GNUNET_MQ_handler_end ());
7534 /* end of file gnunet-service-transport.c */