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
27 * - FIXME-FC: realize transport-to-transport flow control (needed in case
28 * communicators do not offer flow control).
29 * We do transmit FC window sizes now. Left:
31 * - Increment "outbound_fc_window_size_used" on transmission
32 * - Throttle sending if "outbound_fc_window_size_used" reaches limit
33 * - Send *new* challenge when we get close to the limit (including
34 * at the beginning when the limit is zero!)
35 * - Retransmit challenge if it goes unanswered!
38 * - send challenges via DV (when DVH is confirmed *and* we care about
39 * the target to get window size, or when DVH is unconfirmed (passive
40 * learning!) to confirm it!)
41 * - handle challenge responses in this case (note: validity period of addresses
43 * - if available, try to use DV paths when trying to establish
44 * virtual link for a `struct IncomingRequest`. (i.e. if DVH is
45 * unconfirmed, incoming requests also trigger challenge-via-DV!)
47 * - review retransmission logic, right now there is no smartness there!
48 * => congestion control, etc [PERFORMANCE-BASICS]
51 * - When forwarding DV learn messages, if a peer is reached that
52 * has a *bidirectional* link to the origin beyond 1st hop,
53 * do NOT forward it to peers _other_ than the origin, as
54 * there is clearly a better path directly from the origin to
55 * whatever else we could reach.
56 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
57 * => Need 128 bit hash map though! [BANDWIDTH, MEMORY]
58 * - queue_send_msg by API design has to make a copy
59 * of the payload, and route_message on top of that requires a malloc/free.
60 * Change design to approximate "zero" copy better... [CPU]
61 * - could avoid copying body of message into each fragment and keep
62 * fragments as just pointers into the original message and only
63 * fully build fragments just before transmission (optimization, should
64 * reduce CPU and memory use) [CPU, MEMORY]
65 * - if messages are below MTU, consider adding ACKs and other stuff
66 * to the same transmission to avoid tiny messages (requires planning at
67 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
68 * - When we passively learned DV (with unconfirmed freshness), we
69 * right now add the path to our list but with a zero path_valid_until
70 * time and only use it for unconfirmed routes. However, we could consider
71 * triggering an explicit validation mechansim ourselves, specifically routing
72 * a challenge-response message over the path [ROUTING]
73 * - Track ACK losses based on ACK-counter [ROUTING]
74 * - Fragments send over a reliable channel could do without the
75 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
76 * (-> have 2nd type of acknowledgment message; low priority, as we
77 * do not have an MTU-limited *reliable* communicator)
78 * - Adapt available_fc_window_size, using larger values for high-bandwidth
79 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
80 * - Set last_window_consum_limit promise properly based on
81 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
82 * - re-sending challenge response without a challenge when we have
83 * significantly increased the FC window (upon CORE being done with messages)
84 * so as to avoid the sender having to give us a fresh challenge [BANDWIDTH]
85 * Also can re-use signature in this case [CPU]. Marked with "TODO-M1"
87 * Design realizations / discussion:
88 * - communicators do flow control by calling MQ "notify sent"
89 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
90 * or explicitly via backchannel FC ACKs. As long as the
91 * channel is not full, they may 'notify sent' even if the other
92 * peer has not yet confirmed receipt. The other peer confirming
93 * is _only_ for FC, not for more reliable transmission; reliable
94 * transmission (i.e. of fragments) is left to _transport_.
95 * - ACKs sent back in uni-directional communicators are done via
96 * the background channel API; here transport _may_ initially
97 * broadcast (with bounded # hops) if no path is known;
98 * - transport should _integrate_ DV-routing and build a view of
99 * the network; then background channel traffic can be
100 * routed via DV as well as explicit "DV" traffic.
101 * - background channel is also used for ACKs and NAT traversal support
102 * - transport service is responsible for AEAD'ing the background
103 * channel, timestamps and monotonic time are used against replay
104 * of old messages -> peerstore needs to be supplied with
105 * "latest timestamps seen" data
106 * - if transport implements DV, we likely need a 3rd peermap
107 * in addition to ephemerals and (direct) neighbours
108 * ==> check if stuff needs to be moved out of "Neighbour"
109 * - transport should encapsualte core-level messages and do its
110 * own ACKing for RTT/goodput/loss measurements _and_ fragment
113 #include "platform.h"
114 #include "gnunet_util_lib.h"
115 #include "gnunet_statistics_service.h"
116 #include "gnunet_transport_monitor_service.h"
117 #include "gnunet_peerstore_service.h"
118 #include "gnunet_hello_lib.h"
119 #include "gnunet_signatures.h"
120 #include "transport.h"
123 * Maximum number of messages we acknowledge together in one
124 * cummulative ACK. Larger values may save a bit of bandwidth.
126 #define MAX_CUMMULATIVE_ACKS 64
129 * What is the size we assume for a read operation in the
130 * absence of an MTU for the purpose of flow control?
132 #define IN_PACKET_SIZE_WITHOUT_MTU 128
135 * Number of slots we keep of historic data for computation of
136 * goodput / message loss ratio.
138 #define GOODPUT_AGING_SLOTS 4
141 * How big is the flow control window size by default;
142 * limits per-neighbour RAM utilization.
144 #define DEFAULT_WINDOW_SIZE (128 * 1024)
147 * For how many incoming connections do we try to create a
148 * virtual link for (at the same time!). This does NOT
149 * limit the number of incoming connections, just the number
150 * for which we are actively trying to find working addresses
151 * in the absence (!) of our own applications wanting the
154 #define MAX_INCOMING_REQUEST 16
157 * Maximum number of peers we select for forwarding DVInit
158 * messages at the same time (excluding initiator).
160 #define MAX_DV_DISCOVERY_SELECTION 16
163 * Window size. How many messages to the same target do we pass
164 * to CORE without a RECV_OK in between? Small values limit
165 * thoughput, large values will increase latency.
167 * FIXME-OPTIMIZE: find out what good values are experimentally,
168 * maybe set adaptively (i.e. to observed available bandwidth).
170 #define RECV_WINDOW_SIZE 4
173 * Minimum number of hops we should forward DV learn messages
174 * even if they are NOT useful for us in hope of looping
175 * back to the initiator?
177 * FIXME: allow initiator some control here instead?
179 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
182 * Maximum DV distance allowed ever.
184 #define MAX_DV_HOPS_ALLOWED 16
187 * Maximum number of DV learning activities we may
188 * have pending at the same time.
190 #define MAX_DV_LEARN_PENDING 64
193 * Maximum number of DV paths we keep simultaneously to the same target.
195 #define MAX_DV_PATHS_TO_TARGET 3
198 * If a queue delays the next message by more than this number
199 * of seconds we log a warning. Note: this is for testing,
200 * the value chosen here might be too aggressively low!
202 #define DELAY_WARN_THRESHOLD \
203 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
206 * We only consider queues as "quality" connections when
207 * suppressing the generation of DV initiation messages if
208 * the latency of the queue is below this threshold.
210 #define DV_QUALITY_RTT_THRESHOLD \
211 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
214 * How long do we consider a DV path valid if we see no
215 * further updates on it? Note: the value chosen here might be too low!
217 #define DV_PATH_VALIDITY_TIMEOUT \
218 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
221 * How long do we cache backchannel (struct Backtalker) information
222 * after a backchannel goes inactive?
224 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
225 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
228 * How long before paths expire would we like to (re)discover DV paths? Should
229 * be below #DV_PATH_VALIDITY_TIMEOUT.
231 #define DV_PATH_DISCOVERY_FREQUENCY \
232 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
235 * How long are ephemeral keys valid?
237 #define EPHEMERAL_VALIDITY \
238 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
241 * How long do we keep partially reassembled messages around before giving up?
243 #define REASSEMBLY_EXPIRATION \
244 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
247 * What is the fastest rate at which we send challenges *if* we keep learning
248 * an address (gossip, DHT, etc.)?
250 #define FAST_VALIDATION_CHALLENGE_FREQ \
251 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
254 * What is the slowest rate at which we send challenges?
256 #define MAX_VALIDATION_CHALLENGE_FREQ \
257 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
260 * How long until we forget about historic accumulators and thus
261 * reset the ACK counter? Should exceed the maximum time an
262 * active connection experiences without an ACK.
264 #define ACK_CUMMULATOR_TIMEOUT \
265 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
268 * What is the non-randomized base frequency at which we
269 * would initiate DV learn messages?
271 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
274 * How many good connections (confirmed, bi-directional, not DV)
275 * do we need to have to suppress initiating DV learn messages?
277 #define DV_LEARN_QUALITY_THRESHOLD 100
280 * When do we forget an invalid address for sure?
282 #define MAX_ADDRESS_VALID_UNTIL \
283 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
286 * How long do we consider an address valid if we just checked?
288 #define ADDRESS_VALIDATION_LIFETIME \
289 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
292 * What is the maximum frequency at which we do address validation?
293 * A random value between 0 and this value is added when scheduling
294 * the #validation_task (both to ensure we do not validate too often,
295 * and to randomize a bit).
297 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
300 * How many network RTTs before an address validation expires should we begin
301 * trying to revalidate? (Note that the RTT used here is the one that we
302 * experienced during the last validation, not necessarily the latest RTT
305 #define VALIDATION_RTT_BUFFER_FACTOR 3
308 * How many messages can we have pending for a given communicator
309 * process before we start to throttle that communicator?
311 * Used if a communicator might be CPU-bound and cannot handle the traffic.
313 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
316 * How many messages can we have pending for a given queue (queue to
317 * a particular peer via a communicator) process before we start to
318 * throttle that queue?
320 #define QUEUE_LENGTH_LIMIT 32
323 GNUNET_NETWORK_STRUCT_BEGIN
326 * Unique identifier we attach to a message.
331 * Unique value, generated by incrementing the
332 * `message_uuid_ctr` of `struct Neighbour`.
334 uint64_t uuid GNUNET_PACKED;
339 * Unique identifier to map an acknowledgement to a transmission.
341 struct AcknowledgementUUIDP
344 * The UUID value. Not actually a hash, but a random value.
346 struct GNUNET_ShortHashCode value;
351 * Type of a nonce used for challenges.
353 struct ChallengeNonceP
356 * The value of the nonce. Note that this is NOT a hash.
358 struct GNUNET_ShortHashCode value;
363 * Outer layer of an encapsulated backchannel message.
365 struct TransportBackchannelEncapsulationMessage
368 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
370 struct GNUNET_MessageHeader header;
372 /* Followed by *another* message header which is the message to
375 /* Followed by a 0-terminated name of the communicator */
380 * Body by which a peer confirms that it is using an ephemeral key.
382 struct EphemeralConfirmationPS
386 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
388 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
391 * How long is this signature over the ephemeral key valid?
393 * Note that the receiver MUST IGNORE the absolute time, and only interpret
394 * the value as a mononic time and reject "older" values than the last one
395 * observed. This is necessary as we do not want to require synchronized
396 * clocks and may not have a bidirectional communication channel.
398 * Even with this, there is no real guarantee against replay achieved here,
399 * unless the latest timestamp is persisted. While persistence should be
400 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
401 * communicators must protect against replay attacks when using backchannel
404 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
407 * Target's peer identity.
409 struct GNUNET_PeerIdentity target;
412 * Ephemeral key setup by the sender for @e target, used
413 * to encrypt the payload.
415 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
420 * Plaintext of the variable-size payload that is encrypted
421 * within a `struct TransportBackchannelEncapsulationMessage`
423 struct TransportDVBoxPayloadP
427 * Sender's peer identity.
429 struct GNUNET_PeerIdentity sender;
432 * Signature of the sender over an
433 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
435 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
438 * Current monotonic time of the sending transport service. Used to
439 * detect replayed messages. Note that the receiver should remember
440 * a list of the recently seen timestamps and only reject messages
441 * if the timestamp is in the list, or the list is "full" and the
442 * timestamp is smaller than the lowest in the list.
444 * Like the @e ephemeral_validity, the list of timestamps per peer should be
445 * persisted to guard against replays after restarts.
447 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
449 /* Followed by a `struct GNUNET_MessageHeader` with a message
450 for the target peer */
455 * Outer layer of an encapsulated unfragmented application message sent
456 * over an unreliable channel.
458 struct TransportReliabilityBoxMessage
461 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
463 struct GNUNET_MessageHeader header;
466 * Number of messages still to be sent before a commulative
467 * ACK is requested. Zero if an ACK is requested immediately.
468 * In NBO. Note that the receiver may send the ACK faster
469 * if it believes that is reasonable.
471 uint32_t ack_countdown GNUNET_PACKED;
474 * Unique ID of the message used for signalling receipt of
475 * messages sent over possibly unreliable channels. Should
478 struct AcknowledgementUUIDP ack_uuid;
483 * Acknowledgement payload.
485 struct TransportCummulativeAckPayloadP
488 * How long was the ACK delayed for generating cummulative ACKs?
489 * Used to calculate the correct network RTT by taking the receipt
490 * time of the ack minus the transmission time of the sender minus
493 struct GNUNET_TIME_RelativeNBO ack_delay;
496 * UUID of a message being acknowledged.
498 struct AcknowledgementUUIDP ack_uuid;
503 * Confirmation that the receiver got a
504 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
505 * confirmation may be transmitted over a completely different queue,
506 * so ACKs are identified by a combination of PID of sender and
507 * message UUID, without the queue playing any role!
509 struct TransportReliabilityAckMessage
512 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
514 struct GNUNET_MessageHeader header;
517 * Counter of ACKs transmitted by the sender to us. Incremented
518 * by one for each ACK, used to detect how many ACKs were lost.
520 uint32_t ack_counter GNUNET_PACKED;
522 /* followed by any number of `struct TransportCummulativeAckPayloadP`
523 messages providing ACKs */
528 * Outer layer of an encapsulated fragmented application message.
530 struct TransportFragmentBoxMessage
533 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
535 struct GNUNET_MessageHeader header;
538 * Offset of this fragment in the overall message.
540 uint16_t frag_off GNUNET_PACKED;
543 * Total size of the message that is being fragmented.
545 uint16_t msg_size GNUNET_PACKED;
548 * Unique ID of this fragment (and fragment transmission!). Will
549 * change even if a fragement is retransmitted to make each
550 * transmission attempt unique! If a client receives a duplicate
551 * fragment (same @e frag_off for same @a msg_uuid, it must send
552 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
554 struct AcknowledgementUUIDP ack_uuid;
557 * Original message ID for of the message that all the fragments
558 * belong to. Must be the same for all fragments.
560 struct MessageUUIDP msg_uuid;
565 * Content signed by the initator during DV learning.
567 * The signature is required to prevent DDoS attacks. A peer sending out this
568 * message is potentially generating a lot of traffic that will go back to the
569 * initator, as peers receiving this message will try to let the initiator
570 * know that they got the message.
572 * Without this signature, an attacker could abuse this mechanism for traffic
573 * amplification, sending a lot of traffic to a peer by putting out this type
574 * of message with the victim's peer identity.
576 * Even with just a signature, traffic amplification would be possible via
577 * replay attacks. The @e monotonic_time limits such replay attacks, as every
578 * potential amplificator will check the @e monotonic_time and only respond
579 * (at most) once per message.
584 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
586 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
589 * Time at the initiator when generating the signature.
591 * Note that the receiver MUST IGNORE the absolute time, and only interpret
592 * the value as a mononic time and reject "older" values than the last one
593 * observed. This is necessary as we do not want to require synchronized
594 * clocks and may not have a bidirectional communication channel.
596 * Even with this, there is no real guarantee against replay achieved here,
597 * unless the latest timestamp is persisted. Persistence should be
598 * provided via PEERSTORE if possible.
600 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
603 * Challenge value used by the initiator to re-identify the path.
605 struct ChallengeNonceP challenge;
610 * Content signed by each peer during DV learning.
612 * This assues the initiator of the DV learning operation that the hop from @e
613 * pred via the signing peer to @e succ actually exists. This makes it
614 * impossible for an adversary to supply the network with bogus routes.
616 * The @e challenge is included to provide replay protection for the
617 * initiator. This way, the initiator knows that the hop existed after the
618 * original @e challenge was first transmitted, providing a freshness metric.
620 * Peers other than the initiator that passively learn paths by observing
621 * these messages do NOT benefit from this. Here, an adversary may indeed
622 * replay old messages. Thus, passively learned paths should always be
623 * immediately marked as "potentially stale".
628 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
630 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
633 * Identity of the previous peer on the path.
635 struct GNUNET_PeerIdentity pred;
638 * Identity of the next peer on the path.
640 struct GNUNET_PeerIdentity succ;
643 * Challenge value used by the initiator to re-identify the path.
645 struct ChallengeNonceP challenge;
650 * An entry describing a peer on a path in a
651 * `struct TransportDVLearnMessage` message.
656 * Identity of a peer on the path.
658 struct GNUNET_PeerIdentity hop;
661 * Signature of this hop over the path, of purpose
662 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
664 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
669 * Internal message used by transport for distance vector learning.
670 * If @e num_hops does not exceed the threshold, peers should append
671 * themselves to the peer list and flood the message (possibly only
672 * to a subset of their neighbours to limit discoverability of the
673 * network topology). To the extend that the @e bidirectional bits
674 * are set, peers may learn the inverse paths even if they did not
677 * Unless received on a bidirectional queue and @e num_hops just
678 * zero, peers that can forward to the initator should always try to
679 * forward to the initiator.
681 struct TransportDVLearnMessage
684 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
686 struct GNUNET_MessageHeader header;
689 * Number of hops this messages has travelled, in NBO. Zero if
692 uint16_t num_hops GNUNET_PACKED;
695 * Bitmask of the last 16 hops indicating whether they are confirmed
696 * available (without DV) in both directions or not, in NBO. Used
697 * to possibly instantly learn a path in both directions. Each peer
698 * should shift this value by one to the left, and then set the
699 * lowest bit IF the current sender can be reached from it (without
702 uint16_t bidirectional GNUNET_PACKED;
705 * Peers receiving this message and delaying forwarding to other
706 * peers for any reason should increment this value by the non-network
707 * delay created by the peer.
709 struct GNUNET_TIME_RelativeNBO non_network_delay;
712 * Time at the initiator when generating the signature.
714 * Note that the receiver MUST IGNORE the absolute time, and only interpret
715 * the value as a mononic time and reject "older" values than the last one
716 * observed. This is necessary as we do not want to require synchronized
717 * clocks and may not have a bidirectional communication channel.
719 * Even with this, there is no real guarantee against replay achieved here,
720 * unless the latest timestamp is persisted. Persistence should be
721 * provided via PEERSTORE if possible.
723 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
726 * Signature of this hop over the path, of purpose
727 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
729 struct GNUNET_CRYPTO_EddsaSignature init_sig;
732 * Identity of the peer that started this learning activity.
734 struct GNUNET_PeerIdentity initiator;
737 * Challenge value used by the initiator to re-identify the path.
739 struct ChallengeNonceP challenge;
741 /* Followed by @e num_hops `struct DVPathEntryP` values,
742 excluding the initiator of the DV trace; the last entry is the
743 current sender; the current peer must not be included. */
748 * Outer layer of an encapsulated message send over multiple hops.
749 * The path given only includes the identities of the subsequent
750 * peers, i.e. it will be empty if we are the receiver. Each
751 * forwarding peer should scan the list from the end, and if it can,
752 * forward to the respective peer. The list should then be shortened
753 * by all the entries up to and including that peer. Each hop should
754 * also increment @e total_hops to allow the receiver to get a precise
755 * estimate on the number of hops the message travelled. Senders must
756 * provide a learned path that thus should work, but intermediaries
757 * know of a shortcut, they are allowed to send the message via that
760 * If a peer finds itself still on the list, it must drop the message.
762 * The payload of the box can only be decrypted and verified by the
763 * ultimate receiver. Intermediaries do not learn the sender's
764 * identity and the path the message has taken. However, the first
765 * hop does learn the sender as @e total_hops would be zero and thus
766 * the predecessor must be the origin (so this is not really useful
767 * for anonymization).
769 struct TransportDVBoxMessage
772 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
774 struct GNUNET_MessageHeader header;
777 * Number of total hops this messages travelled. In NBO.
778 * @e origin sets this to zero, to be incremented at
779 * each hop. Peers should limit the @e total_hops value
780 * they accept from other peers.
782 uint16_t total_hops GNUNET_PACKED;
785 * Number of hops this messages includes. In NBO. Reduced by one
786 * or more at each hop. Peers should limit the @e num_hops value
787 * they accept from other peers.
789 uint16_t num_hops GNUNET_PACKED;
792 * Ephemeral key setup by the sender for target, used to encrypt the
793 * payload. Intermediaries must not change this value.
795 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
798 * We use an IV here as the @e ephemeral_key is re-used for
799 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
800 * Intermediaries must not change this value.
802 struct GNUNET_ShortHashCode iv;
805 * HMAC over the ciphertext of the encrypted, variable-size body
806 * that follows. Verified via DH of target and @e ephemeral_key.
807 * Intermediaries must not change this value.
809 struct GNUNET_HashCode hmac;
811 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
812 excluding the @e origin and the current peer, the last must be
813 the ultimate target; if @e num_hops is zero, the receiver of this
814 message is the ultimate target. */
816 /* Followed by encrypted, variable-size payload, which
817 must begin with a `struct TransportDVBoxPayloadP` */
819 /* Followed by the actual message, which itself must not be a
820 a DV_LEARN or DV_BOX message! */
825 * Message send to another peer to validate that it can indeed
826 * receive messages at a particular address.
828 struct TransportValidationChallengeMessage
832 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
834 struct GNUNET_MessageHeader header;
839 uint32_t reserved GNUNET_PACKED;
842 * Challenge to be signed by the receiving peer.
844 struct ChallengeNonceP challenge;
847 * Timestamp of the sender, to be copied into the reply to allow
848 * sender to calculate RTT. Must be monotonically increasing!
850 struct GNUNET_TIME_AbsoluteNBO sender_time;
855 * Message signed by a peer to confirm that it can indeed
856 * receive messages at a particular address.
858 struct TransportValidationPS
862 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
864 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
867 * How long does the sender believe the address on
868 * which the challenge was received to remain valid?
870 struct GNUNET_TIME_RelativeNBO validity_duration;
873 * Challenge signed by the receiving peer.
875 struct ChallengeNonceP challenge;
880 * Message send to a peer to respond to a
881 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
883 struct TransportValidationResponseMessage
887 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
889 struct GNUNET_MessageHeader header;
894 uint32_t reserved GNUNET_PACKED;
897 * The peer's signature matching the
898 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
900 struct GNUNET_CRYPTO_EddsaSignature signature;
903 * The challenge that was signed by the receiving peer.
905 struct ChallengeNonceP challenge;
908 * Original timestamp of the sender (was @code{sender_time}),
909 * copied into the reply to allow sender to calculate RTT.
911 struct GNUNET_TIME_AbsoluteNBO origin_time;
914 * How long does the sender believe this address to remain
917 struct GNUNET_TIME_RelativeNBO validity_duration;
922 * Message for Transport-to-Transport Flow control. Specifies the size
923 * of the flow control window, including how much we believe to have
924 * consumed (at transmission time), how much we believe to be allowed
925 * (at transmission time), and how much the other peer is allowed to
926 * send to us, and how much data we already received from the other
929 struct TransportFlowControlMessage
932 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
934 struct GNUNET_MessageHeader header;
937 * Sequence number of the flow control message. Incremented by one
938 * for each message. Starts at zero when a virtual link goes up.
939 * Used to detect one-sided connection drops. On wrap-around, the
940 * flow control counters will be reset as if the connection had
943 uint32_t seq GNUNET_PACKED;
946 * Flow control window size in bytes, in NBO.
947 * The receiver can send this many bytes at most.
949 uint64_t inbound_window_size GNUNET_PACKED;
952 * How many bytes has the sender sent that count for flow control at
953 * this time. Used to allow the receiver to estimate the packet
956 uint64_t outbound_sent GNUNET_PACKED;
959 * Latest flow control window size we learned from the other peer,
960 * in bytes, in NBO. We are limited to sending at most this many
961 * bytes to the other peer. May help the other peer detect when
962 * flow control messages were lost and should thus be retransmitted.
963 * In particular, if the delta to @e outbound_sent is too small,
964 * this signals that we are stalled.
966 uint64_t outbound_window_size GNUNET_PACKED;
969 * Timestamp of the sender. Must be monotonically increasing!
970 * Used to enable receiver to ignore out-of-order packets in
971 * combination with the @e seq. Note that @e seq will go down
972 * (back to zero) whenever either side believes the connection
973 * was dropped, allowing the peers to detect that they need to
974 * reset the counters for the number of bytes sent!
976 struct GNUNET_TIME_AbsoluteNBO sender_time;
981 GNUNET_NETWORK_STRUCT_END
985 * What type of client is the `struct TransportClient` about?
990 * We do not know yet (client is fresh).
995 * Is the CORE service, we need to forward traffic to it.
1000 * It is a monitor, forward monitor data.
1005 * It is a communicator, use for communication.
1007 CT_COMMUNICATOR = 3,
1010 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
1017 * Which transmission options are allowable for transmission?
1018 * Interpreted bit-wise!
1020 enum RouteMessageOptions
1023 * Only confirmed, non-DV direct neighbours.
1028 * We are allowed to use DV routing for this @a hdr
1033 * We are allowed to use unconfirmed queues or DV routes for this message
1035 RMO_UNCONFIRMED_ALLOWED = 2,
1038 * Reliable and unreliable, DV and non-DV are all acceptable.
1040 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1043 * If we have multiple choices, it is OK to send this message
1044 * over multiple channels at the same time to improve loss tolerance.
1045 * (We do at most 2 transmissions.)
1052 * When did we launch this DV learning activity?
1054 struct LearnLaunchEntry
1058 * Kept (also) in a DLL sorted by launch time.
1060 struct LearnLaunchEntry *prev;
1063 * Kept (also) in a DLL sorted by launch time.
1065 struct LearnLaunchEntry *next;
1068 * Challenge that uniquely identifies this activity.
1070 struct ChallengeNonceP challenge;
1073 * When did we transmit the DV learn message (used to calculate RTT) and
1074 * determine freshness of paths learned via this operation.
1076 struct GNUNET_TIME_Absolute launch_time;
1081 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1082 * (or current) transmission performance.
1084 struct TransmissionHistoryEntry
1087 * Number of bytes actually sent in the interval.
1089 uint64_t bytes_sent;
1092 * Number of bytes received and acknowledged by the other peer in
1095 uint64_t bytes_received;
1100 * Performance data for a transmission possibility.
1102 struct PerformanceData
1105 * Weighted average for the RTT.
1107 struct GNUNET_TIME_Relative aged_rtt;
1110 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1113 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1116 * What was the last age when we wrote to @e the? Used to clear
1117 * old entries when the age advances.
1119 unsigned int last_age;
1124 * Client connected to the transport service.
1126 struct TransportClient;
1129 * A neighbour that at least one communicator is connected to.
1134 * Entry in our #dv_routes table, representing a (set of) distance
1135 * vector routes to a particular peer.
1137 struct DistanceVector;
1140 * A queue is a message queue provided by a communicator
1141 * via which we can reach a particular neighbour.
1146 * Message awaiting transmission. See detailed comments below.
1148 struct PendingMessage;
1151 * One possible hop towards a DV target.
1153 struct DistanceVectorHop;
1156 * A virtual link is another reachable peer that is known to CORE. It
1157 * can be either a `struct Neighbour` with at least one confirmed
1158 * `struct Queue`, or a `struct DistanceVector` with at least one
1159 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1160 * data that is per neighbour that is not specific to how the
1161 * connectivity is established.
1167 * Context from #handle_incoming_msg(). Closure for many
1168 * message handlers below.
1170 struct CommunicatorMessageContext
1174 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1175 * flow control to unchoke.
1177 struct CommunicatorMessageContext *next;
1180 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1181 * flow control to unchoke.
1183 struct CommunicatorMessageContext *prev;
1186 * Which communicator provided us with the message.
1188 struct TransportClient *tc;
1191 * Additional information for flow control and about the sender.
1193 struct GNUNET_TRANSPORT_IncomingMessage im;
1196 * Number of hops the message has travelled (if DV-routed).
1197 * FIXME: make use of this in ACK handling!
1199 uint16_t total_hops;
1204 * Closure for #core_env_sent_cb.
1206 struct CoreSentContext
1210 * Kept in a DLL to clear @e vl in case @e vl is lost.
1212 struct CoreSentContext *next;
1215 * Kept in a DLL to clear @e vl in case @e vl is lost.
1217 struct CoreSentContext *prev;
1220 * Virtual link this is about.
1222 struct VirtualLink *vl;
1225 * How big was the message.
1230 * By how much should we increment @e vl's
1231 * incoming_fc_window_size_used once we are done sending to CORE?
1232 * Use to ensure we do not increment twice if there is more than one
1240 * A virtual link is another reachable peer that is known to CORE. It
1241 * can be either a `struct Neighbour` with at least one confirmed
1242 * `struct Queue`, or a `struct DistanceVector` with at least one
1243 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1244 * data that is per neighbour that is not specific to how the
1245 * connectivity is established.
1250 * Identity of the peer at the other end of the link.
1252 struct GNUNET_PeerIdentity target;
1255 * Communicators blocked for receiving on @e target as we are waiting
1256 * on the @e core_recv_window to increase.
1258 struct CommunicatorMessageContext *cmc_head;
1261 * Communicators blocked for receiving on @e target as we are waiting
1262 * on the @e core_recv_window to increase.
1264 struct CommunicatorMessageContext *cmc_tail;
1267 * Head of list of messages pending for this VL.
1269 struct PendingMessage *pending_msg_head;
1272 * Tail of list of messages pending for this VL.
1274 struct PendingMessage *pending_msg_tail;
1277 * Kept in a DLL to clear @e vl in case @e vl is lost.
1279 struct CoreSentContext *csc_tail;
1282 * Kept in a DLL to clear @e vl in case @e vl is lost.
1284 struct CoreSentContext *csc_head;
1287 * Task scheduled to possibly notfiy core that this peer is no
1288 * longer counting as confirmed. Runs the #core_visibility_check(),
1289 * which checks that some DV-path or a queue exists that is still
1290 * considered confirmed.
1292 struct GNUNET_SCHEDULER_Task *visibility_task;
1295 * Neighbour used by this virtual link, NULL if @e dv is used.
1297 struct Neighbour *n;
1300 * Distance vector used by this virtual link, NULL if @e n is used.
1302 struct DistanceVector *dv;
1305 * Last challenge we received from @a n.
1306 * FIXME: where do we need this?
1308 struct ChallengeNonceP n_challenge;
1311 * Last challenge we used with @a n for flow control.
1312 * FIXME: where do we need this?
1314 struct ChallengeNonceP my_challenge;
1317 * Sender timestamp of @e n_challenge, used to generate out-of-order
1318 * challenges (as sender's timestamps must be monotonically
1319 * increasing). FIXME: where do we need this?
1321 struct GNUNET_TIME_Absolute n_challenge_time;
1324 * Sender timestamp of the last
1325 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1326 * received. Note that we do not persist this monotonic time as we
1327 * do not really have to worry about ancient flow control window
1328 * sizes after restarts.
1330 struct GNUNET_TIME_Absolute last_fc_timestamp;
1333 * Used to generate unique UUIDs for messages that are being
1336 uint64_t message_uuid_ctr;
1339 * Memory allocated for this virtual link. Expresses how much RAM
1340 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1341 * Can be adapted to dedicate more RAM to links that need it, while
1342 * sticking to some overall RAM limit. For now, set to
1343 * #DEFAULT_WINDOW_SIZE.
1345 uint64_t available_fc_window_size;
1348 * Memory actually used to buffer packets on this virtual link.
1349 * Expresses how much RAM we are currently using for virtual link.
1350 * Note that once CORE is done with a packet, we decrement the value
1353 uint64_t incoming_fc_window_size_ram;
1356 * Last flow control window size we provided to the other peer, in
1357 * bytes. We are allowing the other peer to send this
1360 uint64_t incoming_fc_window_size;
1363 * How much of the window did the other peer successfully use (and
1364 * we already passed it on to CORE)? Must be below @e
1365 * incoming_fc_window_size. We should effectively signal the
1366 * other peer that the window is this much bigger at the next
1367 * opportunity / challenge.
1369 uint64_t incoming_fc_window_size_used;
1372 * What is our current estimate on the message loss rate for the sender?
1373 * Based on the difference between how much the sender sent according
1374 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1375 * (@e outbound_sent field) and how much we actually received at that
1376 * time (@e incoming_fc_window_size_used). This delta is then
1377 * added onto the @e incoming_fc_window_size when determining the
1378 * @e outbound_window_size we send to the other peer. Initially zero.
1379 * May be negative if we (due to out-of-order delivery) actually received
1380 * more than the sender claims to have sent in its last FC message.
1382 int64_t incoming_fc_window_size_loss;
1385 * Our current flow control window size in bytes. We
1386 * are allowed to transmit this many bytes to @a n as per
1387 * our @e my_challenge "account".
1389 uint64_t outbound_fc_window_size;
1392 * How much of our current flow control window size have we
1393 * used (in bytes). Must be below
1394 * @e outbound_fc_window_size.
1396 uint64_t outbound_fc_window_size_used;
1399 * Generator for the sequence numbers of
1400 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1402 uint32_t fc_seq_gen;
1405 * Last sequence number of a
1406 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1409 uint32_t last_fc_seq;
1412 * How many more messages can we send to CORE before we exhaust
1413 * the receive window of CORE for this peer? If this hits zero,
1414 * we must tell communicators to stop providing us more messages
1415 * for this peer. In fact, the window can go negative as we
1416 * have multiple communicators, so per communicator we can go
1417 * down by one into the negative range. Furthermore, we count
1418 * delivery per CORE client, so if we had multiple cores, that
1419 * might also cause a negative window size here (as one message
1420 * would decrement the window by one per CORE client).
1422 int core_recv_window;
1427 * Data structure kept when we are waiting for an acknowledgement.
1429 struct PendingAcknowledgement
1433 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1434 * is kept in relation to its pending message.
1436 struct PendingAcknowledgement *next_pm;
1439 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1440 * is kept in relation to its pending message.
1442 struct PendingAcknowledgement *prev_pm;
1445 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1446 * is kept in relation to the queue that was used to transmit the
1449 struct PendingAcknowledgement *next_queue;
1452 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1453 * is kept in relation to the queue that was used to transmit the
1456 struct PendingAcknowledgement *prev_queue;
1459 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1460 * is kept in relation to the DVH that was used to transmit the
1463 struct PendingAcknowledgement *next_dvh;
1466 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1467 * is kept in relation to the DVH that was used to transmit the
1470 struct PendingAcknowledgement *prev_dvh;
1473 * Pointers for the DLL of all pending acknowledgements.
1474 * This list is sorted by @e transmission time. If the list gets too
1475 * long, the oldest entries are discarded.
1477 struct PendingAcknowledgement *next_pa;
1480 * Pointers for the DLL of all pending acknowledgements.
1481 * This list is sorted by @e transmission time. If the list gets too
1482 * long, the oldest entries are discarded.
1484 struct PendingAcknowledgement *prev_pa;
1487 * Unique identifier for this transmission operation.
1489 struct AcknowledgementUUIDP ack_uuid;
1492 * Message that was transmitted, may be NULL if the message was ACKed
1493 * via another channel.
1495 struct PendingMessage *pm;
1498 * Distance vector path chosen for this transmission, NULL if transmission
1499 * was to a direct neighbour OR if the path was forgotten in the meantime.
1501 struct DistanceVectorHop *dvh;
1504 * Queue used for transmission, NULL if the queue has been destroyed
1505 * (which may happen before we get an acknowledgement).
1507 struct Queue *queue;
1510 * Time of the transmission, for RTT calculation.
1512 struct GNUNET_TIME_Absolute transmission_time;
1515 * Number of bytes of the original message (to calculate bandwidth).
1517 uint16_t message_size;
1522 * One possible hop towards a DV target.
1524 struct DistanceVectorHop
1528 * Kept in a MDLL, sorted by @e timeout.
1530 struct DistanceVectorHop *next_dv;
1533 * Kept in a MDLL, sorted by @e timeout.
1535 struct DistanceVectorHop *prev_dv;
1540 struct DistanceVectorHop *next_neighbour;
1545 struct DistanceVectorHop *prev_neighbour;
1548 * Head of DLL of PAs that used our @a path.
1550 struct PendingAcknowledgement *pa_head;
1553 * Tail of DLL of PAs that used our @a path.
1555 struct PendingAcknowledgement *pa_tail;
1558 * What would be the next hop to @e target?
1560 struct Neighbour *next_hop;
1563 * Distance vector entry this hop belongs with.
1565 struct DistanceVector *dv;
1568 * Array of @e distance hops to the target, excluding @e next_hop.
1569 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1570 * at the end of this struct. Excludes the target itself!
1572 const struct GNUNET_PeerIdentity *path;
1575 * At what time do we forget about this path unless we see it again
1578 struct GNUNET_TIME_Absolute timeout;
1581 * For how long is the validation of this path considered
1583 * Set to ZERO if the path is learned by snooping on DV learn messages
1584 * initiated by other peers, and to the time at which we generated the
1585 * challenge for DV learn operations this peer initiated.
1587 struct GNUNET_TIME_Absolute path_valid_until;
1590 * Performance data for this transmission possibility.
1592 struct PerformanceData pd;
1595 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1596 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1599 unsigned int distance;
1604 * Entry in our #dv_routes table, representing a (set of) distance
1605 * vector routes to a particular peer.
1607 struct DistanceVector
1611 * To which peer is this a route?
1613 struct GNUNET_PeerIdentity target;
1616 * Known paths to @e target.
1618 struct DistanceVectorHop *dv_head;
1621 * Known paths to @e target.
1623 struct DistanceVectorHop *dv_tail;
1626 * Task scheduled to purge expired paths from @e dv_head MDLL.
1628 struct GNUNET_SCHEDULER_Task *timeout_task;
1631 * Do we have a confirmed working queue and are thus visible to
1632 * CORE? If so, this is the virtual link, otherwise NULL.
1634 struct VirtualLink *vl;
1637 * Signature affirming @e ephemeral_key of type
1638 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1640 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1643 * How long is @e sender_sig valid
1645 struct GNUNET_TIME_Absolute ephemeral_validity;
1648 * What time was @e sender_sig created
1650 struct GNUNET_TIME_Absolute monotime;
1653 * Our ephemeral key.
1655 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1658 * Our private ephemeral key.
1660 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1665 * Entry identifying transmission in one of our `struct
1666 * Queue` which still awaits an ACK. This is used to
1667 * ensure we do not overwhelm a communicator and limit the number of
1668 * messages outstanding per communicator (say in case communicator is
1669 * CPU bound) and per queue (in case bandwidth allocation exceeds
1670 * what the communicator can actually provide towards a particular
1679 struct QueueEntry *next;
1684 struct QueueEntry *prev;
1687 * Queue this entry is queued with.
1689 struct Queue *queue;
1692 * Pending message this entry is for, or NULL for none.
1694 struct PendingMessage *pm;
1697 * Message ID used for this message with the queue used for transmission.
1704 * A queue is a message queue provided by a communicator
1705 * via which we can reach a particular neighbour.
1712 struct Queue *next_neighbour;
1717 struct Queue *prev_neighbour;
1722 struct Queue *prev_client;
1727 struct Queue *next_client;
1730 * Head of DLL of PAs that used this queue.
1732 struct PendingAcknowledgement *pa_head;
1735 * Tail of DLL of PAs that used this queue.
1737 struct PendingAcknowledgement *pa_tail;
1740 * Head of DLL of unacked transmission requests.
1742 struct QueueEntry *queue_head;
1745 * End of DLL of unacked transmission requests.
1747 struct QueueEntry *queue_tail;
1750 * Which neighbour is this queue for?
1752 struct Neighbour *neighbour;
1755 * Which communicator offers this queue?
1757 struct TransportClient *tc;
1760 * Address served by the queue.
1762 const char *address;
1765 * Task scheduled for the time when this queue can (likely) transmit the
1768 struct GNUNET_SCHEDULER_Task *transmit_task;
1771 * How long do *we* consider this @e address to be valid? In the past or
1772 * zero if we have not yet validated it. Can be updated based on
1773 * challenge-response validations (via address validation logic), or when we
1774 * receive ACKs that we can definitively map to transmissions via this
1777 struct GNUNET_TIME_Absolute validated_until;
1780 * Performance data for this queue.
1782 struct PerformanceData pd;
1785 * Message ID generator for transmissions on this queue to the
1791 * Unique identifier of this queue with the communicator.
1796 * Maximum transmission unit supported by this queue.
1803 uint32_t num_msg_pending;
1808 uint32_t num_bytes_pending;
1811 * Length of the DLL starting at @e queue_head.
1813 unsigned int queue_length;
1816 * Network type offered by this queue.
1818 enum GNUNET_NetworkType nt;
1821 * Connection status for this queue.
1823 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1826 * Set to #GNUNET_YES if this queue is idle waiting for some
1827 * virtual link to give it a pending message.
1834 * Information we keep for a message that we are reassembling.
1836 struct ReassemblyContext
1840 * Original message ID for of the message that all the fragments
1843 struct MessageUUIDP msg_uuid;
1846 * Which neighbour is this context for?
1848 struct Neighbour *neighbour;
1851 * Entry in the reassembly heap (sorted by expiration).
1853 struct GNUNET_CONTAINER_HeapNode *hn;
1856 * Bitfield with @e msg_size bits representing the positions
1857 * where we have received fragments. When we receive a fragment,
1858 * we check the bits in @e bitfield before incrementing @e msg_missing.
1860 * Allocated after the reassembled message.
1865 * At what time will we give up reassembly of this message?
1867 struct GNUNET_TIME_Absolute reassembly_timeout;
1870 * Time we received the last fragment. @e avg_ack_delay must be
1871 * incremented by now - @e last_frag multiplied by @e num_acks.
1873 struct GNUNET_TIME_Absolute last_frag;
1876 * How big is the message we are reassembling in total?
1881 * How many bytes of the message are still missing? Defragmentation
1882 * is complete when @e msg_missing == 0.
1884 uint16_t msg_missing;
1886 /* Followed by @e msg_size bytes of the (partially) defragmented original
1889 /* Followed by @e bitfield data */
1894 * A neighbour that at least one communicator is connected to.
1900 * Which peer is this about?
1902 struct GNUNET_PeerIdentity pid;
1905 * Map with `struct ReassemblyContext` structs for fragments under
1906 * reassembly. May be NULL if we currently have no fragments from
1907 * this @e pid (lazy initialization).
1909 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1912 * Heap with `struct ReassemblyContext` structs for fragments under
1913 * reassembly. May be NULL if we currently have no fragments from
1914 * this @e pid (lazy initialization).
1916 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1919 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1921 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1924 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1925 * purged if this neighbour goes down.
1927 struct DistanceVectorHop *dv_head;
1930 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1931 * purged if this neighbour goes down.
1933 struct DistanceVectorHop *dv_tail;
1936 * Head of DLL of queues to this peer.
1938 struct Queue *queue_head;
1941 * Tail of DLL of queues to this peer.
1943 struct Queue *queue_tail;
1946 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1947 * the PEERSTORE, or NULL.
1949 struct GNUNET_PEERSTORE_IterateContext *get;
1952 * Handle to a PEERSTORE store operation to store this @e pid's @e
1953 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1955 struct GNUNET_PEERSTORE_StoreContext *sc;
1958 * Do we have a confirmed working queue and are thus visible to
1959 * CORE? If so, this is the virtual link, otherwise NULL.
1961 struct VirtualLink *vl;
1964 * Latest DVLearn monotonic time seen from this peer. Initialized only
1965 * if @e dl_monotime_available is #GNUNET_YES.
1967 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1970 * Do we have the lastest value for @e last_dv_learn_monotime from
1971 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1973 int dv_monotime_available;
1978 * Another peer attempted to talk to us, we should try to establish
1979 * a connection in the other direction.
1981 struct IncomingRequest
1987 struct IncomingRequest *next;
1992 struct IncomingRequest *prev;
1995 * Handle for watching the peerstore for HELLOs for this peer.
1997 struct GNUNET_PEERSTORE_WatchContext *wc;
2000 * Which peer is this about?
2002 struct GNUNET_PeerIdentity pid;
2007 * A peer that an application (client) would like us to talk to directly.
2013 * Which peer is this about?
2015 struct GNUNET_PeerIdentity pid;
2018 * Client responsible for the request.
2020 struct TransportClient *tc;
2023 * Handle for watching the peerstore for HELLOs for this peer.
2025 struct GNUNET_PEERSTORE_WatchContext *wc;
2028 * What kind of performance preference does this @e tc have?
2032 enum GNUNET_MQ_PriorityPreferences pk;
2035 * How much bandwidth would this @e tc like to see?
2037 struct GNUNET_BANDWIDTH_Value32NBO bw;
2042 * Types of different pending messages.
2044 enum PendingMessageType
2048 * Ordinary message received from the CORE service.
2055 PMT_FRAGMENT_BOX = 1,
2060 PMT_RELIABILITY_BOX = 2
2066 * Transmission request that is awaiting delivery. The original
2067 * transmission requests from CORE may be too big for some queues.
2068 * In this case, a *tree* of fragments is created. At each
2069 * level of the tree, fragments are kept in a DLL ordered by which
2070 * fragment should be sent next (at the head). The tree is searched
2071 * top-down, with the original message at the root.
2073 * To select a node for transmission, first it is checked if the
2074 * current node's message fits with the MTU. If it does not, we
2075 * either calculate the next fragment (based on @e frag_off) from the
2076 * current node, or, if all fragments have already been created,
2077 * descend to the @e head_frag. Even though the node was already
2078 * fragmented, the fragment may be too big if the fragment was
2079 * generated for a queue with a larger MTU. In this case, the node
2080 * may be fragmented again, thus creating a tree.
2082 * When acknowledgements for fragments are received, the tree
2083 * must be pruned, removing those parts that were already
2084 * acknowledged. When fragments are sent over a reliable
2085 * channel, they can be immediately removed.
2087 * If a message is ever fragmented, then the original "full" message
2088 * is never again transmitted (even if it fits below the MTU), and
2089 * only (remaining) fragments are sent.
2091 struct PendingMessage
2094 * Kept in a MDLL of messages for this @a vl.
2096 struct PendingMessage *next_vl;
2099 * Kept in a MDLL of messages for this @a vl.
2101 struct PendingMessage *prev_vl;
2104 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2106 struct PendingMessage *next_client;
2109 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2111 struct PendingMessage *prev_client;
2114 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2115 * #PMT_FRAGMENT_BOx)
2117 struct PendingMessage *next_frag;
2120 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2121 * #PMT_FRAGMENT_BOX)
2123 struct PendingMessage *prev_frag;
2126 * Head of DLL of PAs for this pending message.
2128 struct PendingAcknowledgement *pa_head;
2131 * Tail of DLL of PAs for this pending message.
2133 struct PendingAcknowledgement *pa_tail;
2136 * This message, reliability boxed. Only possibly available if @e pmt is
2139 struct PendingMessage *bpm;
2142 * Target of the request (always the ultimate destination!).
2144 struct VirtualLink *vl;
2147 * Set to non-NULL value if this message is currently being given to a
2148 * communicator and we are awaiting that communicator's acknowledgement.
2149 * Note that we must not retransmit a pending message while we're still
2150 * in the process of giving it to a communicator. If a pending message
2151 * is free'd while this entry is non-NULL, the @e qe reference to us
2152 * should simply be set to NULL.
2154 struct QueueEntry *qe;
2157 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2159 struct TransportClient *client;
2162 * Head of a MDLL of fragments created for this core message.
2164 struct PendingMessage *head_frag;
2167 * Tail of a MDLL of fragments created for this core message.
2169 struct PendingMessage *tail_frag;
2172 * Our parent in the fragmentation tree.
2174 struct PendingMessage *frag_parent;
2177 * At what time should we give up on the transmission (and no longer retry)?
2179 struct GNUNET_TIME_Absolute timeout;
2182 * What is the earliest time for us to retry transmission of this message?
2184 struct GNUNET_TIME_Absolute next_attempt;
2187 * UUID to use for this message (used for reassembly of fragments, only
2188 * initialized if @e msg_uuid_set is #GNUNET_YES).
2190 struct MessageUUIDP msg_uuid;
2193 * UUID we use to identify this message in our logs.
2194 * Generated by incrementing the "logging_uuid_gen".
2196 unsigned long long logging_uuid;
2199 * Type of the pending message.
2201 enum PendingMessageType pmt;
2204 * Preferences for this message.
2205 * TODO: actually use this!
2207 enum GNUNET_MQ_PriorityPreferences prefs;
2210 * Size of the original message.
2215 * Offset at which we should generate the next fragment.
2220 * #GNUNET_YES once @e msg_uuid was initialized
2222 int16_t msg_uuid_set;
2224 /* Followed by @e bytes_msg to transmit */
2229 * Acknowledgement payload.
2231 struct TransportCummulativeAckPayload
2234 * When did we receive the message we are ACKing? Used to calculate
2235 * the delay we introduced by cummulating ACKs.
2237 struct GNUNET_TIME_Absolute receive_time;
2240 * UUID of a message being acknowledged.
2242 struct AcknowledgementUUIDP ack_uuid;
2247 * Data structure in which we track acknowledgements still to
2250 struct AcknowledgementCummulator
2253 * Target peer for which we are accumulating ACKs here.
2255 struct GNUNET_PeerIdentity target;
2258 * ACK data being accumulated. Only @e num_acks slots are valid.
2260 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2263 * Task scheduled either to transmit the cummulative ACK message,
2264 * or to clean up this data structure after extended periods of
2265 * inactivity (if @e num_acks is zero).
2267 struct GNUNET_SCHEDULER_Task *task;
2270 * When is @e task run (only used if @e num_acks is non-zero)?
2272 struct GNUNET_TIME_Absolute min_transmission_time;
2275 * Counter to produce the `ack_counter` in the `struct
2276 * TransportReliabilityAckMessage`. Allows the receiver to detect
2277 * lost ACK messages. Incremented by @e num_acks upon transmission.
2279 uint32_t ack_counter;
2282 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2284 unsigned int num_acks;
2289 * One of the addresses of this peer.
2291 struct AddressListEntry
2297 struct AddressListEntry *next;
2302 struct AddressListEntry *prev;
2305 * Which communicator provides this address?
2307 struct TransportClient *tc;
2310 * The actual address.
2312 const char *address;
2315 * Current context for storing this address in the peerstore.
2317 struct GNUNET_PEERSTORE_StoreContext *sc;
2320 * Task to periodically do @e st operation.
2322 struct GNUNET_SCHEDULER_Task *st;
2325 * What is a typical lifetime the communicator expects this
2326 * address to have? (Always from now.)
2328 struct GNUNET_TIME_Relative expiration;
2331 * Address identifier used by the communicator.
2336 * Network type offered by this address.
2338 enum GNUNET_NetworkType nt;
2343 * Client connected to the transport service.
2345 struct TransportClient
2351 struct TransportClient *next;
2356 struct TransportClient *prev;
2359 * Handle to the client.
2361 struct GNUNET_SERVICE_Client *client;
2364 * Message queue to the client.
2366 struct GNUNET_MQ_Handle *mq;
2369 * What type of client is this?
2371 enum ClientType type;
2377 * Information for @e type #CT_CORE.
2383 * Head of list of messages pending for this client, sorted by
2384 * transmission time ("next_attempt" + possibly internal prioritization).
2386 struct PendingMessage *pending_msg_head;
2389 * Tail of list of messages pending for this client.
2391 struct PendingMessage *pending_msg_tail;
2396 * Information for @e type #CT_MONITOR.
2402 * Peer identity to monitor the addresses of.
2403 * Zero to monitor all neighbours. Valid if
2404 * @e type is #CT_MONITOR.
2406 struct GNUNET_PeerIdentity peer;
2409 * Is this a one-shot monitor?
2417 * Information for @e type #CT_COMMUNICATOR.
2422 * If @e type is #CT_COMMUNICATOR, this communicator
2423 * supports communicating using these addresses.
2425 char *address_prefix;
2428 * Head of DLL of queues offered by this communicator.
2430 struct Queue *queue_head;
2433 * Tail of DLL of queues offered by this communicator.
2435 struct Queue *queue_tail;
2438 * Head of list of the addresses of this peer offered by this
2441 struct AddressListEntry *addr_head;
2444 * Tail of list of the addresses of this peer offered by this
2447 struct AddressListEntry *addr_tail;
2450 * Number of queue entries in all queues to this communicator. Used
2451 * throttle sending to a communicator if we see that the communicator
2452 * is globally unable to keep up.
2454 unsigned int total_queue_length;
2457 * Characteristics of this communicator.
2459 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2464 * Information for @e type #CT_APPLICATION
2470 * Map of requests for peers the given client application would like to
2471 * see connections for. Maps from PIDs to `struct PeerRequest`.
2473 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2482 * State we keep for validation activities. Each of these
2483 * is both in the #validation_heap and the #validation_map.
2485 struct ValidationState
2489 * For which peer is @a address to be validated (or possibly valid)?
2490 * Serves as key in the #validation_map.
2492 struct GNUNET_PeerIdentity pid;
2495 * How long did the peer claim this @e address to be valid? Capped at
2496 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2497 * were told about the address and the value claimed by the other peer at
2498 * that time. May be updated similarly when validation succeeds.
2500 struct GNUNET_TIME_Absolute valid_until;
2503 * How long do *we* consider this @e address to be valid?
2504 * In the past or zero if we have not yet validated it.
2506 struct GNUNET_TIME_Absolute validated_until;
2509 * When did we FIRST use the current @e challenge in a message?
2510 * Used to sanity-check @code{origin_time} in the response when
2511 * calculating the RTT. If the @code{origin_time} is not in
2512 * the expected range, the response is discarded as malicious.
2514 struct GNUNET_TIME_Absolute first_challenge_use;
2517 * When did we LAST use the current @e challenge in a message?
2518 * Used to sanity-check @code{origin_time} in the response when
2519 * calculating the RTT. If the @code{origin_time} is not in
2520 * the expected range, the response is discarded as malicious.
2522 struct GNUNET_TIME_Absolute last_challenge_use;
2525 * Next time we will send the @e challenge to the peer, if this time is past
2526 * @e valid_until, this validation state is released at this time. If the
2527 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2528 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2529 * to re-validate before the validity actually expires.
2531 struct GNUNET_TIME_Absolute next_challenge;
2534 * Current backoff factor we're applying for sending the @a challenge.
2535 * Reset to 0 if the @a challenge is confirmed upon validation.
2536 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2537 * existing value if we receive an unvalidated address again over
2538 * another channel (and thus should consider the information "fresh").
2539 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2541 struct GNUNET_TIME_Relative challenge_backoff;
2544 * Initially set to "forever". Once @e validated_until is set, this value is
2545 * set to the RTT that tells us how long it took to receive the validation.
2547 struct GNUNET_TIME_Relative validation_rtt;
2550 * The challenge we sent to the peer to get it to validate the address. Note
2551 * that we rotate the challenge whenever we update @e validated_until to
2552 * avoid attacks where a peer simply replays an old challenge in the future.
2553 * (We must not rotate more often as otherwise we may discard valid answers
2554 * due to packet losses, latency and reorderings on the network).
2556 struct ChallengeNonceP challenge;
2559 * Claimed address of the peer.
2564 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2565 * heap is used to figure out when the next validation activity should be
2568 struct GNUNET_CONTAINER_HeapNode *hn;
2571 * Handle to a PEERSTORE store operation for this @e address. NULL if
2572 * no PEERSTORE operation is pending.
2574 struct GNUNET_PEERSTORE_StoreContext *sc;
2577 * Self-imposed limit on the previous flow control window. (May be zero,
2578 * if we never used data from the previous window or are establishing the
2579 * connection for the first time).
2581 uint32_t last_window_consum_limit;
2584 * We are technically ready to send the challenge, but we are waiting for
2585 * the respective queue to become available for transmission.
2592 * A Backtalker is a peer sending us backchannel messages. We use this
2593 * struct to detect monotonic time violations, cache ephemeral key
2594 * material (to avoid repeatedly checking signatures), and to synchronize
2595 * monotonic time with the PEERSTORE.
2600 * Peer this is about.
2602 struct GNUNET_PeerIdentity pid;
2605 * Last (valid) monotonic time received from this sender.
2607 struct GNUNET_TIME_Absolute monotonic_time;
2610 * When will this entry time out?
2612 struct GNUNET_TIME_Absolute timeout;
2615 * Last (valid) ephemeral key received from this sender.
2617 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2620 * Task associated with this backtalker. Can be for timeout,
2621 * or other asynchronous operations.
2623 struct GNUNET_SCHEDULER_Task *task;
2626 * Communicator context waiting on this backchannel's @e get, or NULL.
2628 struct CommunicatorMessageContext *cmc;
2631 * Handle for an operation to fetch @e monotonic_time information from the
2632 * PEERSTORE, or NULL.
2634 struct GNUNET_PEERSTORE_IterateContext *get;
2637 * Handle to a PEERSTORE store operation for this @e pid's @e
2638 * monotonic_time. NULL if no PEERSTORE operation is pending.
2640 struct GNUNET_PEERSTORE_StoreContext *sc;
2643 * Number of bytes of the original message body that follows after this
2651 * Head of linked list of all clients to this service.
2653 static struct TransportClient *clients_head;
2656 * Tail of linked list of all clients to this service.
2658 static struct TransportClient *clients_tail;
2661 * Statistics handle.
2663 static struct GNUNET_STATISTICS_Handle *GST_stats;
2666 * Configuration handle.
2668 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2673 static struct GNUNET_PeerIdentity GST_my_identity;
2678 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2681 * Map from PIDs to `struct Neighbour` entries. A peer is
2682 * a neighbour if we have an MQ to it from some communicator.
2684 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2687 * Map from PIDs to `struct Backtalker` entries. A peer is
2688 * a backtalker if it recently send us backchannel messages.
2690 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2693 * Map from PIDs to `struct AcknowledgementCummulator`s.
2694 * Here we track the cummulative ACKs for transmission.
2696 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2699 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2700 * a `struct PendingAcknowledgement`.
2702 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2705 * Map from PIDs to `struct DistanceVector` entries describing
2706 * known paths to the peer.
2708 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2711 * Map from PIDs to `struct ValidationState` entries describing
2712 * addresses we are aware of and their validity state.
2714 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2717 * Map from PIDs to `struct VirtualLink` entries describing
2718 * links CORE knows to exist.
2720 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2723 * Map from challenges to `struct LearnLaunchEntry` values.
2725 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2728 * Head of a DLL sorted by launch time.
2730 static struct LearnLaunchEntry *lle_head;
2733 * Tail of a DLL sorted by launch time.
2735 static struct LearnLaunchEntry *lle_tail;
2738 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2739 * sorting addresses we are aware of by when we should next try to (re)validate
2742 static struct GNUNET_CONTAINER_Heap *validation_heap;
2745 * Database for peer's HELLOs.
2747 static struct GNUNET_PEERSTORE_Handle *peerstore;
2750 * Task run to initiate DV learning.
2752 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2755 * Task to run address validation.
2757 static struct GNUNET_SCHEDULER_Task *validation_task;
2760 * The most recent PA we have created, head of DLL.
2761 * The length of the DLL is kept in #pa_count.
2763 static struct PendingAcknowledgement *pa_head;
2766 * The oldest PA we have created, tail of DLL.
2767 * The length of the DLL is kept in #pa_count.
2769 static struct PendingAcknowledgement *pa_tail;
2772 * List of incomming connections where we are trying
2773 * to get a connection back established. Length
2774 * kept in #ir_total.
2776 static struct IncomingRequest *ir_head;
2779 * Tail of DLL starting at #ir_head.
2781 static struct IncomingRequest *ir_tail;
2784 * Length of the DLL starting at #ir_head.
2786 static unsigned int ir_total;
2789 * Generator of `logging_uuid` in `struct PendingMessage`.
2791 static unsigned long long logging_uuid_gen;
2794 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2795 * limit the size of the data structure.
2797 static unsigned int pa_count;
2800 * Monotonic time we use for HELLOs generated at this time. TODO: we
2801 * should increase this value from time to time (i.e. whenever a
2802 * `struct AddressListEntry` actually expires), but IF we do this, we
2803 * must also update *all* (remaining) addresses in the PEERSTORE at
2804 * that time! (So for now only increased when the peer is restarted,
2805 * which hopefully roughly matches whenever our addresses change.)
2807 static struct GNUNET_TIME_Absolute hello_mono_time;
2811 * Get an offset into the transmission history buffer for `struct
2812 * PerformanceData`. Note that the caller must perform the required
2813 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2816 * An 'age' lasts 15 minute slots.
2818 * @return current age of the world
2823 struct GNUNET_TIME_Absolute now;
2825 now = GNUNET_TIME_absolute_get ();
2826 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2831 * Release @a ir data structure.
2833 * @param ir data structure to release
2836 free_incoming_request (struct IncomingRequest *ir)
2838 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2839 GNUNET_assert (ir_total > 0);
2841 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2847 * Release @a pa data structure.
2849 * @param pa data structure to release
2852 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2854 struct Queue *q = pa->queue;
2855 struct PendingMessage *pm = pa->pm;
2856 struct DistanceVectorHop *dvh = pa->dvh;
2858 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2862 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2867 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2872 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2875 GNUNET_assert (GNUNET_YES ==
2876 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2877 &pa->ack_uuid.value,
2884 * Free fragment tree below @e root, excluding @e root itself.
2885 * FIXME: this does NOT seem to have the intended semantics
2886 * based on how this is called. Seems we generally DO expect
2887 * @a root to be free'ed itself as well!
2889 * @param root root of the tree to free
2892 free_fragment_tree (struct PendingMessage *root)
2894 struct PendingMessage *frag;
2896 while (NULL != (frag = root->head_frag))
2898 struct PendingAcknowledgement *pa;
2900 free_fragment_tree (frag);
2901 while (NULL != (pa = frag->pa_head))
2903 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2906 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2913 * Release memory associated with @a pm and remove @a pm from associated
2914 * data structures. @a pm must be a top-level pending message and not
2915 * a fragment in the tree. The entire tree is freed (if applicable).
2917 * @param pm the pending message to free
2920 free_pending_message (struct PendingMessage *pm)
2922 struct TransportClient *tc = pm->client;
2923 struct VirtualLink *vl = pm->vl;
2924 struct PendingAcknowledgement *pa;
2928 GNUNET_CONTAINER_MDLL_remove (client,
2929 tc->details.core.pending_msg_head,
2930 tc->details.core.pending_msg_tail,
2935 GNUNET_CONTAINER_MDLL_remove (vl,
2936 vl->pending_msg_head,
2937 vl->pending_msg_tail,
2940 while (NULL != (pa = pm->pa_head))
2942 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2946 free_fragment_tree (pm);
2949 GNUNET_assert (pm == pm->qe->pm);
2952 GNUNET_free_non_null (pm->bpm);
2958 * Free virtual link.
2960 * @param vl link data to free
2963 free_virtual_link (struct VirtualLink *vl)
2965 struct PendingMessage *pm;
2966 struct CoreSentContext *csc;
2968 while (NULL != (pm = vl->pending_msg_head))
2969 free_pending_message (pm);
2970 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2971 if (NULL != vl->visibility_task)
2973 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2974 vl->visibility_task = NULL;
2976 while (NULL != (csc = vl->csc_head))
2978 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
2979 GNUNET_assert (vl == csc->vl);
2982 GNUNET_break (NULL == vl->n);
2983 GNUNET_break (NULL == vl->dv);
2989 * Free validation state.
2991 * @param vs validation state to free
2994 free_validation_state (struct ValidationState *vs)
2996 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2997 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3001 GNUNET_PEERSTORE_store_cancel (vs->sc);
3004 GNUNET_free (vs->address);
3010 * Lookup neighbour for peer @a pid.
3012 * @param pid neighbour to look for
3013 * @return NULL if we do not have this peer as a neighbour
3015 static struct Neighbour *
3016 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3018 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3023 * Lookup virtual link for peer @a pid.
3025 * @param pid virtual link to look for
3026 * @return NULL if we do not have this peer as a virtual link
3028 static struct VirtualLink *
3029 lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3031 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3036 * Details about what to notify monitors about.
3041 * @deprecated To be discussed if we keep these...
3043 struct GNUNET_TIME_Absolute last_validation;
3044 struct GNUNET_TIME_Absolute valid_until;
3045 struct GNUNET_TIME_Absolute next_validation;
3048 * Current round-trip time estimate.
3050 struct GNUNET_TIME_Relative rtt;
3053 * Connection status.
3055 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3060 uint32_t num_msg_pending;
3065 uint32_t num_bytes_pending;
3070 * Free a @dvh. Callers MAY want to check if this was the last path to the
3071 * `target`, and if so call #free_dv_route to also free the associated DV
3072 * entry in #dv_routes (if not, the associated scheduler job should eventually
3075 * @param dvh hop to free
3078 free_distance_vector_hop (struct DistanceVectorHop *dvh)
3080 struct Neighbour *n = dvh->next_hop;
3081 struct DistanceVector *dv = dvh->dv;
3082 struct PendingAcknowledgement *pa;
3084 while (NULL != (pa = dvh->pa_head))
3086 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3089 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3090 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3096 * Task run to check whether the hops of the @a cls still
3097 * are validated, or if we need to core about disconnection.
3099 * @param cls a `struct VirtualLink`
3102 check_link_down (void *cls);
3106 * Send message to CORE clients that we lost a connection.
3108 * @param pid peer the connection was for
3111 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3114 "Informing CORE clients about disconnect from %s\n",
3116 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3118 struct GNUNET_MQ_Envelope *env;
3119 struct DisconnectInfoMessage *dim;
3121 if (CT_CORE != tc->type)
3123 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3125 GNUNET_MQ_send (tc->mq, env);
3131 * Free entry in #dv_routes. First frees all hops to the target, and
3132 * if there are no entries left, frees @a dv as well.
3134 * @param dv route to free
3137 free_dv_route (struct DistanceVector *dv)
3139 struct DistanceVectorHop *dvh;
3141 while (NULL != (dvh = dv->dv_head))
3142 free_distance_vector_hop (dvh);
3143 if (NULL == dv->dv_head)
3145 struct VirtualLink *vl;
3149 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3150 if (NULL != (vl = dv->vl))
3152 GNUNET_assert (dv == vl->dv);
3156 cores_send_disconnect_info (&dv->target);
3157 free_virtual_link (vl);
3161 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3162 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3167 if (NULL != dv->timeout_task)
3169 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3170 dv->timeout_task = NULL;
3178 * Notify monitor @a tc about an event. That @a tc
3179 * cares about the event has already been checked.
3181 * Send @a tc information in @a me about a @a peer's status with
3182 * respect to some @a address to all monitors that care.
3184 * @param tc monitor to inform
3185 * @param peer peer the information is about
3186 * @param address address the information is about
3187 * @param nt network type associated with @a address
3188 * @param me detailed information to transmit
3191 notify_monitor (struct TransportClient *tc,
3192 const struct GNUNET_PeerIdentity *peer,
3193 const char *address,
3194 enum GNUNET_NetworkType nt,
3195 const struct MonitorEvent *me)
3197 struct GNUNET_MQ_Envelope *env;
3198 struct GNUNET_TRANSPORT_MonitorData *md;
3199 size_t addr_len = strlen (address) + 1;
3201 env = GNUNET_MQ_msg_extra (md,
3203 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3204 md->nt = htonl ((uint32_t) nt);
3206 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3207 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3208 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3209 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3210 md->cs = htonl ((uint32_t) me->cs);
3211 md->num_msg_pending = htonl (me->num_msg_pending);
3212 md->num_bytes_pending = htonl (me->num_bytes_pending);
3213 memcpy (&md[1], address, addr_len);
3214 GNUNET_MQ_send (tc->mq, env);
3219 * Send information in @a me about a @a peer's status with respect
3220 * to some @a address to all monitors that care.
3222 * @param peer peer the information is about
3223 * @param address address the information is about
3224 * @param nt network type associated with @a address
3225 * @param me detailed information to transmit
3228 notify_monitors (const struct GNUNET_PeerIdentity *peer,
3229 const char *address,
3230 enum GNUNET_NetworkType nt,
3231 const struct MonitorEvent *me)
3233 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3235 if (CT_MONITOR != tc->type)
3237 if (tc->details.monitor.one_shot)
3239 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
3240 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3242 notify_monitor (tc, peer, address, nt, me);
3248 * Called whenever a client connects. Allocates our
3249 * data structures associated with that client.
3251 * @param cls closure, NULL
3252 * @param client identification of the client
3253 * @param mq message queue for the client
3254 * @return our `struct TransportClient`
3257 client_connect_cb (void *cls,
3258 struct GNUNET_SERVICE_Client *client,
3259 struct GNUNET_MQ_Handle *mq)
3261 struct TransportClient *tc;
3264 tc = GNUNET_new (struct TransportClient);
3265 tc->client = client;
3267 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
3276 * @param rc data structure to free
3279 free_reassembly_context (struct ReassemblyContext *rc)
3281 struct Neighbour *n = rc->neighbour;
3283 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3284 GNUNET_assert (GNUNET_OK ==
3285 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
3293 * Task run to clean up reassembly context of a neighbour that have expired.
3295 * @param cls a `struct Neighbour`
3298 reassembly_cleanup_task (void *cls)
3300 struct Neighbour *n = cls;
3301 struct ReassemblyContext *rc;
3303 n->reassembly_timeout_task = NULL;
3304 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
3306 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3309 free_reassembly_context (rc);
3312 GNUNET_assert (NULL == n->reassembly_timeout_task);
3313 n->reassembly_timeout_task =
3314 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3315 &reassembly_cleanup_task,
3323 * function called to #free_reassembly_context().
3327 * @param value a `struct ReassemblyContext` to free
3328 * @return #GNUNET_OK (continue iteration)
3331 free_reassembly_cb (void *cls, uint32_t key, void *value)
3333 struct ReassemblyContext *rc = value;
3337 free_reassembly_context (rc);
3343 * Release memory used by @a neighbour.
3345 * @param neighbour neighbour entry to free
3348 free_neighbour (struct Neighbour *neighbour)
3350 struct DistanceVectorHop *dvh;
3351 struct VirtualLink *vl;
3353 GNUNET_assert (NULL == neighbour->queue_head);
3354 GNUNET_assert (GNUNET_YES ==
3355 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3358 if (NULL != neighbour->reassembly_map)
3360 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
3361 &free_reassembly_cb,
3363 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
3364 neighbour->reassembly_map = NULL;
3365 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
3366 neighbour->reassembly_heap = NULL;
3368 while (NULL != (dvh = neighbour->dv_head))
3370 struct DistanceVector *dv = dvh->dv;
3372 free_distance_vector_hop (dvh);
3373 if (NULL == dv->dv_head)
3376 if (NULL != neighbour->reassembly_timeout_task)
3378 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
3379 neighbour->reassembly_timeout_task = NULL;
3381 if (NULL != neighbour->get)
3383 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3384 neighbour->get = NULL;
3386 if (NULL != neighbour->sc)
3388 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3389 neighbour->sc = NULL;
3391 if (NULL != (vl = neighbour->vl))
3393 GNUNET_assert (neighbour == vl->n);
3397 cores_send_disconnect_info (&vl->target);
3398 free_virtual_link (vl);
3402 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3403 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3405 neighbour->vl = NULL;
3407 GNUNET_free (neighbour);
3412 * Send message to CORE clients that we lost a connection.
3414 * @param tc client to inform (must be CORE client)
3415 * @param pid peer the connection is for
3418 core_send_connect_info (struct TransportClient *tc,
3419 const struct GNUNET_PeerIdentity *pid)
3421 struct GNUNET_MQ_Envelope *env;
3422 struct ConnectInfoMessage *cim;
3424 GNUNET_assert (CT_CORE == tc->type);
3425 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3427 GNUNET_MQ_send (tc->mq, env);
3432 * Send message to CORE clients that we gained a connection
3434 * @param pid peer the queue was for
3437 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3440 "Informing CORE clients about connection to %s\n",
3442 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3444 if (CT_CORE != tc->type)
3446 core_send_connect_info (tc, pid);
3452 * We believe we are ready to transmit a message on a queue. Gives the
3453 * message to the communicator for transmission (updating the tracker,
3454 * and re-scheduling itself if applicable).
3456 * @param cls the `struct Queue` to process transmissions for
3459 transmit_on_queue (void *cls);
3463 * Called whenever something changed that might effect when we
3464 * try to do the next transmission on @a queue using #transmit_on_queue().
3466 * @param queue the queue to do scheduling for
3467 * @param p task priority to use, if @a queue is scheduled
3470 schedule_transmit_on_queue (struct Queue *queue,
3471 enum GNUNET_SCHEDULER_Priority p)
3473 if (queue->tc->details.communicator.total_queue_length >=
3474 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3476 GNUNET_STATISTICS_update (
3478 "# Transmission throttled due to communicator queue limit",
3481 queue->idle = GNUNET_NO;
3484 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3486 GNUNET_STATISTICS_update (GST_stats,
3487 "# Transmission throttled due to queue queue limit",
3490 queue->idle = GNUNET_NO;
3493 /* queue might indeed be ready, schedule it */
3494 if (NULL != queue->transmit_task)
3495 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3496 queue->transmit_task =
3497 GNUNET_SCHEDULER_add_with_priority (p, &transmit_on_queue, queue);
3498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3499 "Considering transmission on queue `%s' to %s\n",
3501 GNUNET_i2s (&queue->neighbour->pid));
3506 * Task run to check whether the hops of the @a cls still
3507 * are validated, or if we need to core about disconnection.
3509 * @param cls a `struct VirtualLink`
3512 check_link_down (void *cls)
3514 struct VirtualLink *vl = cls;
3515 struct DistanceVector *dv = vl->dv;
3516 struct Neighbour *n = vl->n;
3517 struct GNUNET_TIME_Absolute dvh_timeout;
3518 struct GNUNET_TIME_Absolute q_timeout;
3520 vl->visibility_task = NULL;
3521 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3522 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3524 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3525 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3530 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3531 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3532 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3533 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3538 if ((NULL == vl->n) && (NULL == vl->dv))
3540 cores_send_disconnect_info (&vl->target);
3541 free_virtual_link (vl);
3544 vl->visibility_task =
3545 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3554 * @param queue the queue to free
3557 free_queue (struct Queue *queue)
3559 struct Neighbour *neighbour = queue->neighbour;
3560 struct TransportClient *tc = queue->tc;
3561 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3562 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3563 struct QueueEntry *qe;
3565 struct PendingAcknowledgement *pa;
3566 struct VirtualLink *vl;
3568 if (NULL != queue->transmit_task)
3570 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3571 queue->transmit_task = NULL;
3573 while (NULL != (pa = queue->pa_head))
3575 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3579 GNUNET_CONTAINER_MDLL_remove (neighbour,
3580 neighbour->queue_head,
3581 neighbour->queue_tail,
3583 GNUNET_CONTAINER_MDLL_remove (client,
3584 tc->details.communicator.queue_head,
3585 tc->details.communicator.queue_tail,
3587 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3588 tc->details.communicator.total_queue_length);
3589 while (NULL != (qe = queue->queue_head))
3591 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3592 queue->queue_length--;
3593 tc->details.communicator.total_queue_length--;
3596 GNUNET_assert (qe == qe->pm->qe);
3601 GNUNET_assert (0 == queue->queue_length);
3602 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3603 tc->details.communicator.total_queue_length))
3605 /* Communicator dropped below threshold, resume all _other_ queues */
3606 GNUNET_STATISTICS_update (
3608 "# Transmission throttled due to communicator queue limit",
3611 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3613 schedule_transmit_on_queue (s, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3615 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3616 GNUNET_free (queue);
3618 vl = lookup_virtual_link (&neighbour->pid);
3619 if ((NULL != vl) && (neighbour == vl->n))
3621 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3622 check_link_down (vl);
3624 if (NULL == neighbour->queue_head)
3626 free_neighbour (neighbour);
3634 * @param ale address list entry to free
3637 free_address_list_entry (struct AddressListEntry *ale)
3639 struct TransportClient *tc = ale->tc;
3641 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3642 tc->details.communicator.addr_tail,
3644 if (NULL != ale->sc)
3646 GNUNET_PEERSTORE_store_cancel (ale->sc);
3649 if (NULL != ale->st)
3651 GNUNET_SCHEDULER_cancel (ale->st);
3659 * Stop the peer request in @a value.
3661 * @param cls a `struct TransportClient` that no longer makes the request
3662 * @param pid the peer's identity
3663 * @param value a `struct PeerRequest`
3664 * @return #GNUNET_YES (always)
3667 stop_peer_request (void *cls,
3668 const struct GNUNET_PeerIdentity *pid,
3671 struct TransportClient *tc = cls;
3672 struct PeerRequest *pr = value;
3674 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3677 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3687 * Called whenever a client is disconnected. Frees our
3688 * resources associated with that client.
3690 * @param cls closure, NULL
3691 * @param client identification of the client
3692 * @param app_ctx our `struct TransportClient`
3695 client_disconnect_cb (void *cls,
3696 struct GNUNET_SERVICE_Client *client,
3699 struct TransportClient *tc = app_ctx;
3703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3704 "Client %p disconnected, cleaning up.\n",
3706 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3712 struct PendingMessage *pm;
3714 while (NULL != (pm = tc->details.core.pending_msg_head))
3716 GNUNET_CONTAINER_MDLL_remove (client,
3717 tc->details.core.pending_msg_head,
3718 tc->details.core.pending_msg_tail,
3726 case CT_COMMUNICATOR: {
3728 struct AddressListEntry *ale;
3730 while (NULL != (q = tc->details.communicator.queue_head))
3732 while (NULL != (ale = tc->details.communicator.addr_head))
3733 free_address_list_entry (ale);
3734 GNUNET_free (tc->details.communicator.address_prefix);
3737 case CT_APPLICATION:
3738 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3741 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3749 * Iterator telling new CORE client about all existing
3750 * connections to peers.
3752 * @param cls the new `struct TransportClient`
3753 * @param pid a connected peer
3754 * @param value the `struct Neighbour` with more information
3755 * @return #GNUNET_OK (continue to iterate)
3758 notify_client_connect_info (void *cls,
3759 const struct GNUNET_PeerIdentity *pid,
3762 struct TransportClient *tc = cls;
3765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3766 "Telling new CORE client about existing connection to %s\n",
3768 core_send_connect_info (tc, pid);
3774 * Initialize a "CORE" client. We got a start message from this
3775 * client, so add it to the list of clients for broadcasting of
3778 * @param cls the client
3779 * @param start the start message that was sent
3782 handle_client_start (void *cls, const struct StartMessage *start)
3784 struct TransportClient *tc = cls;
3787 options = ntohl (start->options);
3788 if ((0 != (1 & options)) &&
3789 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3791 /* client thinks this is a different peer, reject */
3793 GNUNET_SERVICE_client_drop (tc->client);
3796 if (CT_NONE != tc->type)
3799 GNUNET_SERVICE_client_drop (tc->client);
3803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3804 "New CORE client with PID %s registered\n",
3805 GNUNET_i2s (&start->self));
3806 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3807 ¬ify_client_connect_info,
3809 GNUNET_SERVICE_client_continue (tc->client);
3814 * Client asked for transmission to a peer. Process the request.
3816 * @param cls the client
3817 * @param obm the send message that was sent
3820 check_client_send (void *cls, const struct OutboundMessage *obm)
3822 struct TransportClient *tc = cls;
3824 const struct GNUNET_MessageHeader *obmm;
3826 if (CT_CORE != tc->type)
3829 return GNUNET_SYSERR;
3831 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3832 if (size < sizeof (struct GNUNET_MessageHeader))
3835 return GNUNET_SYSERR;
3837 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3838 if (size != ntohs (obmm->size))
3841 return GNUNET_SYSERR;
3848 * Send a response to the @a pm that we have processed a "send"
3849 * request. Sends a confirmation to the "core" client responsible for
3850 * the original request and free's @a pm.
3852 * @param pm handle to the original pending message
3855 client_send_response (struct PendingMessage *pm)
3857 struct TransportClient *tc = pm->client;
3858 struct VirtualLink *vl = pm->vl;
3859 struct GNUNET_MQ_Envelope *env;
3860 struct SendOkMessage *som;
3864 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3865 som->peer = vl->target;
3866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3867 "Confirming transmission of <%llu> to %s\n",
3869 GNUNET_i2s (&vl->target));
3870 GNUNET_MQ_send (tc->mq, env);
3872 free_pending_message (pm);
3877 * Pick @a hops_array_length random DV paths satisfying @a options
3879 * @param dv data structure to pick paths from
3880 * @param options constraints to satisfy
3881 * @param hops_array[out] set to the result
3882 * @param hops_array_length length of the @a hops_array
3883 * @return number of entries set in @a hops_array
3886 pick_random_dv_hops (const struct DistanceVector *dv,
3887 enum RouteMessageOptions options,
3888 struct DistanceVectorHop **hops_array,
3889 unsigned int hops_array_length)
3891 uint64_t choices[hops_array_length];
3893 unsigned int dv_count;
3895 /* Pick random vectors, but weighted by distance, giving more weight
3896 to shorter vectors */
3899 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3902 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3903 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3904 .rel_value_us == 0))
3905 continue; /* pos unconfirmed and confirmed required */
3906 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3911 if (dv_count <= hops_array_length)
3914 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3916 hops_array[dv_count++] = pos;
3919 for (unsigned int i = 0; i < hops_array_length; i++)
3922 while (GNUNET_NO == ok)
3925 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3927 for (unsigned int j = 0; j < i; j++)
3928 if (choices[i] == choices[j])
3937 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3940 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3942 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3943 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3944 .rel_value_us == 0))
3945 continue; /* pos unconfirmed and confirmed required */
3946 for (unsigned int i = 0; i < hops_array_length; i++)
3947 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3948 hops_array[dv_count++] = pos;
3956 * There is a message at the head of the pending messages for @a vl
3957 * which may be ready for transmission. Check if a queue is ready to
3960 * This function must (1) check for flow control to ensure that we can
3961 * right now send to @a vl, (2) check that the pending message in the
3962 * queue is actually eligible, (3) determine if any applicable queue
3963 * (direct neighbour or DVH path) is ready to accept messages, and
3964 * (4) prioritize based on the preferences associated with the
3969 * @param vl virtual link where we should check for transmission
3972 check_vl_transmission (struct VirtualLink *vl)
3974 struct Neighbour *n = vl->n;
3975 struct DistanceVector *dv = vl->dv;
3976 struct GNUNET_TIME_Absolute now;
3979 /* FIXME-FC: need to implement virtual link flow control! */
3981 /* Check that we have an eligible pending message!
3982 (cheaper than having #transmit_on_queue() find out!) */
3984 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
3988 continue; /* not eligible, is in a queue! */
3992 if (GNUNET_NO == elig)
3995 /* Notify queues at direct neighbours that we are interested */
3996 now = GNUNET_TIME_absolute_get ();
3999 for (struct Queue *queue = n->queue_head; NULL != queue;
4000 queue = queue->next_neighbour)
4001 if ((GNUNET_YES == queue->idle) &&
4002 (queue->validated_until.abs_value_us > now.abs_value_us))
4003 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4005 /* Notify queues via DV that we are interested */
4008 /* Do DV with lower scheduler priority, which effectively means that
4009 IF a neighbour exists and is available, we prefer it. */
4010 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4013 struct Neighbour *nh = pos->next_hop;
4015 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
4016 continue; /* skip this one: path not validated */
4017 for (struct Queue *queue = nh->queue_head; NULL != queue;
4018 queue = queue->next_neighbour)
4019 if ((GNUNET_YES == queue->idle) &&
4020 (queue->validated_until.abs_value_us > now.abs_value_us))
4021 schedule_transmit_on_queue (queue,
4022 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
4029 * Client asked for transmission to a peer. Process the request.
4031 * @param cls the client
4032 * @param obm the send message that was sent
4035 handle_client_send (void *cls, const struct OutboundMessage *obm)
4037 struct TransportClient *tc = cls;
4038 struct PendingMessage *pm;
4039 const struct GNUNET_MessageHeader *obmm;
4041 struct VirtualLink *vl;
4042 enum GNUNET_MQ_PriorityPreferences pp;
4044 GNUNET_assert (CT_CORE == tc->type);
4045 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4046 bytes_msg = ntohs (obmm->size);
4047 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
4048 vl = lookup_virtual_link (&obm->peer);
4051 /* Failure: don't have this peer as a neighbour (anymore).
4052 Might have gone down asynchronously, so this is NOT
4053 a protocol violation by CORE. Still count the event,
4054 as this should be rare. */
4055 GNUNET_SERVICE_client_continue (tc->client);
4056 GNUNET_STATISTICS_update (GST_stats,
4057 "# messages dropped (neighbour unknown)",
4063 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
4064 pm->logging_uuid = logging_uuid_gen++;
4068 pm->bytes_msg = bytes_msg;
4069 memcpy (&pm[1], obmm, bytes_msg);
4070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4071 "Sending %u bytes as <%llu> to %s\n",
4074 GNUNET_i2s (&obm->peer));
4075 GNUNET_CONTAINER_MDLL_insert (client,
4076 tc->details.core.pending_msg_head,
4077 tc->details.core.pending_msg_tail,
4079 GNUNET_CONTAINER_MDLL_insert (vl,
4080 vl->pending_msg_head,
4081 vl->pending_msg_tail,
4083 check_vl_transmission (vl);
4088 * Communicator started. Test message is well-formed.
4090 * @param cls the client
4091 * @param cam the send message that was sent
4094 check_communicator_available (
4096 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4098 struct TransportClient *tc = cls;
4101 if (CT_NONE != tc->type)
4104 return GNUNET_SYSERR;
4106 tc->type = CT_COMMUNICATOR;
4107 size = ntohs (cam->header.size) - sizeof (*cam);
4109 return GNUNET_OK; /* receive-only communicator */
4110 GNUNET_MQ_check_zero_termination (cam);
4116 * Send ACK to communicator (if requested) and free @a cmc.
4118 * @param cmc context for which we are done handling the message
4121 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4123 if (0 != ntohl (cmc->im.fc_on))
4125 /* send ACK when done to communicator for flow control! */
4126 struct GNUNET_MQ_Envelope *env;
4127 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4129 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4130 ack->reserved = htonl (0);
4131 ack->fc_id = cmc->im.fc_id;
4132 ack->sender = cmc->im.sender;
4133 GNUNET_MQ_send (cmc->tc->mq, env);
4135 GNUNET_SERVICE_client_continue (cmc->tc->client);
4141 * Client confirms that it is done handling message(s) to a particular
4142 * peer. We may now provide more messages to CORE for this peer.
4144 * Notifies the respective queues that more messages can now be received.
4146 * @param cls the client
4147 * @param rom the message that was sent
4150 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4152 struct TransportClient *tc = cls;
4153 struct VirtualLink *vl;
4155 struct CommunicatorMessageContext *cmc;
4157 if (CT_CORE != tc->type)
4160 GNUNET_SERVICE_client_drop (tc->client);
4163 vl = lookup_virtual_link (&rom->peer);
4166 GNUNET_STATISTICS_update (GST_stats,
4167 "# RECV_OK dropped: virtual link unknown",
4170 GNUNET_SERVICE_client_continue (tc->client);
4173 delta = ntohl (rom->increase_window_delta);
4174 vl->core_recv_window += delta;
4175 if (vl->core_recv_window <= 0)
4177 /* resume communicators */
4178 while (NULL != (cmc = vl->cmc_tail))
4180 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4181 finish_cmc_handling (cmc);
4187 * Communicator started. Process the request.
4189 * @param cls the client
4190 * @param cam the send message that was sent
4193 handle_communicator_available (
4195 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4197 struct TransportClient *tc = cls;
4200 size = ntohs (cam->header.size) - sizeof (*cam);
4203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4204 "Receive-only communicator connected\n");
4205 return; /* receive-only communicator */
4207 tc->details.communicator.address_prefix =
4208 GNUNET_strdup ((const char *) &cam[1]);
4209 tc->details.communicator.cc =
4210 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4212 "Communicator with prefix `%s' connected\n",
4213 tc->details.communicator.address_prefix);
4214 GNUNET_SERVICE_client_continue (tc->client);
4219 * Communicator requests backchannel transmission. Check the request.
4221 * @param cls the client
4222 * @param cb the send message that was sent
4223 * @return #GNUNET_OK if message is well-formed
4226 check_communicator_backchannel (
4228 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4230 const struct GNUNET_MessageHeader *inbox;
4236 msize = ntohs (cb->header.size) - sizeof (*cb);
4237 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4238 isize = ntohs (inbox->size);
4242 return GNUNET_SYSERR;
4244 is = (const char *) inbox;
4247 GNUNET_assert (0 < msize);
4248 if ('\0' != is[msize - 1])
4251 return GNUNET_SYSERR;
4258 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4261 * @param dv[in,out] virtual link to update ephemeral for
4264 update_ephemeral (struct DistanceVector *dv)
4266 struct EphemeralConfirmationPS ec;
4269 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4271 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4272 dv->ephemeral_validity =
4273 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4274 GNUNET_assert (GNUNET_OK ==
4275 GNUNET_CRYPTO_ecdhe_key_create2 (&dv->private_key));
4276 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4277 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4278 ec.purpose.size = htonl (sizeof (ec));
4279 ec.target = dv->target;
4280 ec.ephemeral_key = dv->ephemeral_key;
4281 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4288 * Send the message @a payload on @a queue.
4290 * @param queue the queue to use for transmission
4291 * @param pm pending message to update once transmission is done, may be NULL!
4292 * @param payload the payload to send (encapsulated in a
4293 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4294 * @param payload_size number of bytes in @a payload
4297 queue_send_msg (struct Queue *queue,
4298 struct PendingMessage *pm,
4299 const void *payload,
4300 size_t payload_size)
4302 struct Neighbour *n = queue->neighbour;
4303 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4304 struct GNUNET_MQ_Envelope *env;
4306 queue->idle = GNUNET_NO;
4308 GNUNET_ERROR_TYPE_DEBUG,
4309 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4310 (unsigned int) payload_size,
4312 (unsigned long long) queue->qid,
4313 GNUNET_i2s (&queue->neighbour->pid));
4314 env = GNUNET_MQ_msg_extra (smt,
4316 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4317 smt->qid = queue->qid;
4318 smt->mid = queue->mid_gen;
4319 smt->receiver = n->pid;
4320 memcpy (&smt[1], payload, payload_size);
4322 /* Pass the env to the communicator of queue for transmission. */
4323 struct QueueEntry *qe;
4325 qe = GNUNET_new (struct QueueEntry);
4326 qe->mid = queue->mid_gen++;
4331 GNUNET_assert (NULL == pm->qe);
4334 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4335 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4336 queue->queue_length++;
4337 queue->tc->details.communicator.total_queue_length++;
4338 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4339 queue->tc->details.communicator.total_queue_length)
4340 queue->idle = GNUNET_NO;
4341 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4342 queue->idle = GNUNET_NO;
4343 GNUNET_MQ_send (queue->tc->mq, env);
4349 * Pick a queue of @a n under constraints @a options and schedule
4350 * transmission of @a hdr.
4352 * @param n neighbour to send to
4353 * @param hdr message to send as payload
4354 * @param options whether queues must be confirmed or not,
4355 * and whether we may pick multiple (2) queues
4358 route_via_neighbour (const struct Neighbour *n,
4359 const struct GNUNET_MessageHeader *hdr,
4360 enum RouteMessageOptions options)
4362 struct GNUNET_TIME_Absolute now;
4363 unsigned int candidates;
4367 /* Pick one or two 'random' queues from n (under constraints of options) */
4368 now = GNUNET_TIME_absolute_get ();
4369 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4370 weight in the future; weight could be assigned by observed
4371 bandwidth (note: not sure if we should do this for this type
4372 of control traffic though). */
4374 for (struct Queue *pos = n->queue_head; NULL != pos;
4375 pos = pos->next_neighbour)
4377 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4378 (pos->validated_until.abs_value_us > now.abs_value_us))
4381 if (0 == candidates)
4383 /* This can happen rarely if the last confirmed queue timed
4384 out just as we were beginning to process this message. */
4385 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4386 "Could not route message of type %u to %s: no valid queue\n",
4388 GNUNET_i2s (&n->pid));
4389 GNUNET_STATISTICS_update (GST_stats,
4390 "# route selection failed (all no valid queue)",
4396 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4397 if (0 == (options & RMO_REDUNDANT))
4398 sel2 = candidates; /* picks none! */
4400 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4402 for (struct Queue *pos = n->queue_head; NULL != pos;
4403 pos = pos->next_neighbour)
4405 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4406 (pos->validated_until.abs_value_us > now.abs_value_us))
4408 if ((sel1 == candidates) || (sel2 == candidates))
4410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4411 "Routing message of type %u to %s using %s (#%u)\n",
4413 GNUNET_i2s (&n->pid),
4415 (sel1 == candidates) ? 1 : 2);
4416 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4425 * Structure of the key material used to encrypt backchannel messages.
4430 * State of our block cipher.
4432 gcry_cipher_hd_t cipher;
4435 * Actual key material.
4441 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4443 struct GNUNET_CRYPTO_AuthKey hmac_key;
4446 * Symmetric key to use for encryption.
4448 char aes_key[256 / 8];
4451 * Counter value to use during setup.
4453 char aes_ctr[128 / 8];
4460 * Given the key material in @a km and the initialization vector
4461 * @a iv, setup the key material for the backchannel in @a key.
4463 * @param km raw master secret
4464 * @param iv initialization vector
4465 * @param key[out] symmetric cipher and HMAC state to generate
4468 dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4469 const struct GNUNET_ShortHashCode *iv,
4470 struct DVKeyState *key)
4472 /* must match #dh_key_derive_eph_pub */
4473 GNUNET_assert (GNUNET_YES ==
4474 GNUNET_CRYPTO_kdf (&key->material,
4475 sizeof (key->material),
4476 "transport-backchannel-key",
4477 strlen ("transport-backchannel-key"),
4482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4483 "Deriving backchannel key based on KM %s and IV %s\n",
4486 gcry_cipher_open (&key->cipher,
4487 GCRY_CIPHER_AES256 /* low level: go for speed */,
4488 GCRY_CIPHER_MODE_CTR,
4490 gcry_cipher_setkey (key->cipher,
4491 &key->material.aes_key,
4492 sizeof (key->material.aes_key));
4493 gcry_cipher_setctr (key->cipher,
4494 &key->material.aes_ctr,
4495 sizeof (key->material.aes_ctr));
4500 * Derive backchannel encryption key material from @a priv_ephemeral
4501 * and @a target and @a iv.
4503 * @param priv_ephemeral ephemeral private key to use
4504 * @param target the target peer to encrypt to
4505 * @param iv unique IV to use
4506 * @param key[out] set to the key material
4509 dh_key_derive_eph_pid (
4510 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4511 const struct GNUNET_PeerIdentity *target,
4512 const struct GNUNET_ShortHashCode *iv,
4513 struct DVKeyState *key)
4515 struct GNUNET_HashCode km;
4517 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4518 &target->public_key,
4520 dv_setup_key_state_from_km (&km, iv, key);
4525 * Derive backchannel encryption key material from #GST_my_private_key
4526 * and @a pub_ephemeral and @a iv.
4528 * @param priv_ephemeral ephemeral private key to use
4529 * @param target the target peer to encrypt to
4530 * @param iv unique IV to use
4531 * @param key[out] set to the key material
4534 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4535 const struct GNUNET_ShortHashCode *iv,
4536 struct DVKeyState *key)
4538 struct GNUNET_HashCode km;
4540 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4543 dv_setup_key_state_from_km (&km, iv, key);
4548 * Do HMAC calculation for backchannel messages over @a data using key
4549 * material from @a key.
4551 * @param key key material (from DH)
4552 * @param hmac[out] set to the HMAC
4553 * @param data data to perform HMAC calculation over
4554 * @param data_size number of bytes in @a data
4557 dv_hmac (const struct DVKeyState *key,
4558 struct GNUNET_HashCode *hmac,
4562 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4567 * Perform backchannel encryption using symmetric secret in @a key
4568 * to encrypt data from @a in to @a dst.
4570 * @param key[in,out] key material to use
4571 * @param dst where to write the result
4572 * @param in input data to encrypt (plaintext)
4573 * @param in_size number of bytes of input in @a in and available at @a dst
4576 dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4579 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4584 * Perform backchannel encryption using symmetric secret in @a key
4585 * to encrypt data from @a in to @a dst.
4587 * @param key[in,out] key material to use
4588 * @param ciph cipher text to decrypt
4589 * @param out[out] output data to generate (plaintext)
4590 * @param out_size number of bytes of input in @a ciph and available in @a out
4593 dv_decrypt (struct DVKeyState *key,
4599 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4604 * Clean up key material in @a key.
4606 * @param key key material to clean up (memory must not be free'd!)
4609 dv_key_clean (struct DVKeyState *key)
4611 gcry_cipher_close (key->cipher);
4612 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4617 * Function to call to further operate on the now DV encapsulated
4618 * message @a hdr, forwarding it via @a next_hop under respect of
4621 * @param cls closure
4622 * @param next_hop next hop of the DV path
4623 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4624 * @param options options of the original message
4626 typedef void (*DVMessageHandler) (void *cls,
4627 struct Neighbour *next_hop,
4628 const struct GNUNET_MessageHeader *hdr,
4629 enum RouteMessageOptions options);
4632 * Pick a path of @a dv under constraints @a options and schedule
4633 * transmission of @a hdr.
4635 * @param target neighbour to ultimately send to
4636 * @param num_dvhs length of the @a dvhs array
4637 * @param dvhs array of hops to send the message to
4638 * @param hdr message to send as payload
4639 * @param use function to call with the encapsulated message
4640 * @param use_cls closure for @a use
4641 * @param options whether path must be confirmed or not, to be passed to @a use
4644 encapsulate_for_dv (struct DistanceVector *dv,
4645 unsigned int num_dvhs,
4646 struct DistanceVectorHop **dvhs,
4647 const struct GNUNET_MessageHeader *hdr,
4648 DVMessageHandler use,
4650 enum RouteMessageOptions options)
4652 struct TransportDVBoxMessage box_hdr;
4653 struct TransportDVBoxPayloadP payload_hdr;
4654 uint16_t enc_body_size = ntohs (hdr->size);
4655 char enc[sizeof (struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4656 struct TransportDVBoxPayloadP *enc_payload_hdr =
4657 (struct TransportDVBoxPayloadP *) enc;
4658 struct DVKeyState key;
4660 /* Encrypt payload */
4661 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4662 box_hdr.total_hops = htons (0);
4663 update_ephemeral (dv);
4664 box_hdr.ephemeral_key = dv->ephemeral_key;
4665 payload_hdr.sender_sig = dv->sender_sig;
4666 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4668 sizeof (box_hdr.iv));
4669 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, &key);
4670 payload_hdr.sender = GST_my_identity;
4671 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4672 dv_encrypt (&key, &payload_hdr, enc_payload_hdr, sizeof (payload_hdr));
4675 &enc[sizeof (struct TransportDVBoxPayloadP)],
4677 dv_hmac (&key, &box_hdr.hmac, enc, sizeof (enc));
4678 dv_key_clean (&key);
4680 /* For each selected path, take the pre-computed header and body
4681 and add the path in the middle of the message; then send it. */
4682 for (unsigned int i = 0; i < num_dvhs; i++)
4684 struct DistanceVectorHop *dvh = dvhs[i];
4685 unsigned int num_hops = dvh->distance + 1;
4686 char buf[sizeof (struct TransportDVBoxMessage) +
4687 sizeof (struct GNUNET_PeerIdentity) * num_hops +
4688 sizeof (struct TransportDVBoxPayloadP) +
4689 enc_body_size] GNUNET_ALIGN;
4690 struct GNUNET_PeerIdentity *dhops;
4692 box_hdr.header.size = htons (sizeof (buf));
4693 box_hdr.num_hops = htons (num_hops);
4694 memcpy (buf, &box_hdr, sizeof (box_hdr));
4695 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof (box_hdr)];
4698 dvh->distance * sizeof (struct GNUNET_PeerIdentity));
4699 dhops[dvh->distance] = dv->target;
4700 if (GNUNET_EXTRA_LOGGING > 0)
4704 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4705 for (unsigned int i = 0; i <= num_hops; i++)
4709 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
4713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4714 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4716 GNUNET_i2s (&dv->target),
4723 memcpy (&dhops[num_hops], enc, sizeof (enc));
4726 (const struct GNUNET_MessageHeader *) buf,
4733 * Wrapper around #route_via_neighbour() that matches the
4734 * #DVMessageHandler structure.
4737 * @param next_hop where to send next
4738 * @param hdr header of the message to send
4739 * @param options message options for queue selection
4742 send_dv_to_neighbour (void *cls,
4743 struct Neighbour *next_hop,
4744 const struct GNUNET_MessageHeader *hdr,
4745 enum RouteMessageOptions options)
4748 route_via_neighbour (next_hop, hdr, options);
4753 * We need to transmit @a hdr to @a target. If necessary, this may
4754 * involve DV routing.
4756 * @param target peer to receive @a hdr
4757 * @param hdr header of the message to route and #GNUNET_free()
4758 * @param options which transmission channels are allowed
4761 route_message (const struct GNUNET_PeerIdentity *target,
4762 const struct GNUNET_MessageHeader *hdr,
4763 enum RouteMessageOptions options)
4765 struct VirtualLink *vl;
4766 struct Neighbour *n;
4767 struct DistanceVector *dv;
4769 vl = lookup_virtual_link (target);
4771 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4772 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4774 /* if confirmed is required, and we do not have anything
4775 confirmed, drop respective options */
4777 n = lookup_neighbour (target);
4778 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4779 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4781 if ((NULL == n) && (NULL == dv))
4783 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4784 "Cannot route message of type %u to %s: no route\n",
4786 GNUNET_i2s (target));
4787 GNUNET_STATISTICS_update (GST_stats,
4788 "# Messages dropped in routing: no acceptable method",
4793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4794 "Routing message of type %u to %s with options %X\n",
4796 GNUNET_i2s (target),
4797 (unsigned int) options);
4798 /* If both dv and n are possible and we must choose:
4799 flip a coin for the choice between the two; for now 50/50 */
4800 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4802 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4807 if ((NULL != n) && (NULL != dv))
4808 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4809 enough for redunancy, so clear the flag. */
4812 route_via_neighbour (n, hdr, options);
4816 struct DistanceVectorHop *hops[2];
4819 res = pick_random_dv_hops (dv,
4822 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4825 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4826 "Failed to route message, could not determine DV path\n");
4829 encapsulate_for_dv (dv,
4833 &send_dv_to_neighbour,
4835 options & (~RMO_REDUNDANT));
4841 * Communicator requests backchannel transmission. Process the request.
4842 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
4843 * (which for now has exactly the same format, only a different message type)
4844 * and passes it on for routing.
4846 * @param cls the client
4847 * @param cb the send message that was sent
4850 handle_communicator_backchannel (
4852 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4854 struct TransportClient *tc = cls;
4855 const struct GNUNET_MessageHeader *inbox =
4856 (const struct GNUNET_MessageHeader *) &cb[1];
4857 uint16_t isize = ntohs (inbox->size);
4858 const char *is = ((const char *) &cb[1]) + isize;
4861 sizeof (struct TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
4862 struct TransportBackchannelEncapsulationMessage *be =
4863 (struct TransportBackchannelEncapsulationMessage *) mbuf;
4865 /* 0-termination of 'is' was checked already in
4866 #check_communicator_backchannel() */
4867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4868 "Preparing backchannel transmission to %s:%s of type %u\n",
4869 GNUNET_i2s (&cb->pid),
4871 ntohs (inbox->size));
4872 /* encapsulate and encrypt message */
4874 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4875 be->header.size = htons (sizeof (mbuf));
4876 memcpy (&be[1], inbox, isize);
4877 memcpy (&mbuf[sizeof (struct TransportBackchannelEncapsulationMessage) +
4881 route_message (&cb->pid, &be->header, RMO_DV_ALLOWED);
4882 GNUNET_SERVICE_client_continue (tc->client);
4887 * Address of our peer added. Test message is well-formed.
4889 * @param cls the client
4890 * @param aam the send message that was sent
4891 * @return #GNUNET_OK if message is well-formed
4894 check_add_address (void *cls,
4895 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4897 struct TransportClient *tc = cls;
4899 if (CT_COMMUNICATOR != tc->type)
4902 return GNUNET_SYSERR;
4904 GNUNET_MQ_check_zero_termination (aam);
4910 * Ask peerstore to store our address.
4912 * @param cls an `struct AddressListEntry *`
4915 store_pi (void *cls);
4919 * Function called when peerstore is done storing our address.
4921 * @param cls a `struct AddressListEntry`
4922 * @param success #GNUNET_YES if peerstore was successful
4925 peerstore_store_own_cb (void *cls, int success)
4927 struct AddressListEntry *ale = cls;
4930 if (GNUNET_YES != success)
4931 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4932 "Failed to store our own address `%s' in peerstore!\n",
4935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4936 "Successfully stored our own address `%s' in peerstore!\n",
4938 /* refresh period is 1/4 of expiration time, that should be plenty
4939 without being excessive. */
4941 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4949 * Ask peerstore to store our address.
4951 * @param cls an `struct AddressListEntry *`
4954 store_pi (void *cls)
4956 struct AddressListEntry *ale = cls;
4959 struct GNUNET_TIME_Absolute expiration;
4962 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4964 "Storing our address `%s' in peerstore until %s!\n",
4966 GNUNET_STRINGS_absolute_time_to_string (expiration));
4967 GNUNET_HELLO_sign_address (ale->address,
4973 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4976 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4980 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4981 &peerstore_store_own_cb,
4984 if (NULL == ale->sc)
4986 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4987 "Failed to store our address `%s' with peerstore\n",
4990 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4996 * Address of our peer added. Process the request.
4998 * @param cls the client
4999 * @param aam the send message that was sent
5002 handle_add_address (void *cls,
5003 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5005 struct TransportClient *tc = cls;
5006 struct AddressListEntry *ale;
5009 /* 0-termination of &aam[1] was checked in #check_add_address */
5010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5011 "Communicator added address `%s'!\n",
5012 (const char *) &aam[1]);
5013 slen = ntohs (aam->header.size) - sizeof (*aam);
5014 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
5016 ale->address = (const char *) &ale[1];
5017 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5018 ale->aid = aam->aid;
5019 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5020 memcpy (&ale[1], &aam[1], slen);
5021 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5022 tc->details.communicator.addr_tail,
5024 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5025 GNUNET_SERVICE_client_continue (tc->client);
5030 * Address of our peer deleted. Process the request.
5032 * @param cls the client
5033 * @param dam the send message that was sent
5036 handle_del_address (void *cls,
5037 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5039 struct TransportClient *tc = cls;
5041 if (CT_COMMUNICATOR != tc->type)
5044 GNUNET_SERVICE_client_drop (tc->client);
5047 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5051 if (dam->aid != ale->aid)
5053 GNUNET_assert (ale->tc == tc);
5054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5055 "Communicator deleted address `%s'!\n",
5057 free_address_list_entry (ale);
5058 GNUNET_SERVICE_client_continue (tc->client);
5061 GNUNET_SERVICE_client_drop (tc->client);
5066 * Given an inbound message @a msg from a communicator @a cmc,
5067 * demultiplex it based on the type calling the right handler.
5069 * @param cmc context for demultiplexing
5070 * @param msg message to demultiplex
5073 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5074 const struct GNUNET_MessageHeader *msg);
5078 * Function called when we are done giving a message of a certain
5079 * size to CORE and should thus decrement the number of bytes of
5080 * RAM reserved for that peer's MQ.
5082 * @param cls a `struct CoreSentContext`
5085 core_env_sent_cb (void *cls)
5087 struct CoreSentContext *ctx = cls;
5088 struct VirtualLink *vl = ctx->vl;
5092 /* lost the link in the meantime, ignore */
5096 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5097 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5098 vl->incoming_fc_window_size_ram -= ctx->size;
5099 vl->incoming_fc_window_size_used += ctx->isize;
5106 * Communicator gave us an unencapsulated message to pass as-is to
5107 * CORE. Process the request.
5109 * @param cls a `struct CommunicatorMessageContext` (must call
5110 * #finish_cmc_handling() when done)
5111 * @param mh the message that was received
5114 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5116 struct CommunicatorMessageContext *cmc = cls;
5117 struct VirtualLink *vl;
5118 uint16_t size = ntohs (mh->size);
5121 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
5122 (size < sizeof (struct GNUNET_MessageHeader)))
5124 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5127 finish_cmc_handling (cmc);
5128 GNUNET_SERVICE_client_drop (client);
5131 vl = lookup_virtual_link (&cmc->im.sender);
5134 /* FIXME: sender is giving us messages for CORE but we don't have
5135 the link up yet! I *suspect* this can happen right now (i.e.
5136 sender has verified us, but we didn't verify sender), but if
5137 we pass this on, CORE would be confused (link down, messages
5138 arrive). We should investigate more if this happens often,
5139 or in a persistent manner, and possibly do "something" about
5140 it. Thus logging as error for now. */
5141 GNUNET_break_op (0);
5142 GNUNET_STATISTICS_update (GST_stats,
5143 "# CORE messages droped (virtual link still down)",
5147 finish_cmc_handling (cmc);
5150 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5152 GNUNET_STATISTICS_update (GST_stats,
5153 "# CORE messages droped (FC arithmetic overflow)",
5157 finish_cmc_handling (cmc);
5160 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5162 GNUNET_STATISTICS_update (GST_stats,
5163 "# CORE messages droped (FC window overflow)",
5166 finish_cmc_handling (cmc);
5170 /* Forward to all CORE clients */
5171 have_core = GNUNET_NO;
5172 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5174 struct GNUNET_MQ_Envelope *env;
5175 struct InboundMessage *im;
5176 struct CoreSentContext *ctx;
5178 if (CT_CORE != tc->type)
5180 vl->incoming_fc_window_size_ram += size;
5181 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5182 ctx = GNUNET_new (struct CoreSentContext);
5185 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5186 have_core = GNUNET_YES;
5187 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5188 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5189 im->peer = cmc->im.sender;
5190 memcpy (&im[1], mh, size);
5191 GNUNET_MQ_send (tc->mq, env);
5192 vl->core_recv_window--;
5194 if (GNUNET_NO == have_core)
5196 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5197 "Dropped message to CORE: no CORE client connected!\n");
5198 /* Nevertheless, count window as used, as it is from the
5199 perspective of the other peer! */
5200 vl->incoming_fc_window_size_used += size;
5202 finish_cmc_handling (cmc);
5205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5206 "Delivered message from %s of type %u to CORE\n",
5207 GNUNET_i2s (&cmc->im.sender),
5209 if (vl->core_recv_window > 0)
5211 finish_cmc_handling (cmc);
5214 /* Wait with calling #finish_cmc_handling(cmc) until the message
5215 was processed by CORE MQs (for CORE flow control)! */
5216 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5221 * Communicator gave us a fragment box. Check the message.
5223 * @param cls a `struct CommunicatorMessageContext`
5224 * @param fb the send message that was sent
5225 * @return #GNUNET_YES if message is well-formed
5228 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5230 uint16_t size = ntohs (fb->header.size);
5231 uint16_t bsize = size - sizeof (*fb);
5236 GNUNET_break_op (0);
5237 return GNUNET_SYSERR;
5239 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5241 GNUNET_break_op (0);
5242 return GNUNET_SYSERR;
5244 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5246 GNUNET_break_op (0);
5247 return GNUNET_SYSERR;
5254 * Clean up an idle cummulative acknowledgement data structure.
5256 * @param cls a `struct AcknowledgementCummulator *`
5259 destroy_ack_cummulator (void *cls)
5261 struct AcknowledgementCummulator *ac = cls;
5264 GNUNET_assert (0 == ac->num_acks);
5267 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5273 * Do the transmission of a cummulative acknowledgement now.
5275 * @param cls a `struct AcknowledgementCummulator *`
5278 transmit_cummulative_ack_cb (void *cls)
5280 struct AcknowledgementCummulator *ac = cls;
5281 char buf[sizeof (struct TransportReliabilityAckMessage) +
5283 sizeof (struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5284 struct TransportReliabilityAckMessage *ack =
5285 (struct TransportReliabilityAckMessage *) buf;
5286 struct TransportCummulativeAckPayloadP *ap;
5289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5290 "Sending ACK with %u components to %s\n",
5292 GNUNET_i2s (&ac->target));
5293 GNUNET_assert (0 < ac->ack_counter);
5294 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5296 htons (sizeof (*ack) +
5297 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
5298 ack->ack_counter = htonl (ac->ack_counter++);
5299 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5300 for (unsigned int i = 0; i < ac->ack_counter; i++)
5302 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5303 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5304 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5306 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
5308 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5309 &destroy_ack_cummulator,
5315 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5316 * transmission by at most @a ack_delay.
5318 * @param pid target peer
5319 * @param ack_uuid UUID to ack
5320 * @param max_delay how long can the ACK wait
5323 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5324 const struct AcknowledgementUUIDP *ack_uuid,
5325 struct GNUNET_TIME_Absolute max_delay)
5327 struct AcknowledgementCummulator *ac;
5329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5330 "Scheduling ACK %s for transmission to %s\n",
5331 GNUNET_sh2s (&ack_uuid->value),
5333 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5336 ac = GNUNET_new (struct AcknowledgementCummulator);
5338 ac->min_transmission_time = max_delay;
5339 GNUNET_assert (GNUNET_YES ==
5340 GNUNET_CONTAINER_multipeermap_put (
5344 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5348 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5350 /* must run immediately, ack buffer full! */
5351 GNUNET_SCHEDULER_cancel (ac->task);
5352 transmit_cummulative_ack_cb (ac);
5354 GNUNET_SCHEDULER_cancel (ac->task);
5355 ac->min_transmission_time =
5356 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5358 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5359 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5360 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5362 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5363 &transmit_cummulative_ack_cb,
5369 * Closure for #find_by_message_uuid.
5371 struct FindByMessageUuidContext
5376 struct MessageUUIDP message_uuid;
5379 * Set to the reassembly context if found.
5381 struct ReassemblyContext *rc;
5386 * Iterator called to find a reassembly context by the message UUID in the
5389 * @param cls a `struct FindByMessageUuidContext`
5390 * @param key a key (unused)
5391 * @param value a `struct ReassemblyContext`
5392 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5395 find_by_message_uuid (void *cls, uint32_t key, void *value)
5397 struct FindByMessageUuidContext *fc = cls;
5398 struct ReassemblyContext *rc = value;
5401 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5411 * Communicator gave us a fragment. Process the request.
5413 * @param cls a `struct CommunicatorMessageContext` (must call
5414 * #finish_cmc_handling() when done)
5415 * @param fb the message that was received
5418 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5420 struct CommunicatorMessageContext *cmc = cls;
5421 struct Neighbour *n;
5422 struct ReassemblyContext *rc;
5423 const struct GNUNET_MessageHeader *msg;
5428 struct GNUNET_TIME_Relative cdelay;
5429 struct FindByMessageUuidContext fc;
5431 n = lookup_neighbour (&cmc->im.sender);
5434 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5437 finish_cmc_handling (cmc);
5438 GNUNET_SERVICE_client_drop (client);
5441 if (NULL == n->reassembly_map)
5443 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5444 n->reassembly_heap =
5445 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5446 n->reassembly_timeout_task =
5447 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5448 &reassembly_cleanup_task,
5451 msize = ntohs (fb->msg_size);
5452 fc.message_uuid = fb->msg_uuid;
5454 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5456 &find_by_message_uuid,
5458 if (NULL == (rc = fc.rc))
5460 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5461 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5462 rc->msg_uuid = fb->msg_uuid;
5464 rc->msg_size = msize;
5465 rc->reassembly_timeout =
5466 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5467 rc->last_frag = GNUNET_TIME_absolute_get ();
5468 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5470 rc->reassembly_timeout.abs_value_us);
5471 GNUNET_assert (GNUNET_OK ==
5472 GNUNET_CONTAINER_multihashmap32_put (
5476 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5477 target = (char *) &rc[1];
5478 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5479 rc->msg_missing = rc->msg_size;
5480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5481 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5482 ntohs (fb->frag_off),
5484 GNUNET_i2s (&cmc->im.sender),
5485 (unsigned int) fb->msg_uuid.uuid);
5489 target = (char *) &rc[1];
5490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5491 "Received fragment at offset %u/%u from %s for message %u\n",
5492 ntohs (fb->frag_off),
5494 GNUNET_i2s (&cmc->im.sender),
5495 (unsigned int) fb->msg_uuid.uuid);
5497 if (msize != rc->msg_size)
5500 finish_cmc_handling (cmc);
5505 fsize = ntohs (fb->header.size) - sizeof (*fb);
5509 finish_cmc_handling (cmc);
5512 frag_off = ntohs (fb->frag_off);
5513 memcpy (&target[frag_off], &fb[1], fsize);
5514 /* update bitfield and msg_missing */
5515 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5517 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5519 rc->bitfield[i / 8] |= (1 << (i % 8));
5524 /* Compute cummulative ACK */
5525 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5526 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5527 if (0 == rc->msg_missing)
5528 cdelay = GNUNET_TIME_UNIT_ZERO;
5529 cummulative_ack (&cmc->im.sender,
5531 GNUNET_TIME_relative_to_absolute (cdelay));
5532 rc->last_frag = GNUNET_TIME_absolute_get ();
5533 /* is reassembly complete? */
5534 if (0 != rc->msg_missing)
5536 finish_cmc_handling (cmc);
5539 /* reassembly is complete, verify result */
5540 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5541 if (ntohs (msg->size) != rc->msg_size)
5544 free_reassembly_context (rc);
5545 finish_cmc_handling (cmc);
5548 /* successful reassembly */
5549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5550 "Fragment reassembly complete for message %u\n",
5551 (unsigned int) fb->msg_uuid.uuid);
5552 /* FIXME: check that the resulting msg is NOT a
5553 DV Box or Reliability Box, as that is NOT allowed! */
5554 demultiplex_with_cmc (cmc, msg);
5555 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5556 en-route and we forget that we finished this reassembly immediately!
5557 -> keep around until timeout?
5558 -> shorten timeout based on ACK? */
5559 free_reassembly_context (rc);
5564 * Communicator gave us a reliability box. Check the message.
5566 * @param cls a `struct CommunicatorMessageContext`
5567 * @param rb the send message that was sent
5568 * @return #GNUNET_YES if message is well-formed
5571 check_reliability_box (void *cls,
5572 const struct TransportReliabilityBoxMessage *rb)
5575 GNUNET_MQ_check_boxed_message (rb);
5581 * Communicator gave us a reliability box. Process the request.
5583 * @param cls a `struct CommunicatorMessageContext` (must call
5584 * #finish_cmc_handling() when done)
5585 * @param rb the message that was received
5588 handle_reliability_box (void *cls,
5589 const struct TransportReliabilityBoxMessage *rb)
5591 struct CommunicatorMessageContext *cmc = cls;
5592 const struct GNUNET_MessageHeader *inbox =
5593 (const struct GNUNET_MessageHeader *) &rb[1];
5594 struct GNUNET_TIME_Relative rtt;
5596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5597 "Received reliability box from %s with UUID %s of type %u\n",
5598 GNUNET_i2s (&cmc->im.sender),
5599 GNUNET_sh2s (&rb->ack_uuid.value),
5600 (unsigned int) ntohs (inbox->type));
5601 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5602 do not really have an RTT for the
5603 *incoming* queue (should we have
5604 the sender add it to the rb message?) */
5608 (0 == ntohl (rb->ack_countdown))
5609 ? GNUNET_TIME_UNIT_ZERO_ABS
5610 : GNUNET_TIME_relative_to_absolute (
5611 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5612 /* continue with inner message */
5613 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5614 reliability box (not allowed!) */
5615 demultiplex_with_cmc (cmc, inbox);
5620 * Check if we have advanced to another age since the last time. If
5621 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5624 * @param pd[in,out] data to update
5625 * @param age current age
5628 update_pd_age (struct PerformanceData *pd, unsigned int age)
5632 if (age == pd->last_age)
5633 return; /* nothing to do */
5634 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5635 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5637 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5639 the->bytes_sent = 0;
5640 the->bytes_received = 0;
5647 * Update @a pd based on the latest @a rtt and the number of bytes
5648 * that were confirmed to be successfully transmitted.
5650 * @param pd[in,out] data to update
5651 * @param rtt latest round-trip time
5652 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5655 update_performance_data (struct PerformanceData *pd,
5656 struct GNUNET_TIME_Relative rtt,
5657 uint16_t bytes_transmitted_ok)
5659 uint64_t nval = rtt.rel_value_us;
5660 uint64_t oval = pd->aged_rtt.rel_value_us;
5661 unsigned int age = get_age ();
5662 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5664 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5667 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5668 update_pd_age (pd, age);
5669 the->bytes_received += bytes_transmitted_ok;
5674 * We have successfully transmitted data via @a q, update metrics.
5676 * @param q queue to update
5677 * @param rtt round trip time observed
5678 * @param bytes_transmitted_ok number of bytes successfully transmitted
5681 update_queue_performance (struct Queue *q,
5682 struct GNUNET_TIME_Relative rtt,
5683 uint16_t bytes_transmitted_ok)
5685 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5690 * We have successfully transmitted data via @a dvh, update metrics.
5692 * @param dvh distance vector path data to update
5693 * @param rtt round trip time observed
5694 * @param bytes_transmitted_ok number of bytes successfully transmitted
5697 update_dvh_performance (struct DistanceVectorHop *dvh,
5698 struct GNUNET_TIME_Relative rtt,
5699 uint16_t bytes_transmitted_ok)
5701 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5706 * We have completed transmission of @a pm, remove it from
5707 * the transmission queues (and if it is a fragment, continue
5708 * up the tree as necessary).
5710 * @param pm pending message that was transmitted
5713 completed_pending_message (struct PendingMessage *pm)
5715 struct PendingMessage *pos;
5720 case PMT_RELIABILITY_BOX:
5721 /* Full message sent, we are done */
5722 client_send_response (pm);
5724 case PMT_FRAGMENT_BOX:
5725 /* Fragment sent over reliabile channel */
5726 free_fragment_tree (pm);
5727 pos = pm->frag_parent;
5728 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5730 /* check if subtree is done */
5731 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5735 pos = pm->frag_parent;
5736 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5740 /* Was this the last applicable fragmment? */
5741 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
5742 (pos->frag_off == pos->bytes_msg))
5743 client_send_response (pos);
5750 * The @a pa was acknowledged, process the acknowledgement.
5752 * @param pa the pending acknowledgement that was satisfied
5753 * @param ack_delay artificial delay from cummulative acks created by the
5757 handle_acknowledged (struct PendingAcknowledgement *pa,
5758 struct GNUNET_TIME_Relative ack_delay)
5760 struct GNUNET_TIME_Relative delay;
5762 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5763 if (delay.rel_value_us > ack_delay.rel_value_us)
5764 delay = GNUNET_TIME_UNIT_ZERO;
5766 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5767 if (NULL != pa->queue)
5768 update_queue_performance (pa->queue, delay, pa->message_size);
5769 if (NULL != pa->dvh)
5770 update_dvh_performance (pa->dvh, delay, pa->message_size);
5772 completed_pending_message (pa->pm);
5773 free_pending_acknowledgement (pa);
5778 * Communicator gave us a reliability ack. Check it is well-formed.
5780 * @param cls a `struct CommunicatorMessageContext` (unused)
5781 * @param ra the message that was received
5782 * @return #GNUNET_Ok if @a ra is well-formed
5785 check_reliability_ack (void *cls,
5786 const struct TransportReliabilityAckMessage *ra)
5788 unsigned int n_acks;
5791 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5792 sizeof (struct TransportCummulativeAckPayloadP);
5795 GNUNET_break_op (0);
5796 return GNUNET_SYSERR;
5798 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5799 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5801 GNUNET_break_op (0);
5802 return GNUNET_SYSERR;
5809 * Communicator gave us a reliability ack. Process the request.
5811 * @param cls a `struct CommunicatorMessageContext` (must call
5812 * #finish_cmc_handling() when done)
5813 * @param ra the message that was received
5816 handle_reliability_ack (void *cls,
5817 const struct TransportReliabilityAckMessage *ra)
5819 struct CommunicatorMessageContext *cmc = cls;
5820 const struct TransportCummulativeAckPayloadP *ack;
5821 struct PendingAcknowledgement *pa;
5822 unsigned int n_acks;
5823 uint32_t ack_counter;
5825 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5826 sizeof (struct TransportCummulativeAckPayloadP);
5827 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5828 for (unsigned int i = 0; i < n_acks; i++)
5831 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5834 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5835 "Received ACK from %s with UUID %s which is unknown to us!\n",
5836 GNUNET_i2s (&cmc->im.sender),
5837 GNUNET_sh2s (&ack[i].ack_uuid.value));
5838 GNUNET_STATISTICS_update (
5840 "# FRAGMENT_ACKS dropped, no matching pending message",
5845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5846 "Received ACK from %s with UUID %s\n",
5847 GNUNET_i2s (&cmc->im.sender),
5848 GNUNET_sh2s (&ack[i].ack_uuid.value));
5849 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5852 ack_counter = htonl (ra->ack_counter);
5853 (void) ack_counter; /* silence compiler warning for now */
5854 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5855 // (DV and/or Neighbour?)
5856 finish_cmc_handling (cmc);
5861 * Communicator gave us a backchannel encapsulation. Check the message.
5863 * @param cls a `struct CommunicatorMessageContext`
5864 * @param be the send message that was sent
5865 * @return #GNUNET_YES if message is well-formed
5868 check_backchannel_encapsulation (
5870 const struct TransportBackchannelEncapsulationMessage *be)
5872 uint16_t size = ntohs (be->header.size) - sizeof (*be);
5873 const struct GNUNET_MessageHeader *inbox =
5874 (const struct GNUNET_MessageHeader *) &be[1];
5879 if (ntohs (inbox->size) >= size)
5881 GNUNET_break_op (0);
5882 return GNUNET_SYSERR;
5884 isize = ntohs (inbox->size);
5885 is = ((const char *) inbox) + isize;
5887 if ('\0' != is[size - 1])
5889 GNUNET_break_op (0);
5890 return GNUNET_SYSERR;
5897 * Communicator gave us a backchannel encapsulation. Process the request.
5898 * (We are the destination of the backchannel here.)
5900 * @param cls a `struct CommunicatorMessageContext` (must call
5901 * #finish_cmc_handling() when done)
5902 * @param be the message that was received
5905 handle_backchannel_encapsulation (
5907 const struct TransportBackchannelEncapsulationMessage *be)
5909 struct CommunicatorMessageContext *cmc = cls;
5910 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5911 struct GNUNET_MQ_Envelope *env;
5912 struct TransportClient *tc;
5913 const struct GNUNET_MessageHeader *inbox =
5914 (const struct GNUNET_MessageHeader *) &be[1];
5915 uint16_t isize = ntohs (inbox->size);
5916 const char *target_communicator = ((const char *) inbox) + isize;
5918 /* Find client providing this communicator */
5919 for (tc = clients_head; NULL != tc; tc = tc->next)
5920 if ((CT_COMMUNICATOR == tc->type) &&
5922 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5930 "# Backchannel message dropped: target communicator `%s' unknown",
5931 target_communicator);
5932 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5933 GNUNET_free (stastr);
5936 /* Finally, deliver backchannel message to communicator */
5937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5938 "Delivering backchannel message from %s of type %u to %s\n",
5939 GNUNET_i2s (&cmc->im.sender),
5940 ntohs (inbox->type),
5941 target_communicator);
5942 env = GNUNET_MQ_msg_extra (
5945 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5946 cbi->pid = cmc->im.sender;
5947 memcpy (&cbi[1], inbox, isize);
5948 GNUNET_MQ_send (tc->mq, env);
5953 * Task called when we should check if any of the DV paths
5954 * we have learned to a target are due for garbage collection.
5956 * Collects stale paths, and possibly frees the entire DV
5957 * entry if no paths are left. Otherwise re-schedules itself.
5959 * @param cls a `struct DistanceVector`
5962 path_cleanup_cb (void *cls)
5964 struct DistanceVector *dv = cls;
5965 struct DistanceVectorHop *pos;
5967 dv->timeout_task = NULL;
5968 while (NULL != (pos = dv->dv_head))
5970 GNUNET_assert (dv == pos->dv);
5971 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5973 free_distance_vector_hop (pos);
5981 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5986 * The @a hop is a validated path to the respective target
5987 * peer and we should tell core about it -- and schedule
5988 * a job to revoke the state.
5990 * @param hop a path to some peer that is the reason for activation
5993 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5995 struct DistanceVector *dv = hop->dv;
5996 struct VirtualLink *vl;
5998 vl = lookup_virtual_link (&dv->target);
6001 /* Link was already up, remember dv is also now available and we are done */
6003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6004 "Virtual link to %s could now also use DV!\n",
6005 GNUNET_i2s (&dv->target));
6008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6009 "Creating new virtual link to %s using DV!\n",
6010 GNUNET_i2s (&dv->target));
6011 vl = GNUNET_new (struct VirtualLink);
6012 vl->message_uuid_ctr =
6013 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6014 vl->target = dv->target;
6017 vl->core_recv_window = RECV_WINDOW_SIZE;
6018 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6019 vl->visibility_task =
6020 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6021 GNUNET_break (GNUNET_YES ==
6022 GNUNET_CONTAINER_multipeermap_put (
6026 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6027 /* We lacked a confirmed connection to the target
6028 before, so tell CORE about it (finally!) */
6029 cores_send_connect_info (&dv->target);
6034 * We have learned a @a path through the network to some other peer, add it to
6035 * our DV data structure (returning #GNUNET_YES on success).
6037 * We do not add paths if we have a sufficient number of shorter
6038 * paths to this target already (returning #GNUNET_NO).
6040 * We also do not add problematic paths, like those where we lack the first
6041 * hop in our neighbour list (i.e. due to a topology change) or where some
6042 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6044 * @param path the path we learned, path[0] should be us,
6045 * and then path contains a valid path from us to
6046 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6047 * @param path_len number of entries on the @a path, at least three!
6048 * @param network_latency how long does the message take from us to
6049 * `path[path_len-1]`? set to "forever" if unknown
6050 * @param path_valid_until how long is this path considered validated? Maybe
6052 * @return #GNUNET_YES on success,
6053 * #GNUNET_NO if we have better path(s) to the target
6054 * #GNUNET_SYSERR if the path is useless and/or invalid
6055 * (i.e. path[1] not a direct neighbour
6056 * or path[i+1] is a direct neighbour for i>0)
6059 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6060 unsigned int path_len,
6061 struct GNUNET_TIME_Relative network_latency,
6062 struct GNUNET_TIME_Absolute path_valid_until)
6064 struct DistanceVectorHop *hop;
6065 struct DistanceVector *dv;
6066 struct Neighbour *next_hop;
6067 unsigned int shorter_distance;
6071 /* what a boring path! not allowed! */
6073 return GNUNET_SYSERR;
6075 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6076 next_hop = lookup_neighbour (&path[1]);
6077 if (NULL == next_hop)
6079 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6081 return GNUNET_SYSERR;
6083 for (unsigned int i = 2; i < path_len; i++)
6084 if (NULL != lookup_neighbour (&path[i]))
6086 /* Useless path: we have a direct connection to some hop
6087 in the middle of the path, so this one is not even
6088 terribly useful for redundancy */
6089 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6090 "Path of %u hops useless: directly link to hop %u (%s)\n",
6093 GNUNET_i2s (&path[i]));
6094 GNUNET_STATISTICS_update (GST_stats,
6095 "# Useless DV path ignored: hop is neighbour",
6098 return GNUNET_SYSERR;
6100 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6103 dv = GNUNET_new (struct DistanceVector);
6104 dv->target = path[path_len - 1];
6105 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6108 GNUNET_assert (GNUNET_OK ==
6109 GNUNET_CONTAINER_multipeermap_put (
6113 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6115 /* Check if we have this path already! */
6116 shorter_distance = 0;
6117 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6120 if (pos->distance < path_len - 2)
6122 /* Note that the distances in 'pos' excludes us (path[0]) and
6123 the next_hop (path[1]), so we need to subtract two
6124 and check next_hop explicitly */
6125 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6127 int match = GNUNET_YES;
6129 for (unsigned int i = 0; i < pos->distance; i++)
6131 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6137 if (GNUNET_YES == match)
6139 struct GNUNET_TIME_Relative last_timeout;
6141 /* Re-discovered known path, update timeout */
6142 GNUNET_STATISTICS_update (GST_stats,
6143 "# Known DV path refreshed",
6146 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6148 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6149 pos->path_valid_until =
6150 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6151 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6152 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6154 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6155 activate_core_visible_dv_path (pos);
6156 if (last_timeout.rel_value_us <
6157 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6158 DV_PATH_DISCOVERY_FREQUENCY)
6161 /* Some peer send DV learn messages too often, we are learning
6162 the same path faster than it would be useful; do not forward! */
6163 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6164 "Rediscovered path too quickly, not forwarding further\n");
6167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6168 "Refreshed known path to %s, forwarding further\n",
6169 GNUNET_i2s (&dv->target));
6174 /* Count how many shorter paths we have (incl. direct
6175 neighbours) before simply giving up on this one! */
6176 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6178 /* We have a shorter path already! */
6179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6180 "Have many shorter DV paths %s, not forwarding further\n",
6181 GNUNET_i2s (&dv->target));
6184 /* create new DV path entry */
6185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6186 "Discovered new DV path to %s\n",
6187 GNUNET_i2s (&dv->target));
6188 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6189 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6190 hop->next_hop = next_hop;
6192 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6195 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6196 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6197 hop->path_valid_until = path_valid_until;
6198 hop->distance = path_len - 2;
6199 hop->pd.aged_rtt = network_latency;
6200 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6201 GNUNET_CONTAINER_MDLL_insert (neighbour,
6205 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6206 activate_core_visible_dv_path (hop);
6212 * Communicator gave us a DV learn message. Check the message.
6214 * @param cls a `struct CommunicatorMessageContext`
6215 * @param dvl the send message that was sent
6216 * @return #GNUNET_YES if message is well-formed
6219 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6221 uint16_t size = ntohs (dvl->header.size);
6222 uint16_t num_hops = ntohs (dvl->num_hops);
6223 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6226 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6228 GNUNET_break_op (0);
6229 return GNUNET_SYSERR;
6231 if (num_hops > MAX_DV_HOPS_ALLOWED)
6233 GNUNET_break_op (0);
6234 return GNUNET_SYSERR;
6236 for (unsigned int i = 0; i < num_hops; i++)
6238 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6240 GNUNET_break_op (0);
6241 return GNUNET_SYSERR;
6243 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6245 GNUNET_break_op (0);
6246 return GNUNET_SYSERR;
6254 * Build and forward a DV learn message to @a next_hop.
6256 * @param next_hop peer to send the message to
6257 * @param msg message received
6258 * @param bi_history bitmask specifying hops on path that were bidirectional
6259 * @param nhops length of the @a hops array
6260 * @param hops path the message traversed so far
6261 * @param in_time when did we receive the message, used to calculate network
6265 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6266 const struct TransportDVLearnMessage *msg,
6267 uint16_t bi_history,
6269 const struct DVPathEntryP *hops,
6270 struct GNUNET_TIME_Absolute in_time)
6272 struct DVPathEntryP *dhops;
6273 char buf[sizeof (struct TransportDVLearnMessage) +
6274 (nhops + 1) * sizeof (struct DVPathEntryP)] GNUNET_ALIGN;
6275 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6276 struct GNUNET_TIME_Relative nnd;
6278 /* compute message for forwarding */
6279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6280 "Forwarding DV learn message originating from %s to %s\n",
6281 GNUNET_i2s (&msg->initiator),
6282 GNUNET_i2s2 (next_hop));
6283 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6284 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6285 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6286 (nhops + 1) * sizeof (struct DVPathEntryP));
6287 fwd->num_hops = htons (nhops + 1);
6288 fwd->bidirectional = htons (bi_history);
6289 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6290 GNUNET_TIME_relative_ntoh (
6291 msg->non_network_delay));
6292 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6293 fwd->init_sig = msg->init_sig;
6294 fwd->initiator = msg->initiator;
6295 fwd->challenge = msg->challenge;
6296 dhops = (struct DVPathEntryP *) &fwd[1];
6297 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6298 dhops[nhops].hop = GST_my_identity;
6300 struct DvHopPS dhp = {.purpose.purpose =
6301 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6302 .purpose.size = htonl (sizeof (dhp)),
6303 .pred = dhops[nhops - 1].hop,
6305 .challenge = msg->challenge};
6307 GNUNET_assert (GNUNET_OK ==
6308 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6310 &dhops[nhops].hop_sig));
6312 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6317 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6319 * @param sender_monotonic_time monotonic time of the initiator
6320 * @param init the signer
6321 * @param challenge the challenge that was signed
6322 * @param init_sig signature presumably by @a init
6323 * @return #GNUNET_OK if the signature is valid
6326 validate_dv_initiator_signature (
6327 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6328 const struct GNUNET_PeerIdentity *init,
6329 const struct ChallengeNonceP *challenge,
6330 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6332 struct DvInitPS ip = {.purpose.purpose = htonl (
6333 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6334 .purpose.size = htonl (sizeof (ip)),
6335 .monotonic_time = sender_monotonic_time,
6336 .challenge = *challenge};
6340 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6345 GNUNET_break_op (0);
6346 return GNUNET_SYSERR;
6353 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6355 struct NeighbourSelectionContext
6358 * Original message we received.
6360 const struct TransportDVLearnMessage *dvl;
6365 const struct DVPathEntryP *hops;
6368 * Time we received the message.
6370 struct GNUNET_TIME_Absolute in_time;
6373 * Offsets of the selected peers.
6375 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6378 * Number of peers eligible for selection.
6380 unsigned int num_eligible;
6383 * Number of peers that were selected for forwarding.
6385 unsigned int num_selections;
6388 * Number of hops in @e hops
6393 * Bitmap of bidirectional connections encountered.
6395 uint16_t bi_history;
6400 * Function called for each neighbour during #handle_dv_learn.
6402 * @param cls a `struct NeighbourSelectionContext *`
6403 * @param pid identity of the peer
6404 * @param value a `struct Neighbour`
6405 * @return #GNUNET_YES (always)
6408 dv_neighbour_selection (void *cls,
6409 const struct GNUNET_PeerIdentity *pid,
6412 struct NeighbourSelectionContext *nsc = cls;
6415 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6416 return GNUNET_YES; /* skip initiator */
6417 for (unsigned int i = 0; i < nsc->nhops; i++)
6418 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6419 return GNUNET_YES; /* skip peers on path */
6420 nsc->num_eligible++;
6426 * Function called for each neighbour during #handle_dv_learn.
6427 * We call #forward_dv_learn() on the neighbour(s) selected
6428 * during #dv_neighbour_selection().
6430 * @param cls a `struct NeighbourSelectionContext *`
6431 * @param pid identity of the peer
6432 * @param value a `struct Neighbour`
6433 * @return #GNUNET_YES (always)
6436 dv_neighbour_transmission (void *cls,
6437 const struct GNUNET_PeerIdentity *pid,
6440 struct NeighbourSelectionContext *nsc = cls;
6443 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6444 return GNUNET_YES; /* skip initiator */
6445 for (unsigned int i = 0; i < nsc->nhops; i++)
6446 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6447 return GNUNET_YES; /* skip peers on path */
6448 for (unsigned int i = 0; i < nsc->num_selections; i++)
6450 if (nsc->selections[i] == nsc->num_eligible)
6452 forward_dv_learn (pid,
6461 nsc->num_eligible++;
6467 * Computes the number of neighbours we should forward a DVInit
6468 * message to given that it has so far taken @a hops_taken hops
6469 * though the network and that the number of neighbours we have
6470 * in total is @a neighbour_count, out of which @a eligible_count
6471 * are not yet on the path.
6473 * NOTE: technically we might want to include NSE in the formula to
6474 * get a better grip on the overall network size. However, for now
6475 * using NSE here would create a dependency issue in the build system.
6476 * => Left for later, hardcoded to 50 for now.
6478 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6479 * peers via DV (`target_total`). We want the reach to be spread out
6480 * over various distances to the origin, with a bias towards shorter
6483 * We make the strong assumption that the network topology looks
6484 * "similar" at other hops, in particular the @a neighbour_count
6485 * should be comparable at other hops.
6487 * If the local neighbourhood is densely connected, we expect that @a
6488 * eligible_count is close to @a neighbour_count minus @a hops_taken
6489 * as a lot of the path is already known. In that case, we should
6490 * forward to few(er) peers to try to find a path out of the
6491 * neighbourhood. OTOH, if @a eligible_count is close to @a
6492 * neighbour_count, we should forward to many peers as we are either
6493 * still close to the origin (i.e. @a hops_taken is small) or because
6494 * we managed to get beyond a local cluster. We express this as
6495 * the `boost_factor` using the square of the fraction of eligible
6496 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6497 * 99% are eligible, the 'boost' will be almost 1).
6499 * Second, the more hops we have taken, the larger the problem of an
6500 * exponential traffic explosion gets. So we take the `target_total`,
6501 * and compute our degree such that at each distance d 2^{-d} peers
6502 * are selected (corrected by the `boost_factor`).
6504 * @param hops_taken number of hops DVInit has travelled so far
6505 * @param neighbour_count number of neighbours we have in total
6506 * @param eligible_count number of neighbours we could in
6510 calculate_fork_degree (unsigned int hops_taken,
6511 unsigned int neighbour_count,
6512 unsigned int eligible_count)
6514 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6515 double eligible_ratio =
6516 ((double) eligible_count) / ((double) neighbour_count);
6517 double boost_factor = eligible_ratio * eligible_ratio;
6521 if (hops_taken >= 64)
6524 return 0; /* precaution given bitshift below */
6526 for (unsigned int i = 1; i < hops_taken; i++)
6528 /* For each hop, subtract the expected number of targets
6529 reached at distance d (so what remains divided by 2^d) */
6530 target_total -= (target_total * boost_factor / (1LLU << i));
6533 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6534 /* round up or down probabilistically depending on how close we were
6535 when floor()ing to rnd */
6536 left = target_total - (double) rnd;
6537 if (UINT32_MAX * left >
6538 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6539 rnd++; /* round up */
6540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6541 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6551 * Function called when peerstore is done storing a DV monotonic time.
6553 * @param cls a `struct Neighbour`
6554 * @param success #GNUNET_YES if peerstore was successful
6557 neighbour_store_dvmono_cb (void *cls, int success)
6559 struct Neighbour *n = cls;
6562 if (GNUNET_YES != success)
6563 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6564 "Failed to store other peer's monotonic time in peerstore!\n");
6569 * Communicator gave us a DV learn message. Process the request.
6571 * @param cls a `struct CommunicatorMessageContext` (must call
6572 * #finish_cmc_handling() when done)
6573 * @param dvl the message that was received
6576 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6578 struct CommunicatorMessageContext *cmc = cls;
6579 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6582 uint16_t bi_history;
6583 const struct DVPathEntryP *hops;
6586 struct GNUNET_TIME_Absolute in_time;
6587 struct Neighbour *n;
6589 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6590 bi_history = ntohs (dvl->bidirectional);
6591 hops = (const struct DVPathEntryP *) &dvl[1];
6595 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6598 finish_cmc_handling (cmc);
6605 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6608 finish_cmc_handling (cmc);
6613 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6614 cc = cmc->tc->details.communicator.cc;
6615 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6616 cc); // FIXME: add bi-directional flag to cc?
6617 in_time = GNUNET_TIME_absolute_get ();
6619 /* continue communicator here, everything else can happen asynchronous! */
6620 finish_cmc_handling (cmc);
6622 n = lookup_neighbour (&dvl->initiator);
6625 if ((n->dv_monotime_available == GNUNET_YES) &&
6626 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6627 n->last_dv_learn_monotime.abs_value_us))
6629 GNUNET_STATISTICS_update (GST_stats,
6630 "# DV learn discarded due to time travel",
6635 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6640 GNUNET_break_op (0);
6643 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6644 if (GNUNET_YES == n->dv_monotime_available)
6647 GNUNET_PEERSTORE_store_cancel (n->sc);
6649 GNUNET_PEERSTORE_store (peerstore,
6652 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6653 &dvl->monotonic_time,
6654 sizeof (dvl->monotonic_time),
6655 GNUNET_TIME_UNIT_FOREVER_ABS,
6656 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6657 &neighbour_store_dvmono_cb,
6661 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6662 If signature verification load too high, implement random drop strategy */
6663 for (unsigned int i = 0; i < nhops; i++)
6665 struct DvHopPS dhp = {.purpose.purpose =
6666 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6667 .purpose.size = htonl (sizeof (dhp)),
6668 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6669 .succ = (nhops == i + 1) ? GST_my_identity
6671 .challenge = dvl->challenge};
6674 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6677 &hops[i].hop.public_key))
6679 GNUNET_break_op (0);
6684 if (GNUNET_EXTRA_LOGGING > 0)
6688 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6689 for (unsigned int i = 0; i < nhops; i++)
6693 GNUNET_asprintf (&tmp,
6696 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6697 GNUNET_i2s (&hops[i].hop));
6701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6702 "Received DVInit via %s%s%s\n",
6704 bi_hop ? "<->" : "-->",
6705 GNUNET_i2s (&GST_my_identity));
6709 do_fwd = GNUNET_YES;
6710 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6712 struct GNUNET_PeerIdentity path[nhops + 1];
6713 struct GNUNET_TIME_Relative host_latency_sum;
6714 struct GNUNET_TIME_Relative latency;
6715 struct GNUNET_TIME_Relative network_latency;
6717 /* We initiated this, learn the forward path! */
6718 path[0] = GST_my_identity;
6719 path[1] = hops[0].hop;
6720 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6722 // Need also something to lookup initiation time
6723 // to compute RTT! -> add RTT argument here?
6724 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6725 // (based on dvl->challenge, we can identify time of origin!)
6727 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6728 /* assumption: latency on all links is the same */
6729 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6731 for (unsigned int i = 2; i <= nhops; i++)
6733 struct GNUNET_TIME_Relative ilat;
6735 /* assumption: linear latency increase per hop */
6736 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6737 path[i] = hops[i - 1].hop;
6738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6739 "Learned path with %u hops to %s with latency %s\n",
6741 GNUNET_i2s (&path[i]),
6742 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6743 learn_dv_path (path,
6746 GNUNET_TIME_relative_to_absolute (
6747 ADDRESS_VALIDATION_LIFETIME));
6749 /* as we initiated, do not forward again (would be circular!) */
6755 /* last hop was bi-directional, we could learn something here! */
6756 struct GNUNET_PeerIdentity path[nhops + 2];
6758 path[0] = GST_my_identity;
6759 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6760 for (unsigned int i = 0; i < nhops; i++)
6764 if (0 == (bi_history & (1 << i)))
6765 break; /* i-th hop not bi-directional, stop learning! */
6768 path[i + 2] = dvl->initiator;
6772 path[i + 2] = hops[nhops - i - 2].hop;
6775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6776 "Learned inverse path with %u hops to %s\n",
6778 GNUNET_i2s (&path[i + 2]));
6779 iret = learn_dv_path (path,
6781 GNUNET_TIME_UNIT_FOREVER_REL,
6782 GNUNET_TIME_UNIT_ZERO_ABS);
6783 if (GNUNET_SYSERR == iret)
6785 /* path invalid or too long to be interesting for US, thus should also
6786 not be interesting to our neighbours, cut path when forwarding to
6787 'i' hops, except of course for the one that goes back to the
6789 GNUNET_STATISTICS_update (GST_stats,
6790 "# DV learn not forwarded due invalidity of path",
6796 if ((GNUNET_NO == iret) && (nhops == i + 1))
6798 /* we have better paths, and this is the longest target,
6799 so there cannot be anything interesting later */
6800 GNUNET_STATISTICS_update (GST_stats,
6801 "# DV learn not forwarded, got better paths",
6810 if (MAX_DV_HOPS_ALLOWED == nhops)
6812 /* At limit, we're out of here! */
6813 finish_cmc_handling (cmc);
6817 /* Forward to initiator, if path non-trivial and possible */
6818 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6819 did_initiator = GNUNET_NO;
6822 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6824 /* send back to origin! */
6825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6826 "Sending DVL back to initiator %s\n",
6827 GNUNET_i2s (&dvl->initiator));
6828 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6829 did_initiator = GNUNET_YES;
6831 /* We forward under two conditions: either we still learned something
6832 ourselves (do_fwd), or the path was darn short and thus the initiator is
6833 likely to still be very interested in this (and we did NOT already
6834 send it back to the initiator) */
6835 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6836 (GNUNET_NO == did_initiator)))
6838 /* Pick random neighbours that are not yet on the path */
6839 struct NeighbourSelectionContext nsc;
6842 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6845 nsc.bi_history = bi_history;
6847 nsc.in_time = in_time;
6848 nsc.num_eligible = 0;
6849 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6850 &dv_neighbour_selection,
6852 if (0 == nsc.num_eligible)
6853 return; /* done here, cannot forward to anyone else */
6854 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6855 nsc.num_selections =
6856 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6858 "Forwarding DVL to %u other peers\n",
6859 nsc.num_selections);
6860 for (unsigned int i = 0; i < nsc.num_selections; i++)
6862 (nsc.num_selections == n_cnt)
6863 ? i /* all were selected, avoid collisions by chance */
6864 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6865 nsc.num_eligible = 0;
6866 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6867 &dv_neighbour_transmission,
6874 * Communicator gave us a DV box. Check the message.
6876 * @param cls a `struct CommunicatorMessageContext`
6877 * @param dvb the send message that was sent
6878 * @return #GNUNET_YES if message is well-formed
6881 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6883 uint16_t size = ntohs (dvb->header.size);
6884 uint16_t num_hops = ntohs (dvb->num_hops);
6885 const struct GNUNET_PeerIdentity *hops =
6886 (const struct GNUNET_PeerIdentity *) &dvb[1];
6889 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6890 sizeof (struct GNUNET_MessageHeader))
6892 GNUNET_break_op (0);
6893 return GNUNET_SYSERR;
6895 /* This peer must not be on the path */
6896 for (unsigned int i = 0; i < num_hops; i++)
6897 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6899 GNUNET_break_op (0);
6900 return GNUNET_SYSERR;
6907 * Create a DV Box message and queue it for transmission to
6910 * @param next_hop peer to receive the message next
6911 * @param total_hops how many hops did the message take so far
6912 * @param num_hops length of the @a hops array
6913 * @param origin origin of the message
6914 * @param hops next peer(s) to the destination, including destination
6915 * @param payload payload of the box
6916 * @param payload_size number of bytes in @a payload
6919 forward_dv_box (struct Neighbour *next_hop,
6920 const struct TransportDVBoxMessage *hdr,
6921 uint16_t total_hops,
6923 const struct GNUNET_PeerIdentity *hops,
6924 const void *enc_payload,
6925 uint16_t enc_payload_size)
6927 char buf[sizeof (struct TransportDVBoxMessage) +
6928 num_hops * sizeof (struct GNUNET_PeerIdentity) + enc_payload_size];
6929 struct GNUNET_PeerIdentity *dhops =
6930 (struct GNUNET_PeerIdentity *) &buf[sizeof (struct TransportDVBoxMessage)];
6932 memcpy (buf, hdr, sizeof (*hdr));
6933 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
6934 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
6935 route_message (&next_hop->pid,
6936 (const struct GNUNET_MessageHeader *) buf,
6942 * Free data structures associated with @a b.
6944 * @param b data structure to release
6947 free_backtalker (struct Backtalker *b)
6951 GNUNET_PEERSTORE_iterate_cancel (b->get);
6953 GNUNET_assert (NULL != b->cmc);
6954 finish_cmc_handling (b->cmc);
6957 if (NULL != b->task)
6959 GNUNET_SCHEDULER_cancel (b->task);
6964 GNUNET_PEERSTORE_store_cancel (b->sc);
6969 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
6975 * Callback to free backtalker records.
6979 * @param value a `struct Backtalker`
6980 * @return #GNUNET_OK (always)
6983 free_backtalker_cb (void *cls,
6984 const struct GNUNET_PeerIdentity *pid,
6987 struct Backtalker *b = value;
6991 free_backtalker (b);
6997 * Function called when it is time to clean up a backtalker.
6999 * @param cls a `struct Backtalker`
7002 backtalker_timeout_cb (void *cls)
7004 struct Backtalker *b = cls;
7007 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7009 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7012 GNUNET_assert (NULL == b->sc);
7013 free_backtalker (b);
7018 * Function called with the monotonic time of a backtalker
7019 * by PEERSTORE. Updates the time and continues processing.
7021 * @param cls a `struct Backtalker`
7022 * @param record the information found, NULL for the last call
7023 * @param emsg error message
7026 backtalker_monotime_cb (void *cls,
7027 const struct GNUNET_PEERSTORE_Record *record,
7030 struct Backtalker *b = cls;
7031 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7032 struct GNUNET_TIME_Absolute mt;
7037 /* we're done with #backtalker_monotime_cb() invocations,
7038 continue normal processing */
7040 GNUNET_assert (NULL != b->cmc);
7041 if (0 != b->body_size)
7042 demultiplex_with_cmc (b->cmc,
7043 (const struct GNUNET_MessageHeader *) &b[1]);
7045 finish_cmc_handling (b->cmc);
7049 if (sizeof (*mtbe) != record->value_size)
7054 mtbe = record->value;
7055 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7056 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7059 "Backtalker message from %s dropped, monotime in the past\n",
7060 GNUNET_i2s (&b->pid));
7061 GNUNET_STATISTICS_update (
7063 "# Backchannel messages dropped: monotonic time not increasing",
7066 b->monotonic_time = mt;
7067 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7076 * Function called by PEERSTORE when the store operation of
7077 * a backtalker's monotonic time is complete.
7079 * @param cls the `struct Backtalker`
7080 * @param success #GNUNET_OK on success
7083 backtalker_monotime_store_cb (void *cls, int success)
7085 struct Backtalker *b = cls;
7087 if (GNUNET_OK != success)
7089 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7090 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7093 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7098 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7100 * @param b a backtalker with updated monotonic time
7103 update_backtalker_monotime (struct Backtalker *b)
7105 struct GNUNET_TIME_AbsoluteNBO mtbe;
7109 GNUNET_PEERSTORE_store_cancel (b->sc);
7114 GNUNET_SCHEDULER_cancel (b->task);
7117 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7119 GNUNET_PEERSTORE_store (peerstore,
7122 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7125 GNUNET_TIME_UNIT_FOREVER_ABS,
7126 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7127 &backtalker_monotime_store_cb,
7133 * Communicator gave us a DV box. Process the request.
7135 * @param cls a `struct CommunicatorMessageContext` (must call
7136 * #finish_cmc_handling() when done)
7137 * @param dvb the message that was received
7140 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7142 struct CommunicatorMessageContext *cmc = cls;
7143 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
7144 uint16_t num_hops = ntohs (dvb->num_hops);
7145 const struct GNUNET_PeerIdentity *hops =
7146 (const struct GNUNET_PeerIdentity *) &dvb[1];
7147 const char *enc_payload = (const char *) &hops[num_hops];
7148 uint16_t enc_payload_size =
7149 size - (num_hops * sizeof (struct GNUNET_PeerIdentity));
7150 struct DVKeyState key;
7151 struct GNUNET_HashCode hmac;
7155 if (GNUNET_EXTRA_LOGGING > 0)
7159 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7160 for (unsigned int i = 0; i < num_hops; i++)
7164 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7169 "Received DVBox with remainig path %s\n",
7176 /* We're trying from the end of the hops array, as we may be
7177 able to find a shortcut unknown to the origin that way */
7178 for (int i = num_hops - 1; i >= 0; i--)
7180 struct Neighbour *n;
7182 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7184 GNUNET_break_op (0);
7185 finish_cmc_handling (cmc);
7188 n = lookup_neighbour (&hops[i]);
7191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7192 "Skipping %u/%u hops ahead while routing DV Box\n",
7197 ntohs (dvb->total_hops) + 1,
7198 num_hops - i - 1, /* number of hops left */
7199 &hops[i + 1], /* remaining hops */
7202 GNUNET_STATISTICS_update (GST_stats,
7203 "# DV hops skipped routing boxes",
7206 GNUNET_STATISTICS_update (GST_stats,
7207 "# DV boxes routed (total)",
7210 finish_cmc_handling (cmc);
7213 /* Woopsie, next hop not in neighbours, drop! */
7214 GNUNET_STATISTICS_update (GST_stats,
7215 "# DV Boxes dropped: next hop unknown",
7218 finish_cmc_handling (cmc);
7221 /* We are the target. Unbox and handle message. */
7222 GNUNET_STATISTICS_update (GST_stats,
7223 "# DV boxes opened (ultimate target)",
7226 cmc->total_hops = ntohs (dvb->total_hops);
7228 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key);
7229 hdr = (const char *) &dvb[1];
7230 hdr_len = ntohs (dvb->header.size) - sizeof (*dvb);
7231 dv_hmac (&key, &hmac, hdr, hdr_len);
7232 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7234 /* HMAC missmatch, disard! */
7235 GNUNET_break_op (0);
7236 finish_cmc_handling (cmc);
7239 /* begin actual decryption */
7241 struct Backtalker *b;
7242 struct GNUNET_TIME_Absolute monotime;
7243 struct TransportDVBoxPayloadP ppay;
7244 char body[hdr_len - sizeof (ppay)] GNUNET_ALIGN;
7245 const struct GNUNET_MessageHeader *mh =
7246 (const struct GNUNET_MessageHeader *) body;
7248 GNUNET_assert (hdr_len >=
7249 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
7250 dv_decrypt (&key, &ppay, hdr, sizeof (ppay));
7251 dv_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
7252 dv_key_clean (&key);
7253 if (ntohs (mh->size) != sizeof (body))
7255 GNUNET_break_op (0);
7256 finish_cmc_handling (cmc);
7259 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7260 switch (ntohs (mh->type))
7262 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7263 GNUNET_break_op (0);
7264 finish_cmc_handling (cmc);
7266 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7267 GNUNET_break_op (0);
7268 finish_cmc_handling (cmc);
7271 /* permitted, continue */
7274 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7276 "Decrypted backtalk from %s\n",
7277 GNUNET_i2s (&ppay.sender));
7278 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
7279 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
7281 GNUNET_STATISTICS_update (
7283 "# Backchannel messages dropped: monotonic time not increasing",
7286 finish_cmc_handling (cmc);
7290 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
7292 /* Check signature */
7293 struct EphemeralConfirmationPS ec;
7295 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
7296 ec.purpose.size = htonl (sizeof (ec));
7297 ec.target = GST_my_identity;
7298 ec.ephemeral_key = dvb->ephemeral_key;
7301 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
7304 &ppay.sender.public_key))
7306 /* Signature invalid, disard! */
7307 GNUNET_break_op (0);
7308 finish_cmc_handling (cmc);
7312 /* Update sender, we now know the real origin! */
7313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7314 "DVBox received for me from %s via %s\n",
7315 GNUNET_i2s2 (&ppay.sender),
7316 GNUNET_i2s (&cmc->im.sender));
7317 cmc->im.sender = ppay.sender;
7321 /* update key cache and mono time */
7322 b->last_ephemeral = dvb->ephemeral_key;
7323 b->monotonic_time = monotime;
7324 update_backtalker_monotime (b);
7326 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7328 demultiplex_with_cmc (cmc, mh);
7331 /* setup data structure to cache signature AND check
7332 monotonic time with PEERSTORE before forwarding backchannel payload */
7333 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
7334 b->pid = ppay.sender;
7335 b->body_size = sizeof (body);
7336 memcpy (&b[1], body, sizeof (body));
7337 GNUNET_assert (GNUNET_YES ==
7338 GNUNET_CONTAINER_multipeermap_put (
7342 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7343 b->monotonic_time = monotime; /* NOTE: to be checked still! */
7346 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7347 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7349 GNUNET_PEERSTORE_iterate (peerstore,
7352 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7353 &backtalker_monotime_cb,
7355 } /* end actual decryption */
7360 * Client notified us about transmission from a peer. Process the request.
7362 * @param cls a `struct TransportClient` which sent us the message
7363 * @param obm the send message that was sent
7364 * @return #GNUNET_YES if message is well-formed
7367 check_incoming_msg (void *cls,
7368 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7370 struct TransportClient *tc = cls;
7372 if (CT_COMMUNICATOR != tc->type)
7375 return GNUNET_SYSERR;
7377 GNUNET_MQ_check_boxed_message (im);
7384 * We received a @a challenge from another peer, check if we can
7385 * increase the flow control window to that peer.
7387 * @param vl virtual link
7388 * @param challenge the challenge we received
7389 * @param sender_time when did the peer send the message?
7390 * @param last_window_consum_limit maximum number of kb the sender
7391 * promises to use of the previous window (if any)
7394 update_fc_window (struct VirtualLink *vl,
7395 struct GNUNET_TIME_Absolute sender_time,
7396 uint32_t last_window_consum_limit)
7398 // FIXME: update to new FC logic
7399 if (0 == GNUNET_memcmp (challenge, &vl->n_challenge))
7403 /* Challenge identical to last one, update
7404 @a last_window_consum_limit (to minimum) */
7405 vl->last_fc_window_size_remaining =
7406 GNUNET_MIN (last_window_consum_limit, vl->last_fc_window_size_remaining);
7407 /* window could have shrunk! */
7408 if (vl->available_fc_window_size > vl->last_fc_window_size_remaining)
7409 avail = vl->available_fc_window_size - vl->last_fc_window_size_remaining;
7412 /* guard against integer overflow */
7413 if (vl->incoming_fc_window_size_used + avail >=
7414 vl->incoming_fc_window_size_used)
7415 vl->incoming_fc_window_size = vl->incoming_fc_window_size_used + avail;
7417 vl->incoming_fc_window_size = UINT32_MAX;
7418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7419 "Updated window to %u/%u kb (%u used) for virtual link to %s!\n",
7420 vl->incoming_fc_window_size,
7421 vl->available_fc_window_size,
7422 vl->incoming_fc_window_size_used,
7423 GNUNET_i2s (&vl->target));
7426 if (vl->n_challenge_time.abs_value_us >= sender_time.abs_value_us)
7428 GNUNET_STATISTICS_update (GST_stats,
7429 "# Challenges ignored: sender time not increasing",
7434 /* new challenge! */
7435 if (vl->incoming_fc_window_size_used > last_window_consum_limit)
7437 /* lying peer: it already used more than it promised it would ever use! */
7438 GNUNET_break_op (0);
7439 last_window_consum_limit = vl->incoming_fc_window_size_used;
7441 /* What remains is at most the difference between what we already processed
7442 and what the sender promises to limit itself to. */
7443 vl->last_fc_window_size_remaining =
7444 last_window_consum_limit - vl->incoming_fc_window_size_used;
7445 vl->n_challenge = *challenge;
7446 vl->n_challenge_time = sender_time;
7447 vl->incoming_fc_window_size_used = 0;
7448 /* window could have shrunk! */
7449 if (vl->available_fc_window_size > vl->last_fc_window_size_remaining)
7450 vl->incoming_fc_window_size =
7451 vl->available_fc_window_size - vl->last_fc_window_size_remaining;
7453 vl->incoming_fc_window_size = 0;
7455 GNUNET_ERROR_TYPE_DEBUG,
7456 "New window at %u/%u kb (%u left on previous) for virtual link to %s!\n",
7457 vl->incoming_fc_window_size,
7458 vl->available_fc_window_size,
7459 vl->last_fc_window_size_remaining,
7460 GNUNET_i2s (&vl->target));
7466 * Closure for #check_known_address.
7468 struct CheckKnownAddressContext
7471 * Set to the address we are looking for.
7473 const char *address;
7476 * Set to a matching validation state, if one was found.
7478 struct ValidationState *vs;
7483 * Test if the validation state in @a value matches the
7484 * address from @a cls.
7486 * @param cls a `struct CheckKnownAddressContext`
7487 * @param pid unused (must match though)
7488 * @param value a `struct ValidationState`
7489 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7492 check_known_address (void *cls,
7493 const struct GNUNET_PeerIdentity *pid,
7496 struct CheckKnownAddressContext *ckac = cls;
7497 struct ValidationState *vs = value;
7500 if (0 != strcmp (vs->address, ckac->address))
7508 * Task run periodically to validate some address based on #validation_heap.
7513 validation_start_cb (void *cls);
7517 * Set the time for next_challenge of @a vs to @a new_time.
7518 * Updates the heap and if necessary reschedules the job.
7520 * @param vs validation state to update
7521 * @param new_time new time for revalidation
7524 update_next_challenge_time (struct ValidationState *vs,
7525 struct GNUNET_TIME_Absolute new_time)
7527 struct GNUNET_TIME_Relative delta;
7529 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7530 return; /* be lazy */
7531 vs->next_challenge = new_time;
7534 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7536 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7537 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7538 (NULL != validation_task))
7540 if (NULL != validation_task)
7541 GNUNET_SCHEDULER_cancel (validation_task);
7542 /* randomize a bit */
7543 delta.rel_value_us =
7544 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7545 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7546 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7548 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7553 * Start address validation.
7555 * @param pid peer the @a address is for
7556 * @param address an address to reach @a pid (presumably)
7559 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7560 const char *address)
7562 struct GNUNET_TIME_Absolute now;
7563 struct ValidationState *vs;
7564 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7566 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7568 &check_known_address,
7570 if (NULL != (vs = ckac.vs))
7572 /* if 'vs' is not currently valid, we need to speed up retrying the
7574 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7576 /* reduce backoff as we got a fresh advertisement */
7577 vs->challenge_backoff =
7578 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7579 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7581 update_next_challenge_time (vs,
7582 GNUNET_TIME_relative_to_absolute (
7583 vs->challenge_backoff));
7587 now = GNUNET_TIME_absolute_get ();
7588 vs = GNUNET_new (struct ValidationState);
7591 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7592 vs->first_challenge_use = now;
7593 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7594 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7596 sizeof (vs->challenge));
7597 vs->address = GNUNET_strdup (address);
7598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7599 "Starting address validation `%s' of peer %s using challenge %s\n",
7602 GNUNET_sh2s (&vs->challenge.value));
7603 GNUNET_assert (GNUNET_YES ==
7604 GNUNET_CONTAINER_multipeermap_put (
7608 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7609 update_next_challenge_time (vs, now);
7614 * Function called by PEERSTORE for each matching record.
7616 * @param cls closure, a `struct IncomingRequest`
7617 * @param record peerstore record information
7618 * @param emsg error message, or NULL if no errors
7621 handle_hello_for_incoming (void *cls,
7622 const struct GNUNET_PEERSTORE_Record *record,
7625 struct IncomingRequest *ir = cls;
7630 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7631 "Got failure from PEERSTORE: %s\n",
7635 val = record->value;
7636 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7641 start_address_validation (&ir->pid, (const char *) record->value);
7646 * Communicator gave us a transport address validation challenge. Process the
7649 * @param cls a `struct CommunicatorMessageContext` (must call
7650 * #finish_cmc_handling() when done)
7651 * @param tvc the message that was received
7654 handle_validation_challenge (
7656 const struct TransportValidationChallengeMessage *tvc)
7658 struct CommunicatorMessageContext *cmc = cls;
7659 struct TransportValidationResponseMessage tvr;
7660 struct VirtualLink *vl;
7661 struct GNUNET_TIME_RelativeNBO validity_duration;
7662 struct IncomingRequest *ir;
7663 struct Neighbour *n;
7665 /* DV-routed messages are not allowed for validation challenges */
7666 if (cmc->total_hops > 0)
7668 GNUNET_break_op (0);
7669 finish_cmc_handling (cmc);
7672 validity_duration = cmc->im.expected_address_validity;
7673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7674 "Received address validation challenge %s\n",
7675 GNUNET_sh2s (&tvc->challenge.value));
7676 /* If we have a virtual link, we use this mechanism to signal the
7677 size of the flow control window, and to allow the sender
7678 to ask for increases. If for us the virtual link is still down,
7679 we will always give a window size of zero. */
7681 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7682 tvr.header.size = htons (sizeof (tvr));
7683 tvr.reserved = htonl (0);
7684 tvr.challenge = tvc->challenge;
7685 tvr.origin_time = tvc->sender_time;
7686 tvr.validity_duration = validity_duration;
7688 /* create signature */
7689 struct TransportValidationPS tvp =
7690 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7691 .purpose.size = htonl (sizeof (tvp)),
7692 .validity_duration = validity_duration,
7693 .challenge = tvc->challenge};
7695 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7699 route_message (&cmc->im.sender,
7701 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7702 finish_cmc_handling (cmc);
7704 vl = lookup_virtual_link (&cmc->im.sender);
7708 /* For us, the link is still down, but we need bi-directional
7709 connections (for flow-control and for this to be useful for
7710 CORE), so we must try to bring the link up! */
7712 /* (1) Check existing queues, if any, we may be lucky! */
7713 n = lookup_neighbour (&cmc->im.sender);
7715 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7716 start_address_validation (&cmc->im.sender, q->address);
7717 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7719 for (ir = ir_head; NULL != ir; ir = ir->next)
7720 if (0 == GNUNET_memcmp (&ir->pid, &cmc->im.sender))
7721 return; /* we are already trying */
7722 ir = GNUNET_new (struct IncomingRequest);
7723 ir->pid = cmc->im.sender;
7724 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7725 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7728 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7729 &handle_hello_for_incoming,
7732 /* Bound attempts we do in parallel here, might otherwise get excessive */
7733 while (ir_total > MAX_INCOMING_REQUEST)
7734 free_incoming_request (ir_head);
7739 * Closure for #check_known_challenge.
7741 struct CheckKnownChallengeContext
7744 * Set to the challenge we are looking for.
7746 const struct ChallengeNonceP *challenge;
7749 * Set to a matching validation state, if one was found.
7751 struct ValidationState *vs;
7756 * Test if the validation state in @a value matches the
7757 * challenge from @a cls.
7759 * @param cls a `struct CheckKnownChallengeContext`
7760 * @param pid unused (must match though)
7761 * @param value a `struct ValidationState`
7762 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7765 check_known_challenge (void *cls,
7766 const struct GNUNET_PeerIdentity *pid,
7769 struct CheckKnownChallengeContext *ckac = cls;
7770 struct ValidationState *vs = value;
7773 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7781 * Function called when peerstore is done storing a
7782 * validated address.
7784 * @param cls a `struct ValidationState`
7785 * @param success #GNUNET_YES on success
7788 peerstore_store_validation_cb (void *cls, int success)
7790 struct ValidationState *vs = cls;
7793 if (GNUNET_YES == success)
7795 GNUNET_STATISTICS_update (GST_stats,
7796 "# Peerstore failed to store foreign address",
7803 * Find the queue matching @a pid and @a address.
7805 * @param pid peer the queue must go to
7806 * @param address address the queue must use
7807 * @return NULL if no such queue exists
7809 static struct Queue *
7810 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7812 struct Neighbour *n;
7814 n = lookup_neighbour (pid);
7817 for (struct Queue *pos = n->queue_head; NULL != pos;
7818 pos = pos->next_neighbour)
7820 if (0 == strcmp (pos->address, address))
7828 * Communicator gave us a transport address validation response. Process the
7831 * @param cls a `struct CommunicatorMessageContext` (must call
7832 * #finish_cmc_handling() when done)
7833 * @param tvr the message that was received
7836 handle_validation_response (
7838 const struct TransportValidationResponseMessage *tvr)
7840 struct CommunicatorMessageContext *cmc = cls;
7841 struct ValidationState *vs;
7842 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7844 struct GNUNET_TIME_Absolute origin_time;
7846 struct Neighbour *n;
7847 struct VirtualLink *vl;
7849 /* check this is one of our challenges */
7850 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7852 &check_known_challenge,
7854 if (NULL == (vs = ckac.vs))
7856 /* This can happen simply if we 'forgot' the challenge by now,
7857 i.e. because we received the validation response twice */
7858 GNUNET_STATISTICS_update (GST_stats,
7859 "# Validations dropped, challenge unknown",
7862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7863 "Validation response %s dropped, challenge unknown\n",
7864 GNUNET_sh2s (&tvr->challenge.value));
7865 finish_cmc_handling (cmc);
7869 /* sanity check on origin time */
7870 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7871 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7872 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7874 GNUNET_break_op (0);
7875 finish_cmc_handling (cmc);
7880 /* check signature */
7881 struct TransportValidationPS tvp =
7882 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7883 .purpose.size = htonl (sizeof (tvp)),
7884 .validity_duration = tvr->validity_duration,
7885 .challenge = tvr->challenge};
7889 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7892 &cmc->im.sender.public_key))
7894 GNUNET_break_op (0);
7895 finish_cmc_handling (cmc);
7900 /* validity is capped by our willingness to keep track of the
7901 validation entry and the maximum the other peer allows */
7902 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7903 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7904 tvr->validity_duration),
7905 MAX_ADDRESS_VALID_UNTIL));
7906 vs->validated_until =
7907 GNUNET_TIME_absolute_min (vs->valid_until,
7908 GNUNET_TIME_relative_to_absolute (
7909 ADDRESS_VALIDATION_LIFETIME));
7910 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7911 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7912 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7914 sizeof (vs->challenge));
7915 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7916 vs->validated_until,
7917 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7918 VALIDATION_RTT_BUFFER_FACTOR));
7919 vs->last_challenge_use =
7920 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7921 update_next_challenge_time (vs, vs->first_challenge_use);
7922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7923 "Validation response %s accepted, address valid until %s\n",
7924 GNUNET_sh2s (&tvr->challenge.value),
7925 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
7926 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7929 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7931 strlen (vs->address) + 1,
7933 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7934 &peerstore_store_validation_cb,
7936 finish_cmc_handling (cmc);
7938 /* Finally, we now possibly have a confirmed (!) working queue,
7939 update queue status (if queue still is around) */
7940 q = find_queue (&vs->pid, vs->address);
7943 GNUNET_STATISTICS_update (GST_stats,
7944 "# Queues lost at time of successful validation",
7949 q->validated_until = vs->validated_until;
7950 q->pd.aged_rtt = vs->validation_rtt;
7952 vl = lookup_virtual_link (&vs->pid);
7955 /* Link was already up, remember n is also now available and we are done */
7960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7961 "Virtual link to %s could now also direct neighbour!\n",
7962 GNUNET_i2s (&vs->pid));
7966 GNUNET_assert (n == vl->n);
7970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7971 "Creating new virtual link to %s using direct neighbour!\n",
7972 GNUNET_i2s (&vs->pid));
7973 vl = GNUNET_new (struct VirtualLink);
7974 vl->target = n->pid;
7977 vl->core_recv_window = RECV_WINDOW_SIZE;
7978 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
7979 vl->my_challenge = tvr->challenge;
7980 vl->visibility_task =
7981 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7982 GNUNET_break (GNUNET_YES ==
7983 GNUNET_CONTAINER_multipeermap_put (
7987 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7988 /* We lacked a confirmed connection to the target
7989 before, so tell CORE about it (finally!) */
7990 cores_send_connect_info (&n->pid);
7995 * Incoming meessage. Process the request.
7997 * @param im the send message that was received
8000 handle_incoming_msg (void *cls,
8001 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8003 struct TransportClient *tc = cls;
8004 struct CommunicatorMessageContext *cmc =
8005 GNUNET_new (struct CommunicatorMessageContext);
8009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8010 "Received message via communicator from peer %s\n",
8011 GNUNET_i2s (&im->sender));
8012 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8017 * Given an inbound message @a msg from a communicator @a cmc,
8018 * demultiplex it based on the type calling the right handler.
8020 * @param cmc context for demultiplexing
8021 * @param msg message to demultiplex
8024 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8025 const struct GNUNET_MessageHeader *msg)
8027 struct GNUNET_MQ_MessageHandler handlers[] =
8028 {GNUNET_MQ_hd_var_size (fragment_box,
8029 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8030 struct TransportFragmentBoxMessage,
8032 GNUNET_MQ_hd_var_size (reliability_box,
8033 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8034 struct TransportReliabilityBoxMessage,
8036 GNUNET_MQ_hd_var_size (reliability_ack,
8037 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8038 struct TransportReliabilityAckMessage,
8040 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8041 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8042 struct TransportBackchannelEncapsulationMessage,
8044 GNUNET_MQ_hd_var_size (dv_learn,
8045 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8046 struct TransportDVLearnMessage,
8048 GNUNET_MQ_hd_var_size (dv_box,
8049 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8050 struct TransportDVBoxMessage,
8052 GNUNET_MQ_hd_fixed_size (
8053 validation_challenge,
8054 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8055 struct TransportValidationChallengeMessage,
8057 GNUNET_MQ_hd_fixed_size (
8058 validation_response,
8059 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8060 struct TransportValidationResponseMessage,
8062 GNUNET_MQ_handler_end ()};
8065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8066 "Handling message of type %u with %u bytes\n",
8067 (unsigned int) ntohs (msg->type),
8068 (unsigned int) ntohs (msg->size));
8069 ret = GNUNET_MQ_handle_message (handlers, msg);
8070 if (GNUNET_SYSERR == ret)
8073 GNUNET_SERVICE_client_drop (cmc->tc->client);
8077 if (GNUNET_NO == ret)
8079 /* unencapsulated 'raw' message */
8080 handle_raw_message (&cmc, msg);
8086 * New queue became available. Check message.
8088 * @param cls the client
8089 * @param aqm the send message that was sent
8092 check_add_queue_message (void *cls,
8093 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8095 struct TransportClient *tc = cls;
8097 if (CT_COMMUNICATOR != tc->type)
8100 return GNUNET_SYSERR;
8102 GNUNET_MQ_check_zero_termination (aqm);
8108 * If necessary, generates the UUID for a @a pm
8110 * @param pm pending message to generate UUID for.
8113 set_pending_message_uuid (struct PendingMessage *pm)
8115 if (pm->msg_uuid_set)
8117 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8118 pm->msg_uuid_set = GNUNET_YES;
8123 * Setup data structure waiting for acknowledgements.
8125 * @param queue queue the @a pm will be sent over
8126 * @param dvh path the message will take, may be NULL
8127 * @param pm the pending message for transmission
8128 * @return corresponding fresh pending acknowledgement
8130 static struct PendingAcknowledgement *
8131 prepare_pending_acknowledgement (struct Queue *queue,
8132 struct DistanceVectorHop *dvh,
8133 struct PendingMessage *pm)
8135 struct PendingAcknowledgement *pa;
8137 pa = GNUNET_new (struct PendingAcknowledgement);
8143 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8145 sizeof (pa->ack_uuid));
8146 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
8148 &pa->ack_uuid.value,
8150 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8151 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8152 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8154 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8155 pa->transmission_time = GNUNET_TIME_absolute_get ();
8156 pa->message_size = pm->bytes_msg;
8157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8158 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8159 GNUNET_sh2s (&pa->ack_uuid.value),
8166 * Fragment the given @a pm to the given @a mtu. Adds
8167 * additional fragments to the neighbour as well. If the
8168 * @a mtu is too small, generates and error for the @a pm
8171 * @param queue which queue to fragment for
8172 * @param dvh path the message will take, or NULL
8173 * @param pm pending message to fragment for transmission
8174 * @return new message to transmit
8176 static struct PendingMessage *
8177 fragment_message (struct Queue *queue,
8178 struct DistanceVectorHop *dvh,
8179 struct PendingMessage *pm)
8181 struct PendingAcknowledgement *pa;
8182 struct PendingMessage *ff;
8185 mtu = (0 == queue->mtu)
8186 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
8188 set_pending_message_uuid (pm);
8189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8190 "Fragmenting message %llu <%llu> to %s for MTU %u\n",
8191 (unsigned long long) pm->msg_uuid.uuid,
8193 GNUNET_i2s (&pm->vl->target),
8194 (unsigned int) mtu);
8195 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8197 /* This invariant is established in #handle_add_queue_message() */
8198 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
8200 /* select fragment for transmission, descending the tree if it has
8201 been expanded until we are at a leaf or at a fragment that is small
8205 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
8206 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
8208 ff = ff->head_frag; /* descent into fragmented fragments */
8211 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
8213 /* Did not yet calculate all fragments, calculate next fragment */
8214 struct PendingMessage *frag;
8215 struct TransportFragmentBoxMessage tfb;
8223 orig = (const char *) &ff[1];
8224 msize = ff->bytes_msg;
8227 const struct TransportFragmentBoxMessage *tfbo;
8229 tfbo = (const struct TransportFragmentBoxMessage *) orig;
8230 orig += sizeof (struct TransportFragmentBoxMessage);
8231 msize -= sizeof (struct TransportFragmentBoxMessage);
8232 xoff = ntohs (tfbo->frag_off);
8234 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
8235 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
8237 GNUNET_malloc (sizeof (struct PendingMessage) +
8238 sizeof (struct TransportFragmentBoxMessage) + fragsize);
8239 frag->logging_uuid = logging_uuid_gen++;
8241 frag->frag_parent = ff;
8242 frag->timeout = pm->timeout;
8243 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
8244 frag->pmt = PMT_FRAGMENT_BOX;
8245 msg = (char *) &frag[1];
8246 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
8248 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
8249 tfb.ack_uuid = pa->ack_uuid;
8250 tfb.msg_uuid = pm->msg_uuid;
8251 tfb.frag_off = htons (ff->frag_off + xoff);
8252 tfb.msg_size = htons (pm->bytes_msg);
8253 memcpy (msg, &tfb, sizeof (tfb));
8254 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
8255 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
8256 ff->frag_off += fragsize;
8260 /* Move head to the tail and return it */
8261 GNUNET_CONTAINER_MDLL_remove (frag,
8262 ff->frag_parent->head_frag,
8263 ff->frag_parent->tail_frag,
8265 GNUNET_CONTAINER_MDLL_insert_tail (frag,
8266 ff->frag_parent->head_frag,
8267 ff->frag_parent->tail_frag,
8274 * Reliability-box the given @a pm. On error (can there be any), NULL
8275 * may be returned, otherwise the "replacement" for @a pm (which
8276 * should then be added to the respective neighbour's queue instead of
8277 * @a pm). If the @a pm is already fragmented or reliability boxed,
8278 * or itself an ACK, this function simply returns @a pm.
8280 * @param queue which queue to prepare transmission for
8281 * @param dvh path the message will take, or NULL
8282 * @param pm pending message to box for transmission over unreliabile queue
8283 * @return new message to transmit
8285 static struct PendingMessage *
8286 reliability_box_message (struct Queue *queue,
8287 struct DistanceVectorHop *dvh,
8288 struct PendingMessage *pm)
8290 struct TransportReliabilityBoxMessage rbox;
8291 struct PendingAcknowledgement *pa;
8292 struct PendingMessage *bpm;
8295 if (PMT_CORE != pm->pmt)
8296 return pm; /* already fragmented or reliability boxed, or control message:
8298 if (NULL != pm->bpm)
8299 return pm->bpm; /* already computed earlier: do nothing */
8300 GNUNET_assert (NULL == pm->head_frag);
8301 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
8305 client_send_response (pm);
8308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8309 "Preparing reliability box for message <%llu> to %s on queue %s\n",
8311 GNUNET_i2s (&pm->vl->target),
8313 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8315 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
8317 bpm->logging_uuid = logging_uuid_gen++;
8319 bpm->frag_parent = pm;
8320 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
8321 bpm->timeout = pm->timeout;
8322 bpm->pmt = PMT_RELIABILITY_BOX;
8323 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
8324 set_pending_message_uuid (bpm);
8325 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
8326 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
8327 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
8329 rbox.ack_uuid = pa->ack_uuid;
8330 msg = (char *) &bpm[1];
8331 memcpy (msg, &rbox, sizeof (rbox));
8332 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
8339 * Change the value of the `next_attempt` field of @a pm
8340 * to @a next_attempt and re-order @a pm in the transmission
8341 * list as required by the new timestmap.
8343 * @param pm a pending message to update
8344 * @param next_attempt timestamp to use
8347 update_pm_next_attempt (struct PendingMessage *pm,
8348 struct GNUNET_TIME_Absolute next_attempt)
8350 struct VirtualLink *vl = pm->vl;
8352 pm->next_attempt = next_attempt;
8353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8354 "Next attempt for message <%llu> set to %s\n",
8356 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
8358 if (NULL == pm->frag_parent)
8360 struct PendingMessage *pos;
8362 /* re-insert sort in neighbour list */
8363 GNUNET_CONTAINER_MDLL_remove (vl,
8364 vl->pending_msg_head,
8365 vl->pending_msg_tail,
8367 pos = vl->pending_msg_tail;
8368 while ((NULL != pos) &&
8369 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8371 GNUNET_CONTAINER_MDLL_insert_after (vl,
8372 vl->pending_msg_head,
8373 vl->pending_msg_tail,
8379 /* re-insert sort in fragment list */
8380 struct PendingMessage *fp = pm->frag_parent;
8381 struct PendingMessage *pos;
8383 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
8384 pos = fp->tail_frag;
8385 while ((NULL != pos) &&
8386 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8387 pos = pos->prev_frag;
8388 GNUNET_CONTAINER_MDLL_insert_after (frag,
8398 * Context for #select_best_pending_from_link().
8400 struct PendingMessageScoreContext
8403 * Set to the best message that was found, NULL for none.
8405 struct PendingMessage *best;
8408 * DVH that @e best should take, or NULL for direct transmission.
8410 struct DistanceVectorHop *dvh;
8413 * What is the estimated total overhead for this message?
8415 size_t real_overhead;
8418 * Number of pending messages we seriously considered this time.
8420 unsigned int consideration_counter;
8423 * Did we have to fragment?
8428 * Did we have to reliability box?
8435 * Select the best pending message from @a vl for transmission
8438 * @param sc[in,out] best message so far (NULL for none), plus scoring data
8439 * @param queue the queue that will be used for transmission
8440 * @param vl the virtual link providing the messages
8441 * @param dvh path we are currently considering, or NULL for none
8442 * @param overhead number of bytes of overhead to be expected
8443 * from DV encapsulation (0 for without DV)
8446 select_best_pending_from_link (struct PendingMessageScoreContext *sc,
8447 struct Queue *queue,
8448 struct VirtualLink *vl,
8449 struct DistanceVectorHop *dvh,
8452 struct GNUNET_TIME_Absolute now;
8454 now = GNUNET_TIME_absolute_get ();
8455 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
8458 size_t real_overhead = overhead;
8462 if (pos->next_attempt.abs_value_us > now.abs_value_us)
8463 break; /* too early for all messages, they are sorted by next_attempt */
8464 if (NULL != pos->qe)
8465 continue; /* not eligible */
8466 sc->consideration_counter++;
8467 /* determine if we have to reliability-box, if so add reliability box
8470 if ((GNUNET_NO == frag) &&
8471 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
8472 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
8475 real_overhead += sizeof (struct TransportReliabilityBoxMessage);
8477 /* determine if we have to fragment, if so add fragmentation
8480 if ( ( (0 != queue->mtu) &&
8481 (pos->bytes_msg + real_overhead > queue->mtu) ) ||
8482 (pos->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
8483 (NULL != pos->head_frag /* fragments already exist, should
8484 respect that even if MTU is 0 for
8488 relb = GNUNET_NO; /* if we fragment, we never also reliability box */
8489 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
8491 /* FIXME-OPTIMIZE: we could use an optimized, shorter fragmentation
8492 header without the ACK UUID when using a *reliable* channel! */
8494 real_overhead = overhead + sizeof (struct TransportFragmentBoxMessage);
8497 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
8498 message would beat it! */
8499 if (NULL != sc->best)
8501 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
8502 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
8503 experimentally validated. There may be some huge potential for
8504 improvement here. Also, we right now only compare how well the
8505 given message fits _this_ queue, and do not consider how well other
8506 queues might suit the message. Taking other queues into consideration
8507 may further improve the result, but could also be expensive
8508 in terms of CPU time. */
8509 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
8510 long long pm_score = frag * 40 + relb * 20 + real_overhead;
8511 long long time_delta =
8512 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us) /
8515 /* "time_delta" considers which message has been 'ready' for transmission
8516 for longer, if a message has a preference for low latency, increase
8517 the weight of the time_delta by 10x if it is favorable for that message */
8518 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8519 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
8520 time_delta *= 10; /* increase weight (always, both are low latency) */
8521 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8524 10; /* increase weight, favors 'pos', which is low latency */
8525 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8528 10; /* increase weight, favors 'sc->best', which is low latency */
8529 if (0 != queue->mtu)
8531 /* Grant bonus if we are bellow MTU, larger bonus the closer we will
8533 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
8534 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
8535 if (queue->mtu > real_overhead + pos->bytes_msg)
8536 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
8538 if (sc_score + time_delta > pm_score)
8539 continue; /* sc_score larger, keep sc->best */
8550 * We believe we are ready to transmit a `struct PendingMessage` on a
8551 * queue, the big question is which one! We need to see if there is
8552 * one pending that is allowed by flow control and congestion control
8553 * and (ideally) matches our queue's performance profile.
8555 * If such a message is found, we give the message to the communicator
8556 * for transmission (updating the tracker, and re-scheduling ourselves
8559 * If no such message is found, the queue's `idle` field must be set
8562 * @param cls the `struct Queue` to process transmissions for
8565 transmit_on_queue (void *cls)
8567 struct Queue *queue = cls;
8568 struct Neighbour *n = queue->neighbour;
8569 struct PendingMessageScoreContext sc;
8570 struct PendingMessage *pm;
8572 queue->transmit_task = NULL;
8575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8576 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
8577 GNUNET_i2s (&n->pid),
8579 queue->idle = GNUNET_YES;
8582 memset (&sc, 0, sizeof (sc));
8583 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
8584 if (NULL == sc.best)
8586 /* Also look at DVH that have the n as first hop! */
8587 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
8588 dvh = dvh->next_neighbour)
8590 select_best_pending_from_link (&sc,
8594 sizeof (struct GNUNET_PeerIdentity) *
8595 (1 + dvh->distance) +
8596 sizeof (struct TransportDVBoxMessage) +
8597 sizeof (struct TransportDVBoxPayloadP));
8600 if (NULL == sc.best)
8602 /* no message pending, nothing to do here! */
8603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8604 "No pending messages, queue `%s' to %s now idle\n",
8606 GNUNET_i2s (&n->pid));
8607 queue->idle = GNUNET_YES;
8611 /* Given selection in `sc`, do transmission */
8613 if (GNUNET_YES == sc.frag)
8615 pm = fragment_message (queue, sc.dvh, sc.best);
8618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8619 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
8621 GNUNET_i2s (&n->pid),
8623 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8626 else if (GNUNET_YES == sc.relb)
8628 pm = reliability_box_message (queue, sc.dvh, sc.best);
8631 /* Reliability boxing failed, try next message... */
8633 GNUNET_ERROR_TYPE_DEBUG,
8634 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
8636 GNUNET_i2s (&n->pid),
8638 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8643 pm = sc.best; /* no boxing required */
8645 /* Pass 'pm' for transission to the communicator */
8647 GNUNET_ERROR_TYPE_DEBUG,
8648 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
8651 GNUNET_i2s (&n->pid),
8652 sc.consideration_counter);
8653 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
8655 /* Check if this transmission somehow conclusively finished handing 'pm'
8656 even without any explicit ACKs */
8657 if ((PMT_CORE == pm->pmt) ||
8658 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
8660 completed_pending_message (pm);
8664 /* Message not finished, waiting for acknowledgement.
8665 Update time by which we might retransmit 's' based on queue
8666 characteristics (i.e. RTT); it takes one RTT for the message to
8667 arrive and the ACK to come back in the best case; but the other
8668 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
8671 OPTIMIZE: Note that in the future this heuristic should likely
8672 be improved further (measure RTT stability, consider message
8673 urgency and size when delaying ACKs, etc.) */
8674 update_pm_next_attempt (pm,
8675 GNUNET_TIME_relative_to_absolute (
8676 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
8679 /* finally, re-schedule queue transmission task itself */
8680 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8685 * Queue to a peer went down. Process the request.
8687 * @param cls the client
8688 * @param dqm the send message that was sent
8691 handle_del_queue_message (void *cls,
8692 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
8694 struct TransportClient *tc = cls;
8696 if (CT_COMMUNICATOR != tc->type)
8699 GNUNET_SERVICE_client_drop (tc->client);
8702 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8703 queue = queue->next_client)
8705 struct Neighbour *neighbour = queue->neighbour;
8707 if ((dqm->qid != queue->qid) ||
8708 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
8710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8711 "Dropped queue %s to peer %s\n",
8713 GNUNET_i2s (&neighbour->pid));
8715 GNUNET_SERVICE_client_continue (tc->client);
8719 GNUNET_SERVICE_client_drop (tc->client);
8724 * Message was transmitted. Process the request.
8726 * @param cls the client
8727 * @param sma the send message that was sent
8730 handle_send_message_ack (void *cls,
8731 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
8733 struct TransportClient *tc = cls;
8734 struct QueueEntry *qe;
8735 struct PendingMessage *pm;
8737 if (CT_COMMUNICATOR != tc->type)
8740 GNUNET_SERVICE_client_drop (tc->client);
8744 /* find our queue entry matching the ACK */
8746 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8747 queue = queue->next_client)
8749 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
8751 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
8754 if (qep->mid != sma->mid)
8763 /* this should never happen */
8765 GNUNET_SERVICE_client_drop (tc->client);
8768 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
8769 qe->queue->queue_tail,
8771 qe->queue->queue_length--;
8772 tc->details.communicator.total_queue_length--;
8773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8774 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
8776 GNUNET_i2s (&qe->queue->neighbour->pid),
8777 qe->queue->queue_length,
8778 tc->details.communicator.total_queue_length);
8779 GNUNET_SERVICE_client_continue (tc->client);
8781 /* if applicable, resume transmissions that waited on ACK */
8782 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
8783 tc->details.communicator.total_queue_length)
8785 /* Communicator dropped below threshold, resume all queues
8786 incident with this client! */
8787 GNUNET_STATISTICS_update (
8789 "# Transmission throttled due to communicator queue limit",
8792 for (struct Queue *queue = tc->details.communicator.queue_head;
8794 queue = queue->next_client)
8795 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8797 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
8799 /* queue dropped below threshold; only resume this one queue */
8800 GNUNET_STATISTICS_update (GST_stats,
8801 "# Transmission throttled due to queue queue limit",
8804 schedule_transmit_on_queue (qe->queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8807 if (NULL != (pm = qe->pm))
8809 struct VirtualLink *vl;
8811 GNUNET_assert (qe == pm->qe);
8813 /* If waiting for this communicator may have blocked transmission
8814 of pm on other queues for this neighbour, force schedule
8815 transmit on queue for queues of the neighbour */
8817 if (vl->pending_msg_head == pm)
8818 check_vl_transmission (vl);
8825 * Iterator telling new MONITOR client about all existing
8828 * @param cls the new `struct TransportClient`
8829 * @param pid a connected peer
8830 * @param value the `struct Neighbour` with more information
8831 * @return #GNUNET_OK (continue to iterate)
8834 notify_client_queues (void *cls,
8835 const struct GNUNET_PeerIdentity *pid,
8838 struct TransportClient *tc = cls;
8839 struct Neighbour *neighbour = value;
8841 GNUNET_assert (CT_MONITOR == tc->type);
8842 for (struct Queue *q = neighbour->queue_head; NULL != q;
8843 q = q->next_neighbour)
8845 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
8847 .num_msg_pending = q->num_msg_pending,
8848 .num_bytes_pending = q->num_bytes_pending};
8850 notify_monitor (tc, pid, q->address, q->nt, &me);
8857 * Initialize a monitor client.
8859 * @param cls the client
8860 * @param start the start message that was sent
8863 handle_monitor_start (void *cls,
8864 const struct GNUNET_TRANSPORT_MonitorStart *start)
8866 struct TransportClient *tc = cls;
8868 if (CT_NONE != tc->type)
8871 GNUNET_SERVICE_client_drop (tc->client);
8874 tc->type = CT_MONITOR;
8875 tc->details.monitor.peer = start->peer;
8876 tc->details.monitor.one_shot = ntohl (start->one_shot);
8877 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
8878 GNUNET_SERVICE_client_mark_monitor (tc->client);
8879 GNUNET_SERVICE_client_continue (tc->client);
8884 * Find transport client providing communication service
8885 * for the protocol @a prefix.
8887 * @param prefix communicator name
8888 * @return NULL if no such transport client is available
8890 static struct TransportClient *
8891 lookup_communicator (const char *prefix)
8893 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
8895 if (CT_COMMUNICATOR != tc->type)
8897 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
8901 GNUNET_ERROR_TYPE_WARNING,
8902 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
8909 * Signature of a function called with a communicator @a address of a peer
8910 * @a pid that an application wants us to connect to.
8912 * @param pid target peer
8913 * @param address the address to try
8916 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
8918 static uint32_t idgen;
8919 struct TransportClient *tc;
8921 struct GNUNET_TRANSPORT_CreateQueue *cqm;
8922 struct GNUNET_MQ_Envelope *env;
8925 prefix = GNUNET_HELLO_address_to_prefix (address);
8928 GNUNET_break (0); /* We got an invalid address!? */
8931 tc = lookup_communicator (prefix);
8934 GNUNET_STATISTICS_update (GST_stats,
8935 "# Suggestions ignored due to missing communicator",
8938 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8939 "Cannot connect to %s at `%s', no matching communicator present\n",
8944 /* forward suggestion for queue creation to communicator */
8945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8946 "Request #%u for `%s' communicator to create queue to `%s'\n",
8947 (unsigned int) idgen,
8950 alen = strlen (address) + 1;
8952 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
8953 cqm->request_id = htonl (idgen++);
8954 cqm->receiver = *pid;
8955 memcpy (&cqm[1], address, alen);
8956 GNUNET_MQ_send (tc->mq, env);
8961 * The queue @a q (which matches the peer and address in @a vs) is
8962 * ready for queueing. We should now queue the validation request.
8964 * @param q queue to send on
8965 * @param vs state to derive validation challenge from
8968 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
8970 struct TransportValidationChallengeMessage tvc;
8972 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
8974 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
8975 tvc.header.size = htons (sizeof (tvc));
8976 tvc.reserved = htonl (0);
8977 tvc.challenge = vs->challenge;
8978 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
8979 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8980 "Sending address validation challenge %s to %s\n",
8981 GNUNET_sh2s (&tvc.challenge.value),
8982 GNUNET_i2s (&q->neighbour->pid));
8983 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
8988 * Task run periodically to validate some address based on #validation_heap.
8993 validation_start_cb (void *cls)
8995 struct ValidationState *vs;
8999 validation_task = NULL;
9000 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9001 /* drop validations past their expiration */
9004 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
9006 free_validation_state (vs);
9007 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9011 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9012 "Address validation task not scheduled anymore, nothing to do\n");
9013 return; /* woopsie, no more addresses known, should only
9014 happen if we're really a lonely peer */
9016 q = find_queue (&vs->pid, vs->address);
9019 vs->awaiting_queue = GNUNET_YES;
9020 suggest_to_connect (&vs->pid, vs->address);
9023 validation_transmit_on_queue (q, vs);
9024 /* Finally, reschedule next attempt */
9025 vs->challenge_backoff =
9026 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
9027 MAX_VALIDATION_CHALLENGE_FREQ);
9028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9029 "Address validation task will run again in %s\n",
9030 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
9032 update_next_challenge_time (vs,
9033 GNUNET_TIME_relative_to_absolute (
9034 vs->challenge_backoff));
9039 * Closure for #check_connection_quality.
9041 struct QueueQualityContext
9044 * Set to the @e k'th queue encountered.
9049 * Set to the number of quality queues encountered.
9051 unsigned int quality_count;
9054 * Set to the total number of queues encountered.
9056 unsigned int num_queues;
9059 * Decremented for each queue, for selection of the
9060 * k-th queue in @e q.
9067 * Check whether any queue to the given neighbour is
9068 * of a good "quality" and if so, increment the counter.
9069 * Also counts the total number of queues, and returns
9070 * the k-th queue found.
9072 * @param cls a `struct QueueQualityContext *` with counters
9073 * @param pid peer this is about
9074 * @param value a `struct Neighbour`
9075 * @return #GNUNET_OK (continue to iterate)
9078 check_connection_quality (void *cls,
9079 const struct GNUNET_PeerIdentity *pid,
9082 struct QueueQualityContext *ctx = cls;
9083 struct Neighbour *n = value;
9088 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9093 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
9094 statistics and consider those as well here? */
9095 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
9096 do_inc = GNUNET_YES;
9098 if (GNUNET_YES == do_inc)
9099 ctx->quality_count++;
9105 * Task run when we CONSIDER initiating a DV learn
9106 * process. We first check that sending out a message is
9107 * even possible (queues exist), then that it is desirable
9108 * (if not, reschedule the task for later), and finally
9109 * we may then begin the job. If there are too many
9110 * entries in the #dvlearn_map, we purge the oldest entry
9116 start_dv_learn (void *cls)
9118 struct LearnLaunchEntry *lle;
9119 struct QueueQualityContext qqc;
9120 struct TransportDVLearnMessage dvl;
9123 dvlearn_task = NULL;
9124 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
9125 return; /* lost all connectivity, cannot do learning */
9126 qqc.quality_count = 0;
9128 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9129 &check_connection_quality,
9131 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
9133 struct GNUNET_TIME_Relative delay;
9134 unsigned int factor;
9136 /* scale our retries by how far we are above the threshold */
9137 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
9138 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
9139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9140 "At connection quality %u, will launch DV learn in %s\n",
9142 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
9143 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
9146 /* remove old entries in #dvlearn_map if it has grown too big */
9147 while (MAX_DV_LEARN_PENDING >=
9148 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
9151 GNUNET_assert (GNUNET_YES ==
9152 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
9153 &lle->challenge.value,
9155 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9158 /* setup data structure for learning */
9159 lle = GNUNET_new (struct LearnLaunchEntry);
9160 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9162 sizeof (lle->challenge));
9163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9164 "Starting launch DV learn with challenge %s\n",
9165 GNUNET_sh2s (&lle->challenge.value));
9166 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
9167 GNUNET_break (GNUNET_YES ==
9168 GNUNET_CONTAINER_multishortmap_put (
9170 &lle->challenge.value,
9172 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9173 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
9174 dvl.header.size = htons (sizeof (dvl));
9175 dvl.num_hops = htons (0);
9176 dvl.bidirectional = htons (0);
9177 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
9178 dvl.monotonic_time =
9179 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
9181 struct DvInitPS dvip = {.purpose.purpose = htonl (
9182 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
9183 .purpose.size = htonl (sizeof (dvip)),
9184 .monotonic_time = dvl.monotonic_time,
9185 .challenge = lle->challenge};
9187 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9191 dvl.initiator = GST_my_identity;
9192 dvl.challenge = lle->challenge;
9194 qqc.quality_count = 0;
9195 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
9198 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9199 &check_connection_quality,
9201 GNUNET_assert (NULL != qqc.q);
9203 /* Do this as close to transmission time as possible! */
9204 lle->launch_time = GNUNET_TIME_absolute_get ();
9206 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
9207 /* reschedule this job, randomizing the time it runs (but no
9209 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
9210 DV_LEARN_BASE_FREQUENCY),
9217 * A new queue has been created, check if any address validation
9218 * requests have been waiting for it.
9220 * @param cls a `struct Queue`
9221 * @param pid peer concerned (unused)
9222 * @param value a `struct ValidationState`
9223 * @return #GNUNET_NO if a match was found and we can stop looking
9226 check_validation_request_pending (void *cls,
9227 const struct GNUNET_PeerIdentity *pid,
9230 struct Queue *q = cls;
9231 struct ValidationState *vs = value;
9234 if ((GNUNET_YES == vs->awaiting_queue) &&
9235 (0 == strcmp (vs->address, q->address)))
9237 vs->awaiting_queue = GNUNET_NO;
9238 validation_transmit_on_queue (q, vs);
9246 * Function called with the monotonic time of a DV initiator
9247 * by PEERSTORE. Updates the time.
9249 * @param cls a `struct Neighbour`
9250 * @param record the information found, NULL for the last call
9251 * @param emsg error message
9254 neighbour_dv_monotime_cb (void *cls,
9255 const struct GNUNET_PEERSTORE_Record *record,
9258 struct Neighbour *n = cls;
9259 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9264 /* we're done with #neighbour_dv_monotime_cb() invocations,
9265 continue normal processing */
9267 n->dv_monotime_available = GNUNET_YES;
9270 if (sizeof (*mtbe) != record->value_size)
9275 mtbe = record->value;
9276 n->last_dv_learn_monotime =
9277 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
9278 GNUNET_TIME_absolute_ntoh (*mtbe));
9283 * New queue became available. Process the request.
9285 * @param cls the client
9286 * @param aqm the send message that was sent
9289 handle_add_queue_message (void *cls,
9290 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9292 struct TransportClient *tc = cls;
9293 struct Queue *queue;
9294 struct Neighbour *neighbour;
9298 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
9300 /* MTU so small as to be useless for transmissions,
9301 required for #fragment_message()! */
9302 GNUNET_break_op (0);
9303 GNUNET_SERVICE_client_drop (tc->client);
9306 neighbour = lookup_neighbour (&aqm->receiver);
9307 if (NULL == neighbour)
9309 neighbour = GNUNET_new (struct Neighbour);
9310 neighbour->pid = aqm->receiver;
9311 GNUNET_assert (GNUNET_OK ==
9312 GNUNET_CONTAINER_multipeermap_put (
9316 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9318 GNUNET_PEERSTORE_iterate (peerstore,
9321 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
9322 &neighbour_dv_monotime_cb,
9325 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
9326 addr = (const char *) &aqm[1];
9327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9328 "New queue %s to %s available with QID %llu\n",
9330 GNUNET_i2s (&aqm->receiver),
9331 (unsigned long long) aqm->qid);
9332 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
9334 queue->address = (const char *) &queue[1];
9335 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
9336 queue->qid = aqm->qid;
9337 queue->mtu = ntohl (aqm->mtu);
9338 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
9339 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
9340 queue->neighbour = neighbour;
9341 queue->idle = GNUNET_YES;
9342 memcpy (&queue[1], addr, addr_len);
9343 /* notify monitors about new queue */
9345 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
9347 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
9349 GNUNET_CONTAINER_MDLL_insert (neighbour,
9350 neighbour->queue_head,
9351 neighbour->queue_tail,
9353 GNUNET_CONTAINER_MDLL_insert (client,
9354 tc->details.communicator.queue_head,
9355 tc->details.communicator.queue_tail,
9357 /* check if valdiations are waiting for the queue */
9359 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9361 &check_validation_request_pending,
9363 /* look for traffic for this queue */
9364 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9365 /* might be our first queue, try launching DV learning */
9366 if (NULL == dvlearn_task)
9367 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
9368 GNUNET_SERVICE_client_continue (tc->client);
9373 * Communicator tells us that our request to create a queue "worked", that
9374 * is setting up the queue is now in process.
9376 * @param cls the `struct TransportClient`
9377 * @param cqr confirmation message
9380 handle_queue_create_ok (void *cls,
9381 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9383 struct TransportClient *tc = cls;
9385 if (CT_COMMUNICATOR != tc->type)
9388 GNUNET_SERVICE_client_drop (tc->client);
9391 GNUNET_STATISTICS_update (GST_stats,
9392 "# Suggestions succeeded at communicator",
9395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9396 "Request #%u for communicator to create queue succeeded\n",
9397 (unsigned int) ntohs (cqr->request_id));
9398 GNUNET_SERVICE_client_continue (tc->client);
9403 * Communicator tells us that our request to create a queue failed. This
9404 * usually indicates that the provided address is simply invalid or that the
9405 * communicator's resources are exhausted.
9407 * @param cls the `struct TransportClient`
9408 * @param cqr failure message
9411 handle_queue_create_fail (
9413 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9415 struct TransportClient *tc = cls;
9417 if (CT_COMMUNICATOR != tc->type)
9420 GNUNET_SERVICE_client_drop (tc->client);
9423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9424 "Request #%u for communicator to create queue failed\n",
9425 (unsigned int) ntohs (cqr->request_id));
9426 GNUNET_STATISTICS_update (GST_stats,
9427 "# Suggestions failed in queue creation at communicator",
9430 GNUNET_SERVICE_client_continue (tc->client);
9435 * We have received a `struct ExpressPreferenceMessage` from an application
9438 * @param cls handle to the client
9439 * @param msg the start message
9442 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
9444 struct TransportClient *tc = cls;
9445 struct PeerRequest *pr;
9447 if (CT_APPLICATION != tc->type)
9450 GNUNET_SERVICE_client_drop (tc->client);
9453 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
9458 GNUNET_SERVICE_client_drop (tc->client);
9461 (void) stop_peer_request (tc, &pr->pid, pr);
9462 GNUNET_SERVICE_client_continue (tc->client);
9467 * Function called by PEERSTORE for each matching record.
9469 * @param cls closure, a `struct PeerRequest`
9470 * @param record peerstore record information
9471 * @param emsg error message, or NULL if no errors
9474 handle_hello_for_client (void *cls,
9475 const struct GNUNET_PEERSTORE_Record *record,
9478 struct PeerRequest *pr = cls;
9483 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9484 "Got failure from PEERSTORE: %s\n",
9488 val = record->value;
9489 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
9494 start_address_validation (&pr->pid, (const char *) record->value);
9499 * We have received a `struct ExpressPreferenceMessage` from an application
9502 * @param cls handle to the client
9503 * @param msg the start message
9506 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9508 struct TransportClient *tc = cls;
9509 struct PeerRequest *pr;
9511 if (CT_NONE == tc->type)
9513 tc->type = CT_APPLICATION;
9514 tc->details.application.requests =
9515 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9517 if (CT_APPLICATION != tc->type)
9520 GNUNET_SERVICE_client_drop (tc->client);
9523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9524 "Client suggested we talk to %s with preference %d at rate %u\n",
9525 GNUNET_i2s (&msg->peer),
9526 (int) ntohl (msg->pk),
9527 (int) ntohl (msg->bw.value__));
9528 pr = GNUNET_new (struct PeerRequest);
9530 pr->pid = msg->peer;
9532 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
9533 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
9534 tc->details.application.requests,
9537 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
9541 GNUNET_SERVICE_client_drop (tc->client);
9544 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
9547 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9548 &handle_hello_for_client,
9550 GNUNET_SERVICE_client_continue (tc->client);
9555 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
9558 * @param cls a `struct TransportClient *`
9559 * @param m message to verify
9560 * @return #GNUNET_OK on success
9563 check_request_hello_validation (void *cls,
9564 const struct RequestHelloValidationMessage *m)
9567 GNUNET_MQ_check_zero_termination (m);
9573 * A client encountered an address of another peer. Consider validating it,
9574 * and if validation succeeds, persist it to PEERSTORE.
9576 * @param cls a `struct TransportClient *`
9577 * @param m message to verify
9580 handle_request_hello_validation (void *cls,
9581 const struct RequestHelloValidationMessage *m)
9583 struct TransportClient *tc = cls;
9585 start_address_validation (&m->peer, (const char *) &m[1]);
9586 GNUNET_SERVICE_client_continue (tc->client);
9591 * Free neighbour entry.
9595 * @param value a `struct Neighbour`
9596 * @return #GNUNET_OK (always)
9599 free_neighbour_cb (void *cls,
9600 const struct GNUNET_PeerIdentity *pid,
9603 struct Neighbour *neighbour = value;
9607 GNUNET_break (0); // should this ever happen?
9608 free_neighbour (neighbour);
9615 * Free DV route entry.
9619 * @param value a `struct DistanceVector`
9620 * @return #GNUNET_OK (always)
9623 free_dv_routes_cb (void *cls,
9624 const struct GNUNET_PeerIdentity *pid,
9627 struct DistanceVector *dv = value;
9638 * Free validation state.
9642 * @param value a `struct ValidationState`
9643 * @return #GNUNET_OK (always)
9646 free_validation_state_cb (void *cls,
9647 const struct GNUNET_PeerIdentity *pid,
9650 struct ValidationState *vs = value;
9654 free_validation_state (vs);
9660 * Free pending acknowledgement.
9664 * @param value a `struct PendingAcknowledgement`
9665 * @return #GNUNET_OK (always)
9668 free_pending_ack_cb (void *cls,
9669 const struct GNUNET_ShortHashCode *key,
9672 struct PendingAcknowledgement *pa = value;
9676 free_pending_acknowledgement (pa);
9682 * Free acknowledgement cummulator.
9686 * @param value a `struct AcknowledgementCummulator`
9687 * @return #GNUNET_OK (always)
9690 free_ack_cummulator_cb (void *cls,
9691 const struct GNUNET_PeerIdentity *pid,
9694 struct AcknowledgementCummulator *ac = value;
9704 * Function called when the service shuts down. Unloads our plugins
9705 * and cancels pending validations.
9707 * @param cls closure, unused
9710 do_shutdown (void *cls)
9712 struct LearnLaunchEntry *lle;
9715 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9716 if (NULL != peerstore)
9718 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9721 if (NULL != GST_stats)
9723 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9726 if (NULL != GST_my_private_key)
9728 GNUNET_free (GST_my_private_key);
9729 GST_my_private_key = NULL;
9731 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9732 &free_ack_cummulator_cb,
9734 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9735 ack_cummulators = NULL;
9736 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
9737 &free_pending_ack_cb,
9739 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
9740 pending_acks = NULL;
9741 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9742 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9744 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9745 GNUNET_CONTAINER_multipeermap_destroy (links);
9747 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9748 &free_backtalker_cb,
9750 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9752 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9753 &free_validation_state_cb,
9755 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9756 validation_map = NULL;
9757 while (NULL != ir_head)
9758 free_incoming_request (ir_head);
9759 GNUNET_assert (0 == ir_total);
9760 while (NULL != (lle = lle_head))
9762 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9765 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
9767 GNUNET_CONTAINER_heap_destroy (validation_heap);
9768 validation_heap = NULL;
9769 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
9770 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
9776 * Initiate transport service.
9778 * @param cls closure
9779 * @param c configuration to use
9780 * @param service the initialized service
9784 const struct GNUNET_CONFIGURATION_Handle *c,
9785 struct GNUNET_SERVICE_Handle *service)
9790 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
9792 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9793 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
9794 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
9795 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9796 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
9797 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9798 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
9800 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9802 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
9803 GST_my_private_key =
9804 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
9805 if (NULL == GST_my_private_key)
9808 GNUNET_ERROR_TYPE_ERROR,
9810 "Transport service is lacking key configuration settings. Exiting.\n"));
9811 GNUNET_SCHEDULER_shutdown ();
9814 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
9815 &GST_my_identity.public_key);
9816 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9817 "My identity is `%s'\n",
9818 GNUNET_i2s_full (&GST_my_identity));
9819 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
9820 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
9821 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
9822 if (NULL == peerstore)
9825 GNUNET_SCHEDULER_shutdown ();
9832 * Define "main" method using service macro.
9834 GNUNET_SERVICE_MAIN (
9836 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
9839 &client_disconnect_cb,
9841 /* communication with applications */
9842 GNUNET_MQ_hd_fixed_size (suggest,
9843 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
9844 struct ExpressPreferenceMessage,
9846 GNUNET_MQ_hd_fixed_size (suggest_cancel,
9847 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
9848 struct ExpressPreferenceMessage,
9850 GNUNET_MQ_hd_var_size (request_hello_validation,
9851 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
9852 struct RequestHelloValidationMessage,
9854 /* communication with core */
9855 GNUNET_MQ_hd_fixed_size (client_start,
9856 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
9857 struct StartMessage,
9859 GNUNET_MQ_hd_var_size (client_send,
9860 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
9861 struct OutboundMessage,
9863 GNUNET_MQ_hd_fixed_size (client_recv_ok,
9864 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
9865 struct RecvOkMessage,
9867 /* communication with communicators */
9868 GNUNET_MQ_hd_var_size (communicator_available,
9869 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
9870 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
9872 GNUNET_MQ_hd_var_size (communicator_backchannel,
9873 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
9874 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
9876 GNUNET_MQ_hd_var_size (add_address,
9877 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
9878 struct GNUNET_TRANSPORT_AddAddressMessage,
9880 GNUNET_MQ_hd_fixed_size (del_address,
9881 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
9882 struct GNUNET_TRANSPORT_DelAddressMessage,
9884 GNUNET_MQ_hd_var_size (incoming_msg,
9885 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
9886 struct GNUNET_TRANSPORT_IncomingMessage,
9888 GNUNET_MQ_hd_fixed_size (queue_create_ok,
9889 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
9890 struct GNUNET_TRANSPORT_CreateQueueResponse,
9892 GNUNET_MQ_hd_fixed_size (queue_create_fail,
9893 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
9894 struct GNUNET_TRANSPORT_CreateQueueResponse,
9896 GNUNET_MQ_hd_var_size (add_queue_message,
9897 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
9898 struct GNUNET_TRANSPORT_AddQueueMessage,
9900 GNUNET_MQ_hd_fixed_size (del_queue_message,
9901 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
9902 struct GNUNET_TRANSPORT_DelQueueMessage,
9904 GNUNET_MQ_hd_fixed_size (send_message_ack,
9905 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
9906 struct GNUNET_TRANSPORT_SendMessageToAck,
9908 /* communication with monitors */
9909 GNUNET_MQ_hd_fixed_size (monitor_start,
9910 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
9911 struct GNUNET_TRANSPORT_MonitorStart,
9913 GNUNET_MQ_handler_end ());
9916 /* end of file gnunet-service-transport.c */