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 * - review retransmission logic, right now there is no smartness there!
28 * => congestion control, etc [PERFORMANCE-BASICS]
30 * Optimizations-Statistics:
31 * - Track ACK losses based on ACK-counter [ROUTING]
32 * - Need to track total bandwidth per VirtualLink and adjust how frequently
33 * we send FC messages based on bandwidth-delay-product (and relation
34 * to the window size!). See OPTIMIZE-FC-BDP.
35 * - Consider more statistics in #check_connection_quality() [FIXME-CONQ-STATISTICS]
36 * - Adapt available_fc_window_size, using larger values for high-bandwidth
37 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
38 * - Set last_window_consum_limit promise properly based on
39 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
42 * - When forwarding DV learn messages, if a peer is reached that
43 * has a *bidirectional* link to the origin beyond 1st hop,
44 * do NOT forward it to peers _other_ than the origin, as
45 * there is clearly a better path directly from the origin to
46 * whatever else we could reach.
47 * - When we passively learned DV (with unconfirmed freshness), we
48 * right now add the path to our list but with a zero path_valid_until
49 * time and only use it for unconfirmed routes. However, we could consider
50 * triggering an explicit validation mechansim ourselves, specifically routing
51 * a challenge-response message over the path [ROUTING]
52 * = if available, try to confirm unconfirmed DV paths when trying to establish
53 * virtual link for a `struct IncomingRequest`. (i.e. if DVH is
54 * unconfirmed, incoming requests cause us to try to validate a passively
55 * learned path (requires new message type!))
57 * Optimizations-Fragmentation:
58 * - Fragments send over a reliable channel could do without the
59 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
60 * (-> have 2nd type of acknowledgment message; low priority, as we
61 * do not have an MTU-limited *reliable* communicator) [FIXME-FRAG-REL-UUID]
62 * - if messages are below MTU, consider adding ACKs and other stuff
63 * to the same transmission to avoid tiny messages (requires planning at
64 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
66 * Optimizations-internals:
67 * - queue_send_msg by API design has to make a copy
68 * of the payload, and route_message on top of that requires a malloc/free.
69 * Change design to approximate "zero" copy better... [CPU]
70 * - could avoid copying body of message into each fragment and keep
71 * fragments as just pointers into the original message and only
72 * fully build fragments just before transmission (optimization, should
73 * reduce CPU and memory use) [CPU, MEMORY]
76 #include "gnunet_util_lib.h"
77 #include "gnunet_statistics_service.h"
78 #include "gnunet_transport_monitor_service.h"
79 #include "gnunet_peerstore_service.h"
80 #include "gnunet_hello_lib.h"
81 #include "gnunet_signatures.h"
82 #include "transport.h"
85 * Maximum number of messages we acknowledge together in one
86 * cummulative ACK. Larger values may save a bit of bandwidth.
88 #define MAX_CUMMULATIVE_ACKS 64
91 * What is the 1:n chance that we send a Flow control response when
92 * receiving a flow control message that did not change anything for
93 * us? Basically, this is used in the case where both peers are stuck
94 * on flow control (no window changes), but one might continue sending
95 * flow control messages to the other peer as the first FC message
96 * when things stalled got lost, and then subsequently the other peer
97 * does *usually* not respond as nothing changed. So to ensure that
98 * eventually the FC messages stop, we do send with 1/8th probability
99 * an FC message even if nothing changed. That prevents one peer
100 * being stuck in sending (useless) FC messages "forever".
102 #define FC_NO_CHANGE_REPLY_PROBABILITY 8
105 * What is the size we assume for a read operation in the
106 * absence of an MTU for the purpose of flow control?
108 #define IN_PACKET_SIZE_WITHOUT_MTU 128
111 * Number of slots we keep of historic data for computation of
112 * goodput / message loss ratio.
114 #define GOODPUT_AGING_SLOTS 4
117 * How big is the flow control window size by default;
118 * limits per-neighbour RAM utilization.
120 #define DEFAULT_WINDOW_SIZE (128 * 1024)
123 * For how many incoming connections do we try to create a
124 * virtual link for (at the same time!). This does NOT
125 * limit the number of incoming connections, just the number
126 * for which we are actively trying to find working addresses
127 * in the absence (!) of our own applications wanting the
130 #define MAX_INCOMING_REQUEST 16
133 * Maximum number of peers we select for forwarding DVInit
134 * messages at the same time (excluding initiator).
136 #define MAX_DV_DISCOVERY_SELECTION 16
139 * Window size. How many messages to the same target do we pass
140 * to CORE without a RECV_OK in between? Small values limit
141 * thoughput, large values will increase latency.
143 * FIXME-OPTIMIZE: find out what good values are experimentally,
144 * maybe set adaptively (i.e. to observed available bandwidth).
146 #define RECV_WINDOW_SIZE 4
149 * Minimum number of hops we should forward DV learn messages
150 * even if they are NOT useful for us in hope of looping
151 * back to the initiator?
153 * FIXME: allow initiator some control here instead?
155 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
158 * Maximum DV distance allowed ever.
160 #define MAX_DV_HOPS_ALLOWED 16
163 * Maximum number of DV learning activities we may
164 * have pending at the same time.
166 #define MAX_DV_LEARN_PENDING 64
169 * Maximum number of DV paths we keep simultaneously to the same target.
171 #define MAX_DV_PATHS_TO_TARGET 3
174 * If a queue delays the next message by more than this number
175 * of seconds we log a warning. Note: this is for testing,
176 * the value chosen here might be too aggressively low!
178 #define DELAY_WARN_THRESHOLD \
179 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
182 * If a DVBox could not be forwarded after this number of
183 * seconds we drop it.
185 #define DV_FORWARD_TIMEOUT \
186 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
189 * We only consider queues as "quality" connections when
190 * suppressing the generation of DV initiation messages if
191 * the latency of the queue is below this threshold.
193 #define DV_QUALITY_RTT_THRESHOLD \
194 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
197 * How long do we consider a DV path valid if we see no
198 * further updates on it? Note: the value chosen here might be too low!
200 #define DV_PATH_VALIDITY_TIMEOUT \
201 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
204 * How long do we cache backchannel (struct Backtalker) information
205 * after a backchannel goes inactive?
207 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
208 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
211 * How long before paths expire would we like to (re)discover DV paths? Should
212 * be below #DV_PATH_VALIDITY_TIMEOUT.
214 #define DV_PATH_DISCOVERY_FREQUENCY \
215 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
218 * How long are ephemeral keys valid?
220 #define EPHEMERAL_VALIDITY \
221 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
224 * How long do we keep partially reassembled messages around before giving up?
226 #define REASSEMBLY_EXPIRATION \
227 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
230 * What is the fastest rate at which we send challenges *if* we keep learning
231 * an address (gossip, DHT, etc.)?
233 #define FAST_VALIDATION_CHALLENGE_FREQ \
234 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
237 * What is the slowest rate at which we send challenges?
239 #define MAX_VALIDATION_CHALLENGE_FREQ \
240 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
243 * How long until we forget about historic accumulators and thus
244 * reset the ACK counter? Should exceed the maximum time an
245 * active connection experiences without an ACK.
247 #define ACK_CUMMULATOR_TIMEOUT \
248 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
251 * What is the non-randomized base frequency at which we
252 * would initiate DV learn messages?
254 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
257 * How many good connections (confirmed, bi-directional, not DV)
258 * do we need to have to suppress initiating DV learn messages?
260 #define DV_LEARN_QUALITY_THRESHOLD 100
263 * When do we forget an invalid address for sure?
265 #define MAX_ADDRESS_VALID_UNTIL \
266 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
269 * How long do we consider an address valid if we just checked?
271 #define ADDRESS_VALIDATION_LIFETIME \
272 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
275 * What is the maximum frequency at which we do address validation?
276 * A random value between 0 and this value is added when scheduling
277 * the #validation_task (both to ensure we do not validate too often,
278 * and to randomize a bit).
280 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
283 * How many network RTTs before an address validation expires should we begin
284 * trying to revalidate? (Note that the RTT used here is the one that we
285 * experienced during the last validation, not necessarily the latest RTT
288 #define VALIDATION_RTT_BUFFER_FACTOR 3
291 * How many messages can we have pending for a given communicator
292 * process before we start to throttle that communicator?
294 * Used if a communicator might be CPU-bound and cannot handle the traffic.
296 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
299 * How many messages can we have pending for a given queue (queue to
300 * a particular peer via a communicator) process before we start to
301 * throttle that queue?
303 #define QUEUE_LENGTH_LIMIT 32
306 GNUNET_NETWORK_STRUCT_BEGIN
309 * Unique identifier we attach to a message.
314 * Unique value, generated by incrementing the
315 * `message_uuid_ctr` of `struct Neighbour`.
317 uint64_t uuid GNUNET_PACKED;
322 * Unique identifier to map an acknowledgement to a transmission.
324 struct AcknowledgementUUIDP
329 struct GNUNET_Uuid value;
334 * Type of a nonce used for challenges.
336 struct ChallengeNonceP
339 * The value of the nonce. Note that this is NOT a hash.
341 struct GNUNET_ShortHashCode value;
346 * Outer layer of an encapsulated backchannel message.
348 struct TransportBackchannelEncapsulationMessage
351 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
353 struct GNUNET_MessageHeader header;
355 /* Followed by *another* message header which is the message to
358 /* Followed by a 0-terminated name of the communicator */
363 * Body by which a peer confirms that it is using an ephemeral key.
365 struct EphemeralConfirmationPS
368 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
370 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
373 * How long is this signature over the ephemeral key valid?
375 * Note that the receiver MUST IGNORE the absolute time, and only interpret
376 * the value as a mononic time and reject "older" values than the last one
377 * observed. This is necessary as we do not want to require synchronized
378 * clocks and may not have a bidirectional communication channel.
380 * Even with this, there is no real guarantee against replay achieved here,
381 * unless the latest timestamp is persisted. While persistence should be
382 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
383 * communicators must protect against replay attacks when using backchannel
386 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
389 * Target's peer identity.
391 struct GNUNET_PeerIdentity target;
394 * Ephemeral key setup by the sender for @e target, used
395 * to encrypt the payload.
397 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
402 * Plaintext of the variable-size payload that is encrypted
403 * within a `struct TransportBackchannelEncapsulationMessage`
405 struct TransportDVBoxPayloadP
408 * Sender's peer identity.
410 struct GNUNET_PeerIdentity sender;
413 * Signature of the sender over an
414 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
416 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
419 * Current monotonic time of the sending transport service. Used to
420 * detect replayed messages. Note that the receiver should remember
421 * a list of the recently seen timestamps and only reject messages
422 * if the timestamp is in the list, or the list is "full" and the
423 * timestamp is smaller than the lowest in the list.
425 * Like the @e ephemeral_validity, the list of timestamps per peer should be
426 * persisted to guard against replays after restarts.
428 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
430 /* Followed by a `struct GNUNET_MessageHeader` with a message
431 for the target peer */
436 * Outer layer of an encapsulated unfragmented application message sent
437 * over an unreliable channel.
439 struct TransportReliabilityBoxMessage
442 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
444 struct GNUNET_MessageHeader header;
447 * Number of messages still to be sent before a commulative
448 * ACK is requested. Zero if an ACK is requested immediately.
449 * In NBO. Note that the receiver may send the ACK faster
450 * if it believes that is reasonable.
452 uint32_t ack_countdown GNUNET_PACKED;
455 * Unique ID of the message used for signalling receipt of
456 * messages sent over possibly unreliable channels. Should
459 struct AcknowledgementUUIDP ack_uuid;
464 * Acknowledgement payload.
466 struct TransportCummulativeAckPayloadP
469 * How long was the ACK delayed for generating cummulative ACKs?
470 * Used to calculate the correct network RTT by taking the receipt
471 * time of the ack minus the transmission time of the sender minus
474 struct GNUNET_TIME_RelativeNBO ack_delay;
477 * UUID of a message being acknowledged.
479 struct AcknowledgementUUIDP ack_uuid;
484 * Confirmation that the receiver got a
485 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
486 * confirmation may be transmitted over a completely different queue,
487 * so ACKs are identified by a combination of PID of sender and
488 * message UUID, without the queue playing any role!
490 struct TransportReliabilityAckMessage
493 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
495 struct GNUNET_MessageHeader header;
498 * Counter of ACKs transmitted by the sender to us. Incremented
499 * by one for each ACK, used to detect how many ACKs were lost.
501 uint32_t ack_counter GNUNET_PACKED;
503 /* followed by any number of `struct TransportCummulativeAckPayloadP`
504 messages providing ACKs */
509 * Outer layer of an encapsulated fragmented application message.
511 struct TransportFragmentBoxMessage
514 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
516 struct GNUNET_MessageHeader header;
519 * Offset of this fragment in the overall message.
521 uint16_t frag_off GNUNET_PACKED;
524 * Total size of the message that is being fragmented.
526 uint16_t msg_size GNUNET_PACKED;
529 * Unique ID of this fragment (and fragment transmission!). Will
530 * change even if a fragement is retransmitted to make each
531 * transmission attempt unique! If a client receives a duplicate
532 * fragment (same @e frag_off for same @a msg_uuid, it must send
533 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
535 struct AcknowledgementUUIDP ack_uuid;
538 * Original message ID for of the message that all the fragments
539 * belong to. Must be the same for all fragments.
541 struct MessageUUIDP msg_uuid;
546 * Content signed by the initator during DV learning.
548 * The signature is required to prevent DDoS attacks. A peer sending out this
549 * message is potentially generating a lot of traffic that will go back to the
550 * initator, as peers receiving this message will try to let the initiator
551 * know that they got the message.
553 * Without this signature, an attacker could abuse this mechanism for traffic
554 * amplification, sending a lot of traffic to a peer by putting out this type
555 * of message with the victim's peer identity.
557 * Even with just a signature, traffic amplification would be possible via
558 * replay attacks. The @e monotonic_time limits such replay attacks, as every
559 * potential amplificator will check the @e monotonic_time and only respond
560 * (at most) once per message.
565 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
567 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
570 * Time at the initiator when generating the signature.
572 * Note that the receiver MUST IGNORE the absolute time, and only interpret
573 * the value as a mononic time and reject "older" values than the last one
574 * observed. This is necessary as we do not want to require synchronized
575 * clocks and may not have a bidirectional communication channel.
577 * Even with this, there is no real guarantee against replay achieved here,
578 * unless the latest timestamp is persisted. Persistence should be
579 * provided via PEERSTORE if possible.
581 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
584 * Challenge value used by the initiator to re-identify the path.
586 struct ChallengeNonceP challenge;
591 * Content signed by each peer during DV learning.
593 * This assues the initiator of the DV learning operation that the hop from @e
594 * pred via the signing peer to @e succ actually exists. This makes it
595 * impossible for an adversary to supply the network with bogus routes.
597 * The @e challenge is included to provide replay protection for the
598 * initiator. This way, the initiator knows that the hop existed after the
599 * original @e challenge was first transmitted, providing a freshness metric.
601 * Peers other than the initiator that passively learn paths by observing
602 * these messages do NOT benefit from this. Here, an adversary may indeed
603 * replay old messages. Thus, passively learned paths should always be
604 * immediately marked as "potentially stale".
609 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
611 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
614 * Identity of the previous peer on the path.
616 struct GNUNET_PeerIdentity pred;
619 * Identity of the next peer on the path.
621 struct GNUNET_PeerIdentity succ;
624 * Challenge value used by the initiator to re-identify the path.
626 struct ChallengeNonceP challenge;
631 * An entry describing a peer on a path in a
632 * `struct TransportDVLearnMessage` message.
637 * Identity of a peer on the path.
639 struct GNUNET_PeerIdentity hop;
642 * Signature of this hop over the path, of purpose
643 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
645 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
650 * Internal message used by transport for distance vector learning.
651 * If @e num_hops does not exceed the threshold, peers should append
652 * themselves to the peer list and flood the message (possibly only
653 * to a subset of their neighbours to limit discoverability of the
654 * network topology). To the extend that the @e bidirectional bits
655 * are set, peers may learn the inverse paths even if they did not
658 * Unless received on a bidirectional queue and @e num_hops just
659 * zero, peers that can forward to the initator should always try to
660 * forward to the initiator.
662 struct TransportDVLearnMessage
665 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
667 struct GNUNET_MessageHeader header;
670 * Number of hops this messages has travelled, in NBO. Zero if
673 uint16_t num_hops GNUNET_PACKED;
676 * Bitmask of the last 16 hops indicating whether they are confirmed
677 * available (without DV) in both directions or not, in NBO. Used
678 * to possibly instantly learn a path in both directions. Each peer
679 * should shift this value by one to the left, and then set the
680 * lowest bit IF the current sender can be reached from it (without
683 uint16_t bidirectional GNUNET_PACKED;
686 * Peers receiving this message and delaying forwarding to other
687 * peers for any reason should increment this value by the non-network
688 * delay created by the peer.
690 struct GNUNET_TIME_RelativeNBO non_network_delay;
693 * Time at the initiator when generating the signature.
695 * Note that the receiver MUST IGNORE the absolute time, and only interpret
696 * the value as a mononic time and reject "older" values than the last one
697 * observed. This is necessary as we do not want to require synchronized
698 * clocks and may not have a bidirectional communication channel.
700 * Even with this, there is no real guarantee against replay achieved here,
701 * unless the latest timestamp is persisted. Persistence should be
702 * provided via PEERSTORE if possible.
704 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
707 * Signature of this hop over the path, of purpose
708 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
710 struct GNUNET_CRYPTO_EddsaSignature init_sig;
713 * Identity of the peer that started this learning activity.
715 struct GNUNET_PeerIdentity initiator;
718 * Challenge value used by the initiator to re-identify the path.
720 struct ChallengeNonceP challenge;
722 /* Followed by @e num_hops `struct DVPathEntryP` values,
723 excluding the initiator of the DV trace; the last entry is the
724 current sender; the current peer must not be included. */
729 * Outer layer of an encapsulated message send over multiple hops.
730 * The path given only includes the identities of the subsequent
731 * peers, i.e. it will be empty if we are the receiver. Each
732 * forwarding peer should scan the list from the end, and if it can,
733 * forward to the respective peer. The list should then be shortened
734 * by all the entries up to and including that peer. Each hop should
735 * also increment @e total_hops to allow the receiver to get a precise
736 * estimate on the number of hops the message travelled. Senders must
737 * provide a learned path that thus should work, but intermediaries
738 * know of a shortcut, they are allowed to send the message via that
741 * If a peer finds itself still on the list, it must drop the message.
743 * The payload of the box can only be decrypted and verified by the
744 * ultimate receiver. Intermediaries do not learn the sender's
745 * identity and the path the message has taken. However, the first
746 * hop does learn the sender as @e total_hops would be zero and thus
747 * the predecessor must be the origin (so this is not really useful
748 * for anonymization).
750 struct TransportDVBoxMessage
753 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
755 struct GNUNET_MessageHeader header;
758 * Number of total hops this messages travelled. In NBO.
759 * @e origin sets this to zero, to be incremented at
760 * each hop. Peers should limit the @e total_hops value
761 * they accept from other peers.
763 uint16_t total_hops GNUNET_PACKED;
766 * Number of hops this messages includes. In NBO. Reduced by one
767 * or more at each hop. Peers should limit the @e num_hops value
768 * they accept from other peers.
770 uint16_t num_hops GNUNET_PACKED;
773 * Ephemeral key setup by the sender for target, used to encrypt the
774 * payload. Intermediaries must not change this value.
776 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
779 * We use an IV here as the @e ephemeral_key is re-used for
780 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
781 * Intermediaries must not change this value.
783 struct GNUNET_ShortHashCode iv;
786 * HMAC over the ciphertext of the encrypted, variable-size body
787 * that follows. Verified via DH of target and @e ephemeral_key.
788 * Intermediaries must not change this value.
790 struct GNUNET_HashCode hmac;
792 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
793 excluding the @e origin and the current peer, the last must be
794 the ultimate target; if @e num_hops is zero, the receiver of this
795 message is the ultimate target. */
797 /* Followed by encrypted, variable-size payload, which
798 must begin with a `struct TransportDVBoxPayloadP` */
800 /* Followed by the actual message, which itself must not be a
801 a DV_LEARN or DV_BOX message! */
806 * Message send to another peer to validate that it can indeed
807 * receive messages at a particular address.
809 struct TransportValidationChallengeMessage
812 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
814 struct GNUNET_MessageHeader header;
819 uint32_t reserved GNUNET_PACKED;
822 * Challenge to be signed by the receiving peer.
824 struct ChallengeNonceP challenge;
827 * Timestamp of the sender, to be copied into the reply to allow
828 * sender to calculate RTT. Must be monotonically increasing!
830 struct GNUNET_TIME_AbsoluteNBO sender_time;
835 * Message signed by a peer to confirm that it can indeed
836 * receive messages at a particular address.
838 struct TransportValidationPS
841 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
843 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
846 * How long does the sender believe the address on
847 * which the challenge was received to remain valid?
849 struct GNUNET_TIME_RelativeNBO validity_duration;
852 * Challenge signed by the receiving peer.
854 struct ChallengeNonceP challenge;
859 * Message send to a peer to respond to a
860 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
862 struct TransportValidationResponseMessage
865 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
867 struct GNUNET_MessageHeader header;
872 uint32_t reserved GNUNET_PACKED;
875 * The peer's signature matching the
876 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
878 struct GNUNET_CRYPTO_EddsaSignature signature;
881 * The challenge that was signed by the receiving peer.
883 struct ChallengeNonceP challenge;
886 * Original timestamp of the sender (was @code{sender_time}),
887 * copied into the reply to allow sender to calculate RTT.
889 struct GNUNET_TIME_AbsoluteNBO origin_time;
892 * How long does the sender believe this address to remain
895 struct GNUNET_TIME_RelativeNBO validity_duration;
900 * Message for Transport-to-Transport Flow control. Specifies the size
901 * of the flow control window, including how much we believe to have
902 * consumed (at transmission time), how much we believe to be allowed
903 * (at transmission time), and how much the other peer is allowed to
904 * send to us, and how much data we already received from the other
907 struct TransportFlowControlMessage
910 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
912 struct GNUNET_MessageHeader header;
915 * Sequence number of the flow control message. Incremented by one
916 * for each message. Starts at zero when a virtual link goes up.
917 * Used to detect one-sided connection drops. On wrap-around, the
918 * flow control counters will be reset as if the connection had
921 uint32_t seq GNUNET_PACKED;
924 * Flow control window size in bytes, in NBO.
925 * The receiver can send this many bytes at most.
927 uint64_t inbound_window_size GNUNET_PACKED;
930 * How many bytes has the sender sent that count for flow control at
931 * this time. Used to allow the receiver to estimate the packet
934 uint64_t outbound_sent GNUNET_PACKED;
937 * Latest flow control window size we learned from the other peer,
938 * in bytes, in NBO. We are limited to sending at most this many
939 * bytes to the other peer. May help the other peer detect when
940 * flow control messages were lost and should thus be retransmitted.
941 * In particular, if the delta to @e outbound_sent is too small,
942 * this signals that we are stalled.
944 uint64_t outbound_window_size GNUNET_PACKED;
947 * Timestamp of the sender. Must be monotonically increasing!
948 * Used to enable receiver to ignore out-of-order packets in
949 * combination with the @e seq. Note that @e seq will go down
950 * (back to zero) whenever either side believes the connection
951 * was dropped, allowing the peers to detect that they need to
952 * reset the counters for the number of bytes sent!
954 struct GNUNET_TIME_AbsoluteNBO sender_time;
958 GNUNET_NETWORK_STRUCT_END
962 * What type of client is the `struct TransportClient` about?
967 * We do not know yet (client is fresh).
972 * Is the CORE service, we need to forward traffic to it.
977 * It is a monitor, forward monitor data.
982 * It is a communicator, use for communication.
987 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
994 * Which transmission options are allowable for transmission?
995 * Interpreted bit-wise!
997 enum RouteMessageOptions
1000 * Only confirmed, non-DV direct neighbours.
1005 * We are allowed to use DV routing for this @a hdr
1010 * We are allowed to use unconfirmed queues or DV routes for this message
1012 RMO_UNCONFIRMED_ALLOWED = 2,
1015 * Reliable and unreliable, DV and non-DV are all acceptable.
1017 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1020 * If we have multiple choices, it is OK to send this message
1021 * over multiple channels at the same time to improve loss tolerance.
1022 * (We do at most 2 transmissions.)
1029 * When did we launch this DV learning activity?
1031 struct LearnLaunchEntry
1034 * Kept (also) in a DLL sorted by launch time.
1036 struct LearnLaunchEntry *prev;
1039 * Kept (also) in a DLL sorted by launch time.
1041 struct LearnLaunchEntry *next;
1044 * Challenge that uniquely identifies this activity.
1046 struct ChallengeNonceP challenge;
1049 * When did we transmit the DV learn message (used to calculate RTT) and
1050 * determine freshness of paths learned via this operation.
1052 struct GNUNET_TIME_Absolute launch_time;
1057 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1058 * (or current) transmission performance.
1060 struct TransmissionHistoryEntry
1063 * Number of bytes actually sent in the interval.
1065 uint64_t bytes_sent;
1068 * Number of bytes received and acknowledged by the other peer in
1071 uint64_t bytes_received;
1076 * Performance data for a transmission possibility.
1078 struct PerformanceData
1081 * Weighted average for the RTT.
1083 struct GNUNET_TIME_Relative aged_rtt;
1086 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1089 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1092 * What was the last age when we wrote to @e the? Used to clear
1093 * old entries when the age advances.
1095 unsigned int last_age;
1100 * Client connected to the transport service.
1102 struct TransportClient;
1105 * A neighbour that at least one communicator is connected to.
1110 * Entry in our #dv_routes table, representing a (set of) distance
1111 * vector routes to a particular peer.
1113 struct DistanceVector;
1116 * A queue is a message queue provided by a communicator
1117 * via which we can reach a particular neighbour.
1122 * Message awaiting transmission. See detailed comments below.
1124 struct PendingMessage;
1127 * One possible hop towards a DV target.
1129 struct DistanceVectorHop;
1132 * A virtual link is another reachable peer that is known to CORE. It
1133 * can be either a `struct Neighbour` with at least one confirmed
1134 * `struct Queue`, or a `struct DistanceVector` with at least one
1135 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1136 * data that is per neighbour that is not specific to how the
1137 * connectivity is established.
1143 * Context from #handle_incoming_msg(). Closure for many
1144 * message handlers below.
1146 struct CommunicatorMessageContext
1149 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1150 * flow control to unchoke.
1152 struct CommunicatorMessageContext *next;
1155 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1156 * flow control to unchoke.
1158 struct CommunicatorMessageContext *prev;
1161 * Which communicator provided us with the message.
1163 struct TransportClient *tc;
1166 * Additional information for flow control and about the sender.
1168 struct GNUNET_TRANSPORT_IncomingMessage im;
1171 * Number of hops the message has travelled (if DV-routed).
1172 * FIXME: make use of this in ACK handling!
1174 uint16_t total_hops;
1179 * Closure for #core_env_sent_cb.
1181 struct CoreSentContext
1184 * Kept in a DLL to clear @e vl in case @e vl is lost.
1186 struct CoreSentContext *next;
1189 * Kept in a DLL to clear @e vl in case @e vl is lost.
1191 struct CoreSentContext *prev;
1194 * Virtual link this is about.
1196 struct VirtualLink *vl;
1199 * How big was the message.
1204 * By how much should we increment @e vl's
1205 * incoming_fc_window_size_used once we are done sending to CORE?
1206 * Use to ensure we do not increment twice if there is more than one
1214 * A virtual link is another reachable peer that is known to CORE. It
1215 * can be either a `struct Neighbour` with at least one confirmed
1216 * `struct Queue`, or a `struct DistanceVector` with at least one
1217 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1218 * data that is per neighbour that is not specific to how the
1219 * connectivity is established.
1224 * Identity of the peer at the other end of the link.
1226 struct GNUNET_PeerIdentity target;
1229 * Communicators blocked for receiving on @e target as we are waiting
1230 * on the @e core_recv_window to increase.
1232 struct CommunicatorMessageContext *cmc_head;
1235 * Communicators blocked for receiving on @e target as we are waiting
1236 * on the @e core_recv_window to increase.
1238 struct CommunicatorMessageContext *cmc_tail;
1241 * Head of list of messages pending for this VL.
1243 struct PendingMessage *pending_msg_head;
1246 * Tail of list of messages pending for this VL.
1248 struct PendingMessage *pending_msg_tail;
1251 * Kept in a DLL to clear @e vl in case @e vl is lost.
1253 struct CoreSentContext *csc_tail;
1256 * Kept in a DLL to clear @e vl in case @e vl is lost.
1258 struct CoreSentContext *csc_head;
1261 * Task scheduled to possibly notfiy core that this peer is no
1262 * longer counting as confirmed. Runs the #core_visibility_check(),
1263 * which checks that some DV-path or a queue exists that is still
1264 * considered confirmed.
1266 struct GNUNET_SCHEDULER_Task *visibility_task;
1269 * Task scheduled to periodically retransmit FC messages (in
1270 * case one got lost).
1272 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1275 * Neighbour used by this virtual link, NULL if @e dv is used.
1277 struct Neighbour *n;
1280 * Distance vector used by this virtual link, NULL if @e n is used.
1282 struct DistanceVector *dv;
1285 * Sender timestamp of @e n_challenge, used to generate out-of-order
1286 * challenges (as sender's timestamps must be monotonically
1287 * increasing). FIXME: where do we need this?
1289 struct GNUNET_TIME_Absolute n_challenge_time;
1292 * When did we last send a
1293 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1294 * Used to determine whether it is time to re-transmit the message.
1296 struct GNUNET_TIME_Absolute last_fc_transmission;
1299 * Sender timestamp of the last
1300 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1301 * received. Note that we do not persist this monotonic time as we
1302 * do not really have to worry about ancient flow control window
1303 * sizes after restarts.
1305 struct GNUNET_TIME_Absolute last_fc_timestamp;
1308 * Expected RTT from the last FC transmission. (Zero if the last
1309 * attempt failed, but could theoretically be zero even on success.)
1311 struct GNUNET_TIME_Relative last_fc_rtt;
1314 * Used to generate unique UUIDs for messages that are being
1317 uint64_t message_uuid_ctr;
1320 * Memory allocated for this virtual link. Expresses how much RAM
1321 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1322 * Can be adapted to dedicate more RAM to links that need it, while
1323 * sticking to some overall RAM limit. For now, set to
1324 * #DEFAULT_WINDOW_SIZE.
1326 uint64_t available_fc_window_size;
1329 * Memory actually used to buffer packets on this virtual link.
1330 * Expresses how much RAM we are currently using for virtual link.
1331 * Note that once CORE is done with a packet, we decrement the value
1334 uint64_t incoming_fc_window_size_ram;
1337 * Last flow control window size we provided to the other peer, in
1338 * bytes. We are allowing the other peer to send this
1341 uint64_t incoming_fc_window_size;
1344 * How much of the window did the other peer successfully use (and
1345 * we already passed it on to CORE)? Must be below @e
1346 * incoming_fc_window_size. We should effectively signal the
1347 * other peer that the window is this much bigger at the next
1348 * opportunity / challenge.
1350 uint64_t incoming_fc_window_size_used;
1353 * What is our current estimate on the message loss rate for the sender?
1354 * Based on the difference between how much the sender sent according
1355 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1356 * (@e outbound_sent field) and how much we actually received at that
1357 * time (@e incoming_fc_window_size_used). This delta is then
1358 * added onto the @e incoming_fc_window_size when determining the
1359 * @e outbound_window_size we send to the other peer. Initially zero.
1360 * May be negative if we (due to out-of-order delivery) actually received
1361 * more than the sender claims to have sent in its last FC message.
1363 int64_t incoming_fc_window_size_loss;
1366 * Our current flow control window size in bytes. We
1367 * are allowed to transmit this many bytes to @a n.
1369 uint64_t outbound_fc_window_size;
1372 * How much of our current flow control window size have we
1373 * used (in bytes). Must be below
1374 * @e outbound_fc_window_size.
1376 uint64_t outbound_fc_window_size_used;
1379 * What is the most recent FC window the other peer sent us
1380 * in `outbound_window_size`? This is basically the window
1381 * size value the other peer has definitively received from
1382 * us. If it matches @e incoming_fc_window_size, we should
1383 * not send a FC message to increase the FC window. However,
1384 * we may still send an FC message to notify the other peer
1385 * that we received the other peer's FC message.
1387 uint64_t last_outbound_window_size_received;
1390 * Generator for the sequence numbers of
1391 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1393 uint32_t fc_seq_gen;
1396 * Last sequence number of a
1397 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1400 uint32_t last_fc_seq;
1403 * How many more messages can we send to CORE before we exhaust
1404 * the receive window of CORE for this peer? If this hits zero,
1405 * we must tell communicators to stop providing us more messages
1406 * for this peer. In fact, the window can go negative as we
1407 * have multiple communicators, so per communicator we can go
1408 * down by one into the negative range. Furthermore, we count
1409 * delivery per CORE client, so if we had multiple cores, that
1410 * might also cause a negative window size here (as one message
1411 * would decrement the window by one per CORE client).
1413 int core_recv_window;
1418 * Data structure kept when we are waiting for an acknowledgement.
1420 struct PendingAcknowledgement
1423 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1424 * is kept in relation to its pending message.
1426 struct PendingAcknowledgement *next_pm;
1429 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1430 * is kept in relation to its pending message.
1432 struct PendingAcknowledgement *prev_pm;
1435 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1436 * is kept in relation to the queue that was used to transmit the
1439 struct PendingAcknowledgement *next_queue;
1442 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1443 * is kept in relation to the queue that was used to transmit the
1446 struct PendingAcknowledgement *prev_queue;
1449 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1450 * is kept in relation to the DVH that was used to transmit the
1453 struct PendingAcknowledgement *next_dvh;
1456 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1457 * is kept in relation to the DVH that was used to transmit the
1460 struct PendingAcknowledgement *prev_dvh;
1463 * Pointers for the DLL of all pending acknowledgements.
1464 * This list is sorted by @e transmission time. If the list gets too
1465 * long, the oldest entries are discarded.
1467 struct PendingAcknowledgement *next_pa;
1470 * Pointers for the DLL of all pending acknowledgements.
1471 * This list is sorted by @e transmission time. If the list gets too
1472 * long, the oldest entries are discarded.
1474 struct PendingAcknowledgement *prev_pa;
1477 * Unique identifier for this transmission operation.
1479 struct AcknowledgementUUIDP ack_uuid;
1482 * Message that was transmitted, may be NULL if the message was ACKed
1483 * via another channel.
1485 struct PendingMessage *pm;
1488 * Distance vector path chosen for this transmission, NULL if transmission
1489 * was to a direct neighbour OR if the path was forgotten in the meantime.
1491 struct DistanceVectorHop *dvh;
1494 * Queue used for transmission, NULL if the queue has been destroyed
1495 * (which may happen before we get an acknowledgement).
1497 struct Queue *queue;
1500 * Time of the transmission, for RTT calculation.
1502 struct GNUNET_TIME_Absolute transmission_time;
1505 * Number of bytes of the original message (to calculate bandwidth).
1507 uint16_t message_size;
1512 * One possible hop towards a DV target.
1514 struct DistanceVectorHop
1517 * Kept in a MDLL, sorted by @e timeout.
1519 struct DistanceVectorHop *next_dv;
1522 * Kept in a MDLL, sorted by @e timeout.
1524 struct DistanceVectorHop *prev_dv;
1529 struct DistanceVectorHop *next_neighbour;
1534 struct DistanceVectorHop *prev_neighbour;
1537 * Head of DLL of PAs that used our @a path.
1539 struct PendingAcknowledgement *pa_head;
1542 * Tail of DLL of PAs that used our @a path.
1544 struct PendingAcknowledgement *pa_tail;
1547 * What would be the next hop to @e target?
1549 struct Neighbour *next_hop;
1552 * Distance vector entry this hop belongs with.
1554 struct DistanceVector *dv;
1557 * Array of @e distance hops to the target, excluding @e next_hop.
1558 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1559 * at the end of this struct. Excludes the target itself!
1561 const struct GNUNET_PeerIdentity *path;
1564 * At what time do we forget about this path unless we see it again
1567 struct GNUNET_TIME_Absolute timeout;
1570 * For how long is the validation of this path considered
1572 * Set to ZERO if the path is learned by snooping on DV learn messages
1573 * initiated by other peers, and to the time at which we generated the
1574 * challenge for DV learn operations this peer initiated.
1576 struct GNUNET_TIME_Absolute path_valid_until;
1579 * Performance data for this transmission possibility.
1581 struct PerformanceData pd;
1584 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1585 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1588 unsigned int distance;
1593 * Entry in our #dv_routes table, representing a (set of) distance
1594 * vector routes to a particular peer.
1596 struct DistanceVector
1599 * To which peer is this a route?
1601 struct GNUNET_PeerIdentity target;
1604 * Known paths to @e target.
1606 struct DistanceVectorHop *dv_head;
1609 * Known paths to @e target.
1611 struct DistanceVectorHop *dv_tail;
1614 * Task scheduled to purge expired paths from @e dv_head MDLL.
1616 struct GNUNET_SCHEDULER_Task *timeout_task;
1619 * Do we have a confirmed working queue and are thus visible to
1620 * CORE? If so, this is the virtual link, otherwise NULL.
1622 struct VirtualLink *vl;
1625 * Signature affirming @e ephemeral_key of type
1626 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1628 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1631 * How long is @e sender_sig valid
1633 struct GNUNET_TIME_Absolute ephemeral_validity;
1636 * What time was @e sender_sig created
1638 struct GNUNET_TIME_Absolute monotime;
1641 * Our ephemeral key.
1643 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1646 * Our private ephemeral key.
1648 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1653 * Entry identifying transmission in one of our `struct
1654 * Queue` which still awaits an ACK. This is used to
1655 * ensure we do not overwhelm a communicator and limit the number of
1656 * messages outstanding per communicator (say in case communicator is
1657 * CPU bound) and per queue (in case bandwidth allocation exceeds
1658 * what the communicator can actually provide towards a particular
1666 struct QueueEntry *next;
1671 struct QueueEntry *prev;
1674 * Queue this entry is queued with.
1676 struct Queue *queue;
1679 * Pending message this entry is for, or NULL for none.
1681 struct PendingMessage *pm;
1684 * Message ID used for this message with the queue used for transmission.
1691 * A queue is a message queue provided by a communicator
1692 * via which we can reach a particular neighbour.
1699 struct Queue *next_neighbour;
1704 struct Queue *prev_neighbour;
1709 struct Queue *prev_client;
1714 struct Queue *next_client;
1717 * Head of DLL of PAs that used this queue.
1719 struct PendingAcknowledgement *pa_head;
1722 * Tail of DLL of PAs that used this queue.
1724 struct PendingAcknowledgement *pa_tail;
1727 * Head of DLL of unacked transmission requests.
1729 struct QueueEntry *queue_head;
1732 * End of DLL of unacked transmission requests.
1734 struct QueueEntry *queue_tail;
1737 * Which neighbour is this queue for?
1739 struct Neighbour *neighbour;
1742 * Which communicator offers this queue?
1744 struct TransportClient *tc;
1747 * Address served by the queue.
1749 const char *address;
1752 * Task scheduled for the time when this queue can (likely) transmit the
1755 struct GNUNET_SCHEDULER_Task *transmit_task;
1758 * How long do *we* consider this @e address to be valid? In the past or
1759 * zero if we have not yet validated it. Can be updated based on
1760 * challenge-response validations (via address validation logic), or when we
1761 * receive ACKs that we can definitively map to transmissions via this
1764 struct GNUNET_TIME_Absolute validated_until;
1767 * Performance data for this queue.
1769 struct PerformanceData pd;
1772 * Message ID generator for transmissions on this queue to the
1778 * Unique identifier of this queue with the communicator.
1783 * Maximum transmission unit supported by this queue.
1790 uint32_t num_msg_pending;
1795 uint32_t num_bytes_pending;
1798 * Length of the DLL starting at @e queue_head.
1800 unsigned int queue_length;
1803 * Network type offered by this queue.
1805 enum GNUNET_NetworkType nt;
1808 * Connection status for this queue.
1810 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1813 * Set to #GNUNET_YES if this queue is idle waiting for some
1814 * virtual link to give it a pending message.
1821 * Information we keep for a message that we are reassembling.
1823 struct ReassemblyContext
1826 * Original message ID for of the message that all the fragments
1829 struct MessageUUIDP msg_uuid;
1832 * Which neighbour is this context for?
1834 struct Neighbour *neighbour;
1837 * Entry in the reassembly heap (sorted by expiration).
1839 struct GNUNET_CONTAINER_HeapNode *hn;
1842 * Bitfield with @e msg_size bits representing the positions
1843 * where we have received fragments. When we receive a fragment,
1844 * we check the bits in @e bitfield before incrementing @e msg_missing.
1846 * Allocated after the reassembled message.
1851 * At what time will we give up reassembly of this message?
1853 struct GNUNET_TIME_Absolute reassembly_timeout;
1856 * Time we received the last fragment. @e avg_ack_delay must be
1857 * incremented by now - @e last_frag multiplied by @e num_acks.
1859 struct GNUNET_TIME_Absolute last_frag;
1862 * How big is the message we are reassembling in total?
1867 * How many bytes of the message are still missing? Defragmentation
1868 * is complete when @e msg_missing == 0.
1870 uint16_t msg_missing;
1872 /* Followed by @e msg_size bytes of the (partially) defragmented original
1875 /* Followed by @e bitfield data */
1880 * A neighbour that at least one communicator is connected to.
1885 * Which peer is this about?
1887 struct GNUNET_PeerIdentity pid;
1890 * Map with `struct ReassemblyContext` structs for fragments under
1891 * reassembly. May be NULL if we currently have no fragments from
1892 * this @e pid (lazy initialization).
1894 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1897 * Heap with `struct ReassemblyContext` structs for fragments under
1898 * reassembly. May be NULL if we currently have no fragments from
1899 * this @e pid (lazy initialization).
1901 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1904 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1906 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1909 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1910 * purged if this neighbour goes down.
1912 struct DistanceVectorHop *dv_head;
1915 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1916 * purged if this neighbour goes down.
1918 struct DistanceVectorHop *dv_tail;
1921 * Head of DLL of queues to this peer.
1923 struct Queue *queue_head;
1926 * Tail of DLL of queues to this peer.
1928 struct Queue *queue_tail;
1931 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1932 * the PEERSTORE, or NULL.
1934 struct GNUNET_PEERSTORE_IterateContext *get;
1937 * Handle to a PEERSTORE store operation to store this @e pid's @e
1938 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1940 struct GNUNET_PEERSTORE_StoreContext *sc;
1943 * Do we have a confirmed working queue and are thus visible to
1944 * CORE? If so, this is the virtual link, otherwise NULL.
1946 struct VirtualLink *vl;
1949 * Latest DVLearn monotonic time seen from this peer. Initialized only
1950 * if @e dl_monotime_available is #GNUNET_YES.
1952 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1955 * Do we have the lastest value for @e last_dv_learn_monotime from
1956 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1958 int dv_monotime_available;
1963 * Another peer attempted to talk to us, we should try to establish
1964 * a connection in the other direction.
1966 struct IncomingRequest
1971 struct IncomingRequest *next;
1976 struct IncomingRequest *prev;
1979 * Handle for watching the peerstore for HELLOs for this peer.
1981 struct GNUNET_PEERSTORE_WatchContext *wc;
1984 * Which peer is this about?
1986 struct GNUNET_PeerIdentity pid;
1991 * A peer that an application (client) would like us to talk to directly.
1996 * Which peer is this about?
1998 struct GNUNET_PeerIdentity pid;
2001 * Client responsible for the request.
2003 struct TransportClient *tc;
2006 * Handle for watching the peerstore for HELLOs for this peer.
2008 struct GNUNET_PEERSTORE_WatchContext *wc;
2011 * What kind of performance preference does this @e tc have?
2015 enum GNUNET_MQ_PriorityPreferences pk;
2018 * How much bandwidth would this @e tc like to see?
2020 struct GNUNET_BANDWIDTH_Value32NBO bw;
2025 * Types of different pending messages.
2027 enum PendingMessageType
2030 * Ordinary message received from the CORE service.
2037 PMT_FRAGMENT_BOX = 1,
2042 PMT_RELIABILITY_BOX = 2,
2045 * Pending message created during #forward_dv_box().
2052 * Transmission request that is awaiting delivery. The original
2053 * transmission requests from CORE may be too big for some queues.
2054 * In this case, a *tree* of fragments is created. At each
2055 * level of the tree, fragments are kept in a DLL ordered by which
2056 * fragment should be sent next (at the head). The tree is searched
2057 * top-down, with the original message at the root.
2059 * To select a node for transmission, first it is checked if the
2060 * current node's message fits with the MTU. If it does not, we
2061 * either calculate the next fragment (based on @e frag_off) from the
2062 * current node, or, if all fragments have already been created,
2063 * descend to the @e head_frag. Even though the node was already
2064 * fragmented, the fragment may be too big if the fragment was
2065 * generated for a queue with a larger MTU. In this case, the node
2066 * may be fragmented again, thus creating a tree.
2068 * When acknowledgements for fragments are received, the tree
2069 * must be pruned, removing those parts that were already
2070 * acknowledged. When fragments are sent over a reliable
2071 * channel, they can be immediately removed.
2073 * If a message is ever fragmented, then the original "full" message
2074 * is never again transmitted (even if it fits below the MTU), and
2075 * only (remaining) fragments are sent.
2077 struct PendingMessage
2080 * Kept in a MDLL of messages for this @a vl.
2082 struct PendingMessage *next_vl;
2085 * Kept in a MDLL of messages for this @a vl.
2087 struct PendingMessage *prev_vl;
2090 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2092 struct PendingMessage *next_client;
2095 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2097 struct PendingMessage *prev_client;
2100 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2101 * #PMT_FRAGMENT_BOx)
2103 struct PendingMessage *next_frag;
2106 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2107 * #PMT_FRAGMENT_BOX)
2109 struct PendingMessage *prev_frag;
2112 * Head of DLL of PAs for this pending message.
2114 struct PendingAcknowledgement *pa_head;
2117 * Tail of DLL of PAs for this pending message.
2119 struct PendingAcknowledgement *pa_tail;
2122 * This message, reliability *or* DV-boxed. Only possibly available
2123 * if @e pmt is #PMT_CORE.
2125 struct PendingMessage *bpm;
2128 * Target of the request (always the ultimate destination!).
2130 struct VirtualLink *vl;
2133 * Set to non-NULL value if this message is currently being given to a
2134 * communicator and we are awaiting that communicator's acknowledgement.
2135 * Note that we must not retransmit a pending message while we're still
2136 * in the process of giving it to a communicator. If a pending message
2137 * is free'd while this entry is non-NULL, the @e qe reference to us
2138 * should simply be set to NULL.
2140 struct QueueEntry *qe;
2143 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2145 struct TransportClient *client;
2148 * Head of a MDLL of fragments created for this core message.
2150 struct PendingMessage *head_frag;
2153 * Tail of a MDLL of fragments created for this core message.
2155 struct PendingMessage *tail_frag;
2158 * Our parent in the fragmentation tree.
2160 struct PendingMessage *frag_parent;
2163 * At what time should we give up on the transmission (and no longer retry)?
2165 struct GNUNET_TIME_Absolute timeout;
2168 * What is the earliest time for us to retry transmission of this message?
2170 struct GNUNET_TIME_Absolute next_attempt;
2173 * UUID to use for this message (used for reassembly of fragments, only
2174 * initialized if @e msg_uuid_set is #GNUNET_YES).
2176 struct MessageUUIDP msg_uuid;
2179 * UUID we use to identify this message in our logs.
2180 * Generated by incrementing the "logging_uuid_gen".
2182 unsigned long long logging_uuid;
2185 * Type of the pending message.
2187 enum PendingMessageType pmt;
2190 * Preferences for this message.
2191 * TODO: actually use this!
2193 enum GNUNET_MQ_PriorityPreferences prefs;
2196 * Size of the original message.
2201 * Offset at which we should generate the next fragment.
2206 * #GNUNET_YES once @e msg_uuid was initialized
2208 int16_t msg_uuid_set;
2210 /* Followed by @e bytes_msg to transmit */
2215 * Acknowledgement payload.
2217 struct TransportCummulativeAckPayload
2220 * When did we receive the message we are ACKing? Used to calculate
2221 * the delay we introduced by cummulating ACKs.
2223 struct GNUNET_TIME_Absolute receive_time;
2226 * UUID of a message being acknowledged.
2228 struct AcknowledgementUUIDP ack_uuid;
2233 * Data structure in which we track acknowledgements still to
2236 struct AcknowledgementCummulator
2239 * Target peer for which we are accumulating ACKs here.
2241 struct GNUNET_PeerIdentity target;
2244 * ACK data being accumulated. Only @e num_acks slots are valid.
2246 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2249 * Task scheduled either to transmit the cummulative ACK message,
2250 * or to clean up this data structure after extended periods of
2251 * inactivity (if @e num_acks is zero).
2253 struct GNUNET_SCHEDULER_Task *task;
2256 * When is @e task run (only used if @e num_acks is non-zero)?
2258 struct GNUNET_TIME_Absolute min_transmission_time;
2261 * Counter to produce the `ack_counter` in the `struct
2262 * TransportReliabilityAckMessage`. Allows the receiver to detect
2263 * lost ACK messages. Incremented by @e num_acks upon transmission.
2265 uint32_t ack_counter;
2268 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2270 unsigned int num_acks;
2275 * One of the addresses of this peer.
2277 struct AddressListEntry
2282 struct AddressListEntry *next;
2287 struct AddressListEntry *prev;
2290 * Which communicator provides this address?
2292 struct TransportClient *tc;
2295 * The actual address.
2297 const char *address;
2300 * Current context for storing this address in the peerstore.
2302 struct GNUNET_PEERSTORE_StoreContext *sc;
2305 * Task to periodically do @e st operation.
2307 struct GNUNET_SCHEDULER_Task *st;
2310 * What is a typical lifetime the communicator expects this
2311 * address to have? (Always from now.)
2313 struct GNUNET_TIME_Relative expiration;
2316 * Address identifier used by the communicator.
2321 * Network type offered by this address.
2323 enum GNUNET_NetworkType nt;
2328 * Client connected to the transport service.
2330 struct TransportClient
2335 struct TransportClient *next;
2340 struct TransportClient *prev;
2343 * Handle to the client.
2345 struct GNUNET_SERVICE_Client *client;
2348 * Message queue to the client.
2350 struct GNUNET_MQ_Handle *mq;
2353 * What type of client is this?
2355 enum ClientType type;
2360 * Information for @e type #CT_CORE.
2365 * Head of list of messages pending for this client, sorted by
2366 * transmission time ("next_attempt" + possibly internal prioritization).
2368 struct PendingMessage *pending_msg_head;
2371 * Tail of list of messages pending for this client.
2373 struct PendingMessage *pending_msg_tail;
2377 * Information for @e type #CT_MONITOR.
2382 * Peer identity to monitor the addresses of.
2383 * Zero to monitor all neighbours. Valid if
2384 * @e type is #CT_MONITOR.
2386 struct GNUNET_PeerIdentity peer;
2389 * Is this a one-shot monitor?
2396 * Information for @e type #CT_COMMUNICATOR.
2401 * If @e type is #CT_COMMUNICATOR, this communicator
2402 * supports communicating using these addresses.
2404 char *address_prefix;
2407 * Head of DLL of queues offered by this communicator.
2409 struct Queue *queue_head;
2412 * Tail of DLL of queues offered by this communicator.
2414 struct Queue *queue_tail;
2417 * Head of list of the addresses of this peer offered by this
2420 struct AddressListEntry *addr_head;
2423 * Tail of list of the addresses of this peer offered by this
2426 struct AddressListEntry *addr_tail;
2429 * Number of queue entries in all queues to this communicator. Used
2430 * throttle sending to a communicator if we see that the communicator
2431 * is globally unable to keep up.
2433 unsigned int total_queue_length;
2436 * Characteristics of this communicator.
2438 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2442 * Information for @e type #CT_APPLICATION
2447 * Map of requests for peers the given client application would like to
2448 * see connections for. Maps from PIDs to `struct PeerRequest`.
2450 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2457 * State we keep for validation activities. Each of these
2458 * is both in the #validation_heap and the #validation_map.
2460 struct ValidationState
2463 * For which peer is @a address to be validated (or possibly valid)?
2464 * Serves as key in the #validation_map.
2466 struct GNUNET_PeerIdentity pid;
2469 * How long did the peer claim this @e address to be valid? Capped at
2470 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2471 * were told about the address and the value claimed by the other peer at
2472 * that time. May be updated similarly when validation succeeds.
2474 struct GNUNET_TIME_Absolute valid_until;
2477 * How long do *we* consider this @e address to be valid?
2478 * In the past or zero if we have not yet validated it.
2480 struct GNUNET_TIME_Absolute validated_until;
2483 * When did we FIRST use the current @e challenge in a message?
2484 * Used to sanity-check @code{origin_time} in the response when
2485 * calculating the RTT. If the @code{origin_time} is not in
2486 * the expected range, the response is discarded as malicious.
2488 struct GNUNET_TIME_Absolute first_challenge_use;
2491 * When did we LAST use the current @e challenge in a message?
2492 * Used to sanity-check @code{origin_time} in the response when
2493 * calculating the RTT. If the @code{origin_time} is not in
2494 * the expected range, the response is discarded as malicious.
2496 struct GNUNET_TIME_Absolute last_challenge_use;
2499 * Next time we will send the @e challenge to the peer, if this time is past
2500 * @e valid_until, this validation state is released at this time. If the
2501 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2502 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2503 * to re-validate before the validity actually expires.
2505 struct GNUNET_TIME_Absolute next_challenge;
2508 * Current backoff factor we're applying for sending the @a challenge.
2509 * Reset to 0 if the @a challenge is confirmed upon validation.
2510 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2511 * existing value if we receive an unvalidated address again over
2512 * another channel (and thus should consider the information "fresh").
2513 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2515 struct GNUNET_TIME_Relative challenge_backoff;
2518 * Initially set to "forever". Once @e validated_until is set, this value is
2519 * set to the RTT that tells us how long it took to receive the validation.
2521 struct GNUNET_TIME_Relative validation_rtt;
2524 * The challenge we sent to the peer to get it to validate the address. Note
2525 * that we rotate the challenge whenever we update @e validated_until to
2526 * avoid attacks where a peer simply replays an old challenge in the future.
2527 * (We must not rotate more often as otherwise we may discard valid answers
2528 * due to packet losses, latency and reorderings on the network).
2530 struct ChallengeNonceP challenge;
2533 * Claimed address of the peer.
2538 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2539 * heap is used to figure out when the next validation activity should be
2542 struct GNUNET_CONTAINER_HeapNode *hn;
2545 * Handle to a PEERSTORE store operation for this @e address. NULL if
2546 * no PEERSTORE operation is pending.
2548 struct GNUNET_PEERSTORE_StoreContext *sc;
2551 * Self-imposed limit on the previous flow control window. (May be zero,
2552 * if we never used data from the previous window or are establishing the
2553 * connection for the first time).
2555 uint32_t last_window_consum_limit;
2558 * We are technically ready to send the challenge, but we are waiting for
2559 * the respective queue to become available for transmission.
2566 * A Backtalker is a peer sending us backchannel messages. We use this
2567 * struct to detect monotonic time violations, cache ephemeral key
2568 * material (to avoid repeatedly checking signatures), and to synchronize
2569 * monotonic time with the PEERSTORE.
2574 * Peer this is about.
2576 struct GNUNET_PeerIdentity pid;
2579 * Last (valid) monotonic time received from this sender.
2581 struct GNUNET_TIME_Absolute monotonic_time;
2584 * When will this entry time out?
2586 struct GNUNET_TIME_Absolute timeout;
2589 * Last (valid) ephemeral key received from this sender.
2591 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2594 * Task associated with this backtalker. Can be for timeout,
2595 * or other asynchronous operations.
2597 struct GNUNET_SCHEDULER_Task *task;
2600 * Communicator context waiting on this backchannel's @e get, or NULL.
2602 struct CommunicatorMessageContext *cmc;
2605 * Handle for an operation to fetch @e monotonic_time information from the
2606 * PEERSTORE, or NULL.
2608 struct GNUNET_PEERSTORE_IterateContext *get;
2611 * Handle to a PEERSTORE store operation for this @e pid's @e
2612 * monotonic_time. NULL if no PEERSTORE operation is pending.
2614 struct GNUNET_PEERSTORE_StoreContext *sc;
2617 * Number of bytes of the original message body that follows after this
2625 * Head of linked list of all clients to this service.
2627 static struct TransportClient *clients_head;
2630 * Tail of linked list of all clients to this service.
2632 static struct TransportClient *clients_tail;
2635 * Statistics handle.
2637 static struct GNUNET_STATISTICS_Handle *GST_stats;
2640 * Configuration handle.
2642 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2647 static struct GNUNET_PeerIdentity GST_my_identity;
2652 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2655 * Map from PIDs to `struct Neighbour` entries. A peer is
2656 * a neighbour if we have an MQ to it from some communicator.
2658 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2661 * Map from PIDs to `struct Backtalker` entries. A peer is
2662 * a backtalker if it recently send us backchannel messages.
2664 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2667 * Map from PIDs to `struct AcknowledgementCummulator`s.
2668 * Here we track the cummulative ACKs for transmission.
2670 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2673 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2674 * a `struct PendingAcknowledgement`.
2676 static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2679 * Map from PIDs to `struct DistanceVector` entries describing
2680 * known paths to the peer.
2682 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2685 * Map from PIDs to `struct ValidationState` entries describing
2686 * addresses we are aware of and their validity state.
2688 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2691 * Map from PIDs to `struct VirtualLink` entries describing
2692 * links CORE knows to exist.
2694 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2697 * Map from challenges to `struct LearnLaunchEntry` values.
2699 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2702 * Head of a DLL sorted by launch time.
2704 static struct LearnLaunchEntry *lle_head;
2707 * Tail of a DLL sorted by launch time.
2709 static struct LearnLaunchEntry *lle_tail;
2712 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2713 * sorting addresses we are aware of by when we should next try to (re)validate
2716 static struct GNUNET_CONTAINER_Heap *validation_heap;
2719 * Database for peer's HELLOs.
2721 static struct GNUNET_PEERSTORE_Handle *peerstore;
2724 * Task run to initiate DV learning.
2726 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2729 * Task to run address validation.
2731 static struct GNUNET_SCHEDULER_Task *validation_task;
2734 * The most recent PA we have created, head of DLL.
2735 * The length of the DLL is kept in #pa_count.
2737 static struct PendingAcknowledgement *pa_head;
2740 * The oldest PA we have created, tail of DLL.
2741 * The length of the DLL is kept in #pa_count.
2743 static struct PendingAcknowledgement *pa_tail;
2746 * List of incomming connections where we are trying
2747 * to get a connection back established. Length
2748 * kept in #ir_total.
2750 static struct IncomingRequest *ir_head;
2753 * Tail of DLL starting at #ir_head.
2755 static struct IncomingRequest *ir_tail;
2758 * Length of the DLL starting at #ir_head.
2760 static unsigned int ir_total;
2763 * Generator of `logging_uuid` in `struct PendingMessage`.
2765 static unsigned long long logging_uuid_gen;
2768 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2769 * limit the size of the data structure.
2771 static unsigned int pa_count;
2774 * Monotonic time we use for HELLOs generated at this time. TODO: we
2775 * should increase this value from time to time (i.e. whenever a
2776 * `struct AddressListEntry` actually expires), but IF we do this, we
2777 * must also update *all* (remaining) addresses in the PEERSTORE at
2778 * that time! (So for now only increased when the peer is restarted,
2779 * which hopefully roughly matches whenever our addresses change.)
2781 static struct GNUNET_TIME_Absolute hello_mono_time;
2785 * Get an offset into the transmission history buffer for `struct
2786 * PerformanceData`. Note that the caller must perform the required
2787 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2790 * An 'age' lasts 15 minute slots.
2792 * @return current age of the world
2797 struct GNUNET_TIME_Absolute now;
2799 now = GNUNET_TIME_absolute_get ();
2800 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2805 * Release @a ir data structure.
2807 * @param ir data structure to release
2810 free_incoming_request (struct IncomingRequest *ir)
2812 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2813 GNUNET_assert (ir_total > 0);
2815 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2821 * Release @a pa data structure.
2823 * @param pa data structure to release
2826 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2828 struct Queue *q = pa->queue;
2829 struct PendingMessage *pm = pa->pm;
2830 struct DistanceVectorHop *dvh = pa->dvh;
2832 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2836 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2841 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2846 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2849 GNUNET_assert (GNUNET_YES ==
2850 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
2851 &pa->ack_uuid.value,
2858 * Free fragment tree below @e root, excluding @e root itself.
2859 * FIXME: this does NOT seem to have the intended semantics
2860 * based on how this is called. Seems we generally DO expect
2861 * @a root to be free'ed itself as well!
2863 * @param root root of the tree to free
2866 free_fragment_tree (struct PendingMessage *root)
2868 struct PendingMessage *frag;
2870 while (NULL != (frag = root->head_frag))
2872 struct PendingAcknowledgement *pa;
2874 free_fragment_tree (frag);
2875 while (NULL != (pa = frag->pa_head))
2877 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2880 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2887 * Release memory associated with @a pm and remove @a pm from associated
2888 * data structures. @a pm must be a top-level pending message and not
2889 * a fragment in the tree. The entire tree is freed (if applicable).
2891 * @param pm the pending message to free
2894 free_pending_message (struct PendingMessage *pm)
2896 struct TransportClient *tc = pm->client;
2897 struct VirtualLink *vl = pm->vl;
2898 struct PendingAcknowledgement *pa;
2902 GNUNET_CONTAINER_MDLL_remove (client,
2903 tc->details.core.pending_msg_head,
2904 tc->details.core.pending_msg_tail,
2909 GNUNET_CONTAINER_MDLL_remove (vl,
2910 vl->pending_msg_head,
2911 vl->pending_msg_tail,
2914 while (NULL != (pa = pm->pa_head))
2916 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2920 free_fragment_tree (pm);
2923 GNUNET_assert (pm == pm->qe->pm);
2926 if (NULL != pm->bpm)
2928 free_fragment_tree (pm->bpm);
2929 GNUNET_free (pm->bpm);
2936 * Free virtual link.
2938 * @param vl link data to free
2941 free_virtual_link (struct VirtualLink *vl)
2943 struct PendingMessage *pm;
2944 struct CoreSentContext *csc;
2946 while (NULL != (pm = vl->pending_msg_head))
2947 free_pending_message (pm);
2948 GNUNET_assert (GNUNET_YES ==
2949 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
2950 if (NULL != vl->visibility_task)
2952 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2953 vl->visibility_task = NULL;
2955 if (NULL != vl->fc_retransmit_task)
2957 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
2958 vl->fc_retransmit_task = NULL;
2960 while (NULL != (csc = vl->csc_head))
2962 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
2963 GNUNET_assert (vl == csc->vl);
2966 GNUNET_break (NULL == vl->n);
2967 GNUNET_break (NULL == vl->dv);
2973 * Free validation state.
2975 * @param vs validation state to free
2978 free_validation_state (struct ValidationState *vs)
2982 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
2983 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2987 GNUNET_PEERSTORE_store_cancel (vs->sc);
2990 GNUNET_free (vs->address);
2996 * Lookup neighbour for peer @a pid.
2998 * @param pid neighbour to look for
2999 * @return NULL if we do not have this peer as a neighbour
3001 static struct Neighbour *
3002 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3004 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3009 * Lookup virtual link for peer @a pid.
3011 * @param pid virtual link to look for
3012 * @return NULL if we do not have this peer as a virtual link
3014 static struct VirtualLink *
3015 lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3017 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3022 * Details about what to notify monitors about.
3027 * @deprecated To be discussed if we keep these...
3029 struct GNUNET_TIME_Absolute last_validation;
3030 struct GNUNET_TIME_Absolute valid_until;
3031 struct GNUNET_TIME_Absolute next_validation;
3034 * Current round-trip time estimate.
3036 struct GNUNET_TIME_Relative rtt;
3039 * Connection status.
3041 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3046 uint32_t num_msg_pending;
3051 uint32_t num_bytes_pending;
3056 * Free a @dvh. Callers MAY want to check if this was the last path to the
3057 * `target`, and if so call #free_dv_route to also free the associated DV
3058 * entry in #dv_routes (if not, the associated scheduler job should eventually
3061 * @param dvh hop to free
3064 free_distance_vector_hop (struct DistanceVectorHop *dvh)
3066 struct Neighbour *n = dvh->next_hop;
3067 struct DistanceVector *dv = dvh->dv;
3068 struct PendingAcknowledgement *pa;
3070 while (NULL != (pa = dvh->pa_head))
3072 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3075 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3076 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3082 * Task run to check whether the hops of the @a cls still
3083 * are validated, or if we need to core about disconnection.
3085 * @param cls a `struct VirtualLink`
3088 check_link_down (void *cls);
3092 * Send message to CORE clients that we lost a connection.
3094 * @param pid peer the connection was for
3097 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3100 "Informing CORE clients about disconnect from %s\n",
3102 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3104 struct GNUNET_MQ_Envelope *env;
3105 struct DisconnectInfoMessage *dim;
3107 if (CT_CORE != tc->type)
3109 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3111 GNUNET_MQ_send (tc->mq, env);
3117 * Free entry in #dv_routes. First frees all hops to the target, and
3118 * if there are no entries left, frees @a dv as well.
3120 * @param dv route to free
3123 free_dv_route (struct DistanceVector *dv)
3125 struct DistanceVectorHop *dvh;
3127 while (NULL != (dvh = dv->dv_head))
3128 free_distance_vector_hop (dvh);
3129 if (NULL == dv->dv_head)
3131 struct VirtualLink *vl;
3135 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3136 if (NULL != (vl = dv->vl))
3138 GNUNET_assert (dv == vl->dv);
3142 cores_send_disconnect_info (&dv->target);
3143 free_virtual_link (vl);
3147 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3148 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3153 if (NULL != dv->timeout_task)
3155 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3156 dv->timeout_task = NULL;
3164 * Notify monitor @a tc about an event. That @a tc
3165 * cares about the event has already been checked.
3167 * Send @a tc information in @a me about a @a peer's status with
3168 * respect to some @a address to all monitors that care.
3170 * @param tc monitor to inform
3171 * @param peer peer the information is about
3172 * @param address address the information is about
3173 * @param nt network type associated with @a address
3174 * @param me detailed information to transmit
3177 notify_monitor (struct TransportClient *tc,
3178 const struct GNUNET_PeerIdentity *peer,
3179 const char *address,
3180 enum GNUNET_NetworkType nt,
3181 const struct MonitorEvent *me)
3183 struct GNUNET_MQ_Envelope *env;
3184 struct GNUNET_TRANSPORT_MonitorData *md;
3185 size_t addr_len = strlen (address) + 1;
3187 env = GNUNET_MQ_msg_extra (md,
3189 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3190 md->nt = htonl ((uint32_t) nt);
3192 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3193 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3194 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3195 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3196 md->cs = htonl ((uint32_t) me->cs);
3197 md->num_msg_pending = htonl (me->num_msg_pending);
3198 md->num_bytes_pending = htonl (me->num_bytes_pending);
3199 memcpy (&md[1], address, addr_len);
3200 GNUNET_MQ_send (tc->mq, env);
3205 * Send information in @a me about a @a peer's status with respect
3206 * to some @a address to all monitors that care.
3208 * @param peer peer the information is about
3209 * @param address address the information is about
3210 * @param nt network type associated with @a address
3211 * @param me detailed information to transmit
3214 notify_monitors (const struct GNUNET_PeerIdentity *peer,
3215 const char *address,
3216 enum GNUNET_NetworkType nt,
3217 const struct MonitorEvent *me)
3219 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3221 if (CT_MONITOR != tc->type)
3223 if (tc->details.monitor.one_shot)
3225 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
3226 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3228 notify_monitor (tc, peer, address, nt, me);
3234 * Called whenever a client connects. Allocates our
3235 * data structures associated with that client.
3237 * @param cls closure, NULL
3238 * @param client identification of the client
3239 * @param mq message queue for the client
3240 * @return our `struct TransportClient`
3243 client_connect_cb (void *cls,
3244 struct GNUNET_SERVICE_Client *client,
3245 struct GNUNET_MQ_Handle *mq)
3247 struct TransportClient *tc;
3250 tc = GNUNET_new (struct TransportClient);
3251 tc->client = client;
3253 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
3262 * @param rc data structure to free
3265 free_reassembly_context (struct ReassemblyContext *rc)
3267 struct Neighbour *n = rc->neighbour;
3269 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3270 GNUNET_assert (GNUNET_OK ==
3271 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
3279 * Task run to clean up reassembly context of a neighbour that have expired.
3281 * @param cls a `struct Neighbour`
3284 reassembly_cleanup_task (void *cls)
3286 struct Neighbour *n = cls;
3287 struct ReassemblyContext *rc;
3289 n->reassembly_timeout_task = NULL;
3290 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
3292 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3295 free_reassembly_context (rc);
3298 GNUNET_assert (NULL == n->reassembly_timeout_task);
3299 n->reassembly_timeout_task =
3300 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3301 &reassembly_cleanup_task,
3309 * function called to #free_reassembly_context().
3313 * @param value a `struct ReassemblyContext` to free
3314 * @return #GNUNET_OK (continue iteration)
3317 free_reassembly_cb (void *cls, uint32_t key, void *value)
3319 struct ReassemblyContext *rc = value;
3323 free_reassembly_context (rc);
3329 * Release memory used by @a neighbour.
3331 * @param neighbour neighbour entry to free
3334 free_neighbour (struct Neighbour *neighbour)
3336 struct DistanceVectorHop *dvh;
3337 struct VirtualLink *vl;
3339 GNUNET_assert (NULL == neighbour->queue_head);
3340 GNUNET_assert (GNUNET_YES ==
3341 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3344 if (NULL != neighbour->reassembly_map)
3346 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
3347 &free_reassembly_cb,
3349 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
3350 neighbour->reassembly_map = NULL;
3351 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
3352 neighbour->reassembly_heap = NULL;
3354 while (NULL != (dvh = neighbour->dv_head))
3356 struct DistanceVector *dv = dvh->dv;
3358 free_distance_vector_hop (dvh);
3359 if (NULL == dv->dv_head)
3362 if (NULL != neighbour->reassembly_timeout_task)
3364 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
3365 neighbour->reassembly_timeout_task = NULL;
3367 if (NULL != neighbour->get)
3369 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3370 neighbour->get = NULL;
3372 if (NULL != neighbour->sc)
3374 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3375 neighbour->sc = NULL;
3377 if (NULL != (vl = neighbour->vl))
3379 GNUNET_assert (neighbour == vl->n);
3383 cores_send_disconnect_info (&vl->target);
3384 free_virtual_link (vl);
3388 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3389 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3391 neighbour->vl = NULL;
3393 GNUNET_free (neighbour);
3398 * Send message to CORE clients that we lost a connection.
3400 * @param tc client to inform (must be CORE client)
3401 * @param pid peer the connection is for
3404 core_send_connect_info (struct TransportClient *tc,
3405 const struct GNUNET_PeerIdentity *pid)
3407 struct GNUNET_MQ_Envelope *env;
3408 struct ConnectInfoMessage *cim;
3410 GNUNET_assert (CT_CORE == tc->type);
3411 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3413 GNUNET_MQ_send (tc->mq, env);
3418 * Send message to CORE clients that we gained a connection
3420 * @param pid peer the queue was for
3423 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3426 "Informing CORE clients about connection to %s\n",
3428 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3430 if (CT_CORE != tc->type)
3432 core_send_connect_info (tc, pid);
3438 * We believe we are ready to transmit a message on a queue. Gives the
3439 * message to the communicator for transmission (updating the tracker,
3440 * and re-scheduling itself if applicable).
3442 * @param cls the `struct Queue` to process transmissions for
3445 transmit_on_queue (void *cls);
3449 * Called whenever something changed that might effect when we
3450 * try to do the next transmission on @a queue using #transmit_on_queue().
3452 * @param queue the queue to do scheduling for
3453 * @param p task priority to use, if @a queue is scheduled
3456 schedule_transmit_on_queue (struct Queue *queue,
3457 enum GNUNET_SCHEDULER_Priority p)
3459 if (queue->tc->details.communicator.total_queue_length >=
3460 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3462 GNUNET_STATISTICS_update (
3464 "# Transmission throttled due to communicator queue limit",
3467 queue->idle = GNUNET_NO;
3470 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3472 GNUNET_STATISTICS_update (GST_stats,
3473 "# Transmission throttled due to queue queue limit",
3476 queue->idle = GNUNET_NO;
3479 /* queue might indeed be ready, schedule it */
3480 if (NULL != queue->transmit_task)
3481 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3482 queue->transmit_task =
3483 GNUNET_SCHEDULER_add_with_priority (p, &transmit_on_queue, queue);
3484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3485 "Considering transmission on queue `%s' to %s\n",
3487 GNUNET_i2s (&queue->neighbour->pid));
3492 * Task run to check whether the hops of the @a cls still
3493 * are validated, or if we need to core about disconnection.
3495 * @param cls a `struct VirtualLink`
3498 check_link_down (void *cls)
3500 struct VirtualLink *vl = cls;
3501 struct DistanceVector *dv = vl->dv;
3502 struct Neighbour *n = vl->n;
3503 struct GNUNET_TIME_Absolute dvh_timeout;
3504 struct GNUNET_TIME_Absolute q_timeout;
3506 vl->visibility_task = NULL;
3507 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3508 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3510 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3511 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3516 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3517 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3518 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3519 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3524 if ((NULL == vl->n) && (NULL == vl->dv))
3526 cores_send_disconnect_info (&vl->target);
3527 free_virtual_link (vl);
3530 vl->visibility_task =
3531 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3540 * @param queue the queue to free
3543 free_queue (struct Queue *queue)
3545 struct Neighbour *neighbour = queue->neighbour;
3546 struct TransportClient *tc = queue->tc;
3547 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3548 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3549 struct QueueEntry *qe;
3551 struct PendingAcknowledgement *pa;
3552 struct VirtualLink *vl;
3554 if (NULL != queue->transmit_task)
3556 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3557 queue->transmit_task = NULL;
3559 while (NULL != (pa = queue->pa_head))
3561 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3565 GNUNET_CONTAINER_MDLL_remove (neighbour,
3566 neighbour->queue_head,
3567 neighbour->queue_tail,
3569 GNUNET_CONTAINER_MDLL_remove (client,
3570 tc->details.communicator.queue_head,
3571 tc->details.communicator.queue_tail,
3573 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3574 tc->details.communicator.total_queue_length);
3575 while (NULL != (qe = queue->queue_head))
3577 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3578 queue->queue_length--;
3579 tc->details.communicator.total_queue_length--;
3582 GNUNET_assert (qe == qe->pm->qe);
3587 GNUNET_assert (0 == queue->queue_length);
3588 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3589 tc->details.communicator.total_queue_length))
3591 /* Communicator dropped below threshold, resume all _other_ queues */
3592 GNUNET_STATISTICS_update (
3594 "# Transmission throttled due to communicator queue limit",
3597 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3599 schedule_transmit_on_queue (s, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3601 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3602 GNUNET_free (queue);
3604 vl = lookup_virtual_link (&neighbour->pid);
3605 if ((NULL != vl) && (neighbour == vl->n))
3607 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3608 check_link_down (vl);
3610 if (NULL == neighbour->queue_head)
3612 free_neighbour (neighbour);
3620 * @param ale address list entry to free
3623 free_address_list_entry (struct AddressListEntry *ale)
3625 struct TransportClient *tc = ale->tc;
3627 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3628 tc->details.communicator.addr_tail,
3630 if (NULL != ale->sc)
3632 GNUNET_PEERSTORE_store_cancel (ale->sc);
3635 if (NULL != ale->st)
3637 GNUNET_SCHEDULER_cancel (ale->st);
3645 * Stop the peer request in @a value.
3647 * @param cls a `struct TransportClient` that no longer makes the request
3648 * @param pid the peer's identity
3649 * @param value a `struct PeerRequest`
3650 * @return #GNUNET_YES (always)
3653 stop_peer_request (void *cls,
3654 const struct GNUNET_PeerIdentity *pid,
3657 struct TransportClient *tc = cls;
3658 struct PeerRequest *pr = value;
3660 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3663 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3673 * Called whenever a client is disconnected. Frees our
3674 * resources associated with that client.
3676 * @param cls closure, NULL
3677 * @param client identification of the client
3678 * @param app_ctx our `struct TransportClient`
3681 client_disconnect_cb (void *cls,
3682 struct GNUNET_SERVICE_Client *client,
3685 struct TransportClient *tc = app_ctx;
3689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3690 "Client %p disconnected, cleaning up.\n",
3692 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3699 struct PendingMessage *pm;
3701 while (NULL != (pm = tc->details.core.pending_msg_head))
3703 GNUNET_CONTAINER_MDLL_remove (client,
3704 tc->details.core.pending_msg_head,
3705 tc->details.core.pending_msg_tail,
3715 case CT_COMMUNICATOR: {
3717 struct AddressListEntry *ale;
3719 while (NULL != (q = tc->details.communicator.queue_head))
3721 while (NULL != (ale = tc->details.communicator.addr_head))
3722 free_address_list_entry (ale);
3723 GNUNET_free (tc->details.communicator.address_prefix);
3727 case CT_APPLICATION:
3728 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3731 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3739 * Iterator telling new CORE client about all existing
3740 * connections to peers.
3742 * @param cls the new `struct TransportClient`
3743 * @param pid a connected peer
3744 * @param value the `struct Neighbour` with more information
3745 * @return #GNUNET_OK (continue to iterate)
3748 notify_client_connect_info (void *cls,
3749 const struct GNUNET_PeerIdentity *pid,
3752 struct TransportClient *tc = cls;
3755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3756 "Telling new CORE client about existing connection to %s\n",
3758 core_send_connect_info (tc, pid);
3764 * Initialize a "CORE" client. We got a start message from this
3765 * client, so add it to the list of clients for broadcasting of
3768 * @param cls the client
3769 * @param start the start message that was sent
3772 handle_client_start (void *cls, const struct StartMessage *start)
3774 struct TransportClient *tc = cls;
3777 options = ntohl (start->options);
3778 if ((0 != (1 & options)) &&
3779 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3781 /* client thinks this is a different peer, reject */
3783 GNUNET_SERVICE_client_drop (tc->client);
3786 if (CT_NONE != tc->type)
3789 GNUNET_SERVICE_client_drop (tc->client);
3793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3794 "New CORE client with PID %s registered\n",
3795 GNUNET_i2s (&start->self));
3796 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3797 ¬ify_client_connect_info,
3799 GNUNET_SERVICE_client_continue (tc->client);
3804 * Client asked for transmission to a peer. Process the request.
3806 * @param cls the client
3807 * @param obm the send message that was sent
3810 check_client_send (void *cls, const struct OutboundMessage *obm)
3812 struct TransportClient *tc = cls;
3814 const struct GNUNET_MessageHeader *obmm;
3816 if (CT_CORE != tc->type)
3819 return GNUNET_SYSERR;
3821 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
3822 if (size < sizeof(struct GNUNET_MessageHeader))
3825 return GNUNET_SYSERR;
3827 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3828 if (size != ntohs (obmm->size))
3831 return GNUNET_SYSERR;
3838 * Send a response to the @a pm that we have processed a "send"
3839 * request. Sends a confirmation to the "core" client responsible for
3840 * the original request and free's @a pm.
3842 * @param pm handle to the original pending message
3845 client_send_response (struct PendingMessage *pm)
3847 struct TransportClient *tc = pm->client;
3848 struct VirtualLink *vl = pm->vl;
3852 struct GNUNET_MQ_Envelope *env;
3853 struct SendOkMessage *som;
3855 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3856 som->peer = vl->target;
3857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3858 "Confirming transmission of <%llu> to %s\n",
3860 GNUNET_i2s (&vl->target));
3861 GNUNET_MQ_send (tc->mq, env);
3863 free_pending_message (pm);
3868 * Pick @a hops_array_length random DV paths satisfying @a options
3870 * @param dv data structure to pick paths from
3871 * @param options constraints to satisfy
3872 * @param hops_array[out] set to the result
3873 * @param hops_array_length length of the @a hops_array
3874 * @return number of entries set in @a hops_array
3877 pick_random_dv_hops (const struct DistanceVector *dv,
3878 enum RouteMessageOptions options,
3879 struct DistanceVectorHop **hops_array,
3880 unsigned int hops_array_length)
3882 uint64_t choices[hops_array_length];
3884 unsigned int dv_count;
3886 /* Pick random vectors, but weighted by distance, giving more weight
3887 to shorter vectors */
3890 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3893 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3894 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3895 .rel_value_us == 0))
3896 continue; /* pos unconfirmed and confirmed required */
3897 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3902 if (dv_count <= hops_array_length)
3905 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3907 hops_array[dv_count++] = pos;
3910 for (unsigned int i = 0; i < hops_array_length; i++)
3913 while (GNUNET_NO == ok)
3916 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3918 for (unsigned int j = 0; j < i; j++)
3919 if (choices[i] == choices[j])
3928 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3931 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3933 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3934 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3935 .rel_value_us == 0))
3936 continue; /* pos unconfirmed and confirmed required */
3937 for (unsigned int i = 0; i < hops_array_length; i++)
3938 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3939 hops_array[dv_count++] = pos;
3947 * Communicator started. Test message is well-formed.
3949 * @param cls the client
3950 * @param cam the send message that was sent
3953 check_communicator_available (
3955 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3957 struct TransportClient *tc = cls;
3960 if (CT_NONE != tc->type)
3963 return GNUNET_SYSERR;
3965 tc->type = CT_COMMUNICATOR;
3966 size = ntohs (cam->header.size) - sizeof(*cam);
3968 return GNUNET_OK; /* receive-only communicator */
3969 GNUNET_MQ_check_zero_termination (cam);
3975 * Send ACK to communicator (if requested) and free @a cmc.
3977 * @param cmc context for which we are done handling the message
3980 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3982 if (0 != ntohl (cmc->im.fc_on))
3984 /* send ACK when done to communicator for flow control! */
3985 struct GNUNET_MQ_Envelope *env;
3986 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3988 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3989 ack->reserved = htonl (0);
3990 ack->fc_id = cmc->im.fc_id;
3991 ack->sender = cmc->im.sender;
3992 GNUNET_MQ_send (cmc->tc->mq, env);
3994 GNUNET_SERVICE_client_continue (cmc->tc->client);
4000 * Client confirms that it is done handling message(s) to a particular
4001 * peer. We may now provide more messages to CORE for this peer.
4003 * Notifies the respective queues that more messages can now be received.
4005 * @param cls the client
4006 * @param rom the message that was sent
4009 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4011 struct TransportClient *tc = cls;
4012 struct VirtualLink *vl;
4014 struct CommunicatorMessageContext *cmc;
4016 if (CT_CORE != tc->type)
4019 GNUNET_SERVICE_client_drop (tc->client);
4022 vl = lookup_virtual_link (&rom->peer);
4025 GNUNET_STATISTICS_update (GST_stats,
4026 "# RECV_OK dropped: virtual link unknown",
4029 GNUNET_SERVICE_client_continue (tc->client);
4032 delta = ntohl (rom->increase_window_delta);
4033 vl->core_recv_window += delta;
4034 if (vl->core_recv_window <= 0)
4036 /* resume communicators */
4037 while (NULL != (cmc = vl->cmc_tail))
4039 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4040 finish_cmc_handling (cmc);
4046 * Communicator started. Process the request.
4048 * @param cls the client
4049 * @param cam the send message that was sent
4052 handle_communicator_available (
4054 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4056 struct TransportClient *tc = cls;
4059 size = ntohs (cam->header.size) - sizeof(*cam);
4062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4063 "Receive-only communicator connected\n");
4064 return; /* receive-only communicator */
4066 tc->details.communicator.address_prefix =
4067 GNUNET_strdup ((const char *) &cam[1]);
4068 tc->details.communicator.cc =
4069 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4071 "Communicator with prefix `%s' connected\n",
4072 tc->details.communicator.address_prefix);
4073 GNUNET_SERVICE_client_continue (tc->client);
4078 * Communicator requests backchannel transmission. Check the request.
4080 * @param cls the client
4081 * @param cb the send message that was sent
4082 * @return #GNUNET_OK if message is well-formed
4085 check_communicator_backchannel (
4087 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4089 const struct GNUNET_MessageHeader *inbox;
4095 msize = ntohs (cb->header.size) - sizeof(*cb);
4096 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4097 isize = ntohs (inbox->size);
4101 return GNUNET_SYSERR;
4103 is = (const char *) inbox;
4106 GNUNET_assert (0 < msize);
4107 if ('\0' != is[msize - 1])
4110 return GNUNET_SYSERR;
4117 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4120 * @param dv[in,out] virtual link to update ephemeral for
4123 update_ephemeral (struct DistanceVector *dv)
4125 struct EphemeralConfirmationPS ec;
4128 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4130 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4131 dv->ephemeral_validity =
4132 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4133 GNUNET_assert (GNUNET_OK ==
4134 GNUNET_CRYPTO_ecdhe_key_create2 (&dv->private_key));
4135 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4136 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4137 ec.purpose.size = htonl (sizeof(ec));
4138 ec.target = dv->target;
4139 ec.ephemeral_key = dv->ephemeral_key;
4140 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4147 * Send the message @a payload on @a queue.
4149 * @param queue the queue to use for transmission
4150 * @param pm pending message to update once transmission is done, may be NULL!
4151 * @param payload the payload to send (encapsulated in a
4152 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4153 * @param payload_size number of bytes in @a payload
4156 queue_send_msg (struct Queue *queue,
4157 struct PendingMessage *pm,
4158 const void *payload,
4159 size_t payload_size)
4161 struct Neighbour *n = queue->neighbour;
4162 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4163 struct GNUNET_MQ_Envelope *env;
4165 queue->idle = GNUNET_NO;
4167 GNUNET_ERROR_TYPE_DEBUG,
4168 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4169 (unsigned int) payload_size,
4170 (NULL == pm) ? 0 : pm->logging_uuid,
4171 (unsigned long long) queue->qid,
4172 GNUNET_i2s (&queue->neighbour->pid));
4173 env = GNUNET_MQ_msg_extra (smt,
4175 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4176 smt->qid = queue->qid;
4177 smt->mid = queue->mid_gen;
4178 smt->receiver = n->pid;
4179 memcpy (&smt[1], payload, payload_size);
4181 /* Pass the env to the communicator of queue for transmission. */
4182 struct QueueEntry *qe;
4184 qe = GNUNET_new (struct QueueEntry);
4185 qe->mid = queue->mid_gen++;
4190 GNUNET_assert (NULL == pm->qe);
4193 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4194 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4195 queue->queue_length++;
4196 queue->tc->details.communicator.total_queue_length++;
4197 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4198 queue->tc->details.communicator.total_queue_length)
4199 queue->idle = GNUNET_NO;
4200 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4201 queue->idle = GNUNET_NO;
4202 GNUNET_MQ_send (queue->tc->mq, env);
4208 * Pick a queue of @a n under constraints @a options and schedule
4209 * transmission of @a hdr.
4211 * @param n neighbour to send to
4212 * @param hdr message to send as payload
4213 * @param options whether queues must be confirmed or not,
4214 * and whether we may pick multiple (2) queues
4215 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4217 static struct GNUNET_TIME_Relative
4218 route_via_neighbour (const struct Neighbour *n,
4219 const struct GNUNET_MessageHeader *hdr,
4220 enum RouteMessageOptions options)
4222 struct GNUNET_TIME_Absolute now;
4223 unsigned int candidates;
4226 struct GNUNET_TIME_Relative rtt;
4228 /* Pick one or two 'random' queues from n (under constraints of options) */
4229 now = GNUNET_TIME_absolute_get ();
4230 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4231 weight in the future; weight could be assigned by observed
4232 bandwidth (note: not sure if we should do this for this type
4233 of control traffic though). */
4235 for (struct Queue *pos = n->queue_head; NULL != pos;
4236 pos = pos->next_neighbour)
4238 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4239 (pos->validated_until.abs_value_us > now.abs_value_us))
4242 if (0 == candidates)
4244 /* This can happen rarely if the last confirmed queue timed
4245 out just as we were beginning to process this message. */
4246 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4247 "Could not route message of type %u to %s: no valid queue\n",
4249 GNUNET_i2s (&n->pid));
4250 GNUNET_STATISTICS_update (GST_stats,
4251 "# route selection failed (all no valid queue)",
4254 return GNUNET_TIME_UNIT_FOREVER_REL;
4257 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4258 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4259 if (0 == (options & RMO_REDUNDANT))
4260 sel2 = candidates; /* picks none! */
4262 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4264 for (struct Queue *pos = n->queue_head; NULL != pos;
4265 pos = pos->next_neighbour)
4267 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4268 (pos->validated_until.abs_value_us > now.abs_value_us))
4270 if ((sel1 == candidates) || (sel2 == candidates))
4272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4273 "Routing message of type %u to %s using %s (#%u)\n",
4275 GNUNET_i2s (&n->pid),
4277 (sel1 == candidates) ? 1 : 2);
4278 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4279 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4289 * Structure of the key material used to encrypt backchannel messages.
4294 * State of our block cipher.
4296 gcry_cipher_hd_t cipher;
4299 * Actual key material.
4304 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4306 struct GNUNET_CRYPTO_AuthKey hmac_key;
4309 * Symmetric key to use for encryption.
4311 char aes_key[256 / 8];
4314 * Counter value to use during setup.
4316 char aes_ctr[128 / 8];
4322 * Given the key material in @a km and the initialization vector
4323 * @a iv, setup the key material for the backchannel in @a key.
4325 * @param km raw master secret
4326 * @param iv initialization vector
4327 * @param key[out] symmetric cipher and HMAC state to generate
4330 dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4331 const struct GNUNET_ShortHashCode *iv,
4332 struct DVKeyState *key)
4334 /* must match #dh_key_derive_eph_pub */
4335 GNUNET_assert (GNUNET_YES ==
4336 GNUNET_CRYPTO_kdf (&key->material,
4337 sizeof(key->material),
4338 "transport-backchannel-key",
4339 strlen ("transport-backchannel-key"),
4344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4345 "Deriving backchannel key based on KM %s and IV %s\n",
4348 gcry_cipher_open (&key->cipher,
4349 GCRY_CIPHER_AES256 /* low level: go for speed */,
4350 GCRY_CIPHER_MODE_CTR,
4352 gcry_cipher_setkey (key->cipher,
4353 &key->material.aes_key,
4354 sizeof(key->material.aes_key));
4355 gcry_cipher_setctr (key->cipher,
4356 &key->material.aes_ctr,
4357 sizeof(key->material.aes_ctr));
4362 * Derive backchannel encryption key material from @a priv_ephemeral
4363 * and @a target and @a iv.
4365 * @param priv_ephemeral ephemeral private key to use
4366 * @param target the target peer to encrypt to
4367 * @param iv unique IV to use
4368 * @param key[out] set to the key material
4371 dh_key_derive_eph_pid (
4372 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4373 const struct GNUNET_PeerIdentity *target,
4374 const struct GNUNET_ShortHashCode *iv,
4375 struct DVKeyState *key)
4377 struct GNUNET_HashCode km;
4379 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4380 &target->public_key,
4382 dv_setup_key_state_from_km (&km, iv, key);
4387 * Derive backchannel encryption key material from #GST_my_private_key
4388 * and @a pub_ephemeral and @a iv.
4390 * @param priv_ephemeral ephemeral private key to use
4391 * @param target the target peer to encrypt to
4392 * @param iv unique IV to use
4393 * @param key[out] set to the key material
4396 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4397 const struct GNUNET_ShortHashCode *iv,
4398 struct DVKeyState *key)
4400 struct GNUNET_HashCode km;
4402 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4405 dv_setup_key_state_from_km (&km, iv, key);
4410 * Do HMAC calculation for backchannel messages over @a data using key
4411 * material from @a key.
4413 * @param key key material (from DH)
4414 * @param hmac[out] set to the HMAC
4415 * @param data data to perform HMAC calculation over
4416 * @param data_size number of bytes in @a data
4419 dv_hmac (const struct DVKeyState *key,
4420 struct GNUNET_HashCode *hmac,
4424 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4429 * Perform backchannel encryption using symmetric secret in @a key
4430 * to encrypt data from @a in to @a dst.
4432 * @param key[in,out] key material to use
4433 * @param dst where to write the result
4434 * @param in input data to encrypt (plaintext)
4435 * @param in_size number of bytes of input in @a in and available at @a dst
4438 dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4441 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4446 * Perform backchannel encryption using symmetric secret in @a key
4447 * to encrypt data from @a in to @a dst.
4449 * @param key[in,out] key material to use
4450 * @param ciph cipher text to decrypt
4451 * @param out[out] output data to generate (plaintext)
4452 * @param out_size number of bytes of input in @a ciph and available in @a out
4455 dv_decrypt (struct DVKeyState *key,
4461 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4466 * Clean up key material in @a key.
4468 * @param key key material to clean up (memory must not be free'd!)
4471 dv_key_clean (struct DVKeyState *key)
4473 gcry_cipher_close (key->cipher);
4474 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
4479 * Function to call to further operate on the now DV encapsulated
4480 * message @a hdr, forwarding it via @a next_hop under respect of
4483 * @param cls closure
4484 * @param next_hop next hop of the DV path
4485 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4486 * @param options options of the original message
4488 typedef void (*DVMessageHandler) (void *cls,
4489 struct Neighbour *next_hop,
4490 const struct GNUNET_MessageHeader *hdr,
4491 enum RouteMessageOptions options);
4494 * Pick a path of @a dv under constraints @a options and schedule
4495 * transmission of @a hdr.
4497 * @param target neighbour to ultimately send to
4498 * @param num_dvhs length of the @a dvhs array
4499 * @param dvhs array of hops to send the message to
4500 * @param hdr message to send as payload
4501 * @param use function to call with the encapsulated message
4502 * @param use_cls closure for @a use
4503 * @param options whether path must be confirmed or not, to be passed to @a use
4504 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4506 static struct GNUNET_TIME_Relative
4507 encapsulate_for_dv (struct DistanceVector *dv,
4508 unsigned int num_dvhs,
4509 struct DistanceVectorHop **dvhs,
4510 const struct GNUNET_MessageHeader *hdr,
4511 DVMessageHandler use,
4513 enum RouteMessageOptions options)
4515 struct TransportDVBoxMessage box_hdr;
4516 struct TransportDVBoxPayloadP payload_hdr;
4517 uint16_t enc_body_size = ntohs (hdr->size);
4518 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4519 struct TransportDVBoxPayloadP *enc_payload_hdr =
4520 (struct TransportDVBoxPayloadP *) enc;
4521 struct DVKeyState key;
4522 struct GNUNET_TIME_Relative rtt;
4524 /* Encrypt payload */
4525 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4526 box_hdr.total_hops = htons (0);
4527 update_ephemeral (dv);
4528 box_hdr.ephemeral_key = dv->ephemeral_key;
4529 payload_hdr.sender_sig = dv->sender_sig;
4530 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4532 sizeof(box_hdr.iv));
4533 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, &key);
4534 payload_hdr.sender = GST_my_identity;
4535 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4536 dv_encrypt (&key, &payload_hdr, enc_payload_hdr, sizeof(payload_hdr));
4539 &enc[sizeof(struct TransportDVBoxPayloadP)],
4541 dv_hmac (&key, &box_hdr.hmac, enc, sizeof(enc));
4542 dv_key_clean (&key);
4543 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4544 /* For each selected path, take the pre-computed header and body
4545 and add the path in the middle of the message; then send it. */
4546 for (unsigned int i = 0; i < num_dvhs; i++)
4548 struct DistanceVectorHop *dvh = dvhs[i];
4549 unsigned int num_hops = dvh->distance + 1;
4550 char buf[sizeof(struct TransportDVBoxMessage)
4551 + sizeof(struct GNUNET_PeerIdentity) * num_hops
4552 + sizeof(struct TransportDVBoxPayloadP)
4553 + enc_body_size] GNUNET_ALIGN;
4554 struct GNUNET_PeerIdentity *dhops;
4556 box_hdr.header.size = htons (sizeof(buf));
4557 box_hdr.num_hops = htons (num_hops);
4558 memcpy (buf, &box_hdr, sizeof(box_hdr));
4559 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
4562 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
4563 dhops[dvh->distance] = dv->target;
4564 if (GNUNET_EXTRA_LOGGING > 0)
4568 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4569 for (unsigned int j = 0; j <= num_hops; j++)
4573 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
4577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4578 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4580 GNUNET_i2s (&dv->target),
4586 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4587 memcpy (&dhops[num_hops], enc, sizeof(enc));
4590 (const struct GNUNET_MessageHeader *) buf,
4598 * Wrapper around #route_via_neighbour() that matches the
4599 * #DVMessageHandler structure.
4602 * @param next_hop where to send next
4603 * @param hdr header of the message to send
4604 * @param options message options for queue selection
4607 send_dv_to_neighbour (void *cls,
4608 struct Neighbour *next_hop,
4609 const struct GNUNET_MessageHeader *hdr,
4610 enum RouteMessageOptions options)
4613 (void) route_via_neighbour (next_hop, hdr, options);
4618 * We need to transmit @a hdr to @a target. If necessary, this may
4619 * involve DV routing. This function routes without applying flow
4620 * control or congestion control and should only be used for control
4623 * @param target peer to receive @a hdr
4624 * @param hdr header of the message to route and #GNUNET_free()
4625 * @param options which transmission channels are allowed
4626 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4628 static struct GNUNET_TIME_Relative
4629 route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4630 const struct GNUNET_MessageHeader *hdr,
4631 enum RouteMessageOptions options)
4633 struct VirtualLink *vl;
4634 struct Neighbour *n;
4635 struct DistanceVector *dv;
4636 struct GNUNET_TIME_Relative rtt1;
4637 struct GNUNET_TIME_Relative rtt2;
4639 vl = lookup_virtual_link (target);
4640 GNUNET_assert (NULL != vl);
4642 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4643 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4645 /* if confirmed is required, and we do not have anything
4646 confirmed, drop respective options */
4648 n = lookup_neighbour (target);
4649 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4650 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4652 if ((NULL == n) && (NULL == dv))
4654 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4655 "Cannot route message of type %u to %s: no route\n",
4657 GNUNET_i2s (target));
4658 GNUNET_STATISTICS_update (GST_stats,
4659 "# Messages dropped in routing: no acceptable method",
4662 return GNUNET_TIME_UNIT_FOREVER_REL;
4664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4665 "Routing message of type %u to %s with options %X\n",
4667 GNUNET_i2s (target),
4668 (unsigned int) options);
4669 /* If both dv and n are possible and we must choose:
4670 flip a coin for the choice between the two; for now 50/50 */
4671 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4673 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4678 if ((NULL != n) && (NULL != dv))
4679 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4680 enough for redunancy, so clear the flag. */
4681 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4682 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4685 rtt1 = route_via_neighbour (n, hdr, options);
4689 struct DistanceVectorHop *hops[2];
4692 res = pick_random_dv_hops (dv,
4695 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4698 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4699 "Failed to route message, could not determine DV path\n");
4702 rtt2 = encapsulate_for_dv (dv,
4706 &send_dv_to_neighbour,
4708 options & (~RMO_REDUNDANT));
4710 return GNUNET_TIME_relative_min (rtt1, rtt2);
4715 * Something changed on the virtual link with respect to flow
4716 * control. Consider retransmitting the FC window size.
4718 * @param cls a `struct VirtualLink` to work with
4721 consider_sending_fc (void *cls)
4723 struct VirtualLink *vl = cls;
4724 struct GNUNET_TIME_Absolute monotime;
4725 struct TransportFlowControlMessage fc;
4726 struct GNUNET_TIME_Relative duration;
4727 struct GNUNET_TIME_Relative rtt;
4729 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
4730 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
4732 /* For example, we should probably ONLY do this if a bit more than
4733 an RTT has passed, or if the window changed "significantly" since
4734 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
4735 need an estimate for the bandwidth-delay-product for the entire
4736 VL, as that determines "significantly". We have the delay, but
4737 the bandwidth statistics need to be added for the VL!*/(void) duration;
4739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4740 "Sending FC seq %u to %s with new window %llu\n",
4741 (unsigned int) vl->fc_seq_gen,
4742 GNUNET_i2s (&vl->target),
4743 (unsigned long long) vl->incoming_fc_window_size);
4744 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4745 vl->last_fc_transmission = monotime;
4746 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
4747 fc.header.size = htons (sizeof(fc));
4748 fc.seq = htonl (vl->fc_seq_gen++);
4749 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
4750 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
4751 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
4752 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
4753 rtt = route_control_message_without_fc (&vl->target, &fc.header, RMO_NONE);
4754 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
4756 rtt = GNUNET_TIME_UNIT_SECONDS;
4757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4758 "FC retransmission to %s failed, will retry in %s\n",
4759 GNUNET_i2s (&vl->target),
4760 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
4761 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
4765 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
4766 vl->last_fc_rtt = rtt;
4768 if (NULL != vl->fc_retransmit_task)
4769 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
4770 vl->fc_retransmit_task =
4771 GNUNET_SCHEDULER_add_delayed (rtt, &consider_sending_fc, vl);
4776 * There is a message at the head of the pending messages for @a vl
4777 * which may be ready for transmission. Check if a queue is ready to
4780 * This function must (1) check for flow control to ensure that we can
4781 * right now send to @a vl, (2) check that the pending message in the
4782 * queue is actually eligible, (3) determine if any applicable queue
4783 * (direct neighbour or DVH path) is ready to accept messages, and
4784 * (4) prioritize based on the preferences associated with the
4789 * @param vl virtual link where we should check for transmission
4792 check_vl_transmission (struct VirtualLink *vl)
4794 struct Neighbour *n = vl->n;
4795 struct DistanceVector *dv = vl->dv;
4796 struct GNUNET_TIME_Absolute now;
4799 /* Check that we have an eligible pending message!
4800 (cheaper than having #transmit_on_queue() find out!) */
4802 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
4806 continue; /* not eligible, is in a queue! */
4807 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
4808 vl->outbound_fc_window_size)
4810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4811 "Stalled transmision on VL %s due to flow control: %llu < %llu\n",
4812 GNUNET_i2s (&vl->target),
4813 (unsigned long long) vl->outbound_fc_window_size,
4814 (unsigned long long) (pm->bytes_msg
4815 + vl->outbound_fc_window_size_used));
4816 consider_sending_fc (vl);
4817 return; /* We have a message, but flow control says "nope" */
4822 if (GNUNET_NO == elig)
4825 /* Notify queues at direct neighbours that we are interested */
4826 now = GNUNET_TIME_absolute_get ();
4829 for (struct Queue *queue = n->queue_head; NULL != queue;
4830 queue = queue->next_neighbour)
4831 if ((GNUNET_YES == queue->idle) &&
4832 (queue->validated_until.abs_value_us > now.abs_value_us))
4833 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4835 /* Notify queues via DV that we are interested */
4838 /* Do DV with lower scheduler priority, which effectively means that
4839 IF a neighbour exists and is available, we prefer it. */
4840 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4843 struct Neighbour *nh = pos->next_hop;
4845 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
4846 continue; /* skip this one: path not validated */
4847 for (struct Queue *queue = nh->queue_head; NULL != queue;
4848 queue = queue->next_neighbour)
4849 if ((GNUNET_YES == queue->idle) &&
4850 (queue->validated_until.abs_value_us > now.abs_value_us))
4851 schedule_transmit_on_queue (queue,
4852 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
4859 * Client asked for transmission to a peer. Process the request.
4861 * @param cls the client
4862 * @param obm the send message that was sent
4865 handle_client_send (void *cls, const struct OutboundMessage *obm)
4867 struct TransportClient *tc = cls;
4868 struct PendingMessage *pm;
4869 const struct GNUNET_MessageHeader *obmm;
4871 struct VirtualLink *vl;
4872 enum GNUNET_MQ_PriorityPreferences pp;
4874 GNUNET_assert (CT_CORE == tc->type);
4875 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4876 bytes_msg = ntohs (obmm->size);
4877 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
4878 vl = lookup_virtual_link (&obm->peer);
4881 /* Failure: don't have this peer as a neighbour (anymore).
4882 Might have gone down asynchronously, so this is NOT
4883 a protocol violation by CORE. Still count the event,
4884 as this should be rare. */
4885 GNUNET_SERVICE_client_continue (tc->client);
4886 GNUNET_STATISTICS_update (GST_stats,
4887 "# messages dropped (neighbour unknown)",
4893 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
4894 pm->logging_uuid = logging_uuid_gen++;
4898 pm->bytes_msg = bytes_msg;
4899 memcpy (&pm[1], obmm, bytes_msg);
4900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4901 "Sending %u bytes as <%llu> to %s\n",
4904 GNUNET_i2s (&obm->peer));
4905 GNUNET_CONTAINER_MDLL_insert (client,
4906 tc->details.core.pending_msg_head,
4907 tc->details.core.pending_msg_tail,
4909 GNUNET_CONTAINER_MDLL_insert (vl,
4910 vl->pending_msg_head,
4911 vl->pending_msg_tail,
4913 check_vl_transmission (vl);
4918 * Communicator requests backchannel transmission. Process the request.
4919 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
4920 * (which for now has exactly the same format, only a different message type)
4921 * and passes it on for routing.
4923 * @param cls the client
4924 * @param cb the send message that was sent
4927 handle_communicator_backchannel (
4929 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4931 struct TransportClient *tc = cls;
4932 const struct GNUNET_MessageHeader *inbox =
4933 (const struct GNUNET_MessageHeader *) &cb[1];
4934 uint16_t isize = ntohs (inbox->size);
4935 const char *is = ((const char *) &cb[1]) + isize;
4939 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
4940 struct TransportBackchannelEncapsulationMessage *be =
4941 (struct TransportBackchannelEncapsulationMessage *) mbuf;
4943 /* 0-termination of 'is' was checked already in
4944 #check_communicator_backchannel() */
4945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4946 "Preparing backchannel transmission to %s:%s of type %u\n",
4947 GNUNET_i2s (&cb->pid),
4949 ntohs (inbox->size));
4950 /* encapsulate and encrypt message */
4952 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4953 be->header.size = htons (sizeof(mbuf));
4954 memcpy (&be[1], inbox, isize);
4955 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
4959 route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
4960 GNUNET_SERVICE_client_continue (tc->client);
4965 * Address of our peer added. Test message is well-formed.
4967 * @param cls the client
4968 * @param aam the send message that was sent
4969 * @return #GNUNET_OK if message is well-formed
4972 check_add_address (void *cls,
4973 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4975 struct TransportClient *tc = cls;
4977 if (CT_COMMUNICATOR != tc->type)
4980 return GNUNET_SYSERR;
4982 GNUNET_MQ_check_zero_termination (aam);
4988 * Ask peerstore to store our address.
4990 * @param cls an `struct AddressListEntry *`
4993 store_pi (void *cls);
4997 * Function called when peerstore is done storing our address.
4999 * @param cls a `struct AddressListEntry`
5000 * @param success #GNUNET_YES if peerstore was successful
5003 peerstore_store_own_cb (void *cls, int success)
5005 struct AddressListEntry *ale = cls;
5008 if (GNUNET_YES != success)
5009 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5010 "Failed to store our own address `%s' in peerstore!\n",
5013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5014 "Successfully stored our own address `%s' in peerstore!\n",
5016 /* refresh period is 1/4 of expiration time, that should be plenty
5017 without being excessive. */
5019 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5027 * Ask peerstore to store our address.
5029 * @param cls an `struct AddressListEntry *`
5032 store_pi (void *cls)
5034 struct AddressListEntry *ale = cls;
5037 struct GNUNET_TIME_Absolute expiration;
5040 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5042 "Storing our address `%s' in peerstore until %s!\n",
5044 GNUNET_STRINGS_absolute_time_to_string (expiration));
5045 GNUNET_HELLO_sign_address (ale->address,
5051 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5054 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5058 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5059 &peerstore_store_own_cb,
5062 if (NULL == ale->sc)
5064 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5065 "Failed to store our address `%s' with peerstore\n",
5068 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5074 * Address of our peer added. Process the request.
5076 * @param cls the client
5077 * @param aam the send message that was sent
5080 handle_add_address (void *cls,
5081 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5083 struct TransportClient *tc = cls;
5084 struct AddressListEntry *ale;
5087 /* 0-termination of &aam[1] was checked in #check_add_address */
5088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5089 "Communicator added address `%s'!\n",
5090 (const char *) &aam[1]);
5091 slen = ntohs (aam->header.size) - sizeof(*aam);
5092 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5094 ale->address = (const char *) &ale[1];
5095 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5096 ale->aid = aam->aid;
5097 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5098 memcpy (&ale[1], &aam[1], slen);
5099 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5100 tc->details.communicator.addr_tail,
5102 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5103 GNUNET_SERVICE_client_continue (tc->client);
5108 * Address of our peer deleted. Process the request.
5110 * @param cls the client
5111 * @param dam the send message that was sent
5114 handle_del_address (void *cls,
5115 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5117 struct TransportClient *tc = cls;
5118 struct AddressListEntry *alen;
5120 if (CT_COMMUNICATOR != tc->type)
5123 GNUNET_SERVICE_client_drop (tc->client);
5126 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5131 if (dam->aid != ale->aid)
5133 GNUNET_assert (ale->tc == tc);
5134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5135 "Communicator deleted address `%s'!\n",
5137 free_address_list_entry (ale);
5138 GNUNET_SERVICE_client_continue (tc->client);
5141 GNUNET_SERVICE_client_drop (tc->client);
5146 * Given an inbound message @a msg from a communicator @a cmc,
5147 * demultiplex it based on the type calling the right handler.
5149 * @param cmc context for demultiplexing
5150 * @param msg message to demultiplex
5153 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5154 const struct GNUNET_MessageHeader *msg);
5158 * Function called when we are done giving a message of a certain
5159 * size to CORE and should thus decrement the number of bytes of
5160 * RAM reserved for that peer's MQ.
5162 * @param cls a `struct CoreSentContext`
5165 core_env_sent_cb (void *cls)
5167 struct CoreSentContext *ctx = cls;
5168 struct VirtualLink *vl = ctx->vl;
5172 /* lost the link in the meantime, ignore */
5176 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5177 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5178 vl->incoming_fc_window_size_ram -= ctx->size;
5179 vl->incoming_fc_window_size_used += ctx->isize;
5180 consider_sending_fc (vl);
5186 * Communicator gave us an unencapsulated message to pass as-is to
5187 * CORE. Process the request.
5189 * @param cls a `struct CommunicatorMessageContext` (must call
5190 * #finish_cmc_handling() when done)
5191 * @param mh the message that was received
5194 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5196 struct CommunicatorMessageContext *cmc = cls;
5197 struct VirtualLink *vl;
5198 uint16_t size = ntohs (mh->size);
5201 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5202 (size < sizeof(struct GNUNET_MessageHeader)))
5204 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5207 finish_cmc_handling (cmc);
5208 GNUNET_SERVICE_client_drop (client);
5211 vl = lookup_virtual_link (&cmc->im.sender);
5214 /* FIXME: sender is giving us messages for CORE but we don't have
5215 the link up yet! I *suspect* this can happen right now (i.e.
5216 sender has verified us, but we didn't verify sender), but if
5217 we pass this on, CORE would be confused (link down, messages
5218 arrive). We should investigate more if this happens often,
5219 or in a persistent manner, and possibly do "something" about
5220 it. Thus logging as error for now. */GNUNET_break_op (0);
5221 GNUNET_STATISTICS_update (GST_stats,
5222 "# CORE messages droped (virtual link still down)",
5226 finish_cmc_handling (cmc);
5229 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5231 GNUNET_STATISTICS_update (GST_stats,
5232 "# CORE messages droped (FC arithmetic overflow)",
5236 finish_cmc_handling (cmc);
5239 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5241 GNUNET_STATISTICS_update (GST_stats,
5242 "# CORE messages droped (FC window overflow)",
5245 finish_cmc_handling (cmc);
5249 /* Forward to all CORE clients */
5250 have_core = GNUNET_NO;
5251 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5253 struct GNUNET_MQ_Envelope *env;
5254 struct InboundMessage *im;
5255 struct CoreSentContext *ctx;
5257 if (CT_CORE != tc->type)
5259 vl->incoming_fc_window_size_ram += size;
5260 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5261 ctx = GNUNET_new (struct CoreSentContext);
5264 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5265 have_core = GNUNET_YES;
5266 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5267 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5268 im->peer = cmc->im.sender;
5269 memcpy (&im[1], mh, size);
5270 GNUNET_MQ_send (tc->mq, env);
5271 vl->core_recv_window--;
5273 if (GNUNET_NO == have_core)
5275 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5276 "Dropped message to CORE: no CORE client connected!\n");
5277 /* Nevertheless, count window as used, as it is from the
5278 perspective of the other peer! */
5279 vl->incoming_fc_window_size_used += size;
5281 finish_cmc_handling (cmc);
5284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5285 "Delivered message from %s of type %u to CORE\n",
5286 GNUNET_i2s (&cmc->im.sender),
5288 if (vl->core_recv_window > 0)
5290 finish_cmc_handling (cmc);
5293 /* Wait with calling #finish_cmc_handling(cmc) until the message
5294 was processed by CORE MQs (for CORE flow control)! */
5295 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5300 * Communicator gave us a fragment box. Check the message.
5302 * @param cls a `struct CommunicatorMessageContext`
5303 * @param fb the send message that was sent
5304 * @return #GNUNET_YES if message is well-formed
5307 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5309 uint16_t size = ntohs (fb->header.size);
5310 uint16_t bsize = size - sizeof(*fb);
5315 GNUNET_break_op (0);
5316 return GNUNET_SYSERR;
5318 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5320 GNUNET_break_op (0);
5321 return GNUNET_SYSERR;
5323 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5325 GNUNET_break_op (0);
5326 return GNUNET_SYSERR;
5333 * Clean up an idle cummulative acknowledgement data structure.
5335 * @param cls a `struct AcknowledgementCummulator *`
5338 destroy_ack_cummulator (void *cls)
5340 struct AcknowledgementCummulator *ac = cls;
5343 GNUNET_assert (0 == ac->num_acks);
5346 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5352 * Do the transmission of a cummulative acknowledgement now.
5354 * @param cls a `struct AcknowledgementCummulator *`
5357 transmit_cummulative_ack_cb (void *cls)
5359 struct AcknowledgementCummulator *ac = cls;
5360 char buf[sizeof(struct TransportReliabilityAckMessage)
5362 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5363 struct TransportReliabilityAckMessage *ack =
5364 (struct TransportReliabilityAckMessage *) buf;
5365 struct TransportCummulativeAckPayloadP *ap;
5368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5369 "Sending ACK with %u components to %s\n",
5371 GNUNET_i2s (&ac->target));
5372 GNUNET_assert (0 < ac->ack_counter);
5373 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5376 + ac->ack_counter * sizeof(struct TransportCummulativeAckPayloadP));
5377 ack->ack_counter = htonl (ac->ack_counter++);
5378 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5379 for (unsigned int i = 0; i < ac->ack_counter; i++)
5381 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5382 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5383 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5385 route_control_message_without_fc (&ac->target, &ack->header, RMO_DV_ALLOWED);
5387 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5388 &destroy_ack_cummulator,
5394 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5395 * transmission by at most @a ack_delay.
5397 * @param pid target peer
5398 * @param ack_uuid UUID to ack
5399 * @param max_delay how long can the ACK wait
5402 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5403 const struct AcknowledgementUUIDP *ack_uuid,
5404 struct GNUNET_TIME_Absolute max_delay)
5406 struct AcknowledgementCummulator *ac;
5408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5409 "Scheduling ACK %s for transmission to %s\n",
5410 GNUNET_uuid2s (&ack_uuid->value),
5412 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5415 ac = GNUNET_new (struct AcknowledgementCummulator);
5417 ac->min_transmission_time = max_delay;
5418 GNUNET_assert (GNUNET_YES ==
5419 GNUNET_CONTAINER_multipeermap_put (
5423 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5427 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5429 /* must run immediately, ack buffer full! */
5430 GNUNET_SCHEDULER_cancel (ac->task);
5431 transmit_cummulative_ack_cb (ac);
5433 GNUNET_SCHEDULER_cancel (ac->task);
5434 ac->min_transmission_time =
5435 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5437 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5438 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5439 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5441 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5442 &transmit_cummulative_ack_cb,
5448 * Closure for #find_by_message_uuid.
5450 struct FindByMessageUuidContext
5455 struct MessageUUIDP message_uuid;
5458 * Set to the reassembly context if found.
5460 struct ReassemblyContext *rc;
5465 * Iterator called to find a reassembly context by the message UUID in the
5468 * @param cls a `struct FindByMessageUuidContext`
5469 * @param key a key (unused)
5470 * @param value a `struct ReassemblyContext`
5471 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5474 find_by_message_uuid (void *cls, uint32_t key, void *value)
5476 struct FindByMessageUuidContext *fc = cls;
5477 struct ReassemblyContext *rc = value;
5480 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5490 * Communicator gave us a fragment. Process the request.
5492 * @param cls a `struct CommunicatorMessageContext` (must call
5493 * #finish_cmc_handling() when done)
5494 * @param fb the message that was received
5497 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5499 struct CommunicatorMessageContext *cmc = cls;
5500 struct Neighbour *n;
5501 struct ReassemblyContext *rc;
5502 const struct GNUNET_MessageHeader *msg;
5507 struct GNUNET_TIME_Relative cdelay;
5508 struct FindByMessageUuidContext fc;
5510 n = lookup_neighbour (&cmc->im.sender);
5513 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5516 finish_cmc_handling (cmc);
5517 GNUNET_SERVICE_client_drop (client);
5520 if (NULL == n->reassembly_map)
5522 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5523 n->reassembly_heap =
5524 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5525 n->reassembly_timeout_task =
5526 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5527 &reassembly_cleanup_task,
5530 msize = ntohs (fb->msg_size);
5531 fc.message_uuid = fb->msg_uuid;
5533 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5535 &find_by_message_uuid,
5537 if (NULL == (rc = fc.rc))
5539 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
5540 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
5541 rc->msg_uuid = fb->msg_uuid;
5543 rc->msg_size = msize;
5544 rc->reassembly_timeout =
5545 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5546 rc->last_frag = GNUNET_TIME_absolute_get ();
5547 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5549 rc->reassembly_timeout.abs_value_us);
5550 GNUNET_assert (GNUNET_OK ==
5551 GNUNET_CONTAINER_multihashmap32_put (
5555 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5556 target = (char *) &rc[1];
5557 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5558 rc->msg_missing = rc->msg_size;
5559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5560 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5561 ntohs (fb->frag_off),
5563 GNUNET_i2s (&cmc->im.sender),
5564 (unsigned int) fb->msg_uuid.uuid);
5568 target = (char *) &rc[1];
5569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5570 "Received fragment at offset %u/%u from %s for message %u\n",
5571 ntohs (fb->frag_off),
5573 GNUNET_i2s (&cmc->im.sender),
5574 (unsigned int) fb->msg_uuid.uuid);
5576 if (msize != rc->msg_size)
5579 finish_cmc_handling (cmc);
5584 fsize = ntohs (fb->header.size) - sizeof(*fb);
5588 finish_cmc_handling (cmc);
5591 frag_off = ntohs (fb->frag_off);
5592 if (frag_off + fsize > msize)
5594 /* Fragment (plus fragment size) exceeds message size! */
5595 GNUNET_break_op (0);
5596 finish_cmc_handling (cmc);
5599 memcpy (&target[frag_off], &fb[1], fsize);
5600 /* update bitfield and msg_missing */
5601 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5603 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5605 rc->bitfield[i / 8] |= (1 << (i % 8));
5610 /* Compute cummulative ACK */
5611 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5612 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5613 if (0 == rc->msg_missing)
5614 cdelay = GNUNET_TIME_UNIT_ZERO;
5615 cummulative_ack (&cmc->im.sender,
5617 GNUNET_TIME_relative_to_absolute (cdelay));
5618 rc->last_frag = GNUNET_TIME_absolute_get ();
5619 /* is reassembly complete? */
5620 if (0 != rc->msg_missing)
5622 finish_cmc_handling (cmc);
5625 /* reassembly is complete, verify result */
5626 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5627 if (ntohs (msg->size) != rc->msg_size)
5630 free_reassembly_context (rc);
5631 finish_cmc_handling (cmc);
5634 /* successful reassembly */
5635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5636 "Fragment reassembly complete for message %u\n",
5637 (unsigned int) fb->msg_uuid.uuid);
5638 /* FIXME: check that the resulting msg is NOT a
5639 DV Box or Reliability Box, as that is NOT allowed! */
5640 demultiplex_with_cmc (cmc, msg);
5641 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5642 en-route and we forget that we finished this reassembly immediately!
5643 -> keep around until timeout?
5644 -> shorten timeout based on ACK? */
5645 free_reassembly_context (rc);
5650 * Communicator gave us a reliability box. Check the message.
5652 * @param cls a `struct CommunicatorMessageContext`
5653 * @param rb the send message that was sent
5654 * @return #GNUNET_YES if message is well-formed
5657 check_reliability_box (void *cls,
5658 const struct TransportReliabilityBoxMessage *rb)
5661 GNUNET_MQ_check_boxed_message (rb);
5667 * Communicator gave us a reliability box. Process the request.
5669 * @param cls a `struct CommunicatorMessageContext` (must call
5670 * #finish_cmc_handling() when done)
5671 * @param rb the message that was received
5674 handle_reliability_box (void *cls,
5675 const struct TransportReliabilityBoxMessage *rb)
5677 struct CommunicatorMessageContext *cmc = cls;
5678 const struct GNUNET_MessageHeader *inbox =
5679 (const struct GNUNET_MessageHeader *) &rb[1];
5680 struct GNUNET_TIME_Relative rtt;
5682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5683 "Received reliability box from %s with UUID %s of type %u\n",
5684 GNUNET_i2s (&cmc->im.sender),
5685 GNUNET_uuid2s (&rb->ack_uuid.value),
5686 (unsigned int) ntohs (inbox->type));
5687 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5688 do not really have an RTT for the
5689 * incoming* queue (should we have
5690 the sender add it to the rb message?) */
5694 (0 == ntohl (rb->ack_countdown))
5695 ? GNUNET_TIME_UNIT_ZERO_ABS
5696 : GNUNET_TIME_relative_to_absolute (
5697 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5698 /* continue with inner message */
5699 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5700 reliability box (not allowed!) */
5701 demultiplex_with_cmc (cmc, inbox);
5706 * Check if we have advanced to another age since the last time. If
5707 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5710 * @param pd[in,out] data to update
5711 * @param age current age
5714 update_pd_age (struct PerformanceData *pd, unsigned int age)
5718 if (age == pd->last_age)
5719 return; /* nothing to do */
5720 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5721 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5723 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5725 the->bytes_sent = 0;
5726 the->bytes_received = 0;
5733 * Update @a pd based on the latest @a rtt and the number of bytes
5734 * that were confirmed to be successfully transmitted.
5736 * @param pd[in,out] data to update
5737 * @param rtt latest round-trip time
5738 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5741 update_performance_data (struct PerformanceData *pd,
5742 struct GNUNET_TIME_Relative rtt,
5743 uint16_t bytes_transmitted_ok)
5745 uint64_t nval = rtt.rel_value_us;
5746 uint64_t oval = pd->aged_rtt.rel_value_us;
5747 unsigned int age = get_age ();
5748 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5750 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5753 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5754 update_pd_age (pd, age);
5755 the->bytes_received += bytes_transmitted_ok;
5760 * We have successfully transmitted data via @a q, update metrics.
5762 * @param q queue to update
5763 * @param rtt round trip time observed
5764 * @param bytes_transmitted_ok number of bytes successfully transmitted
5767 update_queue_performance (struct Queue *q,
5768 struct GNUNET_TIME_Relative rtt,
5769 uint16_t bytes_transmitted_ok)
5771 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5776 * We have successfully transmitted data via @a dvh, update metrics.
5778 * @param dvh distance vector path data to update
5779 * @param rtt round trip time observed
5780 * @param bytes_transmitted_ok number of bytes successfully transmitted
5783 update_dvh_performance (struct DistanceVectorHop *dvh,
5784 struct GNUNET_TIME_Relative rtt,
5785 uint16_t bytes_transmitted_ok)
5787 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5792 * We have completed transmission of @a pm, remove it from
5793 * the transmission queues (and if it is a fragment, continue
5794 * up the tree as necessary).
5796 * @param pm pending message that was transmitted
5799 completed_pending_message (struct PendingMessage *pm)
5801 struct PendingMessage *pos;
5806 case PMT_RELIABILITY_BOX:
5807 /* Full message sent, we are done */
5808 client_send_response (pm);
5811 case PMT_FRAGMENT_BOX:
5812 /* Fragment sent over reliabile channel */
5813 free_fragment_tree (pm);
5814 pos = pm->frag_parent;
5815 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5817 /* check if subtree is done */
5818 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5822 pos = pm->frag_parent;
5823 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5827 /* Was this the last applicable fragmment? */
5828 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
5829 (pos->frag_off == pos->bytes_msg))
5830 client_send_response (pos);
5834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5835 "Completed transmission of message %llu (DV Box)\n",
5837 free_pending_message (pm);
5844 * The @a pa was acknowledged, process the acknowledgement.
5846 * @param pa the pending acknowledgement that was satisfied
5847 * @param ack_delay artificial delay from cummulative acks created by the
5851 handle_acknowledged (struct PendingAcknowledgement *pa,
5852 struct GNUNET_TIME_Relative ack_delay)
5854 struct GNUNET_TIME_Relative delay;
5856 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5857 if (delay.rel_value_us > ack_delay.rel_value_us)
5858 delay = GNUNET_TIME_UNIT_ZERO;
5860 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5861 if (NULL != pa->queue)
5862 update_queue_performance (pa->queue, delay, pa->message_size);
5863 if (NULL != pa->dvh)
5864 update_dvh_performance (pa->dvh, delay, pa->message_size);
5866 completed_pending_message (pa->pm);
5867 free_pending_acknowledgement (pa);
5872 * Communicator gave us a reliability ack. Check it is well-formed.
5874 * @param cls a `struct CommunicatorMessageContext` (unused)
5875 * @param ra the message that was received
5876 * @return #GNUNET_Ok if @a ra is well-formed
5879 check_reliability_ack (void *cls,
5880 const struct TransportReliabilityAckMessage *ra)
5882 unsigned int n_acks;
5885 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5886 / sizeof(struct TransportCummulativeAckPayloadP);
5889 GNUNET_break_op (0);
5890 return GNUNET_SYSERR;
5892 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
5893 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
5895 GNUNET_break_op (0);
5896 return GNUNET_SYSERR;
5903 * Communicator gave us a reliability ack. Process the request.
5905 * @param cls a `struct CommunicatorMessageContext` (must call
5906 * #finish_cmc_handling() when done)
5907 * @param ra the message that was received
5910 handle_reliability_ack (void *cls,
5911 const struct TransportReliabilityAckMessage *ra)
5913 struct CommunicatorMessageContext *cmc = cls;
5914 const struct TransportCummulativeAckPayloadP *ack;
5915 unsigned int n_acks;
5916 uint32_t ack_counter;
5918 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5919 / sizeof(struct TransportCummulativeAckPayloadP);
5920 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5921 for (unsigned int i = 0; i < n_acks; i++)
5923 struct PendingAcknowledgement *pa =
5924 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5927 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5928 "Received ACK from %s with UUID %s which is unknown to us!\n",
5929 GNUNET_i2s (&cmc->im.sender),
5930 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5931 GNUNET_STATISTICS_update (
5933 "# FRAGMENT_ACKS dropped, no matching pending message",
5938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5939 "Received ACK from %s with UUID %s\n",
5940 GNUNET_i2s (&cmc->im.sender),
5941 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5942 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5945 ack_counter = htonl (ra->ack_counter);
5946 (void) ack_counter; /* silence compiler warning for now */
5947 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5948 // (DV and/or Neighbour?)
5949 finish_cmc_handling (cmc);
5954 * Communicator gave us a backchannel encapsulation. Check the message.
5956 * @param cls a `struct CommunicatorMessageContext`
5957 * @param be the send message that was sent
5958 * @return #GNUNET_YES if message is well-formed
5961 check_backchannel_encapsulation (
5963 const struct TransportBackchannelEncapsulationMessage *be)
5965 uint16_t size = ntohs (be->header.size) - sizeof(*be);
5966 const struct GNUNET_MessageHeader *inbox =
5967 (const struct GNUNET_MessageHeader *) &be[1];
5972 if (ntohs (inbox->size) >= size)
5974 GNUNET_break_op (0);
5975 return GNUNET_SYSERR;
5977 isize = ntohs (inbox->size);
5978 is = ((const char *) inbox) + isize;
5980 if ('\0' != is[size - 1])
5982 GNUNET_break_op (0);
5983 return GNUNET_SYSERR;
5990 * Communicator gave us a backchannel encapsulation. Process the request.
5991 * (We are the destination of the backchannel here.)
5993 * @param cls a `struct CommunicatorMessageContext` (must call
5994 * #finish_cmc_handling() when done)
5995 * @param be the message that was received
5998 handle_backchannel_encapsulation (
6000 const struct TransportBackchannelEncapsulationMessage *be)
6002 struct CommunicatorMessageContext *cmc = cls;
6003 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6004 struct GNUNET_MQ_Envelope *env;
6005 struct TransportClient *tc;
6006 const struct GNUNET_MessageHeader *inbox =
6007 (const struct GNUNET_MessageHeader *) &be[1];
6008 uint16_t isize = ntohs (inbox->size);
6009 const char *target_communicator = ((const char *) inbox) + isize;
6011 /* Find client providing this communicator */
6012 for (tc = clients_head; NULL != tc; tc = tc->next)
6013 if ((CT_COMMUNICATOR == tc->type) &&
6015 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6023 "# Backchannel message dropped: target communicator `%s' unknown",
6024 target_communicator);
6025 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6026 GNUNET_free (stastr);
6029 /* Finally, deliver backchannel message to communicator */
6030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6031 "Delivering backchannel message from %s of type %u to %s\n",
6032 GNUNET_i2s (&cmc->im.sender),
6033 ntohs (inbox->type),
6034 target_communicator);
6035 env = GNUNET_MQ_msg_extra (
6038 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6039 cbi->pid = cmc->im.sender;
6040 memcpy (&cbi[1], inbox, isize);
6041 GNUNET_MQ_send (tc->mq, env);
6046 * Task called when we should check if any of the DV paths
6047 * we have learned to a target are due for garbage collection.
6049 * Collects stale paths, and possibly frees the entire DV
6050 * entry if no paths are left. Otherwise re-schedules itself.
6052 * @param cls a `struct DistanceVector`
6055 path_cleanup_cb (void *cls)
6057 struct DistanceVector *dv = cls;
6058 struct DistanceVectorHop *pos;
6060 dv->timeout_task = NULL;
6061 while (NULL != (pos = dv->dv_head))
6063 GNUNET_assert (dv == pos->dv);
6064 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6066 free_distance_vector_hop (pos);
6074 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6079 * The @a hop is a validated path to the respective target
6080 * peer and we should tell core about it -- and schedule
6081 * a job to revoke the state.
6083 * @param hop a path to some peer that is the reason for activation
6086 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6088 struct DistanceVector *dv = hop->dv;
6089 struct VirtualLink *vl;
6091 vl = lookup_virtual_link (&dv->target);
6094 /* Link was already up, remember dv is also now available and we are done */
6096 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6097 "Virtual link to %s could now also use DV!\n",
6098 GNUNET_i2s (&dv->target));
6101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6102 "Creating new virtual link to %s using DV!\n",
6103 GNUNET_i2s (&dv->target));
6104 vl = GNUNET_new (struct VirtualLink);
6105 vl->message_uuid_ctr =
6106 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6107 vl->target = dv->target;
6110 vl->core_recv_window = RECV_WINDOW_SIZE;
6111 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6112 vl->visibility_task =
6113 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6114 GNUNET_break (GNUNET_YES ==
6115 GNUNET_CONTAINER_multipeermap_put (
6119 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6120 consider_sending_fc (vl);
6121 /* We lacked a confirmed connection to the target
6122 before, so tell CORE about it (finally!) */
6123 cores_send_connect_info (&dv->target);
6128 * We have learned a @a path through the network to some other peer, add it to
6129 * our DV data structure (returning #GNUNET_YES on success).
6131 * We do not add paths if we have a sufficient number of shorter
6132 * paths to this target already (returning #GNUNET_NO).
6134 * We also do not add problematic paths, like those where we lack the first
6135 * hop in our neighbour list (i.e. due to a topology change) or where some
6136 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6138 * @param path the path we learned, path[0] should be us,
6139 * and then path contains a valid path from us to
6140 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6141 * @param path_len number of entries on the @a path, at least three!
6142 * @param network_latency how long does the message take from us to
6143 * `path[path_len-1]`? set to "forever" if unknown
6144 * @param path_valid_until how long is this path considered validated? Maybe
6146 * @return #GNUNET_YES on success,
6147 * #GNUNET_NO if we have better path(s) to the target
6148 * #GNUNET_SYSERR if the path is useless and/or invalid
6149 * (i.e. path[1] not a direct neighbour
6150 * or path[i+1] is a direct neighbour for i>0)
6153 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6154 unsigned int path_len,
6155 struct GNUNET_TIME_Relative network_latency,
6156 struct GNUNET_TIME_Absolute path_valid_until)
6158 struct DistanceVectorHop *hop;
6159 struct DistanceVector *dv;
6160 struct Neighbour *next_hop;
6161 unsigned int shorter_distance;
6165 /* what a boring path! not allowed! */
6167 return GNUNET_SYSERR;
6169 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6170 next_hop = lookup_neighbour (&path[1]);
6171 if (NULL == next_hop)
6173 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6175 return GNUNET_SYSERR;
6177 for (unsigned int i = 2; i < path_len; i++)
6178 if (NULL != lookup_neighbour (&path[i]))
6180 /* Useless path: we have a direct connection to some hop
6181 in the middle of the path, so this one is not even
6182 terribly useful for redundancy */
6183 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6184 "Path of %u hops useless: directly link to hop %u (%s)\n",
6187 GNUNET_i2s (&path[i]));
6188 GNUNET_STATISTICS_update (GST_stats,
6189 "# Useless DV path ignored: hop is neighbour",
6192 return GNUNET_SYSERR;
6194 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6197 dv = GNUNET_new (struct DistanceVector);
6198 dv->target = path[path_len - 1];
6199 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6202 GNUNET_assert (GNUNET_OK ==
6203 GNUNET_CONTAINER_multipeermap_put (
6207 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6209 /* Check if we have this path already! */
6210 shorter_distance = 0;
6211 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6214 if (pos->distance < path_len - 2)
6216 /* Note that the distances in 'pos' excludes us (path[0]) and
6217 the next_hop (path[1]), so we need to subtract two
6218 and check next_hop explicitly */
6219 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6221 int match = GNUNET_YES;
6223 for (unsigned int i = 0; i < pos->distance; i++)
6225 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6231 if (GNUNET_YES == match)
6233 struct GNUNET_TIME_Relative last_timeout;
6235 /* Re-discovered known path, update timeout */
6236 GNUNET_STATISTICS_update (GST_stats,
6237 "# Known DV path refreshed",
6240 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6242 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6243 pos->path_valid_until =
6244 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6245 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6246 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6248 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6249 activate_core_visible_dv_path (pos);
6250 if (last_timeout.rel_value_us <
6251 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6252 DV_PATH_DISCOVERY_FREQUENCY)
6255 /* Some peer send DV learn messages too often, we are learning
6256 the same path faster than it would be useful; do not forward! */
6257 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6258 "Rediscovered path too quickly, not forwarding further\n");
6261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6262 "Refreshed known path to %s, forwarding further\n",
6263 GNUNET_i2s (&dv->target));
6268 /* Count how many shorter paths we have (incl. direct
6269 neighbours) before simply giving up on this one! */
6270 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6272 /* We have a shorter path already! */
6273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6274 "Have many shorter DV paths %s, not forwarding further\n",
6275 GNUNET_i2s (&dv->target));
6278 /* create new DV path entry */
6279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6280 "Discovered new DV path to %s\n",
6281 GNUNET_i2s (&dv->target));
6282 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
6283 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6284 hop->next_hop = next_hop;
6286 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6289 sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6290 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6291 hop->path_valid_until = path_valid_until;
6292 hop->distance = path_len - 2;
6293 hop->pd.aged_rtt = network_latency;
6294 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6295 GNUNET_CONTAINER_MDLL_insert (neighbour,
6299 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6300 activate_core_visible_dv_path (hop);
6306 * Communicator gave us a DV learn message. Check the message.
6308 * @param cls a `struct CommunicatorMessageContext`
6309 * @param dvl the send message that was sent
6310 * @return #GNUNET_YES if message is well-formed
6313 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6315 uint16_t size = ntohs (dvl->header.size);
6316 uint16_t num_hops = ntohs (dvl->num_hops);
6317 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6320 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
6322 GNUNET_break_op (0);
6323 return GNUNET_SYSERR;
6325 if (num_hops > MAX_DV_HOPS_ALLOWED)
6327 GNUNET_break_op (0);
6328 return GNUNET_SYSERR;
6330 for (unsigned int i = 0; i < num_hops; i++)
6332 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6334 GNUNET_break_op (0);
6335 return GNUNET_SYSERR;
6337 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6339 GNUNET_break_op (0);
6340 return GNUNET_SYSERR;
6348 * Build and forward a DV learn message to @a next_hop.
6350 * @param next_hop peer to send the message to
6351 * @param msg message received
6352 * @param bi_history bitmask specifying hops on path that were bidirectional
6353 * @param nhops length of the @a hops array
6354 * @param hops path the message traversed so far
6355 * @param in_time when did we receive the message, used to calculate network
6359 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6360 const struct TransportDVLearnMessage *msg,
6361 uint16_t bi_history,
6363 const struct DVPathEntryP *hops,
6364 struct GNUNET_TIME_Absolute in_time)
6366 struct DVPathEntryP *dhops;
6367 char buf[sizeof(struct TransportDVLearnMessage)
6368 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
6369 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6370 struct GNUNET_TIME_Relative nnd;
6372 /* compute message for forwarding */
6373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6374 "Forwarding DV learn message originating from %s to %s\n",
6375 GNUNET_i2s (&msg->initiator),
6376 GNUNET_i2s2 (next_hop));
6377 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6378 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6379 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
6380 + (nhops + 1) * sizeof(struct DVPathEntryP));
6381 fwd->num_hops = htons (nhops + 1);
6382 fwd->bidirectional = htons (bi_history);
6383 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6384 GNUNET_TIME_relative_ntoh (
6385 msg->non_network_delay));
6386 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6387 fwd->init_sig = msg->init_sig;
6388 fwd->initiator = msg->initiator;
6389 fwd->challenge = msg->challenge;
6390 dhops = (struct DVPathEntryP *) &fwd[1];
6391 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
6392 dhops[nhops].hop = GST_my_identity;
6394 struct DvHopPS dhp = { .purpose.purpose =
6395 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6396 .purpose.size = htonl (sizeof(dhp)),
6397 .pred = dhops[nhops - 1].hop,
6399 .challenge = msg->challenge };
6401 GNUNET_assert (GNUNET_OK ==
6402 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6404 &dhops[nhops].hop_sig));
6406 route_control_message_without_fc (next_hop,
6408 RMO_UNCONFIRMED_ALLOWED);
6413 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6415 * @param sender_monotonic_time monotonic time of the initiator
6416 * @param init the signer
6417 * @param challenge the challenge that was signed
6418 * @param init_sig signature presumably by @a init
6419 * @return #GNUNET_OK if the signature is valid
6422 validate_dv_initiator_signature (
6423 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6424 const struct GNUNET_PeerIdentity *init,
6425 const struct ChallengeNonceP *challenge,
6426 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6428 struct DvInitPS ip = { .purpose.purpose = htonl (
6429 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6430 .purpose.size = htonl (sizeof(ip)),
6431 .monotonic_time = sender_monotonic_time,
6432 .challenge = *challenge };
6436 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6441 GNUNET_break_op (0);
6442 return GNUNET_SYSERR;
6449 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6451 struct NeighbourSelectionContext
6454 * Original message we received.
6456 const struct TransportDVLearnMessage *dvl;
6461 const struct DVPathEntryP *hops;
6464 * Time we received the message.
6466 struct GNUNET_TIME_Absolute in_time;
6469 * Offsets of the selected peers.
6471 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6474 * Number of peers eligible for selection.
6476 unsigned int num_eligible;
6479 * Number of peers that were selected for forwarding.
6481 unsigned int num_selections;
6484 * Number of hops in @e hops
6489 * Bitmap of bidirectional connections encountered.
6491 uint16_t bi_history;
6496 * Function called for each neighbour during #handle_dv_learn.
6498 * @param cls a `struct NeighbourSelectionContext *`
6499 * @param pid identity of the peer
6500 * @param value a `struct Neighbour`
6501 * @return #GNUNET_YES (always)
6504 dv_neighbour_selection (void *cls,
6505 const struct GNUNET_PeerIdentity *pid,
6508 struct NeighbourSelectionContext *nsc = cls;
6511 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6512 return GNUNET_YES; /* skip initiator */
6513 for (unsigned int i = 0; i < nsc->nhops; i++)
6514 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6516 /* skip peers on path */
6517 nsc->num_eligible++;
6523 * Function called for each neighbour during #handle_dv_learn.
6524 * We call #forward_dv_learn() on the neighbour(s) selected
6525 * during #dv_neighbour_selection().
6527 * @param cls a `struct NeighbourSelectionContext *`
6528 * @param pid identity of the peer
6529 * @param value a `struct Neighbour`
6530 * @return #GNUNET_YES (always)
6533 dv_neighbour_transmission (void *cls,
6534 const struct GNUNET_PeerIdentity *pid,
6537 struct NeighbourSelectionContext *nsc = cls;
6540 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6541 return GNUNET_YES; /* skip initiator */
6542 for (unsigned int i = 0; i < nsc->nhops; i++)
6543 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6545 /* skip peers on path */
6546 for (unsigned int i = 0; i < nsc->num_selections; i++)
6548 if (nsc->selections[i] == nsc->num_eligible)
6550 forward_dv_learn (pid,
6559 nsc->num_eligible++;
6565 * Computes the number of neighbours we should forward a DVInit
6566 * message to given that it has so far taken @a hops_taken hops
6567 * though the network and that the number of neighbours we have
6568 * in total is @a neighbour_count, out of which @a eligible_count
6569 * are not yet on the path.
6571 * NOTE: technically we might want to include NSE in the formula to
6572 * get a better grip on the overall network size. However, for now
6573 * using NSE here would create a dependency issue in the build system.
6574 * => Left for later, hardcoded to 50 for now.
6576 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6577 * peers via DV (`target_total`). We want the reach to be spread out
6578 * over various distances to the origin, with a bias towards shorter
6581 * We make the strong assumption that the network topology looks
6582 * "similar" at other hops, in particular the @a neighbour_count
6583 * should be comparable at other hops.
6585 * If the local neighbourhood is densely connected, we expect that @a
6586 * eligible_count is close to @a neighbour_count minus @a hops_taken
6587 * as a lot of the path is already known. In that case, we should
6588 * forward to few(er) peers to try to find a path out of the
6589 * neighbourhood. OTOH, if @a eligible_count is close to @a
6590 * neighbour_count, we should forward to many peers as we are either
6591 * still close to the origin (i.e. @a hops_taken is small) or because
6592 * we managed to get beyond a local cluster. We express this as
6593 * the `boost_factor` using the square of the fraction of eligible
6594 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6595 * 99% are eligible, the 'boost' will be almost 1).
6597 * Second, the more hops we have taken, the larger the problem of an
6598 * exponential traffic explosion gets. So we take the `target_total`,
6599 * and compute our degree such that at each distance d 2^{-d} peers
6600 * are selected (corrected by the `boost_factor`).
6602 * @param hops_taken number of hops DVInit has travelled so far
6603 * @param neighbour_count number of neighbours we have in total
6604 * @param eligible_count number of neighbours we could in
6608 calculate_fork_degree (unsigned int hops_taken,
6609 unsigned int neighbour_count,
6610 unsigned int eligible_count)
6612 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6613 double eligible_ratio =
6614 ((double) eligible_count) / ((double) neighbour_count);
6615 double boost_factor = eligible_ratio * eligible_ratio;
6619 if (hops_taken >= 64)
6622 return 0; /* precaution given bitshift below */
6624 for (unsigned int i = 1; i < hops_taken; i++)
6626 /* For each hop, subtract the expected number of targets
6627 reached at distance d (so what remains divided by 2^d) */
6628 target_total -= (target_total * boost_factor / (1LLU << i));
6631 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6632 /* round up or down probabilistically depending on how close we were
6633 when floor()ing to rnd */
6634 left = target_total - (double) rnd;
6635 if (UINT32_MAX * left >
6636 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6637 rnd++; /* round up */
6638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6639 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6649 * Function called when peerstore is done storing a DV monotonic time.
6651 * @param cls a `struct Neighbour`
6652 * @param success #GNUNET_YES if peerstore was successful
6655 neighbour_store_dvmono_cb (void *cls, int success)
6657 struct Neighbour *n = cls;
6660 if (GNUNET_YES != success)
6661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6662 "Failed to store other peer's monotonic time in peerstore!\n");
6667 * Communicator gave us a DV learn message. Process the request.
6669 * @param cls a `struct CommunicatorMessageContext` (must call
6670 * #finish_cmc_handling() when done)
6671 * @param dvl the message that was received
6674 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6676 struct CommunicatorMessageContext *cmc = cls;
6677 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6680 uint16_t bi_history;
6681 const struct DVPathEntryP *hops;
6684 struct GNUNET_TIME_Absolute in_time;
6685 struct Neighbour *n;
6687 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6688 bi_history = ntohs (dvl->bidirectional);
6689 hops = (const struct DVPathEntryP *) &dvl[1];
6693 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6696 finish_cmc_handling (cmc);
6703 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6706 finish_cmc_handling (cmc);
6711 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6712 cc = cmc->tc->details.communicator.cc;
6713 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6714 cc); // FIXME: add bi-directional flag to cc?
6715 in_time = GNUNET_TIME_absolute_get ();
6717 /* continue communicator here, everything else can happen asynchronous! */
6718 finish_cmc_handling (cmc);
6720 n = lookup_neighbour (&dvl->initiator);
6723 if ((n->dv_monotime_available == GNUNET_YES) &&
6724 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6725 n->last_dv_learn_monotime.abs_value_us))
6727 GNUNET_STATISTICS_update (GST_stats,
6728 "# DV learn discarded due to time travel",
6733 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6738 GNUNET_break_op (0);
6741 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6742 if (GNUNET_YES == n->dv_monotime_available)
6745 GNUNET_PEERSTORE_store_cancel (n->sc);
6747 GNUNET_PEERSTORE_store (peerstore,
6750 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6751 &dvl->monotonic_time,
6752 sizeof(dvl->monotonic_time),
6753 GNUNET_TIME_UNIT_FOREVER_ABS,
6754 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6755 &neighbour_store_dvmono_cb,
6759 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6760 If signature verification load too high, implement random drop strategy */
6761 for (unsigned int i = 0; i < nhops; i++)
6763 struct DvHopPS dhp = { .purpose.purpose =
6764 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6765 .purpose.size = htonl (sizeof(dhp)),
6766 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6767 .succ = (nhops == i + 1) ? GST_my_identity
6769 .challenge = dvl->challenge };
6772 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6775 &hops[i].hop.public_key))
6777 GNUNET_break_op (0);
6782 if (GNUNET_EXTRA_LOGGING > 0)
6786 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6787 for (unsigned int i = 0; i < nhops; i++)
6791 GNUNET_asprintf (&tmp,
6794 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6795 GNUNET_i2s (&hops[i].hop));
6799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6800 "Received DVInit via %s%s%s\n",
6802 bi_hop ? "<->" : "-->",
6803 GNUNET_i2s (&GST_my_identity));
6807 do_fwd = GNUNET_YES;
6808 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6810 struct GNUNET_PeerIdentity path[nhops + 1];
6811 struct GNUNET_TIME_Relative host_latency_sum;
6812 struct GNUNET_TIME_Relative latency;
6813 struct GNUNET_TIME_Relative network_latency;
6815 /* We initiated this, learn the forward path! */
6816 path[0] = GST_my_identity;
6817 path[1] = hops[0].hop;
6818 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6820 // Need also something to lookup initiation time
6821 // to compute RTT! -> add RTT argument here?
6822 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6823 // (based on dvl->challenge, we can identify time of origin!)
6825 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6826 /* assumption: latency on all links is the same */
6827 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6829 for (unsigned int i = 2; i <= nhops; i++)
6831 struct GNUNET_TIME_Relative ilat;
6833 /* assumption: linear latency increase per hop */
6834 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6835 path[i] = hops[i - 1].hop;
6836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6837 "Learned path with %u hops to %s with latency %s\n",
6839 GNUNET_i2s (&path[i]),
6840 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6841 learn_dv_path (path,
6844 GNUNET_TIME_relative_to_absolute (
6845 ADDRESS_VALIDATION_LIFETIME));
6847 /* as we initiated, do not forward again (would be circular!) */
6853 /* last hop was bi-directional, we could learn something here! */
6854 struct GNUNET_PeerIdentity path[nhops + 2];
6856 path[0] = GST_my_identity;
6857 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6858 for (unsigned int i = 0; i < nhops; i++)
6862 if (0 == (bi_history & (1 << i)))
6863 break; /* i-th hop not bi-directional, stop learning! */
6866 path[i + 2] = dvl->initiator;
6870 path[i + 2] = hops[nhops - i - 2].hop;
6873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6874 "Learned inverse path with %u hops to %s\n",
6876 GNUNET_i2s (&path[i + 2]));
6877 iret = learn_dv_path (path,
6879 GNUNET_TIME_UNIT_FOREVER_REL,
6880 GNUNET_TIME_UNIT_ZERO_ABS);
6881 if (GNUNET_SYSERR == iret)
6883 /* path invalid or too long to be interesting for US, thus should also
6884 not be interesting to our neighbours, cut path when forwarding to
6885 'i' hops, except of course for the one that goes back to the
6887 GNUNET_STATISTICS_update (GST_stats,
6888 "# DV learn not forwarded due invalidity of path",
6894 if ((GNUNET_NO == iret) && (nhops == i + 1))
6896 /* we have better paths, and this is the longest target,
6897 so there cannot be anything interesting later */
6898 GNUNET_STATISTICS_update (GST_stats,
6899 "# DV learn not forwarded, got better paths",
6908 if (MAX_DV_HOPS_ALLOWED == nhops)
6910 /* At limit, we're out of here! */
6911 finish_cmc_handling (cmc);
6915 /* Forward to initiator, if path non-trivial and possible */
6916 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6917 did_initiator = GNUNET_NO;
6920 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6922 /* send back to origin! */
6923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6924 "Sending DVL back to initiator %s\n",
6925 GNUNET_i2s (&dvl->initiator));
6926 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6927 did_initiator = GNUNET_YES;
6929 /* We forward under two conditions: either we still learned something
6930 ourselves (do_fwd), or the path was darn short and thus the initiator is
6931 likely to still be very interested in this (and we did NOT already
6932 send it back to the initiator) */
6933 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6934 (GNUNET_NO == did_initiator)))
6936 /* Pick random neighbours that are not yet on the path */
6937 struct NeighbourSelectionContext nsc;
6940 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6943 nsc.bi_history = bi_history;
6945 nsc.in_time = in_time;
6946 nsc.num_eligible = 0;
6947 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6948 &dv_neighbour_selection,
6950 if (0 == nsc.num_eligible)
6951 return; /* done here, cannot forward to anyone else */
6952 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6953 nsc.num_selections =
6954 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6956 "Forwarding DVL to %u other peers\n",
6957 nsc.num_selections);
6958 for (unsigned int i = 0; i < nsc.num_selections; i++)
6960 (nsc.num_selections == n_cnt)
6961 ? i /* all were selected, avoid collisions by chance */
6962 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6963 nsc.num_eligible = 0;
6964 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6965 &dv_neighbour_transmission,
6972 * Communicator gave us a DV box. Check the message.
6974 * @param cls a `struct CommunicatorMessageContext`
6975 * @param dvb the send message that was sent
6976 * @return #GNUNET_YES if message is well-formed
6979 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6981 uint16_t size = ntohs (dvb->header.size);
6982 uint16_t num_hops = ntohs (dvb->num_hops);
6983 const struct GNUNET_PeerIdentity *hops =
6984 (const struct GNUNET_PeerIdentity *) &dvb[1];
6987 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
6988 + sizeof(struct GNUNET_MessageHeader))
6990 GNUNET_break_op (0);
6991 return GNUNET_SYSERR;
6993 /* This peer must not be on the path */
6994 for (unsigned int i = 0; i < num_hops; i++)
6995 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6997 GNUNET_break_op (0);
6998 return GNUNET_SYSERR;
7005 * Create a DV Box message and queue it for transmission to
7008 * @param next_hop peer to receive the message next
7009 * @param total_hops how many hops did the message take so far
7010 * @param num_hops length of the @a hops array
7011 * @param origin origin of the message
7012 * @param hops next peer(s) to the destination, including destination
7013 * @param payload payload of the box
7014 * @param payload_size number of bytes in @a payload
7017 forward_dv_box (struct Neighbour *next_hop,
7018 const struct TransportDVBoxMessage *hdr,
7019 uint16_t total_hops,
7021 const struct GNUNET_PeerIdentity *hops,
7022 const void *enc_payload,
7023 uint16_t enc_payload_size)
7025 struct VirtualLink *vl = next_hop->vl;
7026 struct PendingMessage *pm;
7029 struct GNUNET_PeerIdentity *dhops;
7031 GNUNET_assert (NULL != vl);
7032 msg_size = sizeof(struct TransportDVBoxMessage)
7033 + num_hops * sizeof(struct GNUNET_PeerIdentity) + enc_payload_size;
7034 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7035 pm->pmt = PMT_DV_BOX;
7037 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7038 pm->logging_uuid = logging_uuid_gen++;
7039 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7040 pm->bytes_msg = msg_size;
7041 buf = (char *) &pm[1];
7042 memcpy (buf, hdr, sizeof(*hdr));
7044 (struct GNUNET_PeerIdentity *) &buf[sizeof(struct TransportDVBoxMessage)];
7045 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7046 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7047 GNUNET_CONTAINER_MDLL_insert (vl,
7048 vl->pending_msg_head,
7049 vl->pending_msg_tail,
7051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7052 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7054 GNUNET_i2s (&next_hop->pid),
7055 (unsigned int) num_hops,
7056 (unsigned int) total_hops);
7057 check_vl_transmission (vl);
7062 * Free data structures associated with @a b.
7064 * @param b data structure to release
7067 free_backtalker (struct Backtalker *b)
7071 GNUNET_PEERSTORE_iterate_cancel (b->get);
7073 GNUNET_assert (NULL != b->cmc);
7074 finish_cmc_handling (b->cmc);
7077 if (NULL != b->task)
7079 GNUNET_SCHEDULER_cancel (b->task);
7084 GNUNET_PEERSTORE_store_cancel (b->sc);
7089 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7095 * Callback to free backtalker records.
7099 * @param value a `struct Backtalker`
7100 * @return #GNUNET_OK (always)
7103 free_backtalker_cb (void *cls,
7104 const struct GNUNET_PeerIdentity *pid,
7107 struct Backtalker *b = value;
7111 free_backtalker (b);
7117 * Function called when it is time to clean up a backtalker.
7119 * @param cls a `struct Backtalker`
7122 backtalker_timeout_cb (void *cls)
7124 struct Backtalker *b = cls;
7127 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7129 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7132 GNUNET_assert (NULL == b->sc);
7133 free_backtalker (b);
7138 * Function called with the monotonic time of a backtalker
7139 * by PEERSTORE. Updates the time and continues processing.
7141 * @param cls a `struct Backtalker`
7142 * @param record the information found, NULL for the last call
7143 * @param emsg error message
7146 backtalker_monotime_cb (void *cls,
7147 const struct GNUNET_PEERSTORE_Record *record,
7150 struct Backtalker *b = cls;
7151 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7152 struct GNUNET_TIME_Absolute mt;
7157 /* we're done with #backtalker_monotime_cb() invocations,
7158 continue normal processing */
7160 GNUNET_assert (NULL != b->cmc);
7161 if (0 != b->body_size)
7162 demultiplex_with_cmc (b->cmc,
7163 (const struct GNUNET_MessageHeader *) &b[1]);
7165 finish_cmc_handling (b->cmc);
7169 if (sizeof(*mtbe) != record->value_size)
7174 mtbe = record->value;
7175 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7176 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7179 "Backtalker message from %s dropped, monotime in the past\n",
7180 GNUNET_i2s (&b->pid));
7181 GNUNET_STATISTICS_update (
7183 "# Backchannel messages dropped: monotonic time not increasing",
7186 b->monotonic_time = mt;
7187 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7196 * Function called by PEERSTORE when the store operation of
7197 * a backtalker's monotonic time is complete.
7199 * @param cls the `struct Backtalker`
7200 * @param success #GNUNET_OK on success
7203 backtalker_monotime_store_cb (void *cls, int success)
7205 struct Backtalker *b = cls;
7207 if (GNUNET_OK != success)
7209 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7210 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7213 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7218 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7220 * @param b a backtalker with updated monotonic time
7223 update_backtalker_monotime (struct Backtalker *b)
7225 struct GNUNET_TIME_AbsoluteNBO mtbe;
7229 GNUNET_PEERSTORE_store_cancel (b->sc);
7234 GNUNET_SCHEDULER_cancel (b->task);
7237 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7239 GNUNET_PEERSTORE_store (peerstore,
7242 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7245 GNUNET_TIME_UNIT_FOREVER_ABS,
7246 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7247 &backtalker_monotime_store_cb,
7253 * Communicator gave us a DV box. Process the request.
7255 * @param cls a `struct CommunicatorMessageContext` (must call
7256 * #finish_cmc_handling() when done)
7257 * @param dvb the message that was received
7260 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7262 struct CommunicatorMessageContext *cmc = cls;
7263 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
7264 uint16_t num_hops = ntohs (dvb->num_hops);
7265 const struct GNUNET_PeerIdentity *hops =
7266 (const struct GNUNET_PeerIdentity *) &dvb[1];
7267 const char *enc_payload = (const char *) &hops[num_hops];
7268 uint16_t enc_payload_size =
7269 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
7270 struct DVKeyState key;
7271 struct GNUNET_HashCode hmac;
7275 if (GNUNET_EXTRA_LOGGING > 0)
7279 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7280 for (unsigned int i = 0; i < num_hops; i++)
7284 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7289 "Received DVBox with remainig path %s\n",
7296 /* We're trying from the end of the hops array, as we may be
7297 able to find a shortcut unknown to the origin that way */
7298 for (int i = num_hops - 1; i >= 0; i--)
7300 struct Neighbour *n;
7302 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7304 GNUNET_break_op (0);
7305 finish_cmc_handling (cmc);
7308 n = lookup_neighbour (&hops[i]);
7311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7312 "Skipping %u/%u hops ahead while routing DV Box\n",
7317 ntohs (dvb->total_hops) + 1,
7318 num_hops - i - 1, /* number of hops left */
7319 &hops[i + 1], /* remaining hops */
7322 GNUNET_STATISTICS_update (GST_stats,
7323 "# DV hops skipped routing boxes",
7326 GNUNET_STATISTICS_update (GST_stats,
7327 "# DV boxes routed (total)",
7330 finish_cmc_handling (cmc);
7333 /* Woopsie, next hop not in neighbours, drop! */
7334 GNUNET_STATISTICS_update (GST_stats,
7335 "# DV Boxes dropped: next hop unknown",
7338 finish_cmc_handling (cmc);
7341 /* We are the target. Unbox and handle message. */
7342 GNUNET_STATISTICS_update (GST_stats,
7343 "# DV boxes opened (ultimate target)",
7346 cmc->total_hops = ntohs (dvb->total_hops);
7348 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key);
7349 hdr = (const char *) &dvb[1];
7350 hdr_len = ntohs (dvb->header.size) - sizeof(*dvb);
7351 dv_hmac (&key, &hmac, hdr, hdr_len);
7352 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7354 /* HMAC missmatch, disard! */
7355 GNUNET_break_op (0);
7356 finish_cmc_handling (cmc);
7359 /* begin actual decryption */
7361 struct Backtalker *b;
7362 struct GNUNET_TIME_Absolute monotime;
7363 struct TransportDVBoxPayloadP ppay;
7364 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
7365 const struct GNUNET_MessageHeader *mh =
7366 (const struct GNUNET_MessageHeader *) body;
7368 GNUNET_assert (hdr_len >=
7369 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
7370 dv_decrypt (&key, &ppay, hdr, sizeof(ppay));
7371 dv_decrypt (&key, &body, &hdr[sizeof(ppay)], hdr_len - sizeof(ppay));
7372 dv_key_clean (&key);
7373 if (ntohs (mh->size) != sizeof(body))
7375 GNUNET_break_op (0);
7376 finish_cmc_handling (cmc);
7379 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7380 switch (ntohs (mh->type))
7382 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7383 GNUNET_break_op (0);
7384 finish_cmc_handling (cmc);
7387 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7388 GNUNET_break_op (0);
7389 finish_cmc_handling (cmc);
7393 /* permitted, continue */
7396 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7398 "Decrypted backtalk from %s\n",
7399 GNUNET_i2s (&ppay.sender));
7400 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
7401 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
7403 GNUNET_STATISTICS_update (
7405 "# Backchannel messages dropped: monotonic time not increasing",
7408 finish_cmc_handling (cmc);
7412 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
7414 /* Check signature */
7415 struct EphemeralConfirmationPS ec;
7417 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
7418 ec.purpose.size = htonl (sizeof(ec));
7419 ec.target = GST_my_identity;
7420 ec.ephemeral_key = dvb->ephemeral_key;
7423 GNUNET_CRYPTO_eddsa_verify (
7424 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
7427 &ppay.sender.public_key))
7429 /* Signature invalid, disard! */
7430 GNUNET_break_op (0);
7431 finish_cmc_handling (cmc);
7435 /* Update sender, we now know the real origin! */
7436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7437 "DVBox received for me from %s via %s\n",
7438 GNUNET_i2s2 (&ppay.sender),
7439 GNUNET_i2s (&cmc->im.sender));
7440 cmc->im.sender = ppay.sender;
7444 /* update key cache and mono time */
7445 b->last_ephemeral = dvb->ephemeral_key;
7446 b->monotonic_time = monotime;
7447 update_backtalker_monotime (b);
7449 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7451 demultiplex_with_cmc (cmc, mh);
7454 /* setup data structure to cache signature AND check
7455 monotonic time with PEERSTORE before forwarding backchannel payload */
7456 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
7457 b->pid = ppay.sender;
7458 b->body_size = sizeof(body);
7459 memcpy (&b[1], body, sizeof(body));
7460 GNUNET_assert (GNUNET_YES ==
7461 GNUNET_CONTAINER_multipeermap_put (
7465 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7466 b->monotonic_time = monotime; /* NOTE: to be checked still! */
7469 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7470 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7472 GNUNET_PEERSTORE_iterate (peerstore,
7475 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7476 &backtalker_monotime_cb,
7478 } /* end actual decryption */
7483 * Client notified us about transmission from a peer. Process the request.
7485 * @param cls a `struct TransportClient` which sent us the message
7486 * @param obm the send message that was sent
7487 * @return #GNUNET_YES if message is well-formed
7490 check_incoming_msg (void *cls,
7491 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7493 struct TransportClient *tc = cls;
7495 if (CT_COMMUNICATOR != tc->type)
7498 return GNUNET_SYSERR;
7500 GNUNET_MQ_check_boxed_message (im);
7506 * Closure for #check_known_address.
7508 struct CheckKnownAddressContext
7511 * Set to the address we are looking for.
7513 const char *address;
7516 * Set to a matching validation state, if one was found.
7518 struct ValidationState *vs;
7523 * Test if the validation state in @a value matches the
7524 * address from @a cls.
7526 * @param cls a `struct CheckKnownAddressContext`
7527 * @param pid unused (must match though)
7528 * @param value a `struct ValidationState`
7529 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7532 check_known_address (void *cls,
7533 const struct GNUNET_PeerIdentity *pid,
7536 struct CheckKnownAddressContext *ckac = cls;
7537 struct ValidationState *vs = value;
7540 if (0 != strcmp (vs->address, ckac->address))
7548 * Task run periodically to validate some address based on #validation_heap.
7553 validation_start_cb (void *cls);
7557 * Set the time for next_challenge of @a vs to @a new_time.
7558 * Updates the heap and if necessary reschedules the job.
7560 * @param vs validation state to update
7561 * @param new_time new time for revalidation
7564 update_next_challenge_time (struct ValidationState *vs,
7565 struct GNUNET_TIME_Absolute new_time)
7567 struct GNUNET_TIME_Relative delta;
7569 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7570 return; /* be lazy */
7571 vs->next_challenge = new_time;
7574 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7576 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7577 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7578 (NULL != validation_task))
7580 if (NULL != validation_task)
7581 GNUNET_SCHEDULER_cancel (validation_task);
7582 /* randomize a bit */
7583 delta.rel_value_us =
7584 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7585 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7586 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7588 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7593 * Start address validation.
7595 * @param pid peer the @a address is for
7596 * @param address an address to reach @a pid (presumably)
7599 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7600 const char *address)
7602 struct GNUNET_TIME_Absolute now;
7603 struct ValidationState *vs;
7604 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
7606 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7608 &check_known_address,
7610 if (NULL != (vs = ckac.vs))
7612 /* if 'vs' is not currently valid, we need to speed up retrying the
7614 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7616 /* reduce backoff as we got a fresh advertisement */
7617 vs->challenge_backoff =
7618 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7619 GNUNET_TIME_relative_divide (
7620 vs->challenge_backoff,
7622 update_next_challenge_time (vs,
7623 GNUNET_TIME_relative_to_absolute (
7624 vs->challenge_backoff));
7628 now = GNUNET_TIME_absolute_get ();
7629 vs = GNUNET_new (struct ValidationState);
7632 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7633 vs->first_challenge_use = now;
7634 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7635 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7637 sizeof(vs->challenge));
7638 vs->address = GNUNET_strdup (address);
7639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7640 "Starting address validation `%s' of peer %s using challenge %s\n",
7643 GNUNET_sh2s (&vs->challenge.value));
7644 GNUNET_assert (GNUNET_YES ==
7645 GNUNET_CONTAINER_multipeermap_put (
7649 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7650 update_next_challenge_time (vs, now);
7655 * Function called by PEERSTORE for each matching record.
7657 * @param cls closure, a `struct IncomingRequest`
7658 * @param record peerstore record information
7659 * @param emsg error message, or NULL if no errors
7662 handle_hello_for_incoming (void *cls,
7663 const struct GNUNET_PEERSTORE_Record *record,
7666 struct IncomingRequest *ir = cls;
7671 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7672 "Got failure from PEERSTORE: %s\n",
7676 val = record->value;
7677 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7682 start_address_validation (&ir->pid, (const char *) record->value);
7687 * Communicator gave us a transport address validation challenge. Process the
7690 * @param cls a `struct CommunicatorMessageContext` (must call
7691 * #finish_cmc_handling() when done)
7692 * @param tvc the message that was received
7695 handle_validation_challenge (
7697 const struct TransportValidationChallengeMessage *tvc)
7699 struct CommunicatorMessageContext *cmc = cls;
7700 struct TransportValidationResponseMessage tvr;
7701 struct VirtualLink *vl;
7702 struct GNUNET_TIME_RelativeNBO validity_duration;
7703 struct IncomingRequest *ir;
7704 struct Neighbour *n;
7705 struct GNUNET_PeerIdentity sender;
7707 /* DV-routed messages are not allowed for validation challenges */
7708 if (cmc->total_hops > 0)
7710 GNUNET_break_op (0);
7711 finish_cmc_handling (cmc);
7714 validity_duration = cmc->im.expected_address_validity;
7715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7716 "Received address validation challenge %s\n",
7717 GNUNET_sh2s (&tvc->challenge.value));
7718 /* If we have a virtual link, we use this mechanism to signal the
7719 size of the flow control window, and to allow the sender
7720 to ask for increases. If for us the virtual link is still down,
7721 we will always give a window size of zero. */
7723 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7724 tvr.header.size = htons (sizeof(tvr));
7725 tvr.reserved = htonl (0);
7726 tvr.challenge = tvc->challenge;
7727 tvr.origin_time = tvc->sender_time;
7728 tvr.validity_duration = validity_duration;
7730 /* create signature */
7731 struct TransportValidationPS tvp =
7732 { .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7733 .purpose.size = htonl (sizeof(tvp)),
7734 .validity_duration = validity_duration,
7735 .challenge = tvc->challenge };
7737 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7741 route_control_message_without_fc (&cmc->im.sender,
7743 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7744 sender = cmc->im.sender;
7745 finish_cmc_handling (cmc);
7746 vl = lookup_virtual_link (&sender);
7750 /* For us, the link is still down, but we need bi-directional
7751 connections (for flow-control and for this to be useful for
7752 CORE), so we must try to bring the link up! */
7754 /* (1) Check existing queues, if any, we may be lucky! */
7755 n = lookup_neighbour (&sender);
7757 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7758 start_address_validation (&sender, q->address);
7759 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7761 for (ir = ir_head; NULL != ir; ir = ir->next)
7762 if (0 == GNUNET_memcmp (&ir->pid, &sender))
7764 /* we are already trying */
7765 ir = GNUNET_new (struct IncomingRequest);
7767 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7768 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7771 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7772 &handle_hello_for_incoming,
7775 /* Bound attempts we do in parallel here, might otherwise get excessive */
7776 while (ir_total > MAX_INCOMING_REQUEST)
7777 free_incoming_request (ir_head);
7782 * Closure for #check_known_challenge.
7784 struct CheckKnownChallengeContext
7787 * Set to the challenge we are looking for.
7789 const struct ChallengeNonceP *challenge;
7792 * Set to a matching validation state, if one was found.
7794 struct ValidationState *vs;
7799 * Test if the validation state in @a value matches the
7800 * challenge from @a cls.
7802 * @param cls a `struct CheckKnownChallengeContext`
7803 * @param pid unused (must match though)
7804 * @param value a `struct ValidationState`
7805 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7808 check_known_challenge (void *cls,
7809 const struct GNUNET_PeerIdentity *pid,
7812 struct CheckKnownChallengeContext *ckac = cls;
7813 struct ValidationState *vs = value;
7816 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7824 * Function called when peerstore is done storing a
7825 * validated address.
7827 * @param cls a `struct ValidationState`
7828 * @param success #GNUNET_YES on success
7831 peerstore_store_validation_cb (void *cls, int success)
7833 struct ValidationState *vs = cls;
7836 if (GNUNET_YES == success)
7838 GNUNET_STATISTICS_update (GST_stats,
7839 "# Peerstore failed to store foreign address",
7846 * Find the queue matching @a pid and @a address.
7848 * @param pid peer the queue must go to
7849 * @param address address the queue must use
7850 * @return NULL if no such queue exists
7852 static struct Queue *
7853 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7855 struct Neighbour *n;
7857 n = lookup_neighbour (pid);
7860 for (struct Queue *pos = n->queue_head; NULL != pos;
7861 pos = pos->next_neighbour)
7863 if (0 == strcmp (pos->address, address))
7871 * Communicator gave us a transport address validation response. Process the
7874 * @param cls a `struct CommunicatorMessageContext` (must call
7875 * #finish_cmc_handling() when done)
7876 * @param tvr the message that was received
7879 handle_validation_response (
7881 const struct TransportValidationResponseMessage *tvr)
7883 struct CommunicatorMessageContext *cmc = cls;
7884 struct ValidationState *vs;
7885 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
7887 struct GNUNET_TIME_Absolute origin_time;
7889 struct Neighbour *n;
7890 struct VirtualLink *vl;
7892 /* check this is one of our challenges */
7893 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7895 &check_known_challenge,
7897 if (NULL == (vs = ckac.vs))
7899 /* This can happen simply if we 'forgot' the challenge by now,
7900 i.e. because we received the validation response twice */
7901 GNUNET_STATISTICS_update (GST_stats,
7902 "# Validations dropped, challenge unknown",
7905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7906 "Validation response %s dropped, challenge unknown\n",
7907 GNUNET_sh2s (&tvr->challenge.value));
7908 finish_cmc_handling (cmc);
7912 /* sanity check on origin time */
7913 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7914 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7915 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7917 GNUNET_break_op (0);
7918 finish_cmc_handling (cmc);
7923 /* check signature */
7924 struct TransportValidationPS tvp =
7925 { .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7926 .purpose.size = htonl (sizeof(tvp)),
7927 .validity_duration = tvr->validity_duration,
7928 .challenge = tvr->challenge };
7932 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7935 &cmc->im.sender.public_key))
7937 GNUNET_break_op (0);
7938 finish_cmc_handling (cmc);
7943 /* validity is capped by our willingness to keep track of the
7944 validation entry and the maximum the other peer allows */
7945 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7946 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7947 tvr->validity_duration),
7948 MAX_ADDRESS_VALID_UNTIL));
7949 vs->validated_until =
7950 GNUNET_TIME_absolute_min (vs->valid_until,
7951 GNUNET_TIME_relative_to_absolute (
7952 ADDRESS_VALIDATION_LIFETIME));
7953 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7954 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7955 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7957 sizeof(vs->challenge));
7958 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7959 vs->validated_until,
7960 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7961 VALIDATION_RTT_BUFFER_FACTOR));
7962 vs->last_challenge_use =
7963 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7964 update_next_challenge_time (vs, vs->first_challenge_use);
7965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7966 "Validation response %s accepted, address valid until %s\n",
7967 GNUNET_sh2s (&tvr->challenge.value),
7968 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
7969 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7972 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7974 strlen (vs->address) + 1,
7976 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7977 &peerstore_store_validation_cb,
7979 finish_cmc_handling (cmc);
7981 /* Finally, we now possibly have a confirmed (!) working queue,
7982 update queue status (if queue still is around) */
7983 q = find_queue (&vs->pid, vs->address);
7986 GNUNET_STATISTICS_update (GST_stats,
7987 "# Queues lost at time of successful validation",
7992 q->validated_until = vs->validated_until;
7993 q->pd.aged_rtt = vs->validation_rtt;
7995 vl = lookup_virtual_link (&vs->pid);
7998 /* Link was already up, remember n is also now available and we are done */
8003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8004 "Virtual link to %s could now also direct neighbour!\n",
8005 GNUNET_i2s (&vs->pid));
8009 GNUNET_assert (n == vl->n);
8013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8014 "Creating new virtual link to %s using direct neighbour!\n",
8015 GNUNET_i2s (&vs->pid));
8016 vl = GNUNET_new (struct VirtualLink);
8017 vl->target = n->pid;
8020 vl->core_recv_window = RECV_WINDOW_SIZE;
8021 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8022 vl->visibility_task =
8023 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8024 GNUNET_break (GNUNET_YES ==
8025 GNUNET_CONTAINER_multipeermap_put (
8029 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8030 consider_sending_fc (vl);
8031 /* We lacked a confirmed connection to the target
8032 before, so tell CORE about it (finally!) */
8033 cores_send_connect_info (&n->pid);
8038 * Incoming meessage. Process the request.
8040 * @param im the send message that was received
8043 handle_incoming_msg (void *cls,
8044 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8046 struct TransportClient *tc = cls;
8047 struct CommunicatorMessageContext *cmc =
8048 GNUNET_new (struct CommunicatorMessageContext);
8052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8053 "Received message via communicator from peer %s\n",
8054 GNUNET_i2s (&im->sender));
8055 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8060 * Communicator gave us a transport address validation response. Process the
8063 * @param cls a `struct CommunicatorMessageContext` (must call
8064 * #finish_cmc_handling() when done)
8065 * @param fc the message that was received
8068 handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8070 struct CommunicatorMessageContext *cmc = cls;
8071 struct VirtualLink *vl;
8073 struct GNUNET_TIME_Absolute st;
8077 vl = lookup_virtual_link (&cmc->im.sender);
8080 GNUNET_STATISTICS_update (GST_stats,
8081 "# FC dropped: virtual link unknown",
8084 finish_cmc_handling (cmc);
8087 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8088 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8090 /* out of order, drop */
8091 GNUNET_STATISTICS_update (GST_stats,
8092 "# FC dropped: message out of order",
8095 finish_cmc_handling (cmc);
8098 seq = ntohl (fc->seq);
8099 if (seq < vl->last_fc_seq)
8101 /* Wrap-around/reset of other peer; start all counters from zero */
8102 vl->outbound_fc_window_size_used = 0;
8104 vl->last_fc_seq = seq;
8105 vl->last_fc_timestamp = st;
8106 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8107 os = GNUNET_ntohll (fc->outbound_sent);
8108 vl->incoming_fc_window_size_loss =
8109 (int64_t) (os - vl->incoming_fc_window_size_used);
8110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8111 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8112 GNUNET_i2s (&vl->target),
8114 (unsigned long long) vl->outbound_fc_window_size,
8115 (long long) vl->incoming_fc_window_size_loss);
8116 wnd = GNUNET_ntohll (fc->outbound_window_size);
8117 if ((wnd < vl->incoming_fc_window_size) ||
8118 (vl->last_outbound_window_size_received != wnd) ||
8119 (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)
8120 % FC_NO_CHANGE_REPLY_PROBABILITY))
8122 /* Consider re-sending our FC message, as clearly the
8123 other peer's idea of the window is not up-to-date */
8124 consider_sending_fc (vl);
8126 if ((wnd == vl->incoming_fc_window_size) &&
8127 (vl->last_outbound_window_size_received == wnd) &&
8128 (NULL != vl->fc_retransmit_task))
8130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8131 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8132 GNUNET_i2s (&vl->target),
8133 (unsigned long long) wnd);
8134 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8135 vl->fc_retransmit_task = NULL;
8137 vl->last_outbound_window_size_received = wnd;
8138 /* FC window likely increased, check transmission possibilities! */
8139 check_vl_transmission (vl);
8140 finish_cmc_handling (cmc);
8145 * Given an inbound message @a msg from a communicator @a cmc,
8146 * demultiplex it based on the type calling the right handler.
8148 * @param cmc context for demultiplexing
8149 * @param msg message to demultiplex
8152 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8153 const struct GNUNET_MessageHeader *msg)
8155 struct GNUNET_MQ_MessageHandler handlers[] =
8156 { GNUNET_MQ_hd_var_size (fragment_box,
8157 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8158 struct TransportFragmentBoxMessage,
8160 GNUNET_MQ_hd_var_size (reliability_box,
8161 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8162 struct TransportReliabilityBoxMessage,
8164 GNUNET_MQ_hd_var_size (reliability_ack,
8165 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8166 struct TransportReliabilityAckMessage,
8168 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8169 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8170 struct TransportBackchannelEncapsulationMessage,
8172 GNUNET_MQ_hd_var_size (dv_learn,
8173 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8174 struct TransportDVLearnMessage,
8176 GNUNET_MQ_hd_var_size (dv_box,
8177 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8178 struct TransportDVBoxMessage,
8180 GNUNET_MQ_hd_fixed_size (
8181 validation_challenge,
8182 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8183 struct TransportValidationChallengeMessage,
8185 GNUNET_MQ_hd_fixed_size (flow_control,
8186 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8187 struct TransportFlowControlMessage,
8189 GNUNET_MQ_hd_fixed_size (
8190 validation_response,
8191 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8192 struct TransportValidationResponseMessage,
8194 GNUNET_MQ_handler_end () };
8197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8198 "Handling message of type %u with %u bytes\n",
8199 (unsigned int) ntohs (msg->type),
8200 (unsigned int) ntohs (msg->size));
8201 ret = GNUNET_MQ_handle_message (handlers, msg);
8202 if (GNUNET_SYSERR == ret)
8205 GNUNET_SERVICE_client_drop (cmc->tc->client);
8209 if (GNUNET_NO == ret)
8211 /* unencapsulated 'raw' message */
8212 handle_raw_message (&cmc, msg);
8218 * New queue became available. Check message.
8220 * @param cls the client
8221 * @param aqm the send message that was sent
8224 check_add_queue_message (void *cls,
8225 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8227 struct TransportClient *tc = cls;
8229 if (CT_COMMUNICATOR != tc->type)
8232 return GNUNET_SYSERR;
8234 GNUNET_MQ_check_zero_termination (aqm);
8240 * If necessary, generates the UUID for a @a pm
8242 * @param pm pending message to generate UUID for.
8245 set_pending_message_uuid (struct PendingMessage *pm)
8247 if (pm->msg_uuid_set)
8249 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8250 pm->msg_uuid_set = GNUNET_YES;
8255 * Setup data structure waiting for acknowledgements.
8257 * @param queue queue the @a pm will be sent over
8258 * @param dvh path the message will take, may be NULL
8259 * @param pm the pending message for transmission
8260 * @return corresponding fresh pending acknowledgement
8262 static struct PendingAcknowledgement *
8263 prepare_pending_acknowledgement (struct Queue *queue,
8264 struct DistanceVectorHop *dvh,
8265 struct PendingMessage *pm)
8267 struct PendingAcknowledgement *pa;
8269 pa = GNUNET_new (struct PendingAcknowledgement);
8275 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8277 sizeof(pa->ack_uuid));
8279 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8281 &pa->ack_uuid.value,
8283 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8284 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8285 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8287 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8288 pa->transmission_time = GNUNET_TIME_absolute_get ();
8289 pa->message_size = pm->bytes_msg;
8290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8291 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8292 GNUNET_uuid2s (&pa->ack_uuid.value),
8299 * Fragment the given @a pm to the given @a mtu. Adds
8300 * additional fragments to the neighbour as well. If the
8301 * @a mtu is too small, generates and error for the @a pm
8304 * @param queue which queue to fragment for
8305 * @param dvh path the message will take, or NULL
8306 * @param pm pending message to fragment for transmission
8307 * @return new message to transmit
8309 static struct PendingMessage *
8310 fragment_message (struct Queue *queue,
8311 struct DistanceVectorHop *dvh,
8312 struct PendingMessage *pm)
8314 struct PendingAcknowledgement *pa;
8315 struct PendingMessage *ff;
8318 mtu = (0 == queue->mtu)
8319 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
8321 set_pending_message_uuid (pm);
8322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8323 "Fragmenting message %llu <%llu> to %s for MTU %u\n",
8324 (unsigned long long) pm->msg_uuid.uuid,
8326 GNUNET_i2s (&pm->vl->target),
8327 (unsigned int) mtu);
8328 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8330 /* This invariant is established in #handle_add_queue_message() */
8331 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
8333 /* select fragment for transmission, descending the tree if it has
8334 been expanded until we are at a leaf or at a fragment that is small
8338 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
8339 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
8341 ff = ff->head_frag; /* descent into fragmented fragments */
8344 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
8346 /* Did not yet calculate all fragments, calculate next fragment */
8347 struct PendingMessage *frag;
8348 struct TransportFragmentBoxMessage tfb;
8356 orig = (const char *) &ff[1];
8357 msize = ff->bytes_msg;
8360 const struct TransportFragmentBoxMessage *tfbo;
8362 tfbo = (const struct TransportFragmentBoxMessage *) orig;
8363 orig += sizeof(struct TransportFragmentBoxMessage);
8364 msize -= sizeof(struct TransportFragmentBoxMessage);
8365 xoff = ntohs (tfbo->frag_off);
8367 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
8368 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
8370 GNUNET_malloc (sizeof(struct PendingMessage)
8371 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
8372 frag->logging_uuid = logging_uuid_gen++;
8374 frag->frag_parent = ff;
8375 frag->timeout = pm->timeout;
8376 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
8377 frag->pmt = PMT_FRAGMENT_BOX;
8378 msg = (char *) &frag[1];
8379 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
8381 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
8382 tfb.ack_uuid = pa->ack_uuid;
8383 tfb.msg_uuid = pm->msg_uuid;
8384 tfb.frag_off = htons (ff->frag_off + xoff);
8385 tfb.msg_size = htons (pm->bytes_msg);
8386 memcpy (msg, &tfb, sizeof(tfb));
8387 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
8388 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
8389 ff->frag_off += fragsize;
8393 /* Move head to the tail and return it */
8394 GNUNET_CONTAINER_MDLL_remove (frag,
8395 ff->frag_parent->head_frag,
8396 ff->frag_parent->tail_frag,
8398 GNUNET_CONTAINER_MDLL_insert_tail (frag,
8399 ff->frag_parent->head_frag,
8400 ff->frag_parent->tail_frag,
8407 * Reliability-box the given @a pm. On error (can there be any), NULL
8408 * may be returned, otherwise the "replacement" for @a pm (which
8409 * should then be added to the respective neighbour's queue instead of
8410 * @a pm). If the @a pm is already fragmented or reliability boxed,
8411 * or itself an ACK, this function simply returns @a pm.
8413 * @param queue which queue to prepare transmission for
8414 * @param dvh path the message will take, or NULL
8415 * @param pm pending message to box for transmission over unreliabile queue
8416 * @return new message to transmit
8418 static struct PendingMessage *
8419 reliability_box_message (struct Queue *queue,
8420 struct DistanceVectorHop *dvh,
8421 struct PendingMessage *pm)
8423 struct TransportReliabilityBoxMessage rbox;
8424 struct PendingAcknowledgement *pa;
8425 struct PendingMessage *bpm;
8428 if (PMT_CORE != pm->pmt)
8429 return pm; /* already fragmented or reliability boxed, or control message:
8431 if (NULL != pm->bpm)
8432 return pm->bpm; /* already computed earlier: do nothing */
8433 GNUNET_assert (NULL == pm->head_frag);
8434 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
8438 client_send_response (pm);
8441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8442 "Preparing reliability box for message <%llu> to %s on queue %s\n",
8444 GNUNET_i2s (&pm->vl->target),
8446 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8448 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
8450 bpm->logging_uuid = logging_uuid_gen++;
8452 bpm->frag_parent = pm;
8453 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
8454 bpm->timeout = pm->timeout;
8455 bpm->pmt = PMT_RELIABILITY_BOX;
8456 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
8457 set_pending_message_uuid (bpm);
8458 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
8459 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
8460 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
8462 rbox.ack_uuid = pa->ack_uuid;
8463 msg = (char *) &bpm[1];
8464 memcpy (msg, &rbox, sizeof(rbox));
8465 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
8472 * Change the value of the `next_attempt` field of @a pm
8473 * to @a next_attempt and re-order @a pm in the transmission
8474 * list as required by the new timestmap.
8476 * @param pm a pending message to update
8477 * @param next_attempt timestamp to use
8480 update_pm_next_attempt (struct PendingMessage *pm,
8481 struct GNUNET_TIME_Absolute next_attempt)
8483 struct VirtualLink *vl = pm->vl;
8485 pm->next_attempt = next_attempt;
8486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8487 "Next attempt for message <%llu> set to %s\n",
8489 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
8491 if (NULL == pm->frag_parent)
8493 struct PendingMessage *pos;
8495 /* re-insert sort in neighbour list */
8496 GNUNET_CONTAINER_MDLL_remove (vl,
8497 vl->pending_msg_head,
8498 vl->pending_msg_tail,
8500 pos = vl->pending_msg_tail;
8501 while ((NULL != pos) &&
8502 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8504 GNUNET_CONTAINER_MDLL_insert_after (vl,
8505 vl->pending_msg_head,
8506 vl->pending_msg_tail,
8512 /* re-insert sort in fragment list */
8513 struct PendingMessage *fp = pm->frag_parent;
8514 struct PendingMessage *pos;
8516 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
8517 pos = fp->tail_frag;
8518 while ((NULL != pos) &&
8519 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8520 pos = pos->prev_frag;
8521 GNUNET_CONTAINER_MDLL_insert_after (frag,
8531 * Context for #select_best_pending_from_link().
8533 struct PendingMessageScoreContext
8536 * Set to the best message that was found, NULL for none.
8538 struct PendingMessage *best;
8541 * DVH that @e best should take, or NULL for direct transmission.
8543 struct DistanceVectorHop *dvh;
8546 * What is the estimated total overhead for this message?
8548 size_t real_overhead;
8551 * Number of pending messages we seriously considered this time.
8553 unsigned int consideration_counter;
8556 * Did we have to fragment?
8561 * Did we have to reliability box?
8568 * Select the best pending message from @a vl for transmission
8571 * @param sc[in,out] best message so far (NULL for none), plus scoring data
8572 * @param queue the queue that will be used for transmission
8573 * @param vl the virtual link providing the messages
8574 * @param dvh path we are currently considering, or NULL for none
8575 * @param overhead number of bytes of overhead to be expected
8576 * from DV encapsulation (0 for without DV)
8579 select_best_pending_from_link (struct PendingMessageScoreContext *sc,
8580 struct Queue *queue,
8581 struct VirtualLink *vl,
8582 struct DistanceVectorHop *dvh,
8585 struct GNUNET_TIME_Absolute now;
8587 now = GNUNET_TIME_absolute_get ();
8588 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
8591 size_t real_overhead = overhead;
8595 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
8596 continue; /* DV messages must not be DV-routed to next hop! */
8597 if (pos->next_attempt.abs_value_us > now.abs_value_us)
8598 break; /* too early for all messages, they are sorted by next_attempt */
8599 if (NULL != pos->qe)
8600 continue; /* not eligible */
8601 sc->consideration_counter++;
8602 /* determine if we have to fragment, if so add fragmentation
8605 if (((0 != queue->mtu) &&
8606 (pos->bytes_msg + real_overhead > queue->mtu)) ||
8607 (pos->bytes_msg > UINT16_MAX - sizeof(struct
8608 GNUNET_TRANSPORT_SendMessageTo))
8610 (NULL != pos->head_frag /* fragments already exist, should
8611 respect that even if MTU is 0 for
8615 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
8617 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
8618 header without the ACK UUID when using a *reliable* channel! */
8620 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
8622 /* determine if we have to reliability-box, if so add reliability box
8625 if ((GNUNET_NO == frag) &&
8626 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
8627 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
8630 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
8633 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
8634 message would beat it! */
8635 if (NULL != sc->best)
8637 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
8638 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
8639 experimentally validated. There may be some huge potential for
8640 improvement here. Also, we right now only compare how well the
8641 given message fits _this_ queue, and do not consider how well other
8642 queues might suit the message. Taking other queues into consideration
8643 may further improve the result, but could also be expensive
8644 in terms of CPU time. */long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
8645 long long pm_score = frag * 40 + relb * 20 + real_overhead;
8646 long long time_delta =
8647 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
8650 /* "time_delta" considers which message has been 'ready' for transmission
8651 for longer, if a message has a preference for low latency, increase
8652 the weight of the time_delta by 10x if it is favorable for that message */
8653 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8654 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
8655 time_delta *= 10; /* increase weight (always, both are low latency) */
8656 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8659 10; /* increase weight, favors 'pos', which is low latency */
8660 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8663 10; /* increase weight, favors 'sc->best', which is low latency */
8664 if (0 != queue->mtu)
8666 /* Grant bonus if we are bellow MTU, larger bonus the closer we will
8668 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
8669 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
8670 if (queue->mtu > real_overhead + pos->bytes_msg)
8671 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
8673 if (sc_score + time_delta > pm_score)
8674 continue; /* sc_score larger, keep sc->best */
8685 * Function to call to further operate on the now DV encapsulated
8686 * message @a hdr, forwarding it via @a next_hop under respect of
8689 * @param cls a `struct PendingMessageScoreContext`
8690 * @param next_hop next hop of the DV path
8691 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
8692 * @param options options of the original message
8695 extract_box_cb (void *cls,
8696 struct Neighbour *next_hop,
8697 const struct GNUNET_MessageHeader *hdr,
8698 enum RouteMessageOptions options)
8700 struct PendingMessageScoreContext *sc = cls;
8701 struct PendingMessage *pm = sc->best;
8702 struct PendingMessage *bpm;
8703 uint16_t bsize = ntohs (hdr->size);
8705 GNUNET_assert (NULL == pm->bpm);
8706 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
8707 bpm->logging_uuid = logging_uuid_gen++;
8708 bpm->pmt = PMT_DV_BOX;
8709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8710 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
8713 GNUNET_i2s (&next_hop->pid));
8714 memcpy (&bpm[1], hdr, bsize);
8720 * We believe we are ready to transmit a `struct PendingMessage` on a
8721 * queue, the big question is which one! We need to see if there is
8722 * one pending that is allowed by flow control and congestion control
8723 * and (ideally) matches our queue's performance profile.
8725 * If such a message is found, we give the message to the communicator
8726 * for transmission (updating the tracker, and re-scheduling ourselves
8729 * If no such message is found, the queue's `idle` field must be set
8732 * @param cls the `struct Queue` to process transmissions for
8735 transmit_on_queue (void *cls)
8737 struct Queue *queue = cls;
8738 struct Neighbour *n = queue->neighbour;
8739 struct PendingMessageScoreContext sc;
8740 struct PendingMessage *pm;
8742 queue->transmit_task = NULL;
8745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8746 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
8747 GNUNET_i2s (&n->pid),
8749 queue->idle = GNUNET_YES;
8752 memset (&sc, 0, sizeof(sc));
8753 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
8754 if (NULL == sc.best)
8756 /* Also look at DVH that have the n as first hop! */
8757 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
8758 dvh = dvh->next_neighbour)
8760 select_best_pending_from_link (&sc,
8764 sizeof(struct GNUNET_PeerIdentity)
8765 * (1 + dvh->distance)
8766 + sizeof(struct TransportDVBoxMessage)
8767 + sizeof(struct TransportDVBoxPayloadP));
8770 if (NULL == sc.best)
8772 /* no message pending, nothing to do here! */
8773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8774 "No pending messages, queue `%s' to %s now idle\n",
8776 GNUNET_i2s (&n->pid));
8777 queue->idle = GNUNET_YES;
8781 /* Given selection in `sc`, do transmission */
8785 GNUNET_assert (PMT_DV_BOX != pm->pmt);
8786 if (NULL != sc.best->bpm)
8788 /* We did this boxing before, but possibly for a different path!
8789 Discard old DV box! OPTIMIZE-ME: we might want to check if
8790 it is the same and then not re-build the message... */
8791 free_pending_message (sc.best->bpm);
8792 sc.best->bpm = NULL;
8794 encapsulate_for_dv (sc.dvh->dv,
8797 (const struct GNUNET_MessageHeader *) &sc.best[1],
8801 GNUNET_assert (NULL != sc.best->bpm);
8804 if (GNUNET_YES == sc.frag)
8806 pm = fragment_message (queue, sc.dvh, pm);
8809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8810 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
8812 GNUNET_i2s (&n->pid),
8813 sc.best->logging_uuid);
8814 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8818 else if (GNUNET_YES == sc.relb)
8820 pm = reliability_box_message (queue, sc.dvh, pm);
8823 /* Reliability boxing failed, try next message... */
8825 GNUNET_ERROR_TYPE_DEBUG,
8826 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
8828 GNUNET_i2s (&n->pid),
8829 sc.best->logging_uuid);
8830 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8835 /* Pass 'pm' for transission to the communicator */
8837 GNUNET_ERROR_TYPE_DEBUG,
8838 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
8841 GNUNET_i2s (&n->pid),
8842 sc.consideration_counter);
8844 /* Flow control: increment amount of traffic sent; if we are routing
8845 via DV (and thus the ultimate target of the pending message is for
8846 a different virtual link than the one of the queue), then we need
8847 to use up not only the window of the direct link but also the
8848 flow control window for the DV link! */pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
8850 if (pm->vl != queue->neighbour->vl)
8852 /* If the virtual link of the queue differs, this better be distance
8854 GNUNET_assert (NULL != sc.dvh);
8855 /* If we do distance vector routing, we better not do this for a
8856 message that was itself DV-routed */
8857 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
8858 /* We use the size of the unboxed message here, to avoid counting
8859 the DV-Box header which is eaten up on the way by intermediaries */
8860 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
8864 GNUNET_assert (NULL == sc.dvh);
8867 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
8869 /* Check if this transmission somehow conclusively finished handing 'pm'
8870 even without any explicit ACKs */
8871 if ((PMT_CORE == pm->pmt) ||
8872 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
8874 completed_pending_message (pm);
8878 /* Message not finished, waiting for acknowledgement.
8879 Update time by which we might retransmit 's' based on queue
8880 characteristics (i.e. RTT); it takes one RTT for the message to
8881 arrive and the ACK to come back in the best case; but the other
8882 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
8885 OPTIMIZE: Note that in the future this heuristic should likely
8886 be improved further (measure RTT stability, consider message
8887 urgency and size when delaying ACKs, etc.) */update_pm_next_attempt (pm,
8888 GNUNET_TIME_relative_to_absolute (
8889 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
8892 /* finally, re-schedule queue transmission task itself */
8893 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8898 * Queue to a peer went down. Process the request.
8900 * @param cls the client
8901 * @param dqm the send message that was sent
8904 handle_del_queue_message (void *cls,
8905 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
8907 struct TransportClient *tc = cls;
8909 if (CT_COMMUNICATOR != tc->type)
8912 GNUNET_SERVICE_client_drop (tc->client);
8915 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8916 queue = queue->next_client)
8918 struct Neighbour *neighbour = queue->neighbour;
8920 if ((dqm->qid != queue->qid) ||
8921 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
8923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8924 "Dropped queue %s to peer %s\n",
8926 GNUNET_i2s (&neighbour->pid));
8928 GNUNET_SERVICE_client_continue (tc->client);
8932 GNUNET_SERVICE_client_drop (tc->client);
8937 * Message was transmitted. Process the request.
8939 * @param cls the client
8940 * @param sma the send message that was sent
8943 handle_send_message_ack (void *cls,
8944 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
8946 struct TransportClient *tc = cls;
8947 struct QueueEntry *qe;
8948 struct PendingMessage *pm;
8950 if (CT_COMMUNICATOR != tc->type)
8953 GNUNET_SERVICE_client_drop (tc->client);
8957 /* find our queue entry matching the ACK */
8959 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8960 queue = queue->next_client)
8962 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
8964 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
8967 if (qep->mid != sma->mid)
8976 /* this should never happen */
8978 GNUNET_SERVICE_client_drop (tc->client);
8981 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
8982 qe->queue->queue_tail,
8984 qe->queue->queue_length--;
8985 tc->details.communicator.total_queue_length--;
8986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8987 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
8989 GNUNET_i2s (&qe->queue->neighbour->pid),
8990 qe->queue->queue_length,
8991 tc->details.communicator.total_queue_length);
8992 GNUNET_SERVICE_client_continue (tc->client);
8994 /* if applicable, resume transmissions that waited on ACK */
8995 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
8996 tc->details.communicator.total_queue_length)
8998 /* Communicator dropped below threshold, resume all queues
8999 incident with this client! */
9000 GNUNET_STATISTICS_update (
9002 "# Transmission throttled due to communicator queue limit",
9005 for (struct Queue *queue = tc->details.communicator.queue_head;
9007 queue = queue->next_client)
9008 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9010 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9012 /* queue dropped below threshold; only resume this one queue */
9013 GNUNET_STATISTICS_update (GST_stats,
9014 "# Transmission throttled due to queue queue limit",
9017 schedule_transmit_on_queue (qe->queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9020 if (NULL != (pm = qe->pm))
9022 struct VirtualLink *vl;
9024 GNUNET_assert (qe == pm->qe);
9026 /* If waiting for this communicator may have blocked transmission
9027 of pm on other queues for this neighbour, force schedule
9028 transmit on queue for queues of the neighbour */
9030 if (vl->pending_msg_head == pm)
9031 check_vl_transmission (vl);
9038 * Iterator telling new MONITOR client about all existing
9041 * @param cls the new `struct TransportClient`
9042 * @param pid a connected peer
9043 * @param value the `struct Neighbour` with more information
9044 * @return #GNUNET_OK (continue to iterate)
9047 notify_client_queues (void *cls,
9048 const struct GNUNET_PeerIdentity *pid,
9051 struct TransportClient *tc = cls;
9052 struct Neighbour *neighbour = value;
9054 GNUNET_assert (CT_MONITOR == tc->type);
9055 for (struct Queue *q = neighbour->queue_head; NULL != q;
9056 q = q->next_neighbour)
9058 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
9060 .num_msg_pending = q->num_msg_pending,
9061 .num_bytes_pending = q->num_bytes_pending };
9063 notify_monitor (tc, pid, q->address, q->nt, &me);
9070 * Initialize a monitor client.
9072 * @param cls the client
9073 * @param start the start message that was sent
9076 handle_monitor_start (void *cls,
9077 const struct GNUNET_TRANSPORT_MonitorStart *start)
9079 struct TransportClient *tc = cls;
9081 if (CT_NONE != tc->type)
9084 GNUNET_SERVICE_client_drop (tc->client);
9087 tc->type = CT_MONITOR;
9088 tc->details.monitor.peer = start->peer;
9089 tc->details.monitor.one_shot = ntohl (start->one_shot);
9090 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
9091 GNUNET_SERVICE_client_mark_monitor (tc->client);
9092 GNUNET_SERVICE_client_continue (tc->client);
9097 * Find transport client providing communication service
9098 * for the protocol @a prefix.
9100 * @param prefix communicator name
9101 * @return NULL if no such transport client is available
9103 static struct TransportClient *
9104 lookup_communicator (const char *prefix)
9106 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
9108 if (CT_COMMUNICATOR != tc->type)
9110 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
9114 GNUNET_ERROR_TYPE_WARNING,
9115 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
9122 * Signature of a function called with a communicator @a address of a peer
9123 * @a pid that an application wants us to connect to.
9125 * @param pid target peer
9126 * @param address the address to try
9129 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
9131 static uint32_t idgen;
9132 struct TransportClient *tc;
9134 struct GNUNET_TRANSPORT_CreateQueue *cqm;
9135 struct GNUNET_MQ_Envelope *env;
9138 prefix = GNUNET_HELLO_address_to_prefix (address);
9141 GNUNET_break (0); /* We got an invalid address!? */
9144 tc = lookup_communicator (prefix);
9147 GNUNET_STATISTICS_update (GST_stats,
9148 "# Suggestions ignored due to missing communicator",
9151 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9152 "Cannot connect to %s at `%s', no matching communicator present\n",
9155 GNUNET_free (prefix);
9158 /* forward suggestion for queue creation to communicator */
9159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9160 "Request #%u for `%s' communicator to create queue to `%s'\n",
9161 (unsigned int) idgen,
9164 GNUNET_free (prefix);
9165 alen = strlen (address) + 1;
9167 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
9168 cqm->request_id = htonl (idgen++);
9169 cqm->receiver = *pid;
9170 memcpy (&cqm[1], address, alen);
9171 GNUNET_MQ_send (tc->mq, env);
9176 * The queue @a q (which matches the peer and address in @a vs) is
9177 * ready for queueing. We should now queue the validation request.
9179 * @param q queue to send on
9180 * @param vs state to derive validation challenge from
9183 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
9185 struct TransportValidationChallengeMessage tvc;
9187 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
9189 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
9190 tvc.header.size = htons (sizeof(tvc));
9191 tvc.reserved = htonl (0);
9192 tvc.challenge = vs->challenge;
9193 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
9194 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9195 "Sending address validation challenge %s to %s\n",
9196 GNUNET_sh2s (&tvc.challenge.value),
9197 GNUNET_i2s (&q->neighbour->pid));
9198 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
9203 * Task run periodically to validate some address based on #validation_heap.
9208 validation_start_cb (void *cls)
9210 struct ValidationState *vs;
9214 validation_task = NULL;
9215 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9216 /* drop validations past their expiration */
9219 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
9221 free_validation_state (vs);
9222 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9226 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9227 "Address validation task not scheduled anymore, nothing to do\n");
9228 return; /* woopsie, no more addresses known, should only
9229 happen if we're really a lonely peer */
9231 q = find_queue (&vs->pid, vs->address);
9234 vs->awaiting_queue = GNUNET_YES;
9235 suggest_to_connect (&vs->pid, vs->address);
9238 validation_transmit_on_queue (q, vs);
9239 /* Finally, reschedule next attempt */
9240 vs->challenge_backoff =
9241 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
9242 MAX_VALIDATION_CHALLENGE_FREQ);
9243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9244 "Address validation task will run again in %s\n",
9245 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
9247 update_next_challenge_time (vs,
9248 GNUNET_TIME_relative_to_absolute (
9249 vs->challenge_backoff));
9254 * Closure for #check_connection_quality.
9256 struct QueueQualityContext
9259 * Set to the @e k'th queue encountered.
9264 * Set to the number of quality queues encountered.
9266 unsigned int quality_count;
9269 * Set to the total number of queues encountered.
9271 unsigned int num_queues;
9274 * Decremented for each queue, for selection of the
9275 * k-th queue in @e q.
9282 * Check whether any queue to the given neighbour is
9283 * of a good "quality" and if so, increment the counter.
9284 * Also counts the total number of queues, and returns
9285 * the k-th queue found.
9287 * @param cls a `struct QueueQualityContext *` with counters
9288 * @param pid peer this is about
9289 * @param value a `struct Neighbour`
9290 * @return #GNUNET_OK (continue to iterate)
9293 check_connection_quality (void *cls,
9294 const struct GNUNET_PeerIdentity *pid,
9297 struct QueueQualityContext *ctx = cls;
9298 struct Neighbour *n = value;
9303 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9308 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
9309 statistics and consider those as well here? */
9310 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
9311 do_inc = GNUNET_YES;
9313 if (GNUNET_YES == do_inc)
9314 ctx->quality_count++;
9320 * Task run when we CONSIDER initiating a DV learn
9321 * process. We first check that sending out a message is
9322 * even possible (queues exist), then that it is desirable
9323 * (if not, reschedule the task for later), and finally
9324 * we may then begin the job. If there are too many
9325 * entries in the #dvlearn_map, we purge the oldest entry
9331 start_dv_learn (void *cls)
9333 struct LearnLaunchEntry *lle;
9334 struct QueueQualityContext qqc;
9335 struct TransportDVLearnMessage dvl;
9338 dvlearn_task = NULL;
9339 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
9340 return; /* lost all connectivity, cannot do learning */
9341 qqc.quality_count = 0;
9343 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9344 &check_connection_quality,
9346 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
9348 struct GNUNET_TIME_Relative delay;
9349 unsigned int factor;
9351 /* scale our retries by how far we are above the threshold */
9352 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
9353 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
9354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9355 "At connection quality %u, will launch DV learn in %s\n",
9357 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
9358 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
9361 /* remove old entries in #dvlearn_map if it has grown too big */
9362 while (MAX_DV_LEARN_PENDING >=
9363 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
9366 GNUNET_assert (GNUNET_YES ==
9367 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
9368 &lle->challenge.value,
9370 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9373 /* setup data structure for learning */
9374 lle = GNUNET_new (struct LearnLaunchEntry);
9375 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9377 sizeof(lle->challenge));
9378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9379 "Starting launch DV learn with challenge %s\n",
9380 GNUNET_sh2s (&lle->challenge.value));
9381 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
9382 GNUNET_break (GNUNET_YES ==
9383 GNUNET_CONTAINER_multishortmap_put (
9385 &lle->challenge.value,
9387 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9388 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
9389 dvl.header.size = htons (sizeof(dvl));
9390 dvl.num_hops = htons (0);
9391 dvl.bidirectional = htons (0);
9392 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
9393 dvl.monotonic_time =
9394 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
9396 struct DvInitPS dvip = { .purpose.purpose = htonl (
9397 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
9398 .purpose.size = htonl (sizeof(dvip)),
9399 .monotonic_time = dvl.monotonic_time,
9400 .challenge = lle->challenge };
9402 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9406 dvl.initiator = GST_my_identity;
9407 dvl.challenge = lle->challenge;
9409 qqc.quality_count = 0;
9410 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
9413 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9414 &check_connection_quality,
9416 GNUNET_assert (NULL != qqc.q);
9418 /* Do this as close to transmission time as possible! */
9419 lle->launch_time = GNUNET_TIME_absolute_get ();
9421 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
9422 /* reschedule this job, randomizing the time it runs (but no
9424 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
9425 DV_LEARN_BASE_FREQUENCY),
9432 * A new queue has been created, check if any address validation
9433 * requests have been waiting for it.
9435 * @param cls a `struct Queue`
9436 * @param pid peer concerned (unused)
9437 * @param value a `struct ValidationState`
9438 * @return #GNUNET_NO if a match was found and we can stop looking
9441 check_validation_request_pending (void *cls,
9442 const struct GNUNET_PeerIdentity *pid,
9445 struct Queue *q = cls;
9446 struct ValidationState *vs = value;
9449 if ((GNUNET_YES == vs->awaiting_queue) &&
9450 (0 == strcmp (vs->address, q->address)))
9452 vs->awaiting_queue = GNUNET_NO;
9453 validation_transmit_on_queue (q, vs);
9461 * Function called with the monotonic time of a DV initiator
9462 * by PEERSTORE. Updates the time.
9464 * @param cls a `struct Neighbour`
9465 * @param record the information found, NULL for the last call
9466 * @param emsg error message
9469 neighbour_dv_monotime_cb (void *cls,
9470 const struct GNUNET_PEERSTORE_Record *record,
9473 struct Neighbour *n = cls;
9474 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9479 /* we're done with #neighbour_dv_monotime_cb() invocations,
9480 continue normal processing */
9482 n->dv_monotime_available = GNUNET_YES;
9485 if (sizeof(*mtbe) != record->value_size)
9490 mtbe = record->value;
9491 n->last_dv_learn_monotime =
9492 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
9493 GNUNET_TIME_absolute_ntoh (*mtbe));
9498 * New queue became available. Process the request.
9500 * @param cls the client
9501 * @param aqm the send message that was sent
9504 handle_add_queue_message (void *cls,
9505 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9507 struct TransportClient *tc = cls;
9508 struct Queue *queue;
9509 struct Neighbour *neighbour;
9513 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
9515 /* MTU so small as to be useless for transmissions,
9516 required for #fragment_message()! */
9517 GNUNET_break_op (0);
9518 GNUNET_SERVICE_client_drop (tc->client);
9521 neighbour = lookup_neighbour (&aqm->receiver);
9522 if (NULL == neighbour)
9524 neighbour = GNUNET_new (struct Neighbour);
9525 neighbour->pid = aqm->receiver;
9526 GNUNET_assert (GNUNET_OK ==
9527 GNUNET_CONTAINER_multipeermap_put (
9531 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9533 GNUNET_PEERSTORE_iterate (peerstore,
9536 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
9537 &neighbour_dv_monotime_cb,
9540 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
9541 addr = (const char *) &aqm[1];
9542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9543 "New queue %s to %s available with QID %llu\n",
9545 GNUNET_i2s (&aqm->receiver),
9546 (unsigned long long) aqm->qid);
9547 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
9549 queue->address = (const char *) &queue[1];
9550 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
9551 queue->qid = aqm->qid;
9552 queue->mtu = ntohl (aqm->mtu);
9553 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
9554 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
9555 queue->neighbour = neighbour;
9556 queue->idle = GNUNET_YES;
9557 memcpy (&queue[1], addr, addr_len);
9558 /* notify monitors about new queue */
9560 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
9562 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
9564 GNUNET_CONTAINER_MDLL_insert (neighbour,
9565 neighbour->queue_head,
9566 neighbour->queue_tail,
9568 GNUNET_CONTAINER_MDLL_insert (client,
9569 tc->details.communicator.queue_head,
9570 tc->details.communicator.queue_tail,
9572 /* check if valdiations are waiting for the queue */
9574 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9576 &check_validation_request_pending,
9578 /* look for traffic for this queue */
9579 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9580 /* might be our first queue, try launching DV learning */
9581 if (NULL == dvlearn_task)
9582 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
9583 GNUNET_SERVICE_client_continue (tc->client);
9588 * Communicator tells us that our request to create a queue "worked", that
9589 * is setting up the queue is now in process.
9591 * @param cls the `struct TransportClient`
9592 * @param cqr confirmation message
9595 handle_queue_create_ok (void *cls,
9596 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9598 struct TransportClient *tc = cls;
9600 if (CT_COMMUNICATOR != tc->type)
9603 GNUNET_SERVICE_client_drop (tc->client);
9606 GNUNET_STATISTICS_update (GST_stats,
9607 "# Suggestions succeeded at communicator",
9610 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9611 "Request #%u for communicator to create queue succeeded\n",
9612 (unsigned int) ntohs (cqr->request_id));
9613 GNUNET_SERVICE_client_continue (tc->client);
9618 * Communicator tells us that our request to create a queue failed. This
9619 * usually indicates that the provided address is simply invalid or that the
9620 * communicator's resources are exhausted.
9622 * @param cls the `struct TransportClient`
9623 * @param cqr failure message
9626 handle_queue_create_fail (
9628 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9630 struct TransportClient *tc = cls;
9632 if (CT_COMMUNICATOR != tc->type)
9635 GNUNET_SERVICE_client_drop (tc->client);
9638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9639 "Request #%u for communicator to create queue failed\n",
9640 (unsigned int) ntohs (cqr->request_id));
9641 GNUNET_STATISTICS_update (GST_stats,
9642 "# Suggestions failed in queue creation at communicator",
9645 GNUNET_SERVICE_client_continue (tc->client);
9650 * We have received a `struct ExpressPreferenceMessage` from an application
9653 * @param cls handle to the client
9654 * @param msg the start message
9657 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
9659 struct TransportClient *tc = cls;
9660 struct PeerRequest *pr;
9662 if (CT_APPLICATION != tc->type)
9665 GNUNET_SERVICE_client_drop (tc->client);
9668 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
9673 GNUNET_SERVICE_client_drop (tc->client);
9676 (void) stop_peer_request (tc, &pr->pid, pr);
9677 GNUNET_SERVICE_client_continue (tc->client);
9682 * Function called by PEERSTORE for each matching record.
9684 * @param cls closure, a `struct PeerRequest`
9685 * @param record peerstore record information
9686 * @param emsg error message, or NULL if no errors
9689 handle_hello_for_client (void *cls,
9690 const struct GNUNET_PEERSTORE_Record *record,
9693 struct PeerRequest *pr = cls;
9698 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9699 "Got failure from PEERSTORE: %s\n",
9703 val = record->value;
9704 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
9709 start_address_validation (&pr->pid, (const char *) record->value);
9714 * We have received a `struct ExpressPreferenceMessage` from an application
9717 * @param cls handle to the client
9718 * @param msg the start message
9721 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9723 struct TransportClient *tc = cls;
9724 struct PeerRequest *pr;
9726 if (CT_NONE == tc->type)
9728 tc->type = CT_APPLICATION;
9729 tc->details.application.requests =
9730 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9732 if (CT_APPLICATION != tc->type)
9735 GNUNET_SERVICE_client_drop (tc->client);
9738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9739 "Client suggested we talk to %s with preference %d at rate %u\n",
9740 GNUNET_i2s (&msg->peer),
9741 (int) ntohl (msg->pk),
9742 (int) ntohl (msg->bw.value__));
9743 pr = GNUNET_new (struct PeerRequest);
9745 pr->pid = msg->peer;
9747 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
9748 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
9749 tc->details.application.requests,
9752 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
9756 GNUNET_SERVICE_client_drop (tc->client);
9759 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
9762 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9763 &handle_hello_for_client,
9765 GNUNET_SERVICE_client_continue (tc->client);
9770 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
9773 * @param cls a `struct TransportClient *`
9774 * @param m message to verify
9775 * @return #GNUNET_OK on success
9778 check_request_hello_validation (void *cls,
9779 const struct RequestHelloValidationMessage *m)
9782 GNUNET_MQ_check_zero_termination (m);
9788 * A client encountered an address of another peer. Consider validating it,
9789 * and if validation succeeds, persist it to PEERSTORE.
9791 * @param cls a `struct TransportClient *`
9792 * @param m message to verify
9795 handle_request_hello_validation (void *cls,
9796 const struct RequestHelloValidationMessage *m)
9798 struct TransportClient *tc = cls;
9800 start_address_validation (&m->peer, (const char *) &m[1]);
9801 GNUNET_SERVICE_client_continue (tc->client);
9806 * Free neighbour entry.
9810 * @param value a `struct Neighbour`
9811 * @return #GNUNET_OK (always)
9814 free_neighbour_cb (void *cls,
9815 const struct GNUNET_PeerIdentity *pid,
9818 struct Neighbour *neighbour = value;
9822 GNUNET_break (0); // should this ever happen?
9823 free_neighbour (neighbour);
9830 * Free DV route entry.
9834 * @param value a `struct DistanceVector`
9835 * @return #GNUNET_OK (always)
9838 free_dv_routes_cb (void *cls,
9839 const struct GNUNET_PeerIdentity *pid,
9842 struct DistanceVector *dv = value;
9853 * Free validation state.
9857 * @param value a `struct ValidationState`
9858 * @return #GNUNET_OK (always)
9861 free_validation_state_cb (void *cls,
9862 const struct GNUNET_PeerIdentity *pid,
9865 struct ValidationState *vs = value;
9869 free_validation_state (vs);
9875 * Free pending acknowledgement.
9879 * @param value a `struct PendingAcknowledgement`
9880 * @return #GNUNET_OK (always)
9883 free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
9885 struct PendingAcknowledgement *pa = value;
9889 free_pending_acknowledgement (pa);
9895 * Free acknowledgement cummulator.
9899 * @param value a `struct AcknowledgementCummulator`
9900 * @return #GNUNET_OK (always)
9903 free_ack_cummulator_cb (void *cls,
9904 const struct GNUNET_PeerIdentity *pid,
9907 struct AcknowledgementCummulator *ac = value;
9917 * Function called when the service shuts down. Unloads our plugins
9918 * and cancels pending validations.
9920 * @param cls closure, unused
9923 do_shutdown (void *cls)
9925 struct LearnLaunchEntry *lle;
9929 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9930 if (NULL != peerstore)
9932 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9935 if (NULL != GST_stats)
9937 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9940 if (NULL != GST_my_private_key)
9942 GNUNET_free (GST_my_private_key);
9943 GST_my_private_key = NULL;
9945 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9946 &free_ack_cummulator_cb,
9948 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9949 ack_cummulators = NULL;
9950 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
9951 &free_pending_ack_cb,
9953 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
9954 pending_acks = NULL;
9955 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9956 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9958 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9959 GNUNET_CONTAINER_multipeermap_destroy (links);
9961 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9962 &free_backtalker_cb,
9964 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9966 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9967 &free_validation_state_cb,
9969 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9970 validation_map = NULL;
9971 while (NULL != ir_head)
9972 free_incoming_request (ir_head);
9973 GNUNET_assert (0 == ir_total);
9974 while (NULL != (lle = lle_head))
9976 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9979 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
9981 GNUNET_CONTAINER_heap_destroy (validation_heap);
9982 validation_heap = NULL;
9983 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
9984 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
9990 * Initiate transport service.
9992 * @param cls closure
9993 * @param c configuration to use
9994 * @param service the initialized service
9998 const struct GNUNET_CONFIGURATION_Handle *c,
9999 struct GNUNET_SERVICE_Handle *service)
10003 /* setup globals */
10004 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
10006 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10007 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
10008 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
10009 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10010 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
10011 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10012 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
10014 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10016 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
10017 GST_my_private_key =
10018 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
10019 if (NULL == GST_my_private_key)
10022 GNUNET_ERROR_TYPE_ERROR,
10024 "Transport service is lacking key configuration settings. Exiting.\n"));
10025 GNUNET_SCHEDULER_shutdown ();
10028 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
10029 &GST_my_identity.public_key);
10030 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10031 "My identity is `%s'\n",
10032 GNUNET_i2s_full (&GST_my_identity));
10033 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
10034 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
10035 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
10036 if (NULL == peerstore)
10039 GNUNET_SCHEDULER_shutdown ();
10046 * Define "main" method using service macro.
10048 GNUNET_SERVICE_MAIN (
10050 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
10052 &client_connect_cb,
10053 &client_disconnect_cb,
10055 /* communication with applications */
10056 GNUNET_MQ_hd_fixed_size (suggest,
10057 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
10058 struct ExpressPreferenceMessage,
10060 GNUNET_MQ_hd_fixed_size (suggest_cancel,
10061 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
10062 struct ExpressPreferenceMessage,
10064 GNUNET_MQ_hd_var_size (request_hello_validation,
10065 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
10066 struct RequestHelloValidationMessage,
10068 /* communication with core */
10069 GNUNET_MQ_hd_fixed_size (client_start,
10070 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
10071 struct StartMessage,
10073 GNUNET_MQ_hd_var_size (client_send,
10074 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
10075 struct OutboundMessage,
10077 GNUNET_MQ_hd_fixed_size (client_recv_ok,
10078 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
10079 struct RecvOkMessage,
10081 /* communication with communicators */
10082 GNUNET_MQ_hd_var_size (communicator_available,
10083 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
10084 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
10086 GNUNET_MQ_hd_var_size (communicator_backchannel,
10087 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
10088 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
10090 GNUNET_MQ_hd_var_size (add_address,
10091 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
10092 struct GNUNET_TRANSPORT_AddAddressMessage,
10094 GNUNET_MQ_hd_fixed_size (del_address,
10095 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
10096 struct GNUNET_TRANSPORT_DelAddressMessage,
10098 GNUNET_MQ_hd_var_size (incoming_msg,
10099 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
10100 struct GNUNET_TRANSPORT_IncomingMessage,
10102 GNUNET_MQ_hd_fixed_size (queue_create_ok,
10103 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
10104 struct GNUNET_TRANSPORT_CreateQueueResponse,
10106 GNUNET_MQ_hd_fixed_size (queue_create_fail,
10107 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
10108 struct GNUNET_TRANSPORT_CreateQueueResponse,
10110 GNUNET_MQ_hd_var_size (add_queue_message,
10111 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
10112 struct GNUNET_TRANSPORT_AddQueueMessage,
10114 GNUNET_MQ_hd_fixed_size (del_queue_message,
10115 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
10116 struct GNUNET_TRANSPORT_DelQueueMessage,
10118 GNUNET_MQ_hd_fixed_size (send_message_ack,
10119 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
10120 struct GNUNET_TRANSPORT_SendMessageToAck,
10122 /* communication with monitors */
10123 GNUNET_MQ_hd_fixed_size (monitor_start,
10124 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
10125 struct GNUNET_TRANSPORT_MonitorStart,
10127 GNUNET_MQ_handler_end ());
10130 /* end of file gnunet-service-transport.c */