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
369 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
371 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
374 * How long is this signature over the ephemeral key valid?
376 * Note that the receiver MUST IGNORE the absolute time, and only interpret
377 * the value as a mononic time and reject "older" values than the last one
378 * observed. This is necessary as we do not want to require synchronized
379 * clocks and may not have a bidirectional communication channel.
381 * Even with this, there is no real guarantee against replay achieved here,
382 * unless the latest timestamp is persisted. While persistence should be
383 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
384 * communicators must protect against replay attacks when using backchannel
387 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
390 * Target's peer identity.
392 struct GNUNET_PeerIdentity target;
395 * Ephemeral key setup by the sender for @e target, used
396 * to encrypt the payload.
398 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
403 * Plaintext of the variable-size payload that is encrypted
404 * within a `struct TransportBackchannelEncapsulationMessage`
406 struct TransportDVBoxPayloadP
410 * Sender's peer identity.
412 struct GNUNET_PeerIdentity sender;
415 * Signature of the sender over an
416 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
418 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
421 * Current monotonic time of the sending transport service. Used to
422 * detect replayed messages. Note that the receiver should remember
423 * a list of the recently seen timestamps and only reject messages
424 * if the timestamp is in the list, or the list is "full" and the
425 * timestamp is smaller than the lowest in the list.
427 * Like the @e ephemeral_validity, the list of timestamps per peer should be
428 * persisted to guard against replays after restarts.
430 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
432 /* Followed by a `struct GNUNET_MessageHeader` with a message
433 for the target peer */
438 * Outer layer of an encapsulated unfragmented application message sent
439 * over an unreliable channel.
441 struct TransportReliabilityBoxMessage
444 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
446 struct GNUNET_MessageHeader header;
449 * Number of messages still to be sent before a commulative
450 * ACK is requested. Zero if an ACK is requested immediately.
451 * In NBO. Note that the receiver may send the ACK faster
452 * if it believes that is reasonable.
454 uint32_t ack_countdown GNUNET_PACKED;
457 * Unique ID of the message used for signalling receipt of
458 * messages sent over possibly unreliable channels. Should
461 struct AcknowledgementUUIDP ack_uuid;
466 * Acknowledgement payload.
468 struct TransportCummulativeAckPayloadP
471 * How long was the ACK delayed for generating cummulative ACKs?
472 * Used to calculate the correct network RTT by taking the receipt
473 * time of the ack minus the transmission time of the sender minus
476 struct GNUNET_TIME_RelativeNBO ack_delay;
479 * UUID of a message being acknowledged.
481 struct AcknowledgementUUIDP ack_uuid;
486 * Confirmation that the receiver got a
487 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
488 * confirmation may be transmitted over a completely different queue,
489 * so ACKs are identified by a combination of PID of sender and
490 * message UUID, without the queue playing any role!
492 struct TransportReliabilityAckMessage
495 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
497 struct GNUNET_MessageHeader header;
500 * Counter of ACKs transmitted by the sender to us. Incremented
501 * by one for each ACK, used to detect how many ACKs were lost.
503 uint32_t ack_counter GNUNET_PACKED;
505 /* followed by any number of `struct TransportCummulativeAckPayloadP`
506 messages providing ACKs */
511 * Outer layer of an encapsulated fragmented application message.
513 struct TransportFragmentBoxMessage
516 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
518 struct GNUNET_MessageHeader header;
521 * Offset of this fragment in the overall message.
523 uint16_t frag_off GNUNET_PACKED;
526 * Total size of the message that is being fragmented.
528 uint16_t msg_size GNUNET_PACKED;
531 * Unique ID of this fragment (and fragment transmission!). Will
532 * change even if a fragement is retransmitted to make each
533 * transmission attempt unique! If a client receives a duplicate
534 * fragment (same @e frag_off for same @a msg_uuid, it must send
535 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
537 struct AcknowledgementUUIDP ack_uuid;
540 * Original message ID for of the message that all the fragments
541 * belong to. Must be the same for all fragments.
543 struct MessageUUIDP msg_uuid;
548 * Content signed by the initator during DV learning.
550 * The signature is required to prevent DDoS attacks. A peer sending out this
551 * message is potentially generating a lot of traffic that will go back to the
552 * initator, as peers receiving this message will try to let the initiator
553 * know that they got the message.
555 * Without this signature, an attacker could abuse this mechanism for traffic
556 * amplification, sending a lot of traffic to a peer by putting out this type
557 * of message with the victim's peer identity.
559 * Even with just a signature, traffic amplification would be possible via
560 * replay attacks. The @e monotonic_time limits such replay attacks, as every
561 * potential amplificator will check the @e monotonic_time and only respond
562 * (at most) once per message.
567 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
569 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
572 * Time at the initiator when generating the signature.
574 * Note that the receiver MUST IGNORE the absolute time, and only interpret
575 * the value as a mononic time and reject "older" values than the last one
576 * observed. This is necessary as we do not want to require synchronized
577 * clocks and may not have a bidirectional communication channel.
579 * Even with this, there is no real guarantee against replay achieved here,
580 * unless the latest timestamp is persisted. Persistence should be
581 * provided via PEERSTORE if possible.
583 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
586 * Challenge value used by the initiator to re-identify the path.
588 struct ChallengeNonceP challenge;
593 * Content signed by each peer during DV learning.
595 * This assues the initiator of the DV learning operation that the hop from @e
596 * pred via the signing peer to @e succ actually exists. This makes it
597 * impossible for an adversary to supply the network with bogus routes.
599 * The @e challenge is included to provide replay protection for the
600 * initiator. This way, the initiator knows that the hop existed after the
601 * original @e challenge was first transmitted, providing a freshness metric.
603 * Peers other than the initiator that passively learn paths by observing
604 * these messages do NOT benefit from this. Here, an adversary may indeed
605 * replay old messages. Thus, passively learned paths should always be
606 * immediately marked as "potentially stale".
611 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
613 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
616 * Identity of the previous peer on the path.
618 struct GNUNET_PeerIdentity pred;
621 * Identity of the next peer on the path.
623 struct GNUNET_PeerIdentity succ;
626 * Challenge value used by the initiator to re-identify the path.
628 struct ChallengeNonceP challenge;
633 * An entry describing a peer on a path in a
634 * `struct TransportDVLearnMessage` message.
639 * Identity of a peer on the path.
641 struct GNUNET_PeerIdentity hop;
644 * Signature of this hop over the path, of purpose
645 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
647 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
652 * Internal message used by transport for distance vector learning.
653 * If @e num_hops does not exceed the threshold, peers should append
654 * themselves to the peer list and flood the message (possibly only
655 * to a subset of their neighbours to limit discoverability of the
656 * network topology). To the extend that the @e bidirectional bits
657 * are set, peers may learn the inverse paths even if they did not
660 * Unless received on a bidirectional queue and @e num_hops just
661 * zero, peers that can forward to the initator should always try to
662 * forward to the initiator.
664 struct TransportDVLearnMessage
667 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
669 struct GNUNET_MessageHeader header;
672 * Number of hops this messages has travelled, in NBO. Zero if
675 uint16_t num_hops GNUNET_PACKED;
678 * Bitmask of the last 16 hops indicating whether they are confirmed
679 * available (without DV) in both directions or not, in NBO. Used
680 * to possibly instantly learn a path in both directions. Each peer
681 * should shift this value by one to the left, and then set the
682 * lowest bit IF the current sender can be reached from it (without
685 uint16_t bidirectional GNUNET_PACKED;
688 * Peers receiving this message and delaying forwarding to other
689 * peers for any reason should increment this value by the non-network
690 * delay created by the peer.
692 struct GNUNET_TIME_RelativeNBO non_network_delay;
695 * Time at the initiator when generating the signature.
697 * Note that the receiver MUST IGNORE the absolute time, and only interpret
698 * the value as a mononic time and reject "older" values than the last one
699 * observed. This is necessary as we do not want to require synchronized
700 * clocks and may not have a bidirectional communication channel.
702 * Even with this, there is no real guarantee against replay achieved here,
703 * unless the latest timestamp is persisted. Persistence should be
704 * provided via PEERSTORE if possible.
706 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
709 * Signature of this hop over the path, of purpose
710 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
712 struct GNUNET_CRYPTO_EddsaSignature init_sig;
715 * Identity of the peer that started this learning activity.
717 struct GNUNET_PeerIdentity initiator;
720 * Challenge value used by the initiator to re-identify the path.
722 struct ChallengeNonceP challenge;
724 /* Followed by @e num_hops `struct DVPathEntryP` values,
725 excluding the initiator of the DV trace; the last entry is the
726 current sender; the current peer must not be included. */
731 * Outer layer of an encapsulated message send over multiple hops.
732 * The path given only includes the identities of the subsequent
733 * peers, i.e. it will be empty if we are the receiver. Each
734 * forwarding peer should scan the list from the end, and if it can,
735 * forward to the respective peer. The list should then be shortened
736 * by all the entries up to and including that peer. Each hop should
737 * also increment @e total_hops to allow the receiver to get a precise
738 * estimate on the number of hops the message travelled. Senders must
739 * provide a learned path that thus should work, but intermediaries
740 * know of a shortcut, they are allowed to send the message via that
743 * If a peer finds itself still on the list, it must drop the message.
745 * The payload of the box can only be decrypted and verified by the
746 * ultimate receiver. Intermediaries do not learn the sender's
747 * identity and the path the message has taken. However, the first
748 * hop does learn the sender as @e total_hops would be zero and thus
749 * the predecessor must be the origin (so this is not really useful
750 * for anonymization).
752 struct TransportDVBoxMessage
755 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
757 struct GNUNET_MessageHeader header;
760 * Number of total hops this messages travelled. In NBO.
761 * @e origin sets this to zero, to be incremented at
762 * each hop. Peers should limit the @e total_hops value
763 * they accept from other peers.
765 uint16_t total_hops GNUNET_PACKED;
768 * Number of hops this messages includes. In NBO. Reduced by one
769 * or more at each hop. Peers should limit the @e num_hops value
770 * they accept from other peers.
772 uint16_t num_hops GNUNET_PACKED;
775 * Ephemeral key setup by the sender for target, used to encrypt the
776 * payload. Intermediaries must not change this value.
778 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
781 * We use an IV here as the @e ephemeral_key is re-used for
782 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
783 * Intermediaries must not change this value.
785 struct GNUNET_ShortHashCode iv;
788 * HMAC over the ciphertext of the encrypted, variable-size body
789 * that follows. Verified via DH of target and @e ephemeral_key.
790 * Intermediaries must not change this value.
792 struct GNUNET_HashCode hmac;
794 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
795 excluding the @e origin and the current peer, the last must be
796 the ultimate target; if @e num_hops is zero, the receiver of this
797 message is the ultimate target. */
799 /* Followed by encrypted, variable-size payload, which
800 must begin with a `struct TransportDVBoxPayloadP` */
802 /* Followed by the actual message, which itself must not be a
803 a DV_LEARN or DV_BOX message! */
808 * Message send to another peer to validate that it can indeed
809 * receive messages at a particular address.
811 struct TransportValidationChallengeMessage
815 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
817 struct GNUNET_MessageHeader header;
822 uint32_t reserved GNUNET_PACKED;
825 * Challenge to be signed by the receiving peer.
827 struct ChallengeNonceP challenge;
830 * Timestamp of the sender, to be copied into the reply to allow
831 * sender to calculate RTT. Must be monotonically increasing!
833 struct GNUNET_TIME_AbsoluteNBO sender_time;
838 * Message signed by a peer to confirm that it can indeed
839 * receive messages at a particular address.
841 struct TransportValidationPS
845 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
847 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
850 * How long does the sender believe the address on
851 * which the challenge was received to remain valid?
853 struct GNUNET_TIME_RelativeNBO validity_duration;
856 * Challenge signed by the receiving peer.
858 struct ChallengeNonceP challenge;
863 * Message send to a peer to respond to a
864 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
866 struct TransportValidationResponseMessage
870 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
872 struct GNUNET_MessageHeader header;
877 uint32_t reserved GNUNET_PACKED;
880 * The peer's signature matching the
881 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
883 struct GNUNET_CRYPTO_EddsaSignature signature;
886 * The challenge that was signed by the receiving peer.
888 struct ChallengeNonceP challenge;
891 * Original timestamp of the sender (was @code{sender_time}),
892 * copied into the reply to allow sender to calculate RTT.
894 struct GNUNET_TIME_AbsoluteNBO origin_time;
897 * How long does the sender believe this address to remain
900 struct GNUNET_TIME_RelativeNBO validity_duration;
905 * Message for Transport-to-Transport Flow control. Specifies the size
906 * of the flow control window, including how much we believe to have
907 * consumed (at transmission time), how much we believe to be allowed
908 * (at transmission time), and how much the other peer is allowed to
909 * send to us, and how much data we already received from the other
912 struct TransportFlowControlMessage
915 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
917 struct GNUNET_MessageHeader header;
920 * Sequence number of the flow control message. Incremented by one
921 * for each message. Starts at zero when a virtual link goes up.
922 * Used to detect one-sided connection drops. On wrap-around, the
923 * flow control counters will be reset as if the connection had
926 uint32_t seq GNUNET_PACKED;
929 * Flow control window size in bytes, in NBO.
930 * The receiver can send this many bytes at most.
932 uint64_t inbound_window_size GNUNET_PACKED;
935 * How many bytes has the sender sent that count for flow control at
936 * this time. Used to allow the receiver to estimate the packet
939 uint64_t outbound_sent GNUNET_PACKED;
942 * Latest flow control window size we learned from the other peer,
943 * in bytes, in NBO. We are limited to sending at most this many
944 * bytes to the other peer. May help the other peer detect when
945 * flow control messages were lost and should thus be retransmitted.
946 * In particular, if the delta to @e outbound_sent is too small,
947 * this signals that we are stalled.
949 uint64_t outbound_window_size GNUNET_PACKED;
952 * Timestamp of the sender. Must be monotonically increasing!
953 * Used to enable receiver to ignore out-of-order packets in
954 * combination with the @e seq. Note that @e seq will go down
955 * (back to zero) whenever either side believes the connection
956 * was dropped, allowing the peers to detect that they need to
957 * reset the counters for the number of bytes sent!
959 struct GNUNET_TIME_AbsoluteNBO sender_time;
963 GNUNET_NETWORK_STRUCT_END
967 * What type of client is the `struct TransportClient` about?
972 * We do not know yet (client is fresh).
977 * Is the CORE service, we need to forward traffic to it.
982 * It is a monitor, forward monitor data.
987 * It is a communicator, use for communication.
992 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
999 * Which transmission options are allowable for transmission?
1000 * Interpreted bit-wise!
1002 enum RouteMessageOptions
1005 * Only confirmed, non-DV direct neighbours.
1010 * We are allowed to use DV routing for this @a hdr
1015 * We are allowed to use unconfirmed queues or DV routes for this message
1017 RMO_UNCONFIRMED_ALLOWED = 2,
1020 * Reliable and unreliable, DV and non-DV are all acceptable.
1022 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1025 * If we have multiple choices, it is OK to send this message
1026 * over multiple channels at the same time to improve loss tolerance.
1027 * (We do at most 2 transmissions.)
1034 * When did we launch this DV learning activity?
1036 struct LearnLaunchEntry
1040 * Kept (also) in a DLL sorted by launch time.
1042 struct LearnLaunchEntry *prev;
1045 * Kept (also) in a DLL sorted by launch time.
1047 struct LearnLaunchEntry *next;
1050 * Challenge that uniquely identifies this activity.
1052 struct ChallengeNonceP challenge;
1055 * When did we transmit the DV learn message (used to calculate RTT) and
1056 * determine freshness of paths learned via this operation.
1058 struct GNUNET_TIME_Absolute launch_time;
1063 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1064 * (or current) transmission performance.
1066 struct TransmissionHistoryEntry
1069 * Number of bytes actually sent in the interval.
1071 uint64_t bytes_sent;
1074 * Number of bytes received and acknowledged by the other peer in
1077 uint64_t bytes_received;
1082 * Performance data for a transmission possibility.
1084 struct PerformanceData
1087 * Weighted average for the RTT.
1089 struct GNUNET_TIME_Relative aged_rtt;
1092 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1095 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1098 * What was the last age when we wrote to @e the? Used to clear
1099 * old entries when the age advances.
1101 unsigned int last_age;
1106 * Client connected to the transport service.
1108 struct TransportClient;
1111 * A neighbour that at least one communicator is connected to.
1116 * Entry in our #dv_routes table, representing a (set of) distance
1117 * vector routes to a particular peer.
1119 struct DistanceVector;
1122 * A queue is a message queue provided by a communicator
1123 * via which we can reach a particular neighbour.
1128 * Message awaiting transmission. See detailed comments below.
1130 struct PendingMessage;
1133 * One possible hop towards a DV target.
1135 struct DistanceVectorHop;
1138 * A virtual link is another reachable peer that is known to CORE. It
1139 * can be either a `struct Neighbour` with at least one confirmed
1140 * `struct Queue`, or a `struct DistanceVector` with at least one
1141 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1142 * data that is per neighbour that is not specific to how the
1143 * connectivity is established.
1149 * Context from #handle_incoming_msg(). Closure for many
1150 * message handlers below.
1152 struct CommunicatorMessageContext
1156 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1157 * flow control to unchoke.
1159 struct CommunicatorMessageContext *next;
1162 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1163 * flow control to unchoke.
1165 struct CommunicatorMessageContext *prev;
1168 * Which communicator provided us with the message.
1170 struct TransportClient *tc;
1173 * Additional information for flow control and about the sender.
1175 struct GNUNET_TRANSPORT_IncomingMessage im;
1178 * Number of hops the message has travelled (if DV-routed).
1179 * FIXME: make use of this in ACK handling!
1181 uint16_t total_hops;
1186 * Closure for #core_env_sent_cb.
1188 struct CoreSentContext
1192 * Kept in a DLL to clear @e vl in case @e vl is lost.
1194 struct CoreSentContext *next;
1197 * Kept in a DLL to clear @e vl in case @e vl is lost.
1199 struct CoreSentContext *prev;
1202 * Virtual link this is about.
1204 struct VirtualLink *vl;
1207 * How big was the message.
1212 * By how much should we increment @e vl's
1213 * incoming_fc_window_size_used once we are done sending to CORE?
1214 * Use to ensure we do not increment twice if there is more than one
1222 * A virtual link is another reachable peer that is known to CORE. It
1223 * can be either a `struct Neighbour` with at least one confirmed
1224 * `struct Queue`, or a `struct DistanceVector` with at least one
1225 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1226 * data that is per neighbour that is not specific to how the
1227 * connectivity is established.
1232 * Identity of the peer at the other end of the link.
1234 struct GNUNET_PeerIdentity target;
1237 * Communicators blocked for receiving on @e target as we are waiting
1238 * on the @e core_recv_window to increase.
1240 struct CommunicatorMessageContext *cmc_head;
1243 * Communicators blocked for receiving on @e target as we are waiting
1244 * on the @e core_recv_window to increase.
1246 struct CommunicatorMessageContext *cmc_tail;
1249 * Head of list of messages pending for this VL.
1251 struct PendingMessage *pending_msg_head;
1254 * Tail of list of messages pending for this VL.
1256 struct PendingMessage *pending_msg_tail;
1259 * Kept in a DLL to clear @e vl in case @e vl is lost.
1261 struct CoreSentContext *csc_tail;
1264 * Kept in a DLL to clear @e vl in case @e vl is lost.
1266 struct CoreSentContext *csc_head;
1269 * Task scheduled to possibly notfiy core that this peer is no
1270 * longer counting as confirmed. Runs the #core_visibility_check(),
1271 * which checks that some DV-path or a queue exists that is still
1272 * considered confirmed.
1274 struct GNUNET_SCHEDULER_Task *visibility_task;
1277 * Task scheduled to periodically retransmit FC messages (in
1278 * case one got lost).
1280 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1283 * Neighbour used by this virtual link, NULL if @e dv is used.
1285 struct Neighbour *n;
1288 * Distance vector used by this virtual link, NULL if @e n is used.
1290 struct DistanceVector *dv;
1293 * Sender timestamp of @e n_challenge, used to generate out-of-order
1294 * challenges (as sender's timestamps must be monotonically
1295 * increasing). FIXME: where do we need this?
1297 struct GNUNET_TIME_Absolute n_challenge_time;
1300 * When did we last send a
1301 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1302 * Used to determine whether it is time to re-transmit the message.
1304 struct GNUNET_TIME_Absolute last_fc_transmission;
1307 * Sender timestamp of the last
1308 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1309 * received. Note that we do not persist this monotonic time as we
1310 * do not really have to worry about ancient flow control window
1311 * sizes after restarts.
1313 struct GNUNET_TIME_Absolute last_fc_timestamp;
1316 * Expected RTT from the last FC transmission. (Zero if the last
1317 * attempt failed, but could theoretically be zero even on success.)
1319 struct GNUNET_TIME_Relative last_fc_rtt;
1322 * Used to generate unique UUIDs for messages that are being
1325 uint64_t message_uuid_ctr;
1328 * Memory allocated for this virtual link. Expresses how much RAM
1329 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1330 * Can be adapted to dedicate more RAM to links that need it, while
1331 * sticking to some overall RAM limit. For now, set to
1332 * #DEFAULT_WINDOW_SIZE.
1334 uint64_t available_fc_window_size;
1337 * Memory actually used to buffer packets on this virtual link.
1338 * Expresses how much RAM we are currently using for virtual link.
1339 * Note that once CORE is done with a packet, we decrement the value
1342 uint64_t incoming_fc_window_size_ram;
1345 * Last flow control window size we provided to the other peer, in
1346 * bytes. We are allowing the other peer to send this
1349 uint64_t incoming_fc_window_size;
1352 * How much of the window did the other peer successfully use (and
1353 * we already passed it on to CORE)? Must be below @e
1354 * incoming_fc_window_size. We should effectively signal the
1355 * other peer that the window is this much bigger at the next
1356 * opportunity / challenge.
1358 uint64_t incoming_fc_window_size_used;
1361 * What is our current estimate on the message loss rate for the sender?
1362 * Based on the difference between how much the sender sent according
1363 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1364 * (@e outbound_sent field) and how much we actually received at that
1365 * time (@e incoming_fc_window_size_used). This delta is then
1366 * added onto the @e incoming_fc_window_size when determining the
1367 * @e outbound_window_size we send to the other peer. Initially zero.
1368 * May be negative if we (due to out-of-order delivery) actually received
1369 * more than the sender claims to have sent in its last FC message.
1371 int64_t incoming_fc_window_size_loss;
1374 * Our current flow control window size in bytes. We
1375 * are allowed to transmit this many bytes to @a n.
1377 uint64_t outbound_fc_window_size;
1380 * How much of our current flow control window size have we
1381 * used (in bytes). Must be below
1382 * @e outbound_fc_window_size.
1384 uint64_t outbound_fc_window_size_used;
1387 * What is the most recent FC window the other peer sent us
1388 * in `outbound_window_size`? This is basically the window
1389 * size value the other peer has definitively received from
1390 * us. If it matches @e incoming_fc_window_size, we should
1391 * not send a FC message to increase the FC window. However,
1392 * we may still send an FC message to notify the other peer
1393 * that we received the other peer's FC message.
1395 uint64_t last_outbound_window_size_received;
1398 * Generator for the sequence numbers of
1399 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1401 uint32_t fc_seq_gen;
1404 * Last sequence number of a
1405 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1408 uint32_t last_fc_seq;
1411 * How many more messages can we send to CORE before we exhaust
1412 * the receive window of CORE for this peer? If this hits zero,
1413 * we must tell communicators to stop providing us more messages
1414 * for this peer. In fact, the window can go negative as we
1415 * have multiple communicators, so per communicator we can go
1416 * down by one into the negative range. Furthermore, we count
1417 * delivery per CORE client, so if we had multiple cores, that
1418 * might also cause a negative window size here (as one message
1419 * would decrement the window by one per CORE client).
1421 int core_recv_window;
1426 * Data structure kept when we are waiting for an acknowledgement.
1428 struct PendingAcknowledgement
1432 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1433 * is kept in relation to its pending message.
1435 struct PendingAcknowledgement *next_pm;
1438 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1439 * is kept in relation to its pending message.
1441 struct PendingAcknowledgement *prev_pm;
1444 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1445 * is kept in relation to the queue that was used to transmit the
1448 struct PendingAcknowledgement *next_queue;
1451 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1452 * is kept in relation to the queue that was used to transmit the
1455 struct PendingAcknowledgement *prev_queue;
1458 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1459 * is kept in relation to the DVH that was used to transmit the
1462 struct PendingAcknowledgement *next_dvh;
1465 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1466 * is kept in relation to the DVH that was used to transmit the
1469 struct PendingAcknowledgement *prev_dvh;
1472 * Pointers for the DLL of all pending acknowledgements.
1473 * This list is sorted by @e transmission time. If the list gets too
1474 * long, the oldest entries are discarded.
1476 struct PendingAcknowledgement *next_pa;
1479 * Pointers for the DLL of all pending acknowledgements.
1480 * This list is sorted by @e transmission time. If the list gets too
1481 * long, the oldest entries are discarded.
1483 struct PendingAcknowledgement *prev_pa;
1486 * Unique identifier for this transmission operation.
1488 struct AcknowledgementUUIDP ack_uuid;
1491 * Message that was transmitted, may be NULL if the message was ACKed
1492 * via another channel.
1494 struct PendingMessage *pm;
1497 * Distance vector path chosen for this transmission, NULL if transmission
1498 * was to a direct neighbour OR if the path was forgotten in the meantime.
1500 struct DistanceVectorHop *dvh;
1503 * Queue used for transmission, NULL if the queue has been destroyed
1504 * (which may happen before we get an acknowledgement).
1506 struct Queue *queue;
1509 * Time of the transmission, for RTT calculation.
1511 struct GNUNET_TIME_Absolute transmission_time;
1514 * Number of bytes of the original message (to calculate bandwidth).
1516 uint16_t message_size;
1521 * One possible hop towards a DV target.
1523 struct DistanceVectorHop
1527 * Kept in a MDLL, sorted by @e timeout.
1529 struct DistanceVectorHop *next_dv;
1532 * Kept in a MDLL, sorted by @e timeout.
1534 struct DistanceVectorHop *prev_dv;
1539 struct DistanceVectorHop *next_neighbour;
1544 struct DistanceVectorHop *prev_neighbour;
1547 * Head of DLL of PAs that used our @a path.
1549 struct PendingAcknowledgement *pa_head;
1552 * Tail of DLL of PAs that used our @a path.
1554 struct PendingAcknowledgement *pa_tail;
1557 * What would be the next hop to @e target?
1559 struct Neighbour *next_hop;
1562 * Distance vector entry this hop belongs with.
1564 struct DistanceVector *dv;
1567 * Array of @e distance hops to the target, excluding @e next_hop.
1568 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1569 * at the end of this struct. Excludes the target itself!
1571 const struct GNUNET_PeerIdentity *path;
1574 * At what time do we forget about this path unless we see it again
1577 struct GNUNET_TIME_Absolute timeout;
1580 * For how long is the validation of this path considered
1582 * Set to ZERO if the path is learned by snooping on DV learn messages
1583 * initiated by other peers, and to the time at which we generated the
1584 * challenge for DV learn operations this peer initiated.
1586 struct GNUNET_TIME_Absolute path_valid_until;
1589 * Performance data for this transmission possibility.
1591 struct PerformanceData pd;
1594 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1595 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1598 unsigned int distance;
1603 * Entry in our #dv_routes table, representing a (set of) distance
1604 * vector routes to a particular peer.
1606 struct DistanceVector
1610 * To which peer is this a route?
1612 struct GNUNET_PeerIdentity target;
1615 * Known paths to @e target.
1617 struct DistanceVectorHop *dv_head;
1620 * Known paths to @e target.
1622 struct DistanceVectorHop *dv_tail;
1625 * Task scheduled to purge expired paths from @e dv_head MDLL.
1627 struct GNUNET_SCHEDULER_Task *timeout_task;
1630 * Do we have a confirmed working queue and are thus visible to
1631 * CORE? If so, this is the virtual link, otherwise NULL.
1633 struct VirtualLink *vl;
1636 * Signature affirming @e ephemeral_key of type
1637 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1639 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1642 * How long is @e sender_sig valid
1644 struct GNUNET_TIME_Absolute ephemeral_validity;
1647 * What time was @e sender_sig created
1649 struct GNUNET_TIME_Absolute monotime;
1652 * Our ephemeral key.
1654 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1657 * Our private ephemeral key.
1659 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1664 * Entry identifying transmission in one of our `struct
1665 * Queue` which still awaits an ACK. This is used to
1666 * ensure we do not overwhelm a communicator and limit the number of
1667 * messages outstanding per communicator (say in case communicator is
1668 * CPU bound) and per queue (in case bandwidth allocation exceeds
1669 * what the communicator can actually provide towards a particular
1678 struct QueueEntry *next;
1683 struct QueueEntry *prev;
1686 * Queue this entry is queued with.
1688 struct Queue *queue;
1691 * Pending message this entry is for, or NULL for none.
1693 struct PendingMessage *pm;
1696 * Message ID used for this message with the queue used for transmission.
1703 * A queue is a message queue provided by a communicator
1704 * via which we can reach a particular neighbour.
1711 struct Queue *next_neighbour;
1716 struct Queue *prev_neighbour;
1721 struct Queue *prev_client;
1726 struct Queue *next_client;
1729 * Head of DLL of PAs that used this queue.
1731 struct PendingAcknowledgement *pa_head;
1734 * Tail of DLL of PAs that used this queue.
1736 struct PendingAcknowledgement *pa_tail;
1739 * Head of DLL of unacked transmission requests.
1741 struct QueueEntry *queue_head;
1744 * End of DLL of unacked transmission requests.
1746 struct QueueEntry *queue_tail;
1749 * Which neighbour is this queue for?
1751 struct Neighbour *neighbour;
1754 * Which communicator offers this queue?
1756 struct TransportClient *tc;
1759 * Address served by the queue.
1761 const char *address;
1764 * Task scheduled for the time when this queue can (likely) transmit the
1767 struct GNUNET_SCHEDULER_Task *transmit_task;
1770 * How long do *we* consider this @e address to be valid? In the past or
1771 * zero if we have not yet validated it. Can be updated based on
1772 * challenge-response validations (via address validation logic), or when we
1773 * receive ACKs that we can definitively map to transmissions via this
1776 struct GNUNET_TIME_Absolute validated_until;
1779 * Performance data for this queue.
1781 struct PerformanceData pd;
1784 * Message ID generator for transmissions on this queue to the
1790 * Unique identifier of this queue with the communicator.
1795 * Maximum transmission unit supported by this queue.
1802 uint32_t num_msg_pending;
1807 uint32_t num_bytes_pending;
1810 * Length of the DLL starting at @e queue_head.
1812 unsigned int queue_length;
1815 * Network type offered by this queue.
1817 enum GNUNET_NetworkType nt;
1820 * Connection status for this queue.
1822 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1825 * Set to #GNUNET_YES if this queue is idle waiting for some
1826 * virtual link to give it a pending message.
1833 * Information we keep for a message that we are reassembling.
1835 struct ReassemblyContext
1839 * Original message ID for of the message that all the fragments
1842 struct MessageUUIDP msg_uuid;
1845 * Which neighbour is this context for?
1847 struct Neighbour *neighbour;
1850 * Entry in the reassembly heap (sorted by expiration).
1852 struct GNUNET_CONTAINER_HeapNode *hn;
1855 * Bitfield with @e msg_size bits representing the positions
1856 * where we have received fragments. When we receive a fragment,
1857 * we check the bits in @e bitfield before incrementing @e msg_missing.
1859 * Allocated after the reassembled message.
1864 * At what time will we give up reassembly of this message?
1866 struct GNUNET_TIME_Absolute reassembly_timeout;
1869 * Time we received the last fragment. @e avg_ack_delay must be
1870 * incremented by now - @e last_frag multiplied by @e num_acks.
1872 struct GNUNET_TIME_Absolute last_frag;
1875 * How big is the message we are reassembling in total?
1880 * How many bytes of the message are still missing? Defragmentation
1881 * is complete when @e msg_missing == 0.
1883 uint16_t msg_missing;
1885 /* Followed by @e msg_size bytes of the (partially) defragmented original
1888 /* Followed by @e bitfield data */
1893 * A neighbour that at least one communicator is connected to.
1899 * Which peer is this about?
1901 struct GNUNET_PeerIdentity pid;
1904 * Map with `struct ReassemblyContext` structs for fragments under
1905 * reassembly. May be NULL if we currently have no fragments from
1906 * this @e pid (lazy initialization).
1908 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1911 * Heap with `struct ReassemblyContext` structs for fragments under
1912 * reassembly. May be NULL if we currently have no fragments from
1913 * this @e pid (lazy initialization).
1915 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1918 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1920 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1923 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1924 * purged if this neighbour goes down.
1926 struct DistanceVectorHop *dv_head;
1929 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1930 * purged if this neighbour goes down.
1932 struct DistanceVectorHop *dv_tail;
1935 * Head of DLL of queues to this peer.
1937 struct Queue *queue_head;
1940 * Tail of DLL of queues to this peer.
1942 struct Queue *queue_tail;
1945 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1946 * the PEERSTORE, or NULL.
1948 struct GNUNET_PEERSTORE_IterateContext *get;
1951 * Handle to a PEERSTORE store operation to store this @e pid's @e
1952 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1954 struct GNUNET_PEERSTORE_StoreContext *sc;
1957 * Do we have a confirmed working queue and are thus visible to
1958 * CORE? If so, this is the virtual link, otherwise NULL.
1960 struct VirtualLink *vl;
1963 * Latest DVLearn monotonic time seen from this peer. Initialized only
1964 * if @e dl_monotime_available is #GNUNET_YES.
1966 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1969 * Do we have the lastest value for @e last_dv_learn_monotime from
1970 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1972 int dv_monotime_available;
1977 * Another peer attempted to talk to us, we should try to establish
1978 * a connection in the other direction.
1980 struct IncomingRequest
1986 struct IncomingRequest *next;
1991 struct IncomingRequest *prev;
1994 * Handle for watching the peerstore for HELLOs for this peer.
1996 struct GNUNET_PEERSTORE_WatchContext *wc;
1999 * Which peer is this about?
2001 struct GNUNET_PeerIdentity pid;
2006 * A peer that an application (client) would like us to talk to directly.
2012 * Which peer is this about?
2014 struct GNUNET_PeerIdentity pid;
2017 * Client responsible for the request.
2019 struct TransportClient *tc;
2022 * Handle for watching the peerstore for HELLOs for this peer.
2024 struct GNUNET_PEERSTORE_WatchContext *wc;
2027 * What kind of performance preference does this @e tc have?
2031 enum GNUNET_MQ_PriorityPreferences pk;
2034 * How much bandwidth would this @e tc like to see?
2036 struct GNUNET_BANDWIDTH_Value32NBO bw;
2041 * Types of different pending messages.
2043 enum PendingMessageType
2047 * Ordinary message received from the CORE service.
2054 PMT_FRAGMENT_BOX = 1,
2059 PMT_RELIABILITY_BOX = 2,
2062 * Pending message created during #forward_dv_box().
2070 * Transmission request that is awaiting delivery. The original
2071 * transmission requests from CORE may be too big for some queues.
2072 * In this case, a *tree* of fragments is created. At each
2073 * level of the tree, fragments are kept in a DLL ordered by which
2074 * fragment should be sent next (at the head). The tree is searched
2075 * top-down, with the original message at the root.
2077 * To select a node for transmission, first it is checked if the
2078 * current node's message fits with the MTU. If it does not, we
2079 * either calculate the next fragment (based on @e frag_off) from the
2080 * current node, or, if all fragments have already been created,
2081 * descend to the @e head_frag. Even though the node was already
2082 * fragmented, the fragment may be too big if the fragment was
2083 * generated for a queue with a larger MTU. In this case, the node
2084 * may be fragmented again, thus creating a tree.
2086 * When acknowledgements for fragments are received, the tree
2087 * must be pruned, removing those parts that were already
2088 * acknowledged. When fragments are sent over a reliable
2089 * channel, they can be immediately removed.
2091 * If a message is ever fragmented, then the original "full" message
2092 * is never again transmitted (even if it fits below the MTU), and
2093 * only (remaining) fragments are sent.
2095 struct PendingMessage
2098 * Kept in a MDLL of messages for this @a vl.
2100 struct PendingMessage *next_vl;
2103 * Kept in a MDLL of messages for this @a vl.
2105 struct PendingMessage *prev_vl;
2108 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2110 struct PendingMessage *next_client;
2113 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2115 struct PendingMessage *prev_client;
2118 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2119 * #PMT_FRAGMENT_BOx)
2121 struct PendingMessage *next_frag;
2124 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2125 * #PMT_FRAGMENT_BOX)
2127 struct PendingMessage *prev_frag;
2130 * Head of DLL of PAs for this pending message.
2132 struct PendingAcknowledgement *pa_head;
2135 * Tail of DLL of PAs for this pending message.
2137 struct PendingAcknowledgement *pa_tail;
2140 * This message, reliability *or* DV-boxed. Only possibly available
2141 * if @e pmt is #PMT_CORE.
2143 struct PendingMessage *bpm;
2146 * Target of the request (always the ultimate destination!).
2148 struct VirtualLink *vl;
2151 * Set to non-NULL value if this message is currently being given to a
2152 * communicator and we are awaiting that communicator's acknowledgement.
2153 * Note that we must not retransmit a pending message while we're still
2154 * in the process of giving it to a communicator. If a pending message
2155 * is free'd while this entry is non-NULL, the @e qe reference to us
2156 * should simply be set to NULL.
2158 struct QueueEntry *qe;
2161 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2163 struct TransportClient *client;
2166 * Head of a MDLL of fragments created for this core message.
2168 struct PendingMessage *head_frag;
2171 * Tail of a MDLL of fragments created for this core message.
2173 struct PendingMessage *tail_frag;
2176 * Our parent in the fragmentation tree.
2178 struct PendingMessage *frag_parent;
2181 * At what time should we give up on the transmission (and no longer retry)?
2183 struct GNUNET_TIME_Absolute timeout;
2186 * What is the earliest time for us to retry transmission of this message?
2188 struct GNUNET_TIME_Absolute next_attempt;
2191 * UUID to use for this message (used for reassembly of fragments, only
2192 * initialized if @e msg_uuid_set is #GNUNET_YES).
2194 struct MessageUUIDP msg_uuid;
2197 * UUID we use to identify this message in our logs.
2198 * Generated by incrementing the "logging_uuid_gen".
2200 unsigned long long logging_uuid;
2203 * Type of the pending message.
2205 enum PendingMessageType pmt;
2208 * Preferences for this message.
2209 * TODO: actually use this!
2211 enum GNUNET_MQ_PriorityPreferences prefs;
2214 * Size of the original message.
2219 * Offset at which we should generate the next fragment.
2224 * #GNUNET_YES once @e msg_uuid was initialized
2226 int16_t msg_uuid_set;
2228 /* Followed by @e bytes_msg to transmit */
2233 * Acknowledgement payload.
2235 struct TransportCummulativeAckPayload
2238 * When did we receive the message we are ACKing? Used to calculate
2239 * the delay we introduced by cummulating ACKs.
2241 struct GNUNET_TIME_Absolute receive_time;
2244 * UUID of a message being acknowledged.
2246 struct AcknowledgementUUIDP ack_uuid;
2251 * Data structure in which we track acknowledgements still to
2254 struct AcknowledgementCummulator
2257 * Target peer for which we are accumulating ACKs here.
2259 struct GNUNET_PeerIdentity target;
2262 * ACK data being accumulated. Only @e num_acks slots are valid.
2264 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2267 * Task scheduled either to transmit the cummulative ACK message,
2268 * or to clean up this data structure after extended periods of
2269 * inactivity (if @e num_acks is zero).
2271 struct GNUNET_SCHEDULER_Task *task;
2274 * When is @e task run (only used if @e num_acks is non-zero)?
2276 struct GNUNET_TIME_Absolute min_transmission_time;
2279 * Counter to produce the `ack_counter` in the `struct
2280 * TransportReliabilityAckMessage`. Allows the receiver to detect
2281 * lost ACK messages. Incremented by @e num_acks upon transmission.
2283 uint32_t ack_counter;
2286 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2288 unsigned int num_acks;
2293 * One of the addresses of this peer.
2295 struct AddressListEntry
2301 struct AddressListEntry *next;
2306 struct AddressListEntry *prev;
2309 * Which communicator provides this address?
2311 struct TransportClient *tc;
2314 * The actual address.
2316 const char *address;
2319 * Current context for storing this address in the peerstore.
2321 struct GNUNET_PEERSTORE_StoreContext *sc;
2324 * Task to periodically do @e st operation.
2326 struct GNUNET_SCHEDULER_Task *st;
2329 * What is a typical lifetime the communicator expects this
2330 * address to have? (Always from now.)
2332 struct GNUNET_TIME_Relative expiration;
2335 * Address identifier used by the communicator.
2340 * Network type offered by this address.
2342 enum GNUNET_NetworkType nt;
2347 * Client connected to the transport service.
2349 struct TransportClient
2355 struct TransportClient *next;
2360 struct TransportClient *prev;
2363 * Handle to the client.
2365 struct GNUNET_SERVICE_Client *client;
2368 * Message queue to the client.
2370 struct GNUNET_MQ_Handle *mq;
2373 * What type of client is this?
2375 enum ClientType type;
2381 * Information for @e type #CT_CORE.
2387 * Head of list of messages pending for this client, sorted by
2388 * transmission time ("next_attempt" + possibly internal prioritization).
2390 struct PendingMessage *pending_msg_head;
2393 * Tail of list of messages pending for this client.
2395 struct PendingMessage *pending_msg_tail;
2400 * Information for @e type #CT_MONITOR.
2406 * Peer identity to monitor the addresses of.
2407 * Zero to monitor all neighbours. Valid if
2408 * @e type is #CT_MONITOR.
2410 struct GNUNET_PeerIdentity peer;
2413 * Is this a one-shot monitor?
2421 * Information for @e type #CT_COMMUNICATOR.
2426 * If @e type is #CT_COMMUNICATOR, this communicator
2427 * supports communicating using these addresses.
2429 char *address_prefix;
2432 * Head of DLL of queues offered by this communicator.
2434 struct Queue *queue_head;
2437 * Tail of DLL of queues offered by this communicator.
2439 struct Queue *queue_tail;
2442 * Head of list of the addresses of this peer offered by this
2445 struct AddressListEntry *addr_head;
2448 * Tail of list of the addresses of this peer offered by this
2451 struct AddressListEntry *addr_tail;
2454 * Number of queue entries in all queues to this communicator. Used
2455 * throttle sending to a communicator if we see that the communicator
2456 * is globally unable to keep up.
2458 unsigned int total_queue_length;
2461 * Characteristics of this communicator.
2463 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2468 * Information for @e type #CT_APPLICATION
2474 * Map of requests for peers the given client application would like to
2475 * see connections for. Maps from PIDs to `struct PeerRequest`.
2477 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2486 * State we keep for validation activities. Each of these
2487 * is both in the #validation_heap and the #validation_map.
2489 struct ValidationState
2493 * For which peer is @a address to be validated (or possibly valid)?
2494 * Serves as key in the #validation_map.
2496 struct GNUNET_PeerIdentity pid;
2499 * How long did the peer claim this @e address to be valid? Capped at
2500 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2501 * were told about the address and the value claimed by the other peer at
2502 * that time. May be updated similarly when validation succeeds.
2504 struct GNUNET_TIME_Absolute valid_until;
2507 * How long do *we* consider this @e address to be valid?
2508 * In the past or zero if we have not yet validated it.
2510 struct GNUNET_TIME_Absolute validated_until;
2513 * When did we FIRST use the current @e challenge in a message?
2514 * Used to sanity-check @code{origin_time} in the response when
2515 * calculating the RTT. If the @code{origin_time} is not in
2516 * the expected range, the response is discarded as malicious.
2518 struct GNUNET_TIME_Absolute first_challenge_use;
2521 * When did we LAST use the current @e challenge in a message?
2522 * Used to sanity-check @code{origin_time} in the response when
2523 * calculating the RTT. If the @code{origin_time} is not in
2524 * the expected range, the response is discarded as malicious.
2526 struct GNUNET_TIME_Absolute last_challenge_use;
2529 * Next time we will send the @e challenge to the peer, if this time is past
2530 * @e valid_until, this validation state is released at this time. If the
2531 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2532 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2533 * to re-validate before the validity actually expires.
2535 struct GNUNET_TIME_Absolute next_challenge;
2538 * Current backoff factor we're applying for sending the @a challenge.
2539 * Reset to 0 if the @a challenge is confirmed upon validation.
2540 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2541 * existing value if we receive an unvalidated address again over
2542 * another channel (and thus should consider the information "fresh").
2543 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2545 struct GNUNET_TIME_Relative challenge_backoff;
2548 * Initially set to "forever". Once @e validated_until is set, this value is
2549 * set to the RTT that tells us how long it took to receive the validation.
2551 struct GNUNET_TIME_Relative validation_rtt;
2554 * The challenge we sent to the peer to get it to validate the address. Note
2555 * that we rotate the challenge whenever we update @e validated_until to
2556 * avoid attacks where a peer simply replays an old challenge in the future.
2557 * (We must not rotate more often as otherwise we may discard valid answers
2558 * due to packet losses, latency and reorderings on the network).
2560 struct ChallengeNonceP challenge;
2563 * Claimed address of the peer.
2568 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2569 * heap is used to figure out when the next validation activity should be
2572 struct GNUNET_CONTAINER_HeapNode *hn;
2575 * Handle to a PEERSTORE store operation for this @e address. NULL if
2576 * no PEERSTORE operation is pending.
2578 struct GNUNET_PEERSTORE_StoreContext *sc;
2581 * Self-imposed limit on the previous flow control window. (May be zero,
2582 * if we never used data from the previous window or are establishing the
2583 * connection for the first time).
2585 uint32_t last_window_consum_limit;
2588 * We are technically ready to send the challenge, but we are waiting for
2589 * the respective queue to become available for transmission.
2596 * A Backtalker is a peer sending us backchannel messages. We use this
2597 * struct to detect monotonic time violations, cache ephemeral key
2598 * material (to avoid repeatedly checking signatures), and to synchronize
2599 * monotonic time with the PEERSTORE.
2604 * Peer this is about.
2606 struct GNUNET_PeerIdentity pid;
2609 * Last (valid) monotonic time received from this sender.
2611 struct GNUNET_TIME_Absolute monotonic_time;
2614 * When will this entry time out?
2616 struct GNUNET_TIME_Absolute timeout;
2619 * Last (valid) ephemeral key received from this sender.
2621 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2624 * Task associated with this backtalker. Can be for timeout,
2625 * or other asynchronous operations.
2627 struct GNUNET_SCHEDULER_Task *task;
2630 * Communicator context waiting on this backchannel's @e get, or NULL.
2632 struct CommunicatorMessageContext *cmc;
2635 * Handle for an operation to fetch @e monotonic_time information from the
2636 * PEERSTORE, or NULL.
2638 struct GNUNET_PEERSTORE_IterateContext *get;
2641 * Handle to a PEERSTORE store operation for this @e pid's @e
2642 * monotonic_time. NULL if no PEERSTORE operation is pending.
2644 struct GNUNET_PEERSTORE_StoreContext *sc;
2647 * Number of bytes of the original message body that follows after this
2655 * Head of linked list of all clients to this service.
2657 static struct TransportClient *clients_head;
2660 * Tail of linked list of all clients to this service.
2662 static struct TransportClient *clients_tail;
2665 * Statistics handle.
2667 static struct GNUNET_STATISTICS_Handle *GST_stats;
2670 * Configuration handle.
2672 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2677 static struct GNUNET_PeerIdentity GST_my_identity;
2682 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2685 * Map from PIDs to `struct Neighbour` entries. A peer is
2686 * a neighbour if we have an MQ to it from some communicator.
2688 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2691 * Map from PIDs to `struct Backtalker` entries. A peer is
2692 * a backtalker if it recently send us backchannel messages.
2694 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2697 * Map from PIDs to `struct AcknowledgementCummulator`s.
2698 * Here we track the cummulative ACKs for transmission.
2700 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2703 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2704 * a `struct PendingAcknowledgement`.
2706 static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2709 * Map from PIDs to `struct DistanceVector` entries describing
2710 * known paths to the peer.
2712 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2715 * Map from PIDs to `struct ValidationState` entries describing
2716 * addresses we are aware of and their validity state.
2718 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2721 * Map from PIDs to `struct VirtualLink` entries describing
2722 * links CORE knows to exist.
2724 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2727 * Map from challenges to `struct LearnLaunchEntry` values.
2729 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2732 * Head of a DLL sorted by launch time.
2734 static struct LearnLaunchEntry *lle_head;
2737 * Tail of a DLL sorted by launch time.
2739 static struct LearnLaunchEntry *lle_tail;
2742 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2743 * sorting addresses we are aware of by when we should next try to (re)validate
2746 static struct GNUNET_CONTAINER_Heap *validation_heap;
2749 * Database for peer's HELLOs.
2751 static struct GNUNET_PEERSTORE_Handle *peerstore;
2754 * Task run to initiate DV learning.
2756 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2759 * Task to run address validation.
2761 static struct GNUNET_SCHEDULER_Task *validation_task;
2764 * The most recent PA we have created, head of DLL.
2765 * The length of the DLL is kept in #pa_count.
2767 static struct PendingAcknowledgement *pa_head;
2770 * The oldest PA we have created, tail of DLL.
2771 * The length of the DLL is kept in #pa_count.
2773 static struct PendingAcknowledgement *pa_tail;
2776 * List of incomming connections where we are trying
2777 * to get a connection back established. Length
2778 * kept in #ir_total.
2780 static struct IncomingRequest *ir_head;
2783 * Tail of DLL starting at #ir_head.
2785 static struct IncomingRequest *ir_tail;
2788 * Length of the DLL starting at #ir_head.
2790 static unsigned int ir_total;
2793 * Generator of `logging_uuid` in `struct PendingMessage`.
2795 static unsigned long long logging_uuid_gen;
2798 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2799 * limit the size of the data structure.
2801 static unsigned int pa_count;
2804 * Monotonic time we use for HELLOs generated at this time. TODO: we
2805 * should increase this value from time to time (i.e. whenever a
2806 * `struct AddressListEntry` actually expires), but IF we do this, we
2807 * must also update *all* (remaining) addresses in the PEERSTORE at
2808 * that time! (So for now only increased when the peer is restarted,
2809 * which hopefully roughly matches whenever our addresses change.)
2811 static struct GNUNET_TIME_Absolute hello_mono_time;
2815 * Get an offset into the transmission history buffer for `struct
2816 * PerformanceData`. Note that the caller must perform the required
2817 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2820 * An 'age' lasts 15 minute slots.
2822 * @return current age of the world
2827 struct GNUNET_TIME_Absolute now;
2829 now = GNUNET_TIME_absolute_get ();
2830 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2835 * Release @a ir data structure.
2837 * @param ir data structure to release
2840 free_incoming_request (struct IncomingRequest *ir)
2842 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2843 GNUNET_assert (ir_total > 0);
2845 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2851 * Release @a pa data structure.
2853 * @param pa data structure to release
2856 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2858 struct Queue *q = pa->queue;
2859 struct PendingMessage *pm = pa->pm;
2860 struct DistanceVectorHop *dvh = pa->dvh;
2862 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2866 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2871 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2876 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2879 GNUNET_assert (GNUNET_YES ==
2880 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
2881 &pa->ack_uuid.value,
2888 * Free fragment tree below @e root, excluding @e root itself.
2889 * FIXME: this does NOT seem to have the intended semantics
2890 * based on how this is called. Seems we generally DO expect
2891 * @a root to be free'ed itself as well!
2893 * @param root root of the tree to free
2896 free_fragment_tree (struct PendingMessage *root)
2898 struct PendingMessage *frag;
2900 while (NULL != (frag = root->head_frag))
2902 struct PendingAcknowledgement *pa;
2904 free_fragment_tree (frag);
2905 while (NULL != (pa = frag->pa_head))
2907 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2910 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2917 * Release memory associated with @a pm and remove @a pm from associated
2918 * data structures. @a pm must be a top-level pending message and not
2919 * a fragment in the tree. The entire tree is freed (if applicable).
2921 * @param pm the pending message to free
2924 free_pending_message (struct PendingMessage *pm)
2926 struct TransportClient *tc = pm->client;
2927 struct VirtualLink *vl = pm->vl;
2928 struct PendingAcknowledgement *pa;
2932 GNUNET_CONTAINER_MDLL_remove (client,
2933 tc->details.core.pending_msg_head,
2934 tc->details.core.pending_msg_tail,
2939 GNUNET_CONTAINER_MDLL_remove (vl,
2940 vl->pending_msg_head,
2941 vl->pending_msg_tail,
2944 while (NULL != (pa = pm->pa_head))
2946 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2950 free_fragment_tree (pm);
2953 GNUNET_assert (pm == pm->qe->pm);
2956 if (NULL != pm->bpm)
2958 free_fragment_tree (pm->bpm);
2959 GNUNET_free (pm->bpm);
2966 * Free virtual link.
2968 * @param vl link data to free
2971 free_virtual_link (struct VirtualLink *vl)
2973 struct PendingMessage *pm;
2974 struct CoreSentContext *csc;
2976 while (NULL != (pm = vl->pending_msg_head))
2977 free_pending_message (pm);
2978 GNUNET_assert (GNUNET_YES ==
2979 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
2980 if (NULL != vl->visibility_task)
2982 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2983 vl->visibility_task = NULL;
2985 if (NULL != vl->fc_retransmit_task)
2987 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
2988 vl->fc_retransmit_task = NULL;
2990 while (NULL != (csc = vl->csc_head))
2992 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
2993 GNUNET_assert (vl == csc->vl);
2996 GNUNET_break (NULL == vl->n);
2997 GNUNET_break (NULL == vl->dv);
3003 * Free validation state.
3005 * @param vs validation state to free
3008 free_validation_state (struct ValidationState *vs)
3012 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
3013 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3017 GNUNET_PEERSTORE_store_cancel (vs->sc);
3020 GNUNET_free (vs->address);
3026 * Lookup neighbour for peer @a pid.
3028 * @param pid neighbour to look for
3029 * @return NULL if we do not have this peer as a neighbour
3031 static struct Neighbour *
3032 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3034 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3039 * Lookup virtual link for peer @a pid.
3041 * @param pid virtual link to look for
3042 * @return NULL if we do not have this peer as a virtual link
3044 static struct VirtualLink *
3045 lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3047 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3052 * Details about what to notify monitors about.
3057 * @deprecated To be discussed if we keep these...
3059 struct GNUNET_TIME_Absolute last_validation;
3060 struct GNUNET_TIME_Absolute valid_until;
3061 struct GNUNET_TIME_Absolute next_validation;
3064 * Current round-trip time estimate.
3066 struct GNUNET_TIME_Relative rtt;
3069 * Connection status.
3071 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3076 uint32_t num_msg_pending;
3081 uint32_t num_bytes_pending;
3086 * Free a @dvh. Callers MAY want to check if this was the last path to the
3087 * `target`, and if so call #free_dv_route to also free the associated DV
3088 * entry in #dv_routes (if not, the associated scheduler job should eventually
3091 * @param dvh hop to free
3094 free_distance_vector_hop (struct DistanceVectorHop *dvh)
3096 struct Neighbour *n = dvh->next_hop;
3097 struct DistanceVector *dv = dvh->dv;
3098 struct PendingAcknowledgement *pa;
3100 while (NULL != (pa = dvh->pa_head))
3102 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3105 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3106 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3112 * Task run to check whether the hops of the @a cls still
3113 * are validated, or if we need to core about disconnection.
3115 * @param cls a `struct VirtualLink`
3118 check_link_down (void *cls);
3122 * Send message to CORE clients that we lost a connection.
3124 * @param pid peer the connection was for
3127 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3130 "Informing CORE clients about disconnect from %s\n",
3132 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3134 struct GNUNET_MQ_Envelope *env;
3135 struct DisconnectInfoMessage *dim;
3137 if (CT_CORE != tc->type)
3139 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3141 GNUNET_MQ_send (tc->mq, env);
3147 * Free entry in #dv_routes. First frees all hops to the target, and
3148 * if there are no entries left, frees @a dv as well.
3150 * @param dv route to free
3153 free_dv_route (struct DistanceVector *dv)
3155 struct DistanceVectorHop *dvh;
3157 while (NULL != (dvh = dv->dv_head))
3158 free_distance_vector_hop (dvh);
3159 if (NULL == dv->dv_head)
3161 struct VirtualLink *vl;
3165 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3166 if (NULL != (vl = dv->vl))
3168 GNUNET_assert (dv == vl->dv);
3172 cores_send_disconnect_info (&dv->target);
3173 free_virtual_link (vl);
3177 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3178 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3183 if (NULL != dv->timeout_task)
3185 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3186 dv->timeout_task = NULL;
3194 * Notify monitor @a tc about an event. That @a tc
3195 * cares about the event has already been checked.
3197 * Send @a tc information in @a me about a @a peer's status with
3198 * respect to some @a address to all monitors that care.
3200 * @param tc monitor to inform
3201 * @param peer peer the information is about
3202 * @param address address the information is about
3203 * @param nt network type associated with @a address
3204 * @param me detailed information to transmit
3207 notify_monitor (struct TransportClient *tc,
3208 const struct GNUNET_PeerIdentity *peer,
3209 const char *address,
3210 enum GNUNET_NetworkType nt,
3211 const struct MonitorEvent *me)
3213 struct GNUNET_MQ_Envelope *env;
3214 struct GNUNET_TRANSPORT_MonitorData *md;
3215 size_t addr_len = strlen (address) + 1;
3217 env = GNUNET_MQ_msg_extra (md,
3219 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3220 md->nt = htonl ((uint32_t) nt);
3222 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3223 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3224 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3225 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3226 md->cs = htonl ((uint32_t) me->cs);
3227 md->num_msg_pending = htonl (me->num_msg_pending);
3228 md->num_bytes_pending = htonl (me->num_bytes_pending);
3229 memcpy (&md[1], address, addr_len);
3230 GNUNET_MQ_send (tc->mq, env);
3235 * Send information in @a me about a @a peer's status with respect
3236 * to some @a address to all monitors that care.
3238 * @param peer peer the information is about
3239 * @param address address the information is about
3240 * @param nt network type associated with @a address
3241 * @param me detailed information to transmit
3244 notify_monitors (const struct GNUNET_PeerIdentity *peer,
3245 const char *address,
3246 enum GNUNET_NetworkType nt,
3247 const struct MonitorEvent *me)
3249 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3251 if (CT_MONITOR != tc->type)
3253 if (tc->details.monitor.one_shot)
3255 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
3256 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3258 notify_monitor (tc, peer, address, nt, me);
3264 * Called whenever a client connects. Allocates our
3265 * data structures associated with that client.
3267 * @param cls closure, NULL
3268 * @param client identification of the client
3269 * @param mq message queue for the client
3270 * @return our `struct TransportClient`
3273 client_connect_cb (void *cls,
3274 struct GNUNET_SERVICE_Client *client,
3275 struct GNUNET_MQ_Handle *mq)
3277 struct TransportClient *tc;
3280 tc = GNUNET_new (struct TransportClient);
3281 tc->client = client;
3283 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
3292 * @param rc data structure to free
3295 free_reassembly_context (struct ReassemblyContext *rc)
3297 struct Neighbour *n = rc->neighbour;
3299 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3300 GNUNET_assert (GNUNET_OK ==
3301 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
3309 * Task run to clean up reassembly context of a neighbour that have expired.
3311 * @param cls a `struct Neighbour`
3314 reassembly_cleanup_task (void *cls)
3316 struct Neighbour *n = cls;
3317 struct ReassemblyContext *rc;
3319 n->reassembly_timeout_task = NULL;
3320 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
3322 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3325 free_reassembly_context (rc);
3328 GNUNET_assert (NULL == n->reassembly_timeout_task);
3329 n->reassembly_timeout_task =
3330 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3331 &reassembly_cleanup_task,
3339 * function called to #free_reassembly_context().
3343 * @param value a `struct ReassemblyContext` to free
3344 * @return #GNUNET_OK (continue iteration)
3347 free_reassembly_cb (void *cls, uint32_t key, void *value)
3349 struct ReassemblyContext *rc = value;
3353 free_reassembly_context (rc);
3359 * Release memory used by @a neighbour.
3361 * @param neighbour neighbour entry to free
3364 free_neighbour (struct Neighbour *neighbour)
3366 struct DistanceVectorHop *dvh;
3367 struct VirtualLink *vl;
3369 GNUNET_assert (NULL == neighbour->queue_head);
3370 GNUNET_assert (GNUNET_YES ==
3371 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3374 if (NULL != neighbour->reassembly_map)
3376 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
3377 &free_reassembly_cb,
3379 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
3380 neighbour->reassembly_map = NULL;
3381 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
3382 neighbour->reassembly_heap = NULL;
3384 while (NULL != (dvh = neighbour->dv_head))
3386 struct DistanceVector *dv = dvh->dv;
3388 free_distance_vector_hop (dvh);
3389 if (NULL == dv->dv_head)
3392 if (NULL != neighbour->reassembly_timeout_task)
3394 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
3395 neighbour->reassembly_timeout_task = NULL;
3397 if (NULL != neighbour->get)
3399 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3400 neighbour->get = NULL;
3402 if (NULL != neighbour->sc)
3404 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3405 neighbour->sc = NULL;
3407 if (NULL != (vl = neighbour->vl))
3409 GNUNET_assert (neighbour == vl->n);
3413 cores_send_disconnect_info (&vl->target);
3414 free_virtual_link (vl);
3418 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3419 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3421 neighbour->vl = NULL;
3423 GNUNET_free (neighbour);
3428 * Send message to CORE clients that we lost a connection.
3430 * @param tc client to inform (must be CORE client)
3431 * @param pid peer the connection is for
3434 core_send_connect_info (struct TransportClient *tc,
3435 const struct GNUNET_PeerIdentity *pid)
3437 struct GNUNET_MQ_Envelope *env;
3438 struct ConnectInfoMessage *cim;
3440 GNUNET_assert (CT_CORE == tc->type);
3441 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3443 GNUNET_MQ_send (tc->mq, env);
3448 * Send message to CORE clients that we gained a connection
3450 * @param pid peer the queue was for
3453 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3456 "Informing CORE clients about connection to %s\n",
3458 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3460 if (CT_CORE != tc->type)
3462 core_send_connect_info (tc, pid);
3468 * We believe we are ready to transmit a message on a queue. Gives the
3469 * message to the communicator for transmission (updating the tracker,
3470 * and re-scheduling itself if applicable).
3472 * @param cls the `struct Queue` to process transmissions for
3475 transmit_on_queue (void *cls);
3479 * Called whenever something changed that might effect when we
3480 * try to do the next transmission on @a queue using #transmit_on_queue().
3482 * @param queue the queue to do scheduling for
3483 * @param p task priority to use, if @a queue is scheduled
3486 schedule_transmit_on_queue (struct Queue *queue,
3487 enum GNUNET_SCHEDULER_Priority p)
3489 if (queue->tc->details.communicator.total_queue_length >=
3490 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3492 GNUNET_STATISTICS_update (
3494 "# Transmission throttled due to communicator queue limit",
3497 queue->idle = GNUNET_NO;
3500 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3502 GNUNET_STATISTICS_update (GST_stats,
3503 "# Transmission throttled due to queue queue limit",
3506 queue->idle = GNUNET_NO;
3509 /* queue might indeed be ready, schedule it */
3510 if (NULL != queue->transmit_task)
3511 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3512 queue->transmit_task =
3513 GNUNET_SCHEDULER_add_with_priority (p, &transmit_on_queue, queue);
3514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3515 "Considering transmission on queue `%s' to %s\n",
3517 GNUNET_i2s (&queue->neighbour->pid));
3522 * Task run to check whether the hops of the @a cls still
3523 * are validated, or if we need to core about disconnection.
3525 * @param cls a `struct VirtualLink`
3528 check_link_down (void *cls)
3530 struct VirtualLink *vl = cls;
3531 struct DistanceVector *dv = vl->dv;
3532 struct Neighbour *n = vl->n;
3533 struct GNUNET_TIME_Absolute dvh_timeout;
3534 struct GNUNET_TIME_Absolute q_timeout;
3536 vl->visibility_task = NULL;
3537 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3538 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3540 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3541 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3546 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3547 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3548 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3549 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3554 if ((NULL == vl->n) && (NULL == vl->dv))
3556 cores_send_disconnect_info (&vl->target);
3557 free_virtual_link (vl);
3560 vl->visibility_task =
3561 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3570 * @param queue the queue to free
3573 free_queue (struct Queue *queue)
3575 struct Neighbour *neighbour = queue->neighbour;
3576 struct TransportClient *tc = queue->tc;
3577 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3578 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3579 struct QueueEntry *qe;
3581 struct PendingAcknowledgement *pa;
3582 struct VirtualLink *vl;
3584 if (NULL != queue->transmit_task)
3586 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3587 queue->transmit_task = NULL;
3589 while (NULL != (pa = queue->pa_head))
3591 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3595 GNUNET_CONTAINER_MDLL_remove (neighbour,
3596 neighbour->queue_head,
3597 neighbour->queue_tail,
3599 GNUNET_CONTAINER_MDLL_remove (client,
3600 tc->details.communicator.queue_head,
3601 tc->details.communicator.queue_tail,
3603 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3604 tc->details.communicator.total_queue_length);
3605 while (NULL != (qe = queue->queue_head))
3607 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3608 queue->queue_length--;
3609 tc->details.communicator.total_queue_length--;
3612 GNUNET_assert (qe == qe->pm->qe);
3617 GNUNET_assert (0 == queue->queue_length);
3618 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3619 tc->details.communicator.total_queue_length))
3621 /* Communicator dropped below threshold, resume all _other_ queues */
3622 GNUNET_STATISTICS_update (
3624 "# Transmission throttled due to communicator queue limit",
3627 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3629 schedule_transmit_on_queue (s, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3631 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3632 GNUNET_free (queue);
3634 vl = lookup_virtual_link (&neighbour->pid);
3635 if ((NULL != vl) && (neighbour == vl->n))
3637 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3638 check_link_down (vl);
3640 if (NULL == neighbour->queue_head)
3642 free_neighbour (neighbour);
3650 * @param ale address list entry to free
3653 free_address_list_entry (struct AddressListEntry *ale)
3655 struct TransportClient *tc = ale->tc;
3657 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3658 tc->details.communicator.addr_tail,
3660 if (NULL != ale->sc)
3662 GNUNET_PEERSTORE_store_cancel (ale->sc);
3665 if (NULL != ale->st)
3667 GNUNET_SCHEDULER_cancel (ale->st);
3675 * Stop the peer request in @a value.
3677 * @param cls a `struct TransportClient` that no longer makes the request
3678 * @param pid the peer's identity
3679 * @param value a `struct PeerRequest`
3680 * @return #GNUNET_YES (always)
3683 stop_peer_request (void *cls,
3684 const struct GNUNET_PeerIdentity *pid,
3687 struct TransportClient *tc = cls;
3688 struct PeerRequest *pr = value;
3690 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3693 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3703 * Called whenever a client is disconnected. Frees our
3704 * resources associated with that client.
3706 * @param cls closure, NULL
3707 * @param client identification of the client
3708 * @param app_ctx our `struct TransportClient`
3711 client_disconnect_cb (void *cls,
3712 struct GNUNET_SERVICE_Client *client,
3715 struct TransportClient *tc = app_ctx;
3719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3720 "Client %p disconnected, cleaning up.\n",
3722 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3728 struct PendingMessage *pm;
3730 while (NULL != (pm = tc->details.core.pending_msg_head))
3732 GNUNET_CONTAINER_MDLL_remove (client,
3733 tc->details.core.pending_msg_head,
3734 tc->details.core.pending_msg_tail,
3742 case CT_COMMUNICATOR: {
3744 struct AddressListEntry *ale;
3746 while (NULL != (q = tc->details.communicator.queue_head))
3748 while (NULL != (ale = tc->details.communicator.addr_head))
3749 free_address_list_entry (ale);
3750 GNUNET_free (tc->details.communicator.address_prefix);
3753 case CT_APPLICATION:
3754 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3757 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3765 * Iterator telling new CORE client about all existing
3766 * connections to peers.
3768 * @param cls the new `struct TransportClient`
3769 * @param pid a connected peer
3770 * @param value the `struct Neighbour` with more information
3771 * @return #GNUNET_OK (continue to iterate)
3774 notify_client_connect_info (void *cls,
3775 const struct GNUNET_PeerIdentity *pid,
3778 struct TransportClient *tc = cls;
3781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3782 "Telling new CORE client about existing connection to %s\n",
3784 core_send_connect_info (tc, pid);
3790 * Initialize a "CORE" client. We got a start message from this
3791 * client, so add it to the list of clients for broadcasting of
3794 * @param cls the client
3795 * @param start the start message that was sent
3798 handle_client_start (void *cls, const struct StartMessage *start)
3800 struct TransportClient *tc = cls;
3803 options = ntohl (start->options);
3804 if ((0 != (1 & options)) &&
3805 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3807 /* client thinks this is a different peer, reject */
3809 GNUNET_SERVICE_client_drop (tc->client);
3812 if (CT_NONE != tc->type)
3815 GNUNET_SERVICE_client_drop (tc->client);
3819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3820 "New CORE client with PID %s registered\n",
3821 GNUNET_i2s (&start->self));
3822 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3823 ¬ify_client_connect_info,
3825 GNUNET_SERVICE_client_continue (tc->client);
3830 * Client asked for transmission to a peer. Process the request.
3832 * @param cls the client
3833 * @param obm the send message that was sent
3836 check_client_send (void *cls, const struct OutboundMessage *obm)
3838 struct TransportClient *tc = cls;
3840 const struct GNUNET_MessageHeader *obmm;
3842 if (CT_CORE != tc->type)
3845 return GNUNET_SYSERR;
3847 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3848 if (size < sizeof (struct GNUNET_MessageHeader))
3851 return GNUNET_SYSERR;
3853 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3854 if (size != ntohs (obmm->size))
3857 return GNUNET_SYSERR;
3864 * Send a response to the @a pm that we have processed a "send"
3865 * request. Sends a confirmation to the "core" client responsible for
3866 * the original request and free's @a pm.
3868 * @param pm handle to the original pending message
3871 client_send_response (struct PendingMessage *pm)
3873 struct TransportClient *tc = pm->client;
3874 struct VirtualLink *vl = pm->vl;
3875 struct GNUNET_MQ_Envelope *env;
3876 struct SendOkMessage *som;
3880 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3881 som->peer = vl->target;
3882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3883 "Confirming transmission of <%llu> to %s\n",
3885 GNUNET_i2s (&vl->target));
3886 GNUNET_MQ_send (tc->mq, env);
3888 free_pending_message (pm);
3893 * Pick @a hops_array_length random DV paths satisfying @a options
3895 * @param dv data structure to pick paths from
3896 * @param options constraints to satisfy
3897 * @param hops_array[out] set to the result
3898 * @param hops_array_length length of the @a hops_array
3899 * @return number of entries set in @a hops_array
3902 pick_random_dv_hops (const struct DistanceVector *dv,
3903 enum RouteMessageOptions options,
3904 struct DistanceVectorHop **hops_array,
3905 unsigned int hops_array_length)
3907 uint64_t choices[hops_array_length];
3909 unsigned int dv_count;
3911 /* Pick random vectors, but weighted by distance, giving more weight
3912 to shorter vectors */
3915 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3918 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3919 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3920 .rel_value_us == 0))
3921 continue; /* pos unconfirmed and confirmed required */
3922 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3927 if (dv_count <= hops_array_length)
3930 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3932 hops_array[dv_count++] = pos;
3935 for (unsigned int i = 0; i < hops_array_length; i++)
3938 while (GNUNET_NO == ok)
3941 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3943 for (unsigned int j = 0; j < i; j++)
3944 if (choices[i] == choices[j])
3953 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3956 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3958 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3959 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3960 .rel_value_us == 0))
3961 continue; /* pos unconfirmed and confirmed required */
3962 for (unsigned int i = 0; i < hops_array_length; i++)
3963 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3964 hops_array[dv_count++] = pos;
3972 * Communicator started. Test message is well-formed.
3974 * @param cls the client
3975 * @param cam the send message that was sent
3978 check_communicator_available (
3980 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3982 struct TransportClient *tc = cls;
3985 if (CT_NONE != tc->type)
3988 return GNUNET_SYSERR;
3990 tc->type = CT_COMMUNICATOR;
3991 size = ntohs (cam->header.size) - sizeof (*cam);
3993 return GNUNET_OK; /* receive-only communicator */
3994 GNUNET_MQ_check_zero_termination (cam);
4000 * Send ACK to communicator (if requested) and free @a cmc.
4002 * @param cmc context for which we are done handling the message
4005 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4007 if (0 != ntohl (cmc->im.fc_on))
4009 /* send ACK when done to communicator for flow control! */
4010 struct GNUNET_MQ_Envelope *env;
4011 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4013 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4014 ack->reserved = htonl (0);
4015 ack->fc_id = cmc->im.fc_id;
4016 ack->sender = cmc->im.sender;
4017 GNUNET_MQ_send (cmc->tc->mq, env);
4019 GNUNET_SERVICE_client_continue (cmc->tc->client);
4025 * Client confirms that it is done handling message(s) to a particular
4026 * peer. We may now provide more messages to CORE for this peer.
4028 * Notifies the respective queues that more messages can now be received.
4030 * @param cls the client
4031 * @param rom the message that was sent
4034 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4036 struct TransportClient *tc = cls;
4037 struct VirtualLink *vl;
4039 struct CommunicatorMessageContext *cmc;
4041 if (CT_CORE != tc->type)
4044 GNUNET_SERVICE_client_drop (tc->client);
4047 vl = lookup_virtual_link (&rom->peer);
4050 GNUNET_STATISTICS_update (GST_stats,
4051 "# RECV_OK dropped: virtual link unknown",
4054 GNUNET_SERVICE_client_continue (tc->client);
4057 delta = ntohl (rom->increase_window_delta);
4058 vl->core_recv_window += delta;
4059 if (vl->core_recv_window <= 0)
4061 /* resume communicators */
4062 while (NULL != (cmc = vl->cmc_tail))
4064 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4065 finish_cmc_handling (cmc);
4071 * Communicator started. Process the request.
4073 * @param cls the client
4074 * @param cam the send message that was sent
4077 handle_communicator_available (
4079 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4081 struct TransportClient *tc = cls;
4084 size = ntohs (cam->header.size) - sizeof (*cam);
4087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4088 "Receive-only communicator connected\n");
4089 return; /* receive-only communicator */
4091 tc->details.communicator.address_prefix =
4092 GNUNET_strdup ((const char *) &cam[1]);
4093 tc->details.communicator.cc =
4094 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4096 "Communicator with prefix `%s' connected\n",
4097 tc->details.communicator.address_prefix);
4098 GNUNET_SERVICE_client_continue (tc->client);
4103 * Communicator requests backchannel transmission. Check the request.
4105 * @param cls the client
4106 * @param cb the send message that was sent
4107 * @return #GNUNET_OK if message is well-formed
4110 check_communicator_backchannel (
4112 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4114 const struct GNUNET_MessageHeader *inbox;
4120 msize = ntohs (cb->header.size) - sizeof (*cb);
4121 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4122 isize = ntohs (inbox->size);
4126 return GNUNET_SYSERR;
4128 is = (const char *) inbox;
4131 GNUNET_assert (0 < msize);
4132 if ('\0' != is[msize - 1])
4135 return GNUNET_SYSERR;
4142 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4145 * @param dv[in,out] virtual link to update ephemeral for
4148 update_ephemeral (struct DistanceVector *dv)
4150 struct EphemeralConfirmationPS ec;
4153 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4155 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4156 dv->ephemeral_validity =
4157 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4158 GNUNET_assert (GNUNET_OK ==
4159 GNUNET_CRYPTO_ecdhe_key_create2 (&dv->private_key));
4160 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4161 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4162 ec.purpose.size = htonl (sizeof (ec));
4163 ec.target = dv->target;
4164 ec.ephemeral_key = dv->ephemeral_key;
4165 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4172 * Send the message @a payload on @a queue.
4174 * @param queue the queue to use for transmission
4175 * @param pm pending message to update once transmission is done, may be NULL!
4176 * @param payload the payload to send (encapsulated in a
4177 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4178 * @param payload_size number of bytes in @a payload
4181 queue_send_msg (struct Queue *queue,
4182 struct PendingMessage *pm,
4183 const void *payload,
4184 size_t payload_size)
4186 struct Neighbour *n = queue->neighbour;
4187 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4188 struct GNUNET_MQ_Envelope *env;
4190 queue->idle = GNUNET_NO;
4192 GNUNET_ERROR_TYPE_DEBUG,
4193 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4194 (unsigned int) payload_size,
4195 (NULL == pm) ? 0 : pm->logging_uuid,
4196 (unsigned long long) queue->qid,
4197 GNUNET_i2s (&queue->neighbour->pid));
4198 env = GNUNET_MQ_msg_extra (smt,
4200 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4201 smt->qid = queue->qid;
4202 smt->mid = queue->mid_gen;
4203 smt->receiver = n->pid;
4204 memcpy (&smt[1], payload, payload_size);
4206 /* Pass the env to the communicator of queue for transmission. */
4207 struct QueueEntry *qe;
4209 qe = GNUNET_new (struct QueueEntry);
4210 qe->mid = queue->mid_gen++;
4215 GNUNET_assert (NULL == pm->qe);
4218 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4219 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4220 queue->queue_length++;
4221 queue->tc->details.communicator.total_queue_length++;
4222 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4223 queue->tc->details.communicator.total_queue_length)
4224 queue->idle = GNUNET_NO;
4225 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4226 queue->idle = GNUNET_NO;
4227 GNUNET_MQ_send (queue->tc->mq, env);
4233 * Pick a queue of @a n under constraints @a options and schedule
4234 * transmission of @a hdr.
4236 * @param n neighbour to send to
4237 * @param hdr message to send as payload
4238 * @param options whether queues must be confirmed or not,
4239 * and whether we may pick multiple (2) queues
4240 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4242 static struct GNUNET_TIME_Relative
4243 route_via_neighbour (const struct Neighbour *n,
4244 const struct GNUNET_MessageHeader *hdr,
4245 enum RouteMessageOptions options)
4247 struct GNUNET_TIME_Absolute now;
4248 unsigned int candidates;
4251 struct GNUNET_TIME_Relative rtt;
4253 /* Pick one or two 'random' queues from n (under constraints of options) */
4254 now = GNUNET_TIME_absolute_get ();
4255 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4256 weight in the future; weight could be assigned by observed
4257 bandwidth (note: not sure if we should do this for this type
4258 of control traffic though). */
4260 for (struct Queue *pos = n->queue_head; NULL != pos;
4261 pos = pos->next_neighbour)
4263 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4264 (pos->validated_until.abs_value_us > now.abs_value_us))
4267 if (0 == candidates)
4269 /* This can happen rarely if the last confirmed queue timed
4270 out just as we were beginning to process this message. */
4271 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4272 "Could not route message of type %u to %s: no valid queue\n",
4274 GNUNET_i2s (&n->pid));
4275 GNUNET_STATISTICS_update (GST_stats,
4276 "# route selection failed (all no valid queue)",
4279 return GNUNET_TIME_UNIT_FOREVER_REL;
4282 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4283 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4284 if (0 == (options & RMO_REDUNDANT))
4285 sel2 = candidates; /* picks none! */
4287 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4289 for (struct Queue *pos = n->queue_head; NULL != pos;
4290 pos = pos->next_neighbour)
4292 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4293 (pos->validated_until.abs_value_us > now.abs_value_us))
4295 if ((sel1 == candidates) || (sel2 == candidates))
4297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4298 "Routing message of type %u to %s using %s (#%u)\n",
4300 GNUNET_i2s (&n->pid),
4302 (sel1 == candidates) ? 1 : 2);
4303 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4304 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4314 * Structure of the key material used to encrypt backchannel messages.
4319 * State of our block cipher.
4321 gcry_cipher_hd_t cipher;
4324 * Actual key material.
4330 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4332 struct GNUNET_CRYPTO_AuthKey hmac_key;
4335 * Symmetric key to use for encryption.
4337 char aes_key[256 / 8];
4340 * Counter value to use during setup.
4342 char aes_ctr[128 / 8];
4349 * Given the key material in @a km and the initialization vector
4350 * @a iv, setup the key material for the backchannel in @a key.
4352 * @param km raw master secret
4353 * @param iv initialization vector
4354 * @param key[out] symmetric cipher and HMAC state to generate
4357 dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4358 const struct GNUNET_ShortHashCode *iv,
4359 struct DVKeyState *key)
4361 /* must match #dh_key_derive_eph_pub */
4362 GNUNET_assert (GNUNET_YES ==
4363 GNUNET_CRYPTO_kdf (&key->material,
4364 sizeof (key->material),
4365 "transport-backchannel-key",
4366 strlen ("transport-backchannel-key"),
4371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4372 "Deriving backchannel key based on KM %s and IV %s\n",
4375 gcry_cipher_open (&key->cipher,
4376 GCRY_CIPHER_AES256 /* low level: go for speed */,
4377 GCRY_CIPHER_MODE_CTR,
4379 gcry_cipher_setkey (key->cipher,
4380 &key->material.aes_key,
4381 sizeof (key->material.aes_key));
4382 gcry_cipher_setctr (key->cipher,
4383 &key->material.aes_ctr,
4384 sizeof (key->material.aes_ctr));
4389 * Derive backchannel encryption key material from @a priv_ephemeral
4390 * and @a target and @a iv.
4392 * @param priv_ephemeral ephemeral private key to use
4393 * @param target the target peer to encrypt to
4394 * @param iv unique IV to use
4395 * @param key[out] set to the key material
4398 dh_key_derive_eph_pid (
4399 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4400 const struct GNUNET_PeerIdentity *target,
4401 const struct GNUNET_ShortHashCode *iv,
4402 struct DVKeyState *key)
4404 struct GNUNET_HashCode km;
4406 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4407 &target->public_key,
4409 dv_setup_key_state_from_km (&km, iv, key);
4414 * Derive backchannel encryption key material from #GST_my_private_key
4415 * and @a pub_ephemeral and @a iv.
4417 * @param priv_ephemeral ephemeral private key to use
4418 * @param target the target peer to encrypt to
4419 * @param iv unique IV to use
4420 * @param key[out] set to the key material
4423 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4424 const struct GNUNET_ShortHashCode *iv,
4425 struct DVKeyState *key)
4427 struct GNUNET_HashCode km;
4429 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4432 dv_setup_key_state_from_km (&km, iv, key);
4437 * Do HMAC calculation for backchannel messages over @a data using key
4438 * material from @a key.
4440 * @param key key material (from DH)
4441 * @param hmac[out] set to the HMAC
4442 * @param data data to perform HMAC calculation over
4443 * @param data_size number of bytes in @a data
4446 dv_hmac (const struct DVKeyState *key,
4447 struct GNUNET_HashCode *hmac,
4451 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4456 * Perform backchannel encryption using symmetric secret in @a key
4457 * to encrypt data from @a in to @a dst.
4459 * @param key[in,out] key material to use
4460 * @param dst where to write the result
4461 * @param in input data to encrypt (plaintext)
4462 * @param in_size number of bytes of input in @a in and available at @a dst
4465 dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4468 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4473 * Perform backchannel encryption using symmetric secret in @a key
4474 * to encrypt data from @a in to @a dst.
4476 * @param key[in,out] key material to use
4477 * @param ciph cipher text to decrypt
4478 * @param out[out] output data to generate (plaintext)
4479 * @param out_size number of bytes of input in @a ciph and available in @a out
4482 dv_decrypt (struct DVKeyState *key,
4488 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4493 * Clean up key material in @a key.
4495 * @param key key material to clean up (memory must not be free'd!)
4498 dv_key_clean (struct DVKeyState *key)
4500 gcry_cipher_close (key->cipher);
4501 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4506 * Function to call to further operate on the now DV encapsulated
4507 * message @a hdr, forwarding it via @a next_hop under respect of
4510 * @param cls closure
4511 * @param next_hop next hop of the DV path
4512 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4513 * @param options options of the original message
4515 typedef void (*DVMessageHandler) (void *cls,
4516 struct Neighbour *next_hop,
4517 const struct GNUNET_MessageHeader *hdr,
4518 enum RouteMessageOptions options);
4521 * Pick a path of @a dv under constraints @a options and schedule
4522 * transmission of @a hdr.
4524 * @param target neighbour to ultimately send to
4525 * @param num_dvhs length of the @a dvhs array
4526 * @param dvhs array of hops to send the message to
4527 * @param hdr message to send as payload
4528 * @param use function to call with the encapsulated message
4529 * @param use_cls closure for @a use
4530 * @param options whether path must be confirmed or not, to be passed to @a use
4531 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4533 static struct GNUNET_TIME_Relative
4534 encapsulate_for_dv (struct DistanceVector *dv,
4535 unsigned int num_dvhs,
4536 struct DistanceVectorHop **dvhs,
4537 const struct GNUNET_MessageHeader *hdr,
4538 DVMessageHandler use,
4540 enum RouteMessageOptions options)
4542 struct TransportDVBoxMessage box_hdr;
4543 struct TransportDVBoxPayloadP payload_hdr;
4544 uint16_t enc_body_size = ntohs (hdr->size);
4545 char enc[sizeof (struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4546 struct TransportDVBoxPayloadP *enc_payload_hdr =
4547 (struct TransportDVBoxPayloadP *) enc;
4548 struct DVKeyState key;
4549 struct GNUNET_TIME_Relative rtt;
4551 /* Encrypt payload */
4552 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4553 box_hdr.total_hops = htons (0);
4554 update_ephemeral (dv);
4555 box_hdr.ephemeral_key = dv->ephemeral_key;
4556 payload_hdr.sender_sig = dv->sender_sig;
4557 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4559 sizeof (box_hdr.iv));
4560 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, &key);
4561 payload_hdr.sender = GST_my_identity;
4562 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4563 dv_encrypt (&key, &payload_hdr, enc_payload_hdr, sizeof (payload_hdr));
4566 &enc[sizeof (struct TransportDVBoxPayloadP)],
4568 dv_hmac (&key, &box_hdr.hmac, enc, sizeof (enc));
4569 dv_key_clean (&key);
4570 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4571 /* For each selected path, take the pre-computed header and body
4572 and add the path in the middle of the message; then send it. */
4573 for (unsigned int i = 0; i < num_dvhs; i++)
4575 struct DistanceVectorHop *dvh = dvhs[i];
4576 unsigned int num_hops = dvh->distance + 1;
4577 char buf[sizeof (struct TransportDVBoxMessage) +
4578 sizeof (struct GNUNET_PeerIdentity) * num_hops +
4579 sizeof (struct TransportDVBoxPayloadP) +
4580 enc_body_size] GNUNET_ALIGN;
4581 struct GNUNET_PeerIdentity *dhops;
4583 box_hdr.header.size = htons (sizeof (buf));
4584 box_hdr.num_hops = htons (num_hops);
4585 memcpy (buf, &box_hdr, sizeof (box_hdr));
4586 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof (box_hdr)];
4589 dvh->distance * sizeof (struct GNUNET_PeerIdentity));
4590 dhops[dvh->distance] = dv->target;
4591 if (GNUNET_EXTRA_LOGGING > 0)
4595 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4596 for (unsigned int i = 0; i <= num_hops; i++)
4600 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
4604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4605 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4607 GNUNET_i2s (&dv->target),
4613 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4614 memcpy (&dhops[num_hops], enc, sizeof (enc));
4617 (const struct GNUNET_MessageHeader *) buf,
4625 * Wrapper around #route_via_neighbour() that matches the
4626 * #DVMessageHandler structure.
4629 * @param next_hop where to send next
4630 * @param hdr header of the message to send
4631 * @param options message options for queue selection
4634 send_dv_to_neighbour (void *cls,
4635 struct Neighbour *next_hop,
4636 const struct GNUNET_MessageHeader *hdr,
4637 enum RouteMessageOptions options)
4640 (void) route_via_neighbour (next_hop, hdr, options);
4645 * We need to transmit @a hdr to @a target. If necessary, this may
4646 * involve DV routing. This function routes without applying flow
4647 * control or congestion control and should only be used for control
4650 * @param target peer to receive @a hdr
4651 * @param hdr header of the message to route and #GNUNET_free()
4652 * @param options which transmission channels are allowed
4653 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4655 static struct GNUNET_TIME_Relative
4656 route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4657 const struct GNUNET_MessageHeader *hdr,
4658 enum RouteMessageOptions options)
4660 struct VirtualLink *vl;
4661 struct Neighbour *n;
4662 struct DistanceVector *dv;
4663 struct GNUNET_TIME_Relative rtt1;
4664 struct GNUNET_TIME_Relative rtt2;
4666 vl = lookup_virtual_link (target);
4667 GNUNET_assert (NULL != vl);
4669 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4670 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4672 /* if confirmed is required, and we do not have anything
4673 confirmed, drop respective options */
4675 n = lookup_neighbour (target);
4676 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4677 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4679 if ((NULL == n) && (NULL == dv))
4681 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4682 "Cannot route message of type %u to %s: no route\n",
4684 GNUNET_i2s (target));
4685 GNUNET_STATISTICS_update (GST_stats,
4686 "# Messages dropped in routing: no acceptable method",
4689 return GNUNET_TIME_UNIT_FOREVER_REL;
4691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4692 "Routing message of type %u to %s with options %X\n",
4694 GNUNET_i2s (target),
4695 (unsigned int) options);
4696 /* If both dv and n are possible and we must choose:
4697 flip a coin for the choice between the two; for now 50/50 */
4698 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4700 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4705 if ((NULL != n) && (NULL != dv))
4706 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4707 enough for redunancy, so clear the flag. */
4708 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4709 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4712 rtt1 = route_via_neighbour (n, hdr, options);
4716 struct DistanceVectorHop *hops[2];
4719 res = pick_random_dv_hops (dv,
4722 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4725 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4726 "Failed to route message, could not determine DV path\n");
4729 rtt2 = encapsulate_for_dv (dv,
4733 &send_dv_to_neighbour,
4735 options & (~RMO_REDUNDANT));
4737 return GNUNET_TIME_relative_min (rtt1, rtt2);
4742 * Something changed on the virtual link with respect to flow
4743 * control. Consider retransmitting the FC window size.
4745 * @param cls a `struct VirtualLink` to work with
4748 consider_sending_fc (void *cls)
4750 struct VirtualLink *vl = cls;
4751 struct GNUNET_TIME_Absolute monotime;
4752 struct TransportFlowControlMessage fc;
4753 struct GNUNET_TIME_Relative duration;
4754 struct GNUNET_TIME_Relative rtt;
4756 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
4757 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
4759 /* For example, we should probably ONLY do this if a bit more than
4760 an RTT has passed, or if the window changed "significantly" since
4761 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
4762 need an estimate for the bandwidth-delay-product for the entire
4763 VL, as that determines "significantly". We have the delay, but
4764 the bandwidth statistics need to be added for the VL!*/
4767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4768 "Sending FC seq %u to %s with new window %llu\n",
4769 (unsigned int) vl->fc_seq_gen,
4770 GNUNET_i2s (&vl->target),
4771 (unsigned long long) vl->incoming_fc_window_size);
4772 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4773 vl->last_fc_transmission = monotime;
4774 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
4775 fc.header.size = htons (sizeof (fc));
4776 fc.seq = htonl (vl->fc_seq_gen++);
4777 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
4778 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
4779 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
4780 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
4781 rtt = route_control_message_without_fc (&vl->target, &fc.header, RMO_NONE);
4782 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
4784 rtt = GNUNET_TIME_UNIT_SECONDS;
4785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4786 "FC retransmission to %s failed, will retry in %s\n",
4787 GNUNET_i2s (&vl->target),
4788 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
4789 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
4793 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
4794 vl->last_fc_rtt = rtt;
4796 if (NULL != vl->fc_retransmit_task)
4797 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
4798 vl->fc_retransmit_task =
4799 GNUNET_SCHEDULER_add_delayed (rtt, &consider_sending_fc, vl);
4804 * There is a message at the head of the pending messages for @a vl
4805 * which may be ready for transmission. Check if a queue is ready to
4808 * This function must (1) check for flow control to ensure that we can
4809 * right now send to @a vl, (2) check that the pending message in the
4810 * queue is actually eligible, (3) determine if any applicable queue
4811 * (direct neighbour or DVH path) is ready to accept messages, and
4812 * (4) prioritize based on the preferences associated with the
4817 * @param vl virtual link where we should check for transmission
4820 check_vl_transmission (struct VirtualLink *vl)
4822 struct Neighbour *n = vl->n;
4823 struct DistanceVector *dv = vl->dv;
4824 struct GNUNET_TIME_Absolute now;
4827 /* Check that we have an eligible pending message!
4828 (cheaper than having #transmit_on_queue() find out!) */
4830 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
4834 continue; /* not eligible, is in a queue! */
4835 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
4836 vl->outbound_fc_window_size)
4838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4839 "Stalled transmision on VL %s due to flow control: %llu < %llu\n",
4840 GNUNET_i2s (&vl->target),
4841 (unsigned long long) vl->outbound_fc_window_size,
4842 (unsigned long long) (pm->bytes_msg +
4843 vl->outbound_fc_window_size_used));
4844 consider_sending_fc (vl);
4845 return; /* We have a message, but flow control says "nope" */
4850 if (GNUNET_NO == elig)
4853 /* Notify queues at direct neighbours that we are interested */
4854 now = GNUNET_TIME_absolute_get ();
4857 for (struct Queue *queue = n->queue_head; NULL != queue;
4858 queue = queue->next_neighbour)
4859 if ((GNUNET_YES == queue->idle) &&
4860 (queue->validated_until.abs_value_us > now.abs_value_us))
4861 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4863 /* Notify queues via DV that we are interested */
4866 /* Do DV with lower scheduler priority, which effectively means that
4867 IF a neighbour exists and is available, we prefer it. */
4868 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4871 struct Neighbour *nh = pos->next_hop;
4873 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
4874 continue; /* skip this one: path not validated */
4875 for (struct Queue *queue = nh->queue_head; NULL != queue;
4876 queue = queue->next_neighbour)
4877 if ((GNUNET_YES == queue->idle) &&
4878 (queue->validated_until.abs_value_us > now.abs_value_us))
4879 schedule_transmit_on_queue (queue,
4880 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
4887 * Client asked for transmission to a peer. Process the request.
4889 * @param cls the client
4890 * @param obm the send message that was sent
4893 handle_client_send (void *cls, const struct OutboundMessage *obm)
4895 struct TransportClient *tc = cls;
4896 struct PendingMessage *pm;
4897 const struct GNUNET_MessageHeader *obmm;
4899 struct VirtualLink *vl;
4900 enum GNUNET_MQ_PriorityPreferences pp;
4902 GNUNET_assert (CT_CORE == tc->type);
4903 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4904 bytes_msg = ntohs (obmm->size);
4905 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
4906 vl = lookup_virtual_link (&obm->peer);
4909 /* Failure: don't have this peer as a neighbour (anymore).
4910 Might have gone down asynchronously, so this is NOT
4911 a protocol violation by CORE. Still count the event,
4912 as this should be rare. */
4913 GNUNET_SERVICE_client_continue (tc->client);
4914 GNUNET_STATISTICS_update (GST_stats,
4915 "# messages dropped (neighbour unknown)",
4921 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
4922 pm->logging_uuid = logging_uuid_gen++;
4926 pm->bytes_msg = bytes_msg;
4927 memcpy (&pm[1], obmm, bytes_msg);
4928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4929 "Sending %u bytes as <%llu> to %s\n",
4932 GNUNET_i2s (&obm->peer));
4933 GNUNET_CONTAINER_MDLL_insert (client,
4934 tc->details.core.pending_msg_head,
4935 tc->details.core.pending_msg_tail,
4937 GNUNET_CONTAINER_MDLL_insert (vl,
4938 vl->pending_msg_head,
4939 vl->pending_msg_tail,
4941 check_vl_transmission (vl);
4946 * Communicator requests backchannel transmission. Process the request.
4947 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
4948 * (which for now has exactly the same format, only a different message type)
4949 * and passes it on for routing.
4951 * @param cls the client
4952 * @param cb the send message that was sent
4955 handle_communicator_backchannel (
4957 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4959 struct TransportClient *tc = cls;
4960 const struct GNUNET_MessageHeader *inbox =
4961 (const struct GNUNET_MessageHeader *) &cb[1];
4962 uint16_t isize = ntohs (inbox->size);
4963 const char *is = ((const char *) &cb[1]) + isize;
4966 sizeof (struct TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
4967 struct TransportBackchannelEncapsulationMessage *be =
4968 (struct TransportBackchannelEncapsulationMessage *) mbuf;
4970 /* 0-termination of 'is' was checked already in
4971 #check_communicator_backchannel() */
4972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4973 "Preparing backchannel transmission to %s:%s of type %u\n",
4974 GNUNET_i2s (&cb->pid),
4976 ntohs (inbox->size));
4977 /* encapsulate and encrypt message */
4979 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4980 be->header.size = htons (sizeof (mbuf));
4981 memcpy (&be[1], inbox, isize);
4982 memcpy (&mbuf[sizeof (struct TransportBackchannelEncapsulationMessage) +
4986 route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
4987 GNUNET_SERVICE_client_continue (tc->client);
4992 * Address of our peer added. Test message is well-formed.
4994 * @param cls the client
4995 * @param aam the send message that was sent
4996 * @return #GNUNET_OK if message is well-formed
4999 check_add_address (void *cls,
5000 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5002 struct TransportClient *tc = cls;
5004 if (CT_COMMUNICATOR != tc->type)
5007 return GNUNET_SYSERR;
5009 GNUNET_MQ_check_zero_termination (aam);
5015 * Ask peerstore to store our address.
5017 * @param cls an `struct AddressListEntry *`
5020 store_pi (void *cls);
5024 * Function called when peerstore is done storing our address.
5026 * @param cls a `struct AddressListEntry`
5027 * @param success #GNUNET_YES if peerstore was successful
5030 peerstore_store_own_cb (void *cls, int success)
5032 struct AddressListEntry *ale = cls;
5035 if (GNUNET_YES != success)
5036 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5037 "Failed to store our own address `%s' in peerstore!\n",
5040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5041 "Successfully stored our own address `%s' in peerstore!\n",
5043 /* refresh period is 1/4 of expiration time, that should be plenty
5044 without being excessive. */
5046 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5054 * Ask peerstore to store our address.
5056 * @param cls an `struct AddressListEntry *`
5059 store_pi (void *cls)
5061 struct AddressListEntry *ale = cls;
5064 struct GNUNET_TIME_Absolute expiration;
5067 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5069 "Storing our address `%s' in peerstore until %s!\n",
5071 GNUNET_STRINGS_absolute_time_to_string (expiration));
5072 GNUNET_HELLO_sign_address (ale->address,
5078 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5081 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5085 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5086 &peerstore_store_own_cb,
5089 if (NULL == ale->sc)
5091 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5092 "Failed to store our address `%s' with peerstore\n",
5095 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5101 * Address of our peer added. Process the request.
5103 * @param cls the client
5104 * @param aam the send message that was sent
5107 handle_add_address (void *cls,
5108 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5110 struct TransportClient *tc = cls;
5111 struct AddressListEntry *ale;
5114 /* 0-termination of &aam[1] was checked in #check_add_address */
5115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5116 "Communicator added address `%s'!\n",
5117 (const char *) &aam[1]);
5118 slen = ntohs (aam->header.size) - sizeof (*aam);
5119 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
5121 ale->address = (const char *) &ale[1];
5122 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5123 ale->aid = aam->aid;
5124 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5125 memcpy (&ale[1], &aam[1], slen);
5126 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5127 tc->details.communicator.addr_tail,
5129 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5130 GNUNET_SERVICE_client_continue (tc->client);
5135 * Address of our peer deleted. Process the request.
5137 * @param cls the client
5138 * @param dam the send message that was sent
5141 handle_del_address (void *cls,
5142 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5144 struct TransportClient *tc = cls;
5145 struct AddressListEntry *alen;
5147 if (CT_COMMUNICATOR != tc->type)
5150 GNUNET_SERVICE_client_drop (tc->client);
5153 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5158 if (dam->aid != ale->aid)
5160 GNUNET_assert (ale->tc == tc);
5161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5162 "Communicator deleted address `%s'!\n",
5164 free_address_list_entry (ale);
5165 GNUNET_SERVICE_client_continue (tc->client);
5168 GNUNET_SERVICE_client_drop (tc->client);
5173 * Given an inbound message @a msg from a communicator @a cmc,
5174 * demultiplex it based on the type calling the right handler.
5176 * @param cmc context for demultiplexing
5177 * @param msg message to demultiplex
5180 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5181 const struct GNUNET_MessageHeader *msg);
5185 * Function called when we are done giving a message of a certain
5186 * size to CORE and should thus decrement the number of bytes of
5187 * RAM reserved for that peer's MQ.
5189 * @param cls a `struct CoreSentContext`
5192 core_env_sent_cb (void *cls)
5194 struct CoreSentContext *ctx = cls;
5195 struct VirtualLink *vl = ctx->vl;
5199 /* lost the link in the meantime, ignore */
5203 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5204 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5205 vl->incoming_fc_window_size_ram -= ctx->size;
5206 vl->incoming_fc_window_size_used += ctx->isize;
5207 consider_sending_fc (vl);
5213 * Communicator gave us an unencapsulated message to pass as-is to
5214 * CORE. Process the request.
5216 * @param cls a `struct CommunicatorMessageContext` (must call
5217 * #finish_cmc_handling() when done)
5218 * @param mh the message that was received
5221 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5223 struct CommunicatorMessageContext *cmc = cls;
5224 struct VirtualLink *vl;
5225 uint16_t size = ntohs (mh->size);
5228 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
5229 (size < sizeof (struct GNUNET_MessageHeader)))
5231 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5234 finish_cmc_handling (cmc);
5235 GNUNET_SERVICE_client_drop (client);
5238 vl = lookup_virtual_link (&cmc->im.sender);
5241 /* FIXME: sender is giving us messages for CORE but we don't have
5242 the link up yet! I *suspect* this can happen right now (i.e.
5243 sender has verified us, but we didn't verify sender), but if
5244 we pass this on, CORE would be confused (link down, messages
5245 arrive). We should investigate more if this happens often,
5246 or in a persistent manner, and possibly do "something" about
5247 it. Thus logging as error for now. */
5248 GNUNET_break_op (0);
5249 GNUNET_STATISTICS_update (GST_stats,
5250 "# CORE messages droped (virtual link still down)",
5254 finish_cmc_handling (cmc);
5257 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5259 GNUNET_STATISTICS_update (GST_stats,
5260 "# CORE messages droped (FC arithmetic overflow)",
5264 finish_cmc_handling (cmc);
5267 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5269 GNUNET_STATISTICS_update (GST_stats,
5270 "# CORE messages droped (FC window overflow)",
5273 finish_cmc_handling (cmc);
5277 /* Forward to all CORE clients */
5278 have_core = GNUNET_NO;
5279 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5281 struct GNUNET_MQ_Envelope *env;
5282 struct InboundMessage *im;
5283 struct CoreSentContext *ctx;
5285 if (CT_CORE != tc->type)
5287 vl->incoming_fc_window_size_ram += size;
5288 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5289 ctx = GNUNET_new (struct CoreSentContext);
5292 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5293 have_core = GNUNET_YES;
5294 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5295 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5296 im->peer = cmc->im.sender;
5297 memcpy (&im[1], mh, size);
5298 GNUNET_MQ_send (tc->mq, env);
5299 vl->core_recv_window--;
5301 if (GNUNET_NO == have_core)
5303 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5304 "Dropped message to CORE: no CORE client connected!\n");
5305 /* Nevertheless, count window as used, as it is from the
5306 perspective of the other peer! */
5307 vl->incoming_fc_window_size_used += size;
5309 finish_cmc_handling (cmc);
5312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5313 "Delivered message from %s of type %u to CORE\n",
5314 GNUNET_i2s (&cmc->im.sender),
5316 if (vl->core_recv_window > 0)
5318 finish_cmc_handling (cmc);
5321 /* Wait with calling #finish_cmc_handling(cmc) until the message
5322 was processed by CORE MQs (for CORE flow control)! */
5323 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5328 * Communicator gave us a fragment box. Check the message.
5330 * @param cls a `struct CommunicatorMessageContext`
5331 * @param fb the send message that was sent
5332 * @return #GNUNET_YES if message is well-formed
5335 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5337 uint16_t size = ntohs (fb->header.size);
5338 uint16_t bsize = size - sizeof (*fb);
5343 GNUNET_break_op (0);
5344 return GNUNET_SYSERR;
5346 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5348 GNUNET_break_op (0);
5349 return GNUNET_SYSERR;
5351 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5353 GNUNET_break_op (0);
5354 return GNUNET_SYSERR;
5361 * Clean up an idle cummulative acknowledgement data structure.
5363 * @param cls a `struct AcknowledgementCummulator *`
5366 destroy_ack_cummulator (void *cls)
5368 struct AcknowledgementCummulator *ac = cls;
5371 GNUNET_assert (0 == ac->num_acks);
5374 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5380 * Do the transmission of a cummulative acknowledgement now.
5382 * @param cls a `struct AcknowledgementCummulator *`
5385 transmit_cummulative_ack_cb (void *cls)
5387 struct AcknowledgementCummulator *ac = cls;
5388 char buf[sizeof (struct TransportReliabilityAckMessage) +
5390 sizeof (struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5391 struct TransportReliabilityAckMessage *ack =
5392 (struct TransportReliabilityAckMessage *) buf;
5393 struct TransportCummulativeAckPayloadP *ap;
5396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5397 "Sending ACK with %u components to %s\n",
5399 GNUNET_i2s (&ac->target));
5400 GNUNET_assert (0 < ac->ack_counter);
5401 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5403 htons (sizeof (*ack) +
5404 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
5405 ack->ack_counter = htonl (ac->ack_counter++);
5406 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5407 for (unsigned int i = 0; i < ac->ack_counter; i++)
5409 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5410 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5411 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5413 route_control_message_without_fc (&ac->target, &ack->header, RMO_DV_ALLOWED);
5415 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5416 &destroy_ack_cummulator,
5422 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5423 * transmission by at most @a ack_delay.
5425 * @param pid target peer
5426 * @param ack_uuid UUID to ack
5427 * @param max_delay how long can the ACK wait
5430 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5431 const struct AcknowledgementUUIDP *ack_uuid,
5432 struct GNUNET_TIME_Absolute max_delay)
5434 struct AcknowledgementCummulator *ac;
5436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5437 "Scheduling ACK %s for transmission to %s\n",
5438 GNUNET_uuid2s (&ack_uuid->value),
5440 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5443 ac = GNUNET_new (struct AcknowledgementCummulator);
5445 ac->min_transmission_time = max_delay;
5446 GNUNET_assert (GNUNET_YES ==
5447 GNUNET_CONTAINER_multipeermap_put (
5451 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5455 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5457 /* must run immediately, ack buffer full! */
5458 GNUNET_SCHEDULER_cancel (ac->task);
5459 transmit_cummulative_ack_cb (ac);
5461 GNUNET_SCHEDULER_cancel (ac->task);
5462 ac->min_transmission_time =
5463 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5465 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5466 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5467 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5469 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5470 &transmit_cummulative_ack_cb,
5476 * Closure for #find_by_message_uuid.
5478 struct FindByMessageUuidContext
5483 struct MessageUUIDP message_uuid;
5486 * Set to the reassembly context if found.
5488 struct ReassemblyContext *rc;
5493 * Iterator called to find a reassembly context by the message UUID in the
5496 * @param cls a `struct FindByMessageUuidContext`
5497 * @param key a key (unused)
5498 * @param value a `struct ReassemblyContext`
5499 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5502 find_by_message_uuid (void *cls, uint32_t key, void *value)
5504 struct FindByMessageUuidContext *fc = cls;
5505 struct ReassemblyContext *rc = value;
5508 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5518 * Communicator gave us a fragment. Process the request.
5520 * @param cls a `struct CommunicatorMessageContext` (must call
5521 * #finish_cmc_handling() when done)
5522 * @param fb the message that was received
5525 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5527 struct CommunicatorMessageContext *cmc = cls;
5528 struct Neighbour *n;
5529 struct ReassemblyContext *rc;
5530 const struct GNUNET_MessageHeader *msg;
5535 struct GNUNET_TIME_Relative cdelay;
5536 struct FindByMessageUuidContext fc;
5538 n = lookup_neighbour (&cmc->im.sender);
5541 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5544 finish_cmc_handling (cmc);
5545 GNUNET_SERVICE_client_drop (client);
5548 if (NULL == n->reassembly_map)
5550 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5551 n->reassembly_heap =
5552 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5553 n->reassembly_timeout_task =
5554 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5555 &reassembly_cleanup_task,
5558 msize = ntohs (fb->msg_size);
5559 fc.message_uuid = fb->msg_uuid;
5561 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5563 &find_by_message_uuid,
5565 if (NULL == (rc = fc.rc))
5567 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5568 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5569 rc->msg_uuid = fb->msg_uuid;
5571 rc->msg_size = msize;
5572 rc->reassembly_timeout =
5573 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5574 rc->last_frag = GNUNET_TIME_absolute_get ();
5575 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5577 rc->reassembly_timeout.abs_value_us);
5578 GNUNET_assert (GNUNET_OK ==
5579 GNUNET_CONTAINER_multihashmap32_put (
5583 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5584 target = (char *) &rc[1];
5585 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5586 rc->msg_missing = rc->msg_size;
5587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5588 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5589 ntohs (fb->frag_off),
5591 GNUNET_i2s (&cmc->im.sender),
5592 (unsigned int) fb->msg_uuid.uuid);
5596 target = (char *) &rc[1];
5597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5598 "Received fragment at offset %u/%u from %s for message %u\n",
5599 ntohs (fb->frag_off),
5601 GNUNET_i2s (&cmc->im.sender),
5602 (unsigned int) fb->msg_uuid.uuid);
5604 if (msize != rc->msg_size)
5607 finish_cmc_handling (cmc);
5612 fsize = ntohs (fb->header.size) - sizeof (*fb);
5616 finish_cmc_handling (cmc);
5619 frag_off = ntohs (fb->frag_off);
5620 if (frag_off + fsize > msize)
5622 /* Fragment (plus fragment size) exceeds message size! */
5623 GNUNET_break_op (0);
5624 finish_cmc_handling (cmc);
5627 memcpy (&target[frag_off], &fb[1], fsize);
5628 /* update bitfield and msg_missing */
5629 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5631 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5633 rc->bitfield[i / 8] |= (1 << (i % 8));
5638 /* Compute cummulative ACK */
5639 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5640 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5641 if (0 == rc->msg_missing)
5642 cdelay = GNUNET_TIME_UNIT_ZERO;
5643 cummulative_ack (&cmc->im.sender,
5645 GNUNET_TIME_relative_to_absolute (cdelay));
5646 rc->last_frag = GNUNET_TIME_absolute_get ();
5647 /* is reassembly complete? */
5648 if (0 != rc->msg_missing)
5650 finish_cmc_handling (cmc);
5653 /* reassembly is complete, verify result */
5654 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5655 if (ntohs (msg->size) != rc->msg_size)
5658 free_reassembly_context (rc);
5659 finish_cmc_handling (cmc);
5662 /* successful reassembly */
5663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5664 "Fragment reassembly complete for message %u\n",
5665 (unsigned int) fb->msg_uuid.uuid);
5666 /* FIXME: check that the resulting msg is NOT a
5667 DV Box or Reliability Box, as that is NOT allowed! */
5668 demultiplex_with_cmc (cmc, msg);
5669 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5670 en-route and we forget that we finished this reassembly immediately!
5671 -> keep around until timeout?
5672 -> shorten timeout based on ACK? */
5673 free_reassembly_context (rc);
5678 * Communicator gave us a reliability box. Check the message.
5680 * @param cls a `struct CommunicatorMessageContext`
5681 * @param rb the send message that was sent
5682 * @return #GNUNET_YES if message is well-formed
5685 check_reliability_box (void *cls,
5686 const struct TransportReliabilityBoxMessage *rb)
5689 GNUNET_MQ_check_boxed_message (rb);
5695 * Communicator gave us a reliability box. Process the request.
5697 * @param cls a `struct CommunicatorMessageContext` (must call
5698 * #finish_cmc_handling() when done)
5699 * @param rb the message that was received
5702 handle_reliability_box (void *cls,
5703 const struct TransportReliabilityBoxMessage *rb)
5705 struct CommunicatorMessageContext *cmc = cls;
5706 const struct GNUNET_MessageHeader *inbox =
5707 (const struct GNUNET_MessageHeader *) &rb[1];
5708 struct GNUNET_TIME_Relative rtt;
5710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5711 "Received reliability box from %s with UUID %s of type %u\n",
5712 GNUNET_i2s (&cmc->im.sender),
5713 GNUNET_uuid2s (&rb->ack_uuid.value),
5714 (unsigned int) ntohs (inbox->type));
5715 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5716 do not really have an RTT for the
5717 *incoming* queue (should we have
5718 the sender add it to the rb message?) */
5722 (0 == ntohl (rb->ack_countdown))
5723 ? GNUNET_TIME_UNIT_ZERO_ABS
5724 : GNUNET_TIME_relative_to_absolute (
5725 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5726 /* continue with inner message */
5727 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5728 reliability box (not allowed!) */
5729 demultiplex_with_cmc (cmc, inbox);
5734 * Check if we have advanced to another age since the last time. If
5735 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5738 * @param pd[in,out] data to update
5739 * @param age current age
5742 update_pd_age (struct PerformanceData *pd, unsigned int age)
5746 if (age == pd->last_age)
5747 return; /* nothing to do */
5748 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5749 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5751 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5753 the->bytes_sent = 0;
5754 the->bytes_received = 0;
5761 * Update @a pd based on the latest @a rtt and the number of bytes
5762 * that were confirmed to be successfully transmitted.
5764 * @param pd[in,out] data to update
5765 * @param rtt latest round-trip time
5766 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5769 update_performance_data (struct PerformanceData *pd,
5770 struct GNUNET_TIME_Relative rtt,
5771 uint16_t bytes_transmitted_ok)
5773 uint64_t nval = rtt.rel_value_us;
5774 uint64_t oval = pd->aged_rtt.rel_value_us;
5775 unsigned int age = get_age ();
5776 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5778 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5781 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5782 update_pd_age (pd, age);
5783 the->bytes_received += bytes_transmitted_ok;
5788 * We have successfully transmitted data via @a q, update metrics.
5790 * @param q queue to update
5791 * @param rtt round trip time observed
5792 * @param bytes_transmitted_ok number of bytes successfully transmitted
5795 update_queue_performance (struct Queue *q,
5796 struct GNUNET_TIME_Relative rtt,
5797 uint16_t bytes_transmitted_ok)
5799 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5804 * We have successfully transmitted data via @a dvh, update metrics.
5806 * @param dvh distance vector path data to update
5807 * @param rtt round trip time observed
5808 * @param bytes_transmitted_ok number of bytes successfully transmitted
5811 update_dvh_performance (struct DistanceVectorHop *dvh,
5812 struct GNUNET_TIME_Relative rtt,
5813 uint16_t bytes_transmitted_ok)
5815 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5820 * We have completed transmission of @a pm, remove it from
5821 * the transmission queues (and if it is a fragment, continue
5822 * up the tree as necessary).
5824 * @param pm pending message that was transmitted
5827 completed_pending_message (struct PendingMessage *pm)
5829 struct PendingMessage *pos;
5834 case PMT_RELIABILITY_BOX:
5835 /* Full message sent, we are done */
5836 client_send_response (pm);
5838 case PMT_FRAGMENT_BOX:
5839 /* Fragment sent over reliabile channel */
5840 free_fragment_tree (pm);
5841 pos = pm->frag_parent;
5842 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5844 /* check if subtree is done */
5845 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5849 pos = pm->frag_parent;
5850 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5854 /* Was this the last applicable fragmment? */
5855 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
5856 (pos->frag_off == pos->bytes_msg))
5857 client_send_response (pos);
5860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5861 "Completed transmission of message %llu (DV Box)\n",
5863 free_pending_message (pm);
5870 * The @a pa was acknowledged, process the acknowledgement.
5872 * @param pa the pending acknowledgement that was satisfied
5873 * @param ack_delay artificial delay from cummulative acks created by the
5877 handle_acknowledged (struct PendingAcknowledgement *pa,
5878 struct GNUNET_TIME_Relative ack_delay)
5880 struct GNUNET_TIME_Relative delay;
5882 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5883 if (delay.rel_value_us > ack_delay.rel_value_us)
5884 delay = GNUNET_TIME_UNIT_ZERO;
5886 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5887 if (NULL != pa->queue)
5888 update_queue_performance (pa->queue, delay, pa->message_size);
5889 if (NULL != pa->dvh)
5890 update_dvh_performance (pa->dvh, delay, pa->message_size);
5892 completed_pending_message (pa->pm);
5893 free_pending_acknowledgement (pa);
5898 * Communicator gave us a reliability ack. Check it is well-formed.
5900 * @param cls a `struct CommunicatorMessageContext` (unused)
5901 * @param ra the message that was received
5902 * @return #GNUNET_Ok if @a ra is well-formed
5905 check_reliability_ack (void *cls,
5906 const struct TransportReliabilityAckMessage *ra)
5908 unsigned int n_acks;
5911 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5912 sizeof (struct TransportCummulativeAckPayloadP);
5915 GNUNET_break_op (0);
5916 return GNUNET_SYSERR;
5918 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5919 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5921 GNUNET_break_op (0);
5922 return GNUNET_SYSERR;
5929 * Communicator gave us a reliability ack. Process the request.
5931 * @param cls a `struct CommunicatorMessageContext` (must call
5932 * #finish_cmc_handling() when done)
5933 * @param ra the message that was received
5936 handle_reliability_ack (void *cls,
5937 const struct TransportReliabilityAckMessage *ra)
5939 struct CommunicatorMessageContext *cmc = cls;
5940 const struct TransportCummulativeAckPayloadP *ack;
5941 struct PendingAcknowledgement *pa;
5942 unsigned int n_acks;
5943 uint32_t ack_counter;
5945 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5946 sizeof (struct TransportCummulativeAckPayloadP);
5947 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5948 for (unsigned int i = 0; i < n_acks; i++)
5951 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5954 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5955 "Received ACK from %s with UUID %s which is unknown to us!\n",
5956 GNUNET_i2s (&cmc->im.sender),
5957 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5958 GNUNET_STATISTICS_update (
5960 "# FRAGMENT_ACKS dropped, no matching pending message",
5965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5966 "Received ACK from %s with UUID %s\n",
5967 GNUNET_i2s (&cmc->im.sender),
5968 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5969 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5972 ack_counter = htonl (ra->ack_counter);
5973 (void) ack_counter; /* silence compiler warning for now */
5974 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5975 // (DV and/or Neighbour?)
5976 finish_cmc_handling (cmc);
5981 * Communicator gave us a backchannel encapsulation. Check the message.
5983 * @param cls a `struct CommunicatorMessageContext`
5984 * @param be the send message that was sent
5985 * @return #GNUNET_YES if message is well-formed
5988 check_backchannel_encapsulation (
5990 const struct TransportBackchannelEncapsulationMessage *be)
5992 uint16_t size = ntohs (be->header.size) - sizeof (*be);
5993 const struct GNUNET_MessageHeader *inbox =
5994 (const struct GNUNET_MessageHeader *) &be[1];
5999 if (ntohs (inbox->size) >= size)
6001 GNUNET_break_op (0);
6002 return GNUNET_SYSERR;
6004 isize = ntohs (inbox->size);
6005 is = ((const char *) inbox) + isize;
6007 if ('\0' != is[size - 1])
6009 GNUNET_break_op (0);
6010 return GNUNET_SYSERR;
6017 * Communicator gave us a backchannel encapsulation. Process the request.
6018 * (We are the destination of the backchannel here.)
6020 * @param cls a `struct CommunicatorMessageContext` (must call
6021 * #finish_cmc_handling() when done)
6022 * @param be the message that was received
6025 handle_backchannel_encapsulation (
6027 const struct TransportBackchannelEncapsulationMessage *be)
6029 struct CommunicatorMessageContext *cmc = cls;
6030 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6031 struct GNUNET_MQ_Envelope *env;
6032 struct TransportClient *tc;
6033 const struct GNUNET_MessageHeader *inbox =
6034 (const struct GNUNET_MessageHeader *) &be[1];
6035 uint16_t isize = ntohs (inbox->size);
6036 const char *target_communicator = ((const char *) inbox) + isize;
6038 /* Find client providing this communicator */
6039 for (tc = clients_head; NULL != tc; tc = tc->next)
6040 if ((CT_COMMUNICATOR == tc->type) &&
6042 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6050 "# Backchannel message dropped: target communicator `%s' unknown",
6051 target_communicator);
6052 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6053 GNUNET_free (stastr);
6056 /* Finally, deliver backchannel message to communicator */
6057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6058 "Delivering backchannel message from %s of type %u to %s\n",
6059 GNUNET_i2s (&cmc->im.sender),
6060 ntohs (inbox->type),
6061 target_communicator);
6062 env = GNUNET_MQ_msg_extra (
6065 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6066 cbi->pid = cmc->im.sender;
6067 memcpy (&cbi[1], inbox, isize);
6068 GNUNET_MQ_send (tc->mq, env);
6073 * Task called when we should check if any of the DV paths
6074 * we have learned to a target are due for garbage collection.
6076 * Collects stale paths, and possibly frees the entire DV
6077 * entry if no paths are left. Otherwise re-schedules itself.
6079 * @param cls a `struct DistanceVector`
6082 path_cleanup_cb (void *cls)
6084 struct DistanceVector *dv = cls;
6085 struct DistanceVectorHop *pos;
6087 dv->timeout_task = NULL;
6088 while (NULL != (pos = dv->dv_head))
6090 GNUNET_assert (dv == pos->dv);
6091 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6093 free_distance_vector_hop (pos);
6101 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6106 * The @a hop is a validated path to the respective target
6107 * peer and we should tell core about it -- and schedule
6108 * a job to revoke the state.
6110 * @param hop a path to some peer that is the reason for activation
6113 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6115 struct DistanceVector *dv = hop->dv;
6116 struct VirtualLink *vl;
6118 vl = lookup_virtual_link (&dv->target);
6121 /* Link was already up, remember dv is also now available and we are done */
6123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6124 "Virtual link to %s could now also use DV!\n",
6125 GNUNET_i2s (&dv->target));
6128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6129 "Creating new virtual link to %s using DV!\n",
6130 GNUNET_i2s (&dv->target));
6131 vl = GNUNET_new (struct VirtualLink);
6132 vl->message_uuid_ctr =
6133 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6134 vl->target = dv->target;
6137 vl->core_recv_window = RECV_WINDOW_SIZE;
6138 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6139 vl->visibility_task =
6140 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6141 GNUNET_break (GNUNET_YES ==
6142 GNUNET_CONTAINER_multipeermap_put (
6146 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6147 consider_sending_fc (vl);
6148 /* We lacked a confirmed connection to the target
6149 before, so tell CORE about it (finally!) */
6150 cores_send_connect_info (&dv->target);
6155 * We have learned a @a path through the network to some other peer, add it to
6156 * our DV data structure (returning #GNUNET_YES on success).
6158 * We do not add paths if we have a sufficient number of shorter
6159 * paths to this target already (returning #GNUNET_NO).
6161 * We also do not add problematic paths, like those where we lack the first
6162 * hop in our neighbour list (i.e. due to a topology change) or where some
6163 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6165 * @param path the path we learned, path[0] should be us,
6166 * and then path contains a valid path from us to
6167 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6168 * @param path_len number of entries on the @a path, at least three!
6169 * @param network_latency how long does the message take from us to
6170 * `path[path_len-1]`? set to "forever" if unknown
6171 * @param path_valid_until how long is this path considered validated? Maybe
6173 * @return #GNUNET_YES on success,
6174 * #GNUNET_NO if we have better path(s) to the target
6175 * #GNUNET_SYSERR if the path is useless and/or invalid
6176 * (i.e. path[1] not a direct neighbour
6177 * or path[i+1] is a direct neighbour for i>0)
6180 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6181 unsigned int path_len,
6182 struct GNUNET_TIME_Relative network_latency,
6183 struct GNUNET_TIME_Absolute path_valid_until)
6185 struct DistanceVectorHop *hop;
6186 struct DistanceVector *dv;
6187 struct Neighbour *next_hop;
6188 unsigned int shorter_distance;
6192 /* what a boring path! not allowed! */
6194 return GNUNET_SYSERR;
6196 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6197 next_hop = lookup_neighbour (&path[1]);
6198 if (NULL == next_hop)
6200 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6202 return GNUNET_SYSERR;
6204 for (unsigned int i = 2; i < path_len; i++)
6205 if (NULL != lookup_neighbour (&path[i]))
6207 /* Useless path: we have a direct connection to some hop
6208 in the middle of the path, so this one is not even
6209 terribly useful for redundancy */
6210 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6211 "Path of %u hops useless: directly link to hop %u (%s)\n",
6214 GNUNET_i2s (&path[i]));
6215 GNUNET_STATISTICS_update (GST_stats,
6216 "# Useless DV path ignored: hop is neighbour",
6219 return GNUNET_SYSERR;
6221 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6224 dv = GNUNET_new (struct DistanceVector);
6225 dv->target = path[path_len - 1];
6226 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6229 GNUNET_assert (GNUNET_OK ==
6230 GNUNET_CONTAINER_multipeermap_put (
6234 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6236 /* Check if we have this path already! */
6237 shorter_distance = 0;
6238 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6241 if (pos->distance < path_len - 2)
6243 /* Note that the distances in 'pos' excludes us (path[0]) and
6244 the next_hop (path[1]), so we need to subtract two
6245 and check next_hop explicitly */
6246 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6248 int match = GNUNET_YES;
6250 for (unsigned int i = 0; i < pos->distance; i++)
6252 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6258 if (GNUNET_YES == match)
6260 struct GNUNET_TIME_Relative last_timeout;
6262 /* Re-discovered known path, update timeout */
6263 GNUNET_STATISTICS_update (GST_stats,
6264 "# Known DV path refreshed",
6267 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6269 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6270 pos->path_valid_until =
6271 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6272 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6273 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6275 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6276 activate_core_visible_dv_path (pos);
6277 if (last_timeout.rel_value_us <
6278 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6279 DV_PATH_DISCOVERY_FREQUENCY)
6282 /* Some peer send DV learn messages too often, we are learning
6283 the same path faster than it would be useful; do not forward! */
6284 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6285 "Rediscovered path too quickly, not forwarding further\n");
6288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6289 "Refreshed known path to %s, forwarding further\n",
6290 GNUNET_i2s (&dv->target));
6295 /* Count how many shorter paths we have (incl. direct
6296 neighbours) before simply giving up on this one! */
6297 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6299 /* We have a shorter path already! */
6300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6301 "Have many shorter DV paths %s, not forwarding further\n",
6302 GNUNET_i2s (&dv->target));
6305 /* create new DV path entry */
6306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6307 "Discovered new DV path to %s\n",
6308 GNUNET_i2s (&dv->target));
6309 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6310 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6311 hop->next_hop = next_hop;
6313 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6316 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6317 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6318 hop->path_valid_until = path_valid_until;
6319 hop->distance = path_len - 2;
6320 hop->pd.aged_rtt = network_latency;
6321 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6322 GNUNET_CONTAINER_MDLL_insert (neighbour,
6326 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6327 activate_core_visible_dv_path (hop);
6333 * Communicator gave us a DV learn message. Check the message.
6335 * @param cls a `struct CommunicatorMessageContext`
6336 * @param dvl the send message that was sent
6337 * @return #GNUNET_YES if message is well-formed
6340 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6342 uint16_t size = ntohs (dvl->header.size);
6343 uint16_t num_hops = ntohs (dvl->num_hops);
6344 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6347 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6349 GNUNET_break_op (0);
6350 return GNUNET_SYSERR;
6352 if (num_hops > MAX_DV_HOPS_ALLOWED)
6354 GNUNET_break_op (0);
6355 return GNUNET_SYSERR;
6357 for (unsigned int i = 0; i < num_hops; i++)
6359 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6361 GNUNET_break_op (0);
6362 return GNUNET_SYSERR;
6364 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6366 GNUNET_break_op (0);
6367 return GNUNET_SYSERR;
6375 * Build and forward a DV learn message to @a next_hop.
6377 * @param next_hop peer to send the message to
6378 * @param msg message received
6379 * @param bi_history bitmask specifying hops on path that were bidirectional
6380 * @param nhops length of the @a hops array
6381 * @param hops path the message traversed so far
6382 * @param in_time when did we receive the message, used to calculate network
6386 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6387 const struct TransportDVLearnMessage *msg,
6388 uint16_t bi_history,
6390 const struct DVPathEntryP *hops,
6391 struct GNUNET_TIME_Absolute in_time)
6393 struct DVPathEntryP *dhops;
6394 char buf[sizeof (struct TransportDVLearnMessage) +
6395 (nhops + 1) * sizeof (struct DVPathEntryP)] GNUNET_ALIGN;
6396 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6397 struct GNUNET_TIME_Relative nnd;
6399 /* compute message for forwarding */
6400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6401 "Forwarding DV learn message originating from %s to %s\n",
6402 GNUNET_i2s (&msg->initiator),
6403 GNUNET_i2s2 (next_hop));
6404 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6405 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6406 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6407 (nhops + 1) * sizeof (struct DVPathEntryP));
6408 fwd->num_hops = htons (nhops + 1);
6409 fwd->bidirectional = htons (bi_history);
6410 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6411 GNUNET_TIME_relative_ntoh (
6412 msg->non_network_delay));
6413 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6414 fwd->init_sig = msg->init_sig;
6415 fwd->initiator = msg->initiator;
6416 fwd->challenge = msg->challenge;
6417 dhops = (struct DVPathEntryP *) &fwd[1];
6418 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6419 dhops[nhops].hop = GST_my_identity;
6421 struct DvHopPS dhp = {.purpose.purpose =
6422 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6423 .purpose.size = htonl (sizeof (dhp)),
6424 .pred = dhops[nhops - 1].hop,
6426 .challenge = msg->challenge};
6428 GNUNET_assert (GNUNET_OK ==
6429 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6431 &dhops[nhops].hop_sig));
6433 route_control_message_without_fc (next_hop,
6435 RMO_UNCONFIRMED_ALLOWED);
6440 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6442 * @param sender_monotonic_time monotonic time of the initiator
6443 * @param init the signer
6444 * @param challenge the challenge that was signed
6445 * @param init_sig signature presumably by @a init
6446 * @return #GNUNET_OK if the signature is valid
6449 validate_dv_initiator_signature (
6450 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6451 const struct GNUNET_PeerIdentity *init,
6452 const struct ChallengeNonceP *challenge,
6453 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6455 struct DvInitPS ip = {.purpose.purpose = htonl (
6456 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6457 .purpose.size = htonl (sizeof (ip)),
6458 .monotonic_time = sender_monotonic_time,
6459 .challenge = *challenge};
6463 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6468 GNUNET_break_op (0);
6469 return GNUNET_SYSERR;
6476 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6478 struct NeighbourSelectionContext
6481 * Original message we received.
6483 const struct TransportDVLearnMessage *dvl;
6488 const struct DVPathEntryP *hops;
6491 * Time we received the message.
6493 struct GNUNET_TIME_Absolute in_time;
6496 * Offsets of the selected peers.
6498 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6501 * Number of peers eligible for selection.
6503 unsigned int num_eligible;
6506 * Number of peers that were selected for forwarding.
6508 unsigned int num_selections;
6511 * Number of hops in @e hops
6516 * Bitmap of bidirectional connections encountered.
6518 uint16_t bi_history;
6523 * Function called for each neighbour during #handle_dv_learn.
6525 * @param cls a `struct NeighbourSelectionContext *`
6526 * @param pid identity of the peer
6527 * @param value a `struct Neighbour`
6528 * @return #GNUNET_YES (always)
6531 dv_neighbour_selection (void *cls,
6532 const struct GNUNET_PeerIdentity *pid,
6535 struct NeighbourSelectionContext *nsc = cls;
6538 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6539 return GNUNET_YES; /* skip initiator */
6540 for (unsigned int i = 0; i < nsc->nhops; i++)
6541 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6542 return GNUNET_YES; /* skip peers on path */
6543 nsc->num_eligible++;
6549 * Function called for each neighbour during #handle_dv_learn.
6550 * We call #forward_dv_learn() on the neighbour(s) selected
6551 * during #dv_neighbour_selection().
6553 * @param cls a `struct NeighbourSelectionContext *`
6554 * @param pid identity of the peer
6555 * @param value a `struct Neighbour`
6556 * @return #GNUNET_YES (always)
6559 dv_neighbour_transmission (void *cls,
6560 const struct GNUNET_PeerIdentity *pid,
6563 struct NeighbourSelectionContext *nsc = cls;
6566 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6567 return GNUNET_YES; /* skip initiator */
6568 for (unsigned int i = 0; i < nsc->nhops; i++)
6569 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6570 return GNUNET_YES; /* skip peers on path */
6571 for (unsigned int i = 0; i < nsc->num_selections; i++)
6573 if (nsc->selections[i] == nsc->num_eligible)
6575 forward_dv_learn (pid,
6584 nsc->num_eligible++;
6590 * Computes the number of neighbours we should forward a DVInit
6591 * message to given that it has so far taken @a hops_taken hops
6592 * though the network and that the number of neighbours we have
6593 * in total is @a neighbour_count, out of which @a eligible_count
6594 * are not yet on the path.
6596 * NOTE: technically we might want to include NSE in the formula to
6597 * get a better grip on the overall network size. However, for now
6598 * using NSE here would create a dependency issue in the build system.
6599 * => Left for later, hardcoded to 50 for now.
6601 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6602 * peers via DV (`target_total`). We want the reach to be spread out
6603 * over various distances to the origin, with a bias towards shorter
6606 * We make the strong assumption that the network topology looks
6607 * "similar" at other hops, in particular the @a neighbour_count
6608 * should be comparable at other hops.
6610 * If the local neighbourhood is densely connected, we expect that @a
6611 * eligible_count is close to @a neighbour_count minus @a hops_taken
6612 * as a lot of the path is already known. In that case, we should
6613 * forward to few(er) peers to try to find a path out of the
6614 * neighbourhood. OTOH, if @a eligible_count is close to @a
6615 * neighbour_count, we should forward to many peers as we are either
6616 * still close to the origin (i.e. @a hops_taken is small) or because
6617 * we managed to get beyond a local cluster. We express this as
6618 * the `boost_factor` using the square of the fraction of eligible
6619 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6620 * 99% are eligible, the 'boost' will be almost 1).
6622 * Second, the more hops we have taken, the larger the problem of an
6623 * exponential traffic explosion gets. So we take the `target_total`,
6624 * and compute our degree such that at each distance d 2^{-d} peers
6625 * are selected (corrected by the `boost_factor`).
6627 * @param hops_taken number of hops DVInit has travelled so far
6628 * @param neighbour_count number of neighbours we have in total
6629 * @param eligible_count number of neighbours we could in
6633 calculate_fork_degree (unsigned int hops_taken,
6634 unsigned int neighbour_count,
6635 unsigned int eligible_count)
6637 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6638 double eligible_ratio =
6639 ((double) eligible_count) / ((double) neighbour_count);
6640 double boost_factor = eligible_ratio * eligible_ratio;
6644 if (hops_taken >= 64)
6647 return 0; /* precaution given bitshift below */
6649 for (unsigned int i = 1; i < hops_taken; i++)
6651 /* For each hop, subtract the expected number of targets
6652 reached at distance d (so what remains divided by 2^d) */
6653 target_total -= (target_total * boost_factor / (1LLU << i));
6656 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6657 /* round up or down probabilistically depending on how close we were
6658 when floor()ing to rnd */
6659 left = target_total - (double) rnd;
6660 if (UINT32_MAX * left >
6661 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6662 rnd++; /* round up */
6663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6664 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6674 * Function called when peerstore is done storing a DV monotonic time.
6676 * @param cls a `struct Neighbour`
6677 * @param success #GNUNET_YES if peerstore was successful
6680 neighbour_store_dvmono_cb (void *cls, int success)
6682 struct Neighbour *n = cls;
6685 if (GNUNET_YES != success)
6686 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6687 "Failed to store other peer's monotonic time in peerstore!\n");
6692 * Communicator gave us a DV learn message. Process the request.
6694 * @param cls a `struct CommunicatorMessageContext` (must call
6695 * #finish_cmc_handling() when done)
6696 * @param dvl the message that was received
6699 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6701 struct CommunicatorMessageContext *cmc = cls;
6702 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6705 uint16_t bi_history;
6706 const struct DVPathEntryP *hops;
6709 struct GNUNET_TIME_Absolute in_time;
6710 struct Neighbour *n;
6712 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6713 bi_history = ntohs (dvl->bidirectional);
6714 hops = (const struct DVPathEntryP *) &dvl[1];
6718 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6721 finish_cmc_handling (cmc);
6728 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6731 finish_cmc_handling (cmc);
6736 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6737 cc = cmc->tc->details.communicator.cc;
6738 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6739 cc); // FIXME: add bi-directional flag to cc?
6740 in_time = GNUNET_TIME_absolute_get ();
6742 /* continue communicator here, everything else can happen asynchronous! */
6743 finish_cmc_handling (cmc);
6745 n = lookup_neighbour (&dvl->initiator);
6748 if ((n->dv_monotime_available == GNUNET_YES) &&
6749 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6750 n->last_dv_learn_monotime.abs_value_us))
6752 GNUNET_STATISTICS_update (GST_stats,
6753 "# DV learn discarded due to time travel",
6758 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6763 GNUNET_break_op (0);
6766 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6767 if (GNUNET_YES == n->dv_monotime_available)
6770 GNUNET_PEERSTORE_store_cancel (n->sc);
6772 GNUNET_PEERSTORE_store (peerstore,
6775 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6776 &dvl->monotonic_time,
6777 sizeof (dvl->monotonic_time),
6778 GNUNET_TIME_UNIT_FOREVER_ABS,
6779 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6780 &neighbour_store_dvmono_cb,
6784 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6785 If signature verification load too high, implement random drop strategy */
6786 for (unsigned int i = 0; i < nhops; i++)
6788 struct DvHopPS dhp = {.purpose.purpose =
6789 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6790 .purpose.size = htonl (sizeof (dhp)),
6791 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6792 .succ = (nhops == i + 1) ? GST_my_identity
6794 .challenge = dvl->challenge};
6797 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6800 &hops[i].hop.public_key))
6802 GNUNET_break_op (0);
6807 if (GNUNET_EXTRA_LOGGING > 0)
6811 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6812 for (unsigned int i = 0; i < nhops; i++)
6816 GNUNET_asprintf (&tmp,
6819 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6820 GNUNET_i2s (&hops[i].hop));
6824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6825 "Received DVInit via %s%s%s\n",
6827 bi_hop ? "<->" : "-->",
6828 GNUNET_i2s (&GST_my_identity));
6832 do_fwd = GNUNET_YES;
6833 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6835 struct GNUNET_PeerIdentity path[nhops + 1];
6836 struct GNUNET_TIME_Relative host_latency_sum;
6837 struct GNUNET_TIME_Relative latency;
6838 struct GNUNET_TIME_Relative network_latency;
6840 /* We initiated this, learn the forward path! */
6841 path[0] = GST_my_identity;
6842 path[1] = hops[0].hop;
6843 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6845 // Need also something to lookup initiation time
6846 // to compute RTT! -> add RTT argument here?
6847 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6848 // (based on dvl->challenge, we can identify time of origin!)
6850 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6851 /* assumption: latency on all links is the same */
6852 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6854 for (unsigned int i = 2; i <= nhops; i++)
6856 struct GNUNET_TIME_Relative ilat;
6858 /* assumption: linear latency increase per hop */
6859 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6860 path[i] = hops[i - 1].hop;
6861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6862 "Learned path with %u hops to %s with latency %s\n",
6864 GNUNET_i2s (&path[i]),
6865 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6866 learn_dv_path (path,
6869 GNUNET_TIME_relative_to_absolute (
6870 ADDRESS_VALIDATION_LIFETIME));
6872 /* as we initiated, do not forward again (would be circular!) */
6878 /* last hop was bi-directional, we could learn something here! */
6879 struct GNUNET_PeerIdentity path[nhops + 2];
6881 path[0] = GST_my_identity;
6882 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6883 for (unsigned int i = 0; i < nhops; i++)
6887 if (0 == (bi_history & (1 << i)))
6888 break; /* i-th hop not bi-directional, stop learning! */
6891 path[i + 2] = dvl->initiator;
6895 path[i + 2] = hops[nhops - i - 2].hop;
6898 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6899 "Learned inverse path with %u hops to %s\n",
6901 GNUNET_i2s (&path[i + 2]));
6902 iret = learn_dv_path (path,
6904 GNUNET_TIME_UNIT_FOREVER_REL,
6905 GNUNET_TIME_UNIT_ZERO_ABS);
6906 if (GNUNET_SYSERR == iret)
6908 /* path invalid or too long to be interesting for US, thus should also
6909 not be interesting to our neighbours, cut path when forwarding to
6910 'i' hops, except of course for the one that goes back to the
6912 GNUNET_STATISTICS_update (GST_stats,
6913 "# DV learn not forwarded due invalidity of path",
6919 if ((GNUNET_NO == iret) && (nhops == i + 1))
6921 /* we have better paths, and this is the longest target,
6922 so there cannot be anything interesting later */
6923 GNUNET_STATISTICS_update (GST_stats,
6924 "# DV learn not forwarded, got better paths",
6933 if (MAX_DV_HOPS_ALLOWED == nhops)
6935 /* At limit, we're out of here! */
6936 finish_cmc_handling (cmc);
6940 /* Forward to initiator, if path non-trivial and possible */
6941 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6942 did_initiator = GNUNET_NO;
6945 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6947 /* send back to origin! */
6948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6949 "Sending DVL back to initiator %s\n",
6950 GNUNET_i2s (&dvl->initiator));
6951 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6952 did_initiator = GNUNET_YES;
6954 /* We forward under two conditions: either we still learned something
6955 ourselves (do_fwd), or the path was darn short and thus the initiator is
6956 likely to still be very interested in this (and we did NOT already
6957 send it back to the initiator) */
6958 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6959 (GNUNET_NO == did_initiator)))
6961 /* Pick random neighbours that are not yet on the path */
6962 struct NeighbourSelectionContext nsc;
6965 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6968 nsc.bi_history = bi_history;
6970 nsc.in_time = in_time;
6971 nsc.num_eligible = 0;
6972 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6973 &dv_neighbour_selection,
6975 if (0 == nsc.num_eligible)
6976 return; /* done here, cannot forward to anyone else */
6977 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6978 nsc.num_selections =
6979 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6981 "Forwarding DVL to %u other peers\n",
6982 nsc.num_selections);
6983 for (unsigned int i = 0; i < nsc.num_selections; i++)
6985 (nsc.num_selections == n_cnt)
6986 ? i /* all were selected, avoid collisions by chance */
6987 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6988 nsc.num_eligible = 0;
6989 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6990 &dv_neighbour_transmission,
6997 * Communicator gave us a DV box. Check the message.
6999 * @param cls a `struct CommunicatorMessageContext`
7000 * @param dvb the send message that was sent
7001 * @return #GNUNET_YES if message is well-formed
7004 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7006 uint16_t size = ntohs (dvb->header.size);
7007 uint16_t num_hops = ntohs (dvb->num_hops);
7008 const struct GNUNET_PeerIdentity *hops =
7009 (const struct GNUNET_PeerIdentity *) &dvb[1];
7012 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
7013 sizeof (struct GNUNET_MessageHeader))
7015 GNUNET_break_op (0);
7016 return GNUNET_SYSERR;
7018 /* This peer must not be on the path */
7019 for (unsigned int i = 0; i < num_hops; i++)
7020 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7022 GNUNET_break_op (0);
7023 return GNUNET_SYSERR;
7030 * Create a DV Box message and queue it for transmission to
7033 * @param next_hop peer to receive the message next
7034 * @param total_hops how many hops did the message take so far
7035 * @param num_hops length of the @a hops array
7036 * @param origin origin of the message
7037 * @param hops next peer(s) to the destination, including destination
7038 * @param payload payload of the box
7039 * @param payload_size number of bytes in @a payload
7042 forward_dv_box (struct Neighbour *next_hop,
7043 const struct TransportDVBoxMessage *hdr,
7044 uint16_t total_hops,
7046 const struct GNUNET_PeerIdentity *hops,
7047 const void *enc_payload,
7048 uint16_t enc_payload_size)
7050 struct VirtualLink *vl = next_hop->vl;
7051 struct PendingMessage *pm;
7054 struct GNUNET_PeerIdentity *dhops;
7056 GNUNET_assert (NULL != vl);
7057 msg_size = sizeof (struct TransportDVBoxMessage) +
7058 num_hops * sizeof (struct GNUNET_PeerIdentity) + enc_payload_size;
7059 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
7060 pm->pmt = PMT_DV_BOX;
7062 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7063 pm->logging_uuid = logging_uuid_gen++;
7064 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7065 pm->bytes_msg = msg_size;
7066 buf = (char *) &pm[1];
7067 memcpy (buf, hdr, sizeof (*hdr));
7069 (struct GNUNET_PeerIdentity *) &buf[sizeof (struct TransportDVBoxMessage)];
7070 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
7071 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7072 GNUNET_CONTAINER_MDLL_insert (vl,
7073 vl->pending_msg_head,
7074 vl->pending_msg_tail,
7076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7077 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7079 GNUNET_i2s (&next_hop->pid),
7080 (unsigned int) num_hops,
7081 (unsigned int) total_hops);
7082 check_vl_transmission (vl);
7087 * Free data structures associated with @a b.
7089 * @param b data structure to release
7092 free_backtalker (struct Backtalker *b)
7096 GNUNET_PEERSTORE_iterate_cancel (b->get);
7098 GNUNET_assert (NULL != b->cmc);
7099 finish_cmc_handling (b->cmc);
7102 if (NULL != b->task)
7104 GNUNET_SCHEDULER_cancel (b->task);
7109 GNUNET_PEERSTORE_store_cancel (b->sc);
7114 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7120 * Callback to free backtalker records.
7124 * @param value a `struct Backtalker`
7125 * @return #GNUNET_OK (always)
7128 free_backtalker_cb (void *cls,
7129 const struct GNUNET_PeerIdentity *pid,
7132 struct Backtalker *b = value;
7136 free_backtalker (b);
7142 * Function called when it is time to clean up a backtalker.
7144 * @param cls a `struct Backtalker`
7147 backtalker_timeout_cb (void *cls)
7149 struct Backtalker *b = cls;
7152 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7154 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7157 GNUNET_assert (NULL == b->sc);
7158 free_backtalker (b);
7163 * Function called with the monotonic time of a backtalker
7164 * by PEERSTORE. Updates the time and continues processing.
7166 * @param cls a `struct Backtalker`
7167 * @param record the information found, NULL for the last call
7168 * @param emsg error message
7171 backtalker_monotime_cb (void *cls,
7172 const struct GNUNET_PEERSTORE_Record *record,
7175 struct Backtalker *b = cls;
7176 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7177 struct GNUNET_TIME_Absolute mt;
7182 /* we're done with #backtalker_monotime_cb() invocations,
7183 continue normal processing */
7185 GNUNET_assert (NULL != b->cmc);
7186 if (0 != b->body_size)
7187 demultiplex_with_cmc (b->cmc,
7188 (const struct GNUNET_MessageHeader *) &b[1]);
7190 finish_cmc_handling (b->cmc);
7194 if (sizeof (*mtbe) != record->value_size)
7199 mtbe = record->value;
7200 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7201 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7204 "Backtalker message from %s dropped, monotime in the past\n",
7205 GNUNET_i2s (&b->pid));
7206 GNUNET_STATISTICS_update (
7208 "# Backchannel messages dropped: monotonic time not increasing",
7211 b->monotonic_time = mt;
7212 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7221 * Function called by PEERSTORE when the store operation of
7222 * a backtalker's monotonic time is complete.
7224 * @param cls the `struct Backtalker`
7225 * @param success #GNUNET_OK on success
7228 backtalker_monotime_store_cb (void *cls, int success)
7230 struct Backtalker *b = cls;
7232 if (GNUNET_OK != success)
7234 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7235 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7238 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7243 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7245 * @param b a backtalker with updated monotonic time
7248 update_backtalker_monotime (struct Backtalker *b)
7250 struct GNUNET_TIME_AbsoluteNBO mtbe;
7254 GNUNET_PEERSTORE_store_cancel (b->sc);
7259 GNUNET_SCHEDULER_cancel (b->task);
7262 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7264 GNUNET_PEERSTORE_store (peerstore,
7267 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7270 GNUNET_TIME_UNIT_FOREVER_ABS,
7271 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7272 &backtalker_monotime_store_cb,
7278 * Communicator gave us a DV box. Process the request.
7280 * @param cls a `struct CommunicatorMessageContext` (must call
7281 * #finish_cmc_handling() when done)
7282 * @param dvb the message that was received
7285 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7287 struct CommunicatorMessageContext *cmc = cls;
7288 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
7289 uint16_t num_hops = ntohs (dvb->num_hops);
7290 const struct GNUNET_PeerIdentity *hops =
7291 (const struct GNUNET_PeerIdentity *) &dvb[1];
7292 const char *enc_payload = (const char *) &hops[num_hops];
7293 uint16_t enc_payload_size =
7294 size - (num_hops * sizeof (struct GNUNET_PeerIdentity));
7295 struct DVKeyState key;
7296 struct GNUNET_HashCode hmac;
7300 if (GNUNET_EXTRA_LOGGING > 0)
7304 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7305 for (unsigned int i = 0; i < num_hops; i++)
7309 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7314 "Received DVBox with remainig path %s\n",
7321 /* We're trying from the end of the hops array, as we may be
7322 able to find a shortcut unknown to the origin that way */
7323 for (int i = num_hops - 1; i >= 0; i--)
7325 struct Neighbour *n;
7327 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7329 GNUNET_break_op (0);
7330 finish_cmc_handling (cmc);
7333 n = lookup_neighbour (&hops[i]);
7336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7337 "Skipping %u/%u hops ahead while routing DV Box\n",
7342 ntohs (dvb->total_hops) + 1,
7343 num_hops - i - 1, /* number of hops left */
7344 &hops[i + 1], /* remaining hops */
7347 GNUNET_STATISTICS_update (GST_stats,
7348 "# DV hops skipped routing boxes",
7351 GNUNET_STATISTICS_update (GST_stats,
7352 "# DV boxes routed (total)",
7355 finish_cmc_handling (cmc);
7358 /* Woopsie, next hop not in neighbours, drop! */
7359 GNUNET_STATISTICS_update (GST_stats,
7360 "# DV Boxes dropped: next hop unknown",
7363 finish_cmc_handling (cmc);
7366 /* We are the target. Unbox and handle message. */
7367 GNUNET_STATISTICS_update (GST_stats,
7368 "# DV boxes opened (ultimate target)",
7371 cmc->total_hops = ntohs (dvb->total_hops);
7373 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key);
7374 hdr = (const char *) &dvb[1];
7375 hdr_len = ntohs (dvb->header.size) - sizeof (*dvb);
7376 dv_hmac (&key, &hmac, hdr, hdr_len);
7377 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7379 /* HMAC missmatch, disard! */
7380 GNUNET_break_op (0);
7381 finish_cmc_handling (cmc);
7384 /* begin actual decryption */
7386 struct Backtalker *b;
7387 struct GNUNET_TIME_Absolute monotime;
7388 struct TransportDVBoxPayloadP ppay;
7389 char body[hdr_len - sizeof (ppay)] GNUNET_ALIGN;
7390 const struct GNUNET_MessageHeader *mh =
7391 (const struct GNUNET_MessageHeader *) body;
7393 GNUNET_assert (hdr_len >=
7394 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
7395 dv_decrypt (&key, &ppay, hdr, sizeof (ppay));
7396 dv_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
7397 dv_key_clean (&key);
7398 if (ntohs (mh->size) != sizeof (body))
7400 GNUNET_break_op (0);
7401 finish_cmc_handling (cmc);
7404 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7405 switch (ntohs (mh->type))
7407 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7408 GNUNET_break_op (0);
7409 finish_cmc_handling (cmc);
7411 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7412 GNUNET_break_op (0);
7413 finish_cmc_handling (cmc);
7416 /* permitted, continue */
7419 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7421 "Decrypted backtalk from %s\n",
7422 GNUNET_i2s (&ppay.sender));
7423 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
7424 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
7426 GNUNET_STATISTICS_update (
7428 "# Backchannel messages dropped: monotonic time not increasing",
7431 finish_cmc_handling (cmc);
7435 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
7437 /* Check signature */
7438 struct EphemeralConfirmationPS ec;
7440 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
7441 ec.purpose.size = htonl (sizeof (ec));
7442 ec.target = GST_my_identity;
7443 ec.ephemeral_key = dvb->ephemeral_key;
7446 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
7449 &ppay.sender.public_key))
7451 /* Signature invalid, disard! */
7452 GNUNET_break_op (0);
7453 finish_cmc_handling (cmc);
7457 /* Update sender, we now know the real origin! */
7458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7459 "DVBox received for me from %s via %s\n",
7460 GNUNET_i2s2 (&ppay.sender),
7461 GNUNET_i2s (&cmc->im.sender));
7462 cmc->im.sender = ppay.sender;
7466 /* update key cache and mono time */
7467 b->last_ephemeral = dvb->ephemeral_key;
7468 b->monotonic_time = monotime;
7469 update_backtalker_monotime (b);
7471 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7473 demultiplex_with_cmc (cmc, mh);
7476 /* setup data structure to cache signature AND check
7477 monotonic time with PEERSTORE before forwarding backchannel payload */
7478 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
7479 b->pid = ppay.sender;
7480 b->body_size = sizeof (body);
7481 memcpy (&b[1], body, sizeof (body));
7482 GNUNET_assert (GNUNET_YES ==
7483 GNUNET_CONTAINER_multipeermap_put (
7487 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7488 b->monotonic_time = monotime; /* NOTE: to be checked still! */
7491 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7492 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7494 GNUNET_PEERSTORE_iterate (peerstore,
7497 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7498 &backtalker_monotime_cb,
7500 } /* end actual decryption */
7505 * Client notified us about transmission from a peer. Process the request.
7507 * @param cls a `struct TransportClient` which sent us the message
7508 * @param obm the send message that was sent
7509 * @return #GNUNET_YES if message is well-formed
7512 check_incoming_msg (void *cls,
7513 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7515 struct TransportClient *tc = cls;
7517 if (CT_COMMUNICATOR != tc->type)
7520 return GNUNET_SYSERR;
7522 GNUNET_MQ_check_boxed_message (im);
7528 * Closure for #check_known_address.
7530 struct CheckKnownAddressContext
7533 * Set to the address we are looking for.
7535 const char *address;
7538 * Set to a matching validation state, if one was found.
7540 struct ValidationState *vs;
7545 * Test if the validation state in @a value matches the
7546 * address from @a cls.
7548 * @param cls a `struct CheckKnownAddressContext`
7549 * @param pid unused (must match though)
7550 * @param value a `struct ValidationState`
7551 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7554 check_known_address (void *cls,
7555 const struct GNUNET_PeerIdentity *pid,
7558 struct CheckKnownAddressContext *ckac = cls;
7559 struct ValidationState *vs = value;
7562 if (0 != strcmp (vs->address, ckac->address))
7570 * Task run periodically to validate some address based on #validation_heap.
7575 validation_start_cb (void *cls);
7579 * Set the time for next_challenge of @a vs to @a new_time.
7580 * Updates the heap and if necessary reschedules the job.
7582 * @param vs validation state to update
7583 * @param new_time new time for revalidation
7586 update_next_challenge_time (struct ValidationState *vs,
7587 struct GNUNET_TIME_Absolute new_time)
7589 struct GNUNET_TIME_Relative delta;
7591 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7592 return; /* be lazy */
7593 vs->next_challenge = new_time;
7596 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7598 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7599 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7600 (NULL != validation_task))
7602 if (NULL != validation_task)
7603 GNUNET_SCHEDULER_cancel (validation_task);
7604 /* randomize a bit */
7605 delta.rel_value_us =
7606 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7607 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7608 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7610 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7615 * Start address validation.
7617 * @param pid peer the @a address is for
7618 * @param address an address to reach @a pid (presumably)
7621 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7622 const char *address)
7624 struct GNUNET_TIME_Absolute now;
7625 struct ValidationState *vs;
7626 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7628 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7630 &check_known_address,
7632 if (NULL != (vs = ckac.vs))
7634 /* if 'vs' is not currently valid, we need to speed up retrying the
7636 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7638 /* reduce backoff as we got a fresh advertisement */
7639 vs->challenge_backoff =
7640 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7641 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7643 update_next_challenge_time (vs,
7644 GNUNET_TIME_relative_to_absolute (
7645 vs->challenge_backoff));
7649 now = GNUNET_TIME_absolute_get ();
7650 vs = GNUNET_new (struct ValidationState);
7653 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7654 vs->first_challenge_use = now;
7655 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7656 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7658 sizeof (vs->challenge));
7659 vs->address = GNUNET_strdup (address);
7660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7661 "Starting address validation `%s' of peer %s using challenge %s\n",
7664 GNUNET_sh2s (&vs->challenge.value));
7665 GNUNET_assert (GNUNET_YES ==
7666 GNUNET_CONTAINER_multipeermap_put (
7670 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7671 update_next_challenge_time (vs, now);
7676 * Function called by PEERSTORE for each matching record.
7678 * @param cls closure, a `struct IncomingRequest`
7679 * @param record peerstore record information
7680 * @param emsg error message, or NULL if no errors
7683 handle_hello_for_incoming (void *cls,
7684 const struct GNUNET_PEERSTORE_Record *record,
7687 struct IncomingRequest *ir = cls;
7692 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7693 "Got failure from PEERSTORE: %s\n",
7697 val = record->value;
7698 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7703 start_address_validation (&ir->pid, (const char *) record->value);
7708 * Communicator gave us a transport address validation challenge. Process the
7711 * @param cls a `struct CommunicatorMessageContext` (must call
7712 * #finish_cmc_handling() when done)
7713 * @param tvc the message that was received
7716 handle_validation_challenge (
7718 const struct TransportValidationChallengeMessage *tvc)
7720 struct CommunicatorMessageContext *cmc = cls;
7721 struct TransportValidationResponseMessage tvr;
7722 struct VirtualLink *vl;
7723 struct GNUNET_TIME_RelativeNBO validity_duration;
7724 struct IncomingRequest *ir;
7725 struct Neighbour *n;
7726 struct GNUNET_PeerIdentity sender;
7728 /* DV-routed messages are not allowed for validation challenges */
7729 if (cmc->total_hops > 0)
7731 GNUNET_break_op (0);
7732 finish_cmc_handling (cmc);
7735 validity_duration = cmc->im.expected_address_validity;
7736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7737 "Received address validation challenge %s\n",
7738 GNUNET_sh2s (&tvc->challenge.value));
7739 /* If we have a virtual link, we use this mechanism to signal the
7740 size of the flow control window, and to allow the sender
7741 to ask for increases. If for us the virtual link is still down,
7742 we will always give a window size of zero. */
7744 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7745 tvr.header.size = htons (sizeof (tvr));
7746 tvr.reserved = htonl (0);
7747 tvr.challenge = tvc->challenge;
7748 tvr.origin_time = tvc->sender_time;
7749 tvr.validity_duration = validity_duration;
7751 /* create signature */
7752 struct TransportValidationPS tvp =
7753 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7754 .purpose.size = htonl (sizeof (tvp)),
7755 .validity_duration = validity_duration,
7756 .challenge = tvc->challenge};
7758 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7762 route_control_message_without_fc (&cmc->im.sender,
7764 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7765 sender = cmc->im.sender;
7766 finish_cmc_handling (cmc);
7767 vl = lookup_virtual_link (&sender);
7771 /* For us, the link is still down, but we need bi-directional
7772 connections (for flow-control and for this to be useful for
7773 CORE), so we must try to bring the link up! */
7775 /* (1) Check existing queues, if any, we may be lucky! */
7776 n = lookup_neighbour (&sender);
7778 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7779 start_address_validation (&sender, q->address);
7780 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7782 for (ir = ir_head; NULL != ir; ir = ir->next)
7783 if (0 == GNUNET_memcmp (&ir->pid, &sender))
7784 return; /* we are already trying */
7785 ir = GNUNET_new (struct IncomingRequest);
7787 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7788 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7791 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7792 &handle_hello_for_incoming,
7795 /* Bound attempts we do in parallel here, might otherwise get excessive */
7796 while (ir_total > MAX_INCOMING_REQUEST)
7797 free_incoming_request (ir_head);
7802 * Closure for #check_known_challenge.
7804 struct CheckKnownChallengeContext
7807 * Set to the challenge we are looking for.
7809 const struct ChallengeNonceP *challenge;
7812 * Set to a matching validation state, if one was found.
7814 struct ValidationState *vs;
7819 * Test if the validation state in @a value matches the
7820 * challenge from @a cls.
7822 * @param cls a `struct CheckKnownChallengeContext`
7823 * @param pid unused (must match though)
7824 * @param value a `struct ValidationState`
7825 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7828 check_known_challenge (void *cls,
7829 const struct GNUNET_PeerIdentity *pid,
7832 struct CheckKnownChallengeContext *ckac = cls;
7833 struct ValidationState *vs = value;
7836 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7844 * Function called when peerstore is done storing a
7845 * validated address.
7847 * @param cls a `struct ValidationState`
7848 * @param success #GNUNET_YES on success
7851 peerstore_store_validation_cb (void *cls, int success)
7853 struct ValidationState *vs = cls;
7856 if (GNUNET_YES == success)
7858 GNUNET_STATISTICS_update (GST_stats,
7859 "# Peerstore failed to store foreign address",
7866 * Find the queue matching @a pid and @a address.
7868 * @param pid peer the queue must go to
7869 * @param address address the queue must use
7870 * @return NULL if no such queue exists
7872 static struct Queue *
7873 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7875 struct Neighbour *n;
7877 n = lookup_neighbour (pid);
7880 for (struct Queue *pos = n->queue_head; NULL != pos;
7881 pos = pos->next_neighbour)
7883 if (0 == strcmp (pos->address, address))
7891 * Communicator gave us a transport address validation response. Process the
7894 * @param cls a `struct CommunicatorMessageContext` (must call
7895 * #finish_cmc_handling() when done)
7896 * @param tvr the message that was received
7899 handle_validation_response (
7901 const struct TransportValidationResponseMessage *tvr)
7903 struct CommunicatorMessageContext *cmc = cls;
7904 struct ValidationState *vs;
7905 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7907 struct GNUNET_TIME_Absolute origin_time;
7909 struct Neighbour *n;
7910 struct VirtualLink *vl;
7912 /* check this is one of our challenges */
7913 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7915 &check_known_challenge,
7917 if (NULL == (vs = ckac.vs))
7919 /* This can happen simply if we 'forgot' the challenge by now,
7920 i.e. because we received the validation response twice */
7921 GNUNET_STATISTICS_update (GST_stats,
7922 "# Validations dropped, challenge unknown",
7925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7926 "Validation response %s dropped, challenge unknown\n",
7927 GNUNET_sh2s (&tvr->challenge.value));
7928 finish_cmc_handling (cmc);
7932 /* sanity check on origin time */
7933 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7934 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7935 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7937 GNUNET_break_op (0);
7938 finish_cmc_handling (cmc);
7943 /* check signature */
7944 struct TransportValidationPS tvp =
7945 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7946 .purpose.size = htonl (sizeof (tvp)),
7947 .validity_duration = tvr->validity_duration,
7948 .challenge = tvr->challenge};
7952 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7955 &cmc->im.sender.public_key))
7957 GNUNET_break_op (0);
7958 finish_cmc_handling (cmc);
7963 /* validity is capped by our willingness to keep track of the
7964 validation entry and the maximum the other peer allows */
7965 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7966 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7967 tvr->validity_duration),
7968 MAX_ADDRESS_VALID_UNTIL));
7969 vs->validated_until =
7970 GNUNET_TIME_absolute_min (vs->valid_until,
7971 GNUNET_TIME_relative_to_absolute (
7972 ADDRESS_VALIDATION_LIFETIME));
7973 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7974 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7975 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7977 sizeof (vs->challenge));
7978 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7979 vs->validated_until,
7980 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7981 VALIDATION_RTT_BUFFER_FACTOR));
7982 vs->last_challenge_use =
7983 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7984 update_next_challenge_time (vs, vs->first_challenge_use);
7985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7986 "Validation response %s accepted, address valid until %s\n",
7987 GNUNET_sh2s (&tvr->challenge.value),
7988 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
7989 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7992 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7994 strlen (vs->address) + 1,
7996 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7997 &peerstore_store_validation_cb,
7999 finish_cmc_handling (cmc);
8001 /* Finally, we now possibly have a confirmed (!) working queue,
8002 update queue status (if queue still is around) */
8003 q = find_queue (&vs->pid, vs->address);
8006 GNUNET_STATISTICS_update (GST_stats,
8007 "# Queues lost at time of successful validation",
8012 q->validated_until = vs->validated_until;
8013 q->pd.aged_rtt = vs->validation_rtt;
8015 vl = lookup_virtual_link (&vs->pid);
8018 /* Link was already up, remember n is also now available and we are done */
8023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8024 "Virtual link to %s could now also direct neighbour!\n",
8025 GNUNET_i2s (&vs->pid));
8029 GNUNET_assert (n == vl->n);
8033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8034 "Creating new virtual link to %s using direct neighbour!\n",
8035 GNUNET_i2s (&vs->pid));
8036 vl = GNUNET_new (struct VirtualLink);
8037 vl->target = n->pid;
8040 vl->core_recv_window = RECV_WINDOW_SIZE;
8041 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8042 vl->visibility_task =
8043 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8044 GNUNET_break (GNUNET_YES ==
8045 GNUNET_CONTAINER_multipeermap_put (
8049 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8050 consider_sending_fc (vl);
8051 /* We lacked a confirmed connection to the target
8052 before, so tell CORE about it (finally!) */
8053 cores_send_connect_info (&n->pid);
8058 * Incoming meessage. Process the request.
8060 * @param im the send message that was received
8063 handle_incoming_msg (void *cls,
8064 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8066 struct TransportClient *tc = cls;
8067 struct CommunicatorMessageContext *cmc =
8068 GNUNET_new (struct CommunicatorMessageContext);
8072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8073 "Received message via communicator from peer %s\n",
8074 GNUNET_i2s (&im->sender));
8075 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8080 * Communicator gave us a transport address validation response. Process the
8083 * @param cls a `struct CommunicatorMessageContext` (must call
8084 * #finish_cmc_handling() when done)
8085 * @param fc the message that was received
8088 handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8090 struct CommunicatorMessageContext *cmc = cls;
8091 struct VirtualLink *vl;
8093 struct GNUNET_TIME_Absolute st;
8097 vl = lookup_virtual_link (&cmc->im.sender);
8100 GNUNET_STATISTICS_update (GST_stats,
8101 "# FC dropped: virtual link unknown",
8104 finish_cmc_handling (cmc);
8107 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8108 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8110 /* out of order, drop */
8111 GNUNET_STATISTICS_update (GST_stats,
8112 "# FC dropped: message out of order",
8115 finish_cmc_handling (cmc);
8118 seq = ntohl (fc->seq);
8119 if (seq < vl->last_fc_seq)
8121 /* Wrap-around/reset of other peer; start all counters from zero */
8122 vl->outbound_fc_window_size_used = 0;
8124 vl->last_fc_seq = seq;
8125 vl->last_fc_timestamp = st;
8126 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8127 os = GNUNET_ntohll (fc->outbound_sent);
8128 vl->incoming_fc_window_size_loss =
8129 (int64_t) (os - vl->incoming_fc_window_size_used);
8130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8131 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8132 GNUNET_i2s (&vl->target),
8134 (unsigned long long) vl->outbound_fc_window_size,
8135 (long long) vl->incoming_fc_window_size_loss);
8136 wnd = GNUNET_ntohll (fc->outbound_window_size);
8137 if ((wnd < vl->incoming_fc_window_size) ||
8138 (vl->last_outbound_window_size_received != wnd) ||
8139 (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX) %
8140 FC_NO_CHANGE_REPLY_PROBABILITY))
8142 /* Consider re-sending our FC message, as clearly the
8143 other peer's idea of the window is not up-to-date */
8144 consider_sending_fc (vl);
8146 if ((wnd == vl->incoming_fc_window_size) &&
8147 (vl->last_outbound_window_size_received == wnd) &&
8148 (NULL != vl->fc_retransmit_task))
8150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8151 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8152 GNUNET_i2s (&vl->target),
8153 (unsigned long long) wnd);
8154 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8155 vl->fc_retransmit_task = NULL;
8157 vl->last_outbound_window_size_received = wnd;
8158 /* FC window likely increased, check transmission possibilities! */
8159 check_vl_transmission (vl);
8160 finish_cmc_handling (cmc);
8165 * Given an inbound message @a msg from a communicator @a cmc,
8166 * demultiplex it based on the type calling the right handler.
8168 * @param cmc context for demultiplexing
8169 * @param msg message to demultiplex
8172 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8173 const struct GNUNET_MessageHeader *msg)
8175 struct GNUNET_MQ_MessageHandler handlers[] =
8176 {GNUNET_MQ_hd_var_size (fragment_box,
8177 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8178 struct TransportFragmentBoxMessage,
8180 GNUNET_MQ_hd_var_size (reliability_box,
8181 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8182 struct TransportReliabilityBoxMessage,
8184 GNUNET_MQ_hd_var_size (reliability_ack,
8185 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8186 struct TransportReliabilityAckMessage,
8188 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8189 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8190 struct TransportBackchannelEncapsulationMessage,
8192 GNUNET_MQ_hd_var_size (dv_learn,
8193 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8194 struct TransportDVLearnMessage,
8196 GNUNET_MQ_hd_var_size (dv_box,
8197 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8198 struct TransportDVBoxMessage,
8200 GNUNET_MQ_hd_fixed_size (
8201 validation_challenge,
8202 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8203 struct TransportValidationChallengeMessage,
8205 GNUNET_MQ_hd_fixed_size (flow_control,
8206 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8207 struct TransportFlowControlMessage,
8209 GNUNET_MQ_hd_fixed_size (
8210 validation_response,
8211 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8212 struct TransportValidationResponseMessage,
8214 GNUNET_MQ_handler_end ()};
8217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8218 "Handling message of type %u with %u bytes\n",
8219 (unsigned int) ntohs (msg->type),
8220 (unsigned int) ntohs (msg->size));
8221 ret = GNUNET_MQ_handle_message (handlers, msg);
8222 if (GNUNET_SYSERR == ret)
8225 GNUNET_SERVICE_client_drop (cmc->tc->client);
8229 if (GNUNET_NO == ret)
8231 /* unencapsulated 'raw' message */
8232 handle_raw_message (&cmc, msg);
8238 * New queue became available. Check message.
8240 * @param cls the client
8241 * @param aqm the send message that was sent
8244 check_add_queue_message (void *cls,
8245 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8247 struct TransportClient *tc = cls;
8249 if (CT_COMMUNICATOR != tc->type)
8252 return GNUNET_SYSERR;
8254 GNUNET_MQ_check_zero_termination (aqm);
8260 * If necessary, generates the UUID for a @a pm
8262 * @param pm pending message to generate UUID for.
8265 set_pending_message_uuid (struct PendingMessage *pm)
8267 if (pm->msg_uuid_set)
8269 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8270 pm->msg_uuid_set = GNUNET_YES;
8275 * Setup data structure waiting for acknowledgements.
8277 * @param queue queue the @a pm will be sent over
8278 * @param dvh path the message will take, may be NULL
8279 * @param pm the pending message for transmission
8280 * @return corresponding fresh pending acknowledgement
8282 static struct PendingAcknowledgement *
8283 prepare_pending_acknowledgement (struct Queue *queue,
8284 struct DistanceVectorHop *dvh,
8285 struct PendingMessage *pm)
8287 struct PendingAcknowledgement *pa;
8289 pa = GNUNET_new (struct PendingAcknowledgement);
8295 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8297 sizeof (pa->ack_uuid));
8298 } while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8300 &pa->ack_uuid.value,
8302 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8303 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8304 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8306 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8307 pa->transmission_time = GNUNET_TIME_absolute_get ();
8308 pa->message_size = pm->bytes_msg;
8309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8310 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8311 GNUNET_uuid2s (&pa->ack_uuid.value),
8318 * Fragment the given @a pm to the given @a mtu. Adds
8319 * additional fragments to the neighbour as well. If the
8320 * @a mtu is too small, generates and error for the @a pm
8323 * @param queue which queue to fragment for
8324 * @param dvh path the message will take, or NULL
8325 * @param pm pending message to fragment for transmission
8326 * @return new message to transmit
8328 static struct PendingMessage *
8329 fragment_message (struct Queue *queue,
8330 struct DistanceVectorHop *dvh,
8331 struct PendingMessage *pm)
8333 struct PendingAcknowledgement *pa;
8334 struct PendingMessage *ff;
8337 mtu = (0 == queue->mtu)
8338 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
8340 set_pending_message_uuid (pm);
8341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8342 "Fragmenting message %llu <%llu> to %s for MTU %u\n",
8343 (unsigned long long) pm->msg_uuid.uuid,
8345 GNUNET_i2s (&pm->vl->target),
8346 (unsigned int) mtu);
8347 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8349 /* This invariant is established in #handle_add_queue_message() */
8350 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
8352 /* select fragment for transmission, descending the tree if it has
8353 been expanded until we are at a leaf or at a fragment that is small
8357 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
8358 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
8360 ff = ff->head_frag; /* descent into fragmented fragments */
8363 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
8365 /* Did not yet calculate all fragments, calculate next fragment */
8366 struct PendingMessage *frag;
8367 struct TransportFragmentBoxMessage tfb;
8375 orig = (const char *) &ff[1];
8376 msize = ff->bytes_msg;
8379 const struct TransportFragmentBoxMessage *tfbo;
8381 tfbo = (const struct TransportFragmentBoxMessage *) orig;
8382 orig += sizeof (struct TransportFragmentBoxMessage);
8383 msize -= sizeof (struct TransportFragmentBoxMessage);
8384 xoff = ntohs (tfbo->frag_off);
8386 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
8387 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
8389 GNUNET_malloc (sizeof (struct PendingMessage) +
8390 sizeof (struct TransportFragmentBoxMessage) + fragsize);
8391 frag->logging_uuid = logging_uuid_gen++;
8393 frag->frag_parent = ff;
8394 frag->timeout = pm->timeout;
8395 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
8396 frag->pmt = PMT_FRAGMENT_BOX;
8397 msg = (char *) &frag[1];
8398 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
8400 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
8401 tfb.ack_uuid = pa->ack_uuid;
8402 tfb.msg_uuid = pm->msg_uuid;
8403 tfb.frag_off = htons (ff->frag_off + xoff);
8404 tfb.msg_size = htons (pm->bytes_msg);
8405 memcpy (msg, &tfb, sizeof (tfb));
8406 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
8407 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
8408 ff->frag_off += fragsize;
8412 /* Move head to the tail and return it */
8413 GNUNET_CONTAINER_MDLL_remove (frag,
8414 ff->frag_parent->head_frag,
8415 ff->frag_parent->tail_frag,
8417 GNUNET_CONTAINER_MDLL_insert_tail (frag,
8418 ff->frag_parent->head_frag,
8419 ff->frag_parent->tail_frag,
8426 * Reliability-box the given @a pm. On error (can there be any), NULL
8427 * may be returned, otherwise the "replacement" for @a pm (which
8428 * should then be added to the respective neighbour's queue instead of
8429 * @a pm). If the @a pm is already fragmented or reliability boxed,
8430 * or itself an ACK, this function simply returns @a pm.
8432 * @param queue which queue to prepare transmission for
8433 * @param dvh path the message will take, or NULL
8434 * @param pm pending message to box for transmission over unreliabile queue
8435 * @return new message to transmit
8437 static struct PendingMessage *
8438 reliability_box_message (struct Queue *queue,
8439 struct DistanceVectorHop *dvh,
8440 struct PendingMessage *pm)
8442 struct TransportReliabilityBoxMessage rbox;
8443 struct PendingAcknowledgement *pa;
8444 struct PendingMessage *bpm;
8447 if (PMT_CORE != pm->pmt)
8448 return pm; /* already fragmented or reliability boxed, or control message:
8450 if (NULL != pm->bpm)
8451 return pm->bpm; /* already computed earlier: do nothing */
8452 GNUNET_assert (NULL == pm->head_frag);
8453 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
8457 client_send_response (pm);
8460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8461 "Preparing reliability box for message <%llu> to %s on queue %s\n",
8463 GNUNET_i2s (&pm->vl->target),
8465 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8467 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
8469 bpm->logging_uuid = logging_uuid_gen++;
8471 bpm->frag_parent = pm;
8472 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
8473 bpm->timeout = pm->timeout;
8474 bpm->pmt = PMT_RELIABILITY_BOX;
8475 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
8476 set_pending_message_uuid (bpm);
8477 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
8478 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
8479 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
8481 rbox.ack_uuid = pa->ack_uuid;
8482 msg = (char *) &bpm[1];
8483 memcpy (msg, &rbox, sizeof (rbox));
8484 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
8491 * Change the value of the `next_attempt` field of @a pm
8492 * to @a next_attempt and re-order @a pm in the transmission
8493 * list as required by the new timestmap.
8495 * @param pm a pending message to update
8496 * @param next_attempt timestamp to use
8499 update_pm_next_attempt (struct PendingMessage *pm,
8500 struct GNUNET_TIME_Absolute next_attempt)
8502 struct VirtualLink *vl = pm->vl;
8504 pm->next_attempt = next_attempt;
8505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8506 "Next attempt for message <%llu> set to %s\n",
8508 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
8510 if (NULL == pm->frag_parent)
8512 struct PendingMessage *pos;
8514 /* re-insert sort in neighbour list */
8515 GNUNET_CONTAINER_MDLL_remove (vl,
8516 vl->pending_msg_head,
8517 vl->pending_msg_tail,
8519 pos = vl->pending_msg_tail;
8520 while ((NULL != pos) &&
8521 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8523 GNUNET_CONTAINER_MDLL_insert_after (vl,
8524 vl->pending_msg_head,
8525 vl->pending_msg_tail,
8531 /* re-insert sort in fragment list */
8532 struct PendingMessage *fp = pm->frag_parent;
8533 struct PendingMessage *pos;
8535 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
8536 pos = fp->tail_frag;
8537 while ((NULL != pos) &&
8538 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8539 pos = pos->prev_frag;
8540 GNUNET_CONTAINER_MDLL_insert_after (frag,
8550 * Context for #select_best_pending_from_link().
8552 struct PendingMessageScoreContext
8555 * Set to the best message that was found, NULL for none.
8557 struct PendingMessage *best;
8560 * DVH that @e best should take, or NULL for direct transmission.
8562 struct DistanceVectorHop *dvh;
8565 * What is the estimated total overhead for this message?
8567 size_t real_overhead;
8570 * Number of pending messages we seriously considered this time.
8572 unsigned int consideration_counter;
8575 * Did we have to fragment?
8580 * Did we have to reliability box?
8587 * Select the best pending message from @a vl for transmission
8590 * @param sc[in,out] best message so far (NULL for none), plus scoring data
8591 * @param queue the queue that will be used for transmission
8592 * @param vl the virtual link providing the messages
8593 * @param dvh path we are currently considering, or NULL for none
8594 * @param overhead number of bytes of overhead to be expected
8595 * from DV encapsulation (0 for without DV)
8598 select_best_pending_from_link (struct PendingMessageScoreContext *sc,
8599 struct Queue *queue,
8600 struct VirtualLink *vl,
8601 struct DistanceVectorHop *dvh,
8604 struct GNUNET_TIME_Absolute now;
8606 now = GNUNET_TIME_absolute_get ();
8607 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
8610 size_t real_overhead = overhead;
8614 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
8615 continue; /* DV messages must not be DV-routed to next hop! */
8616 if (pos->next_attempt.abs_value_us > now.abs_value_us)
8617 break; /* too early for all messages, they are sorted by next_attempt */
8618 if (NULL != pos->qe)
8619 continue; /* not eligible */
8620 sc->consideration_counter++;
8621 /* determine if we have to fragment, if so add fragmentation
8624 if ( ( (0 != queue->mtu) &&
8625 (pos->bytes_msg + real_overhead > queue->mtu) ) ||
8626 (pos->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
8627 (NULL != pos->head_frag /* fragments already exist, should
8628 respect that even if MTU is 0 for
8632 relb = GNUNET_NO; /* if we fragment, we never also reliability box */
8633 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
8635 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
8636 header without the ACK UUID when using a *reliable* channel! */
8638 real_overhead = overhead + sizeof (struct TransportFragmentBoxMessage);
8640 /* determine if we have to reliability-box, if so add reliability box
8643 if ((GNUNET_NO == frag) &&
8644 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
8645 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
8648 real_overhead += sizeof (struct TransportReliabilityBoxMessage);
8651 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
8652 message would beat it! */
8653 if (NULL != sc->best)
8655 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
8656 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
8657 experimentally validated. There may be some huge potential for
8658 improvement here. Also, we right now only compare how well the
8659 given message fits _this_ queue, and do not consider how well other
8660 queues might suit the message. Taking other queues into consideration
8661 may further improve the result, but could also be expensive
8662 in terms of CPU time. */
8663 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
8664 long long pm_score = frag * 40 + relb * 20 + real_overhead;
8665 long long time_delta =
8666 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us) /
8669 /* "time_delta" considers which message has been 'ready' for transmission
8670 for longer, if a message has a preference for low latency, increase
8671 the weight of the time_delta by 10x if it is favorable for that message */
8672 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8673 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
8674 time_delta *= 10; /* increase weight (always, both are low latency) */
8675 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8678 10; /* increase weight, favors 'pos', which is low latency */
8679 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8682 10; /* increase weight, favors 'sc->best', which is low latency */
8683 if (0 != queue->mtu)
8685 /* Grant bonus if we are bellow MTU, larger bonus the closer we will
8687 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
8688 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
8689 if (queue->mtu > real_overhead + pos->bytes_msg)
8690 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
8692 if (sc_score + time_delta > pm_score)
8693 continue; /* sc_score larger, keep sc->best */
8704 * Function to call to further operate on the now DV encapsulated
8705 * message @a hdr, forwarding it via @a next_hop under respect of
8708 * @param cls a `struct PendingMessageScoreContext`
8709 * @param next_hop next hop of the DV path
8710 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
8711 * @param options options of the original message
8714 extract_box_cb (void *cls,
8715 struct Neighbour *next_hop,
8716 const struct GNUNET_MessageHeader *hdr,
8717 enum RouteMessageOptions options)
8719 struct PendingMessageScoreContext *sc = cls;
8720 struct PendingMessage *pm = sc->best;
8721 struct PendingMessage *bpm;
8722 uint16_t bsize = ntohs (hdr->size);
8724 GNUNET_assert (NULL == pm->bpm);
8725 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + bsize);
8726 bpm->logging_uuid = logging_uuid_gen++;
8727 bpm->pmt = PMT_DV_BOX;
8728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8729 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
8732 GNUNET_i2s (&next_hop->pid));
8733 memcpy (&bpm[1], hdr, bsize);
8739 * We believe we are ready to transmit a `struct PendingMessage` on a
8740 * queue, the big question is which one! We need to see if there is
8741 * one pending that is allowed by flow control and congestion control
8742 * and (ideally) matches our queue's performance profile.
8744 * If such a message is found, we give the message to the communicator
8745 * for transmission (updating the tracker, and re-scheduling ourselves
8748 * If no such message is found, the queue's `idle` field must be set
8751 * @param cls the `struct Queue` to process transmissions for
8754 transmit_on_queue (void *cls)
8756 struct Queue *queue = cls;
8757 struct Neighbour *n = queue->neighbour;
8758 struct PendingMessageScoreContext sc;
8759 struct PendingMessage *pm;
8761 queue->transmit_task = NULL;
8764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8765 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
8766 GNUNET_i2s (&n->pid),
8768 queue->idle = GNUNET_YES;
8771 memset (&sc, 0, sizeof (sc));
8772 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
8773 if (NULL == sc.best)
8775 /* Also look at DVH that have the n as first hop! */
8776 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
8777 dvh = dvh->next_neighbour)
8779 select_best_pending_from_link (&sc,
8783 sizeof (struct GNUNET_PeerIdentity) *
8784 (1 + dvh->distance) +
8785 sizeof (struct TransportDVBoxMessage) +
8786 sizeof (struct TransportDVBoxPayloadP));
8789 if (NULL == sc.best)
8791 /* no message pending, nothing to do here! */
8792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8793 "No pending messages, queue `%s' to %s now idle\n",
8795 GNUNET_i2s (&n->pid));
8796 queue->idle = GNUNET_YES;
8800 /* Given selection in `sc`, do transmission */
8804 GNUNET_assert (PMT_DV_BOX != pm->pmt);
8805 if (NULL != sc.best->bpm)
8807 /* We did this boxing before, but possibly for a different path!
8808 Discard old DV box! OPTIMIZE-ME: we might want to check if
8809 it is the same and then not re-build the message... */
8810 free_pending_message (sc.best->bpm);
8811 sc.best->bpm = NULL;
8813 encapsulate_for_dv (sc.dvh->dv,
8816 (const struct GNUNET_MessageHeader *) &sc.best[1],
8820 GNUNET_assert (NULL != sc.best->bpm);
8823 if (GNUNET_YES == sc.frag)
8825 pm = fragment_message (queue, sc.dvh, pm);
8828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8829 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
8831 GNUNET_i2s (&n->pid),
8833 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8836 else if (GNUNET_YES == sc.relb)
8838 pm = reliability_box_message (queue, sc.dvh, pm);
8841 /* Reliability boxing failed, try next message... */
8843 GNUNET_ERROR_TYPE_DEBUG,
8844 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
8846 GNUNET_i2s (&n->pid),
8848 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8853 /* Pass 'pm' for transission to the communicator */
8855 GNUNET_ERROR_TYPE_DEBUG,
8856 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
8859 GNUNET_i2s (&n->pid),
8860 sc.consideration_counter);
8862 /* Flow control: increment amount of traffic sent; if we are routing
8863 via DV (and thus the ultimate target of the pending message is for
8864 a different virtual link than the one of the queue), then we need
8865 to use up not only the window of the direct link but also the
8866 flow control window for the DV link! */
8867 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
8869 if (pm->vl != queue->neighbour->vl)
8871 /* If the virtual link of the queue differs, this better be distance
8873 GNUNET_assert (NULL != sc.dvh);
8874 /* If we do distance vector routing, we better not do this for a
8875 message that was itself DV-routed */
8876 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
8877 /* We use the size of the unboxed message here, to avoid counting
8878 the DV-Box header which is eaten up on the way by intermediaries */
8879 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
8883 GNUNET_assert (NULL == sc.dvh);
8886 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
8888 /* Check if this transmission somehow conclusively finished handing 'pm'
8889 even without any explicit ACKs */
8890 if ((PMT_CORE == pm->pmt) ||
8891 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
8893 completed_pending_message (pm);
8897 /* Message not finished, waiting for acknowledgement.
8898 Update time by which we might retransmit 's' based on queue
8899 characteristics (i.e. RTT); it takes one RTT for the message to
8900 arrive and the ACK to come back in the best case; but the other
8901 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
8904 OPTIMIZE: Note that in the future this heuristic should likely
8905 be improved further (measure RTT stability, consider message
8906 urgency and size when delaying ACKs, etc.) */
8907 update_pm_next_attempt (pm,
8908 GNUNET_TIME_relative_to_absolute (
8909 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
8912 /* finally, re-schedule queue transmission task itself */
8913 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8918 * Queue to a peer went down. Process the request.
8920 * @param cls the client
8921 * @param dqm the send message that was sent
8924 handle_del_queue_message (void *cls,
8925 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
8927 struct TransportClient *tc = cls;
8929 if (CT_COMMUNICATOR != tc->type)
8932 GNUNET_SERVICE_client_drop (tc->client);
8935 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8936 queue = queue->next_client)
8938 struct Neighbour *neighbour = queue->neighbour;
8940 if ((dqm->qid != queue->qid) ||
8941 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
8943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8944 "Dropped queue %s to peer %s\n",
8946 GNUNET_i2s (&neighbour->pid));
8948 GNUNET_SERVICE_client_continue (tc->client);
8952 GNUNET_SERVICE_client_drop (tc->client);
8957 * Message was transmitted. Process the request.
8959 * @param cls the client
8960 * @param sma the send message that was sent
8963 handle_send_message_ack (void *cls,
8964 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
8966 struct TransportClient *tc = cls;
8967 struct QueueEntry *qe;
8968 struct PendingMessage *pm;
8970 if (CT_COMMUNICATOR != tc->type)
8973 GNUNET_SERVICE_client_drop (tc->client);
8977 /* find our queue entry matching the ACK */
8979 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8980 queue = queue->next_client)
8982 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
8984 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
8987 if (qep->mid != sma->mid)
8996 /* this should never happen */
8998 GNUNET_SERVICE_client_drop (tc->client);
9001 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
9002 qe->queue->queue_tail,
9004 qe->queue->queue_length--;
9005 tc->details.communicator.total_queue_length--;
9006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9007 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
9009 GNUNET_i2s (&qe->queue->neighbour->pid),
9010 qe->queue->queue_length,
9011 tc->details.communicator.total_queue_length);
9012 GNUNET_SERVICE_client_continue (tc->client);
9014 /* if applicable, resume transmissions that waited on ACK */
9015 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
9016 tc->details.communicator.total_queue_length)
9018 /* Communicator dropped below threshold, resume all queues
9019 incident with this client! */
9020 GNUNET_STATISTICS_update (
9022 "# Transmission throttled due to communicator queue limit",
9025 for (struct Queue *queue = tc->details.communicator.queue_head;
9027 queue = queue->next_client)
9028 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9030 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9032 /* queue dropped below threshold; only resume this one queue */
9033 GNUNET_STATISTICS_update (GST_stats,
9034 "# Transmission throttled due to queue queue limit",
9037 schedule_transmit_on_queue (qe->queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9040 if (NULL != (pm = qe->pm))
9042 struct VirtualLink *vl;
9044 GNUNET_assert (qe == pm->qe);
9046 /* If waiting for this communicator may have blocked transmission
9047 of pm on other queues for this neighbour, force schedule
9048 transmit on queue for queues of the neighbour */
9050 if (vl->pending_msg_head == pm)
9051 check_vl_transmission (vl);
9058 * Iterator telling new MONITOR client about all existing
9061 * @param cls the new `struct TransportClient`
9062 * @param pid a connected peer
9063 * @param value the `struct Neighbour` with more information
9064 * @return #GNUNET_OK (continue to iterate)
9067 notify_client_queues (void *cls,
9068 const struct GNUNET_PeerIdentity *pid,
9071 struct TransportClient *tc = cls;
9072 struct Neighbour *neighbour = value;
9074 GNUNET_assert (CT_MONITOR == tc->type);
9075 for (struct Queue *q = neighbour->queue_head; NULL != q;
9076 q = q->next_neighbour)
9078 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
9080 .num_msg_pending = q->num_msg_pending,
9081 .num_bytes_pending = q->num_bytes_pending};
9083 notify_monitor (tc, pid, q->address, q->nt, &me);
9090 * Initialize a monitor client.
9092 * @param cls the client
9093 * @param start the start message that was sent
9096 handle_monitor_start (void *cls,
9097 const struct GNUNET_TRANSPORT_MonitorStart *start)
9099 struct TransportClient *tc = cls;
9101 if (CT_NONE != tc->type)
9104 GNUNET_SERVICE_client_drop (tc->client);
9107 tc->type = CT_MONITOR;
9108 tc->details.monitor.peer = start->peer;
9109 tc->details.monitor.one_shot = ntohl (start->one_shot);
9110 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
9111 GNUNET_SERVICE_client_mark_monitor (tc->client);
9112 GNUNET_SERVICE_client_continue (tc->client);
9117 * Find transport client providing communication service
9118 * for the protocol @a prefix.
9120 * @param prefix communicator name
9121 * @return NULL if no such transport client is available
9123 static struct TransportClient *
9124 lookup_communicator (const char *prefix)
9126 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
9128 if (CT_COMMUNICATOR != tc->type)
9130 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
9134 GNUNET_ERROR_TYPE_WARNING,
9135 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
9142 * Signature of a function called with a communicator @a address of a peer
9143 * @a pid that an application wants us to connect to.
9145 * @param pid target peer
9146 * @param address the address to try
9149 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
9151 static uint32_t idgen;
9152 struct TransportClient *tc;
9154 struct GNUNET_TRANSPORT_CreateQueue *cqm;
9155 struct GNUNET_MQ_Envelope *env;
9158 prefix = GNUNET_HELLO_address_to_prefix (address);
9161 GNUNET_break (0); /* We got an invalid address!? */
9164 tc = lookup_communicator (prefix);
9167 GNUNET_STATISTICS_update (GST_stats,
9168 "# Suggestions ignored due to missing communicator",
9171 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9172 "Cannot connect to %s at `%s', no matching communicator present\n",
9175 GNUNET_free (prefix);
9178 /* forward suggestion for queue creation to communicator */
9179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9180 "Request #%u for `%s' communicator to create queue to `%s'\n",
9181 (unsigned int) idgen,
9184 GNUNET_free (prefix);
9185 alen = strlen (address) + 1;
9187 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
9188 cqm->request_id = htonl (idgen++);
9189 cqm->receiver = *pid;
9190 memcpy (&cqm[1], address, alen);
9191 GNUNET_MQ_send (tc->mq, env);
9196 * The queue @a q (which matches the peer and address in @a vs) is
9197 * ready for queueing. We should now queue the validation request.
9199 * @param q queue to send on
9200 * @param vs state to derive validation challenge from
9203 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
9205 struct TransportValidationChallengeMessage tvc;
9207 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
9209 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
9210 tvc.header.size = htons (sizeof (tvc));
9211 tvc.reserved = htonl (0);
9212 tvc.challenge = vs->challenge;
9213 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
9214 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9215 "Sending address validation challenge %s to %s\n",
9216 GNUNET_sh2s (&tvc.challenge.value),
9217 GNUNET_i2s (&q->neighbour->pid));
9218 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
9223 * Task run periodically to validate some address based on #validation_heap.
9228 validation_start_cb (void *cls)
9230 struct ValidationState *vs;
9234 validation_task = NULL;
9235 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9236 /* drop validations past their expiration */
9239 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
9241 free_validation_state (vs);
9242 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9246 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9247 "Address validation task not scheduled anymore, nothing to do\n");
9248 return; /* woopsie, no more addresses known, should only
9249 happen if we're really a lonely peer */
9251 q = find_queue (&vs->pid, vs->address);
9254 vs->awaiting_queue = GNUNET_YES;
9255 suggest_to_connect (&vs->pid, vs->address);
9258 validation_transmit_on_queue (q, vs);
9259 /* Finally, reschedule next attempt */
9260 vs->challenge_backoff =
9261 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
9262 MAX_VALIDATION_CHALLENGE_FREQ);
9263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9264 "Address validation task will run again in %s\n",
9265 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
9267 update_next_challenge_time (vs,
9268 GNUNET_TIME_relative_to_absolute (
9269 vs->challenge_backoff));
9274 * Closure for #check_connection_quality.
9276 struct QueueQualityContext
9279 * Set to the @e k'th queue encountered.
9284 * Set to the number of quality queues encountered.
9286 unsigned int quality_count;
9289 * Set to the total number of queues encountered.
9291 unsigned int num_queues;
9294 * Decremented for each queue, for selection of the
9295 * k-th queue in @e q.
9302 * Check whether any queue to the given neighbour is
9303 * of a good "quality" and if so, increment the counter.
9304 * Also counts the total number of queues, and returns
9305 * the k-th queue found.
9307 * @param cls a `struct QueueQualityContext *` with counters
9308 * @param pid peer this is about
9309 * @param value a `struct Neighbour`
9310 * @return #GNUNET_OK (continue to iterate)
9313 check_connection_quality (void *cls,
9314 const struct GNUNET_PeerIdentity *pid,
9317 struct QueueQualityContext *ctx = cls;
9318 struct Neighbour *n = value;
9323 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9328 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
9329 statistics and consider those as well here? */
9330 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
9331 do_inc = GNUNET_YES;
9333 if (GNUNET_YES == do_inc)
9334 ctx->quality_count++;
9340 * Task run when we CONSIDER initiating a DV learn
9341 * process. We first check that sending out a message is
9342 * even possible (queues exist), then that it is desirable
9343 * (if not, reschedule the task for later), and finally
9344 * we may then begin the job. If there are too many
9345 * entries in the #dvlearn_map, we purge the oldest entry
9351 start_dv_learn (void *cls)
9353 struct LearnLaunchEntry *lle;
9354 struct QueueQualityContext qqc;
9355 struct TransportDVLearnMessage dvl;
9358 dvlearn_task = NULL;
9359 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
9360 return; /* lost all connectivity, cannot do learning */
9361 qqc.quality_count = 0;
9363 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9364 &check_connection_quality,
9366 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
9368 struct GNUNET_TIME_Relative delay;
9369 unsigned int factor;
9371 /* scale our retries by how far we are above the threshold */
9372 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
9373 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
9374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9375 "At connection quality %u, will launch DV learn in %s\n",
9377 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
9378 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
9381 /* remove old entries in #dvlearn_map if it has grown too big */
9382 while (MAX_DV_LEARN_PENDING >=
9383 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
9386 GNUNET_assert (GNUNET_YES ==
9387 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
9388 &lle->challenge.value,
9390 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9393 /* setup data structure for learning */
9394 lle = GNUNET_new (struct LearnLaunchEntry);
9395 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9397 sizeof (lle->challenge));
9398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9399 "Starting launch DV learn with challenge %s\n",
9400 GNUNET_sh2s (&lle->challenge.value));
9401 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
9402 GNUNET_break (GNUNET_YES ==
9403 GNUNET_CONTAINER_multishortmap_put (
9405 &lle->challenge.value,
9407 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9408 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
9409 dvl.header.size = htons (sizeof (dvl));
9410 dvl.num_hops = htons (0);
9411 dvl.bidirectional = htons (0);
9412 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
9413 dvl.monotonic_time =
9414 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
9416 struct DvInitPS dvip = {.purpose.purpose = htonl (
9417 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
9418 .purpose.size = htonl (sizeof (dvip)),
9419 .monotonic_time = dvl.monotonic_time,
9420 .challenge = lle->challenge};
9422 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9426 dvl.initiator = GST_my_identity;
9427 dvl.challenge = lle->challenge;
9429 qqc.quality_count = 0;
9430 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
9433 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9434 &check_connection_quality,
9436 GNUNET_assert (NULL != qqc.q);
9438 /* Do this as close to transmission time as possible! */
9439 lle->launch_time = GNUNET_TIME_absolute_get ();
9441 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
9442 /* reschedule this job, randomizing the time it runs (but no
9444 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
9445 DV_LEARN_BASE_FREQUENCY),
9452 * A new queue has been created, check if any address validation
9453 * requests have been waiting for it.
9455 * @param cls a `struct Queue`
9456 * @param pid peer concerned (unused)
9457 * @param value a `struct ValidationState`
9458 * @return #GNUNET_NO if a match was found and we can stop looking
9461 check_validation_request_pending (void *cls,
9462 const struct GNUNET_PeerIdentity *pid,
9465 struct Queue *q = cls;
9466 struct ValidationState *vs = value;
9469 if ((GNUNET_YES == vs->awaiting_queue) &&
9470 (0 == strcmp (vs->address, q->address)))
9472 vs->awaiting_queue = GNUNET_NO;
9473 validation_transmit_on_queue (q, vs);
9481 * Function called with the monotonic time of a DV initiator
9482 * by PEERSTORE. Updates the time.
9484 * @param cls a `struct Neighbour`
9485 * @param record the information found, NULL for the last call
9486 * @param emsg error message
9489 neighbour_dv_monotime_cb (void *cls,
9490 const struct GNUNET_PEERSTORE_Record *record,
9493 struct Neighbour *n = cls;
9494 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9499 /* we're done with #neighbour_dv_monotime_cb() invocations,
9500 continue normal processing */
9502 n->dv_monotime_available = GNUNET_YES;
9505 if (sizeof (*mtbe) != record->value_size)
9510 mtbe = record->value;
9511 n->last_dv_learn_monotime =
9512 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
9513 GNUNET_TIME_absolute_ntoh (*mtbe));
9518 * New queue became available. Process the request.
9520 * @param cls the client
9521 * @param aqm the send message that was sent
9524 handle_add_queue_message (void *cls,
9525 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9527 struct TransportClient *tc = cls;
9528 struct Queue *queue;
9529 struct Neighbour *neighbour;
9533 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
9535 /* MTU so small as to be useless for transmissions,
9536 required for #fragment_message()! */
9537 GNUNET_break_op (0);
9538 GNUNET_SERVICE_client_drop (tc->client);
9541 neighbour = lookup_neighbour (&aqm->receiver);
9542 if (NULL == neighbour)
9544 neighbour = GNUNET_new (struct Neighbour);
9545 neighbour->pid = aqm->receiver;
9546 GNUNET_assert (GNUNET_OK ==
9547 GNUNET_CONTAINER_multipeermap_put (
9551 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9553 GNUNET_PEERSTORE_iterate (peerstore,
9556 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
9557 &neighbour_dv_monotime_cb,
9560 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
9561 addr = (const char *) &aqm[1];
9562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9563 "New queue %s to %s available with QID %llu\n",
9565 GNUNET_i2s (&aqm->receiver),
9566 (unsigned long long) aqm->qid);
9567 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
9569 queue->address = (const char *) &queue[1];
9570 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
9571 queue->qid = aqm->qid;
9572 queue->mtu = ntohl (aqm->mtu);
9573 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
9574 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
9575 queue->neighbour = neighbour;
9576 queue->idle = GNUNET_YES;
9577 memcpy (&queue[1], addr, addr_len);
9578 /* notify monitors about new queue */
9580 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
9582 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
9584 GNUNET_CONTAINER_MDLL_insert (neighbour,
9585 neighbour->queue_head,
9586 neighbour->queue_tail,
9588 GNUNET_CONTAINER_MDLL_insert (client,
9589 tc->details.communicator.queue_head,
9590 tc->details.communicator.queue_tail,
9592 /* check if valdiations are waiting for the queue */
9594 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9596 &check_validation_request_pending,
9598 /* look for traffic for this queue */
9599 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9600 /* might be our first queue, try launching DV learning */
9601 if (NULL == dvlearn_task)
9602 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
9603 GNUNET_SERVICE_client_continue (tc->client);
9608 * Communicator tells us that our request to create a queue "worked", that
9609 * is setting up the queue is now in process.
9611 * @param cls the `struct TransportClient`
9612 * @param cqr confirmation message
9615 handle_queue_create_ok (void *cls,
9616 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9618 struct TransportClient *tc = cls;
9620 if (CT_COMMUNICATOR != tc->type)
9623 GNUNET_SERVICE_client_drop (tc->client);
9626 GNUNET_STATISTICS_update (GST_stats,
9627 "# Suggestions succeeded at communicator",
9630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9631 "Request #%u for communicator to create queue succeeded\n",
9632 (unsigned int) ntohs (cqr->request_id));
9633 GNUNET_SERVICE_client_continue (tc->client);
9638 * Communicator tells us that our request to create a queue failed. This
9639 * usually indicates that the provided address is simply invalid or that the
9640 * communicator's resources are exhausted.
9642 * @param cls the `struct TransportClient`
9643 * @param cqr failure message
9646 handle_queue_create_fail (
9648 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9650 struct TransportClient *tc = cls;
9652 if (CT_COMMUNICATOR != tc->type)
9655 GNUNET_SERVICE_client_drop (tc->client);
9658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9659 "Request #%u for communicator to create queue failed\n",
9660 (unsigned int) ntohs (cqr->request_id));
9661 GNUNET_STATISTICS_update (GST_stats,
9662 "# Suggestions failed in queue creation at communicator",
9665 GNUNET_SERVICE_client_continue (tc->client);
9670 * We have received a `struct ExpressPreferenceMessage` from an application
9673 * @param cls handle to the client
9674 * @param msg the start message
9677 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
9679 struct TransportClient *tc = cls;
9680 struct PeerRequest *pr;
9682 if (CT_APPLICATION != tc->type)
9685 GNUNET_SERVICE_client_drop (tc->client);
9688 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
9693 GNUNET_SERVICE_client_drop (tc->client);
9696 (void) stop_peer_request (tc, &pr->pid, pr);
9697 GNUNET_SERVICE_client_continue (tc->client);
9702 * Function called by PEERSTORE for each matching record.
9704 * @param cls closure, a `struct PeerRequest`
9705 * @param record peerstore record information
9706 * @param emsg error message, or NULL if no errors
9709 handle_hello_for_client (void *cls,
9710 const struct GNUNET_PEERSTORE_Record *record,
9713 struct PeerRequest *pr = cls;
9718 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9719 "Got failure from PEERSTORE: %s\n",
9723 val = record->value;
9724 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
9729 start_address_validation (&pr->pid, (const char *) record->value);
9734 * We have received a `struct ExpressPreferenceMessage` from an application
9737 * @param cls handle to the client
9738 * @param msg the start message
9741 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9743 struct TransportClient *tc = cls;
9744 struct PeerRequest *pr;
9746 if (CT_NONE == tc->type)
9748 tc->type = CT_APPLICATION;
9749 tc->details.application.requests =
9750 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9752 if (CT_APPLICATION != tc->type)
9755 GNUNET_SERVICE_client_drop (tc->client);
9758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9759 "Client suggested we talk to %s with preference %d at rate %u\n",
9760 GNUNET_i2s (&msg->peer),
9761 (int) ntohl (msg->pk),
9762 (int) ntohl (msg->bw.value__));
9763 pr = GNUNET_new (struct PeerRequest);
9765 pr->pid = msg->peer;
9767 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
9768 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
9769 tc->details.application.requests,
9772 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
9776 GNUNET_SERVICE_client_drop (tc->client);
9779 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
9782 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9783 &handle_hello_for_client,
9785 GNUNET_SERVICE_client_continue (tc->client);
9790 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
9793 * @param cls a `struct TransportClient *`
9794 * @param m message to verify
9795 * @return #GNUNET_OK on success
9798 check_request_hello_validation (void *cls,
9799 const struct RequestHelloValidationMessage *m)
9802 GNUNET_MQ_check_zero_termination (m);
9808 * A client encountered an address of another peer. Consider validating it,
9809 * and if validation succeeds, persist it to PEERSTORE.
9811 * @param cls a `struct TransportClient *`
9812 * @param m message to verify
9815 handle_request_hello_validation (void *cls,
9816 const struct RequestHelloValidationMessage *m)
9818 struct TransportClient *tc = cls;
9820 start_address_validation (&m->peer, (const char *) &m[1]);
9821 GNUNET_SERVICE_client_continue (tc->client);
9826 * Free neighbour entry.
9830 * @param value a `struct Neighbour`
9831 * @return #GNUNET_OK (always)
9834 free_neighbour_cb (void *cls,
9835 const struct GNUNET_PeerIdentity *pid,
9838 struct Neighbour *neighbour = value;
9842 GNUNET_break (0); // should this ever happen?
9843 free_neighbour (neighbour);
9850 * Free DV route entry.
9854 * @param value a `struct DistanceVector`
9855 * @return #GNUNET_OK (always)
9858 free_dv_routes_cb (void *cls,
9859 const struct GNUNET_PeerIdentity *pid,
9862 struct DistanceVector *dv = value;
9873 * Free validation state.
9877 * @param value a `struct ValidationState`
9878 * @return #GNUNET_OK (always)
9881 free_validation_state_cb (void *cls,
9882 const struct GNUNET_PeerIdentity *pid,
9885 struct ValidationState *vs = value;
9889 free_validation_state (vs);
9895 * Free pending acknowledgement.
9899 * @param value a `struct PendingAcknowledgement`
9900 * @return #GNUNET_OK (always)
9903 free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
9905 struct PendingAcknowledgement *pa = value;
9909 free_pending_acknowledgement (pa);
9915 * Free acknowledgement cummulator.
9919 * @param value a `struct AcknowledgementCummulator`
9920 * @return #GNUNET_OK (always)
9923 free_ack_cummulator_cb (void *cls,
9924 const struct GNUNET_PeerIdentity *pid,
9927 struct AcknowledgementCummulator *ac = value;
9937 * Function called when the service shuts down. Unloads our plugins
9938 * and cancels pending validations.
9940 * @param cls closure, unused
9943 do_shutdown (void *cls)
9945 struct LearnLaunchEntry *lle;
9948 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9949 if (NULL != peerstore)
9951 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9954 if (NULL != GST_stats)
9956 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9959 if (NULL != GST_my_private_key)
9961 GNUNET_free (GST_my_private_key);
9962 GST_my_private_key = NULL;
9964 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9965 &free_ack_cummulator_cb,
9967 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9968 ack_cummulators = NULL;
9969 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
9970 &free_pending_ack_cb,
9972 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
9973 pending_acks = NULL;
9974 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9975 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9977 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9978 GNUNET_CONTAINER_multipeermap_destroy (links);
9980 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9981 &free_backtalker_cb,
9983 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9985 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9986 &free_validation_state_cb,
9988 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9989 validation_map = NULL;
9990 while (NULL != ir_head)
9991 free_incoming_request (ir_head);
9992 GNUNET_assert (0 == ir_total);
9993 while (NULL != (lle = lle_head))
9995 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9998 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
10000 GNUNET_CONTAINER_heap_destroy (validation_heap);
10001 validation_heap = NULL;
10002 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
10003 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
10009 * Initiate transport service.
10011 * @param cls closure
10012 * @param c configuration to use
10013 * @param service the initialized service
10017 const struct GNUNET_CONFIGURATION_Handle *c,
10018 struct GNUNET_SERVICE_Handle *service)
10022 /* setup globals */
10023 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
10025 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10026 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
10027 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
10028 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10029 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
10030 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10031 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
10033 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10035 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
10036 GST_my_private_key =
10037 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
10038 if (NULL == GST_my_private_key)
10041 GNUNET_ERROR_TYPE_ERROR,
10043 "Transport service is lacking key configuration settings. Exiting.\n"));
10044 GNUNET_SCHEDULER_shutdown ();
10047 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
10048 &GST_my_identity.public_key);
10049 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10050 "My identity is `%s'\n",
10051 GNUNET_i2s_full (&GST_my_identity));
10052 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
10053 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
10054 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
10055 if (NULL == peerstore)
10058 GNUNET_SCHEDULER_shutdown ();
10065 * Define "main" method using service macro.
10067 GNUNET_SERVICE_MAIN (
10069 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
10071 &client_connect_cb,
10072 &client_disconnect_cb,
10074 /* communication with applications */
10075 GNUNET_MQ_hd_fixed_size (suggest,
10076 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
10077 struct ExpressPreferenceMessage,
10079 GNUNET_MQ_hd_fixed_size (suggest_cancel,
10080 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
10081 struct ExpressPreferenceMessage,
10083 GNUNET_MQ_hd_var_size (request_hello_validation,
10084 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
10085 struct RequestHelloValidationMessage,
10087 /* communication with core */
10088 GNUNET_MQ_hd_fixed_size (client_start,
10089 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
10090 struct StartMessage,
10092 GNUNET_MQ_hd_var_size (client_send,
10093 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
10094 struct OutboundMessage,
10096 GNUNET_MQ_hd_fixed_size (client_recv_ok,
10097 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
10098 struct RecvOkMessage,
10100 /* communication with communicators */
10101 GNUNET_MQ_hd_var_size (communicator_available,
10102 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
10103 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
10105 GNUNET_MQ_hd_var_size (communicator_backchannel,
10106 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
10107 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
10109 GNUNET_MQ_hd_var_size (add_address,
10110 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
10111 struct GNUNET_TRANSPORT_AddAddressMessage,
10113 GNUNET_MQ_hd_fixed_size (del_address,
10114 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
10115 struct GNUNET_TRANSPORT_DelAddressMessage,
10117 GNUNET_MQ_hd_var_size (incoming_msg,
10118 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
10119 struct GNUNET_TRANSPORT_IncomingMessage,
10121 GNUNET_MQ_hd_fixed_size (queue_create_ok,
10122 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
10123 struct GNUNET_TRANSPORT_CreateQueueResponse,
10125 GNUNET_MQ_hd_fixed_size (queue_create_fail,
10126 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
10127 struct GNUNET_TRANSPORT_CreateQueueResponse,
10129 GNUNET_MQ_hd_var_size (add_queue_message,
10130 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
10131 struct GNUNET_TRANSPORT_AddQueueMessage,
10133 GNUNET_MQ_hd_fixed_size (del_queue_message,
10134 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
10135 struct GNUNET_TRANSPORT_DelQueueMessage,
10137 GNUNET_MQ_hd_fixed_size (send_message_ack,
10138 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
10139 struct GNUNET_TRANSPORT_SendMessageToAck,
10141 /* communication with monitors */
10142 GNUNET_MQ_hd_fixed_size (monitor_start,
10143 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
10144 struct GNUNET_TRANSPORT_MonitorStart,
10146 GNUNET_MQ_handler_end ());
10149 /* end of file gnunet-service-transport.c */