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_CRYPTO_ecdhe_key_create (&dv->private_key);
4134 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4135 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4136 ec.purpose.size = htonl (sizeof(ec));
4137 ec.target = dv->target;
4138 ec.ephemeral_key = dv->ephemeral_key;
4139 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4146 * Send the message @a payload on @a queue.
4148 * @param queue the queue to use for transmission
4149 * @param pm pending message to update once transmission is done, may be NULL!
4150 * @param payload the payload to send (encapsulated in a
4151 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4152 * @param payload_size number of bytes in @a payload
4155 queue_send_msg (struct Queue *queue,
4156 struct PendingMessage *pm,
4157 const void *payload,
4158 size_t payload_size)
4160 struct Neighbour *n = queue->neighbour;
4161 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4162 struct GNUNET_MQ_Envelope *env;
4164 queue->idle = GNUNET_NO;
4166 GNUNET_ERROR_TYPE_DEBUG,
4167 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4168 (unsigned int) payload_size,
4169 (NULL == pm) ? 0 : pm->logging_uuid,
4170 (unsigned long long) queue->qid,
4171 GNUNET_i2s (&queue->neighbour->pid));
4172 env = GNUNET_MQ_msg_extra (smt,
4174 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4175 smt->qid = queue->qid;
4176 smt->mid = queue->mid_gen;
4177 smt->receiver = n->pid;
4178 memcpy (&smt[1], payload, payload_size);
4180 /* Pass the env to the communicator of queue for transmission. */
4181 struct QueueEntry *qe;
4183 qe = GNUNET_new (struct QueueEntry);
4184 qe->mid = queue->mid_gen++;
4189 GNUNET_assert (NULL == pm->qe);
4192 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4193 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4194 queue->queue_length++;
4195 queue->tc->details.communicator.total_queue_length++;
4196 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4197 queue->tc->details.communicator.total_queue_length)
4198 queue->idle = GNUNET_NO;
4199 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4200 queue->idle = GNUNET_NO;
4201 GNUNET_MQ_send (queue->tc->mq, env);
4207 * Pick a queue of @a n under constraints @a options and schedule
4208 * transmission of @a hdr.
4210 * @param n neighbour to send to
4211 * @param hdr message to send as payload
4212 * @param options whether queues must be confirmed or not,
4213 * and whether we may pick multiple (2) queues
4214 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4216 static struct GNUNET_TIME_Relative
4217 route_via_neighbour (const struct Neighbour *n,
4218 const struct GNUNET_MessageHeader *hdr,
4219 enum RouteMessageOptions options)
4221 struct GNUNET_TIME_Absolute now;
4222 unsigned int candidates;
4225 struct GNUNET_TIME_Relative rtt;
4227 /* Pick one or two 'random' queues from n (under constraints of options) */
4228 now = GNUNET_TIME_absolute_get ();
4229 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4230 weight in the future; weight could be assigned by observed
4231 bandwidth (note: not sure if we should do this for this type
4232 of control traffic though). */
4234 for (struct Queue *pos = n->queue_head; NULL != pos;
4235 pos = pos->next_neighbour)
4237 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4238 (pos->validated_until.abs_value_us > now.abs_value_us))
4241 if (0 == candidates)
4243 /* This can happen rarely if the last confirmed queue timed
4244 out just as we were beginning to process this message. */
4245 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4246 "Could not route message of type %u to %s: no valid queue\n",
4248 GNUNET_i2s (&n->pid));
4249 GNUNET_STATISTICS_update (GST_stats,
4250 "# route selection failed (all no valid queue)",
4253 return GNUNET_TIME_UNIT_FOREVER_REL;
4256 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4257 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4258 if (0 == (options & RMO_REDUNDANT))
4259 sel2 = candidates; /* picks none! */
4261 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4263 for (struct Queue *pos = n->queue_head; NULL != pos;
4264 pos = pos->next_neighbour)
4266 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4267 (pos->validated_until.abs_value_us > now.abs_value_us))
4269 if ((sel1 == candidates) || (sel2 == candidates))
4271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4272 "Routing message of type %u to %s using %s (#%u)\n",
4274 GNUNET_i2s (&n->pid),
4276 (sel1 == candidates) ? 1 : 2);
4277 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4278 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4288 * Structure of the key material used to encrypt backchannel messages.
4293 * State of our block cipher.
4295 gcry_cipher_hd_t cipher;
4298 * Actual key material.
4303 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4305 struct GNUNET_CRYPTO_AuthKey hmac_key;
4308 * Symmetric key to use for encryption.
4310 char aes_key[256 / 8];
4313 * Counter value to use during setup.
4315 char aes_ctr[128 / 8];
4321 * Given the key material in @a km and the initialization vector
4322 * @a iv, setup the key material for the backchannel in @a key.
4324 * @param km raw master secret
4325 * @param iv initialization vector
4326 * @param key[out] symmetric cipher and HMAC state to generate
4329 dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4330 const struct GNUNET_ShortHashCode *iv,
4331 struct DVKeyState *key)
4333 /* must match #dh_key_derive_eph_pub */
4334 GNUNET_assert (GNUNET_YES ==
4335 GNUNET_CRYPTO_kdf (&key->material,
4336 sizeof(key->material),
4337 "transport-backchannel-key",
4338 strlen ("transport-backchannel-key"),
4343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4344 "Deriving backchannel key based on KM %s and IV %s\n",
4347 gcry_cipher_open (&key->cipher,
4348 GCRY_CIPHER_AES256 /* low level: go for speed */,
4349 GCRY_CIPHER_MODE_CTR,
4351 gcry_cipher_setkey (key->cipher,
4352 &key->material.aes_key,
4353 sizeof(key->material.aes_key));
4354 gcry_cipher_setctr (key->cipher,
4355 &key->material.aes_ctr,
4356 sizeof(key->material.aes_ctr));
4361 * Derive backchannel encryption key material from @a priv_ephemeral
4362 * and @a target and @a iv.
4364 * @param priv_ephemeral ephemeral private key to use
4365 * @param target the target peer to encrypt to
4366 * @param iv unique IV to use
4367 * @param key[out] set to the key material
4370 dh_key_derive_eph_pid (
4371 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4372 const struct GNUNET_PeerIdentity *target,
4373 const struct GNUNET_ShortHashCode *iv,
4374 struct DVKeyState *key)
4376 struct GNUNET_HashCode km;
4378 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4379 &target->public_key,
4381 dv_setup_key_state_from_km (&km, iv, key);
4386 * Derive backchannel encryption key material from #GST_my_private_key
4387 * and @a pub_ephemeral and @a iv.
4389 * @param priv_ephemeral ephemeral private key to use
4390 * @param target the target peer to encrypt to
4391 * @param iv unique IV to use
4392 * @param key[out] set to the key material
4395 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4396 const struct GNUNET_ShortHashCode *iv,
4397 struct DVKeyState *key)
4399 struct GNUNET_HashCode km;
4401 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4404 dv_setup_key_state_from_km (&km, iv, key);
4409 * Do HMAC calculation for backchannel messages over @a data using key
4410 * material from @a key.
4412 * @param key key material (from DH)
4413 * @param hmac[out] set to the HMAC
4414 * @param data data to perform HMAC calculation over
4415 * @param data_size number of bytes in @a data
4418 dv_hmac (const struct DVKeyState *key,
4419 struct GNUNET_HashCode *hmac,
4423 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4428 * Perform backchannel encryption using symmetric secret in @a key
4429 * to encrypt data from @a in to @a dst.
4431 * @param key[in,out] key material to use
4432 * @param dst where to write the result
4433 * @param in input data to encrypt (plaintext)
4434 * @param in_size number of bytes of input in @a in and available at @a dst
4437 dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4440 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4445 * Perform backchannel encryption using symmetric secret in @a key
4446 * to encrypt data from @a in to @a dst.
4448 * @param key[in,out] key material to use
4449 * @param ciph cipher text to decrypt
4450 * @param out[out] output data to generate (plaintext)
4451 * @param out_size number of bytes of input in @a ciph and available in @a out
4454 dv_decrypt (struct DVKeyState *key,
4460 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4465 * Clean up key material in @a key.
4467 * @param key key material to clean up (memory must not be free'd!)
4470 dv_key_clean (struct DVKeyState *key)
4472 gcry_cipher_close (key->cipher);
4473 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
4478 * Function to call to further operate on the now DV encapsulated
4479 * message @a hdr, forwarding it via @a next_hop under respect of
4482 * @param cls closure
4483 * @param next_hop next hop of the DV path
4484 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4485 * @param options options of the original message
4487 typedef void (*DVMessageHandler) (void *cls,
4488 struct Neighbour *next_hop,
4489 const struct GNUNET_MessageHeader *hdr,
4490 enum RouteMessageOptions options);
4493 * Pick a path of @a dv under constraints @a options and schedule
4494 * transmission of @a hdr.
4496 * @param target neighbour to ultimately send to
4497 * @param num_dvhs length of the @a dvhs array
4498 * @param dvhs array of hops to send the message to
4499 * @param hdr message to send as payload
4500 * @param use function to call with the encapsulated message
4501 * @param use_cls closure for @a use
4502 * @param options whether path must be confirmed or not, to be passed to @a use
4503 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4505 static struct GNUNET_TIME_Relative
4506 encapsulate_for_dv (struct DistanceVector *dv,
4507 unsigned int num_dvhs,
4508 struct DistanceVectorHop **dvhs,
4509 const struct GNUNET_MessageHeader *hdr,
4510 DVMessageHandler use,
4512 enum RouteMessageOptions options)
4514 struct TransportDVBoxMessage box_hdr;
4515 struct TransportDVBoxPayloadP payload_hdr;
4516 uint16_t enc_body_size = ntohs (hdr->size);
4517 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4518 struct TransportDVBoxPayloadP *enc_payload_hdr =
4519 (struct TransportDVBoxPayloadP *) enc;
4520 struct DVKeyState key;
4521 struct GNUNET_TIME_Relative rtt;
4523 /* Encrypt payload */
4524 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4525 box_hdr.total_hops = htons (0);
4526 update_ephemeral (dv);
4527 box_hdr.ephemeral_key = dv->ephemeral_key;
4528 payload_hdr.sender_sig = dv->sender_sig;
4529 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4531 sizeof(box_hdr.iv));
4532 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, &key);
4533 payload_hdr.sender = GST_my_identity;
4534 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4535 dv_encrypt (&key, &payload_hdr, enc_payload_hdr, sizeof(payload_hdr));
4538 &enc[sizeof(struct TransportDVBoxPayloadP)],
4540 dv_hmac (&key, &box_hdr.hmac, enc, sizeof(enc));
4541 dv_key_clean (&key);
4542 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4543 /* For each selected path, take the pre-computed header and body
4544 and add the path in the middle of the message; then send it. */
4545 for (unsigned int i = 0; i < num_dvhs; i++)
4547 struct DistanceVectorHop *dvh = dvhs[i];
4548 unsigned int num_hops = dvh->distance + 1;
4549 char buf[sizeof(struct TransportDVBoxMessage)
4550 + sizeof(struct GNUNET_PeerIdentity) * num_hops
4551 + sizeof(struct TransportDVBoxPayloadP)
4552 + enc_body_size] GNUNET_ALIGN;
4553 struct GNUNET_PeerIdentity *dhops;
4555 box_hdr.header.size = htons (sizeof(buf));
4556 box_hdr.num_hops = htons (num_hops);
4557 memcpy (buf, &box_hdr, sizeof(box_hdr));
4558 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
4561 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
4562 dhops[dvh->distance] = dv->target;
4563 if (GNUNET_EXTRA_LOGGING > 0)
4567 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4568 for (unsigned int j = 0; j <= num_hops; j++)
4572 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
4576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4577 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4579 GNUNET_i2s (&dv->target),
4585 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4586 memcpy (&dhops[num_hops], enc, sizeof(enc));
4589 (const struct GNUNET_MessageHeader *) buf,
4597 * Wrapper around #route_via_neighbour() that matches the
4598 * #DVMessageHandler structure.
4601 * @param next_hop where to send next
4602 * @param hdr header of the message to send
4603 * @param options message options for queue selection
4606 send_dv_to_neighbour (void *cls,
4607 struct Neighbour *next_hop,
4608 const struct GNUNET_MessageHeader *hdr,
4609 enum RouteMessageOptions options)
4612 (void) route_via_neighbour (next_hop, hdr, options);
4617 * We need to transmit @a hdr to @a target. If necessary, this may
4618 * involve DV routing. This function routes without applying flow
4619 * control or congestion control and should only be used for control
4622 * @param target peer to receive @a hdr
4623 * @param hdr header of the message to route and #GNUNET_free()
4624 * @param options which transmission channels are allowed
4625 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4627 static struct GNUNET_TIME_Relative
4628 route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4629 const struct GNUNET_MessageHeader *hdr,
4630 enum RouteMessageOptions options)
4632 struct VirtualLink *vl;
4633 struct Neighbour *n;
4634 struct DistanceVector *dv;
4635 struct GNUNET_TIME_Relative rtt1;
4636 struct GNUNET_TIME_Relative rtt2;
4638 vl = lookup_virtual_link (target);
4639 GNUNET_assert (NULL != vl);
4641 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4642 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4644 /* if confirmed is required, and we do not have anything
4645 confirmed, drop respective options */
4647 n = lookup_neighbour (target);
4648 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4649 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4651 if ((NULL == n) && (NULL == dv))
4653 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4654 "Cannot route message of type %u to %s: no route\n",
4656 GNUNET_i2s (target));
4657 GNUNET_STATISTICS_update (GST_stats,
4658 "# Messages dropped in routing: no acceptable method",
4661 return GNUNET_TIME_UNIT_FOREVER_REL;
4663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4664 "Routing message of type %u to %s with options %X\n",
4666 GNUNET_i2s (target),
4667 (unsigned int) options);
4668 /* If both dv and n are possible and we must choose:
4669 flip a coin for the choice between the two; for now 50/50 */
4670 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4672 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4677 if ((NULL != n) && (NULL != dv))
4678 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4679 enough for redunancy, so clear the flag. */
4680 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4681 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4684 rtt1 = route_via_neighbour (n, hdr, options);
4688 struct DistanceVectorHop *hops[2];
4691 res = pick_random_dv_hops (dv,
4694 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4697 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4698 "Failed to route message, could not determine DV path\n");
4701 rtt2 = encapsulate_for_dv (dv,
4705 &send_dv_to_neighbour,
4707 options & (~RMO_REDUNDANT));
4709 return GNUNET_TIME_relative_min (rtt1, rtt2);
4714 * Something changed on the virtual link with respect to flow
4715 * control. Consider retransmitting the FC window size.
4717 * @param cls a `struct VirtualLink` to work with
4720 consider_sending_fc (void *cls)
4722 struct VirtualLink *vl = cls;
4723 struct GNUNET_TIME_Absolute monotime;
4724 struct TransportFlowControlMessage fc;
4725 struct GNUNET_TIME_Relative duration;
4726 struct GNUNET_TIME_Relative rtt;
4728 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
4729 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
4731 /* For example, we should probably ONLY do this if a bit more than
4732 an RTT has passed, or if the window changed "significantly" since
4733 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
4734 need an estimate for the bandwidth-delay-product for the entire
4735 VL, as that determines "significantly". We have the delay, but
4736 the bandwidth statistics need to be added for the VL!*/(void) duration;
4738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4739 "Sending FC seq %u to %s with new window %llu\n",
4740 (unsigned int) vl->fc_seq_gen,
4741 GNUNET_i2s (&vl->target),
4742 (unsigned long long) vl->incoming_fc_window_size);
4743 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4744 vl->last_fc_transmission = monotime;
4745 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
4746 fc.header.size = htons (sizeof(fc));
4747 fc.seq = htonl (vl->fc_seq_gen++);
4748 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
4749 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
4750 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
4751 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
4752 rtt = route_control_message_without_fc (&vl->target, &fc.header, RMO_NONE);
4753 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
4755 rtt = GNUNET_TIME_UNIT_SECONDS;
4756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4757 "FC retransmission to %s failed, will retry in %s\n",
4758 GNUNET_i2s (&vl->target),
4759 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
4760 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
4764 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
4765 vl->last_fc_rtt = rtt;
4767 if (NULL != vl->fc_retransmit_task)
4768 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
4769 vl->fc_retransmit_task =
4770 GNUNET_SCHEDULER_add_delayed (rtt, &consider_sending_fc, vl);
4775 * There is a message at the head of the pending messages for @a vl
4776 * which may be ready for transmission. Check if a queue is ready to
4779 * This function must (1) check for flow control to ensure that we can
4780 * right now send to @a vl, (2) check that the pending message in the
4781 * queue is actually eligible, (3) determine if any applicable queue
4782 * (direct neighbour or DVH path) is ready to accept messages, and
4783 * (4) prioritize based on the preferences associated with the
4788 * @param vl virtual link where we should check for transmission
4791 check_vl_transmission (struct VirtualLink *vl)
4793 struct Neighbour *n = vl->n;
4794 struct DistanceVector *dv = vl->dv;
4795 struct GNUNET_TIME_Absolute now;
4798 /* Check that we have an eligible pending message!
4799 (cheaper than having #transmit_on_queue() find out!) */
4801 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
4805 continue; /* not eligible, is in a queue! */
4806 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
4807 vl->outbound_fc_window_size)
4809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4810 "Stalled transmision on VL %s due to flow control: %llu < %llu\n",
4811 GNUNET_i2s (&vl->target),
4812 (unsigned long long) vl->outbound_fc_window_size,
4813 (unsigned long long) (pm->bytes_msg
4814 + vl->outbound_fc_window_size_used));
4815 consider_sending_fc (vl);
4816 return; /* We have a message, but flow control says "nope" */
4821 if (GNUNET_NO == elig)
4824 /* Notify queues at direct neighbours that we are interested */
4825 now = GNUNET_TIME_absolute_get ();
4828 for (struct Queue *queue = n->queue_head; NULL != queue;
4829 queue = queue->next_neighbour)
4830 if ((GNUNET_YES == queue->idle) &&
4831 (queue->validated_until.abs_value_us > now.abs_value_us))
4832 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4834 /* Notify queues via DV that we are interested */
4837 /* Do DV with lower scheduler priority, which effectively means that
4838 IF a neighbour exists and is available, we prefer it. */
4839 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4842 struct Neighbour *nh = pos->next_hop;
4844 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
4845 continue; /* skip this one: path not validated */
4846 for (struct Queue *queue = nh->queue_head; NULL != queue;
4847 queue = queue->next_neighbour)
4848 if ((GNUNET_YES == queue->idle) &&
4849 (queue->validated_until.abs_value_us > now.abs_value_us))
4850 schedule_transmit_on_queue (queue,
4851 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
4858 * Client asked for transmission to a peer. Process the request.
4860 * @param cls the client
4861 * @param obm the send message that was sent
4864 handle_client_send (void *cls, const struct OutboundMessage *obm)
4866 struct TransportClient *tc = cls;
4867 struct PendingMessage *pm;
4868 const struct GNUNET_MessageHeader *obmm;
4870 struct VirtualLink *vl;
4871 enum GNUNET_MQ_PriorityPreferences pp;
4873 GNUNET_assert (CT_CORE == tc->type);
4874 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4875 bytes_msg = ntohs (obmm->size);
4876 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
4877 vl = lookup_virtual_link (&obm->peer);
4880 /* Failure: don't have this peer as a neighbour (anymore).
4881 Might have gone down asynchronously, so this is NOT
4882 a protocol violation by CORE. Still count the event,
4883 as this should be rare. */
4884 GNUNET_SERVICE_client_continue (tc->client);
4885 GNUNET_STATISTICS_update (GST_stats,
4886 "# messages dropped (neighbour unknown)",
4892 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
4893 pm->logging_uuid = logging_uuid_gen++;
4897 pm->bytes_msg = bytes_msg;
4898 memcpy (&pm[1], obmm, bytes_msg);
4899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4900 "Sending %u bytes as <%llu> to %s\n",
4903 GNUNET_i2s (&obm->peer));
4904 GNUNET_CONTAINER_MDLL_insert (client,
4905 tc->details.core.pending_msg_head,
4906 tc->details.core.pending_msg_tail,
4908 GNUNET_CONTAINER_MDLL_insert (vl,
4909 vl->pending_msg_head,
4910 vl->pending_msg_tail,
4912 check_vl_transmission (vl);
4917 * Communicator requests backchannel transmission. Process the request.
4918 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
4919 * (which for now has exactly the same format, only a different message type)
4920 * and passes it on for routing.
4922 * @param cls the client
4923 * @param cb the send message that was sent
4926 handle_communicator_backchannel (
4928 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4930 struct TransportClient *tc = cls;
4931 const struct GNUNET_MessageHeader *inbox =
4932 (const struct GNUNET_MessageHeader *) &cb[1];
4933 uint16_t isize = ntohs (inbox->size);
4934 const char *is = ((const char *) &cb[1]) + isize;
4938 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
4939 struct TransportBackchannelEncapsulationMessage *be =
4940 (struct TransportBackchannelEncapsulationMessage *) mbuf;
4942 /* 0-termination of 'is' was checked already in
4943 #check_communicator_backchannel() */
4944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4945 "Preparing backchannel transmission to %s:%s of type %u\n",
4946 GNUNET_i2s (&cb->pid),
4948 ntohs (inbox->size));
4949 /* encapsulate and encrypt message */
4951 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4952 be->header.size = htons (sizeof(mbuf));
4953 memcpy (&be[1], inbox, isize);
4954 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
4958 route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
4959 GNUNET_SERVICE_client_continue (tc->client);
4964 * Address of our peer added. Test message is well-formed.
4966 * @param cls the client
4967 * @param aam the send message that was sent
4968 * @return #GNUNET_OK if message is well-formed
4971 check_add_address (void *cls,
4972 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4974 struct TransportClient *tc = cls;
4976 if (CT_COMMUNICATOR != tc->type)
4979 return GNUNET_SYSERR;
4981 GNUNET_MQ_check_zero_termination (aam);
4987 * Ask peerstore to store our address.
4989 * @param cls an `struct AddressListEntry *`
4992 store_pi (void *cls);
4996 * Function called when peerstore is done storing our address.
4998 * @param cls a `struct AddressListEntry`
4999 * @param success #GNUNET_YES if peerstore was successful
5002 peerstore_store_own_cb (void *cls, int success)
5004 struct AddressListEntry *ale = cls;
5007 if (GNUNET_YES != success)
5008 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5009 "Failed to store our own address `%s' in peerstore!\n",
5012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5013 "Successfully stored our own address `%s' in peerstore!\n",
5015 /* refresh period is 1/4 of expiration time, that should be plenty
5016 without being excessive. */
5018 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5026 * Ask peerstore to store our address.
5028 * @param cls an `struct AddressListEntry *`
5031 store_pi (void *cls)
5033 struct AddressListEntry *ale = cls;
5036 struct GNUNET_TIME_Absolute expiration;
5039 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5041 "Storing our address `%s' in peerstore until %s!\n",
5043 GNUNET_STRINGS_absolute_time_to_string (expiration));
5044 GNUNET_HELLO_sign_address (ale->address,
5050 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5053 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5057 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5058 &peerstore_store_own_cb,
5061 if (NULL == ale->sc)
5063 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5064 "Failed to store our address `%s' with peerstore\n",
5067 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5073 * Address of our peer added. Process the request.
5075 * @param cls the client
5076 * @param aam the send message that was sent
5079 handle_add_address (void *cls,
5080 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5082 struct TransportClient *tc = cls;
5083 struct AddressListEntry *ale;
5086 /* 0-termination of &aam[1] was checked in #check_add_address */
5087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5088 "Communicator added address `%s'!\n",
5089 (const char *) &aam[1]);
5090 slen = ntohs (aam->header.size) - sizeof(*aam);
5091 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5093 ale->address = (const char *) &ale[1];
5094 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5095 ale->aid = aam->aid;
5096 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5097 memcpy (&ale[1], &aam[1], slen);
5098 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5099 tc->details.communicator.addr_tail,
5101 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5102 GNUNET_SERVICE_client_continue (tc->client);
5107 * Address of our peer deleted. Process the request.
5109 * @param cls the client
5110 * @param dam the send message that was sent
5113 handle_del_address (void *cls,
5114 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5116 struct TransportClient *tc = cls;
5117 struct AddressListEntry *alen;
5119 if (CT_COMMUNICATOR != tc->type)
5122 GNUNET_SERVICE_client_drop (tc->client);
5125 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5130 if (dam->aid != ale->aid)
5132 GNUNET_assert (ale->tc == tc);
5133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5134 "Communicator deleted address `%s'!\n",
5136 free_address_list_entry (ale);
5137 GNUNET_SERVICE_client_continue (tc->client);
5140 GNUNET_SERVICE_client_drop (tc->client);
5145 * Given an inbound message @a msg from a communicator @a cmc,
5146 * demultiplex it based on the type calling the right handler.
5148 * @param cmc context for demultiplexing
5149 * @param msg message to demultiplex
5152 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5153 const struct GNUNET_MessageHeader *msg);
5157 * Function called when we are done giving a message of a certain
5158 * size to CORE and should thus decrement the number of bytes of
5159 * RAM reserved for that peer's MQ.
5161 * @param cls a `struct CoreSentContext`
5164 core_env_sent_cb (void *cls)
5166 struct CoreSentContext *ctx = cls;
5167 struct VirtualLink *vl = ctx->vl;
5171 /* lost the link in the meantime, ignore */
5175 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5176 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5177 vl->incoming_fc_window_size_ram -= ctx->size;
5178 vl->incoming_fc_window_size_used += ctx->isize;
5179 consider_sending_fc (vl);
5185 * Communicator gave us an unencapsulated message to pass as-is to
5186 * CORE. Process the request.
5188 * @param cls a `struct CommunicatorMessageContext` (must call
5189 * #finish_cmc_handling() when done)
5190 * @param mh the message that was received
5193 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5195 struct CommunicatorMessageContext *cmc = cls;
5196 struct VirtualLink *vl;
5197 uint16_t size = ntohs (mh->size);
5200 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5201 (size < sizeof(struct GNUNET_MessageHeader)))
5203 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5206 finish_cmc_handling (cmc);
5207 GNUNET_SERVICE_client_drop (client);
5210 vl = lookup_virtual_link (&cmc->im.sender);
5213 /* FIXME: sender is giving us messages for CORE but we don't have
5214 the link up yet! I *suspect* this can happen right now (i.e.
5215 sender has verified us, but we didn't verify sender), but if
5216 we pass this on, CORE would be confused (link down, messages
5217 arrive). We should investigate more if this happens often,
5218 or in a persistent manner, and possibly do "something" about
5219 it. Thus logging as error for now. */GNUNET_break_op (0);
5220 GNUNET_STATISTICS_update (GST_stats,
5221 "# CORE messages droped (virtual link still down)",
5225 finish_cmc_handling (cmc);
5228 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5230 GNUNET_STATISTICS_update (GST_stats,
5231 "# CORE messages droped (FC arithmetic overflow)",
5235 finish_cmc_handling (cmc);
5238 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5240 GNUNET_STATISTICS_update (GST_stats,
5241 "# CORE messages droped (FC window overflow)",
5244 finish_cmc_handling (cmc);
5248 /* Forward to all CORE clients */
5249 have_core = GNUNET_NO;
5250 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5252 struct GNUNET_MQ_Envelope *env;
5253 struct InboundMessage *im;
5254 struct CoreSentContext *ctx;
5256 if (CT_CORE != tc->type)
5258 vl->incoming_fc_window_size_ram += size;
5259 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5260 ctx = GNUNET_new (struct CoreSentContext);
5263 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5264 have_core = GNUNET_YES;
5265 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5266 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5267 im->peer = cmc->im.sender;
5268 memcpy (&im[1], mh, size);
5269 GNUNET_MQ_send (tc->mq, env);
5270 vl->core_recv_window--;
5272 if (GNUNET_NO == have_core)
5274 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5275 "Dropped message to CORE: no CORE client connected!\n");
5276 /* Nevertheless, count window as used, as it is from the
5277 perspective of the other peer! */
5278 vl->incoming_fc_window_size_used += size;
5280 finish_cmc_handling (cmc);
5283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5284 "Delivered message from %s of type %u to CORE\n",
5285 GNUNET_i2s (&cmc->im.sender),
5287 if (vl->core_recv_window > 0)
5289 finish_cmc_handling (cmc);
5292 /* Wait with calling #finish_cmc_handling(cmc) until the message
5293 was processed by CORE MQs (for CORE flow control)! */
5294 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5299 * Communicator gave us a fragment box. Check the message.
5301 * @param cls a `struct CommunicatorMessageContext`
5302 * @param fb the send message that was sent
5303 * @return #GNUNET_YES if message is well-formed
5306 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5308 uint16_t size = ntohs (fb->header.size);
5309 uint16_t bsize = size - sizeof(*fb);
5314 GNUNET_break_op (0);
5315 return GNUNET_SYSERR;
5317 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5319 GNUNET_break_op (0);
5320 return GNUNET_SYSERR;
5322 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5324 GNUNET_break_op (0);
5325 return GNUNET_SYSERR;
5332 * Clean up an idle cummulative acknowledgement data structure.
5334 * @param cls a `struct AcknowledgementCummulator *`
5337 destroy_ack_cummulator (void *cls)
5339 struct AcknowledgementCummulator *ac = cls;
5342 GNUNET_assert (0 == ac->num_acks);
5345 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5351 * Do the transmission of a cummulative acknowledgement now.
5353 * @param cls a `struct AcknowledgementCummulator *`
5356 transmit_cummulative_ack_cb (void *cls)
5358 struct AcknowledgementCummulator *ac = cls;
5359 char buf[sizeof(struct TransportReliabilityAckMessage)
5361 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5362 struct TransportReliabilityAckMessage *ack =
5363 (struct TransportReliabilityAckMessage *) buf;
5364 struct TransportCummulativeAckPayloadP *ap;
5367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5368 "Sending ACK with %u components to %s\n",
5370 GNUNET_i2s (&ac->target));
5371 GNUNET_assert (0 < ac->ack_counter);
5372 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5375 + ac->ack_counter * sizeof(struct TransportCummulativeAckPayloadP));
5376 ack->ack_counter = htonl (ac->ack_counter++);
5377 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5378 for (unsigned int i = 0; i < ac->ack_counter; i++)
5380 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5381 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5382 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5384 route_control_message_without_fc (&ac->target, &ack->header, RMO_DV_ALLOWED);
5386 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5387 &destroy_ack_cummulator,
5393 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5394 * transmission by at most @a ack_delay.
5396 * @param pid target peer
5397 * @param ack_uuid UUID to ack
5398 * @param max_delay how long can the ACK wait
5401 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5402 const struct AcknowledgementUUIDP *ack_uuid,
5403 struct GNUNET_TIME_Absolute max_delay)
5405 struct AcknowledgementCummulator *ac;
5407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5408 "Scheduling ACK %s for transmission to %s\n",
5409 GNUNET_uuid2s (&ack_uuid->value),
5411 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5414 ac = GNUNET_new (struct AcknowledgementCummulator);
5416 ac->min_transmission_time = max_delay;
5417 GNUNET_assert (GNUNET_YES ==
5418 GNUNET_CONTAINER_multipeermap_put (
5422 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5426 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5428 /* must run immediately, ack buffer full! */
5429 GNUNET_SCHEDULER_cancel (ac->task);
5430 transmit_cummulative_ack_cb (ac);
5432 GNUNET_SCHEDULER_cancel (ac->task);
5433 ac->min_transmission_time =
5434 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5436 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5437 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5438 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5440 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5441 &transmit_cummulative_ack_cb,
5447 * Closure for #find_by_message_uuid.
5449 struct FindByMessageUuidContext
5454 struct MessageUUIDP message_uuid;
5457 * Set to the reassembly context if found.
5459 struct ReassemblyContext *rc;
5464 * Iterator called to find a reassembly context by the message UUID in the
5467 * @param cls a `struct FindByMessageUuidContext`
5468 * @param key a key (unused)
5469 * @param value a `struct ReassemblyContext`
5470 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5473 find_by_message_uuid (void *cls, uint32_t key, void *value)
5475 struct FindByMessageUuidContext *fc = cls;
5476 struct ReassemblyContext *rc = value;
5479 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5489 * Communicator gave us a fragment. Process the request.
5491 * @param cls a `struct CommunicatorMessageContext` (must call
5492 * #finish_cmc_handling() when done)
5493 * @param fb the message that was received
5496 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5498 struct CommunicatorMessageContext *cmc = cls;
5499 struct Neighbour *n;
5500 struct ReassemblyContext *rc;
5501 const struct GNUNET_MessageHeader *msg;
5506 struct GNUNET_TIME_Relative cdelay;
5507 struct FindByMessageUuidContext fc;
5509 n = lookup_neighbour (&cmc->im.sender);
5512 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5515 finish_cmc_handling (cmc);
5516 GNUNET_SERVICE_client_drop (client);
5519 if (NULL == n->reassembly_map)
5521 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5522 n->reassembly_heap =
5523 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5524 n->reassembly_timeout_task =
5525 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5526 &reassembly_cleanup_task,
5529 msize = ntohs (fb->msg_size);
5530 fc.message_uuid = fb->msg_uuid;
5532 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5534 &find_by_message_uuid,
5536 if (NULL == (rc = fc.rc))
5538 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
5539 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
5540 rc->msg_uuid = fb->msg_uuid;
5542 rc->msg_size = msize;
5543 rc->reassembly_timeout =
5544 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5545 rc->last_frag = GNUNET_TIME_absolute_get ();
5546 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5548 rc->reassembly_timeout.abs_value_us);
5549 GNUNET_assert (GNUNET_OK ==
5550 GNUNET_CONTAINER_multihashmap32_put (
5554 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5555 target = (char *) &rc[1];
5556 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5557 rc->msg_missing = rc->msg_size;
5558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5559 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5560 ntohs (fb->frag_off),
5562 GNUNET_i2s (&cmc->im.sender),
5563 (unsigned int) fb->msg_uuid.uuid);
5567 target = (char *) &rc[1];
5568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5569 "Received fragment at offset %u/%u from %s for message %u\n",
5570 ntohs (fb->frag_off),
5572 GNUNET_i2s (&cmc->im.sender),
5573 (unsigned int) fb->msg_uuid.uuid);
5575 if (msize != rc->msg_size)
5578 finish_cmc_handling (cmc);
5583 fsize = ntohs (fb->header.size) - sizeof(*fb);
5587 finish_cmc_handling (cmc);
5590 frag_off = ntohs (fb->frag_off);
5591 if (frag_off + fsize > msize)
5593 /* Fragment (plus fragment size) exceeds message size! */
5594 GNUNET_break_op (0);
5595 finish_cmc_handling (cmc);
5598 memcpy (&target[frag_off], &fb[1], fsize);
5599 /* update bitfield and msg_missing */
5600 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5602 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5604 rc->bitfield[i / 8] |= (1 << (i % 8));
5609 /* Compute cummulative ACK */
5610 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5611 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5612 if (0 == rc->msg_missing)
5613 cdelay = GNUNET_TIME_UNIT_ZERO;
5614 cummulative_ack (&cmc->im.sender,
5616 GNUNET_TIME_relative_to_absolute (cdelay));
5617 rc->last_frag = GNUNET_TIME_absolute_get ();
5618 /* is reassembly complete? */
5619 if (0 != rc->msg_missing)
5621 finish_cmc_handling (cmc);
5624 /* reassembly is complete, verify result */
5625 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5626 if (ntohs (msg->size) != rc->msg_size)
5629 free_reassembly_context (rc);
5630 finish_cmc_handling (cmc);
5633 /* successful reassembly */
5634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5635 "Fragment reassembly complete for message %u\n",
5636 (unsigned int) fb->msg_uuid.uuid);
5637 /* FIXME: check that the resulting msg is NOT a
5638 DV Box or Reliability Box, as that is NOT allowed! */
5639 demultiplex_with_cmc (cmc, msg);
5640 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5641 en-route and we forget that we finished this reassembly immediately!
5642 -> keep around until timeout?
5643 -> shorten timeout based on ACK? */
5644 free_reassembly_context (rc);
5649 * Communicator gave us a reliability box. Check the message.
5651 * @param cls a `struct CommunicatorMessageContext`
5652 * @param rb the send message that was sent
5653 * @return #GNUNET_YES if message is well-formed
5656 check_reliability_box (void *cls,
5657 const struct TransportReliabilityBoxMessage *rb)
5660 GNUNET_MQ_check_boxed_message (rb);
5666 * Communicator gave us a reliability box. Process the request.
5668 * @param cls a `struct CommunicatorMessageContext` (must call
5669 * #finish_cmc_handling() when done)
5670 * @param rb the message that was received
5673 handle_reliability_box (void *cls,
5674 const struct TransportReliabilityBoxMessage *rb)
5676 struct CommunicatorMessageContext *cmc = cls;
5677 const struct GNUNET_MessageHeader *inbox =
5678 (const struct GNUNET_MessageHeader *) &rb[1];
5679 struct GNUNET_TIME_Relative rtt;
5681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5682 "Received reliability box from %s with UUID %s of type %u\n",
5683 GNUNET_i2s (&cmc->im.sender),
5684 GNUNET_uuid2s (&rb->ack_uuid.value),
5685 (unsigned int) ntohs (inbox->type));
5686 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5687 do not really have an RTT for the
5688 * incoming* queue (should we have
5689 the sender add it to the rb message?) */
5693 (0 == ntohl (rb->ack_countdown))
5694 ? GNUNET_TIME_UNIT_ZERO_ABS
5695 : GNUNET_TIME_relative_to_absolute (
5696 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5697 /* continue with inner message */
5698 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5699 reliability box (not allowed!) */
5700 demultiplex_with_cmc (cmc, inbox);
5705 * Check if we have advanced to another age since the last time. If
5706 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5709 * @param pd[in,out] data to update
5710 * @param age current age
5713 update_pd_age (struct PerformanceData *pd, unsigned int age)
5717 if (age == pd->last_age)
5718 return; /* nothing to do */
5719 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5720 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5722 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5724 the->bytes_sent = 0;
5725 the->bytes_received = 0;
5732 * Update @a pd based on the latest @a rtt and the number of bytes
5733 * that were confirmed to be successfully transmitted.
5735 * @param pd[in,out] data to update
5736 * @param rtt latest round-trip time
5737 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5740 update_performance_data (struct PerformanceData *pd,
5741 struct GNUNET_TIME_Relative rtt,
5742 uint16_t bytes_transmitted_ok)
5744 uint64_t nval = rtt.rel_value_us;
5745 uint64_t oval = pd->aged_rtt.rel_value_us;
5746 unsigned int age = get_age ();
5747 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5749 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5752 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5753 update_pd_age (pd, age);
5754 the->bytes_received += bytes_transmitted_ok;
5759 * We have successfully transmitted data via @a q, update metrics.
5761 * @param q queue to update
5762 * @param rtt round trip time observed
5763 * @param bytes_transmitted_ok number of bytes successfully transmitted
5766 update_queue_performance (struct Queue *q,
5767 struct GNUNET_TIME_Relative rtt,
5768 uint16_t bytes_transmitted_ok)
5770 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5775 * We have successfully transmitted data via @a dvh, update metrics.
5777 * @param dvh distance vector path data to update
5778 * @param rtt round trip time observed
5779 * @param bytes_transmitted_ok number of bytes successfully transmitted
5782 update_dvh_performance (struct DistanceVectorHop *dvh,
5783 struct GNUNET_TIME_Relative rtt,
5784 uint16_t bytes_transmitted_ok)
5786 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5791 * We have completed transmission of @a pm, remove it from
5792 * the transmission queues (and if it is a fragment, continue
5793 * up the tree as necessary).
5795 * @param pm pending message that was transmitted
5798 completed_pending_message (struct PendingMessage *pm)
5800 struct PendingMessage *pos;
5805 case PMT_RELIABILITY_BOX:
5806 /* Full message sent, we are done */
5807 client_send_response (pm);
5810 case PMT_FRAGMENT_BOX:
5811 /* Fragment sent over reliabile channel */
5812 free_fragment_tree (pm);
5813 pos = pm->frag_parent;
5814 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5816 /* check if subtree is done */
5817 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5821 pos = pm->frag_parent;
5822 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5826 /* Was this the last applicable fragmment? */
5827 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
5828 (pos->frag_off == pos->bytes_msg))
5829 client_send_response (pos);
5833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5834 "Completed transmission of message %llu (DV Box)\n",
5836 free_pending_message (pm);
5843 * The @a pa was acknowledged, process the acknowledgement.
5845 * @param pa the pending acknowledgement that was satisfied
5846 * @param ack_delay artificial delay from cummulative acks created by the
5850 handle_acknowledged (struct PendingAcknowledgement *pa,
5851 struct GNUNET_TIME_Relative ack_delay)
5853 struct GNUNET_TIME_Relative delay;
5855 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5856 if (delay.rel_value_us > ack_delay.rel_value_us)
5857 delay = GNUNET_TIME_UNIT_ZERO;
5859 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5860 if (NULL != pa->queue)
5861 update_queue_performance (pa->queue, delay, pa->message_size);
5862 if (NULL != pa->dvh)
5863 update_dvh_performance (pa->dvh, delay, pa->message_size);
5865 completed_pending_message (pa->pm);
5866 free_pending_acknowledgement (pa);
5871 * Communicator gave us a reliability ack. Check it is well-formed.
5873 * @param cls a `struct CommunicatorMessageContext` (unused)
5874 * @param ra the message that was received
5875 * @return #GNUNET_Ok if @a ra is well-formed
5878 check_reliability_ack (void *cls,
5879 const struct TransportReliabilityAckMessage *ra)
5881 unsigned int n_acks;
5884 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5885 / sizeof(struct TransportCummulativeAckPayloadP);
5888 GNUNET_break_op (0);
5889 return GNUNET_SYSERR;
5891 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
5892 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
5894 GNUNET_break_op (0);
5895 return GNUNET_SYSERR;
5902 * Communicator gave us a reliability ack. Process the request.
5904 * @param cls a `struct CommunicatorMessageContext` (must call
5905 * #finish_cmc_handling() when done)
5906 * @param ra the message that was received
5909 handle_reliability_ack (void *cls,
5910 const struct TransportReliabilityAckMessage *ra)
5912 struct CommunicatorMessageContext *cmc = cls;
5913 const struct TransportCummulativeAckPayloadP *ack;
5914 unsigned int n_acks;
5915 uint32_t ack_counter;
5917 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5918 / sizeof(struct TransportCummulativeAckPayloadP);
5919 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5920 for (unsigned int i = 0; i < n_acks; i++)
5922 struct PendingAcknowledgement *pa =
5923 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5926 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5927 "Received ACK from %s with UUID %s which is unknown to us!\n",
5928 GNUNET_i2s (&cmc->im.sender),
5929 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5930 GNUNET_STATISTICS_update (
5932 "# FRAGMENT_ACKS dropped, no matching pending message",
5937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5938 "Received ACK from %s with UUID %s\n",
5939 GNUNET_i2s (&cmc->im.sender),
5940 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5941 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5944 ack_counter = htonl (ra->ack_counter);
5945 (void) ack_counter; /* silence compiler warning for now */
5946 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5947 // (DV and/or Neighbour?)
5948 finish_cmc_handling (cmc);
5953 * Communicator gave us a backchannel encapsulation. Check the message.
5955 * @param cls a `struct CommunicatorMessageContext`
5956 * @param be the send message that was sent
5957 * @return #GNUNET_YES if message is well-formed
5960 check_backchannel_encapsulation (
5962 const struct TransportBackchannelEncapsulationMessage *be)
5964 uint16_t size = ntohs (be->header.size) - sizeof(*be);
5965 const struct GNUNET_MessageHeader *inbox =
5966 (const struct GNUNET_MessageHeader *) &be[1];
5971 if (ntohs (inbox->size) >= size)
5973 GNUNET_break_op (0);
5974 return GNUNET_SYSERR;
5976 isize = ntohs (inbox->size);
5977 is = ((const char *) inbox) + isize;
5979 if ('\0' != is[size - 1])
5981 GNUNET_break_op (0);
5982 return GNUNET_SYSERR;
5989 * Communicator gave us a backchannel encapsulation. Process the request.
5990 * (We are the destination of the backchannel here.)
5992 * @param cls a `struct CommunicatorMessageContext` (must call
5993 * #finish_cmc_handling() when done)
5994 * @param be the message that was received
5997 handle_backchannel_encapsulation (
5999 const struct TransportBackchannelEncapsulationMessage *be)
6001 struct CommunicatorMessageContext *cmc = cls;
6002 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6003 struct GNUNET_MQ_Envelope *env;
6004 struct TransportClient *tc;
6005 const struct GNUNET_MessageHeader *inbox =
6006 (const struct GNUNET_MessageHeader *) &be[1];
6007 uint16_t isize = ntohs (inbox->size);
6008 const char *target_communicator = ((const char *) inbox) + isize;
6010 /* Find client providing this communicator */
6011 for (tc = clients_head; NULL != tc; tc = tc->next)
6012 if ((CT_COMMUNICATOR == tc->type) &&
6014 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6022 "# Backchannel message dropped: target communicator `%s' unknown",
6023 target_communicator);
6024 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6025 GNUNET_free (stastr);
6028 /* Finally, deliver backchannel message to communicator */
6029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6030 "Delivering backchannel message from %s of type %u to %s\n",
6031 GNUNET_i2s (&cmc->im.sender),
6032 ntohs (inbox->type),
6033 target_communicator);
6034 env = GNUNET_MQ_msg_extra (
6037 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6038 cbi->pid = cmc->im.sender;
6039 memcpy (&cbi[1], inbox, isize);
6040 GNUNET_MQ_send (tc->mq, env);
6045 * Task called when we should check if any of the DV paths
6046 * we have learned to a target are due for garbage collection.
6048 * Collects stale paths, and possibly frees the entire DV
6049 * entry if no paths are left. Otherwise re-schedules itself.
6051 * @param cls a `struct DistanceVector`
6054 path_cleanup_cb (void *cls)
6056 struct DistanceVector *dv = cls;
6057 struct DistanceVectorHop *pos;
6059 dv->timeout_task = NULL;
6060 while (NULL != (pos = dv->dv_head))
6062 GNUNET_assert (dv == pos->dv);
6063 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6065 free_distance_vector_hop (pos);
6073 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6078 * The @a hop is a validated path to the respective target
6079 * peer and we should tell core about it -- and schedule
6080 * a job to revoke the state.
6082 * @param hop a path to some peer that is the reason for activation
6085 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6087 struct DistanceVector *dv = hop->dv;
6088 struct VirtualLink *vl;
6090 vl = lookup_virtual_link (&dv->target);
6093 /* Link was already up, remember dv is also now available and we are done */
6095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6096 "Virtual link to %s could now also use DV!\n",
6097 GNUNET_i2s (&dv->target));
6100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6101 "Creating new virtual link to %s using DV!\n",
6102 GNUNET_i2s (&dv->target));
6103 vl = GNUNET_new (struct VirtualLink);
6104 vl->message_uuid_ctr =
6105 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6106 vl->target = dv->target;
6109 vl->core_recv_window = RECV_WINDOW_SIZE;
6110 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6111 vl->visibility_task =
6112 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6113 GNUNET_break (GNUNET_YES ==
6114 GNUNET_CONTAINER_multipeermap_put (
6118 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6119 consider_sending_fc (vl);
6120 /* We lacked a confirmed connection to the target
6121 before, so tell CORE about it (finally!) */
6122 cores_send_connect_info (&dv->target);
6127 * We have learned a @a path through the network to some other peer, add it to
6128 * our DV data structure (returning #GNUNET_YES on success).
6130 * We do not add paths if we have a sufficient number of shorter
6131 * paths to this target already (returning #GNUNET_NO).
6133 * We also do not add problematic paths, like those where we lack the first
6134 * hop in our neighbour list (i.e. due to a topology change) or where some
6135 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6137 * @param path the path we learned, path[0] should be us,
6138 * and then path contains a valid path from us to
6139 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6140 * @param path_len number of entries on the @a path, at least three!
6141 * @param network_latency how long does the message take from us to
6142 * `path[path_len-1]`? set to "forever" if unknown
6143 * @param path_valid_until how long is this path considered validated? Maybe
6145 * @return #GNUNET_YES on success,
6146 * #GNUNET_NO if we have better path(s) to the target
6147 * #GNUNET_SYSERR if the path is useless and/or invalid
6148 * (i.e. path[1] not a direct neighbour
6149 * or path[i+1] is a direct neighbour for i>0)
6152 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6153 unsigned int path_len,
6154 struct GNUNET_TIME_Relative network_latency,
6155 struct GNUNET_TIME_Absolute path_valid_until)
6157 struct DistanceVectorHop *hop;
6158 struct DistanceVector *dv;
6159 struct Neighbour *next_hop;
6160 unsigned int shorter_distance;
6164 /* what a boring path! not allowed! */
6166 return GNUNET_SYSERR;
6168 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6169 next_hop = lookup_neighbour (&path[1]);
6170 if (NULL == next_hop)
6172 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6174 return GNUNET_SYSERR;
6176 for (unsigned int i = 2; i < path_len; i++)
6177 if (NULL != lookup_neighbour (&path[i]))
6179 /* Useless path: we have a direct connection to some hop
6180 in the middle of the path, so this one is not even
6181 terribly useful for redundancy */
6182 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6183 "Path of %u hops useless: directly link to hop %u (%s)\n",
6186 GNUNET_i2s (&path[i]));
6187 GNUNET_STATISTICS_update (GST_stats,
6188 "# Useless DV path ignored: hop is neighbour",
6191 return GNUNET_SYSERR;
6193 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6196 dv = GNUNET_new (struct DistanceVector);
6197 dv->target = path[path_len - 1];
6198 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6201 GNUNET_assert (GNUNET_OK ==
6202 GNUNET_CONTAINER_multipeermap_put (
6206 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6208 /* Check if we have this path already! */
6209 shorter_distance = 0;
6210 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6213 if (pos->distance < path_len - 2)
6215 /* Note that the distances in 'pos' excludes us (path[0]) and
6216 the next_hop (path[1]), so we need to subtract two
6217 and check next_hop explicitly */
6218 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6220 int match = GNUNET_YES;
6222 for (unsigned int i = 0; i < pos->distance; i++)
6224 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6230 if (GNUNET_YES == match)
6232 struct GNUNET_TIME_Relative last_timeout;
6234 /* Re-discovered known path, update timeout */
6235 GNUNET_STATISTICS_update (GST_stats,
6236 "# Known DV path refreshed",
6239 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6241 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6242 pos->path_valid_until =
6243 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6244 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6245 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6247 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6248 activate_core_visible_dv_path (pos);
6249 if (last_timeout.rel_value_us <
6250 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6251 DV_PATH_DISCOVERY_FREQUENCY)
6254 /* Some peer send DV learn messages too often, we are learning
6255 the same path faster than it would be useful; do not forward! */
6256 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6257 "Rediscovered path too quickly, not forwarding further\n");
6260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6261 "Refreshed known path to %s, forwarding further\n",
6262 GNUNET_i2s (&dv->target));
6267 /* Count how many shorter paths we have (incl. direct
6268 neighbours) before simply giving up on this one! */
6269 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6271 /* We have a shorter path already! */
6272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6273 "Have many shorter DV paths %s, not forwarding further\n",
6274 GNUNET_i2s (&dv->target));
6277 /* create new DV path entry */
6278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6279 "Discovered new DV path to %s\n",
6280 GNUNET_i2s (&dv->target));
6281 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
6282 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6283 hop->next_hop = next_hop;
6285 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6288 sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6289 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6290 hop->path_valid_until = path_valid_until;
6291 hop->distance = path_len - 2;
6292 hop->pd.aged_rtt = network_latency;
6293 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6294 GNUNET_CONTAINER_MDLL_insert (neighbour,
6298 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6299 activate_core_visible_dv_path (hop);
6305 * Communicator gave us a DV learn message. Check the message.
6307 * @param cls a `struct CommunicatorMessageContext`
6308 * @param dvl the send message that was sent
6309 * @return #GNUNET_YES if message is well-formed
6312 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6314 uint16_t size = ntohs (dvl->header.size);
6315 uint16_t num_hops = ntohs (dvl->num_hops);
6316 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6319 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
6321 GNUNET_break_op (0);
6322 return GNUNET_SYSERR;
6324 if (num_hops > MAX_DV_HOPS_ALLOWED)
6326 GNUNET_break_op (0);
6327 return GNUNET_SYSERR;
6329 for (unsigned int i = 0; i < num_hops; i++)
6331 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6333 GNUNET_break_op (0);
6334 return GNUNET_SYSERR;
6336 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6338 GNUNET_break_op (0);
6339 return GNUNET_SYSERR;
6347 * Build and forward a DV learn message to @a next_hop.
6349 * @param next_hop peer to send the message to
6350 * @param msg message received
6351 * @param bi_history bitmask specifying hops on path that were bidirectional
6352 * @param nhops length of the @a hops array
6353 * @param hops path the message traversed so far
6354 * @param in_time when did we receive the message, used to calculate network
6358 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6359 const struct TransportDVLearnMessage *msg,
6360 uint16_t bi_history,
6362 const struct DVPathEntryP *hops,
6363 struct GNUNET_TIME_Absolute in_time)
6365 struct DVPathEntryP *dhops;
6366 char buf[sizeof(struct TransportDVLearnMessage)
6367 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
6368 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6369 struct GNUNET_TIME_Relative nnd;
6371 /* compute message for forwarding */
6372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6373 "Forwarding DV learn message originating from %s to %s\n",
6374 GNUNET_i2s (&msg->initiator),
6375 GNUNET_i2s2 (next_hop));
6376 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6377 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6378 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
6379 + (nhops + 1) * sizeof(struct DVPathEntryP));
6380 fwd->num_hops = htons (nhops + 1);
6381 fwd->bidirectional = htons (bi_history);
6382 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6383 GNUNET_TIME_relative_ntoh (
6384 msg->non_network_delay));
6385 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6386 fwd->init_sig = msg->init_sig;
6387 fwd->initiator = msg->initiator;
6388 fwd->challenge = msg->challenge;
6389 dhops = (struct DVPathEntryP *) &fwd[1];
6390 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
6391 dhops[nhops].hop = GST_my_identity;
6393 struct DvHopPS dhp = {
6394 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6395 .purpose.size = htonl (sizeof(dhp)),
6396 .pred = dhops[nhops - 1].hop,
6398 .challenge = msg->challenge
6401 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6403 &dhops[nhops].hop_sig);
6405 route_control_message_without_fc (next_hop,
6407 RMO_UNCONFIRMED_ALLOWED);
6412 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6414 * @param sender_monotonic_time monotonic time of the initiator
6415 * @param init the signer
6416 * @param challenge the challenge that was signed
6417 * @param init_sig signature presumably by @a init
6418 * @return #GNUNET_OK if the signature is valid
6421 validate_dv_initiator_signature (
6422 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6423 const struct GNUNET_PeerIdentity *init,
6424 const struct ChallengeNonceP *challenge,
6425 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6427 struct DvInitPS ip = { .purpose.purpose = htonl (
6428 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6429 .purpose.size = htonl (sizeof(ip)),
6430 .monotonic_time = sender_monotonic_time,
6431 .challenge = *challenge };
6435 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6440 GNUNET_break_op (0);
6441 return GNUNET_SYSERR;
6448 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6450 struct NeighbourSelectionContext
6453 * Original message we received.
6455 const struct TransportDVLearnMessage *dvl;
6460 const struct DVPathEntryP *hops;
6463 * Time we received the message.
6465 struct GNUNET_TIME_Absolute in_time;
6468 * Offsets of the selected peers.
6470 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6473 * Number of peers eligible for selection.
6475 unsigned int num_eligible;
6478 * Number of peers that were selected for forwarding.
6480 unsigned int num_selections;
6483 * Number of hops in @e hops
6488 * Bitmap of bidirectional connections encountered.
6490 uint16_t bi_history;
6495 * Function called for each neighbour during #handle_dv_learn.
6497 * @param cls a `struct NeighbourSelectionContext *`
6498 * @param pid identity of the peer
6499 * @param value a `struct Neighbour`
6500 * @return #GNUNET_YES (always)
6503 dv_neighbour_selection (void *cls,
6504 const struct GNUNET_PeerIdentity *pid,
6507 struct NeighbourSelectionContext *nsc = cls;
6510 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6511 return GNUNET_YES; /* skip initiator */
6512 for (unsigned int i = 0; i < nsc->nhops; i++)
6513 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6515 /* skip peers on path */
6516 nsc->num_eligible++;
6522 * Function called for each neighbour during #handle_dv_learn.
6523 * We call #forward_dv_learn() on the neighbour(s) selected
6524 * during #dv_neighbour_selection().
6526 * @param cls a `struct NeighbourSelectionContext *`
6527 * @param pid identity of the peer
6528 * @param value a `struct Neighbour`
6529 * @return #GNUNET_YES (always)
6532 dv_neighbour_transmission (void *cls,
6533 const struct GNUNET_PeerIdentity *pid,
6536 struct NeighbourSelectionContext *nsc = cls;
6539 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6540 return GNUNET_YES; /* skip initiator */
6541 for (unsigned int i = 0; i < nsc->nhops; i++)
6542 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6544 /* skip peers on path */
6545 for (unsigned int i = 0; i < nsc->num_selections; i++)
6547 if (nsc->selections[i] == nsc->num_eligible)
6549 forward_dv_learn (pid,
6558 nsc->num_eligible++;
6564 * Computes the number of neighbours we should forward a DVInit
6565 * message to given that it has so far taken @a hops_taken hops
6566 * though the network and that the number of neighbours we have
6567 * in total is @a neighbour_count, out of which @a eligible_count
6568 * are not yet on the path.
6570 * NOTE: technically we might want to include NSE in the formula to
6571 * get a better grip on the overall network size. However, for now
6572 * using NSE here would create a dependency issue in the build system.
6573 * => Left for later, hardcoded to 50 for now.
6575 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6576 * peers via DV (`target_total`). We want the reach to be spread out
6577 * over various distances to the origin, with a bias towards shorter
6580 * We make the strong assumption that the network topology looks
6581 * "similar" at other hops, in particular the @a neighbour_count
6582 * should be comparable at other hops.
6584 * If the local neighbourhood is densely connected, we expect that @a
6585 * eligible_count is close to @a neighbour_count minus @a hops_taken
6586 * as a lot of the path is already known. In that case, we should
6587 * forward to few(er) peers to try to find a path out of the
6588 * neighbourhood. OTOH, if @a eligible_count is close to @a
6589 * neighbour_count, we should forward to many peers as we are either
6590 * still close to the origin (i.e. @a hops_taken is small) or because
6591 * we managed to get beyond a local cluster. We express this as
6592 * the `boost_factor` using the square of the fraction of eligible
6593 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6594 * 99% are eligible, the 'boost' will be almost 1).
6596 * Second, the more hops we have taken, the larger the problem of an
6597 * exponential traffic explosion gets. So we take the `target_total`,
6598 * and compute our degree such that at each distance d 2^{-d} peers
6599 * are selected (corrected by the `boost_factor`).
6601 * @param hops_taken number of hops DVInit has travelled so far
6602 * @param neighbour_count number of neighbours we have in total
6603 * @param eligible_count number of neighbours we could in
6607 calculate_fork_degree (unsigned int hops_taken,
6608 unsigned int neighbour_count,
6609 unsigned int eligible_count)
6611 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6612 double eligible_ratio =
6613 ((double) eligible_count) / ((double) neighbour_count);
6614 double boost_factor = eligible_ratio * eligible_ratio;
6618 if (hops_taken >= 64)
6621 return 0; /* precaution given bitshift below */
6623 for (unsigned int i = 1; i < hops_taken; i++)
6625 /* For each hop, subtract the expected number of targets
6626 reached at distance d (so what remains divided by 2^d) */
6627 target_total -= (target_total * boost_factor / (1LLU << i));
6630 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6631 /* round up or down probabilistically depending on how close we were
6632 when floor()ing to rnd */
6633 left = target_total - (double) rnd;
6634 if (UINT32_MAX * left >
6635 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6636 rnd++; /* round up */
6637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6638 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6648 * Function called when peerstore is done storing a DV monotonic time.
6650 * @param cls a `struct Neighbour`
6651 * @param success #GNUNET_YES if peerstore was successful
6654 neighbour_store_dvmono_cb (void *cls, int success)
6656 struct Neighbour *n = cls;
6659 if (GNUNET_YES != success)
6660 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6661 "Failed to store other peer's monotonic time in peerstore!\n");
6666 * Communicator gave us a DV learn message. Process the request.
6668 * @param cls a `struct CommunicatorMessageContext` (must call
6669 * #finish_cmc_handling() when done)
6670 * @param dvl the message that was received
6673 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6675 struct CommunicatorMessageContext *cmc = cls;
6676 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6679 uint16_t bi_history;
6680 const struct DVPathEntryP *hops;
6683 struct GNUNET_TIME_Absolute in_time;
6684 struct Neighbour *n;
6686 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6687 bi_history = ntohs (dvl->bidirectional);
6688 hops = (const struct DVPathEntryP *) &dvl[1];
6692 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6695 finish_cmc_handling (cmc);
6702 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6705 finish_cmc_handling (cmc);
6710 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6711 cc = cmc->tc->details.communicator.cc;
6712 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6713 cc); // FIXME: add bi-directional flag to cc?
6714 in_time = GNUNET_TIME_absolute_get ();
6716 /* continue communicator here, everything else can happen asynchronous! */
6717 finish_cmc_handling (cmc);
6719 n = lookup_neighbour (&dvl->initiator);
6722 if ((n->dv_monotime_available == GNUNET_YES) &&
6723 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6724 n->last_dv_learn_monotime.abs_value_us))
6726 GNUNET_STATISTICS_update (GST_stats,
6727 "# DV learn discarded due to time travel",
6732 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6737 GNUNET_break_op (0);
6740 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6741 if (GNUNET_YES == n->dv_monotime_available)
6744 GNUNET_PEERSTORE_store_cancel (n->sc);
6746 GNUNET_PEERSTORE_store (peerstore,
6749 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6750 &dvl->monotonic_time,
6751 sizeof(dvl->monotonic_time),
6752 GNUNET_TIME_UNIT_FOREVER_ABS,
6753 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6754 &neighbour_store_dvmono_cb,
6758 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6759 If signature verification load too high, implement random drop strategy */
6760 for (unsigned int i = 0; i < nhops; i++)
6762 struct DvHopPS dhp = { .purpose.purpose =
6763 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6764 .purpose.size = htonl (sizeof(dhp)),
6765 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6766 .succ = (nhops == i + 1) ? GST_my_identity
6768 .challenge = dvl->challenge };
6771 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6774 &hops[i].hop.public_key))
6776 GNUNET_break_op (0);
6781 if (GNUNET_EXTRA_LOGGING > 0)
6785 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6786 for (unsigned int i = 0; i < nhops; i++)
6790 GNUNET_asprintf (&tmp,
6793 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6794 GNUNET_i2s (&hops[i].hop));
6798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6799 "Received DVInit via %s%s%s\n",
6801 bi_hop ? "<->" : "-->",
6802 GNUNET_i2s (&GST_my_identity));
6806 do_fwd = GNUNET_YES;
6807 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6809 struct GNUNET_PeerIdentity path[nhops + 1];
6810 struct GNUNET_TIME_Relative host_latency_sum;
6811 struct GNUNET_TIME_Relative latency;
6812 struct GNUNET_TIME_Relative network_latency;
6814 /* We initiated this, learn the forward path! */
6815 path[0] = GST_my_identity;
6816 path[1] = hops[0].hop;
6817 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6819 // Need also something to lookup initiation time
6820 // to compute RTT! -> add RTT argument here?
6821 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6822 // (based on dvl->challenge, we can identify time of origin!)
6824 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6825 /* assumption: latency on all links is the same */
6826 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6828 for (unsigned int i = 2; i <= nhops; i++)
6830 struct GNUNET_TIME_Relative ilat;
6832 /* assumption: linear latency increase per hop */
6833 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6834 path[i] = hops[i - 1].hop;
6835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6836 "Learned path with %u hops to %s with latency %s\n",
6838 GNUNET_i2s (&path[i]),
6839 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6840 learn_dv_path (path,
6843 GNUNET_TIME_relative_to_absolute (
6844 ADDRESS_VALIDATION_LIFETIME));
6846 /* as we initiated, do not forward again (would be circular!) */
6852 /* last hop was bi-directional, we could learn something here! */
6853 struct GNUNET_PeerIdentity path[nhops + 2];
6855 path[0] = GST_my_identity;
6856 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6857 for (unsigned int i = 0; i < nhops; i++)
6861 if (0 == (bi_history & (1 << i)))
6862 break; /* i-th hop not bi-directional, stop learning! */
6865 path[i + 2] = dvl->initiator;
6869 path[i + 2] = hops[nhops - i - 2].hop;
6872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6873 "Learned inverse path with %u hops to %s\n",
6875 GNUNET_i2s (&path[i + 2]));
6876 iret = learn_dv_path (path,
6878 GNUNET_TIME_UNIT_FOREVER_REL,
6879 GNUNET_TIME_UNIT_ZERO_ABS);
6880 if (GNUNET_SYSERR == iret)
6882 /* path invalid or too long to be interesting for US, thus should also
6883 not be interesting to our neighbours, cut path when forwarding to
6884 'i' hops, except of course for the one that goes back to the
6886 GNUNET_STATISTICS_update (GST_stats,
6887 "# DV learn not forwarded due invalidity of path",
6893 if ((GNUNET_NO == iret) && (nhops == i + 1))
6895 /* we have better paths, and this is the longest target,
6896 so there cannot be anything interesting later */
6897 GNUNET_STATISTICS_update (GST_stats,
6898 "# DV learn not forwarded, got better paths",
6907 if (MAX_DV_HOPS_ALLOWED == nhops)
6909 /* At limit, we're out of here! */
6910 finish_cmc_handling (cmc);
6914 /* Forward to initiator, if path non-trivial and possible */
6915 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6916 did_initiator = GNUNET_NO;
6919 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6921 /* send back to origin! */
6922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6923 "Sending DVL back to initiator %s\n",
6924 GNUNET_i2s (&dvl->initiator));
6925 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6926 did_initiator = GNUNET_YES;
6928 /* We forward under two conditions: either we still learned something
6929 ourselves (do_fwd), or the path was darn short and thus the initiator is
6930 likely to still be very interested in this (and we did NOT already
6931 send it back to the initiator) */
6932 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6933 (GNUNET_NO == did_initiator)))
6935 /* Pick random neighbours that are not yet on the path */
6936 struct NeighbourSelectionContext nsc;
6939 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6942 nsc.bi_history = bi_history;
6944 nsc.in_time = in_time;
6945 nsc.num_eligible = 0;
6946 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6947 &dv_neighbour_selection,
6949 if (0 == nsc.num_eligible)
6950 return; /* done here, cannot forward to anyone else */
6951 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6952 nsc.num_selections =
6953 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6955 "Forwarding DVL to %u other peers\n",
6956 nsc.num_selections);
6957 for (unsigned int i = 0; i < nsc.num_selections; i++)
6959 (nsc.num_selections == n_cnt)
6960 ? i /* all were selected, avoid collisions by chance */
6961 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6962 nsc.num_eligible = 0;
6963 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6964 &dv_neighbour_transmission,
6971 * Communicator gave us a DV box. Check the message.
6973 * @param cls a `struct CommunicatorMessageContext`
6974 * @param dvb the send message that was sent
6975 * @return #GNUNET_YES if message is well-formed
6978 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6980 uint16_t size = ntohs (dvb->header.size);
6981 uint16_t num_hops = ntohs (dvb->num_hops);
6982 const struct GNUNET_PeerIdentity *hops =
6983 (const struct GNUNET_PeerIdentity *) &dvb[1];
6986 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
6987 + sizeof(struct GNUNET_MessageHeader))
6989 GNUNET_break_op (0);
6990 return GNUNET_SYSERR;
6992 /* This peer must not be on the path */
6993 for (unsigned int i = 0; i < num_hops; i++)
6994 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6996 GNUNET_break_op (0);
6997 return GNUNET_SYSERR;
7004 * Create a DV Box message and queue it for transmission to
7007 * @param next_hop peer to receive the message next
7008 * @param total_hops how many hops did the message take so far
7009 * @param num_hops length of the @a hops array
7010 * @param origin origin of the message
7011 * @param hops next peer(s) to the destination, including destination
7012 * @param payload payload of the box
7013 * @param payload_size number of bytes in @a payload
7016 forward_dv_box (struct Neighbour *next_hop,
7017 const struct TransportDVBoxMessage *hdr,
7018 uint16_t total_hops,
7020 const struct GNUNET_PeerIdentity *hops,
7021 const void *enc_payload,
7022 uint16_t enc_payload_size)
7024 struct VirtualLink *vl = next_hop->vl;
7025 struct PendingMessage *pm;
7028 struct GNUNET_PeerIdentity *dhops;
7030 GNUNET_assert (NULL != vl);
7031 msg_size = sizeof(struct TransportDVBoxMessage)
7032 + num_hops * sizeof(struct GNUNET_PeerIdentity) + enc_payload_size;
7033 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7034 pm->pmt = PMT_DV_BOX;
7036 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7037 pm->logging_uuid = logging_uuid_gen++;
7038 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7039 pm->bytes_msg = msg_size;
7040 buf = (char *) &pm[1];
7041 memcpy (buf, hdr, sizeof(*hdr));
7043 (struct GNUNET_PeerIdentity *) &buf[sizeof(struct TransportDVBoxMessage)];
7044 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7045 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7046 GNUNET_CONTAINER_MDLL_insert (vl,
7047 vl->pending_msg_head,
7048 vl->pending_msg_tail,
7050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7051 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7053 GNUNET_i2s (&next_hop->pid),
7054 (unsigned int) num_hops,
7055 (unsigned int) total_hops);
7056 check_vl_transmission (vl);
7061 * Free data structures associated with @a b.
7063 * @param b data structure to release
7066 free_backtalker (struct Backtalker *b)
7070 GNUNET_PEERSTORE_iterate_cancel (b->get);
7072 GNUNET_assert (NULL != b->cmc);
7073 finish_cmc_handling (b->cmc);
7076 if (NULL != b->task)
7078 GNUNET_SCHEDULER_cancel (b->task);
7083 GNUNET_PEERSTORE_store_cancel (b->sc);
7088 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7094 * Callback to free backtalker records.
7098 * @param value a `struct Backtalker`
7099 * @return #GNUNET_OK (always)
7102 free_backtalker_cb (void *cls,
7103 const struct GNUNET_PeerIdentity *pid,
7106 struct Backtalker *b = value;
7110 free_backtalker (b);
7116 * Function called when it is time to clean up a backtalker.
7118 * @param cls a `struct Backtalker`
7121 backtalker_timeout_cb (void *cls)
7123 struct Backtalker *b = cls;
7126 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7128 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7131 GNUNET_assert (NULL == b->sc);
7132 free_backtalker (b);
7137 * Function called with the monotonic time of a backtalker
7138 * by PEERSTORE. Updates the time and continues processing.
7140 * @param cls a `struct Backtalker`
7141 * @param record the information found, NULL for the last call
7142 * @param emsg error message
7145 backtalker_monotime_cb (void *cls,
7146 const struct GNUNET_PEERSTORE_Record *record,
7149 struct Backtalker *b = cls;
7150 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7151 struct GNUNET_TIME_Absolute mt;
7156 /* we're done with #backtalker_monotime_cb() invocations,
7157 continue normal processing */
7159 GNUNET_assert (NULL != b->cmc);
7160 if (0 != b->body_size)
7161 demultiplex_with_cmc (b->cmc,
7162 (const struct GNUNET_MessageHeader *) &b[1]);
7164 finish_cmc_handling (b->cmc);
7168 if (sizeof(*mtbe) != record->value_size)
7173 mtbe = record->value;
7174 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7175 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7178 "Backtalker message from %s dropped, monotime in the past\n",
7179 GNUNET_i2s (&b->pid));
7180 GNUNET_STATISTICS_update (
7182 "# Backchannel messages dropped: monotonic time not increasing",
7185 b->monotonic_time = mt;
7186 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7195 * Function called by PEERSTORE when the store operation of
7196 * a backtalker's monotonic time is complete.
7198 * @param cls the `struct Backtalker`
7199 * @param success #GNUNET_OK on success
7202 backtalker_monotime_store_cb (void *cls, int success)
7204 struct Backtalker *b = cls;
7206 if (GNUNET_OK != success)
7208 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7209 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7212 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7217 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7219 * @param b a backtalker with updated monotonic time
7222 update_backtalker_monotime (struct Backtalker *b)
7224 struct GNUNET_TIME_AbsoluteNBO mtbe;
7228 GNUNET_PEERSTORE_store_cancel (b->sc);
7233 GNUNET_SCHEDULER_cancel (b->task);
7236 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7238 GNUNET_PEERSTORE_store (peerstore,
7241 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7244 GNUNET_TIME_UNIT_FOREVER_ABS,
7245 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7246 &backtalker_monotime_store_cb,
7252 * Communicator gave us a DV box. Process the request.
7254 * @param cls a `struct CommunicatorMessageContext` (must call
7255 * #finish_cmc_handling() when done)
7256 * @param dvb the message that was received
7259 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7261 struct CommunicatorMessageContext *cmc = cls;
7262 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
7263 uint16_t num_hops = ntohs (dvb->num_hops);
7264 const struct GNUNET_PeerIdentity *hops =
7265 (const struct GNUNET_PeerIdentity *) &dvb[1];
7266 const char *enc_payload = (const char *) &hops[num_hops];
7267 uint16_t enc_payload_size =
7268 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
7269 struct DVKeyState key;
7270 struct GNUNET_HashCode hmac;
7274 if (GNUNET_EXTRA_LOGGING > 0)
7278 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7279 for (unsigned int i = 0; i < num_hops; i++)
7283 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7288 "Received DVBox with remainig path %s\n",
7295 /* We're trying from the end of the hops array, as we may be
7296 able to find a shortcut unknown to the origin that way */
7297 for (int i = num_hops - 1; i >= 0; i--)
7299 struct Neighbour *n;
7301 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7303 GNUNET_break_op (0);
7304 finish_cmc_handling (cmc);
7307 n = lookup_neighbour (&hops[i]);
7310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7311 "Skipping %u/%u hops ahead while routing DV Box\n",
7316 ntohs (dvb->total_hops) + 1,
7317 num_hops - i - 1, /* number of hops left */
7318 &hops[i + 1], /* remaining hops */
7321 GNUNET_STATISTICS_update (GST_stats,
7322 "# DV hops skipped routing boxes",
7325 GNUNET_STATISTICS_update (GST_stats,
7326 "# DV boxes routed (total)",
7329 finish_cmc_handling (cmc);
7332 /* Woopsie, next hop not in neighbours, drop! */
7333 GNUNET_STATISTICS_update (GST_stats,
7334 "# DV Boxes dropped: next hop unknown",
7337 finish_cmc_handling (cmc);
7340 /* We are the target. Unbox and handle message. */
7341 GNUNET_STATISTICS_update (GST_stats,
7342 "# DV boxes opened (ultimate target)",
7345 cmc->total_hops = ntohs (dvb->total_hops);
7347 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key);
7348 hdr = (const char *) &dvb[1];
7349 hdr_len = ntohs (dvb->header.size) - sizeof(*dvb);
7350 dv_hmac (&key, &hmac, hdr, hdr_len);
7351 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7353 /* HMAC missmatch, disard! */
7354 GNUNET_break_op (0);
7355 finish_cmc_handling (cmc);
7358 /* begin actual decryption */
7360 struct Backtalker *b;
7361 struct GNUNET_TIME_Absolute monotime;
7362 struct TransportDVBoxPayloadP ppay;
7363 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
7364 const struct GNUNET_MessageHeader *mh =
7365 (const struct GNUNET_MessageHeader *) body;
7367 GNUNET_assert (hdr_len >=
7368 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
7369 dv_decrypt (&key, &ppay, hdr, sizeof(ppay));
7370 dv_decrypt (&key, &body, &hdr[sizeof(ppay)], hdr_len - sizeof(ppay));
7371 dv_key_clean (&key);
7372 if (ntohs (mh->size) != sizeof(body))
7374 GNUNET_break_op (0);
7375 finish_cmc_handling (cmc);
7378 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7379 switch (ntohs (mh->type))
7381 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7382 GNUNET_break_op (0);
7383 finish_cmc_handling (cmc);
7386 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7387 GNUNET_break_op (0);
7388 finish_cmc_handling (cmc);
7392 /* permitted, continue */
7395 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7397 "Decrypted backtalk from %s\n",
7398 GNUNET_i2s (&ppay.sender));
7399 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
7400 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
7402 GNUNET_STATISTICS_update (
7404 "# Backchannel messages dropped: monotonic time not increasing",
7407 finish_cmc_handling (cmc);
7411 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
7413 /* Check signature */
7414 struct EphemeralConfirmationPS ec;
7416 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
7417 ec.purpose.size = htonl (sizeof(ec));
7418 ec.target = GST_my_identity;
7419 ec.ephemeral_key = dvb->ephemeral_key;
7422 GNUNET_CRYPTO_eddsa_verify (
7423 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
7426 &ppay.sender.public_key))
7428 /* Signature invalid, disard! */
7429 GNUNET_break_op (0);
7430 finish_cmc_handling (cmc);
7434 /* Update sender, we now know the real origin! */
7435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7436 "DVBox received for me from %s via %s\n",
7437 GNUNET_i2s2 (&ppay.sender),
7438 GNUNET_i2s (&cmc->im.sender));
7439 cmc->im.sender = ppay.sender;
7443 /* update key cache and mono time */
7444 b->last_ephemeral = dvb->ephemeral_key;
7445 b->monotonic_time = monotime;
7446 update_backtalker_monotime (b);
7448 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7450 demultiplex_with_cmc (cmc, mh);
7453 /* setup data structure to cache signature AND check
7454 monotonic time with PEERSTORE before forwarding backchannel payload */
7455 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
7456 b->pid = ppay.sender;
7457 b->body_size = sizeof(body);
7458 memcpy (&b[1], body, sizeof(body));
7459 GNUNET_assert (GNUNET_YES ==
7460 GNUNET_CONTAINER_multipeermap_put (
7464 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7465 b->monotonic_time = monotime; /* NOTE: to be checked still! */
7468 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7469 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7471 GNUNET_PEERSTORE_iterate (peerstore,
7474 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7475 &backtalker_monotime_cb,
7477 } /* end actual decryption */
7482 * Client notified us about transmission from a peer. Process the request.
7484 * @param cls a `struct TransportClient` which sent us the message
7485 * @param obm the send message that was sent
7486 * @return #GNUNET_YES if message is well-formed
7489 check_incoming_msg (void *cls,
7490 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7492 struct TransportClient *tc = cls;
7494 if (CT_COMMUNICATOR != tc->type)
7497 return GNUNET_SYSERR;
7499 GNUNET_MQ_check_boxed_message (im);
7505 * Closure for #check_known_address.
7507 struct CheckKnownAddressContext
7510 * Set to the address we are looking for.
7512 const char *address;
7515 * Set to a matching validation state, if one was found.
7517 struct ValidationState *vs;
7522 * Test if the validation state in @a value matches the
7523 * address from @a cls.
7525 * @param cls a `struct CheckKnownAddressContext`
7526 * @param pid unused (must match though)
7527 * @param value a `struct ValidationState`
7528 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7531 check_known_address (void *cls,
7532 const struct GNUNET_PeerIdentity *pid,
7535 struct CheckKnownAddressContext *ckac = cls;
7536 struct ValidationState *vs = value;
7539 if (0 != strcmp (vs->address, ckac->address))
7547 * Task run periodically to validate some address based on #validation_heap.
7552 validation_start_cb (void *cls);
7556 * Set the time for next_challenge of @a vs to @a new_time.
7557 * Updates the heap and if necessary reschedules the job.
7559 * @param vs validation state to update
7560 * @param new_time new time for revalidation
7563 update_next_challenge_time (struct ValidationState *vs,
7564 struct GNUNET_TIME_Absolute new_time)
7566 struct GNUNET_TIME_Relative delta;
7568 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7569 return; /* be lazy */
7570 vs->next_challenge = new_time;
7573 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7575 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7576 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7577 (NULL != validation_task))
7579 if (NULL != validation_task)
7580 GNUNET_SCHEDULER_cancel (validation_task);
7581 /* randomize a bit */
7582 delta.rel_value_us =
7583 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7584 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7585 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7587 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7592 * Start address validation.
7594 * @param pid peer the @a address is for
7595 * @param address an address to reach @a pid (presumably)
7598 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7599 const char *address)
7601 struct GNUNET_TIME_Absolute now;
7602 struct ValidationState *vs;
7603 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
7605 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7607 &check_known_address,
7609 if (NULL != (vs = ckac.vs))
7611 /* if 'vs' is not currently valid, we need to speed up retrying the
7613 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7615 /* reduce backoff as we got a fresh advertisement */
7616 vs->challenge_backoff =
7617 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7618 GNUNET_TIME_relative_divide (
7619 vs->challenge_backoff,
7621 update_next_challenge_time (vs,
7622 GNUNET_TIME_relative_to_absolute (
7623 vs->challenge_backoff));
7627 now = GNUNET_TIME_absolute_get ();
7628 vs = GNUNET_new (struct ValidationState);
7631 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7632 vs->first_challenge_use = now;
7633 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7634 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7636 sizeof(vs->challenge));
7637 vs->address = GNUNET_strdup (address);
7638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7639 "Starting address validation `%s' of peer %s using challenge %s\n",
7642 GNUNET_sh2s (&vs->challenge.value));
7643 GNUNET_assert (GNUNET_YES ==
7644 GNUNET_CONTAINER_multipeermap_put (
7648 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7649 update_next_challenge_time (vs, now);
7654 * Function called by PEERSTORE for each matching record.
7656 * @param cls closure, a `struct IncomingRequest`
7657 * @param record peerstore record information
7658 * @param emsg error message, or NULL if no errors
7661 handle_hello_for_incoming (void *cls,
7662 const struct GNUNET_PEERSTORE_Record *record,
7665 struct IncomingRequest *ir = cls;
7670 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7671 "Got failure from PEERSTORE: %s\n",
7675 val = record->value;
7676 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7681 start_address_validation (&ir->pid, (const char *) record->value);
7686 * Communicator gave us a transport address validation challenge. Process the
7689 * @param cls a `struct CommunicatorMessageContext` (must call
7690 * #finish_cmc_handling() when done)
7691 * @param tvc the message that was received
7694 handle_validation_challenge (
7696 const struct TransportValidationChallengeMessage *tvc)
7698 struct CommunicatorMessageContext *cmc = cls;
7699 struct TransportValidationResponseMessage tvr;
7700 struct VirtualLink *vl;
7701 struct GNUNET_TIME_RelativeNBO validity_duration;
7702 struct IncomingRequest *ir;
7703 struct Neighbour *n;
7704 struct GNUNET_PeerIdentity sender;
7706 /* DV-routed messages are not allowed for validation challenges */
7707 if (cmc->total_hops > 0)
7709 GNUNET_break_op (0);
7710 finish_cmc_handling (cmc);
7713 validity_duration = cmc->im.expected_address_validity;
7714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7715 "Received address validation challenge %s\n",
7716 GNUNET_sh2s (&tvc->challenge.value));
7717 /* If we have a virtual link, we use this mechanism to signal the
7718 size of the flow control window, and to allow the sender
7719 to ask for increases. If for us the virtual link is still down,
7720 we will always give a window size of zero. */
7722 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7723 tvr.header.size = htons (sizeof(tvr));
7724 tvr.reserved = htonl (0);
7725 tvr.challenge = tvc->challenge;
7726 tvr.origin_time = tvc->sender_time;
7727 tvr.validity_duration = validity_duration;
7729 /* create signature */
7730 struct TransportValidationPS tvp = {
7731 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7732 .purpose.size = htonl (sizeof(tvp)),
7733 .validity_duration = validity_duration,
7734 .challenge = tvc->challenge
7737 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7741 route_control_message_without_fc (&cmc->im.sender,
7743 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7744 sender = cmc->im.sender;
7745 finish_cmc_handling (cmc);
7746 vl = lookup_virtual_link (&sender);
7750 /* For us, the link is still down, but we need bi-directional
7751 connections (for flow-control and for this to be useful for
7752 CORE), so we must try to bring the link up! */
7754 /* (1) Check existing queues, if any, we may be lucky! */
7755 n = lookup_neighbour (&sender);
7757 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7758 start_address_validation (&sender, q->address);
7759 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7761 for (ir = ir_head; NULL != ir; ir = ir->next)
7762 if (0 == GNUNET_memcmp (&ir->pid, &sender))
7764 /* we are already trying */
7765 ir = GNUNET_new (struct IncomingRequest);
7767 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7768 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7771 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7772 &handle_hello_for_incoming,
7775 /* Bound attempts we do in parallel here, might otherwise get excessive */
7776 while (ir_total > MAX_INCOMING_REQUEST)
7777 free_incoming_request (ir_head);
7782 * Closure for #check_known_challenge.
7784 struct CheckKnownChallengeContext
7787 * Set to the challenge we are looking for.
7789 const struct ChallengeNonceP *challenge;
7792 * Set to a matching validation state, if one was found.
7794 struct ValidationState *vs;
7799 * Test if the validation state in @a value matches the
7800 * challenge from @a cls.
7802 * @param cls a `struct CheckKnownChallengeContext`
7803 * @param pid unused (must match though)
7804 * @param value a `struct ValidationState`
7805 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7808 check_known_challenge (void *cls,
7809 const struct GNUNET_PeerIdentity *pid,
7812 struct CheckKnownChallengeContext *ckac = cls;
7813 struct ValidationState *vs = value;
7816 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7824 * Function called when peerstore is done storing a
7825 * validated address.
7827 * @param cls a `struct ValidationState`
7828 * @param success #GNUNET_YES on success
7831 peerstore_store_validation_cb (void *cls, int success)
7833 struct ValidationState *vs = cls;
7836 if (GNUNET_YES == success)
7838 GNUNET_STATISTICS_update (GST_stats,
7839 "# Peerstore failed to store foreign address",
7846 * Find the queue matching @a pid and @a address.
7848 * @param pid peer the queue must go to
7849 * @param address address the queue must use
7850 * @return NULL if no such queue exists
7852 static struct Queue *
7853 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7855 struct Neighbour *n;
7857 n = lookup_neighbour (pid);
7860 for (struct Queue *pos = n->queue_head; NULL != pos;
7861 pos = pos->next_neighbour)
7863 if (0 == strcmp (pos->address, address))
7871 * Communicator gave us a transport address validation response. Process the
7874 * @param cls a `struct CommunicatorMessageContext` (must call
7875 * #finish_cmc_handling() when done)
7876 * @param tvr the message that was received
7879 handle_validation_response (
7881 const struct TransportValidationResponseMessage *tvr)
7883 struct CommunicatorMessageContext *cmc = cls;
7884 struct ValidationState *vs;
7885 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
7887 struct GNUNET_TIME_Absolute origin_time;
7889 struct Neighbour *n;
7890 struct VirtualLink *vl;
7892 /* check this is one of our challenges */
7893 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7895 &check_known_challenge,
7897 if (NULL == (vs = ckac.vs))
7899 /* This can happen simply if we 'forgot' the challenge by now,
7900 i.e. because we received the validation response twice */
7901 GNUNET_STATISTICS_update (GST_stats,
7902 "# Validations dropped, challenge unknown",
7905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7906 "Validation response %s dropped, challenge unknown\n",
7907 GNUNET_sh2s (&tvr->challenge.value));
7908 finish_cmc_handling (cmc);
7912 /* sanity check on origin time */
7913 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7914 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7915 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7917 GNUNET_break_op (0);
7918 finish_cmc_handling (cmc);
7923 /* check signature */
7924 struct TransportValidationPS tvp = {
7925 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7926 .purpose.size = htonl (sizeof(tvp)),
7927 .validity_duration = tvr->validity_duration,
7928 .challenge = tvr->challenge
7933 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7936 &cmc->im.sender.public_key))
7938 GNUNET_break_op (0);
7939 finish_cmc_handling (cmc);
7944 /* validity is capped by our willingness to keep track of the
7945 validation entry and the maximum the other peer allows */
7946 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7947 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7948 tvr->validity_duration),
7949 MAX_ADDRESS_VALID_UNTIL));
7950 vs->validated_until =
7951 GNUNET_TIME_absolute_min (vs->valid_until,
7952 GNUNET_TIME_relative_to_absolute (
7953 ADDRESS_VALIDATION_LIFETIME));
7954 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7955 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7956 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7958 sizeof(vs->challenge));
7959 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7960 vs->validated_until,
7961 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7962 VALIDATION_RTT_BUFFER_FACTOR));
7963 vs->last_challenge_use =
7964 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7965 update_next_challenge_time (vs, vs->first_challenge_use);
7966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7967 "Validation response %s accepted, address valid until %s\n",
7968 GNUNET_sh2s (&tvr->challenge.value),
7969 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
7970 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7973 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7975 strlen (vs->address) + 1,
7977 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7978 &peerstore_store_validation_cb,
7980 finish_cmc_handling (cmc);
7982 /* Finally, we now possibly have a confirmed (!) working queue,
7983 update queue status (if queue still is around) */
7984 q = find_queue (&vs->pid, vs->address);
7987 GNUNET_STATISTICS_update (GST_stats,
7988 "# Queues lost at time of successful validation",
7993 q->validated_until = vs->validated_until;
7994 q->pd.aged_rtt = vs->validation_rtt;
7996 vl = lookup_virtual_link (&vs->pid);
7999 /* Link was already up, remember n is also now available and we are done */
8004 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8005 "Virtual link to %s could now also direct neighbour!\n",
8006 GNUNET_i2s (&vs->pid));
8010 GNUNET_assert (n == vl->n);
8014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8015 "Creating new virtual link to %s using direct neighbour!\n",
8016 GNUNET_i2s (&vs->pid));
8017 vl = GNUNET_new (struct VirtualLink);
8018 vl->target = n->pid;
8021 vl->core_recv_window = RECV_WINDOW_SIZE;
8022 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8023 vl->visibility_task =
8024 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8025 GNUNET_break (GNUNET_YES ==
8026 GNUNET_CONTAINER_multipeermap_put (
8030 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8031 consider_sending_fc (vl);
8032 /* We lacked a confirmed connection to the target
8033 before, so tell CORE about it (finally!) */
8034 cores_send_connect_info (&n->pid);
8039 * Incoming meessage. Process the request.
8041 * @param im the send message that was received
8044 handle_incoming_msg (void *cls,
8045 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8047 struct TransportClient *tc = cls;
8048 struct CommunicatorMessageContext *cmc =
8049 GNUNET_new (struct CommunicatorMessageContext);
8053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8054 "Received message via communicator from peer %s\n",
8055 GNUNET_i2s (&im->sender));
8056 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8061 * Communicator gave us a transport address validation response. Process the
8064 * @param cls a `struct CommunicatorMessageContext` (must call
8065 * #finish_cmc_handling() when done)
8066 * @param fc the message that was received
8069 handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8071 struct CommunicatorMessageContext *cmc = cls;
8072 struct VirtualLink *vl;
8074 struct GNUNET_TIME_Absolute st;
8078 vl = lookup_virtual_link (&cmc->im.sender);
8081 GNUNET_STATISTICS_update (GST_stats,
8082 "# FC dropped: virtual link unknown",
8085 finish_cmc_handling (cmc);
8088 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8089 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8091 /* out of order, drop */
8092 GNUNET_STATISTICS_update (GST_stats,
8093 "# FC dropped: message out of order",
8096 finish_cmc_handling (cmc);
8099 seq = ntohl (fc->seq);
8100 if (seq < vl->last_fc_seq)
8102 /* Wrap-around/reset of other peer; start all counters from zero */
8103 vl->outbound_fc_window_size_used = 0;
8105 vl->last_fc_seq = seq;
8106 vl->last_fc_timestamp = st;
8107 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8108 os = GNUNET_ntohll (fc->outbound_sent);
8109 vl->incoming_fc_window_size_loss =
8110 (int64_t) (os - vl->incoming_fc_window_size_used);
8111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8112 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8113 GNUNET_i2s (&vl->target),
8115 (unsigned long long) vl->outbound_fc_window_size,
8116 (long long) vl->incoming_fc_window_size_loss);
8117 wnd = GNUNET_ntohll (fc->outbound_window_size);
8118 if ((wnd < vl->incoming_fc_window_size) ||
8119 (vl->last_outbound_window_size_received != wnd) ||
8120 (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)
8121 % FC_NO_CHANGE_REPLY_PROBABILITY))
8123 /* Consider re-sending our FC message, as clearly the
8124 other peer's idea of the window is not up-to-date */
8125 consider_sending_fc (vl);
8127 if ((wnd == vl->incoming_fc_window_size) &&
8128 (vl->last_outbound_window_size_received == wnd) &&
8129 (NULL != vl->fc_retransmit_task))
8131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8132 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8133 GNUNET_i2s (&vl->target),
8134 (unsigned long long) wnd);
8135 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8136 vl->fc_retransmit_task = NULL;
8138 vl->last_outbound_window_size_received = wnd;
8139 /* FC window likely increased, check transmission possibilities! */
8140 check_vl_transmission (vl);
8141 finish_cmc_handling (cmc);
8146 * Given an inbound message @a msg from a communicator @a cmc,
8147 * demultiplex it based on the type calling the right handler.
8149 * @param cmc context for demultiplexing
8150 * @param msg message to demultiplex
8153 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8154 const struct GNUNET_MessageHeader *msg)
8156 struct GNUNET_MQ_MessageHandler handlers[] =
8157 { GNUNET_MQ_hd_var_size (fragment_box,
8158 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8159 struct TransportFragmentBoxMessage,
8161 GNUNET_MQ_hd_var_size (reliability_box,
8162 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8163 struct TransportReliabilityBoxMessage,
8165 GNUNET_MQ_hd_var_size (reliability_ack,
8166 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8167 struct TransportReliabilityAckMessage,
8169 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8170 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8171 struct TransportBackchannelEncapsulationMessage,
8173 GNUNET_MQ_hd_var_size (dv_learn,
8174 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8175 struct TransportDVLearnMessage,
8177 GNUNET_MQ_hd_var_size (dv_box,
8178 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8179 struct TransportDVBoxMessage,
8181 GNUNET_MQ_hd_fixed_size (
8182 validation_challenge,
8183 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8184 struct TransportValidationChallengeMessage,
8186 GNUNET_MQ_hd_fixed_size (flow_control,
8187 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8188 struct TransportFlowControlMessage,
8190 GNUNET_MQ_hd_fixed_size (
8191 validation_response,
8192 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8193 struct TransportValidationResponseMessage,
8195 GNUNET_MQ_handler_end () };
8198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8199 "Handling message of type %u with %u bytes\n",
8200 (unsigned int) ntohs (msg->type),
8201 (unsigned int) ntohs (msg->size));
8202 ret = GNUNET_MQ_handle_message (handlers, msg);
8203 if (GNUNET_SYSERR == ret)
8206 GNUNET_SERVICE_client_drop (cmc->tc->client);
8210 if (GNUNET_NO == ret)
8212 /* unencapsulated 'raw' message */
8213 handle_raw_message (&cmc, msg);
8219 * New queue became available. Check message.
8221 * @param cls the client
8222 * @param aqm the send message that was sent
8225 check_add_queue_message (void *cls,
8226 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8228 struct TransportClient *tc = cls;
8230 if (CT_COMMUNICATOR != tc->type)
8233 return GNUNET_SYSERR;
8235 GNUNET_MQ_check_zero_termination (aqm);
8241 * If necessary, generates the UUID for a @a pm
8243 * @param pm pending message to generate UUID for.
8246 set_pending_message_uuid (struct PendingMessage *pm)
8248 if (pm->msg_uuid_set)
8250 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8251 pm->msg_uuid_set = GNUNET_YES;
8256 * Setup data structure waiting for acknowledgements.
8258 * @param queue queue the @a pm will be sent over
8259 * @param dvh path the message will take, may be NULL
8260 * @param pm the pending message for transmission
8261 * @return corresponding fresh pending acknowledgement
8263 static struct PendingAcknowledgement *
8264 prepare_pending_acknowledgement (struct Queue *queue,
8265 struct DistanceVectorHop *dvh,
8266 struct PendingMessage *pm)
8268 struct PendingAcknowledgement *pa;
8270 pa = GNUNET_new (struct PendingAcknowledgement);
8276 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8278 sizeof(pa->ack_uuid));
8280 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8282 &pa->ack_uuid.value,
8284 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8285 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8286 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8288 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8289 pa->transmission_time = GNUNET_TIME_absolute_get ();
8290 pa->message_size = pm->bytes_msg;
8291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8292 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8293 GNUNET_uuid2s (&pa->ack_uuid.value),
8300 * Fragment the given @a pm to the given @a mtu. Adds
8301 * additional fragments to the neighbour as well. If the
8302 * @a mtu is too small, generates and error for the @a pm
8305 * @param queue which queue to fragment for
8306 * @param dvh path the message will take, or NULL
8307 * @param pm pending message to fragment for transmission
8308 * @return new message to transmit
8310 static struct PendingMessage *
8311 fragment_message (struct Queue *queue,
8312 struct DistanceVectorHop *dvh,
8313 struct PendingMessage *pm)
8315 struct PendingAcknowledgement *pa;
8316 struct PendingMessage *ff;
8319 mtu = (0 == queue->mtu)
8320 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
8322 set_pending_message_uuid (pm);
8323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8324 "Fragmenting message %llu <%llu> to %s for MTU %u\n",
8325 (unsigned long long) pm->msg_uuid.uuid,
8327 GNUNET_i2s (&pm->vl->target),
8328 (unsigned int) mtu);
8329 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8331 /* This invariant is established in #handle_add_queue_message() */
8332 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
8334 /* select fragment for transmission, descending the tree if it has
8335 been expanded until we are at a leaf or at a fragment that is small
8339 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
8340 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
8342 ff = ff->head_frag; /* descent into fragmented fragments */
8345 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
8347 /* Did not yet calculate all fragments, calculate next fragment */
8348 struct PendingMessage *frag;
8349 struct TransportFragmentBoxMessage tfb;
8357 orig = (const char *) &ff[1];
8358 msize = ff->bytes_msg;
8361 const struct TransportFragmentBoxMessage *tfbo;
8363 tfbo = (const struct TransportFragmentBoxMessage *) orig;
8364 orig += sizeof(struct TransportFragmentBoxMessage);
8365 msize -= sizeof(struct TransportFragmentBoxMessage);
8366 xoff = ntohs (tfbo->frag_off);
8368 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
8369 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
8371 GNUNET_malloc (sizeof(struct PendingMessage)
8372 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
8373 frag->logging_uuid = logging_uuid_gen++;
8375 frag->frag_parent = ff;
8376 frag->timeout = pm->timeout;
8377 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
8378 frag->pmt = PMT_FRAGMENT_BOX;
8379 msg = (char *) &frag[1];
8380 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
8382 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
8383 tfb.ack_uuid = pa->ack_uuid;
8384 tfb.msg_uuid = pm->msg_uuid;
8385 tfb.frag_off = htons (ff->frag_off + xoff);
8386 tfb.msg_size = htons (pm->bytes_msg);
8387 memcpy (msg, &tfb, sizeof(tfb));
8388 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
8389 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
8390 ff->frag_off += fragsize;
8394 /* Move head to the tail and return it */
8395 GNUNET_CONTAINER_MDLL_remove (frag,
8396 ff->frag_parent->head_frag,
8397 ff->frag_parent->tail_frag,
8399 GNUNET_CONTAINER_MDLL_insert_tail (frag,
8400 ff->frag_parent->head_frag,
8401 ff->frag_parent->tail_frag,
8408 * Reliability-box the given @a pm. On error (can there be any), NULL
8409 * may be returned, otherwise the "replacement" for @a pm (which
8410 * should then be added to the respective neighbour's queue instead of
8411 * @a pm). If the @a pm is already fragmented or reliability boxed,
8412 * or itself an ACK, this function simply returns @a pm.
8414 * @param queue which queue to prepare transmission for
8415 * @param dvh path the message will take, or NULL
8416 * @param pm pending message to box for transmission over unreliabile queue
8417 * @return new message to transmit
8419 static struct PendingMessage *
8420 reliability_box_message (struct Queue *queue,
8421 struct DistanceVectorHop *dvh,
8422 struct PendingMessage *pm)
8424 struct TransportReliabilityBoxMessage rbox;
8425 struct PendingAcknowledgement *pa;
8426 struct PendingMessage *bpm;
8429 if (PMT_CORE != pm->pmt)
8430 return pm; /* already fragmented or reliability boxed, or control message:
8432 if (NULL != pm->bpm)
8433 return pm->bpm; /* already computed earlier: do nothing */
8434 GNUNET_assert (NULL == pm->head_frag);
8435 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
8439 client_send_response (pm);
8442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8443 "Preparing reliability box for message <%llu> to %s on queue %s\n",
8445 GNUNET_i2s (&pm->vl->target),
8447 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8449 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
8451 bpm->logging_uuid = logging_uuid_gen++;
8453 bpm->frag_parent = pm;
8454 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
8455 bpm->timeout = pm->timeout;
8456 bpm->pmt = PMT_RELIABILITY_BOX;
8457 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
8458 set_pending_message_uuid (bpm);
8459 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
8460 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
8461 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
8463 rbox.ack_uuid = pa->ack_uuid;
8464 msg = (char *) &bpm[1];
8465 memcpy (msg, &rbox, sizeof(rbox));
8466 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
8473 * Change the value of the `next_attempt` field of @a pm
8474 * to @a next_attempt and re-order @a pm in the transmission
8475 * list as required by the new timestmap.
8477 * @param pm a pending message to update
8478 * @param next_attempt timestamp to use
8481 update_pm_next_attempt (struct PendingMessage *pm,
8482 struct GNUNET_TIME_Absolute next_attempt)
8484 struct VirtualLink *vl = pm->vl;
8486 pm->next_attempt = next_attempt;
8487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8488 "Next attempt for message <%llu> set to %s\n",
8490 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
8492 if (NULL == pm->frag_parent)
8494 struct PendingMessage *pos;
8496 /* re-insert sort in neighbour list */
8497 GNUNET_CONTAINER_MDLL_remove (vl,
8498 vl->pending_msg_head,
8499 vl->pending_msg_tail,
8501 pos = vl->pending_msg_tail;
8502 while ((NULL != pos) &&
8503 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8505 GNUNET_CONTAINER_MDLL_insert_after (vl,
8506 vl->pending_msg_head,
8507 vl->pending_msg_tail,
8513 /* re-insert sort in fragment list */
8514 struct PendingMessage *fp = pm->frag_parent;
8515 struct PendingMessage *pos;
8517 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
8518 pos = fp->tail_frag;
8519 while ((NULL != pos) &&
8520 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8521 pos = pos->prev_frag;
8522 GNUNET_CONTAINER_MDLL_insert_after (frag,
8532 * Context for #select_best_pending_from_link().
8534 struct PendingMessageScoreContext
8537 * Set to the best message that was found, NULL for none.
8539 struct PendingMessage *best;
8542 * DVH that @e best should take, or NULL for direct transmission.
8544 struct DistanceVectorHop *dvh;
8547 * What is the estimated total overhead for this message?
8549 size_t real_overhead;
8552 * Number of pending messages we seriously considered this time.
8554 unsigned int consideration_counter;
8557 * Did we have to fragment?
8562 * Did we have to reliability box?
8569 * Select the best pending message from @a vl for transmission
8572 * @param sc[in,out] best message so far (NULL for none), plus scoring data
8573 * @param queue the queue that will be used for transmission
8574 * @param vl the virtual link providing the messages
8575 * @param dvh path we are currently considering, or NULL for none
8576 * @param overhead number of bytes of overhead to be expected
8577 * from DV encapsulation (0 for without DV)
8580 select_best_pending_from_link (struct PendingMessageScoreContext *sc,
8581 struct Queue *queue,
8582 struct VirtualLink *vl,
8583 struct DistanceVectorHop *dvh,
8586 struct GNUNET_TIME_Absolute now;
8588 now = GNUNET_TIME_absolute_get ();
8589 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
8592 size_t real_overhead = overhead;
8596 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
8597 continue; /* DV messages must not be DV-routed to next hop! */
8598 if (pos->next_attempt.abs_value_us > now.abs_value_us)
8599 break; /* too early for all messages, they are sorted by next_attempt */
8600 if (NULL != pos->qe)
8601 continue; /* not eligible */
8602 sc->consideration_counter++;
8603 /* determine if we have to fragment, if so add fragmentation
8606 if (((0 != queue->mtu) &&
8607 (pos->bytes_msg + real_overhead > queue->mtu)) ||
8608 (pos->bytes_msg > UINT16_MAX - sizeof(struct
8609 GNUNET_TRANSPORT_SendMessageTo))
8611 (NULL != pos->head_frag /* fragments already exist, should
8612 respect that even if MTU is 0 for
8616 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
8618 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
8619 header without the ACK UUID when using a *reliable* channel! */
8621 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
8623 /* determine if we have to reliability-box, if so add reliability box
8626 if ((GNUNET_NO == frag) &&
8627 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
8628 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
8631 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
8634 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
8635 message would beat it! */
8636 if (NULL != sc->best)
8638 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
8639 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
8640 experimentally validated. There may be some huge potential for
8641 improvement here. Also, we right now only compare how well the
8642 given message fits _this_ queue, and do not consider how well other
8643 queues might suit the message. Taking other queues into consideration
8644 may further improve the result, but could also be expensive
8645 in terms of CPU time. */long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
8646 long long pm_score = frag * 40 + relb * 20 + real_overhead;
8647 long long time_delta =
8648 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
8651 /* "time_delta" considers which message has been 'ready' for transmission
8652 for longer, if a message has a preference for low latency, increase
8653 the weight of the time_delta by 10x if it is favorable for that message */
8654 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8655 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
8656 time_delta *= 10; /* increase weight (always, both are low latency) */
8657 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8660 10; /* increase weight, favors 'pos', which is low latency */
8661 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8664 10; /* increase weight, favors 'sc->best', which is low latency */
8665 if (0 != queue->mtu)
8667 /* Grant bonus if we are bellow MTU, larger bonus the closer we will
8669 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
8670 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
8671 if (queue->mtu > real_overhead + pos->bytes_msg)
8672 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
8674 if (sc_score + time_delta > pm_score)
8675 continue; /* sc_score larger, keep sc->best */
8686 * Function to call to further operate on the now DV encapsulated
8687 * message @a hdr, forwarding it via @a next_hop under respect of
8690 * @param cls a `struct PendingMessageScoreContext`
8691 * @param next_hop next hop of the DV path
8692 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
8693 * @param options options of the original message
8696 extract_box_cb (void *cls,
8697 struct Neighbour *next_hop,
8698 const struct GNUNET_MessageHeader *hdr,
8699 enum RouteMessageOptions options)
8701 struct PendingMessageScoreContext *sc = cls;
8702 struct PendingMessage *pm = sc->best;
8703 struct PendingMessage *bpm;
8704 uint16_t bsize = ntohs (hdr->size);
8706 GNUNET_assert (NULL == pm->bpm);
8707 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
8708 bpm->logging_uuid = logging_uuid_gen++;
8709 bpm->pmt = PMT_DV_BOX;
8710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8711 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
8714 GNUNET_i2s (&next_hop->pid));
8715 memcpy (&bpm[1], hdr, bsize);
8721 * We believe we are ready to transmit a `struct PendingMessage` on a
8722 * queue, the big question is which one! We need to see if there is
8723 * one pending that is allowed by flow control and congestion control
8724 * and (ideally) matches our queue's performance profile.
8726 * If such a message is found, we give the message to the communicator
8727 * for transmission (updating the tracker, and re-scheduling ourselves
8730 * If no such message is found, the queue's `idle` field must be set
8733 * @param cls the `struct Queue` to process transmissions for
8736 transmit_on_queue (void *cls)
8738 struct Queue *queue = cls;
8739 struct Neighbour *n = queue->neighbour;
8740 struct PendingMessageScoreContext sc;
8741 struct PendingMessage *pm;
8743 queue->transmit_task = NULL;
8746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8747 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
8748 GNUNET_i2s (&n->pid),
8750 queue->idle = GNUNET_YES;
8753 memset (&sc, 0, sizeof(sc));
8754 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
8755 if (NULL == sc.best)
8757 /* Also look at DVH that have the n as first hop! */
8758 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
8759 dvh = dvh->next_neighbour)
8761 select_best_pending_from_link (&sc,
8765 sizeof(struct GNUNET_PeerIdentity)
8766 * (1 + dvh->distance)
8767 + sizeof(struct TransportDVBoxMessage)
8768 + sizeof(struct TransportDVBoxPayloadP));
8771 if (NULL == sc.best)
8773 /* no message pending, nothing to do here! */
8774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8775 "No pending messages, queue `%s' to %s now idle\n",
8777 GNUNET_i2s (&n->pid));
8778 queue->idle = GNUNET_YES;
8782 /* Given selection in `sc`, do transmission */
8786 GNUNET_assert (PMT_DV_BOX != pm->pmt);
8787 if (NULL != sc.best->bpm)
8789 /* We did this boxing before, but possibly for a different path!
8790 Discard old DV box! OPTIMIZE-ME: we might want to check if
8791 it is the same and then not re-build the message... */
8792 free_pending_message (sc.best->bpm);
8793 sc.best->bpm = NULL;
8795 encapsulate_for_dv (sc.dvh->dv,
8798 (const struct GNUNET_MessageHeader *) &sc.best[1],
8802 GNUNET_assert (NULL != sc.best->bpm);
8805 if (GNUNET_YES == sc.frag)
8807 pm = fragment_message (queue, sc.dvh, pm);
8810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8811 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
8813 GNUNET_i2s (&n->pid),
8814 sc.best->logging_uuid);
8815 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8819 else if (GNUNET_YES == sc.relb)
8821 pm = reliability_box_message (queue, sc.dvh, pm);
8824 /* Reliability boxing failed, try next message... */
8826 GNUNET_ERROR_TYPE_DEBUG,
8827 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
8829 GNUNET_i2s (&n->pid),
8830 sc.best->logging_uuid);
8831 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8836 /* Pass 'pm' for transission to the communicator */
8838 GNUNET_ERROR_TYPE_DEBUG,
8839 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
8842 GNUNET_i2s (&n->pid),
8843 sc.consideration_counter);
8845 /* Flow control: increment amount of traffic sent; if we are routing
8846 via DV (and thus the ultimate target of the pending message is for
8847 a different virtual link than the one of the queue), then we need
8848 to use up not only the window of the direct link but also the
8849 flow control window for the DV link! */pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
8851 if (pm->vl != queue->neighbour->vl)
8853 /* If the virtual link of the queue differs, this better be distance
8855 GNUNET_assert (NULL != sc.dvh);
8856 /* If we do distance vector routing, we better not do this for a
8857 message that was itself DV-routed */
8858 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
8859 /* We use the size of the unboxed message here, to avoid counting
8860 the DV-Box header which is eaten up on the way by intermediaries */
8861 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
8865 GNUNET_assert (NULL == sc.dvh);
8868 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
8870 /* Check if this transmission somehow conclusively finished handing 'pm'
8871 even without any explicit ACKs */
8872 if ((PMT_CORE == pm->pmt) ||
8873 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
8875 completed_pending_message (pm);
8879 /* Message not finished, waiting for acknowledgement.
8880 Update time by which we might retransmit 's' based on queue
8881 characteristics (i.e. RTT); it takes one RTT for the message to
8882 arrive and the ACK to come back in the best case; but the other
8883 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
8886 OPTIMIZE: Note that in the future this heuristic should likely
8887 be improved further (measure RTT stability, consider message
8888 urgency and size when delaying ACKs, etc.) */update_pm_next_attempt (pm,
8889 GNUNET_TIME_relative_to_absolute (
8890 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
8893 /* finally, re-schedule queue transmission task itself */
8894 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8899 * Queue to a peer went down. Process the request.
8901 * @param cls the client
8902 * @param dqm the send message that was sent
8905 handle_del_queue_message (void *cls,
8906 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
8908 struct TransportClient *tc = cls;
8910 if (CT_COMMUNICATOR != tc->type)
8913 GNUNET_SERVICE_client_drop (tc->client);
8916 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8917 queue = queue->next_client)
8919 struct Neighbour *neighbour = queue->neighbour;
8921 if ((dqm->qid != queue->qid) ||
8922 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
8924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8925 "Dropped queue %s to peer %s\n",
8927 GNUNET_i2s (&neighbour->pid));
8929 GNUNET_SERVICE_client_continue (tc->client);
8933 GNUNET_SERVICE_client_drop (tc->client);
8938 * Message was transmitted. Process the request.
8940 * @param cls the client
8941 * @param sma the send message that was sent
8944 handle_send_message_ack (void *cls,
8945 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
8947 struct TransportClient *tc = cls;
8948 struct QueueEntry *qe;
8949 struct PendingMessage *pm;
8951 if (CT_COMMUNICATOR != tc->type)
8954 GNUNET_SERVICE_client_drop (tc->client);
8958 /* find our queue entry matching the ACK */
8960 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8961 queue = queue->next_client)
8963 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
8965 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
8968 if (qep->mid != sma->mid)
8977 /* this should never happen */
8979 GNUNET_SERVICE_client_drop (tc->client);
8982 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
8983 qe->queue->queue_tail,
8985 qe->queue->queue_length--;
8986 tc->details.communicator.total_queue_length--;
8987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8988 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
8990 GNUNET_i2s (&qe->queue->neighbour->pid),
8991 qe->queue->queue_length,
8992 tc->details.communicator.total_queue_length);
8993 GNUNET_SERVICE_client_continue (tc->client);
8995 /* if applicable, resume transmissions that waited on ACK */
8996 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
8997 tc->details.communicator.total_queue_length)
8999 /* Communicator dropped below threshold, resume all queues
9000 incident with this client! */
9001 GNUNET_STATISTICS_update (
9003 "# Transmission throttled due to communicator queue limit",
9006 for (struct Queue *queue = tc->details.communicator.queue_head;
9008 queue = queue->next_client)
9009 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9011 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9013 /* queue dropped below threshold; only resume this one queue */
9014 GNUNET_STATISTICS_update (GST_stats,
9015 "# Transmission throttled due to queue queue limit",
9018 schedule_transmit_on_queue (qe->queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9021 if (NULL != (pm = qe->pm))
9023 struct VirtualLink *vl;
9025 GNUNET_assert (qe == pm->qe);
9027 /* If waiting for this communicator may have blocked transmission
9028 of pm on other queues for this neighbour, force schedule
9029 transmit on queue for queues of the neighbour */
9031 if (vl->pending_msg_head == pm)
9032 check_vl_transmission (vl);
9039 * Iterator telling new MONITOR client about all existing
9042 * @param cls the new `struct TransportClient`
9043 * @param pid a connected peer
9044 * @param value the `struct Neighbour` with more information
9045 * @return #GNUNET_OK (continue to iterate)
9048 notify_client_queues (void *cls,
9049 const struct GNUNET_PeerIdentity *pid,
9052 struct TransportClient *tc = cls;
9053 struct Neighbour *neighbour = value;
9055 GNUNET_assert (CT_MONITOR == tc->type);
9056 for (struct Queue *q = neighbour->queue_head; NULL != q;
9057 q = q->next_neighbour)
9059 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
9061 .num_msg_pending = q->num_msg_pending,
9062 .num_bytes_pending = q->num_bytes_pending };
9064 notify_monitor (tc, pid, q->address, q->nt, &me);
9071 * Initialize a monitor client.
9073 * @param cls the client
9074 * @param start the start message that was sent
9077 handle_monitor_start (void *cls,
9078 const struct GNUNET_TRANSPORT_MonitorStart *start)
9080 struct TransportClient *tc = cls;
9082 if (CT_NONE != tc->type)
9085 GNUNET_SERVICE_client_drop (tc->client);
9088 tc->type = CT_MONITOR;
9089 tc->details.monitor.peer = start->peer;
9090 tc->details.monitor.one_shot = ntohl (start->one_shot);
9091 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
9092 GNUNET_SERVICE_client_mark_monitor (tc->client);
9093 GNUNET_SERVICE_client_continue (tc->client);
9098 * Find transport client providing communication service
9099 * for the protocol @a prefix.
9101 * @param prefix communicator name
9102 * @return NULL if no such transport client is available
9104 static struct TransportClient *
9105 lookup_communicator (const char *prefix)
9107 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
9109 if (CT_COMMUNICATOR != tc->type)
9111 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
9115 GNUNET_ERROR_TYPE_WARNING,
9116 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
9123 * Signature of a function called with a communicator @a address of a peer
9124 * @a pid that an application wants us to connect to.
9126 * @param pid target peer
9127 * @param address the address to try
9130 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
9132 static uint32_t idgen;
9133 struct TransportClient *tc;
9135 struct GNUNET_TRANSPORT_CreateQueue *cqm;
9136 struct GNUNET_MQ_Envelope *env;
9139 prefix = GNUNET_HELLO_address_to_prefix (address);
9142 GNUNET_break (0); /* We got an invalid address!? */
9145 tc = lookup_communicator (prefix);
9148 GNUNET_STATISTICS_update (GST_stats,
9149 "# Suggestions ignored due to missing communicator",
9152 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9153 "Cannot connect to %s at `%s', no matching communicator present\n",
9156 GNUNET_free (prefix);
9159 /* forward suggestion for queue creation to communicator */
9160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9161 "Request #%u for `%s' communicator to create queue to `%s'\n",
9162 (unsigned int) idgen,
9165 GNUNET_free (prefix);
9166 alen = strlen (address) + 1;
9168 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
9169 cqm->request_id = htonl (idgen++);
9170 cqm->receiver = *pid;
9171 memcpy (&cqm[1], address, alen);
9172 GNUNET_MQ_send (tc->mq, env);
9177 * The queue @a q (which matches the peer and address in @a vs) is
9178 * ready for queueing. We should now queue the validation request.
9180 * @param q queue to send on
9181 * @param vs state to derive validation challenge from
9184 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
9186 struct TransportValidationChallengeMessage tvc;
9188 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
9190 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
9191 tvc.header.size = htons (sizeof(tvc));
9192 tvc.reserved = htonl (0);
9193 tvc.challenge = vs->challenge;
9194 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
9195 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9196 "Sending address validation challenge %s to %s\n",
9197 GNUNET_sh2s (&tvc.challenge.value),
9198 GNUNET_i2s (&q->neighbour->pid));
9199 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
9204 * Task run periodically to validate some address based on #validation_heap.
9209 validation_start_cb (void *cls)
9211 struct ValidationState *vs;
9215 validation_task = NULL;
9216 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9217 /* drop validations past their expiration */
9220 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
9222 free_validation_state (vs);
9223 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9227 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9228 "Address validation task not scheduled anymore, nothing to do\n");
9229 return; /* woopsie, no more addresses known, should only
9230 happen if we're really a lonely peer */
9232 q = find_queue (&vs->pid, vs->address);
9235 vs->awaiting_queue = GNUNET_YES;
9236 suggest_to_connect (&vs->pid, vs->address);
9239 validation_transmit_on_queue (q, vs);
9240 /* Finally, reschedule next attempt */
9241 vs->challenge_backoff =
9242 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
9243 MAX_VALIDATION_CHALLENGE_FREQ);
9244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9245 "Address validation task will run again in %s\n",
9246 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
9248 update_next_challenge_time (vs,
9249 GNUNET_TIME_relative_to_absolute (
9250 vs->challenge_backoff));
9255 * Closure for #check_connection_quality.
9257 struct QueueQualityContext
9260 * Set to the @e k'th queue encountered.
9265 * Set to the number of quality queues encountered.
9267 unsigned int quality_count;
9270 * Set to the total number of queues encountered.
9272 unsigned int num_queues;
9275 * Decremented for each queue, for selection of the
9276 * k-th queue in @e q.
9283 * Check whether any queue to the given neighbour is
9284 * of a good "quality" and if so, increment the counter.
9285 * Also counts the total number of queues, and returns
9286 * the k-th queue found.
9288 * @param cls a `struct QueueQualityContext *` with counters
9289 * @param pid peer this is about
9290 * @param value a `struct Neighbour`
9291 * @return #GNUNET_OK (continue to iterate)
9294 check_connection_quality (void *cls,
9295 const struct GNUNET_PeerIdentity *pid,
9298 struct QueueQualityContext *ctx = cls;
9299 struct Neighbour *n = value;
9304 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9309 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
9310 statistics and consider those as well here? */
9311 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
9312 do_inc = GNUNET_YES;
9314 if (GNUNET_YES == do_inc)
9315 ctx->quality_count++;
9321 * Task run when we CONSIDER initiating a DV learn
9322 * process. We first check that sending out a message is
9323 * even possible (queues exist), then that it is desirable
9324 * (if not, reschedule the task for later), and finally
9325 * we may then begin the job. If there are too many
9326 * entries in the #dvlearn_map, we purge the oldest entry
9332 start_dv_learn (void *cls)
9334 struct LearnLaunchEntry *lle;
9335 struct QueueQualityContext qqc;
9336 struct TransportDVLearnMessage dvl;
9339 dvlearn_task = NULL;
9340 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
9341 return; /* lost all connectivity, cannot do learning */
9342 qqc.quality_count = 0;
9344 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9345 &check_connection_quality,
9347 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
9349 struct GNUNET_TIME_Relative delay;
9350 unsigned int factor;
9352 /* scale our retries by how far we are above the threshold */
9353 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
9354 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
9355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9356 "At connection quality %u, will launch DV learn in %s\n",
9358 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
9359 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
9362 /* remove old entries in #dvlearn_map if it has grown too big */
9363 while (MAX_DV_LEARN_PENDING >=
9364 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
9367 GNUNET_assert (GNUNET_YES ==
9368 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
9369 &lle->challenge.value,
9371 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9374 /* setup data structure for learning */
9375 lle = GNUNET_new (struct LearnLaunchEntry);
9376 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9378 sizeof(lle->challenge));
9379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9380 "Starting launch DV learn with challenge %s\n",
9381 GNUNET_sh2s (&lle->challenge.value));
9382 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
9383 GNUNET_break (GNUNET_YES ==
9384 GNUNET_CONTAINER_multishortmap_put (
9386 &lle->challenge.value,
9388 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9389 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
9390 dvl.header.size = htons (sizeof(dvl));
9391 dvl.num_hops = htons (0);
9392 dvl.bidirectional = htons (0);
9393 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
9394 dvl.monotonic_time =
9395 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
9397 struct DvInitPS dvip = {
9398 .purpose.purpose = htonl (
9399 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
9400 .purpose.size = htonl (sizeof(dvip)),
9401 .monotonic_time = dvl.monotonic_time,
9402 .challenge = lle->challenge
9405 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9409 dvl.initiator = GST_my_identity;
9410 dvl.challenge = lle->challenge;
9412 qqc.quality_count = 0;
9413 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
9416 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9417 &check_connection_quality,
9419 GNUNET_assert (NULL != qqc.q);
9421 /* Do this as close to transmission time as possible! */
9422 lle->launch_time = GNUNET_TIME_absolute_get ();
9424 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
9425 /* reschedule this job, randomizing the time it runs (but no
9427 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
9428 DV_LEARN_BASE_FREQUENCY),
9435 * A new queue has been created, check if any address validation
9436 * requests have been waiting for it.
9438 * @param cls a `struct Queue`
9439 * @param pid peer concerned (unused)
9440 * @param value a `struct ValidationState`
9441 * @return #GNUNET_NO if a match was found and we can stop looking
9444 check_validation_request_pending (void *cls,
9445 const struct GNUNET_PeerIdentity *pid,
9448 struct Queue *q = cls;
9449 struct ValidationState *vs = value;
9452 if ((GNUNET_YES == vs->awaiting_queue) &&
9453 (0 == strcmp (vs->address, q->address)))
9455 vs->awaiting_queue = GNUNET_NO;
9456 validation_transmit_on_queue (q, vs);
9464 * Function called with the monotonic time of a DV initiator
9465 * by PEERSTORE. Updates the time.
9467 * @param cls a `struct Neighbour`
9468 * @param record the information found, NULL for the last call
9469 * @param emsg error message
9472 neighbour_dv_monotime_cb (void *cls,
9473 const struct GNUNET_PEERSTORE_Record *record,
9476 struct Neighbour *n = cls;
9477 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9482 /* we're done with #neighbour_dv_monotime_cb() invocations,
9483 continue normal processing */
9485 n->dv_monotime_available = GNUNET_YES;
9488 if (sizeof(*mtbe) != record->value_size)
9493 mtbe = record->value;
9494 n->last_dv_learn_monotime =
9495 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
9496 GNUNET_TIME_absolute_ntoh (*mtbe));
9501 * New queue became available. Process the request.
9503 * @param cls the client
9504 * @param aqm the send message that was sent
9507 handle_add_queue_message (void *cls,
9508 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9510 struct TransportClient *tc = cls;
9511 struct Queue *queue;
9512 struct Neighbour *neighbour;
9516 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
9518 /* MTU so small as to be useless for transmissions,
9519 required for #fragment_message()! */
9520 GNUNET_break_op (0);
9521 GNUNET_SERVICE_client_drop (tc->client);
9524 neighbour = lookup_neighbour (&aqm->receiver);
9525 if (NULL == neighbour)
9527 neighbour = GNUNET_new (struct Neighbour);
9528 neighbour->pid = aqm->receiver;
9529 GNUNET_assert (GNUNET_OK ==
9530 GNUNET_CONTAINER_multipeermap_put (
9534 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9536 GNUNET_PEERSTORE_iterate (peerstore,
9539 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
9540 &neighbour_dv_monotime_cb,
9543 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
9544 addr = (const char *) &aqm[1];
9545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9546 "New queue %s to %s available with QID %llu\n",
9548 GNUNET_i2s (&aqm->receiver),
9549 (unsigned long long) aqm->qid);
9550 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
9552 queue->address = (const char *) &queue[1];
9553 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
9554 queue->qid = aqm->qid;
9555 queue->mtu = ntohl (aqm->mtu);
9556 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
9557 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
9558 queue->neighbour = neighbour;
9559 queue->idle = GNUNET_YES;
9560 memcpy (&queue[1], addr, addr_len);
9561 /* notify monitors about new queue */
9563 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
9565 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
9567 GNUNET_CONTAINER_MDLL_insert (neighbour,
9568 neighbour->queue_head,
9569 neighbour->queue_tail,
9571 GNUNET_CONTAINER_MDLL_insert (client,
9572 tc->details.communicator.queue_head,
9573 tc->details.communicator.queue_tail,
9575 /* check if valdiations are waiting for the queue */
9577 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9579 &check_validation_request_pending,
9581 /* look for traffic for this queue */
9582 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9583 /* might be our first queue, try launching DV learning */
9584 if (NULL == dvlearn_task)
9585 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
9586 GNUNET_SERVICE_client_continue (tc->client);
9591 * Communicator tells us that our request to create a queue "worked", that
9592 * is setting up the queue is now in process.
9594 * @param cls the `struct TransportClient`
9595 * @param cqr confirmation message
9598 handle_queue_create_ok (void *cls,
9599 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9601 struct TransportClient *tc = cls;
9603 if (CT_COMMUNICATOR != tc->type)
9606 GNUNET_SERVICE_client_drop (tc->client);
9609 GNUNET_STATISTICS_update (GST_stats,
9610 "# Suggestions succeeded at communicator",
9613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9614 "Request #%u for communicator to create queue succeeded\n",
9615 (unsigned int) ntohs (cqr->request_id));
9616 GNUNET_SERVICE_client_continue (tc->client);
9621 * Communicator tells us that our request to create a queue failed. This
9622 * usually indicates that the provided address is simply invalid or that the
9623 * communicator's resources are exhausted.
9625 * @param cls the `struct TransportClient`
9626 * @param cqr failure message
9629 handle_queue_create_fail (
9631 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9633 struct TransportClient *tc = cls;
9635 if (CT_COMMUNICATOR != tc->type)
9638 GNUNET_SERVICE_client_drop (tc->client);
9641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9642 "Request #%u for communicator to create queue failed\n",
9643 (unsigned int) ntohs (cqr->request_id));
9644 GNUNET_STATISTICS_update (GST_stats,
9645 "# Suggestions failed in queue creation at communicator",
9648 GNUNET_SERVICE_client_continue (tc->client);
9653 * We have received a `struct ExpressPreferenceMessage` from an application
9656 * @param cls handle to the client
9657 * @param msg the start message
9660 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
9662 struct TransportClient *tc = cls;
9663 struct PeerRequest *pr;
9665 if (CT_APPLICATION != tc->type)
9668 GNUNET_SERVICE_client_drop (tc->client);
9671 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
9676 GNUNET_SERVICE_client_drop (tc->client);
9679 (void) stop_peer_request (tc, &pr->pid, pr);
9680 GNUNET_SERVICE_client_continue (tc->client);
9685 * Function called by PEERSTORE for each matching record.
9687 * @param cls closure, a `struct PeerRequest`
9688 * @param record peerstore record information
9689 * @param emsg error message, or NULL if no errors
9692 handle_hello_for_client (void *cls,
9693 const struct GNUNET_PEERSTORE_Record *record,
9696 struct PeerRequest *pr = cls;
9701 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9702 "Got failure from PEERSTORE: %s\n",
9706 val = record->value;
9707 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
9712 start_address_validation (&pr->pid, (const char *) record->value);
9717 * We have received a `struct ExpressPreferenceMessage` from an application
9720 * @param cls handle to the client
9721 * @param msg the start message
9724 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9726 struct TransportClient *tc = cls;
9727 struct PeerRequest *pr;
9729 if (CT_NONE == tc->type)
9731 tc->type = CT_APPLICATION;
9732 tc->details.application.requests =
9733 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9735 if (CT_APPLICATION != tc->type)
9738 GNUNET_SERVICE_client_drop (tc->client);
9741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9742 "Client suggested we talk to %s with preference %d at rate %u\n",
9743 GNUNET_i2s (&msg->peer),
9744 (int) ntohl (msg->pk),
9745 (int) ntohl (msg->bw.value__));
9746 pr = GNUNET_new (struct PeerRequest);
9748 pr->pid = msg->peer;
9750 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
9751 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
9752 tc->details.application.requests,
9755 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
9759 GNUNET_SERVICE_client_drop (tc->client);
9762 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
9765 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9766 &handle_hello_for_client,
9768 GNUNET_SERVICE_client_continue (tc->client);
9773 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
9776 * @param cls a `struct TransportClient *`
9777 * @param m message to verify
9778 * @return #GNUNET_OK on success
9781 check_request_hello_validation (void *cls,
9782 const struct RequestHelloValidationMessage *m)
9785 GNUNET_MQ_check_zero_termination (m);
9791 * A client encountered an address of another peer. Consider validating it,
9792 * and if validation succeeds, persist it to PEERSTORE.
9794 * @param cls a `struct TransportClient *`
9795 * @param m message to verify
9798 handle_request_hello_validation (void *cls,
9799 const struct RequestHelloValidationMessage *m)
9801 struct TransportClient *tc = cls;
9803 start_address_validation (&m->peer, (const char *) &m[1]);
9804 GNUNET_SERVICE_client_continue (tc->client);
9809 * Free neighbour entry.
9813 * @param value a `struct Neighbour`
9814 * @return #GNUNET_OK (always)
9817 free_neighbour_cb (void *cls,
9818 const struct GNUNET_PeerIdentity *pid,
9821 struct Neighbour *neighbour = value;
9825 GNUNET_break (0); // should this ever happen?
9826 free_neighbour (neighbour);
9833 * Free DV route entry.
9837 * @param value a `struct DistanceVector`
9838 * @return #GNUNET_OK (always)
9841 free_dv_routes_cb (void *cls,
9842 const struct GNUNET_PeerIdentity *pid,
9845 struct DistanceVector *dv = value;
9856 * Free validation state.
9860 * @param value a `struct ValidationState`
9861 * @return #GNUNET_OK (always)
9864 free_validation_state_cb (void *cls,
9865 const struct GNUNET_PeerIdentity *pid,
9868 struct ValidationState *vs = value;
9872 free_validation_state (vs);
9878 * Free pending acknowledgement.
9882 * @param value a `struct PendingAcknowledgement`
9883 * @return #GNUNET_OK (always)
9886 free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
9888 struct PendingAcknowledgement *pa = value;
9892 free_pending_acknowledgement (pa);
9898 * Free acknowledgement cummulator.
9902 * @param value a `struct AcknowledgementCummulator`
9903 * @return #GNUNET_OK (always)
9906 free_ack_cummulator_cb (void *cls,
9907 const struct GNUNET_PeerIdentity *pid,
9910 struct AcknowledgementCummulator *ac = value;
9920 * Function called when the service shuts down. Unloads our plugins
9921 * and cancels pending validations.
9923 * @param cls closure, unused
9926 do_shutdown (void *cls)
9928 struct LearnLaunchEntry *lle;
9932 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9933 if (NULL != peerstore)
9935 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9938 if (NULL != GST_stats)
9940 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9943 if (NULL != GST_my_private_key)
9945 GNUNET_free (GST_my_private_key);
9946 GST_my_private_key = NULL;
9948 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9949 &free_ack_cummulator_cb,
9951 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9952 ack_cummulators = NULL;
9953 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
9954 &free_pending_ack_cb,
9956 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
9957 pending_acks = NULL;
9958 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9959 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9961 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9962 GNUNET_CONTAINER_multipeermap_destroy (links);
9964 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9965 &free_backtalker_cb,
9967 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9969 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9970 &free_validation_state_cb,
9972 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9973 validation_map = NULL;
9974 while (NULL != ir_head)
9975 free_incoming_request (ir_head);
9976 GNUNET_assert (0 == ir_total);
9977 while (NULL != (lle = lle_head))
9979 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9982 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
9984 GNUNET_CONTAINER_heap_destroy (validation_heap);
9985 validation_heap = NULL;
9986 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
9987 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
9993 * Initiate transport service.
9995 * @param cls closure
9996 * @param c configuration to use
9997 * @param service the initialized service
10001 const struct GNUNET_CONFIGURATION_Handle *c,
10002 struct GNUNET_SERVICE_Handle *service)
10006 /* setup globals */
10007 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
10009 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10010 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
10011 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
10012 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10013 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
10014 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10015 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
10017 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10019 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
10020 GST_my_private_key =
10021 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
10022 if (NULL == GST_my_private_key)
10025 GNUNET_ERROR_TYPE_ERROR,
10027 "Transport service is lacking key configuration settings. Exiting.\n"));
10028 GNUNET_SCHEDULER_shutdown ();
10031 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
10032 &GST_my_identity.public_key);
10033 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10034 "My identity is `%s'\n",
10035 GNUNET_i2s_full (&GST_my_identity));
10036 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
10037 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
10038 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
10039 if (NULL == peerstore)
10042 GNUNET_SCHEDULER_shutdown ();
10049 * Define "main" method using service macro.
10051 GNUNET_SERVICE_MAIN (
10053 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
10055 &client_connect_cb,
10056 &client_disconnect_cb,
10058 /* communication with applications */
10059 GNUNET_MQ_hd_fixed_size (suggest,
10060 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
10061 struct ExpressPreferenceMessage,
10063 GNUNET_MQ_hd_fixed_size (suggest_cancel,
10064 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
10065 struct ExpressPreferenceMessage,
10067 GNUNET_MQ_hd_var_size (request_hello_validation,
10068 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
10069 struct RequestHelloValidationMessage,
10071 /* communication with core */
10072 GNUNET_MQ_hd_fixed_size (client_start,
10073 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
10074 struct StartMessage,
10076 GNUNET_MQ_hd_var_size (client_send,
10077 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
10078 struct OutboundMessage,
10080 GNUNET_MQ_hd_fixed_size (client_recv_ok,
10081 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
10082 struct RecvOkMessage,
10084 /* communication with communicators */
10085 GNUNET_MQ_hd_var_size (communicator_available,
10086 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
10087 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
10089 GNUNET_MQ_hd_var_size (communicator_backchannel,
10090 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
10091 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
10093 GNUNET_MQ_hd_var_size (add_address,
10094 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
10095 struct GNUNET_TRANSPORT_AddAddressMessage,
10097 GNUNET_MQ_hd_fixed_size (del_address,
10098 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
10099 struct GNUNET_TRANSPORT_DelAddressMessage,
10101 GNUNET_MQ_hd_var_size (incoming_msg,
10102 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
10103 struct GNUNET_TRANSPORT_IncomingMessage,
10105 GNUNET_MQ_hd_fixed_size (queue_create_ok,
10106 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
10107 struct GNUNET_TRANSPORT_CreateQueueResponse,
10109 GNUNET_MQ_hd_fixed_size (queue_create_fail,
10110 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
10111 struct GNUNET_TRANSPORT_CreateQueueResponse,
10113 GNUNET_MQ_hd_var_size (add_queue_message,
10114 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
10115 struct GNUNET_TRANSPORT_AddQueueMessage,
10117 GNUNET_MQ_hd_fixed_size (del_queue_message,
10118 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
10119 struct GNUNET_TRANSPORT_DelQueueMessage,
10121 GNUNET_MQ_hd_fixed_size (send_message_ack,
10122 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
10123 struct GNUNET_TRANSPORT_SendMessageToAck,
10125 /* communication with monitors */
10126 GNUNET_MQ_hd_fixed_size (monitor_start,
10127 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
10128 struct GNUNET_TRANSPORT_MonitorStart,
10130 GNUNET_MQ_handler_end ());
10133 /* end of file gnunet-service-transport.c */