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!*/
4740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4741 "Sending FC seq %u to %s with new window %llu\n",
4742 (unsigned int) vl->fc_seq_gen,
4743 GNUNET_i2s (&vl->target),
4744 (unsigned long long) vl->incoming_fc_window_size);
4745 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4746 vl->last_fc_transmission = monotime;
4747 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
4748 fc.header.size = htons (sizeof(fc));
4749 fc.seq = htonl (vl->fc_seq_gen++);
4750 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
4751 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
4752 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
4753 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
4754 rtt = route_control_message_without_fc (&vl->target, &fc.header, RMO_NONE);
4755 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
4757 rtt = GNUNET_TIME_UNIT_SECONDS;
4758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4759 "FC retransmission to %s failed, will retry in %s\n",
4760 GNUNET_i2s (&vl->target),
4761 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
4762 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
4766 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
4767 vl->last_fc_rtt = rtt;
4769 if (NULL != vl->fc_retransmit_task)
4770 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
4771 vl->fc_retransmit_task =
4772 GNUNET_SCHEDULER_add_delayed (rtt, &consider_sending_fc, vl);
4777 * There is a message at the head of the pending messages for @a vl
4778 * which may be ready for transmission. Check if a queue is ready to
4781 * This function must (1) check for flow control to ensure that we can
4782 * right now send to @a vl, (2) check that the pending message in the
4783 * queue is actually eligible, (3) determine if any applicable queue
4784 * (direct neighbour or DVH path) is ready to accept messages, and
4785 * (4) prioritize based on the preferences associated with the
4790 * @param vl virtual link where we should check for transmission
4793 check_vl_transmission (struct VirtualLink *vl)
4795 struct Neighbour *n = vl->n;
4796 struct DistanceVector *dv = vl->dv;
4797 struct GNUNET_TIME_Absolute now;
4800 /* Check that we have an eligible pending message!
4801 (cheaper than having #transmit_on_queue() find out!) */
4803 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
4807 continue; /* not eligible, is in a queue! */
4808 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
4809 vl->outbound_fc_window_size)
4811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4812 "Stalled transmision on VL %s due to flow control: %llu < %llu\n",
4813 GNUNET_i2s (&vl->target),
4814 (unsigned long long) vl->outbound_fc_window_size,
4815 (unsigned long long) (pm->bytes_msg
4816 + vl->outbound_fc_window_size_used));
4817 consider_sending_fc (vl);
4818 return; /* We have a message, but flow control says "nope" */
4823 if (GNUNET_NO == elig)
4826 /* Notify queues at direct neighbours that we are interested */
4827 now = GNUNET_TIME_absolute_get ();
4830 for (struct Queue *queue = n->queue_head; NULL != queue;
4831 queue = queue->next_neighbour)
4832 if ((GNUNET_YES == queue->idle) &&
4833 (queue->validated_until.abs_value_us > now.abs_value_us))
4834 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4836 /* Notify queues via DV that we are interested */
4839 /* Do DV with lower scheduler priority, which effectively means that
4840 IF a neighbour exists and is available, we prefer it. */
4841 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4844 struct Neighbour *nh = pos->next_hop;
4846 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
4847 continue; /* skip this one: path not validated */
4848 for (struct Queue *queue = nh->queue_head; NULL != queue;
4849 queue = queue->next_neighbour)
4850 if ((GNUNET_YES == queue->idle) &&
4851 (queue->validated_until.abs_value_us > now.abs_value_us))
4852 schedule_transmit_on_queue (queue,
4853 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
4860 * Client asked for transmission to a peer. Process the request.
4862 * @param cls the client
4863 * @param obm the send message that was sent
4866 handle_client_send (void *cls, const struct OutboundMessage *obm)
4868 struct TransportClient *tc = cls;
4869 struct PendingMessage *pm;
4870 const struct GNUNET_MessageHeader *obmm;
4872 struct VirtualLink *vl;
4873 enum GNUNET_MQ_PriorityPreferences pp;
4875 GNUNET_assert (CT_CORE == tc->type);
4876 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4877 bytes_msg = ntohs (obmm->size);
4878 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
4879 vl = lookup_virtual_link (&obm->peer);
4882 /* Failure: don't have this peer as a neighbour (anymore).
4883 Might have gone down asynchronously, so this is NOT
4884 a protocol violation by CORE. Still count the event,
4885 as this should be rare. */
4886 GNUNET_SERVICE_client_continue (tc->client);
4887 GNUNET_STATISTICS_update (GST_stats,
4888 "# messages dropped (neighbour unknown)",
4894 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
4895 pm->logging_uuid = logging_uuid_gen++;
4899 pm->bytes_msg = bytes_msg;
4900 memcpy (&pm[1], obmm, bytes_msg);
4901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4902 "Sending %u bytes as <%llu> to %s\n",
4905 GNUNET_i2s (&obm->peer));
4906 GNUNET_CONTAINER_MDLL_insert (client,
4907 tc->details.core.pending_msg_head,
4908 tc->details.core.pending_msg_tail,
4910 GNUNET_CONTAINER_MDLL_insert (vl,
4911 vl->pending_msg_head,
4912 vl->pending_msg_tail,
4914 check_vl_transmission (vl);
4919 * Communicator requests backchannel transmission. Process the request.
4920 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
4921 * (which for now has exactly the same format, only a different message type)
4922 * and passes it on for routing.
4924 * @param cls the client
4925 * @param cb the send message that was sent
4928 handle_communicator_backchannel (
4930 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4932 struct TransportClient *tc = cls;
4933 const struct GNUNET_MessageHeader *inbox =
4934 (const struct GNUNET_MessageHeader *) &cb[1];
4935 uint16_t isize = ntohs (inbox->size);
4936 const char *is = ((const char *) &cb[1]) + isize;
4940 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
4941 struct TransportBackchannelEncapsulationMessage *be =
4942 (struct TransportBackchannelEncapsulationMessage *) mbuf;
4944 /* 0-termination of 'is' was checked already in
4945 #check_communicator_backchannel() */
4946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4947 "Preparing backchannel transmission to %s:%s of type %u\n",
4948 GNUNET_i2s (&cb->pid),
4950 ntohs (inbox->size));
4951 /* encapsulate and encrypt message */
4953 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4954 be->header.size = htons (sizeof(mbuf));
4955 memcpy (&be[1], inbox, isize);
4956 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
4960 route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
4961 GNUNET_SERVICE_client_continue (tc->client);
4966 * Address of our peer added. Test message is well-formed.
4968 * @param cls the client
4969 * @param aam the send message that was sent
4970 * @return #GNUNET_OK if message is well-formed
4973 check_add_address (void *cls,
4974 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4976 struct TransportClient *tc = cls;
4978 if (CT_COMMUNICATOR != tc->type)
4981 return GNUNET_SYSERR;
4983 GNUNET_MQ_check_zero_termination (aam);
4989 * Ask peerstore to store our address.
4991 * @param cls an `struct AddressListEntry *`
4994 store_pi (void *cls);
4998 * Function called when peerstore is done storing our address.
5000 * @param cls a `struct AddressListEntry`
5001 * @param success #GNUNET_YES if peerstore was successful
5004 peerstore_store_own_cb (void *cls, int success)
5006 struct AddressListEntry *ale = cls;
5009 if (GNUNET_YES != success)
5010 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5011 "Failed to store our own address `%s' in peerstore!\n",
5014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5015 "Successfully stored our own address `%s' in peerstore!\n",
5017 /* refresh period is 1/4 of expiration time, that should be plenty
5018 without being excessive. */
5020 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5028 * Ask peerstore to store our address.
5030 * @param cls an `struct AddressListEntry *`
5033 store_pi (void *cls)
5035 struct AddressListEntry *ale = cls;
5038 struct GNUNET_TIME_Absolute expiration;
5041 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5043 "Storing our address `%s' in peerstore until %s!\n",
5045 GNUNET_STRINGS_absolute_time_to_string (expiration));
5046 GNUNET_HELLO_sign_address (ale->address,
5052 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5055 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5059 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5060 &peerstore_store_own_cb,
5063 if (NULL == ale->sc)
5065 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5066 "Failed to store our address `%s' with peerstore\n",
5069 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5075 * Address of our peer added. Process the request.
5077 * @param cls the client
5078 * @param aam the send message that was sent
5081 handle_add_address (void *cls,
5082 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5084 struct TransportClient *tc = cls;
5085 struct AddressListEntry *ale;
5088 /* 0-termination of &aam[1] was checked in #check_add_address */
5089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5090 "Communicator added address `%s'!\n",
5091 (const char *) &aam[1]);
5092 slen = ntohs (aam->header.size) - sizeof(*aam);
5093 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5095 ale->address = (const char *) &ale[1];
5096 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5097 ale->aid = aam->aid;
5098 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5099 memcpy (&ale[1], &aam[1], slen);
5100 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5101 tc->details.communicator.addr_tail,
5103 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5104 GNUNET_SERVICE_client_continue (tc->client);
5109 * Address of our peer deleted. Process the request.
5111 * @param cls the client
5112 * @param dam the send message that was sent
5115 handle_del_address (void *cls,
5116 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5118 struct TransportClient *tc = cls;
5119 struct AddressListEntry *alen;
5121 if (CT_COMMUNICATOR != tc->type)
5124 GNUNET_SERVICE_client_drop (tc->client);
5127 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5132 if (dam->aid != ale->aid)
5134 GNUNET_assert (ale->tc == tc);
5135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5136 "Communicator deleted address `%s'!\n",
5138 free_address_list_entry (ale);
5139 GNUNET_SERVICE_client_continue (tc->client);
5142 GNUNET_SERVICE_client_drop (tc->client);
5147 * Given an inbound message @a msg from a communicator @a cmc,
5148 * demultiplex it based on the type calling the right handler.
5150 * @param cmc context for demultiplexing
5151 * @param msg message to demultiplex
5154 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5155 const struct GNUNET_MessageHeader *msg);
5159 * Function called when we are done giving a message of a certain
5160 * size to CORE and should thus decrement the number of bytes of
5161 * RAM reserved for that peer's MQ.
5163 * @param cls a `struct CoreSentContext`
5166 core_env_sent_cb (void *cls)
5168 struct CoreSentContext *ctx = cls;
5169 struct VirtualLink *vl = ctx->vl;
5173 /* lost the link in the meantime, ignore */
5177 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5178 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5179 vl->incoming_fc_window_size_ram -= ctx->size;
5180 vl->incoming_fc_window_size_used += ctx->isize;
5181 consider_sending_fc (vl);
5187 * Communicator gave us an unencapsulated message to pass as-is to
5188 * CORE. Process the request.
5190 * @param cls a `struct CommunicatorMessageContext` (must call
5191 * #finish_cmc_handling() when done)
5192 * @param mh the message that was received
5195 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5197 struct CommunicatorMessageContext *cmc = cls;
5198 struct VirtualLink *vl;
5199 uint16_t size = ntohs (mh->size);
5202 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5203 (size < sizeof(struct GNUNET_MessageHeader)))
5205 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5208 finish_cmc_handling (cmc);
5209 GNUNET_SERVICE_client_drop (client);
5212 vl = lookup_virtual_link (&cmc->im.sender);
5215 /* FIXME: sender is giving us messages for CORE but we don't have
5216 the link up yet! I *suspect* this can happen right now (i.e.
5217 sender has verified us, but we didn't verify sender), but if
5218 we pass this on, CORE would be confused (link down, messages
5219 arrive). We should investigate more if this happens often,
5220 or in a persistent manner, and possibly do "something" about
5221 it. Thus logging as error for now. */
5222 GNUNET_break_op (0);
5223 GNUNET_STATISTICS_update (GST_stats,
5224 "# CORE messages droped (virtual link still down)",
5228 finish_cmc_handling (cmc);
5231 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5233 GNUNET_STATISTICS_update (GST_stats,
5234 "# CORE messages droped (FC arithmetic overflow)",
5238 finish_cmc_handling (cmc);
5241 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5243 GNUNET_STATISTICS_update (GST_stats,
5244 "# CORE messages droped (FC window overflow)",
5247 finish_cmc_handling (cmc);
5251 /* Forward to all CORE clients */
5252 have_core = GNUNET_NO;
5253 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5255 struct GNUNET_MQ_Envelope *env;
5256 struct InboundMessage *im;
5257 struct CoreSentContext *ctx;
5259 if (CT_CORE != tc->type)
5261 vl->incoming_fc_window_size_ram += size;
5262 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5263 ctx = GNUNET_new (struct CoreSentContext);
5266 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5267 have_core = GNUNET_YES;
5268 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5269 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5270 im->peer = cmc->im.sender;
5271 memcpy (&im[1], mh, size);
5272 GNUNET_MQ_send (tc->mq, env);
5273 vl->core_recv_window--;
5275 if (GNUNET_NO == have_core)
5277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5278 "Dropped message to CORE: no CORE client connected!\n");
5279 /* Nevertheless, count window as used, as it is from the
5280 perspective of the other peer! */
5281 vl->incoming_fc_window_size_used += size;
5283 finish_cmc_handling (cmc);
5286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5287 "Delivered message from %s of type %u to CORE\n",
5288 GNUNET_i2s (&cmc->im.sender),
5290 if (vl->core_recv_window > 0)
5292 finish_cmc_handling (cmc);
5295 /* Wait with calling #finish_cmc_handling(cmc) until the message
5296 was processed by CORE MQs (for CORE flow control)! */
5297 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5302 * Communicator gave us a fragment box. Check the message.
5304 * @param cls a `struct CommunicatorMessageContext`
5305 * @param fb the send message that was sent
5306 * @return #GNUNET_YES if message is well-formed
5309 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5311 uint16_t size = ntohs (fb->header.size);
5312 uint16_t bsize = size - sizeof(*fb);
5317 GNUNET_break_op (0);
5318 return GNUNET_SYSERR;
5320 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5322 GNUNET_break_op (0);
5323 return GNUNET_SYSERR;
5325 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5327 GNUNET_break_op (0);
5328 return GNUNET_SYSERR;
5335 * Clean up an idle cummulative acknowledgement data structure.
5337 * @param cls a `struct AcknowledgementCummulator *`
5340 destroy_ack_cummulator (void *cls)
5342 struct AcknowledgementCummulator *ac = cls;
5345 GNUNET_assert (0 == ac->num_acks);
5348 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5354 * Do the transmission of a cummulative acknowledgement now.
5356 * @param cls a `struct AcknowledgementCummulator *`
5359 transmit_cummulative_ack_cb (void *cls)
5361 struct AcknowledgementCummulator *ac = cls;
5362 char buf[sizeof(struct TransportReliabilityAckMessage)
5364 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5365 struct TransportReliabilityAckMessage *ack =
5366 (struct TransportReliabilityAckMessage *) buf;
5367 struct TransportCummulativeAckPayloadP *ap;
5370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5371 "Sending ACK with %u components to %s\n",
5373 GNUNET_i2s (&ac->target));
5374 GNUNET_assert (0 < ac->ack_counter);
5375 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5378 + ac->ack_counter * sizeof(struct TransportCummulativeAckPayloadP));
5379 ack->ack_counter = htonl (ac->ack_counter++);
5380 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5381 for (unsigned int i = 0; i < ac->ack_counter; i++)
5383 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5384 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5385 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5387 route_control_message_without_fc (&ac->target, &ack->header, RMO_DV_ALLOWED);
5389 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5390 &destroy_ack_cummulator,
5396 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5397 * transmission by at most @a ack_delay.
5399 * @param pid target peer
5400 * @param ack_uuid UUID to ack
5401 * @param max_delay how long can the ACK wait
5404 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5405 const struct AcknowledgementUUIDP *ack_uuid,
5406 struct GNUNET_TIME_Absolute max_delay)
5408 struct AcknowledgementCummulator *ac;
5410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5411 "Scheduling ACK %s for transmission to %s\n",
5412 GNUNET_uuid2s (&ack_uuid->value),
5414 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5417 ac = GNUNET_new (struct AcknowledgementCummulator);
5419 ac->min_transmission_time = max_delay;
5420 GNUNET_assert (GNUNET_YES ==
5421 GNUNET_CONTAINER_multipeermap_put (
5425 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5429 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5431 /* must run immediately, ack buffer full! */
5432 GNUNET_SCHEDULER_cancel (ac->task);
5433 transmit_cummulative_ack_cb (ac);
5435 GNUNET_SCHEDULER_cancel (ac->task);
5436 ac->min_transmission_time =
5437 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5439 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5440 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5441 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5443 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5444 &transmit_cummulative_ack_cb,
5450 * Closure for #find_by_message_uuid.
5452 struct FindByMessageUuidContext
5457 struct MessageUUIDP message_uuid;
5460 * Set to the reassembly context if found.
5462 struct ReassemblyContext *rc;
5467 * Iterator called to find a reassembly context by the message UUID in the
5470 * @param cls a `struct FindByMessageUuidContext`
5471 * @param key a key (unused)
5472 * @param value a `struct ReassemblyContext`
5473 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5476 find_by_message_uuid (void *cls, uint32_t key, void *value)
5478 struct FindByMessageUuidContext *fc = cls;
5479 struct ReassemblyContext *rc = value;
5482 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5492 * Communicator gave us a fragment. Process the request.
5494 * @param cls a `struct CommunicatorMessageContext` (must call
5495 * #finish_cmc_handling() when done)
5496 * @param fb the message that was received
5499 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5501 struct CommunicatorMessageContext *cmc = cls;
5502 struct Neighbour *n;
5503 struct ReassemblyContext *rc;
5504 const struct GNUNET_MessageHeader *msg;
5509 struct GNUNET_TIME_Relative cdelay;
5510 struct FindByMessageUuidContext fc;
5512 n = lookup_neighbour (&cmc->im.sender);
5515 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5518 finish_cmc_handling (cmc);
5519 GNUNET_SERVICE_client_drop (client);
5522 if (NULL == n->reassembly_map)
5524 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5525 n->reassembly_heap =
5526 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5527 n->reassembly_timeout_task =
5528 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5529 &reassembly_cleanup_task,
5532 msize = ntohs (fb->msg_size);
5533 fc.message_uuid = fb->msg_uuid;
5535 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5537 &find_by_message_uuid,
5539 if (NULL == (rc = fc.rc))
5541 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
5542 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
5543 rc->msg_uuid = fb->msg_uuid;
5545 rc->msg_size = msize;
5546 rc->reassembly_timeout =
5547 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5548 rc->last_frag = GNUNET_TIME_absolute_get ();
5549 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5551 rc->reassembly_timeout.abs_value_us);
5552 GNUNET_assert (GNUNET_OK ==
5553 GNUNET_CONTAINER_multihashmap32_put (
5557 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5558 target = (char *) &rc[1];
5559 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5560 rc->msg_missing = rc->msg_size;
5561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5562 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5563 ntohs (fb->frag_off),
5565 GNUNET_i2s (&cmc->im.sender),
5566 (unsigned int) fb->msg_uuid.uuid);
5570 target = (char *) &rc[1];
5571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5572 "Received fragment at offset %u/%u from %s for message %u\n",
5573 ntohs (fb->frag_off),
5575 GNUNET_i2s (&cmc->im.sender),
5576 (unsigned int) fb->msg_uuid.uuid);
5578 if (msize != rc->msg_size)
5581 finish_cmc_handling (cmc);
5586 fsize = ntohs (fb->header.size) - sizeof(*fb);
5590 finish_cmc_handling (cmc);
5593 frag_off = ntohs (fb->frag_off);
5594 if (frag_off + fsize > msize)
5596 /* Fragment (plus fragment size) exceeds message size! */
5597 GNUNET_break_op (0);
5598 finish_cmc_handling (cmc);
5601 memcpy (&target[frag_off], &fb[1], fsize);
5602 /* update bitfield and msg_missing */
5603 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5605 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5607 rc->bitfield[i / 8] |= (1 << (i % 8));
5612 /* Compute cummulative ACK */
5613 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5614 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5615 if (0 == rc->msg_missing)
5616 cdelay = GNUNET_TIME_UNIT_ZERO;
5617 cummulative_ack (&cmc->im.sender,
5619 GNUNET_TIME_relative_to_absolute (cdelay));
5620 rc->last_frag = GNUNET_TIME_absolute_get ();
5621 /* is reassembly complete? */
5622 if (0 != rc->msg_missing)
5624 finish_cmc_handling (cmc);
5627 /* reassembly is complete, verify result */
5628 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5629 if (ntohs (msg->size) != rc->msg_size)
5632 free_reassembly_context (rc);
5633 finish_cmc_handling (cmc);
5636 /* successful reassembly */
5637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5638 "Fragment reassembly complete for message %u\n",
5639 (unsigned int) fb->msg_uuid.uuid);
5640 /* FIXME: check that the resulting msg is NOT a
5641 DV Box or Reliability Box, as that is NOT allowed! */
5642 demultiplex_with_cmc (cmc, msg);
5643 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5644 en-route and we forget that we finished this reassembly immediately!
5645 -> keep around until timeout?
5646 -> shorten timeout based on ACK? */
5647 free_reassembly_context (rc);
5652 * Communicator gave us a reliability box. Check the message.
5654 * @param cls a `struct CommunicatorMessageContext`
5655 * @param rb the send message that was sent
5656 * @return #GNUNET_YES if message is well-formed
5659 check_reliability_box (void *cls,
5660 const struct TransportReliabilityBoxMessage *rb)
5663 GNUNET_MQ_check_boxed_message (rb);
5669 * Communicator gave us a reliability box. Process the request.
5671 * @param cls a `struct CommunicatorMessageContext` (must call
5672 * #finish_cmc_handling() when done)
5673 * @param rb the message that was received
5676 handle_reliability_box (void *cls,
5677 const struct TransportReliabilityBoxMessage *rb)
5679 struct CommunicatorMessageContext *cmc = cls;
5680 const struct GNUNET_MessageHeader *inbox =
5681 (const struct GNUNET_MessageHeader *) &rb[1];
5682 struct GNUNET_TIME_Relative rtt;
5684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5685 "Received reliability box from %s with UUID %s of type %u\n",
5686 GNUNET_i2s (&cmc->im.sender),
5687 GNUNET_uuid2s (&rb->ack_uuid.value),
5688 (unsigned int) ntohs (inbox->type));
5689 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5690 do not really have an RTT for the
5691 * incoming* queue (should we have
5692 the sender add it to the rb message?) */
5696 (0 == ntohl (rb->ack_countdown))
5697 ? GNUNET_TIME_UNIT_ZERO_ABS
5698 : GNUNET_TIME_relative_to_absolute (
5699 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5700 /* continue with inner message */
5701 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5702 reliability box (not allowed!) */
5703 demultiplex_with_cmc (cmc, inbox);
5708 * Check if we have advanced to another age since the last time. If
5709 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5712 * @param pd[in,out] data to update
5713 * @param age current age
5716 update_pd_age (struct PerformanceData *pd, unsigned int age)
5720 if (age == pd->last_age)
5721 return; /* nothing to do */
5722 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5723 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5725 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5727 the->bytes_sent = 0;
5728 the->bytes_received = 0;
5735 * Update @a pd based on the latest @a rtt and the number of bytes
5736 * that were confirmed to be successfully transmitted.
5738 * @param pd[in,out] data to update
5739 * @param rtt latest round-trip time
5740 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5743 update_performance_data (struct PerformanceData *pd,
5744 struct GNUNET_TIME_Relative rtt,
5745 uint16_t bytes_transmitted_ok)
5747 uint64_t nval = rtt.rel_value_us;
5748 uint64_t oval = pd->aged_rtt.rel_value_us;
5749 unsigned int age = get_age ();
5750 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5752 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5755 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5756 update_pd_age (pd, age);
5757 the->bytes_received += bytes_transmitted_ok;
5762 * We have successfully transmitted data via @a q, update metrics.
5764 * @param q queue to update
5765 * @param rtt round trip time observed
5766 * @param bytes_transmitted_ok number of bytes successfully transmitted
5769 update_queue_performance (struct Queue *q,
5770 struct GNUNET_TIME_Relative rtt,
5771 uint16_t bytes_transmitted_ok)
5773 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5778 * We have successfully transmitted data via @a dvh, update metrics.
5780 * @param dvh distance vector path data to update
5781 * @param rtt round trip time observed
5782 * @param bytes_transmitted_ok number of bytes successfully transmitted
5785 update_dvh_performance (struct DistanceVectorHop *dvh,
5786 struct GNUNET_TIME_Relative rtt,
5787 uint16_t bytes_transmitted_ok)
5789 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5794 * We have completed transmission of @a pm, remove it from
5795 * the transmission queues (and if it is a fragment, continue
5796 * up the tree as necessary).
5798 * @param pm pending message that was transmitted
5801 completed_pending_message (struct PendingMessage *pm)
5803 struct PendingMessage *pos;
5808 case PMT_RELIABILITY_BOX:
5809 /* Full message sent, we are done */
5810 client_send_response (pm);
5813 case PMT_FRAGMENT_BOX:
5814 /* Fragment sent over reliabile channel */
5815 free_fragment_tree (pm);
5816 pos = pm->frag_parent;
5817 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5819 /* check if subtree is done */
5820 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5824 pos = pm->frag_parent;
5825 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5829 /* Was this the last applicable fragmment? */
5830 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
5831 (pos->frag_off == pos->bytes_msg))
5832 client_send_response (pos);
5836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5837 "Completed transmission of message %llu (DV Box)\n",
5839 free_pending_message (pm);
5846 * The @a pa was acknowledged, process the acknowledgement.
5848 * @param pa the pending acknowledgement that was satisfied
5849 * @param ack_delay artificial delay from cummulative acks created by the
5853 handle_acknowledged (struct PendingAcknowledgement *pa,
5854 struct GNUNET_TIME_Relative ack_delay)
5856 struct GNUNET_TIME_Relative delay;
5858 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5859 if (delay.rel_value_us > ack_delay.rel_value_us)
5860 delay = GNUNET_TIME_UNIT_ZERO;
5862 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5863 if (NULL != pa->queue)
5864 update_queue_performance (pa->queue, delay, pa->message_size);
5865 if (NULL != pa->dvh)
5866 update_dvh_performance (pa->dvh, delay, pa->message_size);
5868 completed_pending_message (pa->pm);
5869 free_pending_acknowledgement (pa);
5874 * Communicator gave us a reliability ack. Check it is well-formed.
5876 * @param cls a `struct CommunicatorMessageContext` (unused)
5877 * @param ra the message that was received
5878 * @return #GNUNET_Ok if @a ra is well-formed
5881 check_reliability_ack (void *cls,
5882 const struct TransportReliabilityAckMessage *ra)
5884 unsigned int n_acks;
5887 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5888 / sizeof(struct TransportCummulativeAckPayloadP);
5891 GNUNET_break_op (0);
5892 return GNUNET_SYSERR;
5894 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
5895 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
5897 GNUNET_break_op (0);
5898 return GNUNET_SYSERR;
5905 * Communicator gave us a reliability ack. Process the request.
5907 * @param cls a `struct CommunicatorMessageContext` (must call
5908 * #finish_cmc_handling() when done)
5909 * @param ra the message that was received
5912 handle_reliability_ack (void *cls,
5913 const struct TransportReliabilityAckMessage *ra)
5915 struct CommunicatorMessageContext *cmc = cls;
5916 const struct TransportCummulativeAckPayloadP *ack;
5917 unsigned int n_acks;
5918 uint32_t ack_counter;
5920 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5921 / sizeof(struct TransportCummulativeAckPayloadP);
5922 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5923 for (unsigned int i = 0; i < n_acks; i++)
5925 struct PendingAcknowledgement *pa =
5926 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5929 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5930 "Received ACK from %s with UUID %s which is unknown to us!\n",
5931 GNUNET_i2s (&cmc->im.sender),
5932 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5933 GNUNET_STATISTICS_update (
5935 "# FRAGMENT_ACKS dropped, no matching pending message",
5940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5941 "Received ACK from %s with UUID %s\n",
5942 GNUNET_i2s (&cmc->im.sender),
5943 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5944 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5947 ack_counter = htonl (ra->ack_counter);
5948 (void) ack_counter; /* silence compiler warning for now */
5949 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5950 // (DV and/or Neighbour?)
5951 finish_cmc_handling (cmc);
5956 * Communicator gave us a backchannel encapsulation. Check the message.
5958 * @param cls a `struct CommunicatorMessageContext`
5959 * @param be the send message that was sent
5960 * @return #GNUNET_YES if message is well-formed
5963 check_backchannel_encapsulation (
5965 const struct TransportBackchannelEncapsulationMessage *be)
5967 uint16_t size = ntohs (be->header.size) - sizeof(*be);
5968 const struct GNUNET_MessageHeader *inbox =
5969 (const struct GNUNET_MessageHeader *) &be[1];
5974 if (ntohs (inbox->size) >= size)
5976 GNUNET_break_op (0);
5977 return GNUNET_SYSERR;
5979 isize = ntohs (inbox->size);
5980 is = ((const char *) inbox) + isize;
5982 if ('\0' != is[size - 1])
5984 GNUNET_break_op (0);
5985 return GNUNET_SYSERR;
5992 * Communicator gave us a backchannel encapsulation. Process the request.
5993 * (We are the destination of the backchannel here.)
5995 * @param cls a `struct CommunicatorMessageContext` (must call
5996 * #finish_cmc_handling() when done)
5997 * @param be the message that was received
6000 handle_backchannel_encapsulation (
6002 const struct TransportBackchannelEncapsulationMessage *be)
6004 struct CommunicatorMessageContext *cmc = cls;
6005 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6006 struct GNUNET_MQ_Envelope *env;
6007 struct TransportClient *tc;
6008 const struct GNUNET_MessageHeader *inbox =
6009 (const struct GNUNET_MessageHeader *) &be[1];
6010 uint16_t isize = ntohs (inbox->size);
6011 const char *target_communicator = ((const char *) inbox) + isize;
6013 /* Find client providing this communicator */
6014 for (tc = clients_head; NULL != tc; tc = tc->next)
6015 if ((CT_COMMUNICATOR == tc->type) &&
6017 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6025 "# Backchannel message dropped: target communicator `%s' unknown",
6026 target_communicator);
6027 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6028 GNUNET_free (stastr);
6031 /* Finally, deliver backchannel message to communicator */
6032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6033 "Delivering backchannel message from %s of type %u to %s\n",
6034 GNUNET_i2s (&cmc->im.sender),
6035 ntohs (inbox->type),
6036 target_communicator);
6037 env = GNUNET_MQ_msg_extra (
6040 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6041 cbi->pid = cmc->im.sender;
6042 memcpy (&cbi[1], inbox, isize);
6043 GNUNET_MQ_send (tc->mq, env);
6048 * Task called when we should check if any of the DV paths
6049 * we have learned to a target are due for garbage collection.
6051 * Collects stale paths, and possibly frees the entire DV
6052 * entry if no paths are left. Otherwise re-schedules itself.
6054 * @param cls a `struct DistanceVector`
6057 path_cleanup_cb (void *cls)
6059 struct DistanceVector *dv = cls;
6060 struct DistanceVectorHop *pos;
6062 dv->timeout_task = NULL;
6063 while (NULL != (pos = dv->dv_head))
6065 GNUNET_assert (dv == pos->dv);
6066 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6068 free_distance_vector_hop (pos);
6076 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6081 * The @a hop is a validated path to the respective target
6082 * peer and we should tell core about it -- and schedule
6083 * a job to revoke the state.
6085 * @param hop a path to some peer that is the reason for activation
6088 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6090 struct DistanceVector *dv = hop->dv;
6091 struct VirtualLink *vl;
6093 vl = lookup_virtual_link (&dv->target);
6096 /* Link was already up, remember dv is also now available and we are done */
6098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6099 "Virtual link to %s could now also use DV!\n",
6100 GNUNET_i2s (&dv->target));
6103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6104 "Creating new virtual link to %s using DV!\n",
6105 GNUNET_i2s (&dv->target));
6106 vl = GNUNET_new (struct VirtualLink);
6107 vl->message_uuid_ctr =
6108 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6109 vl->target = dv->target;
6112 vl->core_recv_window = RECV_WINDOW_SIZE;
6113 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6114 vl->visibility_task =
6115 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6116 GNUNET_break (GNUNET_YES ==
6117 GNUNET_CONTAINER_multipeermap_put (
6121 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6122 consider_sending_fc (vl);
6123 /* We lacked a confirmed connection to the target
6124 before, so tell CORE about it (finally!) */
6125 cores_send_connect_info (&dv->target);
6130 * We have learned a @a path through the network to some other peer, add it to
6131 * our DV data structure (returning #GNUNET_YES on success).
6133 * We do not add paths if we have a sufficient number of shorter
6134 * paths to this target already (returning #GNUNET_NO).
6136 * We also do not add problematic paths, like those where we lack the first
6137 * hop in our neighbour list (i.e. due to a topology change) or where some
6138 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6140 * @param path the path we learned, path[0] should be us,
6141 * and then path contains a valid path from us to
6142 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6143 * @param path_len number of entries on the @a path, at least three!
6144 * @param network_latency how long does the message take from us to
6145 * `path[path_len-1]`? set to "forever" if unknown
6146 * @param path_valid_until how long is this path considered validated? Maybe
6148 * @return #GNUNET_YES on success,
6149 * #GNUNET_NO if we have better path(s) to the target
6150 * #GNUNET_SYSERR if the path is useless and/or invalid
6151 * (i.e. path[1] not a direct neighbour
6152 * or path[i+1] is a direct neighbour for i>0)
6155 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6156 unsigned int path_len,
6157 struct GNUNET_TIME_Relative network_latency,
6158 struct GNUNET_TIME_Absolute path_valid_until)
6160 struct DistanceVectorHop *hop;
6161 struct DistanceVector *dv;
6162 struct Neighbour *next_hop;
6163 unsigned int shorter_distance;
6167 /* what a boring path! not allowed! */
6169 return GNUNET_SYSERR;
6171 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6172 next_hop = lookup_neighbour (&path[1]);
6173 if (NULL == next_hop)
6175 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6177 return GNUNET_SYSERR;
6179 for (unsigned int i = 2; i < path_len; i++)
6180 if (NULL != lookup_neighbour (&path[i]))
6182 /* Useless path: we have a direct connection to some hop
6183 in the middle of the path, so this one is not even
6184 terribly useful for redundancy */
6185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6186 "Path of %u hops useless: directly link to hop %u (%s)\n",
6189 GNUNET_i2s (&path[i]));
6190 GNUNET_STATISTICS_update (GST_stats,
6191 "# Useless DV path ignored: hop is neighbour",
6194 return GNUNET_SYSERR;
6196 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6199 dv = GNUNET_new (struct DistanceVector);
6200 dv->target = path[path_len - 1];
6201 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6204 GNUNET_assert (GNUNET_OK ==
6205 GNUNET_CONTAINER_multipeermap_put (
6209 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6211 /* Check if we have this path already! */
6212 shorter_distance = 0;
6213 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6216 if (pos->distance < path_len - 2)
6218 /* Note that the distances in 'pos' excludes us (path[0]) and
6219 the next_hop (path[1]), so we need to subtract two
6220 and check next_hop explicitly */
6221 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6223 int match = GNUNET_YES;
6225 for (unsigned int i = 0; i < pos->distance; i++)
6227 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6233 if (GNUNET_YES == match)
6235 struct GNUNET_TIME_Relative last_timeout;
6237 /* Re-discovered known path, update timeout */
6238 GNUNET_STATISTICS_update (GST_stats,
6239 "# Known DV path refreshed",
6242 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6244 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6245 pos->path_valid_until =
6246 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6247 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6248 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6250 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6251 activate_core_visible_dv_path (pos);
6252 if (last_timeout.rel_value_us <
6253 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6254 DV_PATH_DISCOVERY_FREQUENCY)
6257 /* Some peer send DV learn messages too often, we are learning
6258 the same path faster than it would be useful; do not forward! */
6259 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6260 "Rediscovered path too quickly, not forwarding further\n");
6263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6264 "Refreshed known path to %s, forwarding further\n",
6265 GNUNET_i2s (&dv->target));
6270 /* Count how many shorter paths we have (incl. direct
6271 neighbours) before simply giving up on this one! */
6272 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6274 /* We have a shorter path already! */
6275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6276 "Have many shorter DV paths %s, not forwarding further\n",
6277 GNUNET_i2s (&dv->target));
6280 /* create new DV path entry */
6281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6282 "Discovered new DV path to %s\n",
6283 GNUNET_i2s (&dv->target));
6284 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
6285 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6286 hop->next_hop = next_hop;
6288 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6291 sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6292 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6293 hop->path_valid_until = path_valid_until;
6294 hop->distance = path_len - 2;
6295 hop->pd.aged_rtt = network_latency;
6296 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6297 GNUNET_CONTAINER_MDLL_insert (neighbour,
6301 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6302 activate_core_visible_dv_path (hop);
6308 * Communicator gave us a DV learn message. Check the message.
6310 * @param cls a `struct CommunicatorMessageContext`
6311 * @param dvl the send message that was sent
6312 * @return #GNUNET_YES if message is well-formed
6315 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6317 uint16_t size = ntohs (dvl->header.size);
6318 uint16_t num_hops = ntohs (dvl->num_hops);
6319 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6322 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
6324 GNUNET_break_op (0);
6325 return GNUNET_SYSERR;
6327 if (num_hops > MAX_DV_HOPS_ALLOWED)
6329 GNUNET_break_op (0);
6330 return GNUNET_SYSERR;
6332 for (unsigned int i = 0; i < num_hops; i++)
6334 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6336 GNUNET_break_op (0);
6337 return GNUNET_SYSERR;
6339 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6341 GNUNET_break_op (0);
6342 return GNUNET_SYSERR;
6350 * Build and forward a DV learn message to @a next_hop.
6352 * @param next_hop peer to send the message to
6353 * @param msg message received
6354 * @param bi_history bitmask specifying hops on path that were bidirectional
6355 * @param nhops length of the @a hops array
6356 * @param hops path the message traversed so far
6357 * @param in_time when did we receive the message, used to calculate network
6361 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6362 const struct TransportDVLearnMessage *msg,
6363 uint16_t bi_history,
6365 const struct DVPathEntryP *hops,
6366 struct GNUNET_TIME_Absolute in_time)
6368 struct DVPathEntryP *dhops;
6369 char buf[sizeof(struct TransportDVLearnMessage)
6370 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
6371 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6372 struct GNUNET_TIME_Relative nnd;
6374 /* compute message for forwarding */
6375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6376 "Forwarding DV learn message originating from %s to %s\n",
6377 GNUNET_i2s (&msg->initiator),
6378 GNUNET_i2s2 (next_hop));
6379 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6380 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6381 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
6382 + (nhops + 1) * sizeof(struct DVPathEntryP));
6383 fwd->num_hops = htons (nhops + 1);
6384 fwd->bidirectional = htons (bi_history);
6385 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6386 GNUNET_TIME_relative_ntoh (
6387 msg->non_network_delay));
6388 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6389 fwd->init_sig = msg->init_sig;
6390 fwd->initiator = msg->initiator;
6391 fwd->challenge = msg->challenge;
6392 dhops = (struct DVPathEntryP *) &fwd[1];
6393 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
6394 dhops[nhops].hop = GST_my_identity;
6396 struct DvHopPS dhp = { .purpose.purpose =
6397 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6398 .purpose.size = htonl (sizeof(dhp)),
6399 .pred = dhops[nhops - 1].hop,
6401 .challenge = msg->challenge };
6403 GNUNET_assert (GNUNET_OK ==
6404 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6406 &dhops[nhops].hop_sig));
6408 route_control_message_without_fc (next_hop,
6410 RMO_UNCONFIRMED_ALLOWED);
6415 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6417 * @param sender_monotonic_time monotonic time of the initiator
6418 * @param init the signer
6419 * @param challenge the challenge that was signed
6420 * @param init_sig signature presumably by @a init
6421 * @return #GNUNET_OK if the signature is valid
6424 validate_dv_initiator_signature (
6425 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6426 const struct GNUNET_PeerIdentity *init,
6427 const struct ChallengeNonceP *challenge,
6428 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6430 struct DvInitPS ip = { .purpose.purpose = htonl (
6431 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6432 .purpose.size = htonl (sizeof(ip)),
6433 .monotonic_time = sender_monotonic_time,
6434 .challenge = *challenge };
6438 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6443 GNUNET_break_op (0);
6444 return GNUNET_SYSERR;
6451 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6453 struct NeighbourSelectionContext
6456 * Original message we received.
6458 const struct TransportDVLearnMessage *dvl;
6463 const struct DVPathEntryP *hops;
6466 * Time we received the message.
6468 struct GNUNET_TIME_Absolute in_time;
6471 * Offsets of the selected peers.
6473 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6476 * Number of peers eligible for selection.
6478 unsigned int num_eligible;
6481 * Number of peers that were selected for forwarding.
6483 unsigned int num_selections;
6486 * Number of hops in @e hops
6491 * Bitmap of bidirectional connections encountered.
6493 uint16_t bi_history;
6498 * Function called for each neighbour during #handle_dv_learn.
6500 * @param cls a `struct NeighbourSelectionContext *`
6501 * @param pid identity of the peer
6502 * @param value a `struct Neighbour`
6503 * @return #GNUNET_YES (always)
6506 dv_neighbour_selection (void *cls,
6507 const struct GNUNET_PeerIdentity *pid,
6510 struct NeighbourSelectionContext *nsc = cls;
6513 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6514 return GNUNET_YES; /* skip initiator */
6515 for (unsigned int i = 0; i < nsc->nhops; i++)
6516 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6518 /* skip peers on path */
6519 nsc->num_eligible++;
6525 * Function called for each neighbour during #handle_dv_learn.
6526 * We call #forward_dv_learn() on the neighbour(s) selected
6527 * during #dv_neighbour_selection().
6529 * @param cls a `struct NeighbourSelectionContext *`
6530 * @param pid identity of the peer
6531 * @param value a `struct Neighbour`
6532 * @return #GNUNET_YES (always)
6535 dv_neighbour_transmission (void *cls,
6536 const struct GNUNET_PeerIdentity *pid,
6539 struct NeighbourSelectionContext *nsc = cls;
6542 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6543 return GNUNET_YES; /* skip initiator */
6544 for (unsigned int i = 0; i < nsc->nhops; i++)
6545 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6547 /* skip peers on path */
6548 for (unsigned int i = 0; i < nsc->num_selections; i++)
6550 if (nsc->selections[i] == nsc->num_eligible)
6552 forward_dv_learn (pid,
6561 nsc->num_eligible++;
6567 * Computes the number of neighbours we should forward a DVInit
6568 * message to given that it has so far taken @a hops_taken hops
6569 * though the network and that the number of neighbours we have
6570 * in total is @a neighbour_count, out of which @a eligible_count
6571 * are not yet on the path.
6573 * NOTE: technically we might want to include NSE in the formula to
6574 * get a better grip on the overall network size. However, for now
6575 * using NSE here would create a dependency issue in the build system.
6576 * => Left for later, hardcoded to 50 for now.
6578 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6579 * peers via DV (`target_total`). We want the reach to be spread out
6580 * over various distances to the origin, with a bias towards shorter
6583 * We make the strong assumption that the network topology looks
6584 * "similar" at other hops, in particular the @a neighbour_count
6585 * should be comparable at other hops.
6587 * If the local neighbourhood is densely connected, we expect that @a
6588 * eligible_count is close to @a neighbour_count minus @a hops_taken
6589 * as a lot of the path is already known. In that case, we should
6590 * forward to few(er) peers to try to find a path out of the
6591 * neighbourhood. OTOH, if @a eligible_count is close to @a
6592 * neighbour_count, we should forward to many peers as we are either
6593 * still close to the origin (i.e. @a hops_taken is small) or because
6594 * we managed to get beyond a local cluster. We express this as
6595 * the `boost_factor` using the square of the fraction of eligible
6596 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6597 * 99% are eligible, the 'boost' will be almost 1).
6599 * Second, the more hops we have taken, the larger the problem of an
6600 * exponential traffic explosion gets. So we take the `target_total`,
6601 * and compute our degree such that at each distance d 2^{-d} peers
6602 * are selected (corrected by the `boost_factor`).
6604 * @param hops_taken number of hops DVInit has travelled so far
6605 * @param neighbour_count number of neighbours we have in total
6606 * @param eligible_count number of neighbours we could in
6610 calculate_fork_degree (unsigned int hops_taken,
6611 unsigned int neighbour_count,
6612 unsigned int eligible_count)
6614 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6615 double eligible_ratio =
6616 ((double) eligible_count) / ((double) neighbour_count);
6617 double boost_factor = eligible_ratio * eligible_ratio;
6621 if (hops_taken >= 64)
6624 return 0; /* precaution given bitshift below */
6626 for (unsigned int i = 1; i < hops_taken; i++)
6628 /* For each hop, subtract the expected number of targets
6629 reached at distance d (so what remains divided by 2^d) */
6630 target_total -= (target_total * boost_factor / (1LLU << i));
6633 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6634 /* round up or down probabilistically depending on how close we were
6635 when floor()ing to rnd */
6636 left = target_total - (double) rnd;
6637 if (UINT32_MAX * left >
6638 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6639 rnd++; /* round up */
6640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6641 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6651 * Function called when peerstore is done storing a DV monotonic time.
6653 * @param cls a `struct Neighbour`
6654 * @param success #GNUNET_YES if peerstore was successful
6657 neighbour_store_dvmono_cb (void *cls, int success)
6659 struct Neighbour *n = cls;
6662 if (GNUNET_YES != success)
6663 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6664 "Failed to store other peer's monotonic time in peerstore!\n");
6669 * Communicator gave us a DV learn message. Process the request.
6671 * @param cls a `struct CommunicatorMessageContext` (must call
6672 * #finish_cmc_handling() when done)
6673 * @param dvl the message that was received
6676 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6678 struct CommunicatorMessageContext *cmc = cls;
6679 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6682 uint16_t bi_history;
6683 const struct DVPathEntryP *hops;
6686 struct GNUNET_TIME_Absolute in_time;
6687 struct Neighbour *n;
6689 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6690 bi_history = ntohs (dvl->bidirectional);
6691 hops = (const struct DVPathEntryP *) &dvl[1];
6695 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6698 finish_cmc_handling (cmc);
6705 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6708 finish_cmc_handling (cmc);
6713 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6714 cc = cmc->tc->details.communicator.cc;
6715 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6716 cc); // FIXME: add bi-directional flag to cc?
6717 in_time = GNUNET_TIME_absolute_get ();
6719 /* continue communicator here, everything else can happen asynchronous! */
6720 finish_cmc_handling (cmc);
6722 n = lookup_neighbour (&dvl->initiator);
6725 if ((n->dv_monotime_available == GNUNET_YES) &&
6726 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6727 n->last_dv_learn_monotime.abs_value_us))
6729 GNUNET_STATISTICS_update (GST_stats,
6730 "# DV learn discarded due to time travel",
6735 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6740 GNUNET_break_op (0);
6743 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6744 if (GNUNET_YES == n->dv_monotime_available)
6747 GNUNET_PEERSTORE_store_cancel (n->sc);
6749 GNUNET_PEERSTORE_store (peerstore,
6752 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6753 &dvl->monotonic_time,
6754 sizeof(dvl->monotonic_time),
6755 GNUNET_TIME_UNIT_FOREVER_ABS,
6756 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6757 &neighbour_store_dvmono_cb,
6761 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6762 If signature verification load too high, implement random drop strategy */
6763 for (unsigned int i = 0; i < nhops; i++)
6765 struct DvHopPS dhp = { .purpose.purpose =
6766 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6767 .purpose.size = htonl (sizeof(dhp)),
6768 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6769 .succ = (nhops == i + 1) ? GST_my_identity
6771 .challenge = dvl->challenge };
6774 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6777 &hops[i].hop.public_key))
6779 GNUNET_break_op (0);
6784 if (GNUNET_EXTRA_LOGGING > 0)
6788 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6789 for (unsigned int i = 0; i < nhops; i++)
6793 GNUNET_asprintf (&tmp,
6796 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6797 GNUNET_i2s (&hops[i].hop));
6801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6802 "Received DVInit via %s%s%s\n",
6804 bi_hop ? "<->" : "-->",
6805 GNUNET_i2s (&GST_my_identity));
6809 do_fwd = GNUNET_YES;
6810 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6812 struct GNUNET_PeerIdentity path[nhops + 1];
6813 struct GNUNET_TIME_Relative host_latency_sum;
6814 struct GNUNET_TIME_Relative latency;
6815 struct GNUNET_TIME_Relative network_latency;
6817 /* We initiated this, learn the forward path! */
6818 path[0] = GST_my_identity;
6819 path[1] = hops[0].hop;
6820 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6822 // Need also something to lookup initiation time
6823 // to compute RTT! -> add RTT argument here?
6824 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6825 // (based on dvl->challenge, we can identify time of origin!)
6827 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6828 /* assumption: latency on all links is the same */
6829 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6831 for (unsigned int i = 2; i <= nhops; i++)
6833 struct GNUNET_TIME_Relative ilat;
6835 /* assumption: linear latency increase per hop */
6836 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6837 path[i] = hops[i - 1].hop;
6838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6839 "Learned path with %u hops to %s with latency %s\n",
6841 GNUNET_i2s (&path[i]),
6842 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6843 learn_dv_path (path,
6846 GNUNET_TIME_relative_to_absolute (
6847 ADDRESS_VALIDATION_LIFETIME));
6849 /* as we initiated, do not forward again (would be circular!) */
6855 /* last hop was bi-directional, we could learn something here! */
6856 struct GNUNET_PeerIdentity path[nhops + 2];
6858 path[0] = GST_my_identity;
6859 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6860 for (unsigned int i = 0; i < nhops; i++)
6864 if (0 == (bi_history & (1 << i)))
6865 break; /* i-th hop not bi-directional, stop learning! */
6868 path[i + 2] = dvl->initiator;
6872 path[i + 2] = hops[nhops - i - 2].hop;
6875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6876 "Learned inverse path with %u hops to %s\n",
6878 GNUNET_i2s (&path[i + 2]));
6879 iret = learn_dv_path (path,
6881 GNUNET_TIME_UNIT_FOREVER_REL,
6882 GNUNET_TIME_UNIT_ZERO_ABS);
6883 if (GNUNET_SYSERR == iret)
6885 /* path invalid or too long to be interesting for US, thus should also
6886 not be interesting to our neighbours, cut path when forwarding to
6887 'i' hops, except of course for the one that goes back to the
6889 GNUNET_STATISTICS_update (GST_stats,
6890 "# DV learn not forwarded due invalidity of path",
6896 if ((GNUNET_NO == iret) && (nhops == i + 1))
6898 /* we have better paths, and this is the longest target,
6899 so there cannot be anything interesting later */
6900 GNUNET_STATISTICS_update (GST_stats,
6901 "# DV learn not forwarded, got better paths",
6910 if (MAX_DV_HOPS_ALLOWED == nhops)
6912 /* At limit, we're out of here! */
6913 finish_cmc_handling (cmc);
6917 /* Forward to initiator, if path non-trivial and possible */
6918 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6919 did_initiator = GNUNET_NO;
6922 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6924 /* send back to origin! */
6925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6926 "Sending DVL back to initiator %s\n",
6927 GNUNET_i2s (&dvl->initiator));
6928 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6929 did_initiator = GNUNET_YES;
6931 /* We forward under two conditions: either we still learned something
6932 ourselves (do_fwd), or the path was darn short and thus the initiator is
6933 likely to still be very interested in this (and we did NOT already
6934 send it back to the initiator) */
6935 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6936 (GNUNET_NO == did_initiator)))
6938 /* Pick random neighbours that are not yet on the path */
6939 struct NeighbourSelectionContext nsc;
6942 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6945 nsc.bi_history = bi_history;
6947 nsc.in_time = in_time;
6948 nsc.num_eligible = 0;
6949 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6950 &dv_neighbour_selection,
6952 if (0 == nsc.num_eligible)
6953 return; /* done here, cannot forward to anyone else */
6954 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6955 nsc.num_selections =
6956 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6958 "Forwarding DVL to %u other peers\n",
6959 nsc.num_selections);
6960 for (unsigned int i = 0; i < nsc.num_selections; i++)
6962 (nsc.num_selections == n_cnt)
6963 ? i /* all were selected, avoid collisions by chance */
6964 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6965 nsc.num_eligible = 0;
6966 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6967 &dv_neighbour_transmission,
6974 * Communicator gave us a DV box. Check the message.
6976 * @param cls a `struct CommunicatorMessageContext`
6977 * @param dvb the send message that was sent
6978 * @return #GNUNET_YES if message is well-formed
6981 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6983 uint16_t size = ntohs (dvb->header.size);
6984 uint16_t num_hops = ntohs (dvb->num_hops);
6985 const struct GNUNET_PeerIdentity *hops =
6986 (const struct GNUNET_PeerIdentity *) &dvb[1];
6989 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
6990 + sizeof(struct GNUNET_MessageHeader))
6992 GNUNET_break_op (0);
6993 return GNUNET_SYSERR;
6995 /* This peer must not be on the path */
6996 for (unsigned int i = 0; i < num_hops; i++)
6997 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6999 GNUNET_break_op (0);
7000 return GNUNET_SYSERR;
7007 * Create a DV Box message and queue it for transmission to
7010 * @param next_hop peer to receive the message next
7011 * @param total_hops how many hops did the message take so far
7012 * @param num_hops length of the @a hops array
7013 * @param origin origin of the message
7014 * @param hops next peer(s) to the destination, including destination
7015 * @param payload payload of the box
7016 * @param payload_size number of bytes in @a payload
7019 forward_dv_box (struct Neighbour *next_hop,
7020 const struct TransportDVBoxMessage *hdr,
7021 uint16_t total_hops,
7023 const struct GNUNET_PeerIdentity *hops,
7024 const void *enc_payload,
7025 uint16_t enc_payload_size)
7027 struct VirtualLink *vl = next_hop->vl;
7028 struct PendingMessage *pm;
7031 struct GNUNET_PeerIdentity *dhops;
7033 GNUNET_assert (NULL != vl);
7034 msg_size = sizeof(struct TransportDVBoxMessage)
7035 + num_hops * sizeof(struct GNUNET_PeerIdentity) + enc_payload_size;
7036 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7037 pm->pmt = PMT_DV_BOX;
7039 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7040 pm->logging_uuid = logging_uuid_gen++;
7041 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7042 pm->bytes_msg = msg_size;
7043 buf = (char *) &pm[1];
7044 memcpy (buf, hdr, sizeof(*hdr));
7046 (struct GNUNET_PeerIdentity *) &buf[sizeof(struct TransportDVBoxMessage)];
7047 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7048 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7049 GNUNET_CONTAINER_MDLL_insert (vl,
7050 vl->pending_msg_head,
7051 vl->pending_msg_tail,
7053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7054 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7056 GNUNET_i2s (&next_hop->pid),
7057 (unsigned int) num_hops,
7058 (unsigned int) total_hops);
7059 check_vl_transmission (vl);
7064 * Free data structures associated with @a b.
7066 * @param b data structure to release
7069 free_backtalker (struct Backtalker *b)
7073 GNUNET_PEERSTORE_iterate_cancel (b->get);
7075 GNUNET_assert (NULL != b->cmc);
7076 finish_cmc_handling (b->cmc);
7079 if (NULL != b->task)
7081 GNUNET_SCHEDULER_cancel (b->task);
7086 GNUNET_PEERSTORE_store_cancel (b->sc);
7091 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7097 * Callback to free backtalker records.
7101 * @param value a `struct Backtalker`
7102 * @return #GNUNET_OK (always)
7105 free_backtalker_cb (void *cls,
7106 const struct GNUNET_PeerIdentity *pid,
7109 struct Backtalker *b = value;
7113 free_backtalker (b);
7119 * Function called when it is time to clean up a backtalker.
7121 * @param cls a `struct Backtalker`
7124 backtalker_timeout_cb (void *cls)
7126 struct Backtalker *b = cls;
7129 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7131 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7134 GNUNET_assert (NULL == b->sc);
7135 free_backtalker (b);
7140 * Function called with the monotonic time of a backtalker
7141 * by PEERSTORE. Updates the time and continues processing.
7143 * @param cls a `struct Backtalker`
7144 * @param record the information found, NULL for the last call
7145 * @param emsg error message
7148 backtalker_monotime_cb (void *cls,
7149 const struct GNUNET_PEERSTORE_Record *record,
7152 struct Backtalker *b = cls;
7153 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7154 struct GNUNET_TIME_Absolute mt;
7159 /* we're done with #backtalker_monotime_cb() invocations,
7160 continue normal processing */
7162 GNUNET_assert (NULL != b->cmc);
7163 if (0 != b->body_size)
7164 demultiplex_with_cmc (b->cmc,
7165 (const struct GNUNET_MessageHeader *) &b[1]);
7167 finish_cmc_handling (b->cmc);
7171 if (sizeof(*mtbe) != record->value_size)
7176 mtbe = record->value;
7177 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7178 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7181 "Backtalker message from %s dropped, monotime in the past\n",
7182 GNUNET_i2s (&b->pid));
7183 GNUNET_STATISTICS_update (
7185 "# Backchannel messages dropped: monotonic time not increasing",
7188 b->monotonic_time = mt;
7189 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7198 * Function called by PEERSTORE when the store operation of
7199 * a backtalker's monotonic time is complete.
7201 * @param cls the `struct Backtalker`
7202 * @param success #GNUNET_OK on success
7205 backtalker_monotime_store_cb (void *cls, int success)
7207 struct Backtalker *b = cls;
7209 if (GNUNET_OK != success)
7211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7212 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7215 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7220 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7222 * @param b a backtalker with updated monotonic time
7225 update_backtalker_monotime (struct Backtalker *b)
7227 struct GNUNET_TIME_AbsoluteNBO mtbe;
7231 GNUNET_PEERSTORE_store_cancel (b->sc);
7236 GNUNET_SCHEDULER_cancel (b->task);
7239 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7241 GNUNET_PEERSTORE_store (peerstore,
7244 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7247 GNUNET_TIME_UNIT_FOREVER_ABS,
7248 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7249 &backtalker_monotime_store_cb,
7255 * Communicator gave us a DV box. Process the request.
7257 * @param cls a `struct CommunicatorMessageContext` (must call
7258 * #finish_cmc_handling() when done)
7259 * @param dvb the message that was received
7262 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7264 struct CommunicatorMessageContext *cmc = cls;
7265 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
7266 uint16_t num_hops = ntohs (dvb->num_hops);
7267 const struct GNUNET_PeerIdentity *hops =
7268 (const struct GNUNET_PeerIdentity *) &dvb[1];
7269 const char *enc_payload = (const char *) &hops[num_hops];
7270 uint16_t enc_payload_size =
7271 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
7272 struct DVKeyState key;
7273 struct GNUNET_HashCode hmac;
7277 if (GNUNET_EXTRA_LOGGING > 0)
7281 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7282 for (unsigned int i = 0; i < num_hops; i++)
7286 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7291 "Received DVBox with remainig path %s\n",
7298 /* We're trying from the end of the hops array, as we may be
7299 able to find a shortcut unknown to the origin that way */
7300 for (int i = num_hops - 1; i >= 0; i--)
7302 struct Neighbour *n;
7304 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7306 GNUNET_break_op (0);
7307 finish_cmc_handling (cmc);
7310 n = lookup_neighbour (&hops[i]);
7313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7314 "Skipping %u/%u hops ahead while routing DV Box\n",
7319 ntohs (dvb->total_hops) + 1,
7320 num_hops - i - 1, /* number of hops left */
7321 &hops[i + 1], /* remaining hops */
7324 GNUNET_STATISTICS_update (GST_stats,
7325 "# DV hops skipped routing boxes",
7328 GNUNET_STATISTICS_update (GST_stats,
7329 "# DV boxes routed (total)",
7332 finish_cmc_handling (cmc);
7335 /* Woopsie, next hop not in neighbours, drop! */
7336 GNUNET_STATISTICS_update (GST_stats,
7337 "# DV Boxes dropped: next hop unknown",
7340 finish_cmc_handling (cmc);
7343 /* We are the target. Unbox and handle message. */
7344 GNUNET_STATISTICS_update (GST_stats,
7345 "# DV boxes opened (ultimate target)",
7348 cmc->total_hops = ntohs (dvb->total_hops);
7350 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key);
7351 hdr = (const char *) &dvb[1];
7352 hdr_len = ntohs (dvb->header.size) - sizeof(*dvb);
7353 dv_hmac (&key, &hmac, hdr, hdr_len);
7354 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7356 /* HMAC missmatch, disard! */
7357 GNUNET_break_op (0);
7358 finish_cmc_handling (cmc);
7361 /* begin actual decryption */
7363 struct Backtalker *b;
7364 struct GNUNET_TIME_Absolute monotime;
7365 struct TransportDVBoxPayloadP ppay;
7366 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
7367 const struct GNUNET_MessageHeader *mh =
7368 (const struct GNUNET_MessageHeader *) body;
7370 GNUNET_assert (hdr_len >=
7371 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
7372 dv_decrypt (&key, &ppay, hdr, sizeof(ppay));
7373 dv_decrypt (&key, &body, &hdr[sizeof(ppay)], hdr_len - sizeof(ppay));
7374 dv_key_clean (&key);
7375 if (ntohs (mh->size) != sizeof(body))
7377 GNUNET_break_op (0);
7378 finish_cmc_handling (cmc);
7381 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7382 switch (ntohs (mh->type))
7384 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7385 GNUNET_break_op (0);
7386 finish_cmc_handling (cmc);
7389 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7390 GNUNET_break_op (0);
7391 finish_cmc_handling (cmc);
7395 /* permitted, continue */
7398 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7400 "Decrypted backtalk from %s\n",
7401 GNUNET_i2s (&ppay.sender));
7402 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
7403 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
7405 GNUNET_STATISTICS_update (
7407 "# Backchannel messages dropped: monotonic time not increasing",
7410 finish_cmc_handling (cmc);
7414 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
7416 /* Check signature */
7417 struct EphemeralConfirmationPS ec;
7419 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
7420 ec.purpose.size = htonl (sizeof(ec));
7421 ec.target = GST_my_identity;
7422 ec.ephemeral_key = dvb->ephemeral_key;
7425 GNUNET_CRYPTO_eddsa_verify (
7426 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
7429 &ppay.sender.public_key))
7431 /* Signature invalid, disard! */
7432 GNUNET_break_op (0);
7433 finish_cmc_handling (cmc);
7437 /* Update sender, we now know the real origin! */
7438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7439 "DVBox received for me from %s via %s\n",
7440 GNUNET_i2s2 (&ppay.sender),
7441 GNUNET_i2s (&cmc->im.sender));
7442 cmc->im.sender = ppay.sender;
7446 /* update key cache and mono time */
7447 b->last_ephemeral = dvb->ephemeral_key;
7448 b->monotonic_time = monotime;
7449 update_backtalker_monotime (b);
7451 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7453 demultiplex_with_cmc (cmc, mh);
7456 /* setup data structure to cache signature AND check
7457 monotonic time with PEERSTORE before forwarding backchannel payload */
7458 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
7459 b->pid = ppay.sender;
7460 b->body_size = sizeof(body);
7461 memcpy (&b[1], body, sizeof(body));
7462 GNUNET_assert (GNUNET_YES ==
7463 GNUNET_CONTAINER_multipeermap_put (
7467 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7468 b->monotonic_time = monotime; /* NOTE: to be checked still! */
7471 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7472 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7474 GNUNET_PEERSTORE_iterate (peerstore,
7477 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7478 &backtalker_monotime_cb,
7480 } /* end actual decryption */
7485 * Client notified us about transmission from a peer. Process the request.
7487 * @param cls a `struct TransportClient` which sent us the message
7488 * @param obm the send message that was sent
7489 * @return #GNUNET_YES if message is well-formed
7492 check_incoming_msg (void *cls,
7493 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7495 struct TransportClient *tc = cls;
7497 if (CT_COMMUNICATOR != tc->type)
7500 return GNUNET_SYSERR;
7502 GNUNET_MQ_check_boxed_message (im);
7508 * Closure for #check_known_address.
7510 struct CheckKnownAddressContext
7513 * Set to the address we are looking for.
7515 const char *address;
7518 * Set to a matching validation state, if one was found.
7520 struct ValidationState *vs;
7525 * Test if the validation state in @a value matches the
7526 * address from @a cls.
7528 * @param cls a `struct CheckKnownAddressContext`
7529 * @param pid unused (must match though)
7530 * @param value a `struct ValidationState`
7531 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7534 check_known_address (void *cls,
7535 const struct GNUNET_PeerIdentity *pid,
7538 struct CheckKnownAddressContext *ckac = cls;
7539 struct ValidationState *vs = value;
7542 if (0 != strcmp (vs->address, ckac->address))
7550 * Task run periodically to validate some address based on #validation_heap.
7555 validation_start_cb (void *cls);
7559 * Set the time for next_challenge of @a vs to @a new_time.
7560 * Updates the heap and if necessary reschedules the job.
7562 * @param vs validation state to update
7563 * @param new_time new time for revalidation
7566 update_next_challenge_time (struct ValidationState *vs,
7567 struct GNUNET_TIME_Absolute new_time)
7569 struct GNUNET_TIME_Relative delta;
7571 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7572 return; /* be lazy */
7573 vs->next_challenge = new_time;
7576 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7578 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7579 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7580 (NULL != validation_task))
7582 if (NULL != validation_task)
7583 GNUNET_SCHEDULER_cancel (validation_task);
7584 /* randomize a bit */
7585 delta.rel_value_us =
7586 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7587 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7588 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7590 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7595 * Start address validation.
7597 * @param pid peer the @a address is for
7598 * @param address an address to reach @a pid (presumably)
7601 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7602 const char *address)
7604 struct GNUNET_TIME_Absolute now;
7605 struct ValidationState *vs;
7606 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
7608 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7610 &check_known_address,
7612 if (NULL != (vs = ckac.vs))
7614 /* if 'vs' is not currently valid, we need to speed up retrying the
7616 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7618 /* reduce backoff as we got a fresh advertisement */
7619 vs->challenge_backoff =
7620 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7621 GNUNET_TIME_relative_divide (
7622 vs->challenge_backoff,
7624 update_next_challenge_time (vs,
7625 GNUNET_TIME_relative_to_absolute (
7626 vs->challenge_backoff));
7630 now = GNUNET_TIME_absolute_get ();
7631 vs = GNUNET_new (struct ValidationState);
7634 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7635 vs->first_challenge_use = now;
7636 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7637 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7639 sizeof(vs->challenge));
7640 vs->address = GNUNET_strdup (address);
7641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7642 "Starting address validation `%s' of peer %s using challenge %s\n",
7645 GNUNET_sh2s (&vs->challenge.value));
7646 GNUNET_assert (GNUNET_YES ==
7647 GNUNET_CONTAINER_multipeermap_put (
7651 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7652 update_next_challenge_time (vs, now);
7657 * Function called by PEERSTORE for each matching record.
7659 * @param cls closure, a `struct IncomingRequest`
7660 * @param record peerstore record information
7661 * @param emsg error message, or NULL if no errors
7664 handle_hello_for_incoming (void *cls,
7665 const struct GNUNET_PEERSTORE_Record *record,
7668 struct IncomingRequest *ir = cls;
7673 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7674 "Got failure from PEERSTORE: %s\n",
7678 val = record->value;
7679 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7684 start_address_validation (&ir->pid, (const char *) record->value);
7689 * Communicator gave us a transport address validation challenge. Process the
7692 * @param cls a `struct CommunicatorMessageContext` (must call
7693 * #finish_cmc_handling() when done)
7694 * @param tvc the message that was received
7697 handle_validation_challenge (
7699 const struct TransportValidationChallengeMessage *tvc)
7701 struct CommunicatorMessageContext *cmc = cls;
7702 struct TransportValidationResponseMessage tvr;
7703 struct VirtualLink *vl;
7704 struct GNUNET_TIME_RelativeNBO validity_duration;
7705 struct IncomingRequest *ir;
7706 struct Neighbour *n;
7707 struct GNUNET_PeerIdentity sender;
7709 /* DV-routed messages are not allowed for validation challenges */
7710 if (cmc->total_hops > 0)
7712 GNUNET_break_op (0);
7713 finish_cmc_handling (cmc);
7716 validity_duration = cmc->im.expected_address_validity;
7717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7718 "Received address validation challenge %s\n",
7719 GNUNET_sh2s (&tvc->challenge.value));
7720 /* If we have a virtual link, we use this mechanism to signal the
7721 size of the flow control window, and to allow the sender
7722 to ask for increases. If for us the virtual link is still down,
7723 we will always give a window size of zero. */
7725 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7726 tvr.header.size = htons (sizeof(tvr));
7727 tvr.reserved = htonl (0);
7728 tvr.challenge = tvc->challenge;
7729 tvr.origin_time = tvc->sender_time;
7730 tvr.validity_duration = validity_duration;
7732 /* create signature */
7733 struct TransportValidationPS tvp =
7734 { .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7735 .purpose.size = htonl (sizeof(tvp)),
7736 .validity_duration = validity_duration,
7737 .challenge = tvc->challenge };
7739 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7743 route_control_message_without_fc (&cmc->im.sender,
7745 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7746 sender = cmc->im.sender;
7747 finish_cmc_handling (cmc);
7748 vl = lookup_virtual_link (&sender);
7752 /* For us, the link is still down, but we need bi-directional
7753 connections (for flow-control and for this to be useful for
7754 CORE), so we must try to bring the link up! */
7756 /* (1) Check existing queues, if any, we may be lucky! */
7757 n = lookup_neighbour (&sender);
7759 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7760 start_address_validation (&sender, q->address);
7761 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7763 for (ir = ir_head; NULL != ir; ir = ir->next)
7764 if (0 == GNUNET_memcmp (&ir->pid, &sender))
7766 /* we are already trying */
7767 ir = GNUNET_new (struct IncomingRequest);
7769 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7770 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7773 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7774 &handle_hello_for_incoming,
7777 /* Bound attempts we do in parallel here, might otherwise get excessive */
7778 while (ir_total > MAX_INCOMING_REQUEST)
7779 free_incoming_request (ir_head);
7784 * Closure for #check_known_challenge.
7786 struct CheckKnownChallengeContext
7789 * Set to the challenge we are looking for.
7791 const struct ChallengeNonceP *challenge;
7794 * Set to a matching validation state, if one was found.
7796 struct ValidationState *vs;
7801 * Test if the validation state in @a value matches the
7802 * challenge from @a cls.
7804 * @param cls a `struct CheckKnownChallengeContext`
7805 * @param pid unused (must match though)
7806 * @param value a `struct ValidationState`
7807 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7810 check_known_challenge (void *cls,
7811 const struct GNUNET_PeerIdentity *pid,
7814 struct CheckKnownChallengeContext *ckac = cls;
7815 struct ValidationState *vs = value;
7818 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7826 * Function called when peerstore is done storing a
7827 * validated address.
7829 * @param cls a `struct ValidationState`
7830 * @param success #GNUNET_YES on success
7833 peerstore_store_validation_cb (void *cls, int success)
7835 struct ValidationState *vs = cls;
7838 if (GNUNET_YES == success)
7840 GNUNET_STATISTICS_update (GST_stats,
7841 "# Peerstore failed to store foreign address",
7848 * Find the queue matching @a pid and @a address.
7850 * @param pid peer the queue must go to
7851 * @param address address the queue must use
7852 * @return NULL if no such queue exists
7854 static struct Queue *
7855 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7857 struct Neighbour *n;
7859 n = lookup_neighbour (pid);
7862 for (struct Queue *pos = n->queue_head; NULL != pos;
7863 pos = pos->next_neighbour)
7865 if (0 == strcmp (pos->address, address))
7873 * Communicator gave us a transport address validation response. Process the
7876 * @param cls a `struct CommunicatorMessageContext` (must call
7877 * #finish_cmc_handling() when done)
7878 * @param tvr the message that was received
7881 handle_validation_response (
7883 const struct TransportValidationResponseMessage *tvr)
7885 struct CommunicatorMessageContext *cmc = cls;
7886 struct ValidationState *vs;
7887 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
7889 struct GNUNET_TIME_Absolute origin_time;
7891 struct Neighbour *n;
7892 struct VirtualLink *vl;
7894 /* check this is one of our challenges */
7895 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7897 &check_known_challenge,
7899 if (NULL == (vs = ckac.vs))
7901 /* This can happen simply if we 'forgot' the challenge by now,
7902 i.e. because we received the validation response twice */
7903 GNUNET_STATISTICS_update (GST_stats,
7904 "# Validations dropped, challenge unknown",
7907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7908 "Validation response %s dropped, challenge unknown\n",
7909 GNUNET_sh2s (&tvr->challenge.value));
7910 finish_cmc_handling (cmc);
7914 /* sanity check on origin time */
7915 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7916 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7917 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7919 GNUNET_break_op (0);
7920 finish_cmc_handling (cmc);
7925 /* check signature */
7926 struct TransportValidationPS tvp =
7927 { .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7928 .purpose.size = htonl (sizeof(tvp)),
7929 .validity_duration = tvr->validity_duration,
7930 .challenge = tvr->challenge };
7934 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7937 &cmc->im.sender.public_key))
7939 GNUNET_break_op (0);
7940 finish_cmc_handling (cmc);
7945 /* validity is capped by our willingness to keep track of the
7946 validation entry and the maximum the other peer allows */
7947 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7948 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7949 tvr->validity_duration),
7950 MAX_ADDRESS_VALID_UNTIL));
7951 vs->validated_until =
7952 GNUNET_TIME_absolute_min (vs->valid_until,
7953 GNUNET_TIME_relative_to_absolute (
7954 ADDRESS_VALIDATION_LIFETIME));
7955 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7956 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7957 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7959 sizeof(vs->challenge));
7960 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7961 vs->validated_until,
7962 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7963 VALIDATION_RTT_BUFFER_FACTOR));
7964 vs->last_challenge_use =
7965 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7966 update_next_challenge_time (vs, vs->first_challenge_use);
7967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7968 "Validation response %s accepted, address valid until %s\n",
7969 GNUNET_sh2s (&tvr->challenge.value),
7970 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
7971 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7974 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7976 strlen (vs->address) + 1,
7978 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7979 &peerstore_store_validation_cb,
7981 finish_cmc_handling (cmc);
7983 /* Finally, we now possibly have a confirmed (!) working queue,
7984 update queue status (if queue still is around) */
7985 q = find_queue (&vs->pid, vs->address);
7988 GNUNET_STATISTICS_update (GST_stats,
7989 "# Queues lost at time of successful validation",
7994 q->validated_until = vs->validated_until;
7995 q->pd.aged_rtt = vs->validation_rtt;
7997 vl = lookup_virtual_link (&vs->pid);
8000 /* Link was already up, remember n is also now available and we are done */
8005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8006 "Virtual link to %s could now also direct neighbour!\n",
8007 GNUNET_i2s (&vs->pid));
8011 GNUNET_assert (n == vl->n);
8015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8016 "Creating new virtual link to %s using direct neighbour!\n",
8017 GNUNET_i2s (&vs->pid));
8018 vl = GNUNET_new (struct VirtualLink);
8019 vl->target = n->pid;
8022 vl->core_recv_window = RECV_WINDOW_SIZE;
8023 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8024 vl->visibility_task =
8025 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8026 GNUNET_break (GNUNET_YES ==
8027 GNUNET_CONTAINER_multipeermap_put (
8031 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8032 consider_sending_fc (vl);
8033 /* We lacked a confirmed connection to the target
8034 before, so tell CORE about it (finally!) */
8035 cores_send_connect_info (&n->pid);
8040 * Incoming meessage. Process the request.
8042 * @param im the send message that was received
8045 handle_incoming_msg (void *cls,
8046 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8048 struct TransportClient *tc = cls;
8049 struct CommunicatorMessageContext *cmc =
8050 GNUNET_new (struct CommunicatorMessageContext);
8054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8055 "Received message via communicator from peer %s\n",
8056 GNUNET_i2s (&im->sender));
8057 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8062 * Communicator gave us a transport address validation response. Process the
8065 * @param cls a `struct CommunicatorMessageContext` (must call
8066 * #finish_cmc_handling() when done)
8067 * @param fc the message that was received
8070 handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8072 struct CommunicatorMessageContext *cmc = cls;
8073 struct VirtualLink *vl;
8075 struct GNUNET_TIME_Absolute st;
8079 vl = lookup_virtual_link (&cmc->im.sender);
8082 GNUNET_STATISTICS_update (GST_stats,
8083 "# FC dropped: virtual link unknown",
8086 finish_cmc_handling (cmc);
8089 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8090 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8092 /* out of order, drop */
8093 GNUNET_STATISTICS_update (GST_stats,
8094 "# FC dropped: message out of order",
8097 finish_cmc_handling (cmc);
8100 seq = ntohl (fc->seq);
8101 if (seq < vl->last_fc_seq)
8103 /* Wrap-around/reset of other peer; start all counters from zero */
8104 vl->outbound_fc_window_size_used = 0;
8106 vl->last_fc_seq = seq;
8107 vl->last_fc_timestamp = st;
8108 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8109 os = GNUNET_ntohll (fc->outbound_sent);
8110 vl->incoming_fc_window_size_loss =
8111 (int64_t) (os - vl->incoming_fc_window_size_used);
8112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8113 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8114 GNUNET_i2s (&vl->target),
8116 (unsigned long long) vl->outbound_fc_window_size,
8117 (long long) vl->incoming_fc_window_size_loss);
8118 wnd = GNUNET_ntohll (fc->outbound_window_size);
8119 if ((wnd < vl->incoming_fc_window_size) ||
8120 (vl->last_outbound_window_size_received != wnd) ||
8121 (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)
8122 % FC_NO_CHANGE_REPLY_PROBABILITY))
8124 /* Consider re-sending our FC message, as clearly the
8125 other peer's idea of the window is not up-to-date */
8126 consider_sending_fc (vl);
8128 if ((wnd == vl->incoming_fc_window_size) &&
8129 (vl->last_outbound_window_size_received == wnd) &&
8130 (NULL != vl->fc_retransmit_task))
8132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8133 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8134 GNUNET_i2s (&vl->target),
8135 (unsigned long long) wnd);
8136 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8137 vl->fc_retransmit_task = NULL;
8139 vl->last_outbound_window_size_received = wnd;
8140 /* FC window likely increased, check transmission possibilities! */
8141 check_vl_transmission (vl);
8142 finish_cmc_handling (cmc);
8147 * Given an inbound message @a msg from a communicator @a cmc,
8148 * demultiplex it based on the type calling the right handler.
8150 * @param cmc context for demultiplexing
8151 * @param msg message to demultiplex
8154 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8155 const struct GNUNET_MessageHeader *msg)
8157 struct GNUNET_MQ_MessageHandler handlers[] =
8158 { GNUNET_MQ_hd_var_size (fragment_box,
8159 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8160 struct TransportFragmentBoxMessage,
8162 GNUNET_MQ_hd_var_size (reliability_box,
8163 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8164 struct TransportReliabilityBoxMessage,
8166 GNUNET_MQ_hd_var_size (reliability_ack,
8167 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8168 struct TransportReliabilityAckMessage,
8170 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8171 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8172 struct TransportBackchannelEncapsulationMessage,
8174 GNUNET_MQ_hd_var_size (dv_learn,
8175 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8176 struct TransportDVLearnMessage,
8178 GNUNET_MQ_hd_var_size (dv_box,
8179 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8180 struct TransportDVBoxMessage,
8182 GNUNET_MQ_hd_fixed_size (
8183 validation_challenge,
8184 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8185 struct TransportValidationChallengeMessage,
8187 GNUNET_MQ_hd_fixed_size (flow_control,
8188 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8189 struct TransportFlowControlMessage,
8191 GNUNET_MQ_hd_fixed_size (
8192 validation_response,
8193 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8194 struct TransportValidationResponseMessage,
8196 GNUNET_MQ_handler_end () };
8199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8200 "Handling message of type %u with %u bytes\n",
8201 (unsigned int) ntohs (msg->type),
8202 (unsigned int) ntohs (msg->size));
8203 ret = GNUNET_MQ_handle_message (handlers, msg);
8204 if (GNUNET_SYSERR == ret)
8207 GNUNET_SERVICE_client_drop (cmc->tc->client);
8211 if (GNUNET_NO == ret)
8213 /* unencapsulated 'raw' message */
8214 handle_raw_message (&cmc, msg);
8220 * New queue became available. Check message.
8222 * @param cls the client
8223 * @param aqm the send message that was sent
8226 check_add_queue_message (void *cls,
8227 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8229 struct TransportClient *tc = cls;
8231 if (CT_COMMUNICATOR != tc->type)
8234 return GNUNET_SYSERR;
8236 GNUNET_MQ_check_zero_termination (aqm);
8242 * If necessary, generates the UUID for a @a pm
8244 * @param pm pending message to generate UUID for.
8247 set_pending_message_uuid (struct PendingMessage *pm)
8249 if (pm->msg_uuid_set)
8251 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8252 pm->msg_uuid_set = GNUNET_YES;
8257 * Setup data structure waiting for acknowledgements.
8259 * @param queue queue the @a pm will be sent over
8260 * @param dvh path the message will take, may be NULL
8261 * @param pm the pending message for transmission
8262 * @return corresponding fresh pending acknowledgement
8264 static struct PendingAcknowledgement *
8265 prepare_pending_acknowledgement (struct Queue *queue,
8266 struct DistanceVectorHop *dvh,
8267 struct PendingMessage *pm)
8269 struct PendingAcknowledgement *pa;
8271 pa = GNUNET_new (struct PendingAcknowledgement);
8277 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8279 sizeof(pa->ack_uuid));
8281 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8283 &pa->ack_uuid.value,
8285 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8286 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8287 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8289 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8290 pa->transmission_time = GNUNET_TIME_absolute_get ();
8291 pa->message_size = pm->bytes_msg;
8292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8293 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8294 GNUNET_uuid2s (&pa->ack_uuid.value),
8301 * Fragment the given @a pm to the given @a mtu. Adds
8302 * additional fragments to the neighbour as well. If the
8303 * @a mtu is too small, generates and error for the @a pm
8306 * @param queue which queue to fragment for
8307 * @param dvh path the message will take, or NULL
8308 * @param pm pending message to fragment for transmission
8309 * @return new message to transmit
8311 static struct PendingMessage *
8312 fragment_message (struct Queue *queue,
8313 struct DistanceVectorHop *dvh,
8314 struct PendingMessage *pm)
8316 struct PendingAcknowledgement *pa;
8317 struct PendingMessage *ff;
8320 mtu = (0 == queue->mtu)
8321 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
8323 set_pending_message_uuid (pm);
8324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8325 "Fragmenting message %llu <%llu> to %s for MTU %u\n",
8326 (unsigned long long) pm->msg_uuid.uuid,
8328 GNUNET_i2s (&pm->vl->target),
8329 (unsigned int) mtu);
8330 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8332 /* This invariant is established in #handle_add_queue_message() */
8333 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
8335 /* select fragment for transmission, descending the tree if it has
8336 been expanded until we are at a leaf or at a fragment that is small
8340 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
8341 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
8343 ff = ff->head_frag; /* descent into fragmented fragments */
8346 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
8348 /* Did not yet calculate all fragments, calculate next fragment */
8349 struct PendingMessage *frag;
8350 struct TransportFragmentBoxMessage tfb;
8358 orig = (const char *) &ff[1];
8359 msize = ff->bytes_msg;
8362 const struct TransportFragmentBoxMessage *tfbo;
8364 tfbo = (const struct TransportFragmentBoxMessage *) orig;
8365 orig += sizeof(struct TransportFragmentBoxMessage);
8366 msize -= sizeof(struct TransportFragmentBoxMessage);
8367 xoff = ntohs (tfbo->frag_off);
8369 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
8370 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
8372 GNUNET_malloc (sizeof(struct PendingMessage)
8373 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
8374 frag->logging_uuid = logging_uuid_gen++;
8376 frag->frag_parent = ff;
8377 frag->timeout = pm->timeout;
8378 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
8379 frag->pmt = PMT_FRAGMENT_BOX;
8380 msg = (char *) &frag[1];
8381 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
8383 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
8384 tfb.ack_uuid = pa->ack_uuid;
8385 tfb.msg_uuid = pm->msg_uuid;
8386 tfb.frag_off = htons (ff->frag_off + xoff);
8387 tfb.msg_size = htons (pm->bytes_msg);
8388 memcpy (msg, &tfb, sizeof(tfb));
8389 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
8390 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
8391 ff->frag_off += fragsize;
8395 /* Move head to the tail and return it */
8396 GNUNET_CONTAINER_MDLL_remove (frag,
8397 ff->frag_parent->head_frag,
8398 ff->frag_parent->tail_frag,
8400 GNUNET_CONTAINER_MDLL_insert_tail (frag,
8401 ff->frag_parent->head_frag,
8402 ff->frag_parent->tail_frag,
8409 * Reliability-box the given @a pm. On error (can there be any), NULL
8410 * may be returned, otherwise the "replacement" for @a pm (which
8411 * should then be added to the respective neighbour's queue instead of
8412 * @a pm). If the @a pm is already fragmented or reliability boxed,
8413 * or itself an ACK, this function simply returns @a pm.
8415 * @param queue which queue to prepare transmission for
8416 * @param dvh path the message will take, or NULL
8417 * @param pm pending message to box for transmission over unreliabile queue
8418 * @return new message to transmit
8420 static struct PendingMessage *
8421 reliability_box_message (struct Queue *queue,
8422 struct DistanceVectorHop *dvh,
8423 struct PendingMessage *pm)
8425 struct TransportReliabilityBoxMessage rbox;
8426 struct PendingAcknowledgement *pa;
8427 struct PendingMessage *bpm;
8430 if (PMT_CORE != pm->pmt)
8431 return pm; /* already fragmented or reliability boxed, or control message:
8433 if (NULL != pm->bpm)
8434 return pm->bpm; /* already computed earlier: do nothing */
8435 GNUNET_assert (NULL == pm->head_frag);
8436 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
8440 client_send_response (pm);
8443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8444 "Preparing reliability box for message <%llu> to %s on queue %s\n",
8446 GNUNET_i2s (&pm->vl->target),
8448 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8450 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
8452 bpm->logging_uuid = logging_uuid_gen++;
8454 bpm->frag_parent = pm;
8455 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
8456 bpm->timeout = pm->timeout;
8457 bpm->pmt = PMT_RELIABILITY_BOX;
8458 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
8459 set_pending_message_uuid (bpm);
8460 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
8461 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
8462 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
8464 rbox.ack_uuid = pa->ack_uuid;
8465 msg = (char *) &bpm[1];
8466 memcpy (msg, &rbox, sizeof(rbox));
8467 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
8474 * Change the value of the `next_attempt` field of @a pm
8475 * to @a next_attempt and re-order @a pm in the transmission
8476 * list as required by the new timestmap.
8478 * @param pm a pending message to update
8479 * @param next_attempt timestamp to use
8482 update_pm_next_attempt (struct PendingMessage *pm,
8483 struct GNUNET_TIME_Absolute next_attempt)
8485 struct VirtualLink *vl = pm->vl;
8487 pm->next_attempt = next_attempt;
8488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8489 "Next attempt for message <%llu> set to %s\n",
8491 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
8493 if (NULL == pm->frag_parent)
8495 struct PendingMessage *pos;
8497 /* re-insert sort in neighbour list */
8498 GNUNET_CONTAINER_MDLL_remove (vl,
8499 vl->pending_msg_head,
8500 vl->pending_msg_tail,
8502 pos = vl->pending_msg_tail;
8503 while ((NULL != pos) &&
8504 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8506 GNUNET_CONTAINER_MDLL_insert_after (vl,
8507 vl->pending_msg_head,
8508 vl->pending_msg_tail,
8514 /* re-insert sort in fragment list */
8515 struct PendingMessage *fp = pm->frag_parent;
8516 struct PendingMessage *pos;
8518 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
8519 pos = fp->tail_frag;
8520 while ((NULL != pos) &&
8521 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8522 pos = pos->prev_frag;
8523 GNUNET_CONTAINER_MDLL_insert_after (frag,
8533 * Context for #select_best_pending_from_link().
8535 struct PendingMessageScoreContext
8538 * Set to the best message that was found, NULL for none.
8540 struct PendingMessage *best;
8543 * DVH that @e best should take, or NULL for direct transmission.
8545 struct DistanceVectorHop *dvh;
8548 * What is the estimated total overhead for this message?
8550 size_t real_overhead;
8553 * Number of pending messages we seriously considered this time.
8555 unsigned int consideration_counter;
8558 * Did we have to fragment?
8563 * Did we have to reliability box?
8570 * Select the best pending message from @a vl for transmission
8573 * @param sc[in,out] best message so far (NULL for none), plus scoring data
8574 * @param queue the queue that will be used for transmission
8575 * @param vl the virtual link providing the messages
8576 * @param dvh path we are currently considering, or NULL for none
8577 * @param overhead number of bytes of overhead to be expected
8578 * from DV encapsulation (0 for without DV)
8581 select_best_pending_from_link (struct PendingMessageScoreContext *sc,
8582 struct Queue *queue,
8583 struct VirtualLink *vl,
8584 struct DistanceVectorHop *dvh,
8587 struct GNUNET_TIME_Absolute now;
8589 now = GNUNET_TIME_absolute_get ();
8590 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
8593 size_t real_overhead = overhead;
8597 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
8598 continue; /* DV messages must not be DV-routed to next hop! */
8599 if (pos->next_attempt.abs_value_us > now.abs_value_us)
8600 break; /* too early for all messages, they are sorted by next_attempt */
8601 if (NULL != pos->qe)
8602 continue; /* not eligible */
8603 sc->consideration_counter++;
8604 /* determine if we have to fragment, if so add fragmentation
8607 if (((0 != queue->mtu) &&
8608 (pos->bytes_msg + real_overhead > queue->mtu)) ||
8609 (pos->bytes_msg > UINT16_MAX - sizeof(struct
8610 GNUNET_TRANSPORT_SendMessageTo))
8612 (NULL != pos->head_frag /* fragments already exist, should
8613 respect that even if MTU is 0 for
8617 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
8619 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
8620 header without the ACK UUID when using a *reliable* channel! */
8622 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
8624 /* determine if we have to reliability-box, if so add reliability box
8627 if ((GNUNET_NO == frag) &&
8628 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
8629 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
8632 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
8635 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
8636 message would beat it! */
8637 if (NULL != sc->best)
8639 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
8640 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
8641 experimentally validated. There may be some huge potential for
8642 improvement here. Also, we right now only compare how well the
8643 given message fits _this_ queue, and do not consider how well other
8644 queues might suit the message. Taking other queues into consideration
8645 may further improve the result, but could also be expensive
8646 in terms of CPU time. */
8647 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
8648 long long pm_score = frag * 40 + relb * 20 + real_overhead;
8649 long long time_delta =
8650 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
8653 /* "time_delta" considers which message has been 'ready' for transmission
8654 for longer, if a message has a preference for low latency, increase
8655 the weight of the time_delta by 10x if it is favorable for that message */
8656 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8657 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
8658 time_delta *= 10; /* increase weight (always, both are low latency) */
8659 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8662 10; /* increase weight, favors 'pos', which is low latency */
8663 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8666 10; /* increase weight, favors 'sc->best', which is low latency */
8667 if (0 != queue->mtu)
8669 /* Grant bonus if we are bellow MTU, larger bonus the closer we will
8671 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
8672 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
8673 if (queue->mtu > real_overhead + pos->bytes_msg)
8674 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
8676 if (sc_score + time_delta > pm_score)
8677 continue; /* sc_score larger, keep sc->best */
8688 * Function to call to further operate on the now DV encapsulated
8689 * message @a hdr, forwarding it via @a next_hop under respect of
8692 * @param cls a `struct PendingMessageScoreContext`
8693 * @param next_hop next hop of the DV path
8694 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
8695 * @param options options of the original message
8698 extract_box_cb (void *cls,
8699 struct Neighbour *next_hop,
8700 const struct GNUNET_MessageHeader *hdr,
8701 enum RouteMessageOptions options)
8703 struct PendingMessageScoreContext *sc = cls;
8704 struct PendingMessage *pm = sc->best;
8705 struct PendingMessage *bpm;
8706 uint16_t bsize = ntohs (hdr->size);
8708 GNUNET_assert (NULL == pm->bpm);
8709 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
8710 bpm->logging_uuid = logging_uuid_gen++;
8711 bpm->pmt = PMT_DV_BOX;
8712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8713 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
8716 GNUNET_i2s (&next_hop->pid));
8717 memcpy (&bpm[1], hdr, bsize);
8723 * We believe we are ready to transmit a `struct PendingMessage` on a
8724 * queue, the big question is which one! We need to see if there is
8725 * one pending that is allowed by flow control and congestion control
8726 * and (ideally) matches our queue's performance profile.
8728 * If such a message is found, we give the message to the communicator
8729 * for transmission (updating the tracker, and re-scheduling ourselves
8732 * If no such message is found, the queue's `idle` field must be set
8735 * @param cls the `struct Queue` to process transmissions for
8738 transmit_on_queue (void *cls)
8740 struct Queue *queue = cls;
8741 struct Neighbour *n = queue->neighbour;
8742 struct PendingMessageScoreContext sc;
8743 struct PendingMessage *pm;
8745 queue->transmit_task = NULL;
8748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8749 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
8750 GNUNET_i2s (&n->pid),
8752 queue->idle = GNUNET_YES;
8755 memset (&sc, 0, sizeof(sc));
8756 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
8757 if (NULL == sc.best)
8759 /* Also look at DVH that have the n as first hop! */
8760 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
8761 dvh = dvh->next_neighbour)
8763 select_best_pending_from_link (&sc,
8767 sizeof(struct GNUNET_PeerIdentity)
8768 * (1 + dvh->distance)
8769 + sizeof(struct TransportDVBoxMessage)
8770 + sizeof(struct TransportDVBoxPayloadP));
8773 if (NULL == sc.best)
8775 /* no message pending, nothing to do here! */
8776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8777 "No pending messages, queue `%s' to %s now idle\n",
8779 GNUNET_i2s (&n->pid));
8780 queue->idle = GNUNET_YES;
8784 /* Given selection in `sc`, do transmission */
8788 GNUNET_assert (PMT_DV_BOX != pm->pmt);
8789 if (NULL != sc.best->bpm)
8791 /* We did this boxing before, but possibly for a different path!
8792 Discard old DV box! OPTIMIZE-ME: we might want to check if
8793 it is the same and then not re-build the message... */
8794 free_pending_message (sc.best->bpm);
8795 sc.best->bpm = NULL;
8797 encapsulate_for_dv (sc.dvh->dv,
8800 (const struct GNUNET_MessageHeader *) &sc.best[1],
8804 GNUNET_assert (NULL != sc.best->bpm);
8807 if (GNUNET_YES == sc.frag)
8809 pm = fragment_message (queue, sc.dvh, pm);
8812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8813 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
8815 GNUNET_i2s (&n->pid),
8816 sc.best->logging_uuid);
8817 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8821 else if (GNUNET_YES == sc.relb)
8823 pm = reliability_box_message (queue, sc.dvh, pm);
8826 /* Reliability boxing failed, try next message... */
8828 GNUNET_ERROR_TYPE_DEBUG,
8829 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
8831 GNUNET_i2s (&n->pid),
8832 sc.best->logging_uuid);
8833 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8838 /* Pass 'pm' for transission to the communicator */
8840 GNUNET_ERROR_TYPE_DEBUG,
8841 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
8844 GNUNET_i2s (&n->pid),
8845 sc.consideration_counter);
8847 /* Flow control: increment amount of traffic sent; if we are routing
8848 via DV (and thus the ultimate target of the pending message is for
8849 a different virtual link than the one of the queue), then we need
8850 to use up not only the window of the direct link but also the
8851 flow control window for the DV link! */
8852 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
8854 if (pm->vl != queue->neighbour->vl)
8856 /* If the virtual link of the queue differs, this better be distance
8858 GNUNET_assert (NULL != sc.dvh);
8859 /* If we do distance vector routing, we better not do this for a
8860 message that was itself DV-routed */
8861 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
8862 /* We use the size of the unboxed message here, to avoid counting
8863 the DV-Box header which is eaten up on the way by intermediaries */
8864 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
8868 GNUNET_assert (NULL == sc.dvh);
8871 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
8873 /* Check if this transmission somehow conclusively finished handing 'pm'
8874 even without any explicit ACKs */
8875 if ((PMT_CORE == pm->pmt) ||
8876 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
8878 completed_pending_message (pm);
8882 /* Message not finished, waiting for acknowledgement.
8883 Update time by which we might retransmit 's' based on queue
8884 characteristics (i.e. RTT); it takes one RTT for the message to
8885 arrive and the ACK to come back in the best case; but the other
8886 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
8889 OPTIMIZE: Note that in the future this heuristic should likely
8890 be improved further (measure RTT stability, consider message
8891 urgency and size when delaying ACKs, etc.) */
8892 update_pm_next_attempt (pm,
8893 GNUNET_TIME_relative_to_absolute (
8894 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
8897 /* finally, re-schedule queue transmission task itself */
8898 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8903 * Queue to a peer went down. Process the request.
8905 * @param cls the client
8906 * @param dqm the send message that was sent
8909 handle_del_queue_message (void *cls,
8910 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
8912 struct TransportClient *tc = cls;
8914 if (CT_COMMUNICATOR != tc->type)
8917 GNUNET_SERVICE_client_drop (tc->client);
8920 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8921 queue = queue->next_client)
8923 struct Neighbour *neighbour = queue->neighbour;
8925 if ((dqm->qid != queue->qid) ||
8926 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
8928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8929 "Dropped queue %s to peer %s\n",
8931 GNUNET_i2s (&neighbour->pid));
8933 GNUNET_SERVICE_client_continue (tc->client);
8937 GNUNET_SERVICE_client_drop (tc->client);
8942 * Message was transmitted. Process the request.
8944 * @param cls the client
8945 * @param sma the send message that was sent
8948 handle_send_message_ack (void *cls,
8949 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
8951 struct TransportClient *tc = cls;
8952 struct QueueEntry *qe;
8953 struct PendingMessage *pm;
8955 if (CT_COMMUNICATOR != tc->type)
8958 GNUNET_SERVICE_client_drop (tc->client);
8962 /* find our queue entry matching the ACK */
8964 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8965 queue = queue->next_client)
8967 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
8969 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
8972 if (qep->mid != sma->mid)
8981 /* this should never happen */
8983 GNUNET_SERVICE_client_drop (tc->client);
8986 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
8987 qe->queue->queue_tail,
8989 qe->queue->queue_length--;
8990 tc->details.communicator.total_queue_length--;
8991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8992 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
8994 GNUNET_i2s (&qe->queue->neighbour->pid),
8995 qe->queue->queue_length,
8996 tc->details.communicator.total_queue_length);
8997 GNUNET_SERVICE_client_continue (tc->client);
8999 /* if applicable, resume transmissions that waited on ACK */
9000 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
9001 tc->details.communicator.total_queue_length)
9003 /* Communicator dropped below threshold, resume all queues
9004 incident with this client! */
9005 GNUNET_STATISTICS_update (
9007 "# Transmission throttled due to communicator queue limit",
9010 for (struct Queue *queue = tc->details.communicator.queue_head;
9012 queue = queue->next_client)
9013 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9015 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9017 /* queue dropped below threshold; only resume this one queue */
9018 GNUNET_STATISTICS_update (GST_stats,
9019 "# Transmission throttled due to queue queue limit",
9022 schedule_transmit_on_queue (qe->queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9025 if (NULL != (pm = qe->pm))
9027 struct VirtualLink *vl;
9029 GNUNET_assert (qe == pm->qe);
9031 /* If waiting for this communicator may have blocked transmission
9032 of pm on other queues for this neighbour, force schedule
9033 transmit on queue for queues of the neighbour */
9035 if (vl->pending_msg_head == pm)
9036 check_vl_transmission (vl);
9043 * Iterator telling new MONITOR client about all existing
9046 * @param cls the new `struct TransportClient`
9047 * @param pid a connected peer
9048 * @param value the `struct Neighbour` with more information
9049 * @return #GNUNET_OK (continue to iterate)
9052 notify_client_queues (void *cls,
9053 const struct GNUNET_PeerIdentity *pid,
9056 struct TransportClient *tc = cls;
9057 struct Neighbour *neighbour = value;
9059 GNUNET_assert (CT_MONITOR == tc->type);
9060 for (struct Queue *q = neighbour->queue_head; NULL != q;
9061 q = q->next_neighbour)
9063 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
9065 .num_msg_pending = q->num_msg_pending,
9066 .num_bytes_pending = q->num_bytes_pending };
9068 notify_monitor (tc, pid, q->address, q->nt, &me);
9075 * Initialize a monitor client.
9077 * @param cls the client
9078 * @param start the start message that was sent
9081 handle_monitor_start (void *cls,
9082 const struct GNUNET_TRANSPORT_MonitorStart *start)
9084 struct TransportClient *tc = cls;
9086 if (CT_NONE != tc->type)
9089 GNUNET_SERVICE_client_drop (tc->client);
9092 tc->type = CT_MONITOR;
9093 tc->details.monitor.peer = start->peer;
9094 tc->details.monitor.one_shot = ntohl (start->one_shot);
9095 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
9096 GNUNET_SERVICE_client_mark_monitor (tc->client);
9097 GNUNET_SERVICE_client_continue (tc->client);
9102 * Find transport client providing communication service
9103 * for the protocol @a prefix.
9105 * @param prefix communicator name
9106 * @return NULL if no such transport client is available
9108 static struct TransportClient *
9109 lookup_communicator (const char *prefix)
9111 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
9113 if (CT_COMMUNICATOR != tc->type)
9115 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
9119 GNUNET_ERROR_TYPE_WARNING,
9120 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
9127 * Signature of a function called with a communicator @a address of a peer
9128 * @a pid that an application wants us to connect to.
9130 * @param pid target peer
9131 * @param address the address to try
9134 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
9136 static uint32_t idgen;
9137 struct TransportClient *tc;
9139 struct GNUNET_TRANSPORT_CreateQueue *cqm;
9140 struct GNUNET_MQ_Envelope *env;
9143 prefix = GNUNET_HELLO_address_to_prefix (address);
9146 GNUNET_break (0); /* We got an invalid address!? */
9149 tc = lookup_communicator (prefix);
9152 GNUNET_STATISTICS_update (GST_stats,
9153 "# Suggestions ignored due to missing communicator",
9156 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9157 "Cannot connect to %s at `%s', no matching communicator present\n",
9160 GNUNET_free (prefix);
9163 /* forward suggestion for queue creation to communicator */
9164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9165 "Request #%u for `%s' communicator to create queue to `%s'\n",
9166 (unsigned int) idgen,
9169 GNUNET_free (prefix);
9170 alen = strlen (address) + 1;
9172 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
9173 cqm->request_id = htonl (idgen++);
9174 cqm->receiver = *pid;
9175 memcpy (&cqm[1], address, alen);
9176 GNUNET_MQ_send (tc->mq, env);
9181 * The queue @a q (which matches the peer and address in @a vs) is
9182 * ready for queueing. We should now queue the validation request.
9184 * @param q queue to send on
9185 * @param vs state to derive validation challenge from
9188 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
9190 struct TransportValidationChallengeMessage tvc;
9192 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
9194 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
9195 tvc.header.size = htons (sizeof(tvc));
9196 tvc.reserved = htonl (0);
9197 tvc.challenge = vs->challenge;
9198 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
9199 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9200 "Sending address validation challenge %s to %s\n",
9201 GNUNET_sh2s (&tvc.challenge.value),
9202 GNUNET_i2s (&q->neighbour->pid));
9203 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
9208 * Task run periodically to validate some address based on #validation_heap.
9213 validation_start_cb (void *cls)
9215 struct ValidationState *vs;
9219 validation_task = NULL;
9220 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9221 /* drop validations past their expiration */
9224 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
9226 free_validation_state (vs);
9227 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9231 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9232 "Address validation task not scheduled anymore, nothing to do\n");
9233 return; /* woopsie, no more addresses known, should only
9234 happen if we're really a lonely peer */
9236 q = find_queue (&vs->pid, vs->address);
9239 vs->awaiting_queue = GNUNET_YES;
9240 suggest_to_connect (&vs->pid, vs->address);
9243 validation_transmit_on_queue (q, vs);
9244 /* Finally, reschedule next attempt */
9245 vs->challenge_backoff =
9246 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
9247 MAX_VALIDATION_CHALLENGE_FREQ);
9248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9249 "Address validation task will run again in %s\n",
9250 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
9252 update_next_challenge_time (vs,
9253 GNUNET_TIME_relative_to_absolute (
9254 vs->challenge_backoff));
9259 * Closure for #check_connection_quality.
9261 struct QueueQualityContext
9264 * Set to the @e k'th queue encountered.
9269 * Set to the number of quality queues encountered.
9271 unsigned int quality_count;
9274 * Set to the total number of queues encountered.
9276 unsigned int num_queues;
9279 * Decremented for each queue, for selection of the
9280 * k-th queue in @e q.
9287 * Check whether any queue to the given neighbour is
9288 * of a good "quality" and if so, increment the counter.
9289 * Also counts the total number of queues, and returns
9290 * the k-th queue found.
9292 * @param cls a `struct QueueQualityContext *` with counters
9293 * @param pid peer this is about
9294 * @param value a `struct Neighbour`
9295 * @return #GNUNET_OK (continue to iterate)
9298 check_connection_quality (void *cls,
9299 const struct GNUNET_PeerIdentity *pid,
9302 struct QueueQualityContext *ctx = cls;
9303 struct Neighbour *n = value;
9308 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9313 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
9314 statistics and consider those as well here? */
9315 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
9316 do_inc = GNUNET_YES;
9318 if (GNUNET_YES == do_inc)
9319 ctx->quality_count++;
9325 * Task run when we CONSIDER initiating a DV learn
9326 * process. We first check that sending out a message is
9327 * even possible (queues exist), then that it is desirable
9328 * (if not, reschedule the task for later), and finally
9329 * we may then begin the job. If there are too many
9330 * entries in the #dvlearn_map, we purge the oldest entry
9336 start_dv_learn (void *cls)
9338 struct LearnLaunchEntry *lle;
9339 struct QueueQualityContext qqc;
9340 struct TransportDVLearnMessage dvl;
9343 dvlearn_task = NULL;
9344 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
9345 return; /* lost all connectivity, cannot do learning */
9346 qqc.quality_count = 0;
9348 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9349 &check_connection_quality,
9351 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
9353 struct GNUNET_TIME_Relative delay;
9354 unsigned int factor;
9356 /* scale our retries by how far we are above the threshold */
9357 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
9358 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
9359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9360 "At connection quality %u, will launch DV learn in %s\n",
9362 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
9363 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
9366 /* remove old entries in #dvlearn_map if it has grown too big */
9367 while (MAX_DV_LEARN_PENDING >=
9368 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
9371 GNUNET_assert (GNUNET_YES ==
9372 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
9373 &lle->challenge.value,
9375 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9378 /* setup data structure for learning */
9379 lle = GNUNET_new (struct LearnLaunchEntry);
9380 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9382 sizeof(lle->challenge));
9383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9384 "Starting launch DV learn with challenge %s\n",
9385 GNUNET_sh2s (&lle->challenge.value));
9386 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
9387 GNUNET_break (GNUNET_YES ==
9388 GNUNET_CONTAINER_multishortmap_put (
9390 &lle->challenge.value,
9392 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9393 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
9394 dvl.header.size = htons (sizeof(dvl));
9395 dvl.num_hops = htons (0);
9396 dvl.bidirectional = htons (0);
9397 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
9398 dvl.monotonic_time =
9399 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
9401 struct DvInitPS dvip = { .purpose.purpose = htonl (
9402 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
9403 .purpose.size = htonl (sizeof(dvip)),
9404 .monotonic_time = dvl.monotonic_time,
9405 .challenge = lle->challenge };
9407 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9411 dvl.initiator = GST_my_identity;
9412 dvl.challenge = lle->challenge;
9414 qqc.quality_count = 0;
9415 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
9418 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9419 &check_connection_quality,
9421 GNUNET_assert (NULL != qqc.q);
9423 /* Do this as close to transmission time as possible! */
9424 lle->launch_time = GNUNET_TIME_absolute_get ();
9426 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
9427 /* reschedule this job, randomizing the time it runs (but no
9429 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
9430 DV_LEARN_BASE_FREQUENCY),
9437 * A new queue has been created, check if any address validation
9438 * requests have been waiting for it.
9440 * @param cls a `struct Queue`
9441 * @param pid peer concerned (unused)
9442 * @param value a `struct ValidationState`
9443 * @return #GNUNET_NO if a match was found and we can stop looking
9446 check_validation_request_pending (void *cls,
9447 const struct GNUNET_PeerIdentity *pid,
9450 struct Queue *q = cls;
9451 struct ValidationState *vs = value;
9454 if ((GNUNET_YES == vs->awaiting_queue) &&
9455 (0 == strcmp (vs->address, q->address)))
9457 vs->awaiting_queue = GNUNET_NO;
9458 validation_transmit_on_queue (q, vs);
9466 * Function called with the monotonic time of a DV initiator
9467 * by PEERSTORE. Updates the time.
9469 * @param cls a `struct Neighbour`
9470 * @param record the information found, NULL for the last call
9471 * @param emsg error message
9474 neighbour_dv_monotime_cb (void *cls,
9475 const struct GNUNET_PEERSTORE_Record *record,
9478 struct Neighbour *n = cls;
9479 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9484 /* we're done with #neighbour_dv_monotime_cb() invocations,
9485 continue normal processing */
9487 n->dv_monotime_available = GNUNET_YES;
9490 if (sizeof(*mtbe) != record->value_size)
9495 mtbe = record->value;
9496 n->last_dv_learn_monotime =
9497 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
9498 GNUNET_TIME_absolute_ntoh (*mtbe));
9503 * New queue became available. Process the request.
9505 * @param cls the client
9506 * @param aqm the send message that was sent
9509 handle_add_queue_message (void *cls,
9510 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9512 struct TransportClient *tc = cls;
9513 struct Queue *queue;
9514 struct Neighbour *neighbour;
9518 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
9520 /* MTU so small as to be useless for transmissions,
9521 required for #fragment_message()! */
9522 GNUNET_break_op (0);
9523 GNUNET_SERVICE_client_drop (tc->client);
9526 neighbour = lookup_neighbour (&aqm->receiver);
9527 if (NULL == neighbour)
9529 neighbour = GNUNET_new (struct Neighbour);
9530 neighbour->pid = aqm->receiver;
9531 GNUNET_assert (GNUNET_OK ==
9532 GNUNET_CONTAINER_multipeermap_put (
9536 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9538 GNUNET_PEERSTORE_iterate (peerstore,
9541 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
9542 &neighbour_dv_monotime_cb,
9545 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
9546 addr = (const char *) &aqm[1];
9547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9548 "New queue %s to %s available with QID %llu\n",
9550 GNUNET_i2s (&aqm->receiver),
9551 (unsigned long long) aqm->qid);
9552 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
9554 queue->address = (const char *) &queue[1];
9555 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
9556 queue->qid = aqm->qid;
9557 queue->mtu = ntohl (aqm->mtu);
9558 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
9559 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
9560 queue->neighbour = neighbour;
9561 queue->idle = GNUNET_YES;
9562 memcpy (&queue[1], addr, addr_len);
9563 /* notify monitors about new queue */
9565 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
9567 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
9569 GNUNET_CONTAINER_MDLL_insert (neighbour,
9570 neighbour->queue_head,
9571 neighbour->queue_tail,
9573 GNUNET_CONTAINER_MDLL_insert (client,
9574 tc->details.communicator.queue_head,
9575 tc->details.communicator.queue_tail,
9577 /* check if valdiations are waiting for the queue */
9579 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9581 &check_validation_request_pending,
9583 /* look for traffic for this queue */
9584 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9585 /* might be our first queue, try launching DV learning */
9586 if (NULL == dvlearn_task)
9587 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
9588 GNUNET_SERVICE_client_continue (tc->client);
9593 * Communicator tells us that our request to create a queue "worked", that
9594 * is setting up the queue is now in process.
9596 * @param cls the `struct TransportClient`
9597 * @param cqr confirmation message
9600 handle_queue_create_ok (void *cls,
9601 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9603 struct TransportClient *tc = cls;
9605 if (CT_COMMUNICATOR != tc->type)
9608 GNUNET_SERVICE_client_drop (tc->client);
9611 GNUNET_STATISTICS_update (GST_stats,
9612 "# Suggestions succeeded at communicator",
9615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9616 "Request #%u for communicator to create queue succeeded\n",
9617 (unsigned int) ntohs (cqr->request_id));
9618 GNUNET_SERVICE_client_continue (tc->client);
9623 * Communicator tells us that our request to create a queue failed. This
9624 * usually indicates that the provided address is simply invalid or that the
9625 * communicator's resources are exhausted.
9627 * @param cls the `struct TransportClient`
9628 * @param cqr failure message
9631 handle_queue_create_fail (
9633 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9635 struct TransportClient *tc = cls;
9637 if (CT_COMMUNICATOR != tc->type)
9640 GNUNET_SERVICE_client_drop (tc->client);
9643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9644 "Request #%u for communicator to create queue failed\n",
9645 (unsigned int) ntohs (cqr->request_id));
9646 GNUNET_STATISTICS_update (GST_stats,
9647 "# Suggestions failed in queue creation at communicator",
9650 GNUNET_SERVICE_client_continue (tc->client);
9655 * We have received a `struct ExpressPreferenceMessage` from an application
9658 * @param cls handle to the client
9659 * @param msg the start message
9662 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
9664 struct TransportClient *tc = cls;
9665 struct PeerRequest *pr;
9667 if (CT_APPLICATION != tc->type)
9670 GNUNET_SERVICE_client_drop (tc->client);
9673 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
9678 GNUNET_SERVICE_client_drop (tc->client);
9681 (void) stop_peer_request (tc, &pr->pid, pr);
9682 GNUNET_SERVICE_client_continue (tc->client);
9687 * Function called by PEERSTORE for each matching record.
9689 * @param cls closure, a `struct PeerRequest`
9690 * @param record peerstore record information
9691 * @param emsg error message, or NULL if no errors
9694 handle_hello_for_client (void *cls,
9695 const struct GNUNET_PEERSTORE_Record *record,
9698 struct PeerRequest *pr = cls;
9703 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9704 "Got failure from PEERSTORE: %s\n",
9708 val = record->value;
9709 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
9714 start_address_validation (&pr->pid, (const char *) record->value);
9719 * We have received a `struct ExpressPreferenceMessage` from an application
9722 * @param cls handle to the client
9723 * @param msg the start message
9726 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9728 struct TransportClient *tc = cls;
9729 struct PeerRequest *pr;
9731 if (CT_NONE == tc->type)
9733 tc->type = CT_APPLICATION;
9734 tc->details.application.requests =
9735 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9737 if (CT_APPLICATION != tc->type)
9740 GNUNET_SERVICE_client_drop (tc->client);
9743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9744 "Client suggested we talk to %s with preference %d at rate %u\n",
9745 GNUNET_i2s (&msg->peer),
9746 (int) ntohl (msg->pk),
9747 (int) ntohl (msg->bw.value__));
9748 pr = GNUNET_new (struct PeerRequest);
9750 pr->pid = msg->peer;
9752 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
9753 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
9754 tc->details.application.requests,
9757 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
9761 GNUNET_SERVICE_client_drop (tc->client);
9764 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
9767 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9768 &handle_hello_for_client,
9770 GNUNET_SERVICE_client_continue (tc->client);
9775 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
9778 * @param cls a `struct TransportClient *`
9779 * @param m message to verify
9780 * @return #GNUNET_OK on success
9783 check_request_hello_validation (void *cls,
9784 const struct RequestHelloValidationMessage *m)
9787 GNUNET_MQ_check_zero_termination (m);
9793 * A client encountered an address of another peer. Consider validating it,
9794 * and if validation succeeds, persist it to PEERSTORE.
9796 * @param cls a `struct TransportClient *`
9797 * @param m message to verify
9800 handle_request_hello_validation (void *cls,
9801 const struct RequestHelloValidationMessage *m)
9803 struct TransportClient *tc = cls;
9805 start_address_validation (&m->peer, (const char *) &m[1]);
9806 GNUNET_SERVICE_client_continue (tc->client);
9811 * Free neighbour entry.
9815 * @param value a `struct Neighbour`
9816 * @return #GNUNET_OK (always)
9819 free_neighbour_cb (void *cls,
9820 const struct GNUNET_PeerIdentity *pid,
9823 struct Neighbour *neighbour = value;
9827 GNUNET_break (0); // should this ever happen?
9828 free_neighbour (neighbour);
9835 * Free DV route entry.
9839 * @param value a `struct DistanceVector`
9840 * @return #GNUNET_OK (always)
9843 free_dv_routes_cb (void *cls,
9844 const struct GNUNET_PeerIdentity *pid,
9847 struct DistanceVector *dv = value;
9858 * Free validation state.
9862 * @param value a `struct ValidationState`
9863 * @return #GNUNET_OK (always)
9866 free_validation_state_cb (void *cls,
9867 const struct GNUNET_PeerIdentity *pid,
9870 struct ValidationState *vs = value;
9874 free_validation_state (vs);
9880 * Free pending acknowledgement.
9884 * @param value a `struct PendingAcknowledgement`
9885 * @return #GNUNET_OK (always)
9888 free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
9890 struct PendingAcknowledgement *pa = value;
9894 free_pending_acknowledgement (pa);
9900 * Free acknowledgement cummulator.
9904 * @param value a `struct AcknowledgementCummulator`
9905 * @return #GNUNET_OK (always)
9908 free_ack_cummulator_cb (void *cls,
9909 const struct GNUNET_PeerIdentity *pid,
9912 struct AcknowledgementCummulator *ac = value;
9922 * Function called when the service shuts down. Unloads our plugins
9923 * and cancels pending validations.
9925 * @param cls closure, unused
9928 do_shutdown (void *cls)
9930 struct LearnLaunchEntry *lle;
9934 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9935 if (NULL != peerstore)
9937 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9940 if (NULL != GST_stats)
9942 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9945 if (NULL != GST_my_private_key)
9947 GNUNET_free (GST_my_private_key);
9948 GST_my_private_key = NULL;
9950 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9951 &free_ack_cummulator_cb,
9953 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9954 ack_cummulators = NULL;
9955 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
9956 &free_pending_ack_cb,
9958 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
9959 pending_acks = NULL;
9960 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9961 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9963 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9964 GNUNET_CONTAINER_multipeermap_destroy (links);
9966 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9967 &free_backtalker_cb,
9969 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9971 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9972 &free_validation_state_cb,
9974 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9975 validation_map = NULL;
9976 while (NULL != ir_head)
9977 free_incoming_request (ir_head);
9978 GNUNET_assert (0 == ir_total);
9979 while (NULL != (lle = lle_head))
9981 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9984 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
9986 GNUNET_CONTAINER_heap_destroy (validation_heap);
9987 validation_heap = NULL;
9988 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
9989 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
9995 * Initiate transport service.
9997 * @param cls closure
9998 * @param c configuration to use
9999 * @param service the initialized service
10003 const struct GNUNET_CONFIGURATION_Handle *c,
10004 struct GNUNET_SERVICE_Handle *service)
10008 /* setup globals */
10009 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
10011 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10012 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
10013 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
10014 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10015 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
10016 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10017 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
10019 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10021 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
10022 GST_my_private_key =
10023 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
10024 if (NULL == GST_my_private_key)
10027 GNUNET_ERROR_TYPE_ERROR,
10029 "Transport service is lacking key configuration settings. Exiting.\n"));
10030 GNUNET_SCHEDULER_shutdown ();
10033 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
10034 &GST_my_identity.public_key);
10035 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10036 "My identity is `%s'\n",
10037 GNUNET_i2s_full (&GST_my_identity));
10038 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
10039 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
10040 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
10041 if (NULL == peerstore)
10044 GNUNET_SCHEDULER_shutdown ();
10051 * Define "main" method using service macro.
10053 GNUNET_SERVICE_MAIN (
10055 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
10057 &client_connect_cb,
10058 &client_disconnect_cb,
10060 /* communication with applications */
10061 GNUNET_MQ_hd_fixed_size (suggest,
10062 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
10063 struct ExpressPreferenceMessage,
10065 GNUNET_MQ_hd_fixed_size (suggest_cancel,
10066 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
10067 struct ExpressPreferenceMessage,
10069 GNUNET_MQ_hd_var_size (request_hello_validation,
10070 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
10071 struct RequestHelloValidationMessage,
10073 /* communication with core */
10074 GNUNET_MQ_hd_fixed_size (client_start,
10075 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
10076 struct StartMessage,
10078 GNUNET_MQ_hd_var_size (client_send,
10079 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
10080 struct OutboundMessage,
10082 GNUNET_MQ_hd_fixed_size (client_recv_ok,
10083 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
10084 struct RecvOkMessage,
10086 /* communication with communicators */
10087 GNUNET_MQ_hd_var_size (communicator_available,
10088 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
10089 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
10091 GNUNET_MQ_hd_var_size (communicator_backchannel,
10092 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
10093 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
10095 GNUNET_MQ_hd_var_size (add_address,
10096 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
10097 struct GNUNET_TRANSPORT_AddAddressMessage,
10099 GNUNET_MQ_hd_fixed_size (del_address,
10100 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
10101 struct GNUNET_TRANSPORT_DelAddressMessage,
10103 GNUNET_MQ_hd_var_size (incoming_msg,
10104 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
10105 struct GNUNET_TRANSPORT_IncomingMessage,
10107 GNUNET_MQ_hd_fixed_size (queue_create_ok,
10108 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
10109 struct GNUNET_TRANSPORT_CreateQueueResponse,
10111 GNUNET_MQ_hd_fixed_size (queue_create_fail,
10112 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
10113 struct GNUNET_TRANSPORT_CreateQueueResponse,
10115 GNUNET_MQ_hd_var_size (add_queue_message,
10116 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
10117 struct GNUNET_TRANSPORT_AddQueueMessage,
10119 GNUNET_MQ_hd_fixed_size (del_queue_message,
10120 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
10121 struct GNUNET_TRANSPORT_DelQueueMessage,
10123 GNUNET_MQ_hd_fixed_size (send_message_ack,
10124 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
10125 struct GNUNET_TRANSPORT_SendMessageToAck,
10127 /* communication with monitors */
10128 GNUNET_MQ_hd_fixed_size (monitor_start,
10129 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
10130 struct GNUNET_TRANSPORT_MonitorStart,
10132 GNUNET_MQ_handler_end ());
10135 /* end of file gnunet-service-transport.c */