2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
27 * - FIXME: transmit_on_queue: track dvh we may be using and pass it to
28 * fragment_message() and reliability_box_message() if applicable
29 * - proper use/initialization of timestamps in messages exchanged
31 * - persistence of monotonic time from DVInit to prevent
32 * replay attacks using DVInit messages
33 * - dv hop-by-hop signature verification (at least at initiator)
34 * - persistence of monotonic time obtained from other peers
35 * in PEERSTORE (by message type) -- done for backchannel, needed elsewhere?
36 * - change transport-core API to provide proper flow control in both
37 * directions, allow multiple messages per peer simultaneously (tag
38 * confirmations with unique message ID), and replace quota-out with
39 * proper flow control; specify transmission preferences (latency,
40 * reliability, etc.) per message!
44 * - review retransmission logic, right now there is no smartness there!
45 * => congestion control, flow control, etc
48 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
49 * => Need 128 bit hash map though!
50 * - queue_send_msg and route_message both by API design have to make copies
51 * of the payload, and route_message on top of that requires a malloc/free.
52 * Change design to approximate "zero" copy better...
53 * - could avoid copying body of message into each fragment and keep
54 * fragments as just pointers into the original message and only
55 * fully build fragments just before transmission (optimization, should
56 * reduce CPU and memory use)
57 * - if messages are below MTU, consider adding ACKs and other stuff
58 * (requires planning at receiver, and additional MST-style demultiplex
60 * - When we passively learned DV (with unconfirmed freshness), we
61 * right now add the path to our list but with a zero path_valid_until
62 * time and only use it for unconfirmed routes. However, we could consider
63 * triggering an explicit validation mechansim ourselves, specifically routing
64 * a challenge-response message over the path (OPTIMIZATION-FIXME).
66 * Design realizations / discussion:
67 * - communicators do flow control by calling MQ "notify sent"
68 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
69 * or explicitly via backchannel FC ACKs. As long as the
70 * channel is not full, they may 'notify sent' even if the other
71 * peer has not yet confirmed receipt. The other peer confirming
72 * is _only_ for FC, not for more reliable transmission; reliable
73 * transmission (i.e. of fragments) is left to _transport_.
74 * - ACKs sent back in uni-directional communicators are done via
75 * the background channel API; here transport _may_ initially
76 * broadcast (with bounded # hops) if no path is known;
77 * - transport should _integrate_ DV-routing and build a view of
78 * the network; then background channel traffic can be
79 * routed via DV as well as explicit "DV" traffic.
80 * - background channel is also used for ACKs and NAT traversal support
81 * - transport service is responsible for AEAD'ing the background
82 * channel, timestamps and monotonic time are used against replay
83 * of old messages -> peerstore needs to be supplied with
84 * "latest timestamps seen" data
85 * - if transport implements DV, we likely need a 3rd peermap
86 * in addition to ephemerals and (direct) neighbours
87 * ==> check if stuff needs to be moved out of "Neighbour"
88 * - transport should encapsualte core-level messages and do its
89 * own ACKing for RTT/goodput/loss measurements _and_ fragment
93 #include "gnunet_util_lib.h"
94 #include "gnunet_statistics_service.h"
95 #include "gnunet_transport_monitor_service.h"
96 #include "gnunet_peerstore_service.h"
97 #include "gnunet_hello_lib.h"
98 #include "gnunet_signatures.h"
99 #include "transport.h"
102 * Maximum number of messages we acknowledge together in one
103 * cummulative ACK. Larger values may save a bit of bandwidth.
105 #define MAX_CUMMULATIVE_ACKS 64
108 * What is the size we assume for a read operation in the
109 * absence of an MTU for the purpose of flow control?
111 #define IN_PACKET_SIZE_WITHOUT_MTU 128
114 * Number of slots we keep of historic data for computation of
115 * goodput / message loss ratio.
117 #define GOODPUT_AGING_SLOTS 4
120 * Maximum number of peers we select for forwarding DVInit
121 * messages at the same time (excluding initiator).
123 #define MAX_DV_DISCOVERY_SELECTION 16
126 * Minimum number of hops we should forward DV learn messages
127 * even if they are NOT useful for us in hope of looping
128 * back to the initiator?
130 * FIXME: allow initiator some control here instead?
132 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
135 * Maximum DV distance allowed ever.
137 #define MAX_DV_HOPS_ALLOWED 16
140 * Maximum number of DV learning activities we may
141 * have pending at the same time.
143 #define MAX_DV_LEARN_PENDING 64
146 * Maximum number of DV paths we keep simultaneously to the same target.
148 #define MAX_DV_PATHS_TO_TARGET 3
151 * If a queue delays the next message by more than this number
152 * of seconds we log a warning. Note: this is for testing,
153 * the value chosen here might be too aggressively low!
155 #define DELAY_WARN_THRESHOLD \
156 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
159 * We only consider queues as "quality" connections when
160 * suppressing the generation of DV initiation messages if
161 * the latency of the queue is below this threshold.
163 #define DV_QUALITY_RTT_THRESHOLD \
164 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
167 * How long do we consider a DV path valid if we see no
168 * further updates on it? Note: the value chosen here might be too low!
170 #define DV_PATH_VALIDITY_TIMEOUT \
171 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
174 * How long do we cache backchannel (struct Backtalker) information
175 * after a backchannel goes inactive?
177 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
178 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
181 * How long before paths expire would we like to (re)discover DV paths? Should
182 * be below #DV_PATH_VALIDITY_TIMEOUT.
184 #define DV_PATH_DISCOVERY_FREQUENCY \
185 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
188 * How long are ephemeral keys valid?
190 #define EPHEMERAL_VALIDITY \
191 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
194 * How long do we keep partially reassembled messages around before giving up?
196 #define REASSEMBLY_EXPIRATION \
197 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
200 * What is the fastest rate at which we send challenges *if* we keep learning
201 * an address (gossip, DHT, etc.)?
203 #define FAST_VALIDATION_CHALLENGE_FREQ \
204 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
207 * What is the slowest rate at which we send challenges?
209 #define MAX_VALIDATION_CHALLENGE_FREQ \
210 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
213 * How long until we forget about historic accumulators and thus
214 * reset the ACK counter? Should exceed the maximum time an
215 * active connection experiences without an ACK.
217 #define ACK_CUMMULATOR_TIMEOUT \
218 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
221 * What is the non-randomized base frequency at which we
222 * would initiate DV learn messages?
224 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
227 * How many good connections (confirmed, bi-directional, not DV)
228 * do we need to have to suppress initiating DV learn messages?
230 #define DV_LEARN_QUALITY_THRESHOLD 100
233 * When do we forget an invalid address for sure?
235 #define MAX_ADDRESS_VALID_UNTIL \
236 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
239 * How long do we consider an address valid if we just checked?
241 #define ADDRESS_VALIDATION_LIFETIME \
242 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
245 * What is the maximum frequency at which we do address validation?
246 * A random value between 0 and this value is added when scheduling
247 * the #validation_task (both to ensure we do not validate too often,
248 * and to randomize a bit).
250 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
253 * How many network RTTs before an address validation expires should we begin
254 * trying to revalidate? (Note that the RTT used here is the one that we
255 * experienced during the last validation, not necessarily the latest RTT
258 #define VALIDATION_RTT_BUFFER_FACTOR 3
261 * How many messages can we have pending for a given communicator
262 * process before we start to throttle that communicator?
264 * Used if a communicator might be CPU-bound and cannot handle the traffic.
266 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
269 * How many messages can we have pending for a given queue (queue to
270 * a particular peer via a communicator) process before we start to
271 * throttle that queue?
273 #define QUEUE_LENGTH_LIMIT 32
276 GNUNET_NETWORK_STRUCT_BEGIN
279 * Unique identifier we attach to a message.
284 * Unique value, generated by incrementing the
285 * `message_uuid_ctr` of `struct Neighbour`.
287 uint64_t uuid GNUNET_PACKED;
292 * Unique identifier to map an acknowledgement to a transmission.
294 struct AcknowledgementUUIDP
297 * The UUID value. Not actually a hash, but a random value.
299 struct GNUNET_ShortHashCode value;
304 * Unique identifier we attach to a message.
309 * Unique value identifying a fragment, in NBO.
311 uint32_t uuid GNUNET_PACKED;
316 * Type of a nonce used for challenges.
318 struct ChallengeNonceP
321 * The value of the nonce. Note that this is NOT a hash.
323 struct GNUNET_ShortHashCode value;
328 * Outer layer of an encapsulated backchannel message.
330 struct TransportBackchannelEncapsulationMessage
333 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
335 struct GNUNET_MessageHeader header;
338 * Reserved, always zero.
340 uint32_t reserved GNUNET_PACKED;
343 * Target's peer identity (as backchannels may be transmitted
344 * indirectly, or even be broadcast).
346 struct GNUNET_PeerIdentity target;
349 * Ephemeral key setup by the sender for @e target, used
350 * to encrypt the payload.
352 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
355 * We use an IV here as the @e ephemeral_key is re-used for
356 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
358 struct GNUNET_ShortHashCode iv;
361 * HMAC over the ciphertext of the encrypted, variable-size
362 * body that follows. Verified via DH of @e target and
365 struct GNUNET_HashCode hmac;
367 /* Followed by encrypted, variable-size payload */
372 * Body by which a peer confirms that it is using an ephemeral key.
374 struct EphemeralConfirmationPS
378 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
380 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
383 * How long is this signature over the ephemeral key valid?
385 * Note that the receiver MUST IGNORE the absolute time, and only interpret
386 * the value as a mononic time and reject "older" values than the last one
387 * observed. This is necessary as we do not want to require synchronized
388 * clocks and may not have a bidirectional communication channel.
390 * Even with this, there is no real guarantee against replay achieved here,
391 * unless the latest timestamp is persisted. While persistence should be
392 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
393 * communicators must protect against replay attacks when using backchannel
396 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
399 * Target's peer identity.
401 struct GNUNET_PeerIdentity target;
404 * Ephemeral key setup by the sender for @e target, used
405 * to encrypt the payload.
407 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
412 * Plaintext of the variable-size payload that is encrypted
413 * within a `struct TransportBackchannelEncapsulationMessage`
415 struct TransportBackchannelRequestPayloadP
419 * Sender's peer identity.
421 struct GNUNET_PeerIdentity sender;
424 * Signature of the sender over an
425 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
427 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
430 * How long is this signature over the ephemeral key valid?
432 * Note that the receiver MUST IGNORE the absolute time, and only interpret
433 * the value as a mononic time and reject "older" values than the last one
434 * observed. This is necessary as we do not want to require synchronized
435 * clocks and may not have a bidirectional communication channel.
437 * Even with this, there is no real guarantee against replay achieved here,
438 * unless the latest timestamp is persisted. While persistence should be
439 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
440 * communicators must protect against replay attacks when using backchannel
443 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
446 * Current monotonic time of the sending transport service. Used to
447 * detect replayed messages. Note that the receiver should remember
448 * a list of the recently seen timestamps and only reject messages
449 * if the timestamp is in the list, or the list is "full" and the
450 * timestamp is smaller than the lowest in the list.
452 * Like the @e ephemeral_validity, the list of timestamps per peer should be
453 * persisted to guard against replays after restarts.
455 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
457 /* Followed by a `struct GNUNET_MessageHeader` with a message
458 for a communicator */
460 /* Followed by a 0-termianted string specifying the name of
461 the communicator which is to receive the message */
466 * Outer layer of an encapsulated unfragmented application message sent
467 * over an unreliable channel.
469 struct TransportReliabilityBoxMessage
472 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
474 struct GNUNET_MessageHeader header;
477 * Number of messages still to be sent before a commulative
478 * ACK is requested. Zero if an ACK is requested immediately.
479 * In NBO. Note that the receiver may send the ACK faster
480 * if it believes that is reasonable.
482 uint32_t ack_countdown GNUNET_PACKED;
485 * Unique ID of the message used for signalling receipt of
486 * messages sent over possibly unreliable channels. Should
489 struct AcknowledgementUUIDP ack_uuid;
494 * Acknowledgement payload.
496 struct TransportCummulativeAckPayloadP
499 * How long was the ACK delayed for generating cummulative ACKs?
500 * Used to calculate the correct network RTT by taking the receipt
501 * time of the ack minus the transmission time of the sender minus
504 struct GNUNET_TIME_RelativeNBO ack_delay;
507 * UUID of a message being acknowledged.
509 struct AcknowledgementUUIDP ack_uuid;
514 * Confirmation that the receiver got a
515 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
516 * confirmation may be transmitted over a completely different queue,
517 * so ACKs are identified by a combination of PID of sender and
518 * message UUID, without the queue playing any role!
520 struct TransportReliabilityAckMessage
523 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
525 struct GNUNET_MessageHeader header;
528 * Counter of ACKs transmitted by the sender to us. Incremented
529 * by one for each ACK, used to detect how many ACKs were lost.
531 uint32_t ack_counter GNUNET_PACKED;
533 /* followed by any number of `struct TransportCummulativeAckPayloadP`
534 messages providing ACKs */
539 * Outer layer of an encapsulated fragmented application message.
541 struct TransportFragmentBoxMessage
544 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
546 struct GNUNET_MessageHeader header;
549 * Unique ID of this fragment (and fragment transmission!). Will
550 * change even if a fragement is retransmitted to make each
551 * transmission attempt unique! If a client receives a duplicate
552 * fragment (same @e frag_off for same @a msg_uuid, it must send
553 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
555 struct AcknowledgementUUIDP ack_uuid;
558 * Original message ID for of the message that all the fragments
559 * belong to. Must be the same for all fragments.
561 struct MessageUUIDP msg_uuid;
564 * Offset of this fragment in the overall message.
566 uint16_t frag_off GNUNET_PACKED;
569 * Total size of the message that is being fragmented.
571 uint16_t msg_size GNUNET_PACKED;
576 * Content signed by the initator during DV learning.
578 * The signature is required to prevent DDoS attacks. A peer sending out this
579 * message is potentially generating a lot of traffic that will go back to the
580 * initator, as peers receiving this message will try to let the initiator
581 * know that they got the message.
583 * Without this signature, an attacker could abuse this mechanism for traffic
584 * amplification, sending a lot of traffic to a peer by putting out this type
585 * of message with the victim's peer identity.
587 * Even with just a signature, traffic amplification would be possible via
588 * replay attacks. The @e monotonic_time limits such replay attacks, as every
589 * potential amplificator will check the @e monotonic_time and only respond
590 * (at most) once per message.
595 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
597 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
600 * Time at the initiator when generating the signature.
602 * Note that the receiver MUST IGNORE the absolute time, and only interpret
603 * the value as a mononic time and reject "older" values than the last one
604 * observed. This is necessary as we do not want to require synchronized
605 * clocks and may not have a bidirectional communication channel.
607 * Even with this, there is no real guarantee against replay achieved here,
608 * unless the latest timestamp is persisted. Persistence should be
609 * provided via PEERSTORE if possible.
611 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
614 * Challenge value used by the initiator to re-identify the path.
616 struct ChallengeNonceP challenge;
621 * Content signed by each peer during DV learning.
623 * This assues the initiator of the DV learning operation that the hop from @e
624 * pred via the signing peer to @e succ actually exists. This makes it
625 * impossible for an adversary to supply the network with bogus routes.
627 * The @e challenge is included to provide replay protection for the
628 * initiator. This way, the initiator knows that the hop existed after the
629 * original @e challenge was first transmitted, providing a freshness metric.
631 * Peers other than the initiator that passively learn paths by observing
632 * these messages do NOT benefit from this. Here, an adversary may indeed
633 * replay old messages. Thus, passively learned paths should always be
634 * immediately marked as "potentially stale".
639 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
641 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
644 * Identity of the previous peer on the path.
646 struct GNUNET_PeerIdentity pred;
649 * Identity of the next peer on the path.
651 struct GNUNET_PeerIdentity succ;
654 * Challenge value used by the initiator to re-identify the path.
656 struct ChallengeNonceP challenge;
661 * An entry describing a peer on a path in a
662 * `struct TransportDVLearnMessage` message.
667 * Identity of a peer on the path.
669 struct GNUNET_PeerIdentity hop;
672 * Signature of this hop over the path, of purpose
673 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
675 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
680 * Internal message used by transport for distance vector learning.
681 * If @e num_hops does not exceed the threshold, peers should append
682 * themselves to the peer list and flood the message (possibly only
683 * to a subset of their neighbours to limit discoverability of the
684 * network topology). To the extend that the @e bidirectional bits
685 * are set, peers may learn the inverse paths even if they did not
688 * Unless received on a bidirectional queue and @e num_hops just
689 * zero, peers that can forward to the initator should always try to
690 * forward to the initiator.
692 struct TransportDVLearnMessage
695 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
697 struct GNUNET_MessageHeader header;
700 * Number of hops this messages has travelled, in NBO. Zero if
703 uint16_t num_hops GNUNET_PACKED;
706 * Bitmask of the last 16 hops indicating whether they are confirmed
707 * available (without DV) in both directions or not, in NBO. Used
708 * to possibly instantly learn a path in both directions. Each peer
709 * should shift this value by one to the left, and then set the
710 * lowest bit IF the current sender can be reached from it (without
713 uint16_t bidirectional GNUNET_PACKED;
716 * Peers receiving this message and delaying forwarding to other
717 * peers for any reason should increment this value by the non-network
718 * delay created by the peer.
720 struct GNUNET_TIME_RelativeNBO non_network_delay;
723 * Signature of this hop over the path, of purpose
724 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
726 struct GNUNET_CRYPTO_EddsaSignature init_sig;
729 * Identity of the peer that started this learning activity.
731 struct GNUNET_PeerIdentity initiator;
734 * Challenge value used by the initiator to re-identify the path.
736 struct ChallengeNonceP challenge;
738 /* Followed by @e num_hops `struct DVPathEntryP` values,
739 excluding the initiator of the DV trace; the last entry is the
740 current sender; the current peer must not be included. */
745 * Outer layer of an encapsulated message send over multiple hops.
746 * The path given only includes the identities of the subsequent
747 * peers, i.e. it will be empty if we are the receiver. Each
748 * forwarding peer should scan the list from the end, and if it can,
749 * forward to the respective peer. The list should then be shortened
750 * by all the entries up to and including that peer. Each hop should
751 * also increment @e total_hops to allow the receiver to get a precise
752 * estimate on the number of hops the message travelled. Senders must
753 * provide a learned path that thus should work, but intermediaries
754 * know of a shortcut, they are allowed to send the message via that
757 * If a peer finds itself still on the list, it must drop the message.
759 struct TransportDVBoxMessage
762 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
764 struct GNUNET_MessageHeader header;
767 * Number of total hops this messages travelled. In NBO.
768 * @e origin sets this to zero, to be incremented at
771 uint16_t total_hops GNUNET_PACKED;
774 * Number of hops this messages includes. In NBO.
776 uint16_t num_hops GNUNET_PACKED;
779 * Identity of the peer that originated the message.
781 struct GNUNET_PeerIdentity origin;
783 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
784 excluding the @e origin and the current peer, the last must be
785 the ultimate target; if @e num_hops is zero, the receiver of this
786 message is the ultimate target. */
788 /* Followed by the actual message, which itself may be
789 another box, but not a DV_LEARN or DV_BOX message! */
794 * Message send to another peer to validate that it can indeed
795 * receive messages at a particular address.
797 struct TransportValidationChallengeMessage
801 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
803 struct GNUNET_MessageHeader header;
808 uint32_t reserved GNUNET_PACKED;
811 * Challenge to be signed by the receiving peer.
813 struct ChallengeNonceP challenge;
816 * Timestamp of the sender, to be copied into the reply
817 * to allow sender to calculate RTT.
819 struct GNUNET_TIME_AbsoluteNBO sender_time;
824 * Message signed by a peer to confirm that it can indeed
825 * receive messages at a particular address.
827 struct TransportValidationPS
831 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
833 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
836 * How long does the sender believe the address on
837 * which the challenge was received to remain valid?
839 struct GNUNET_TIME_RelativeNBO validity_duration;
842 * Challenge signed by the receiving peer.
844 struct ChallengeNonceP challenge;
849 * Message send to a peer to respond to a
850 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
852 struct TransportValidationResponseMessage
856 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
858 struct GNUNET_MessageHeader header;
863 uint32_t reserved GNUNET_PACKED;
866 * The peer's signature matching the
867 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
869 struct GNUNET_CRYPTO_EddsaSignature signature;
872 * The challenge that was signed by the receiving peer.
874 struct ChallengeNonceP challenge;
877 * Original timestamp of the sender (was @code{sender_time}),
878 * copied into the reply to allow sender to calculate RTT.
880 struct GNUNET_TIME_AbsoluteNBO origin_time;
883 * How long does the sender believe this address to remain
886 struct GNUNET_TIME_RelativeNBO validity_duration;
890 GNUNET_NETWORK_STRUCT_END
894 * What type of client is the `struct TransportClient` about?
899 * We do not know yet (client is fresh).
904 * Is the CORE service, we need to forward traffic to it.
909 * It is a monitor, forward monitor data.
914 * It is a communicator, use for communication.
919 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
926 * When did we launch this DV learning activity?
928 struct LearnLaunchEntry
932 * Kept (also) in a DLL sorted by launch time.
934 struct LearnLaunchEntry *prev;
937 * Kept (also) in a DLL sorted by launch time.
939 struct LearnLaunchEntry *next;
942 * Challenge that uniquely identifies this activity.
944 struct ChallengeNonceP challenge;
947 * When did we transmit the DV learn message (used to calculate RTT) and
948 * determine freshness of paths learned via this operation.
950 struct GNUNET_TIME_Absolute launch_time;
955 * Entry in our cache of ephemeral keys we currently use. This way, we only
956 * sign an ephemeral once per @e target, and then can re-use it over multiple
957 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
958 * signing is expensive and in some cases we may use backchannel messages a
961 struct EphemeralCacheEntry
965 * Target's peer identity (we don't re-use ephemerals
966 * to limit linkability of messages).
968 struct GNUNET_PeerIdentity target;
971 * Signature affirming @e ephemeral_key of type
972 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
974 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
977 * How long is @e sender_sig valid
979 struct GNUNET_TIME_Absolute ephemeral_validity;
984 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
987 * Our private ephemeral key.
989 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
992 * Node in the ephemeral cache for this entry.
993 * Used for expiration.
995 struct GNUNET_CONTAINER_HeapNode *hn;
1000 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1001 * (or current) transmission performance.
1003 struct TransmissionHistoryEntry
1006 * Number of bytes actually sent in the interval.
1008 uint64_t bytes_sent;
1011 * Number of bytes received and acknowledged by the other peer in
1014 uint64_t bytes_received;
1019 * Performance data for a transmission possibility.
1021 struct PerformanceData
1024 * Weighted average for the RTT.
1026 struct GNUNET_TIME_Relative aged_rtt;
1029 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1032 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1035 * What was the last age when we wrote to @e the? Used to clear
1036 * old entries when the age advances.
1038 unsigned int last_age;
1043 * Client connected to the transport service.
1045 struct TransportClient;
1048 * A neighbour that at least one communicator is connected to.
1053 * Entry in our #dv_routes table, representing a (set of) distance
1054 * vector routes to a particular peer.
1056 struct DistanceVector;
1059 * A queue is a message queue provided by a communicator
1060 * via which we can reach a particular neighbour.
1065 * Message awaiting transmission. See detailed comments below.
1067 struct PendingMessage;
1070 * One possible hop towards a DV target.
1072 struct DistanceVectorHop;
1076 * Data structure kept when we are waiting for an acknowledgement.
1078 struct PendingAcknowledgement
1082 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1083 * is kept in relation to its pending message.
1085 struct PendingAcknowledgement *next_pm;
1088 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1089 * is kept in relation to its pending message.
1091 struct PendingAcknowledgement *prev_pm;
1094 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1095 * is kept in relation to the queue that was used to transmit the
1098 struct PendingAcknowledgement *next_queue;
1101 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1102 * is kept in relation to the queue that was used to transmit the
1105 struct PendingAcknowledgement *prev_queue;
1108 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1109 * is kept in relation to the DVH that was used to transmit the
1112 struct PendingAcknowledgement *next_dvh;
1115 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1116 * is kept in relation to the DVH that was used to transmit the
1119 struct PendingAcknowledgement *prev_dvh;
1122 * Pointers for the DLL of all pending acknowledgements.
1123 * This list is sorted by @e transmission time. If the list gets too
1124 * long, the oldest entries are discarded.
1126 struct PendingAcknowledgement *next_pa;
1129 * Pointers for the DLL of all pending acknowledgements.
1130 * This list is sorted by @e transmission time. If the list gets too
1131 * long, the oldest entries are discarded.
1133 struct PendingAcknowledgement *prev_pa;
1136 * Unique identifier for this transmission operation.
1138 struct AcknowledgementUUIDP ack_uuid;
1141 * Message that was transmitted, may be NULL if the message was ACKed
1142 * via another channel.
1144 struct PendingMessage *pm;
1147 * Distance vector path chosen for this transmission, NULL if transmission
1148 * was to a direct neighbour OR if the path was forgotten in the meantime.
1150 struct DistanceVectorHop *dvh;
1153 * Queue used for transmission, NULL if the queue has been destroyed
1154 * (which may happen before we get an acknowledgement).
1156 struct Queue *queue;
1159 * Time of the transmission, for RTT calculation.
1161 struct GNUNET_TIME_Absolute transmission_time;
1164 * Number of bytes of the original message (to calculate bandwidth).
1166 uint16_t message_size;
1171 * One possible hop towards a DV target.
1173 struct DistanceVectorHop
1177 * Kept in a MDLL, sorted by @e timeout.
1179 struct DistanceVectorHop *next_dv;
1182 * Kept in a MDLL, sorted by @e timeout.
1184 struct DistanceVectorHop *prev_dv;
1189 struct DistanceVectorHop *next_neighbour;
1194 struct DistanceVectorHop *prev_neighbour;
1197 * Head of DLL of PAs that used our @a path.
1199 struct PendingAcknowledgement *pa_head;
1202 * Tail of DLL of PAs that used our @a path.
1204 struct PendingAcknowledgement *pa_tail;
1207 * What would be the next hop to @e target?
1209 struct Neighbour *next_hop;
1212 * Distance vector entry this hop belongs with.
1214 struct DistanceVector *dv;
1217 * Array of @e distance hops to the target, excluding @e next_hop.
1218 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1219 * at the end of this struct. Excludes the target itself!
1221 const struct GNUNET_PeerIdentity *path;
1224 * At what time do we forget about this path unless we see it again
1227 struct GNUNET_TIME_Absolute timeout;
1230 * For how long is the validation of this path considered
1232 * Set to ZERO if the path is learned by snooping on DV learn messages
1233 * initiated by other peers, and to the time at which we generated the
1234 * challenge for DV learn operations this peer initiated.
1236 struct GNUNET_TIME_Absolute path_valid_until;
1239 * Performance data for this transmission possibility.
1241 struct PerformanceData pd;
1244 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1245 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1248 unsigned int distance;
1253 * Entry in our #dv_routes table, representing a (set of) distance
1254 * vector routes to a particular peer.
1256 struct DistanceVector
1260 * To which peer is this a route?
1262 struct GNUNET_PeerIdentity target;
1265 * Known paths to @e target.
1267 struct DistanceVectorHop *dv_head;
1270 * Known paths to @e target.
1272 struct DistanceVectorHop *dv_tail;
1275 * Task scheduled to purge expired paths from @e dv_head MDLL.
1277 struct GNUNET_SCHEDULER_Task *timeout_task;
1280 * Task scheduled to possibly notfiy core that this queue is no longer
1281 * counting as confirmed. Runs the #core_queue_visibility_check().
1283 struct GNUNET_SCHEDULER_Task *visibility_task;
1286 * Quota at which CORE is allowed to transmit to this peer
1287 * (note that the value CORE should actually be told is this
1288 * value plus the respective value in `struct Neighbour`).
1289 * Should match the sum of the quotas of all of the paths.
1291 * FIXME: not yet set, tricky to get right given multiple paths,
1292 * many of which may be inactive! (=> Idea: measure???)
1293 * FIXME: how do we set this value initially when we tell CORE?
1294 * Options: start at a minimum value or at literally zero?
1295 * (=> Current thought: clean would be zero!)
1297 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1300 * Is one of the DV paths in this struct 'confirmed' and thus
1301 * the cause for CORE to see this peer as connected? (Note that
1302 * the same may apply to a `struct Neighbour` at the same time.)
1309 * Entry identifying transmission in one of our `struct
1310 * Queue` which still awaits an ACK. This is used to
1311 * ensure we do not overwhelm a communicator and limit the number of
1312 * messages outstanding per communicator (say in case communicator is
1313 * CPU bound) and per queue (in case bandwidth allocation exceeds
1314 * what the communicator can actually provide towards a particular
1323 struct QueueEntry *next;
1328 struct QueueEntry *prev;
1331 * Queue this entry is queued with.
1333 struct Queue *queue;
1336 * Pending message this entry is for, or NULL for none.
1338 struct PendingMessage *pm;
1341 * Message ID used for this message with the queue used for transmission.
1348 * A queue is a message queue provided by a communicator
1349 * via which we can reach a particular neighbour.
1356 struct Queue *next_neighbour;
1361 struct Queue *prev_neighbour;
1366 struct Queue *prev_client;
1371 struct Queue *next_client;
1374 * Head of DLL of PAs that used this queue.
1376 struct PendingAcknowledgement *pa_head;
1379 * Tail of DLL of PAs that used this queue.
1381 struct PendingAcknowledgement *pa_tail;
1384 * Head of DLL of unacked transmission requests.
1386 struct QueueEntry *queue_head;
1389 * End of DLL of unacked transmission requests.
1391 struct QueueEntry *queue_tail;
1394 * Which neighbour is this queue for?
1396 struct Neighbour *neighbour;
1399 * Which communicator offers this queue?
1401 struct TransportClient *tc;
1404 * Address served by the queue.
1406 const char *address;
1409 * Task scheduled for the time when this queue can (likely) transmit the
1410 * next message. Still needs to check with the @e tracker_out to be sure.
1412 struct GNUNET_SCHEDULER_Task *transmit_task;
1415 * Task scheduled to possibly notfiy core that this queue is no longer
1416 * counting as confirmed. Runs the #core_queue_visibility_check().
1418 struct GNUNET_SCHEDULER_Task *visibility_task;
1421 * How long do *we* consider this @e address to be valid? In the past or
1422 * zero if we have not yet validated it. Can be updated based on
1423 * challenge-response validations (via address validation logic), or when we
1424 * receive ACKs that we can definitively map to transmissions via this
1427 struct GNUNET_TIME_Absolute validated_until;
1430 * Performance data for this queue.
1432 struct PerformanceData pd;
1435 * Message ID generator for transmissions on this queue to the
1441 * Unique identifier of this queue with the communicator.
1446 * Maximum transmission unit supported by this queue.
1453 uint32_t num_msg_pending;
1458 uint32_t num_bytes_pending;
1461 * Length of the DLL starting at @e queue_head.
1463 unsigned int queue_length;
1466 * Network type offered by this queue.
1468 enum GNUNET_NetworkType nt;
1471 * Connection status for this queue.
1473 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1476 * How much outbound bandwidth do we have available for this queue?
1478 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1481 * How much inbound bandwidth do we have available for this queue?
1483 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1488 * Information we keep for a message that we are reassembling.
1490 struct ReassemblyContext
1494 * Original message ID for of the message that all the fragments
1497 struct MessageUUIDP msg_uuid;
1500 * Which neighbour is this context for?
1502 struct Neighbour *neighbour;
1505 * Entry in the reassembly heap (sorted by expiration).
1507 struct GNUNET_CONTAINER_HeapNode *hn;
1510 * Bitfield with @e msg_size bits representing the positions
1511 * where we have received fragments. When we receive a fragment,
1512 * we check the bits in @e bitfield before incrementing @e msg_missing.
1514 * Allocated after the reassembled message.
1519 * Task for sending ACK. We may send ACKs either because of hitting
1520 * the @e extra_acks limit, or based on time and @e num_acks. This
1521 * task is for the latter case.
1523 struct GNUNET_SCHEDULER_Task *ack_task;
1526 * At what time will we give up reassembly of this message?
1528 struct GNUNET_TIME_Absolute reassembly_timeout;
1531 * Time we received the last fragment. @e avg_ack_delay must be
1532 * incremented by now - @e last_frag multiplied by @e num_acks.
1534 struct GNUNET_TIME_Absolute last_frag;
1537 * How big is the message we are reassembling in total?
1542 * How many bytes of the message are still missing? Defragmentation
1543 * is complete when @e msg_missing == 0.
1545 uint16_t msg_missing;
1547 /* Followed by @e msg_size bytes of the (partially) defragmented original
1550 /* Followed by @e bitfield data */
1555 * A neighbour that at least one communicator is connected to.
1561 * Which peer is this about?
1563 struct GNUNET_PeerIdentity pid;
1566 * Map with `struct ReassemblyContext` structs for fragments under
1567 * reassembly. May be NULL if we currently have no fragments from
1568 * this @e pid (lazy initialization).
1570 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1573 * Heap with `struct ReassemblyContext` structs for fragments under
1574 * reassembly. May be NULL if we currently have no fragments from
1575 * this @e pid (lazy initialization).
1577 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1580 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1582 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1585 * Head of list of messages pending for this neighbour.
1587 struct PendingMessage *pending_msg_head;
1590 * Tail of list of messages pending for this neighbour.
1592 struct PendingMessage *pending_msg_tail;
1595 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1596 * purged if this neighbour goes down.
1598 struct DistanceVectorHop *dv_head;
1601 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1602 * purged if this neighbour goes down.
1604 struct DistanceVectorHop *dv_tail;
1607 * Head of DLL of queues to this peer.
1609 struct Queue *queue_head;
1612 * Tail of DLL of queues to this peer.
1614 struct Queue *queue_tail;
1617 * Task run to cleanup pending messages that have exceeded their timeout.
1619 struct GNUNET_SCHEDULER_Task *timeout_task;
1622 * Quota at which CORE is allowed to transmit to this peer
1623 * (note that the value CORE should actually be told is this
1624 * value plus the respective value in `struct DistanceVector`).
1625 * Should match the sum of the quotas of all of the queues.
1627 * FIXME: not yet set, tricky to get right given multiple queues!
1628 * (=> Idea: measure???)
1629 * FIXME: how do we set this value initially when we tell CORE?
1630 * Options: start at a minimum value or at literally zero?
1631 * (=> Current thought: clean would be zero!)
1633 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1636 * What is the earliest timeout of any message in @e pending_msg_tail?
1638 struct GNUNET_TIME_Absolute earliest_timeout;
1641 * Do we have a confirmed working queue and are thus visible to
1649 * A peer that an application (client) would like us to talk to directly.
1655 * Which peer is this about?
1657 struct GNUNET_PeerIdentity pid;
1660 * Client responsible for the request.
1662 struct TransportClient *tc;
1665 * Handle for watching the peerstore for HELLOs for this peer.
1667 struct GNUNET_PEERSTORE_WatchContext *wc;
1670 * What kind of performance preference does this @e tc have?
1672 enum GNUNET_MQ_PreferenceKind pk;
1675 * How much bandwidth would this @e tc like to see?
1677 struct GNUNET_BANDWIDTH_Value32NBO bw;
1682 * Types of different pending messages.
1684 enum PendingMessageType
1688 * Ordinary message received from the CORE service.
1695 PMT_FRAGMENT_BOX = 1,
1700 PMT_RELIABILITY_BOX = 2,
1703 * Any type of acknowledgement.
1705 PMT_ACKNOWLEDGEMENT = 3,
1708 * Control traffic generated by the TRANSPORT service itself.
1716 * Transmission request that is awaiting delivery. The original
1717 * transmission requests from CORE may be too big for some queues.
1718 * In this case, a *tree* of fragments is created. At each
1719 * level of the tree, fragments are kept in a DLL ordered by which
1720 * fragment should be sent next (at the head). The tree is searched
1721 * top-down, with the original message at the root.
1723 * To select a node for transmission, first it is checked if the
1724 * current node's message fits with the MTU. If it does not, we
1725 * either calculate the next fragment (based on @e frag_off) from the
1726 * current node, or, if all fragments have already been created,
1727 * descend to the @e head_frag. Even though the node was already
1728 * fragmented, the fragment may be too big if the fragment was
1729 * generated for a queue with a larger MTU. In this case, the node
1730 * may be fragmented again, thus creating a tree.
1732 * When acknowledgements for fragments are received, the tree
1733 * must be pruned, removing those parts that were already
1734 * acknowledged. When fragments are sent over a reliable
1735 * channel, they can be immediately removed.
1737 * If a message is ever fragmented, then the original "full" message
1738 * is never again transmitted (even if it fits below the MTU), and
1739 * only (remaining) fragments are sent.
1741 struct PendingMessage
1744 * Kept in a MDLL of messages for this @a target.
1746 struct PendingMessage *next_neighbour;
1749 * Kept in a MDLL of messages for this @a target.
1751 struct PendingMessage *prev_neighbour;
1754 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1756 struct PendingMessage *next_client;
1759 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1761 struct PendingMessage *prev_client;
1764 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1765 * #PMT_FRAGMENT_BOx)
1767 struct PendingMessage *next_frag;
1770 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1771 * #PMT_FRAGMENT_BOX)
1773 struct PendingMessage *prev_frag;
1776 * Head of DLL of PAs for this pending message.
1778 struct PendingAcknowledgement *pa_head;
1781 * Tail of DLL of PAs for this pending message.
1783 struct PendingAcknowledgement *pa_tail;
1786 * This message, reliability boxed. Only possibly available if @e pmt is
1789 struct PendingMessage *bpm;
1792 * Target of the request.
1794 struct Neighbour *target;
1797 * Set to non-NULL value if this message is currently being given to a
1798 * communicator and we are awaiting that communicator's acknowledgement.
1799 * Note that we must not retransmit a pending message while we're still
1800 * in the process of giving it to a communicator. If a pending message
1801 * is free'd while this entry is non-NULL, the @e qe reference to us
1802 * should simply be set to NULL.
1804 struct QueueEntry *qe;
1807 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1809 struct TransportClient *client;
1812 * Head of a MDLL of fragments created for this core message.
1814 struct PendingMessage *head_frag;
1817 * Tail of a MDLL of fragments created for this core message.
1819 struct PendingMessage *tail_frag;
1822 * Our parent in the fragmentation tree.
1824 struct PendingMessage *frag_parent;
1827 * At what time should we give up on the transmission (and no longer retry)?
1829 struct GNUNET_TIME_Absolute timeout;
1832 * What is the earliest time for us to retry transmission of this message?
1834 struct GNUNET_TIME_Absolute next_attempt;
1837 * UUID to use for this message (used for reassembly of fragments, only
1838 * initialized if @e msg_uuid_set is #GNUNET_YES).
1840 struct MessageUUIDP msg_uuid;
1843 * Type of the pending message.
1845 enum PendingMessageType pmt;
1848 * Size of the original message.
1853 * Offset at which we should generate the next fragment.
1858 * #GNUNET_YES once @e msg_uuid was initialized
1860 int16_t msg_uuid_set;
1862 /* Followed by @e bytes_msg to transmit */
1867 * Acknowledgement payload.
1869 struct TransportCummulativeAckPayload
1872 * When did we receive the message we are ACKing? Used to calculate
1873 * the delay we introduced by cummulating ACKs.
1875 struct GNUNET_TIME_Absolute receive_time;
1878 * UUID of a message being acknowledged.
1880 struct AcknowledgementUUIDP ack_uuid;
1885 * Data structure in which we track acknowledgements still to
1888 struct AcknowledgementCummulator
1891 * Target peer for which we are accumulating ACKs here.
1893 struct GNUNET_PeerIdentity target;
1896 * ACK data being accumulated. Only @e num_acks slots are valid.
1898 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
1901 * Task scheduled either to transmit the cummulative ACK message,
1902 * or to clean up this data structure after extended periods of
1903 * inactivity (if @e num_acks is zero).
1905 struct GNUNET_SCHEDULER_Task *task;
1908 * When is @e task run (only used if @e num_acks is non-zero)?
1910 struct GNUNET_TIME_Absolute min_transmission_time;
1913 * Counter to produce the `ack_counter` in the `struct
1914 * TransportReliabilityAckMessage`. Allows the receiver to detect
1915 * lost ACK messages. Incremented by @e num_acks upon transmission.
1917 uint32_t ack_counter;
1920 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
1922 unsigned int num_acks;
1927 * One of the addresses of this peer.
1929 struct AddressListEntry
1935 struct AddressListEntry *next;
1940 struct AddressListEntry *prev;
1943 * Which communicator provides this address?
1945 struct TransportClient *tc;
1948 * The actual address.
1950 const char *address;
1953 * Current context for storing this address in the peerstore.
1955 struct GNUNET_PEERSTORE_StoreContext *sc;
1958 * Task to periodically do @e st operation.
1960 struct GNUNET_SCHEDULER_Task *st;
1963 * What is a typical lifetime the communicator expects this
1964 * address to have? (Always from now.)
1966 struct GNUNET_TIME_Relative expiration;
1969 * Address identifier used by the communicator.
1974 * Network type offered by this address.
1976 enum GNUNET_NetworkType nt;
1981 * Client connected to the transport service.
1983 struct TransportClient
1989 struct TransportClient *next;
1994 struct TransportClient *prev;
1997 * Handle to the client.
1999 struct GNUNET_SERVICE_Client *client;
2002 * Message queue to the client.
2004 struct GNUNET_MQ_Handle *mq;
2007 * What type of client is this?
2009 enum ClientType type;
2015 * Information for @e type #CT_CORE.
2021 * Head of list of messages pending for this client, sorted by
2022 * transmission time ("next_attempt" + possibly internal prioritization).
2024 struct PendingMessage *pending_msg_head;
2027 * Tail of list of messages pending for this client.
2029 struct PendingMessage *pending_msg_tail;
2034 * Information for @e type #CT_MONITOR.
2040 * Peer identity to monitor the addresses of.
2041 * Zero to monitor all neighbours. Valid if
2042 * @e type is #CT_MONITOR.
2044 struct GNUNET_PeerIdentity peer;
2047 * Is this a one-shot monitor?
2055 * Information for @e type #CT_COMMUNICATOR.
2060 * If @e type is #CT_COMMUNICATOR, this communicator
2061 * supports communicating using these addresses.
2063 char *address_prefix;
2066 * Head of DLL of queues offered by this communicator.
2068 struct Queue *queue_head;
2071 * Tail of DLL of queues offered by this communicator.
2073 struct Queue *queue_tail;
2076 * Head of list of the addresses of this peer offered by this
2079 struct AddressListEntry *addr_head;
2082 * Tail of list of the addresses of this peer offered by this
2085 struct AddressListEntry *addr_tail;
2088 * Number of queue entries in all queues to this communicator. Used
2089 * throttle sending to a communicator if we see that the communicator
2090 * is globally unable to keep up.
2092 unsigned int total_queue_length;
2095 * Characteristics of this communicator.
2097 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2102 * Information for @e type #CT_APPLICATION
2108 * Map of requests for peers the given client application would like to
2109 * see connections for. Maps from PIDs to `struct PeerRequest`.
2111 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2120 * State we keep for validation activities. Each of these
2121 * is both in the #validation_heap and the #validation_map.
2123 struct ValidationState
2127 * For which peer is @a address to be validated (or possibly valid)?
2128 * Serves as key in the #validation_map.
2130 struct GNUNET_PeerIdentity pid;
2133 * How long did the peer claim this @e address to be valid? Capped at
2134 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2135 * were told about the address and the value claimed by the other peer at
2136 * that time. May be updated similarly when validation succeeds.
2138 struct GNUNET_TIME_Absolute valid_until;
2141 * How long do *we* consider this @e address to be valid?
2142 * In the past or zero if we have not yet validated it.
2144 struct GNUNET_TIME_Absolute validated_until;
2147 * When did we FIRST use the current @e challenge in a message?
2148 * Used to sanity-check @code{origin_time} in the response when
2149 * calculating the RTT. If the @code{origin_time} is not in
2150 * the expected range, the response is discarded as malicious.
2152 struct GNUNET_TIME_Absolute first_challenge_use;
2155 * When did we LAST use the current @e challenge in a message?
2156 * Used to sanity-check @code{origin_time} in the response when
2157 * calculating the RTT. If the @code{origin_time} is not in
2158 * the expected range, the response is discarded as malicious.
2160 struct GNUNET_TIME_Absolute last_challenge_use;
2163 * Next time we will send the @e challenge to the peer, if this time is past
2164 * @e valid_until, this validation state is released at this time. If the
2165 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2166 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2167 * to re-validate before the validity actually expires.
2169 struct GNUNET_TIME_Absolute next_challenge;
2172 * Current backoff factor we're applying for sending the @a challenge.
2173 * Reset to 0 if the @a challenge is confirmed upon validation.
2174 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2175 * existing value if we receive an unvalidated address again over
2176 * another channel (and thus should consider the information "fresh").
2177 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2179 struct GNUNET_TIME_Relative challenge_backoff;
2182 * Initially set to "forever". Once @e validated_until is set, this value is
2183 * set to the RTT that tells us how long it took to receive the validation.
2185 struct GNUNET_TIME_Relative validation_rtt;
2188 * The challenge we sent to the peer to get it to validate the address. Note
2189 * that we rotate the challenge whenever we update @e validated_until to
2190 * avoid attacks where a peer simply replays an old challenge in the future.
2191 * (We must not rotate more often as otherwise we may discard valid answers
2192 * due to packet losses, latency and reorderings on the network).
2194 struct ChallengeNonceP challenge;
2197 * Claimed address of the peer.
2202 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2203 * heap is used to figure out when the next validation activity should be
2206 struct GNUNET_CONTAINER_HeapNode *hn;
2209 * Handle to a PEERSTORE store operation for this @e address. NULL if
2210 * no PEERSTORE operation is pending.
2212 struct GNUNET_PEERSTORE_StoreContext *sc;
2215 * We are technically ready to send the challenge, but we are waiting for
2216 * the respective queue to become available for transmission.
2223 * A Backtalker is a peer sending us backchannel messages. We use this
2224 * struct to detect monotonic time violations, cache ephemeral key
2225 * material (to avoid repeatedly checking signatures), and to synchronize
2226 * monotonic time with the PEERSTORE.
2231 * Peer this is about.
2233 struct GNUNET_PeerIdentity pid;
2236 * Last (valid) monotonic time received from this sender.
2238 struct GNUNET_TIME_Absolute monotonic_time;
2241 * When will this entry time out?
2243 struct GNUNET_TIME_Absolute timeout;
2246 * Last (valid) ephemeral key received from this sender.
2248 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2251 * Task associated with this backtalker. Can be for timeout,
2252 * or other asynchronous operations.
2254 struct GNUNET_SCHEDULER_Task *task;
2257 * Communicator context waiting on this backchannel's @e get, or NULL.
2259 struct CommunicatorMessageContext *cmc;
2262 * Handle for an operation to fetch @e monotonic_time information from the
2263 * PEERSTORE, or NULL.
2265 struct GNUNET_PEERSTORE_IterateContext *get;
2268 * Handle to a PEERSTORE store operation for this @e pid's @e
2269 * monotonic_time. NULL if no PEERSTORE operation is pending.
2271 struct GNUNET_PEERSTORE_StoreContext *sc;
2274 * Number of bytes of the original message body that follows after this
2282 * Head of linked list of all clients to this service.
2284 static struct TransportClient *clients_head;
2287 * Tail of linked list of all clients to this service.
2289 static struct TransportClient *clients_tail;
2292 * Statistics handle.
2294 static struct GNUNET_STATISTICS_Handle *GST_stats;
2297 * Configuration handle.
2299 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2304 static struct GNUNET_PeerIdentity GST_my_identity;
2309 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2312 * Map from PIDs to `struct Neighbour` entries. A peer is
2313 * a neighbour if we have an MQ to it from some communicator.
2315 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2318 * Map from PIDs to `struct Backtalker` entries. A peer is
2319 * a backtalker if it recently send us backchannel messages.
2321 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2324 * Map from PIDs to `struct AcknowledgementCummulator`s.
2325 * Here we track the cummulative ACKs for transmission.
2327 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2330 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2331 * a `struct PendingAcknowledgement`.
2333 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2336 * Map from PIDs to `struct DistanceVector` entries describing
2337 * known paths to the peer.
2339 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2342 * Map from PIDs to `struct ValidationState` entries describing
2343 * addresses we are aware of and their validity state.
2345 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2348 * Map from challenges to `struct LearnLaunchEntry` values.
2350 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2353 * Head of a DLL sorted by launch time.
2355 static struct LearnLaunchEntry *lle_head;
2358 * Tail of a DLL sorted by launch time.
2360 static struct LearnLaunchEntry *lle_tail;
2363 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2364 * sorting addresses we are aware of by when we should next try to (re)validate
2367 static struct GNUNET_CONTAINER_Heap *validation_heap;
2370 * Database for peer's HELLOs.
2372 static struct GNUNET_PEERSTORE_Handle *peerstore;
2375 * Heap sorting `struct EphemeralCacheEntry` by their
2376 * key/signature validity.
2378 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2381 * Hash map for looking up `struct EphemeralCacheEntry`s
2382 * by peer identity. (We may have ephemerals in our
2383 * cache for which we do not have a neighbour entry,
2384 * and similar many neighbours may not need ephemerals,
2385 * so we use a second map.)
2387 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2390 * Task to free expired ephemerals.
2392 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2395 * Task run to initiate DV learning.
2397 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2400 * Task to run address validation.
2402 static struct GNUNET_SCHEDULER_Task *validation_task;
2405 * The most recent PA we have created, head of DLL.
2406 * The length of the DLL is kept in #pa_count.
2408 static struct PendingAcknowledgement *pa_head;
2411 * The oldest PA we have created, tail of DLL.
2412 * The length of the DLL is kept in #pa_count.
2414 static struct PendingAcknowledgement *pa_tail;
2417 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2418 * limit the size of the data structure.
2420 static unsigned int pa_count;
2424 * Get an offset into the transmission history buffer for `struct
2425 * PerformanceData`. Note that the caller must perform the required
2426 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2429 * An 'age' lasts 15 minute slots.
2431 * @return current age of the world
2436 struct GNUNET_TIME_Absolute now;
2438 now = GNUNET_TIME_absolute_get ();
2439 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2444 * Release @a pa data structure.
2446 * @param pa data structure to release
2449 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2451 struct Queue *q = pa->queue;
2452 struct PendingMessage *pm = pa->pm;
2453 struct DistanceVectorHop *dvh = pa->dvh;
2455 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2459 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2464 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2469 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2472 GNUNET_assert (GNUNET_YES ==
2473 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2474 &pa->ack_uuid.value,
2481 * Free cached ephemeral key.
2483 * @param ece cached signature to free
2486 free_ephemeral (struct EphemeralCacheEntry *ece)
2488 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2489 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2495 * Free validation state.
2497 * @param vs validation state to free
2500 free_validation_state (struct ValidationState *vs)
2502 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2503 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2507 GNUNET_PEERSTORE_store_cancel (vs->sc);
2510 GNUNET_free (vs->address);
2516 * Lookup neighbour record for peer @a pid.
2518 * @param pid neighbour to look for
2519 * @return NULL if we do not have this peer as a neighbour
2521 static struct Neighbour *
2522 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2524 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2529 * Details about what to notify monitors about.
2534 * @deprecated To be discussed if we keep these...
2536 struct GNUNET_TIME_Absolute last_validation;
2537 struct GNUNET_TIME_Absolute valid_until;
2538 struct GNUNET_TIME_Absolute next_validation;
2541 * Current round-trip time estimate.
2543 struct GNUNET_TIME_Relative rtt;
2546 * Connection status.
2548 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2553 uint32_t num_msg_pending;
2558 uint32_t num_bytes_pending;
2563 * Free a @dvh. Callers MAY want to check if this was the last path to the
2564 * `target`, and if so call #free_dv_route to also free the associated DV
2565 * entry in #dv_routes (if not, the associated scheduler job should eventually
2568 * @param dvh hop to free
2571 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2573 struct Neighbour *n = dvh->next_hop;
2574 struct DistanceVector *dv = dvh->dv;
2575 struct PendingAcknowledgement *pa;
2577 while (NULL != (pa = dvh->pa_head))
2579 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2582 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2583 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2589 * Free entry in #dv_routes. First frees all hops to the target, and
2590 * if there are no entries left, frees @a dv as well.
2592 * @param dv route to free
2595 free_dv_route (struct DistanceVector *dv)
2597 struct DistanceVectorHop *dvh;
2599 while (NULL != (dvh = dv->dv_head))
2600 free_distance_vector_hop (dvh);
2601 if (NULL == dv->dv_head)
2605 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2606 if (NULL != dv->visibility_task)
2607 GNUNET_SCHEDULER_cancel (dv->visibility_task);
2608 if (NULL != dv->timeout_task)
2609 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2616 * Notify monitor @a tc about an event. That @a tc
2617 * cares about the event has already been checked.
2619 * Send @a tc information in @a me about a @a peer's status with
2620 * respect to some @a address to all monitors that care.
2622 * @param tc monitor to inform
2623 * @param peer peer the information is about
2624 * @param address address the information is about
2625 * @param nt network type associated with @a address
2626 * @param me detailed information to transmit
2629 notify_monitor (struct TransportClient *tc,
2630 const struct GNUNET_PeerIdentity *peer,
2631 const char *address,
2632 enum GNUNET_NetworkType nt,
2633 const struct MonitorEvent *me)
2635 struct GNUNET_MQ_Envelope *env;
2636 struct GNUNET_TRANSPORT_MonitorData *md;
2637 size_t addr_len = strlen (address) + 1;
2639 env = GNUNET_MQ_msg_extra (md,
2641 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2642 md->nt = htonl ((uint32_t) nt);
2644 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2645 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2646 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2647 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2648 md->cs = htonl ((uint32_t) me->cs);
2649 md->num_msg_pending = htonl (me->num_msg_pending);
2650 md->num_bytes_pending = htonl (me->num_bytes_pending);
2651 memcpy (&md[1], address, addr_len);
2652 GNUNET_MQ_send (tc->mq, env);
2657 * Send information in @a me about a @a peer's status with respect
2658 * to some @a address to all monitors that care.
2660 * @param peer peer the information is about
2661 * @param address address the information is about
2662 * @param nt network type associated with @a address
2663 * @param me detailed information to transmit
2666 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2667 const char *address,
2668 enum GNUNET_NetworkType nt,
2669 const struct MonitorEvent *me)
2671 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2673 if (CT_MONITOR != tc->type)
2675 if (tc->details.monitor.one_shot)
2677 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2678 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2680 notify_monitor (tc, peer, address, nt, me);
2686 * Called whenever a client connects. Allocates our
2687 * data structures associated with that client.
2689 * @param cls closure, NULL
2690 * @param client identification of the client
2691 * @param mq message queue for the client
2692 * @return our `struct TransportClient`
2695 client_connect_cb (void *cls,
2696 struct GNUNET_SERVICE_Client *client,
2697 struct GNUNET_MQ_Handle *mq)
2699 struct TransportClient *tc;
2702 tc = GNUNET_new (struct TransportClient);
2703 tc->client = client;
2705 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2714 * @param rc data structure to free
2717 free_reassembly_context (struct ReassemblyContext *rc)
2719 struct Neighbour *n = rc->neighbour;
2721 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2722 GNUNET_assert (GNUNET_OK ==
2723 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2731 * Task run to clean up reassembly context of a neighbour that have expired.
2733 * @param cls a `struct Neighbour`
2736 reassembly_cleanup_task (void *cls)
2738 struct Neighbour *n = cls;
2739 struct ReassemblyContext *rc;
2741 n->reassembly_timeout_task = NULL;
2742 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2744 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2747 free_reassembly_context (rc);
2750 GNUNET_assert (NULL == n->reassembly_timeout_task);
2751 n->reassembly_timeout_task =
2752 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2753 &reassembly_cleanup_task,
2761 * function called to #free_reassembly_context().
2765 * @param value a `struct ReassemblyContext` to free
2766 * @return #GNUNET_OK (continue iteration)
2769 free_reassembly_cb (void *cls, uint32_t key, void *value)
2771 struct ReassemblyContext *rc = value;
2775 free_reassembly_context (rc);
2781 * Release memory used by @a neighbour.
2783 * @param neighbour neighbour entry to free
2786 free_neighbour (struct Neighbour *neighbour)
2788 struct DistanceVectorHop *dvh;
2790 GNUNET_assert (NULL == neighbour->queue_head);
2791 GNUNET_assert (GNUNET_YES ==
2792 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2795 if (NULL != neighbour->timeout_task)
2796 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2797 if (NULL != neighbour->reassembly_map)
2799 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2800 &free_reassembly_cb,
2802 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2803 neighbour->reassembly_map = NULL;
2804 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2805 neighbour->reassembly_heap = NULL;
2807 while (NULL != (dvh = neighbour->dv_head))
2809 struct DistanceVector *dv = dvh->dv;
2811 free_distance_vector_hop (dvh);
2812 if (NULL == dv->dv_head)
2815 if (NULL != neighbour->reassembly_timeout_task)
2816 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2817 GNUNET_free (neighbour);
2822 * Send message to CORE clients that we lost a connection.
2824 * @param tc client to inform (must be CORE client)
2825 * @param pid peer the connection is for
2826 * @param quota_out current quota for the peer
2829 core_send_connect_info (struct TransportClient *tc,
2830 const struct GNUNET_PeerIdentity *pid,
2831 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2833 struct GNUNET_MQ_Envelope *env;
2834 struct ConnectInfoMessage *cim;
2836 GNUNET_assert (CT_CORE == tc->type);
2837 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2838 cim->quota_out = quota_out;
2840 GNUNET_MQ_send (tc->mq, env);
2845 * Send message to CORE clients that we gained a connection
2847 * @param pid peer the queue was for
2848 * @param quota_out current quota for the peer
2851 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2852 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2854 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2856 if (CT_CORE != tc->type)
2858 core_send_connect_info (tc, pid, quota_out);
2864 * Send message to CORE clients that we lost a connection.
2866 * @param pid peer the connection was for
2869 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2871 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2873 struct GNUNET_MQ_Envelope *env;
2874 struct DisconnectInfoMessage *dim;
2876 if (CT_CORE != tc->type)
2878 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2880 GNUNET_MQ_send (tc->mq, env);
2886 * We believe we are ready to transmit a message on a queue. Double-checks
2887 * with the queue's "tracker_out" and then gives the message to the
2888 * communicator for transmission (updating the tracker, and re-scheduling
2889 * itself if applicable).
2891 * @param cls the `struct Queue` to process transmissions for
2894 transmit_on_queue (void *cls);
2898 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2899 * we should run immediately or if the message queue is empty.
2900 * Test for no task being added AND queue not being empty to
2901 * transmit immediately afterwards! This function must only
2902 * be called if the message queue is non-empty!
2904 * @param queue the queue to do scheduling for
2905 * @param inside_job set to #GNUNET_YES if called from
2906 * #transmit_on_queue() itself and NOT setting
2907 * the task means running immediately
2910 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
2912 struct Neighbour *n = queue->neighbour;
2913 struct PendingMessage *pm = n->pending_msg_head;
2914 struct GNUNET_TIME_Relative out_delay;
2917 GNUNET_assert (NULL != pm);
2918 if (queue->tc->details.communicator.total_queue_length >=
2919 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2921 GNUNET_STATISTICS_update (
2923 "# Transmission throttled due to communicator queue limit",
2928 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2930 GNUNET_STATISTICS_update (GST_stats,
2931 "# Transmission throttled due to queue queue limit",
2937 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
2939 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
2940 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
2943 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
2944 return; /* we should run immediately! */
2945 /* queue has changed since we were scheduled, reschedule again */
2946 queue->transmit_task =
2947 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
2948 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2949 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2950 "Next transmission on queue `%s' in %s (high delay)\n",
2952 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2955 "Next transmission on queue `%s' in %s\n",
2957 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2962 * Check whether the CORE visibility of @a n changed. If so,
2963 * check whether we need to notify CORE.
2965 * @param n neighbour to perform the check for
2968 update_neighbour_core_visibility (struct Neighbour *n);
2974 * @param queue the queue to free
2977 free_queue (struct Queue *queue)
2979 struct Neighbour *neighbour = queue->neighbour;
2980 struct TransportClient *tc = queue->tc;
2981 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
2982 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
2983 struct QueueEntry *qe;
2985 struct PendingAcknowledgement *pa;
2987 if (NULL != queue->transmit_task)
2989 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2990 queue->transmit_task = NULL;
2992 if (NULL != queue->visibility_task)
2994 GNUNET_SCHEDULER_cancel (queue->visibility_task);
2995 queue->visibility_task = NULL;
2997 while (NULL != (pa = queue->pa_head))
2999 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3003 GNUNET_CONTAINER_MDLL_remove (neighbour,
3004 neighbour->queue_head,
3005 neighbour->queue_tail,
3007 GNUNET_CONTAINER_MDLL_remove (client,
3008 tc->details.communicator.queue_head,
3009 tc->details.communicator.queue_tail,
3011 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3012 tc->details.communicator.total_queue_length);
3013 while (NULL != (qe = queue->queue_head))
3015 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3016 queue->queue_length--;
3017 tc->details.communicator.total_queue_length--;
3020 GNUNET_assert (qe == qe->pm->qe);
3025 GNUNET_assert (0 == queue->queue_length);
3026 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3027 tc->details.communicator.total_queue_length))
3029 /* Communicator dropped below threshold, resume all queues */
3030 GNUNET_STATISTICS_update (
3032 "# Transmission throttled due to communicator queue limit",
3035 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3037 schedule_transmit_on_queue (s, GNUNET_NO);
3039 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3040 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
3041 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
3042 GNUNET_free (queue);
3044 update_neighbour_core_visibility (neighbour);
3045 cores_send_disconnect_info (&neighbour->pid);
3047 if (NULL == neighbour->queue_head)
3049 free_neighbour (neighbour);
3057 * @param ale address list entry to free
3060 free_address_list_entry (struct AddressListEntry *ale)
3062 struct TransportClient *tc = ale->tc;
3064 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3065 tc->details.communicator.addr_tail,
3067 if (NULL != ale->sc)
3069 GNUNET_PEERSTORE_store_cancel (ale->sc);
3072 if (NULL != ale->st)
3074 GNUNET_SCHEDULER_cancel (ale->st);
3082 * Stop the peer request in @a value.
3084 * @param cls a `struct TransportClient` that no longer makes the request
3085 * @param pid the peer's identity
3086 * @param value a `struct PeerRequest`
3087 * @return #GNUNET_YES (always)
3090 stop_peer_request (void *cls,
3091 const struct GNUNET_PeerIdentity *pid,
3094 struct TransportClient *tc = cls;
3095 struct PeerRequest *pr = value;
3097 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3100 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3110 * Called whenever a client is disconnected. Frees our
3111 * resources associated with that client.
3113 * @param cls closure, NULL
3114 * @param client identification of the client
3115 * @param app_ctx our `struct TransportClient`
3118 client_disconnect_cb (void *cls,
3119 struct GNUNET_SERVICE_Client *client,
3122 struct TransportClient *tc = app_ctx;
3125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3126 "Client %p disconnected, cleaning up.\n",
3128 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3134 struct PendingMessage *pm;
3136 while (NULL != (pm = tc->details.core.pending_msg_head))
3138 GNUNET_CONTAINER_MDLL_remove (client,
3139 tc->details.core.pending_msg_head,
3140 tc->details.core.pending_msg_tail,
3148 case CT_COMMUNICATOR: {
3150 struct AddressListEntry *ale;
3152 while (NULL != (q = tc->details.communicator.queue_head))
3154 while (NULL != (ale = tc->details.communicator.addr_head))
3155 free_address_list_entry (ale);
3156 GNUNET_free (tc->details.communicator.address_prefix);
3159 case CT_APPLICATION:
3160 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3163 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3171 * Iterator telling new CORE client about all existing
3172 * connections to peers.
3174 * @param cls the new `struct TransportClient`
3175 * @param pid a connected peer
3176 * @param value the `struct Neighbour` with more information
3177 * @return #GNUNET_OK (continue to iterate)
3180 notify_client_connect_info (void *cls,
3181 const struct GNUNET_PeerIdentity *pid,
3184 struct TransportClient *tc = cls;
3185 struct Neighbour *neighbour = value;
3187 core_send_connect_info (tc, pid, neighbour->quota_out);
3193 * Initialize a "CORE" client. We got a start message from this
3194 * client, so add it to the list of clients for broadcasting of
3197 * @param cls the client
3198 * @param start the start message that was sent
3201 handle_client_start (void *cls, const struct StartMessage *start)
3203 struct TransportClient *tc = cls;
3206 options = ntohl (start->options);
3207 if ((0 != (1 & options)) &&
3208 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3210 /* client thinks this is a different peer, reject */
3212 GNUNET_SERVICE_client_drop (tc->client);
3215 if (CT_NONE != tc->type)
3218 GNUNET_SERVICE_client_drop (tc->client);
3222 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3223 ¬ify_client_connect_info,
3225 GNUNET_SERVICE_client_continue (tc->client);
3230 * Client asked for transmission to a peer. Process the request.
3232 * @param cls the client
3233 * @param obm the send message that was sent
3236 check_client_send (void *cls, const struct OutboundMessage *obm)
3238 struct TransportClient *tc = cls;
3240 const struct GNUNET_MessageHeader *obmm;
3242 if (CT_CORE != tc->type)
3245 return GNUNET_SYSERR;
3247 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3248 if (size < sizeof (struct GNUNET_MessageHeader))
3251 return GNUNET_SYSERR;
3253 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3254 if (size != ntohs (obmm->size))
3257 return GNUNET_SYSERR;
3264 * Free fragment tree below @e root, excluding @e root itself.
3265 * FIXME: this does NOT seem to have the intended semantics
3266 * based on how this is called. Seems we generally DO expect
3267 * @a root to be free'ed itself as well!
3269 * @param root root of the tree to free
3272 free_fragment_tree (struct PendingMessage *root)
3274 struct PendingMessage *frag;
3276 while (NULL != (frag = root->head_frag))
3278 struct PendingAcknowledgement *pa;
3280 free_fragment_tree (frag);
3281 while (NULL != (pa = frag->pa_head))
3283 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3286 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3293 * Release memory associated with @a pm and remove @a pm from associated
3294 * data structures. @a pm must be a top-level pending message and not
3295 * a fragment in the tree. The entire tree is freed (if applicable).
3297 * @param pm the pending message to free
3300 free_pending_message (struct PendingMessage *pm)
3302 struct TransportClient *tc = pm->client;
3303 struct Neighbour *target = pm->target;
3304 struct PendingAcknowledgement *pa;
3308 GNUNET_CONTAINER_MDLL_remove (client,
3309 tc->details.core.pending_msg_head,
3310 tc->details.core.pending_msg_tail,
3313 GNUNET_CONTAINER_MDLL_remove (neighbour,
3314 target->pending_msg_head,
3315 target->pending_msg_tail,
3317 while (NULL != (pa = pm->pa_head))
3319 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3323 free_fragment_tree (pm);
3326 GNUNET_assert (pm == pm->qe->pm);
3329 GNUNET_free_non_null (pm->bpm);
3335 * Send a response to the @a pm that we have processed a
3336 * "send" request with status @a success. We
3337 * transmitted @a bytes_physical on the actual wire.
3338 * Sends a confirmation to the "core" client responsible
3339 * for the original request and free's @a pm.
3341 * @param pm handle to the original pending message
3342 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
3343 * for transmission failure
3344 * @param bytes_physical amount of bandwidth consumed
3347 client_send_response (struct PendingMessage *pm,
3349 uint32_t bytes_physical)
3351 struct TransportClient *tc = pm->client;
3352 struct Neighbour *target = pm->target;
3353 struct GNUNET_MQ_Envelope *env;
3354 struct SendOkMessage *som;
3358 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3359 som->success = htonl ((uint32_t) success);
3360 som->bytes_msg = htons (pm->bytes_msg);
3361 som->bytes_physical = htonl (bytes_physical);
3362 som->peer = target->pid;
3363 GNUNET_MQ_send (tc->mq, env);
3365 free_pending_message (pm);
3370 * Checks the message queue for a neighbour for messages that have timed
3371 * out and purges them.
3373 * @param cls a `struct Neighbour`
3376 check_queue_timeouts (void *cls)
3378 struct Neighbour *n = cls;
3379 struct PendingMessage *pm;
3380 struct GNUNET_TIME_Absolute now;
3381 struct GNUNET_TIME_Absolute earliest_timeout;
3383 n->timeout_task = NULL;
3384 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
3385 now = GNUNET_TIME_absolute_get ();
3386 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
3388 pm = pos->next_neighbour;
3389 if (pos->timeout.abs_value_us <= now.abs_value_us)
3391 GNUNET_STATISTICS_update (GST_stats,
3392 "# messages dropped (timeout before confirmation)",
3395 client_send_response (pm, GNUNET_NO, 0);
3399 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
3401 n->earliest_timeout = earliest_timeout;
3402 if (NULL != n->pending_msg_head)
3404 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
3409 * Client asked for transmission to a peer. Process the request.
3411 * @param cls the client
3412 * @param obm the send message that was sent
3415 handle_client_send (void *cls, const struct OutboundMessage *obm)
3417 struct TransportClient *tc = cls;
3418 struct PendingMessage *pm;
3419 const struct GNUNET_MessageHeader *obmm;
3420 struct Neighbour *target;
3424 GNUNET_assert (CT_CORE == tc->type);
3425 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3426 bytes_msg = ntohs (obmm->size);
3427 target = lookup_neighbour (&obm->peer);
3430 /* Failure: don't have this peer as a neighbour (anymore).
3431 Might have gone down asynchronously, so this is NOT
3432 a protocol violation by CORE. Still count the event,
3433 as this should be rare. */
3434 struct GNUNET_MQ_Envelope *env;
3435 struct SendOkMessage *som;
3437 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3438 som->success = htonl (GNUNET_SYSERR);
3439 som->bytes_msg = htonl (bytes_msg);
3440 som->bytes_physical = htonl (0);
3441 som->peer = obm->peer;
3442 GNUNET_MQ_send (tc->mq, env);
3443 GNUNET_SERVICE_client_continue (tc->client);
3444 GNUNET_STATISTICS_update (GST_stats,
3445 "# messages dropped (neighbour unknown)",
3450 was_empty = (NULL == target->pending_msg_head);
3451 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
3453 pm->target = target;
3454 pm->bytes_msg = bytes_msg;
3456 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
3457 memcpy (&pm[1], &obm[1], bytes_msg);
3458 GNUNET_CONTAINER_MDLL_insert (neighbour,
3459 target->pending_msg_head,
3460 target->pending_msg_tail,
3462 GNUNET_CONTAINER_MDLL_insert (client,
3463 tc->details.core.pending_msg_head,
3464 tc->details.core.pending_msg_tail,
3466 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3468 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3469 if (NULL != target->timeout_task)
3470 GNUNET_SCHEDULER_cancel (target->timeout_task);
3471 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3472 &check_queue_timeouts,
3476 return; /* all queues must already be busy */
3477 for (struct Queue *queue = target->queue_head; NULL != queue;
3478 queue = queue->next_neighbour)
3480 /* try transmission on any queue that is idle */
3481 if (NULL == queue->transmit_task)
3482 queue->transmit_task =
3483 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3489 * Communicator started. Test message is well-formed.
3491 * @param cls the client
3492 * @param cam the send message that was sent
3495 check_communicator_available (
3497 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3499 struct TransportClient *tc = cls;
3502 if (CT_NONE != tc->type)
3505 return GNUNET_SYSERR;
3507 tc->type = CT_COMMUNICATOR;
3508 size = ntohs (cam->header.size) - sizeof (*cam);
3510 return GNUNET_OK; /* receive-only communicator */
3511 GNUNET_MQ_check_zero_termination (cam);
3517 * Communicator started. Process the request.
3519 * @param cls the client
3520 * @param cam the send message that was sent
3523 handle_communicator_available (
3525 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3527 struct TransportClient *tc = cls;
3530 size = ntohs (cam->header.size) - sizeof (*cam);
3532 return; /* receive-only communicator */
3533 tc->details.communicator.address_prefix =
3534 GNUNET_strdup ((const char *) &cam[1]);
3535 tc->details.communicator.cc =
3536 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3537 GNUNET_SERVICE_client_continue (tc->client);
3542 * Communicator requests backchannel transmission. Check the request.
3544 * @param cls the client
3545 * @param cb the send message that was sent
3546 * @return #GNUNET_OK if message is well-formed
3549 check_communicator_backchannel (
3551 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3553 const struct GNUNET_MessageHeader *inbox;
3559 msize = ntohs (cb->header.size) - sizeof (*cb);
3560 if (UINT16_MAX - msize >
3561 sizeof (struct TransportBackchannelEncapsulationMessage) +
3562 sizeof (struct TransportBackchannelRequestPayloadP))
3565 return GNUNET_SYSERR;
3567 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3568 isize = ntohs (inbox->size);
3572 return GNUNET_SYSERR;
3574 is = (const char *) inbox;
3577 GNUNET_assert (msize > 0);
3578 if ('\0' != is[msize - 1])
3581 return GNUNET_SYSERR;
3588 * Remove memory used by expired ephemeral keys.
3593 expire_ephemerals (void *cls)
3595 struct EphemeralCacheEntry *ece;
3598 ephemeral_task = NULL;
3599 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3601 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3604 free_ephemeral (ece);
3607 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3616 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3617 * one, cache it and return it.
3619 * @param pid peer to look up ephemeral for
3620 * @param private_key[out] set to the private key
3621 * @param ephemeral_key[out] set to the key
3622 * @param ephemeral_sender_sig[out] set to the signature
3623 * @param ephemeral_validity[out] set to the validity expiration time
3626 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3627 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3628 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3629 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3630 struct GNUNET_TIME_Absolute *ephemeral_validity)
3632 struct EphemeralCacheEntry *ece;
3633 struct EphemeralConfirmationPS ec;
3635 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3636 if ((NULL != ece) &&
3637 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3640 free_ephemeral (ece);
3645 ece = GNUNET_new (struct EphemeralCacheEntry);
3647 ece->ephemeral_validity =
3648 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3649 EPHEMERAL_VALIDITY);
3650 GNUNET_assert (GNUNET_OK ==
3651 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3652 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3653 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3654 ec.purpose.size = htonl (sizeof (ec));
3656 ec.ephemeral_key = ece->ephemeral_key;
3657 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3661 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3663 ece->ephemeral_validity.abs_value_us);
3664 GNUNET_assert (GNUNET_OK ==
3665 GNUNET_CONTAINER_multipeermap_put (
3669 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3670 if (NULL == ephemeral_task)
3671 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3675 *private_key = ece->private_key;
3676 *ephemeral_key = ece->ephemeral_key;
3677 *ephemeral_sender_sig = ece->sender_sig;
3678 *ephemeral_validity = ece->ephemeral_validity;
3683 * Send the control message @a payload on @a queue.
3685 * @param queue the queue to use for transmission
3686 * @param pm pending message to update once transmission is done, may be NULL!
3687 * @param payload the payload to send (encapsulated in a
3688 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3689 * @param payload_size number of bytes in @a payload
3692 queue_send_msg (struct Queue *queue,
3693 struct PendingMessage *pm,
3694 const void *payload,
3695 size_t payload_size)
3697 struct Neighbour *n = queue->neighbour;
3698 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3699 struct GNUNET_MQ_Envelope *env;
3701 env = GNUNET_MQ_msg_extra (smt,
3703 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3704 smt->qid = queue->qid;
3705 smt->mid = queue->mid_gen;
3706 smt->receiver = n->pid;
3707 memcpy (&smt[1], payload, payload_size);
3709 /* Pass the env to the communicator of queue for transmission. */
3710 struct QueueEntry *qe;
3712 qe = GNUNET_new (struct QueueEntry);
3713 qe->mid = queue->mid_gen++;
3718 GNUNET_assert (NULL == pm->qe);
3721 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3722 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3723 queue->queue_length++;
3724 queue->tc->details.communicator.total_queue_length++;
3725 GNUNET_MQ_send (queue->tc->mq, env);
3731 * Which transmission options are allowable for transmission?
3732 * Interpreted bit-wise!
3734 enum RouteMessageOptions
3737 * Only confirmed, non-DV direct neighbours.
3742 * We are allowed to use DV routing for this @a hdr
3747 * We are allowed to use unconfirmed queues or DV routes for this message
3749 RMO_UNCONFIRMED_ALLOWED = 2,
3752 * Reliable and unreliable, DV and non-DV are all acceptable.
3754 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
3757 * If we have multiple choices, it is OK to send this message
3758 * over multiple channels at the same time to improve loss tolerance.
3759 * (We do at most 2 transmissions.)
3766 * Pick a queue of @a n under constraints @a options and schedule
3767 * transmission of @a hdr.
3769 * @param n neighbour to send to
3770 * @param hdr message to send as payload
3771 * @param options whether queues must be confirmed or not,
3772 * and whether we may pick multiple (2) queues
3775 route_via_neighbour (const struct Neighbour *n,
3776 const struct GNUNET_MessageHeader *hdr,
3777 enum RouteMessageOptions options)
3779 struct GNUNET_TIME_Absolute now;
3780 unsigned int candidates;
3784 /* Pick one or two 'random' queues from n (under constraints of options) */
3785 now = GNUNET_TIME_absolute_get ();
3786 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
3787 weight in the future; weight could be assigned by observed
3788 bandwidth (note: not sure if we should do this for this type
3789 of control traffic though). */
3791 for (struct Queue *pos = n->queue_head; NULL != pos;
3792 pos = pos->next_neighbour)
3794 /* Count the queue with the visibility task in all cases, as
3795 otherwise we may end up with no queues just because the
3796 time for the visibility task just expired but the scheduler
3797 just ran this task first */
3798 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
3799 (pos->validated_until.abs_value_us > now.abs_value_us) ||
3800 (NULL != pos->visibility_task))
3803 if (0 == candidates)
3805 /* Given that we above check for pos->visibility task,
3806 this should be strictly impossible. */
3810 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3811 if (0 == (options & RMO_REDUNDANT))
3812 sel2 = candidates; /* picks none! */
3814 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3816 for (struct Queue *pos = n->queue_head; NULL != pos;
3817 pos = pos->next_neighbour)
3819 /* Count the queue with the visibility task in all cases, as
3820 otherwise we may end up with no queues just because the
3821 time for the visibility task just expired but the scheduler
3822 just ran this task first */
3823 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
3824 (NULL != pos->visibility_task))
3826 if ((sel1 == candidates) || (sel2 == candidates))
3827 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
3835 * Given a distance vector path @a dvh route @a payload to
3836 * the ultimate destination respecting @a options.
3837 * Sets up the boxed message and queues it at the next hop.
3839 * @param dvh choice of the path for the message
3840 * @param payload body to transmit
3841 * @param options options to use for control
3844 forward_via_dvh (const struct DistanceVectorHop *dvh,
3845 const struct GNUNET_MessageHeader *payload,
3846 enum RouteMessageOptions options)
3848 uint16_t mlen = ntohs (payload->size);
3849 char boxram[sizeof (struct TransportDVBoxMessage) +
3850 (dvh->distance + 1) * sizeof (struct GNUNET_PeerIdentity) +
3852 struct TransportDVBoxMessage *box = (struct TransportDVBoxMessage *) boxram;
3853 struct GNUNET_PeerIdentity *path = (struct GNUNET_PeerIdentity *) &box[1];
3855 box->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3856 box->header.size = htons (sizeof (boxram));
3857 box->total_hops = htons (0);
3858 box->num_hops = htons (dvh->distance + 1);
3859 box->origin = GST_my_identity;
3860 memcpy (path, dvh->path, dvh->distance * sizeof (struct GNUNET_PeerIdentity));
3861 path[dvh->distance] = dvh->dv->target;
3862 memcpy (&path[dvh->distance + 1], payload, mlen);
3863 route_via_neighbour (dvh->next_hop, &box->header, options);
3868 * Pick a path of @a dv under constraints @a options and schedule
3869 * transmission of @a hdr.
3871 * @param n neighbour to send to
3872 * @param hdr message to send as payload
3873 * @param options whether path must be confirmed or not
3874 * and whether we may pick multiple (2) paths
3877 route_via_dv (const struct DistanceVector *dv,
3878 const struct GNUNET_MessageHeader *hdr,
3879 enum RouteMessageOptions options)
3881 struct DistanceVectorHop *h1;
3882 struct DistanceVectorHop *h2;
3887 /* Pick random vectors, but weighted by distance, giving more weight
3888 to shorter vectors */
3890 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3893 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3894 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3895 .rel_value_us == 0))
3896 continue; /* pos unconfirmed and confirmed required */
3897 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3904 choice1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3905 choice2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3909 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3912 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3914 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3915 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3916 .rel_value_us == 0))
3917 continue; /* pos unconfirmed and confirmed required */
3918 if ((num_dv <= choice1) && (num_dv + delta > choice1))
3920 if ((num_dv <= choice2) && (num_dv + delta > choice2))
3924 forward_via_dvh (h1, hdr, options & (~RMO_REDUNDANT));
3925 if (0 == (options & RMO_REDUNDANT))
3926 forward_via_dvh (h2, hdr, options & (~RMO_REDUNDANT));
3931 * We need to transmit @a hdr to @a target. If necessary, this may
3932 * involve DV routing.
3934 * @param target peer to receive @a hdr
3935 * @param hdr header of the message to route and #GNUNET_free()
3936 * @param options which transmission channels are allowed
3939 route_message (const struct GNUNET_PeerIdentity *target,
3940 struct GNUNET_MessageHeader *hdr,
3941 enum RouteMessageOptions options)
3943 struct Neighbour *n;
3944 struct DistanceVector *dv;
3946 n = GNUNET_CONTAINER_multipeermap_get (neighbours, target);
3947 dv = (0 != (options & RMO_DV_ALLOWED))
3948 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
3950 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
3952 /* if confirmed is required, and we do not have anything
3953 confirmed, drop respective options */
3954 if ((NULL != n) && (GNUNET_NO == n->core_visible))
3956 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
3959 if ((NULL == n) && (NULL == dv))
3961 GNUNET_STATISTICS_update (GST_stats,
3962 "# Messages dropped in routing: no acceptable method",
3968 /* If both dv and n are possible and we must choose:
3969 flip a coin for the choice between the two; for now 50/50 */
3970 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
3972 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
3977 if ((NULL != n) && (NULL != dv))
3978 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
3979 enough for redunancy, so clear the flag. */
3982 route_via_neighbour (n, hdr, options);
3986 route_via_dv (dv, hdr, options);
3993 * Structure of the key material used to encrypt backchannel messages.
3995 struct BackchannelKeyState
3998 * State of our block cipher.
4000 gcry_cipher_hd_t cipher;
4003 * Actual key material.
4009 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4011 struct GNUNET_CRYPTO_AuthKey hmac_key;
4014 * Symmetric key to use for encryption.
4016 char aes_key[256 / 8];
4019 * Counter value to use during setup.
4021 char aes_ctr[128 / 8];
4028 * Given the key material in @a km and the initialization vector
4029 * @a iv, setup the key material for the backchannel in @a key.
4031 * @param km raw master secret
4032 * @param iv initialization vector
4033 * @param key[out] symmetric cipher and HMAC state to generate
4036 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4037 const struct GNUNET_ShortHashCode *iv,
4038 struct BackchannelKeyState *key)
4040 /* must match #dh_key_derive_eph_pub */
4041 GNUNET_assert (GNUNET_YES ==
4042 GNUNET_CRYPTO_kdf (&key->material,
4043 sizeof (key->material),
4044 "transport-backchannel-key",
4045 strlen ("transport-backchannel-key"),
4050 gcry_cipher_open (&key->cipher,
4051 GCRY_CIPHER_AES256 /* low level: go for speed */,
4052 GCRY_CIPHER_MODE_CTR,
4054 gcry_cipher_setkey (key->cipher,
4055 &key->material.aes_key,
4056 sizeof (key->material.aes_key));
4057 gcry_cipher_setctr (key->cipher,
4058 &key->material.aes_ctr,
4059 sizeof (key->material.aes_ctr));
4064 * Derive backchannel encryption key material from @a priv_ephemeral
4065 * and @a target and @a iv.
4067 * @param priv_ephemeral ephemeral private key to use
4068 * @param target the target peer to encrypt to
4069 * @param iv unique IV to use
4070 * @param key[out] set to the key material
4073 dh_key_derive_eph_pid (
4074 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4075 const struct GNUNET_PeerIdentity *target,
4076 const struct GNUNET_ShortHashCode *iv,
4077 struct BackchannelKeyState *key)
4079 struct GNUNET_HashCode km;
4081 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4082 &target->public_key,
4084 bc_setup_key_state_from_km (&km, iv, key);
4089 * Derive backchannel encryption key material from #GST_my_private_key
4090 * and @a pub_ephemeral and @a iv.
4092 * @param priv_ephemeral ephemeral private key to use
4093 * @param target the target peer to encrypt to
4094 * @param iv unique IV to use
4095 * @param key[out] set to the key material
4098 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4099 const struct GNUNET_ShortHashCode *iv,
4100 struct BackchannelKeyState *key)
4102 struct GNUNET_HashCode km;
4104 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4107 bc_setup_key_state_from_km (&km, iv, key);
4112 * Do HMAC calculation for backchannel messages over @a data using key
4113 * material from @a key.
4115 * @param key key material (from DH)
4116 * @param hmac[out] set to the HMAC
4117 * @param data data to perform HMAC calculation over
4118 * @param data_size number of bytes in @a data
4121 bc_hmac (const struct BackchannelKeyState *key,
4122 struct GNUNET_HashCode *hmac,
4126 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4131 * Perform backchannel encryption using symmetric secret in @a key
4132 * to encrypt data from @a in to @a dst.
4134 * @param key[in,out] key material to use
4135 * @param dst where to write the result
4136 * @param in input data to encrypt (plaintext)
4137 * @param in_size number of bytes of input in @a in and available at @a dst
4140 bc_encrypt (struct BackchannelKeyState *key,
4146 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4151 * Perform backchannel encryption using symmetric secret in @a key
4152 * to encrypt data from @a in to @a dst.
4154 * @param key[in,out] key material to use
4155 * @param ciph cipher text to decrypt
4156 * @param out[out] output data to generate (plaintext)
4157 * @param out_size number of bytes of input in @a ciph and available in @a out
4160 bc_decrypt (struct BackchannelKeyState *key,
4166 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4171 * Clean up key material in @a key.
4173 * @param key key material to clean up (memory must not be free'd!)
4176 bc_key_clean (struct BackchannelKeyState *key)
4178 gcry_cipher_close (key->cipher);
4179 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4184 * Communicator requests backchannel transmission. Process the request.
4186 * @param cls the client
4187 * @param cb the send message that was sent
4190 handle_communicator_backchannel (
4192 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4194 struct TransportClient *tc = cls;
4195 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4196 struct GNUNET_TIME_Absolute ephemeral_validity;
4197 struct TransportBackchannelEncapsulationMessage *enc;
4198 struct TransportBackchannelRequestPayloadP ppay;
4199 struct BackchannelKeyState key;
4203 /* encapsulate and encrypt message */
4204 msize = ntohs (cb->header.size) - sizeof (*cb) +
4205 sizeof (struct TransportBackchannelRequestPayloadP);
4206 enc = GNUNET_malloc (sizeof (*enc) + msize);
4208 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4209 enc->header.size = htons (sizeof (*enc) + msize);
4210 enc->target = cb->pid;
4211 lookup_ephemeral (&cb->pid,
4213 &enc->ephemeral_key,
4215 &ephemeral_validity);
4216 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4219 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4220 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
4221 ppay.monotonic_time =
4222 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
4223 mpos = (char *) &enc[1];
4224 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4227 &mpos[sizeof (ppay)],
4228 ntohs (cb->header.size) - sizeof (*cb));
4232 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4233 bc_key_clean (&key);
4234 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4235 GNUNET_SERVICE_client_continue (tc->client);
4240 * Address of our peer added. Test message is well-formed.
4242 * @param cls the client
4243 * @param aam the send message that was sent
4244 * @return #GNUNET_OK if message is well-formed
4247 check_add_address (void *cls,
4248 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4250 struct TransportClient *tc = cls;
4252 if (CT_COMMUNICATOR != tc->type)
4255 return GNUNET_SYSERR;
4257 GNUNET_MQ_check_zero_termination (aam);
4263 * Ask peerstore to store our address.
4265 * @param cls an `struct AddressListEntry *`
4268 store_pi (void *cls);
4272 * Function called when peerstore is done storing our address.
4274 * @param cls a `struct AddressListEntry`
4275 * @param success #GNUNET_YES if peerstore was successful
4278 peerstore_store_own_cb (void *cls, int success)
4280 struct AddressListEntry *ale = cls;
4283 if (GNUNET_YES != success)
4284 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4285 "Failed to store our own address `%s' in peerstore!\n",
4287 /* refresh period is 1/4 of expiration time, that should be plenty
4288 without being excessive. */
4290 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4298 * Ask peerstore to store our address.
4300 * @param cls an `struct AddressListEntry *`
4303 store_pi (void *cls)
4305 struct AddressListEntry *ale = cls;
4308 struct GNUNET_TIME_Absolute expiration;
4311 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4312 GNUNET_HELLO_sign_address (ale->address,
4318 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4321 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4325 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4326 &peerstore_store_own_cb,
4329 if (NULL == ale->sc)
4331 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4332 "Failed to store our address `%s' with peerstore\n",
4335 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4341 * Address of our peer added. Process the request.
4343 * @param cls the client
4344 * @param aam the send message that was sent
4347 handle_add_address (void *cls,
4348 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4350 struct TransportClient *tc = cls;
4351 struct AddressListEntry *ale;
4354 slen = ntohs (aam->header.size) - sizeof (*aam);
4355 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4357 ale->address = (const char *) &ale[1];
4358 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4359 ale->aid = aam->aid;
4360 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4361 memcpy (&ale[1], &aam[1], slen);
4362 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4363 tc->details.communicator.addr_tail,
4365 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4366 GNUNET_SERVICE_client_continue (tc->client);
4371 * Address of our peer deleted. Process the request.
4373 * @param cls the client
4374 * @param dam the send message that was sent
4377 handle_del_address (void *cls,
4378 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4380 struct TransportClient *tc = cls;
4382 if (CT_COMMUNICATOR != tc->type)
4385 GNUNET_SERVICE_client_drop (tc->client);
4388 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4392 if (dam->aid != ale->aid)
4394 GNUNET_assert (ale->tc == tc);
4395 free_address_list_entry (ale);
4396 GNUNET_SERVICE_client_continue (tc->client);
4399 GNUNET_SERVICE_client_drop (tc->client);
4404 * Context from #handle_incoming_msg(). Closure for many
4405 * message handlers below.
4407 struct CommunicatorMessageContext
4410 * Which communicator provided us with the message.
4412 struct TransportClient *tc;
4415 * Additional information for flow control and about the sender.
4417 struct GNUNET_TRANSPORT_IncomingMessage im;
4420 * Number of hops the message has travelled (if DV-routed).
4421 * FIXME: make use of this in ACK handling!
4423 uint16_t total_hops;
4428 * Given an inbound message @a msg from a communicator @a cmc,
4429 * demultiplex it based on the type calling the right handler.
4431 * @param cmc context for demultiplexing
4432 * @param msg message to demultiplex
4435 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4436 const struct GNUNET_MessageHeader *msg);
4440 * Send ACK to communicator (if requested) and free @a cmc.
4442 * @param cmc context for which we are done handling the message
4445 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4447 if (0 != ntohl (cmc->im.fc_on))
4449 /* send ACK when done to communicator for flow control! */
4450 struct GNUNET_MQ_Envelope *env;
4451 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4453 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4454 ack->reserved = htonl (0);
4455 ack->fc_id = cmc->im.fc_id;
4456 ack->sender = cmc->im.sender;
4457 GNUNET_MQ_send (cmc->tc->mq, env);
4459 GNUNET_SERVICE_client_continue (cmc->tc->client);
4465 * Communicator gave us an unencapsulated message to pass as-is to
4466 * CORE. Process the request.
4468 * @param cls a `struct CommunicatorMessageContext` (must call
4469 * #finish_cmc_handling() when done)
4470 * @param mh the message that was received
4473 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4475 struct CommunicatorMessageContext *cmc = cls;
4476 uint16_t size = ntohs (mh->size);
4478 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4479 (size < sizeof (struct GNUNET_MessageHeader)))
4481 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4484 finish_cmc_handling (cmc);
4485 GNUNET_SERVICE_client_drop (client);
4488 /* Forward to all CORE clients */
4489 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4491 struct GNUNET_MQ_Envelope *env;
4492 struct InboundMessage *im;
4494 if (CT_CORE != tc->type)
4496 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4497 im->peer = cmc->im.sender;
4498 memcpy (&im[1], mh, size);
4499 GNUNET_MQ_send (tc->mq, env);
4501 /* FIXME: consider doing this _only_ once the message
4502 was drained from the CORE MQs to extend flow control to CORE!
4503 (basically, increment counter in cmc, decrement on MQ send continuation! */
4504 finish_cmc_handling (cmc);
4509 * Communicator gave us a fragment box. Check the message.
4511 * @param cls a `struct CommunicatorMessageContext`
4512 * @param fb the send message that was sent
4513 * @return #GNUNET_YES if message is well-formed
4516 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4518 uint16_t size = ntohs (fb->header.size);
4519 uint16_t bsize = size - sizeof (*fb);
4523 GNUNET_break_op (0);
4524 return GNUNET_SYSERR;
4526 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4528 GNUNET_break_op (0);
4529 return GNUNET_SYSERR;
4531 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4533 GNUNET_break_op (0);
4534 return GNUNET_SYSERR;
4541 * Clean up an idle cummulative acknowledgement data structure.
4543 * @param cls a `struct AcknowledgementCummulator *`
4546 destroy_ack_cummulator (void *cls)
4548 struct AcknowledgementCummulator *ac = cls;
4551 GNUNET_assert (0 == ac->num_acks);
4554 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4560 * Do the transmission of a cummulative acknowledgement now.
4562 * @param cls a `struct AcknowledgementCummulator *`
4565 transmit_cummulative_ack_cb (void *cls)
4567 struct AcknowledgementCummulator *ac = cls;
4568 struct TransportReliabilityAckMessage *ack;
4569 struct TransportCummulativeAckPayloadP *ap;
4572 GNUNET_assert (0 < ac->ack_counter);
4573 ack = GNUNET_malloc (sizeof (*ack) +
4575 sizeof (struct TransportCummulativeAckPayloadP));
4576 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4578 htons (sizeof (*ack) +
4579 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4580 ack->ack_counter = htonl (ac->ack_counter++);
4581 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4582 for (unsigned int i = 0; i < ac->ack_counter; i++)
4584 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4585 ap[i].ack_delay = GNUNET_TIME_relative_hton (
4586 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
4588 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
4590 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
4591 &destroy_ack_cummulator,
4597 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
4598 * transmission by at most @a ack_delay.
4600 * @param pid target peer
4601 * @param ack_uuid UUID to ack
4602 * @param max_delay how long can the ACK wait
4605 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
4606 const struct AcknowledgementUUIDP *ack_uuid,
4607 struct GNUNET_TIME_Absolute max_delay)
4609 struct AcknowledgementCummulator *ac;
4611 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
4614 ac = GNUNET_new (struct AcknowledgementCummulator);
4616 ac->min_transmission_time = max_delay;
4617 GNUNET_assert (GNUNET_YES ==
4618 GNUNET_CONTAINER_multipeermap_put (
4622 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4626 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
4628 /* must run immediately, ack buffer full! */
4629 GNUNET_SCHEDULER_cancel (ac->task);
4630 transmit_cummulative_ack_cb (ac);
4632 GNUNET_SCHEDULER_cancel (ac->task);
4633 ac->min_transmission_time =
4634 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
4636 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
4637 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
4638 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
4640 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
4641 &transmit_cummulative_ack_cb,
4647 * Closure for #find_by_message_uuid.
4649 struct FindByMessageUuidContext
4654 struct MessageUUIDP message_uuid;
4657 * Set to the reassembly context if found.
4659 struct ReassemblyContext *rc;
4664 * Iterator called to find a reassembly context by the message UUID in the
4667 * @param cls a `struct FindByMessageUuidContext`
4668 * @param key a key (unused)
4669 * @param value a `struct ReassemblyContext`
4670 * @return #GNUNET_YES if not found, #GNUNET_NO if found
4673 find_by_message_uuid (void *cls, uint32_t key, void *value)
4675 struct FindByMessageUuidContext *fc = cls;
4676 struct ReassemblyContext *rc = value;
4679 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
4689 * Communicator gave us a fragment. Process the request.
4691 * @param cls a `struct CommunicatorMessageContext` (must call
4692 * #finish_cmc_handling() when done)
4693 * @param fb the message that was received
4696 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4698 struct CommunicatorMessageContext *cmc = cls;
4699 struct Neighbour *n;
4700 struct ReassemblyContext *rc;
4701 const struct GNUNET_MessageHeader *msg;
4706 struct GNUNET_TIME_Relative cdelay;
4707 struct FindByMessageUuidContext fc;
4709 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4712 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4715 finish_cmc_handling (cmc);
4716 GNUNET_SERVICE_client_drop (client);
4719 if (NULL == n->reassembly_map)
4721 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
4722 n->reassembly_heap =
4723 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4724 n->reassembly_timeout_task =
4725 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4726 &reassembly_cleanup_task,
4729 msize = ntohs (fb->msg_size);
4730 fc.message_uuid = fb->msg_uuid;
4732 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
4734 &find_by_message_uuid,
4736 if (NULL == (rc = fc.rc))
4738 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4739 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4740 rc->msg_uuid = fb->msg_uuid;
4742 rc->msg_size = msize;
4743 rc->reassembly_timeout =
4744 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4745 rc->last_frag = GNUNET_TIME_absolute_get ();
4746 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4748 rc->reassembly_timeout.abs_value_us);
4749 GNUNET_assert (GNUNET_OK ==
4750 GNUNET_CONTAINER_multihashmap32_put (
4754 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
4755 target = (char *) &rc[1];
4756 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4757 rc->msg_missing = rc->msg_size;
4761 target = (char *) &rc[1];
4763 if (msize != rc->msg_size)
4766 finish_cmc_handling (cmc);
4771 fsize = ntohs (fb->header.size) - sizeof (*fb);
4775 finish_cmc_handling (cmc);
4778 frag_off = ntohs (fb->frag_off);
4779 memcpy (&target[frag_off], &fb[1], fsize);
4780 /* update bitfield and msg_missing */
4781 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4783 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4785 rc->bitfield[i / 8] |= (1 << (i % 8));
4790 /* Compute cummulative ACK */
4791 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4792 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
4793 if (0 == rc->msg_missing)
4794 cdelay = GNUNET_TIME_UNIT_ZERO;
4795 cummulative_ack (&cmc->im.sender,
4797 GNUNET_TIME_relative_to_absolute (cdelay));
4798 rc->last_frag = GNUNET_TIME_absolute_get ();
4799 /* is reassembly complete? */
4800 if (0 != rc->msg_missing)
4802 finish_cmc_handling (cmc);
4805 /* reassembly is complete, verify result */
4806 msg = (const struct GNUNET_MessageHeader *) &rc[1];
4807 if (ntohs (msg->size) != rc->msg_size)
4810 free_reassembly_context (rc);
4811 finish_cmc_handling (cmc);
4814 /* successful reassembly */
4815 demultiplex_with_cmc (cmc, msg);
4816 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
4817 en-route and we forget that we finished this reassembly immediately!
4818 -> keep around until timeout?
4819 -> shorten timeout based on ACK? */
4820 free_reassembly_context (rc);
4825 * Communicator gave us a reliability box. Check the message.
4827 * @param cls a `struct CommunicatorMessageContext`
4828 * @param rb the send message that was sent
4829 * @return #GNUNET_YES if message is well-formed
4832 check_reliability_box (void *cls,
4833 const struct TransportReliabilityBoxMessage *rb)
4835 GNUNET_MQ_check_boxed_message (rb);
4841 * Communicator gave us a reliability box. Process the request.
4843 * @param cls a `struct CommunicatorMessageContext` (must call
4844 * #finish_cmc_handling() when done)
4845 * @param rb the message that was received
4848 handle_reliability_box (void *cls,
4849 const struct TransportReliabilityBoxMessage *rb)
4851 struct CommunicatorMessageContext *cmc = cls;
4852 const struct GNUNET_MessageHeader *inbox =
4853 (const struct GNUNET_MessageHeader *) &rb[1];
4855 // FIXME: call cummulative_ack(), have ack_countdown influence max_delay!
4856 (void) (0 == ntohl (rb->ack_countdown));
4857 /* continue with inner message */
4858 demultiplex_with_cmc (cmc, inbox);
4863 * Check if we have advanced to another age since the last time. If
4864 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
4867 * @param pd[in,out] data to update
4868 * @param age current age
4871 update_pd_age (struct PerformanceData *pd, unsigned int age)
4875 if (age == pd->last_age)
4876 return; /* nothing to do */
4877 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
4878 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
4880 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
4882 the->bytes_sent = 0;
4883 the->bytes_received = 0;
4890 * Update @a pd based on the latest @a rtt and the number of bytes
4891 * that were confirmed to be successfully transmitted.
4893 * @param pd[in,out] data to update
4894 * @param rtt latest round-trip time
4895 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
4898 update_performance_data (struct PerformanceData *pd,
4899 struct GNUNET_TIME_Relative rtt,
4900 uint16_t bytes_transmitted_ok)
4902 uint64_t nval = rtt.rel_value_us;
4903 uint64_t oval = pd->aged_rtt.rel_value_us;
4904 unsigned int age = get_age ();
4905 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
4907 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
4910 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
4911 update_pd_age (pd, age);
4912 the->bytes_received += bytes_transmitted_ok;
4917 * We have successfully transmitted data via @a q, update metrics.
4919 * @param q queue to update
4920 * @param rtt round trip time observed
4921 * @param bytes_transmitted_ok number of bytes successfully transmitted
4924 update_queue_performance (struct Queue *q,
4925 struct GNUNET_TIME_Relative rtt,
4926 uint16_t bytes_transmitted_ok)
4928 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
4933 * We have successfully transmitted data via @a dvh, update metrics.
4935 * @param dvh distance vector path data to update
4936 * @param rtt round trip time observed
4937 * @param bytes_transmitted_ok number of bytes successfully transmitted
4940 update_dvh_performance (struct DistanceVectorHop *dvh,
4941 struct GNUNET_TIME_Relative rtt,
4942 uint16_t bytes_transmitted_ok)
4944 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
4949 * The @a pa was acknowledged, process the acknowledgement.
4951 * @param pa the pending acknowledgement that was satisfied
4952 * @param ack_delay artificial delay from cummulative acks created by the other
4956 handle_acknowledged (struct PendingAcknowledgement *pa,
4957 struct GNUNET_TIME_Relative ack_delay)
4959 struct PendingMessage *pm = pa->pm;
4960 struct GNUNET_TIME_Relative delay;
4962 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
4963 if (delay.rel_value_us > ack_delay.rel_value_us)
4964 delay = GNUNET_TIME_UNIT_ZERO;
4966 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
4967 if (NULL != pa->queue)
4968 update_queue_performance (pa->queue, delay, pa->message_size);
4969 if (NULL != pa->dvh)
4970 update_dvh_performance (pa->dvh, delay, pa->message_size);
4973 if (NULL != pm->frag_parent)
4975 pm = pm->frag_parent;
4976 free_fragment_tree (pa->pm);
4978 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
4980 struct PendingMessage *parent = pm->frag_parent;
4982 free_fragment_tree (pm);
4985 if (NULL != pm->head_frag)
4986 pm = NULL; /* we are done, otherwise free 'pm' below */
4989 free_pending_message (pm);
4990 free_pending_acknowledgement (pa);
4995 * Communicator gave us a reliability ack. Check it is well-formed.
4997 * @param cls a `struct CommunicatorMessageContext` (unused)
4998 * @param ra the message that was received
4999 * @return #GNUNET_Ok if @a ra is well-formed
5002 check_reliability_ack (void *cls,
5003 const struct TransportReliabilityAckMessage *ra)
5005 unsigned int n_acks;
5008 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5009 sizeof (struct TransportCummulativeAckPayloadP);
5012 GNUNET_break_op (0);
5013 return GNUNET_SYSERR;
5015 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5016 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5018 GNUNET_break_op (0);
5019 return GNUNET_SYSERR;
5026 * Communicator gave us a reliability ack. Process the request.
5028 * @param cls a `struct CommunicatorMessageContext` (must call
5029 * #finish_cmc_handling() when done)
5030 * @param ra the message that was received
5033 handle_reliability_ack (void *cls,
5034 const struct TransportReliabilityAckMessage *ra)
5036 struct CommunicatorMessageContext *cmc = cls;
5037 const struct TransportCummulativeAckPayloadP *ack;
5038 struct PendingAcknowledgement *pa;
5039 unsigned int n_acks;
5040 uint32_t ack_counter;
5042 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5043 sizeof (struct TransportCummulativeAckPayloadP);
5044 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5045 for (unsigned int i = 0; i < n_acks; i++)
5048 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5051 GNUNET_STATISTICS_update (
5053 "# FRAGMENT_ACKS dropped, no matching pending message",
5058 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5061 ack_counter = htonl (ra->ack_counter);
5062 // FIXME: track ACK losses based on ack_counter somewhere!
5063 // (DV and/or Neighbour?)
5064 finish_cmc_handling (cmc);
5069 * Communicator gave us a backchannel encapsulation. Check the message.
5071 * @param cls a `struct CommunicatorMessageContext`
5072 * @param be the send message that was sent
5073 * @return #GNUNET_YES if message is well-formed
5076 check_backchannel_encapsulation (
5078 const struct TransportBackchannelEncapsulationMessage *be)
5080 uint16_t size = ntohs (be->header.size);
5083 if ((size - sizeof (*be)) <
5084 (sizeof (struct TransportBackchannelRequestPayloadP) +
5085 sizeof (struct GNUNET_MessageHeader)))
5087 GNUNET_break_op (0);
5088 return GNUNET_SYSERR;
5095 * We received the plaintext @a msg from backtalker @a b. Forward
5096 * it to the respective communicator.
5098 * @param b a backtalker
5099 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5100 * followed by the target name of the communicator
5101 * @param msg_size number of bytes in @a msg
5104 forward_backchannel_payload (struct Backtalker *b,
5108 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5109 struct GNUNET_MQ_Envelope *env;
5110 struct TransportClient *tc;
5111 const struct GNUNET_MessageHeader *mh;
5112 const char *target_communicator;
5115 /* Determine target_communicator and check @a msg is well-formed */
5117 mhs = ntohs (mh->size);
5118 if (mhs <= msg_size)
5120 GNUNET_break_op (0);
5123 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5124 if ('\0' != target_communicator[msg_size - mhs - 1])
5126 GNUNET_break_op (0);
5129 /* Find client providing this communicator */
5130 for (tc = clients_head; NULL != tc; tc = tc->next)
5131 if ((CT_COMMUNICATOR == tc->type) &&
5133 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5141 "# Backchannel message dropped: target communicator `%s' unknown",
5142 target_communicator);
5143 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5144 GNUNET_free (stastr);
5147 /* Finally, deliver backchannel message to communicator */
5148 env = GNUNET_MQ_msg_extra (
5151 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5153 memcpy (&cbi[1], msg, msg_size);
5154 GNUNET_MQ_send (tc->mq, env);
5159 * Free data structures associated with @a b.
5161 * @param b data structure to release
5164 free_backtalker (struct Backtalker *b)
5168 GNUNET_PEERSTORE_iterate_cancel (b->get);
5170 GNUNET_assert (NULL != b->cmc);
5171 finish_cmc_handling (b->cmc);
5174 if (NULL != b->task)
5176 GNUNET_SCHEDULER_cancel (b->task);
5181 GNUNET_PEERSTORE_store_cancel (b->sc);
5186 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5192 * Callback to free backtalker records.
5196 * @param value a `struct Backtalker`
5197 * @return #GNUNET_OK (always)
5200 free_backtalker_cb (void *cls,
5201 const struct GNUNET_PeerIdentity *pid,
5204 struct Backtalker *b = value;
5208 free_backtalker (b);
5214 * Function called when it is time to clean up a backtalker.
5216 * @param cls a `struct Backtalker`
5219 backtalker_timeout_cb (void *cls)
5221 struct Backtalker *b = cls;
5224 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5226 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5229 GNUNET_assert (NULL == b->sc);
5230 free_backtalker (b);
5235 * Function called with the monotonic time of a backtalker
5236 * by PEERSTORE. Updates the time and continues processing.
5238 * @param cls a `struct Backtalker`
5239 * @param record the information found, NULL for the last call
5240 * @param emsg error message
5243 backtalker_monotime_cb (void *cls,
5244 const struct GNUNET_PEERSTORE_Record *record,
5247 struct Backtalker *b = cls;
5248 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5249 struct GNUNET_TIME_Absolute mt;
5254 /* we're done with #backtalker_monotime_cb() invocations,
5255 continue normal processing */
5257 GNUNET_assert (NULL != b->cmc);
5258 finish_cmc_handling (b->cmc);
5260 if (0 != b->body_size)
5261 forward_backchannel_payload (b, &b[1], b->body_size);
5264 if (sizeof (*mtbe) != record->value_size)
5269 mtbe = record->value;
5270 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5271 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5273 GNUNET_STATISTICS_update (
5275 "# Backchannel messages dropped: monotonic time not increasing",
5278 b->monotonic_time = mt;
5279 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5288 * Function called by PEERSTORE when the store operation of
5289 * a backtalker's monotonic time is complete.
5291 * @param cls the `struct Backtalker`
5292 * @param success #GNUNET_OK on success
5295 backtalker_monotime_store_cb (void *cls, int success)
5297 struct Backtalker *b = cls;
5299 if (GNUNET_OK != success)
5301 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5302 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5305 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5310 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5312 * @param b a backtalker with updated monotonic time
5315 update_backtalker_monotime (struct Backtalker *b)
5317 struct GNUNET_TIME_AbsoluteNBO mtbe;
5321 GNUNET_PEERSTORE_store_cancel (b->sc);
5326 GNUNET_SCHEDULER_cancel (b->task);
5329 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5331 GNUNET_PEERSTORE_store (peerstore,
5334 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5337 GNUNET_TIME_UNIT_FOREVER_ABS,
5338 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5339 &backtalker_monotime_store_cb,
5345 * Communicator gave us a backchannel encapsulation. Process the request.
5346 * (We are not the origin of the backchannel here, the communicator simply
5347 * received a backchannel message and we are expected to forward it.)
5349 * @param cls a `struct CommunicatorMessageContext` (must call
5350 * #finish_cmc_handling() when done)
5351 * @param be the message that was received
5354 handle_backchannel_encapsulation (
5356 const struct TransportBackchannelEncapsulationMessage *be)
5358 struct CommunicatorMessageContext *cmc = cls;
5359 struct BackchannelKeyState key;
5360 struct GNUNET_HashCode hmac;
5364 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5366 /* not for me, try to route to target */
5367 route_message (&be->target,
5368 GNUNET_copy_message (&be->header),
5370 finish_cmc_handling (cmc);
5373 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5374 hdr = (const char *) &be[1];
5375 hdr_len = ntohs (be->header.size) - sizeof (*be);
5376 bc_hmac (&key, &hmac, hdr, hdr_len);
5377 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5379 /* HMAC missmatch, disard! */
5380 GNUNET_break_op (0);
5381 finish_cmc_handling (cmc);
5384 /* begin actual decryption */
5386 struct Backtalker *b;
5387 struct GNUNET_TIME_Absolute monotime;
5388 struct TransportBackchannelRequestPayloadP ppay;
5389 char body[hdr_len - sizeof (ppay)];
5391 GNUNET_assert (hdr_len >=
5392 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5393 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5394 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5395 bc_key_clean (&key);
5396 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5397 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5398 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5400 GNUNET_STATISTICS_update (
5402 "# Backchannel messages dropped: monotonic time not increasing",
5405 finish_cmc_handling (cmc);
5409 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5411 /* Check signature */
5412 struct EphemeralConfirmationPS ec;
5414 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5415 ec.purpose.size = htonl (sizeof (ec));
5416 ec.target = GST_my_identity;
5417 ec.ephemeral_key = be->ephemeral_key;
5420 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5423 &ppay.sender.public_key))
5425 /* Signature invalid, disard! */
5426 GNUNET_break_op (0);
5427 finish_cmc_handling (cmc);
5433 /* update key cache and mono time */
5434 b->last_ephemeral = be->ephemeral_key;
5435 b->monotonic_time = monotime;
5436 update_backtalker_monotime (b);
5437 forward_backchannel_payload (b, body, sizeof (body));
5439 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5440 finish_cmc_handling (cmc);
5443 /* setup data structure to cache signature AND check
5444 monotonic time with PEERSTORE before forwarding backchannel payload */
5445 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5446 b->pid = ppay.sender;
5447 b->body_size = sizeof (body);
5448 memcpy (&b[1], body, sizeof (body));
5449 GNUNET_assert (GNUNET_YES ==
5450 GNUNET_CONTAINER_multipeermap_put (
5454 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5455 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5458 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5459 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5461 GNUNET_PEERSTORE_iterate (peerstore,
5464 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5465 &backtalker_monotime_cb,
5472 * Task called when we should check if any of the DV paths
5473 * we have learned to a target are due for garbage collection.
5475 * Collects stale paths, and possibly frees the entire DV
5476 * entry if no paths are left. Otherwise re-schedules itself.
5478 * @param cls a `struct DistanceVector`
5481 path_cleanup_cb (void *cls)
5483 struct DistanceVector *dv = cls;
5484 struct DistanceVectorHop *pos;
5486 dv->timeout_task = NULL;
5487 while (NULL != (pos = dv->dv_head))
5489 GNUNET_assert (dv == pos->dv);
5490 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5492 free_distance_vector_hop (pos);
5500 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5504 * Task run to check whether the hops of the @a cls still
5505 * are validated, or if we need to core about disconnection.
5507 * @param cls a `struct DistanceVector` (with core_visible set!)
5510 check_dv_path_down (void *cls)
5512 struct DistanceVector *dv = cls;
5513 struct Neighbour *n;
5515 dv->visibility_task = NULL;
5516 GNUNET_assert (GNUNET_YES == dv->core_visible);
5517 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5521 GNUNET_TIME_absolute_get_remaining (pos->path_valid_until).rel_value_us)
5523 dv->visibility_task = GNUNET_SCHEDULER_add_at (pos->path_valid_until,
5524 &check_dv_path_down,
5529 /* all paths invalid, make dv core-invisible */
5530 dv->core_visible = GNUNET_NO;
5531 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
5532 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5533 return; /* no need to tell core, connection still up! */
5534 cores_send_disconnect_info (&dv->target);
5539 * The @a hop is a validated path to the respective target
5540 * peer and we should tell core about it -- and schedule
5541 * a job to revoke the state.
5543 * @param hop a path to some peer that is the reason for activation
5546 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5548 struct DistanceVector *dv = hop->dv;
5549 struct Neighbour *n;
5551 GNUNET_assert (GNUNET_NO == dv->core_visible);
5552 GNUNET_assert (NULL == dv->visibility_task);
5554 dv->core_visible = GNUNET_YES;
5555 dv->visibility_task =
5556 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_dv_path_down, dv);
5557 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
5558 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5559 return; /* no need to tell core, connection already up! */
5560 cores_send_connect_info (&dv->target,
5562 ? GNUNET_BANDWIDTH_value_sum (n->quota_out,
5569 * We have learned a @a path through the network to some other peer, add it to
5570 * our DV data structure (returning #GNUNET_YES on success).
5572 * We do not add paths if we have a sufficient number of shorter
5573 * paths to this target already (returning #GNUNET_NO).
5575 * We also do not add problematic paths, like those where we lack the first
5576 * hop in our neighbour list (i.e. due to a topology change) or where some
5577 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5579 * @param path the path we learned, path[0] should be us,
5580 * and then path contains a valid path from us to
5581 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
5582 * @param path_len number of entries on the @a path, at least three!
5583 * @param network_latency how long does the message take from us to
5584 * `path[path_len-1]`? set to "forever" if unknown
5585 * @param path_valid_until how long is this path considered validated? Maybe
5587 * @return #GNUNET_YES on success,
5588 * #GNUNET_NO if we have better path(s) to the target
5589 * #GNUNET_SYSERR if the path is useless and/or invalid
5590 * (i.e. path[1] not a direct neighbour
5591 * or path[i+1] is a direct neighbour for i>0)
5594 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5595 unsigned int path_len,
5596 struct GNUNET_TIME_Relative network_latency,
5597 struct GNUNET_TIME_Absolute path_valid_until)
5599 struct DistanceVectorHop *hop;
5600 struct DistanceVector *dv;
5601 struct Neighbour *next_hop;
5602 unsigned int shorter_distance;
5606 /* what a boring path! not allowed! */
5608 return GNUNET_SYSERR;
5610 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5611 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours, &path[1]);
5612 if (NULL == next_hop)
5614 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5616 return GNUNET_SYSERR;
5618 for (unsigned int i = 2; i < path_len; i++)
5619 if (NULL != GNUNET_CONTAINER_multipeermap_get (neighbours, &path[i]))
5621 /* Useless path, we have a direct connection to some hop
5622 in the middle of the path, so this one doesn't even
5623 seem terribly useful for redundancy */
5624 return GNUNET_SYSERR;
5626 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5629 dv = GNUNET_new (struct DistanceVector);
5630 dv->target = path[path_len - 1];
5631 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5634 GNUNET_assert (GNUNET_OK ==
5635 GNUNET_CONTAINER_multipeermap_put (
5639 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5641 /* Check if we have this path already! */
5642 shorter_distance = 0;
5643 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5646 if (pos->distance < path_len - 2)
5648 /* Note that the distances in 'pos' excludes us (path[0]) and
5649 the next_hop (path[1]), so we need to subtract two
5650 and check next_hop explicitly */
5651 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5653 int match = GNUNET_YES;
5655 for (unsigned int i = 0; i < pos->distance; i++)
5657 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5663 if (GNUNET_YES == match)
5665 struct GNUNET_TIME_Relative last_timeout;
5667 /* Re-discovered known path, update timeout */
5668 GNUNET_STATISTICS_update (GST_stats,
5669 "# Known DV path refreshed",
5672 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5674 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5675 pos->path_valid_until =
5676 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5677 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5678 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5679 if ((GNUNET_NO == dv->core_visible) &&
5680 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until)
5682 activate_core_visible_dv_path (pos);
5683 if (last_timeout.rel_value_us <
5684 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5685 DV_PATH_DISCOVERY_FREQUENCY)
5688 /* Some peer send DV learn messages too often, we are learning
5689 the same path faster than it would be useful; do not forward! */
5696 /* Count how many shorter paths we have (incl. direct
5697 neighbours) before simply giving up on this one! */
5698 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
5700 /* We have a shorter path already! */
5703 /* create new DV path entry */
5704 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
5705 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5706 hop->next_hop = next_hop;
5708 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
5711 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5712 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5713 hop->path_valid_until = path_valid_until;
5714 hop->distance = path_len - 2;
5715 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
5716 GNUNET_CONTAINER_MDLL_insert (neighbour,
5720 if ((GNUNET_NO == dv->core_visible) &&
5721 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us))
5722 activate_core_visible_dv_path (hop);
5728 * Communicator gave us a DV learn message. Check the message.
5730 * @param cls a `struct CommunicatorMessageContext`
5731 * @param dvl the send message that was sent
5732 * @return #GNUNET_YES if message is well-formed
5735 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
5737 uint16_t size = ntohs (dvl->header.size);
5738 uint16_t num_hops = ntohs (dvl->num_hops);
5739 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
5742 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
5744 GNUNET_break_op (0);
5745 return GNUNET_SYSERR;
5747 if (num_hops > MAX_DV_HOPS_ALLOWED)
5749 GNUNET_break_op (0);
5750 return GNUNET_SYSERR;
5752 for (unsigned int i = 0; i < num_hops; i++)
5754 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
5756 GNUNET_break_op (0);
5757 return GNUNET_SYSERR;
5759 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
5761 GNUNET_break_op (0);
5762 return GNUNET_SYSERR;
5770 * Build and forward a DV learn message to @a next_hop.
5772 * @param next_hop peer to send the message to
5773 * @param msg message received
5774 * @param bi_history bitmask specifying hops on path that were bidirectional
5775 * @param nhops length of the @a hops array
5776 * @param hops path the message traversed so far
5777 * @param in_time when did we receive the message, used to calculate network
5781 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
5782 const struct TransportDVLearnMessage *msg,
5783 uint16_t bi_history,
5785 const struct DVPathEntryP *hops,
5786 struct GNUNET_TIME_Absolute in_time)
5788 struct DVPathEntryP *dhops;
5789 struct TransportDVLearnMessage *fwd;
5790 struct GNUNET_TIME_Relative nnd;
5792 /* compute message for forwarding */
5793 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
5794 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
5795 (nhops + 1) * sizeof (struct DVPathEntryP));
5796 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
5797 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
5798 (nhops + 1) * sizeof (struct DVPathEntryP));
5799 fwd->num_hops = htons (nhops + 1);
5800 fwd->bidirectional = htons (bi_history);
5801 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
5802 GNUNET_TIME_relative_ntoh (
5803 msg->non_network_delay));
5804 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
5805 fwd->init_sig = msg->init_sig;
5806 fwd->initiator = msg->initiator;
5807 fwd->challenge = msg->challenge;
5808 dhops = (struct DVPathEntryP *) &fwd[1];
5809 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
5810 dhops[nhops].hop = GST_my_identity;
5812 struct DvHopPS dhp = {.purpose.purpose =
5813 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
5814 .purpose.size = htonl (sizeof (dhp)),
5815 .pred = dhops[nhops - 1].hop,
5817 .challenge = msg->challenge};
5819 GNUNET_assert (GNUNET_OK ==
5820 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5822 &dhops[nhops].hop_sig));
5824 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
5829 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
5831 * @param init the signer
5832 * @param challenge the challenge that was signed
5833 * @param init_sig signature presumably by @a init
5834 * @return #GNUNET_OK if the signature is valid
5837 validate_dv_initiator_signature (
5838 const struct GNUNET_PeerIdentity *init,
5839 const struct ChallengeNonceP *challenge,
5840 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
5842 struct DvInitPS ip = {.purpose.purpose = htonl (
5843 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
5844 .purpose.size = htonl (sizeof (ip)),
5845 .challenge = *challenge};
5849 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
5854 GNUNET_break_op (0);
5855 return GNUNET_SYSERR;
5862 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
5864 struct NeighbourSelectionContext
5867 * Original message we received.
5869 const struct TransportDVLearnMessage *dvl;
5874 const struct DVPathEntryP *hops;
5877 * Time we received the message.
5879 struct GNUNET_TIME_Absolute in_time;
5882 * Offsets of the selected peers.
5884 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
5887 * Number of peers eligible for selection.
5889 unsigned int num_eligible;
5892 * Number of peers that were selected for forwarding.
5894 unsigned int num_selections;
5897 * Number of hops in @e hops
5902 * Bitmap of bidirectional connections encountered.
5904 uint16_t bi_history;
5909 * Function called for each neighbour during #handle_dv_learn.
5911 * @param cls a `struct NeighbourSelectionContext *`
5912 * @param pid identity of the peer
5913 * @param value a `struct Neighbour`
5914 * @return #GNUNET_YES (always)
5917 dv_neighbour_selection (void *cls,
5918 const struct GNUNET_PeerIdentity *pid,
5921 struct NeighbourSelectionContext *nsc = cls;
5924 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
5925 return GNUNET_YES; /* skip initiator */
5926 for (unsigned int i = 0; i < nsc->nhops; i++)
5927 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
5928 return GNUNET_YES; /* skip peers on path */
5929 nsc->num_eligible++;
5935 * Function called for each neighbour during #handle_dv_learn.
5936 * We call #forward_dv_learn() on the neighbour(s) selected
5937 * during #dv_neighbour_selection().
5939 * @param cls a `struct NeighbourSelectionContext *`
5940 * @param pid identity of the peer
5941 * @param value a `struct Neighbour`
5942 * @return #GNUNET_YES (always)
5945 dv_neighbour_transmission (void *cls,
5946 const struct GNUNET_PeerIdentity *pid,
5949 struct NeighbourSelectionContext *nsc = cls;
5952 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
5953 return GNUNET_YES; /* skip initiator */
5954 for (unsigned int i = 0; i < nsc->nhops; i++)
5955 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
5956 return GNUNET_YES; /* skip peers on path */
5957 for (unsigned int i = 0; i < nsc->num_selections; i++)
5959 if (nsc->selections[i] == nsc->num_eligible)
5961 forward_dv_learn (pid,
5970 nsc->num_eligible++;
5976 * Computes the number of neighbours we should forward a DVInit
5977 * message to given that it has so far taken @a hops_taken hops
5978 * though the network and that the number of neighbours we have
5979 * in total is @a neighbour_count, out of which @a eligible_count
5980 * are not yet on the path.
5982 * NOTE: technically we might want to include NSE in the formula to
5983 * get a better grip on the overall network size. However, for now
5984 * using NSE here would create a dependency issue in the build system.
5985 * => Left for later, hardcoded to 50 for now.
5987 * The goal of the fomula is that we want to reach a total of LOG(NSE)
5988 * peers via DV (`target_total`). We want the reach to be spread out
5989 * over various distances to the origin, with a bias towards shorter
5992 * We make the strong assumption that the network topology looks
5993 * "similar" at other hops, in particular the @a neighbour_count
5994 * should be comparable at other hops.
5996 * If the local neighbourhood is densely connected, we expect that @a
5997 * eligible_count is close to @a neighbour_count minus @a hops_taken
5998 * as a lot of the path is already known. In that case, we should
5999 * forward to few(er) peers to try to find a path out of the
6000 * neighbourhood. OTOH, if @a eligible_count is close to @a
6001 * neighbour_count, we should forward to many peers as we are either
6002 * still close to the origin (i.e. @a hops_taken is small) or because
6003 * we managed to get beyond a local cluster. We express this as
6004 * the `boost_factor` using the square of the fraction of eligible
6005 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6006 * 99% are eligible, the 'boost' will be almost 1).
6008 * Second, the more hops we have taken, the larger the problem of an
6009 * exponential traffic explosion gets. So we take the `target_total`,
6010 * and compute our degree such that at each distance d 2^{-d} peers
6011 * are selected (corrected by the `boost_factor`).
6013 * @param hops_taken number of hops DVInit has travelled so far
6014 * @param neighbour_count number of neighbours we have in total
6015 * @param eligible_count number of neighbours we could in
6019 calculate_fork_degree (unsigned int hops_taken,
6020 unsigned int neighbour_count,
6021 unsigned int eligible_count)
6023 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6024 double eligible_ratio =
6025 ((double) eligible_count) / ((double) neighbour_count);
6026 double boost_factor = eligible_ratio * eligible_ratio;
6030 if (hops_taken >= 64)
6031 return 0; /* precaution given bitshift below */
6032 for (unsigned int i = 1; i < hops_taken; i++)
6034 /* For each hop, subtract the expected number of targets
6035 reached at distance d (so what remains divided by 2^d) */
6036 target_total -= (target_total * boost_factor / (1LLU << i));
6039 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6040 /* round up or down probabilistically depending on how close we were
6041 when floor()ing to rnd */
6042 left = target_total - (double) rnd;
6043 if (UINT32_MAX * left >
6044 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6045 rnd++; /* round up */
6051 * Communicator gave us a DV learn message. Process the request.
6053 * @param cls a `struct CommunicatorMessageContext` (must call
6054 * #finish_cmc_handling() when done)
6055 * @param dvl the message that was received
6058 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6060 struct CommunicatorMessageContext *cmc = cls;
6061 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6064 uint16_t bi_history;
6065 const struct DVPathEntryP *hops;
6068 struct GNUNET_TIME_Absolute in_time;
6070 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6071 bi_history = ntohs (dvl->bidirectional);
6072 hops = (const struct DVPathEntryP *) &dvl[1];
6076 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6079 finish_cmc_handling (cmc);
6086 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6089 finish_cmc_handling (cmc);
6094 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6095 cc = cmc->tc->details.communicator.cc;
6096 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6097 cc); // FIXME: add bi-directional flag to cc?
6098 in_time = GNUNET_TIME_absolute_get ();
6100 /* continue communicator here, everything else can happen asynchronous! */
6101 finish_cmc_handling (cmc);
6103 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
6104 the initiator signature if we send the message back to the initiator...
6106 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
6110 GNUNET_break_op (0);
6113 // FIXME: asynchronously (!) verify hop-by-hop signatures!
6114 // => if signature verification load too high, implement random drop
6117 do_fwd = GNUNET_YES;
6118 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6120 struct GNUNET_PeerIdentity path[nhops + 1];
6121 struct GNUNET_TIME_Relative host_latency_sum;
6122 struct GNUNET_TIME_Relative latency;
6123 struct GNUNET_TIME_Relative network_latency;
6125 /* We initiated this, learn the forward path! */
6126 path[0] = GST_my_identity;
6127 path[1] = hops[0].hop;
6128 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6130 // Need also something to lookup initiation time
6131 // to compute RTT! -> add RTT argument here?
6132 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6133 // (based on dvl->challenge, we can identify time of origin!)
6135 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6136 /* assumption: latency on all links is the same */
6137 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6139 for (unsigned int i = 2; i <= nhops; i++)
6141 struct GNUNET_TIME_Relative ilat;
6143 /* assumption: linear latency increase per hop */
6144 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6145 path[i] = hops[i - 1].hop;
6146 learn_dv_path (path,
6149 GNUNET_TIME_relative_to_absolute (
6150 ADDRESS_VALIDATION_LIFETIME));
6152 /* as we initiated, do not forward again (would be circular!) */
6158 /* last hop was bi-directional, we could learn something here! */
6159 struct GNUNET_PeerIdentity path[nhops + 2];
6161 path[0] = GST_my_identity;
6162 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6163 for (unsigned int i = 0; i < nhops; i++)
6167 if (0 == (bi_history & (1 << i)))
6168 break; /* i-th hop not bi-directional, stop learning! */
6171 path[i + 2] = dvl->initiator;
6175 path[i + 2] = hops[nhops - i - 2].hop;
6178 iret = learn_dv_path (path,
6180 GNUNET_TIME_UNIT_FOREVER_REL,
6181 GNUNET_TIME_UNIT_ZERO_ABS);
6182 if (GNUNET_SYSERR == iret)
6184 /* path invalid or too long to be interesting for US, thus should also
6185 not be interesting to our neighbours, cut path when forwarding to
6186 'i' hops, except of course for the one that goes back to the
6188 GNUNET_STATISTICS_update (GST_stats,
6189 "# DV learn not forwarded due invalidity of path",
6195 if ((GNUNET_NO == iret) && (nhops == i + 1))
6197 /* we have better paths, and this is the longest target,
6198 so there cannot be anything interesting later */
6199 GNUNET_STATISTICS_update (GST_stats,
6200 "# DV learn not forwarded, got better paths",
6209 if (MAX_DV_HOPS_ALLOWED == nhops)
6211 /* At limit, we're out of here! */
6212 finish_cmc_handling (cmc);
6216 /* Forward to initiator, if path non-trivial and possible */
6217 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6218 did_initiator = GNUNET_NO;
6221 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6223 /* send back to origin! */
6224 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6225 did_initiator = GNUNET_YES;
6227 /* We forward under two conditions: either we still learned something
6228 ourselves (do_fwd), or the path was darn short and thus the initiator is
6229 likely to still be very interested in this (and we did NOT already
6230 send it back to the initiator) */
6231 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6232 (GNUNET_NO == did_initiator)))
6234 /* Pick random neighbours that are not yet on the path */
6235 struct NeighbourSelectionContext nsc;
6238 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6241 nsc.bi_history = bi_history;
6243 nsc.in_time = in_time;
6244 nsc.num_eligible = 0;
6245 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6246 &dv_neighbour_selection,
6248 if (0 == nsc.num_eligible)
6249 return; /* done here, cannot forward to anyone else */
6250 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6251 nsc.num_selections =
6252 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6253 for (unsigned int i = 0; i < nsc.num_selections; i++)
6255 (nsc.num_selections == n_cnt)
6256 ? i /* all were selected, avoid collisions by chance */
6257 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6258 nsc.num_eligible = 0;
6259 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6260 &dv_neighbour_transmission,
6267 * Communicator gave us a DV box. Check the message.
6269 * @param cls a `struct CommunicatorMessageContext`
6270 * @param dvb the send message that was sent
6271 * @return #GNUNET_YES if message is well-formed
6274 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6276 uint16_t size = ntohs (dvb->header.size);
6277 uint16_t num_hops = ntohs (dvb->num_hops);
6278 const struct GNUNET_PeerIdentity *hops =
6279 (const struct GNUNET_PeerIdentity *) &dvb[1];
6280 const struct GNUNET_MessageHeader *inbox =
6281 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6286 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6287 sizeof (struct GNUNET_MessageHeader))
6289 GNUNET_break_op (0);
6290 return GNUNET_SYSERR;
6292 isize = ntohs (inbox->size);
6294 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6296 GNUNET_break_op (0);
6297 return GNUNET_SYSERR;
6299 itype = ntohs (inbox->type);
6300 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6301 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6303 GNUNET_break_op (0);
6304 return GNUNET_SYSERR;
6306 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6308 GNUNET_break_op (0);
6309 return GNUNET_SYSERR;
6316 * Create a DV Box message and queue it for transmission to
6319 * @param next_hop peer to receive the message next
6320 * @param total_hops how many hops did the message take so far
6321 * @param num_hops length of the @a hops array
6322 * @param origin origin of the message
6323 * @param hops next peer(s) to the destination, including destination
6324 * @param payload payload of the box
6325 * @param payload_size number of bytes in @a payload
6328 forward_dv_box (struct Neighbour *next_hop,
6329 uint16_t total_hops,
6331 const struct GNUNET_PeerIdentity *origin,
6332 const struct GNUNET_PeerIdentity *hops,
6333 const void *payload,
6334 uint16_t payload_size)
6336 struct TransportDVBoxMessage *dvb;
6337 struct GNUNET_PeerIdentity *dhops;
6339 GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBoxMessage) +
6340 sizeof (struct GNUNET_PeerIdentity) * num_hops +
6342 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
6343 sizeof (struct GNUNET_PeerIdentity) * num_hops +
6346 htons (sizeof (struct TransportDVBoxMessage) +
6347 sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size);
6348 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
6349 dvb->total_hops = htons (total_hops);
6350 dvb->num_hops = htons (num_hops);
6351 dvb->origin = *origin;
6352 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
6353 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
6354 memcpy (&dhops[num_hops], payload, payload_size);
6355 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6360 * Communicator gave us a DV box. Process the request.
6362 * @param cls a `struct CommunicatorMessageContext` (must call
6363 * #finish_cmc_handling() when done)
6364 * @param dvb the message that was received
6367 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6369 struct CommunicatorMessageContext *cmc = cls;
6370 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6371 uint16_t num_hops = ntohs (dvb->num_hops);
6372 const struct GNUNET_PeerIdentity *hops =
6373 (const struct GNUNET_PeerIdentity *) &dvb[1];
6374 const struct GNUNET_MessageHeader *inbox =
6375 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6379 /* We're trying from the end of the hops array, as we may be
6380 able to find a shortcut unknown to the origin that way */
6381 for (int i = num_hops - 1; i >= 0; i--)
6383 struct Neighbour *n;
6385 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6387 GNUNET_break_op (0);
6388 finish_cmc_handling (cmc);
6391 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &hops[i]);
6395 ntohs (dvb->total_hops) + 1,
6396 num_hops - i - 1, /* number of hops left */
6398 &hops[i + 1], /* remaining hops */
6399 (const void *) &dvb[1],
6401 finish_cmc_handling (cmc);
6404 /* Woopsie, next hop not in neighbours, drop! */
6405 GNUNET_STATISTICS_update (GST_stats,
6406 "# DV Boxes dropped: next hop unknown",
6409 finish_cmc_handling (cmc);
6412 /* We are the target. Unbox and handle message. */
6413 cmc->im.sender = dvb->origin;
6414 cmc->total_hops = ntohs (dvb->total_hops);
6415 demultiplex_with_cmc (cmc, inbox);
6420 * Client notified us about transmission from a peer. Process the request.
6422 * @param cls a `struct TransportClient` which sent us the message
6423 * @param obm the send message that was sent
6424 * @return #GNUNET_YES if message is well-formed
6427 check_incoming_msg (void *cls,
6428 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6430 struct TransportClient *tc = cls;
6432 if (CT_COMMUNICATOR != tc->type)
6435 return GNUNET_SYSERR;
6437 GNUNET_MQ_check_boxed_message (im);
6443 * Communicator gave us a transport address validation challenge. Process the
6446 * @param cls a `struct CommunicatorMessageContext` (must call
6447 * #finish_cmc_handling() when done)
6448 * @param tvc the message that was received
6451 handle_validation_challenge (
6453 const struct TransportValidationChallengeMessage *tvc)
6455 struct CommunicatorMessageContext *cmc = cls;
6456 struct TransportValidationResponseMessage *tvr;
6458 if (cmc->total_hops > 0)
6460 /* DV routing is not allowed for validation challenges! */
6461 GNUNET_break_op (0);
6462 finish_cmc_handling (cmc);
6465 tvr = GNUNET_new (struct TransportValidationResponseMessage);
6467 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
6468 tvr->header.size = htons (sizeof (*tvr));
6469 tvr->challenge = tvc->challenge;
6470 tvr->origin_time = tvc->sender_time;
6471 tvr->validity_duration = cmc->im.expected_address_validity;
6473 /* create signature */
6474 struct TransportValidationPS tvp =
6475 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6476 .purpose.size = htonl (sizeof (tvp)),
6477 .validity_duration = tvr->validity_duration,
6478 .challenge = tvc->challenge};
6480 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6484 route_message (&cmc->im.sender,
6486 RMO_ANYTHING_GOES | RMO_REDUNDANT);
6487 finish_cmc_handling (cmc);
6492 * Closure for #check_known_challenge.
6494 struct CheckKnownChallengeContext
6497 * Set to the challenge we are looking for.
6499 const struct ChallengeNonceP *challenge;
6502 * Set to a matching validation state, if one was found.
6504 struct ValidationState *vs;
6509 * Test if the validation state in @a value matches the
6510 * challenge from @a cls.
6512 * @param cls a `struct CheckKnownChallengeContext`
6513 * @param pid unused (must match though)
6514 * @param value a `struct ValidationState`
6515 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6518 check_known_challenge (void *cls,
6519 const struct GNUNET_PeerIdentity *pid,
6522 struct CheckKnownChallengeContext *ckac = cls;
6523 struct ValidationState *vs = value;
6526 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
6534 * Function called when peerstore is done storing a
6535 * validated address.
6537 * @param cls a `struct ValidationState`
6538 * @param success #GNUNET_YES on success
6541 peerstore_store_validation_cb (void *cls, int success)
6543 struct ValidationState *vs = cls;
6546 if (GNUNET_YES == success)
6548 GNUNET_STATISTICS_update (GST_stats,
6549 "# Peerstore failed to store foreign address",
6556 * Task run periodically to validate some address based on #validation_heap.
6561 validation_start_cb (void *cls);
6565 * Set the time for next_challenge of @a vs to @a new_time.
6566 * Updates the heap and if necessary reschedules the job.
6568 * @param vs validation state to update
6569 * @param new_time new time for revalidation
6572 update_next_challenge_time (struct ValidationState *vs,
6573 struct GNUNET_TIME_Absolute new_time)
6575 struct GNUNET_TIME_Relative delta;
6577 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
6578 return; /* be lazy */
6579 vs->next_challenge = new_time;
6582 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
6584 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
6585 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
6586 (NULL != validation_task))
6588 if (NULL != validation_task)
6589 GNUNET_SCHEDULER_cancel (validation_task);
6590 /* randomize a bit */
6591 delta.rel_value_us =
6592 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6593 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
6594 new_time = GNUNET_TIME_absolute_add (new_time, delta);
6596 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
6601 * Find the queue matching @a pid and @a address.
6603 * @param pid peer the queue must go to
6604 * @param address address the queue must use
6605 * @return NULL if no such queue exists
6607 static struct Queue *
6608 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
6610 struct Neighbour *n;
6612 n = GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
6615 for (struct Queue *pos = n->queue_head; NULL != pos;
6616 pos = pos->next_neighbour)
6618 if (0 == strcmp (pos->address, address))
6626 * Task run periodically to check whether the validity of the given queue has
6627 * run its course. If so, finds either another queue to take over, or clears
6628 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
6629 * chance to take over, and if that fails, notifies CORE about the disconnect.
6631 * @param cls a `struct Queue`
6634 core_queue_visibility_check (void *cls)
6636 struct Queue *q = cls;
6638 q->visibility_task = NULL;
6639 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
6641 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
6642 &core_queue_visibility_check,
6646 update_neighbour_core_visibility (q->neighbour);
6651 * Check whether the CORE visibility of @a n should change. Finds either a
6652 * queue to preserve the visibility, or clears the neighbour's `core_visible`
6653 * flag. In the latter case, gives DV routes a chance to take over, and if
6654 * that fails, notifies CORE about the disconnect. If so, check whether we
6655 * need to notify CORE.
6657 * @param n neighbour to perform the check for
6660 update_neighbour_core_visibility (struct Neighbour *n)
6662 struct DistanceVector *dv;
6664 GNUNET_assert (GNUNET_YES == n->core_visible);
6665 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
6666 the #core_queue_visibility_check() task for that queue */
6667 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6670 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
6672 /* found a valid queue, use this one */
6673 q->visibility_task =
6674 GNUNET_SCHEDULER_add_at (q->validated_until,
6675 &core_queue_visibility_check,
6680 n->core_visible = GNUNET_NO;
6682 /* Check if _any_ DV route to this neighbour is currently
6683 valid, if so, do NOT tell core about the loss of direct
6684 connectivity (DV still counts!) */
6685 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
6686 if (GNUNET_YES == dv->core_visible)
6688 /* Nothing works anymore, need to tell CORE about the loss of
6690 cores_send_disconnect_info (&n->pid);
6695 * Communicator gave us a transport address validation response. Process the
6698 * @param cls a `struct CommunicatorMessageContext` (must call
6699 * #finish_cmc_handling() when done)
6700 * @param tvr the message that was received
6703 handle_validation_response (
6705 const struct TransportValidationResponseMessage *tvr)
6707 struct CommunicatorMessageContext *cmc = cls;
6708 struct ValidationState *vs;
6709 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
6711 struct GNUNET_TIME_Absolute origin_time;
6713 struct DistanceVector *dv;
6714 struct Neighbour *n;
6716 /* check this is one of our challenges */
6717 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6719 &check_known_challenge,
6721 if (NULL == (vs = ckac.vs))
6723 /* This can happen simply if we 'forgot' the challenge by now,
6724 i.e. because we received the validation response twice */
6725 GNUNET_STATISTICS_update (GST_stats,
6726 "# Validations dropped, challenge unknown",
6729 finish_cmc_handling (cmc);
6733 /* sanity check on origin time */
6734 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
6735 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
6736 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
6738 GNUNET_break_op (0);
6739 finish_cmc_handling (cmc);
6744 /* check signature */
6745 struct TransportValidationPS tvp =
6746 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6747 .purpose.size = htonl (sizeof (tvp)),
6748 .validity_duration = tvr->validity_duration,
6749 .challenge = tvr->challenge};
6753 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
6756 &cmc->im.sender.public_key))
6758 GNUNET_break_op (0);
6759 finish_cmc_handling (cmc);
6764 /* validity is capped by our willingness to keep track of the
6765 validation entry and the maximum the other peer allows */
6766 vs->valid_until = GNUNET_TIME_relative_to_absolute (
6767 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
6768 tvr->validity_duration),
6769 MAX_ADDRESS_VALID_UNTIL));
6770 vs->validated_until =
6771 GNUNET_TIME_absolute_min (vs->valid_until,
6772 GNUNET_TIME_relative_to_absolute (
6773 ADDRESS_VALIDATION_LIFETIME));
6774 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
6775 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
6776 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6778 sizeof (vs->challenge));
6779 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
6780 vs->validated_until,
6781 GNUNET_TIME_relative_multiply (vs->validation_rtt,
6782 VALIDATION_RTT_BUFFER_FACTOR));
6783 vs->last_challenge_use =
6784 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
6785 update_next_challenge_time (vs, vs->first_challenge_use);
6786 vs->sc = GNUNET_PEERSTORE_store (peerstore,
6789 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
6791 strlen (vs->address) + 1,
6793 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
6794 &peerstore_store_validation_cb,
6796 finish_cmc_handling (cmc);
6798 /* Finally, we now possibly have a confirmed (!) working queue,
6799 update queue status (if queue still is around) */
6800 q = find_queue (&vs->pid, vs->address);
6803 GNUNET_STATISTICS_update (GST_stats,
6804 "# Queues lost at time of successful validation",
6809 q->validated_until = vs->validated_until;
6810 q->pd.aged_rtt = vs->validation_rtt;
6812 if (GNUNET_NO != n->core_visible)
6813 return; /* nothing changed, we are done here */
6814 n->core_visible = GNUNET_YES;
6815 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
6816 &core_queue_visibility_check,
6818 /* Check if _any_ DV route to this neighbour is
6819 currently valid, if so, do NOT tell core anything! */
6820 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
6821 if ((NULL != dv) && (GNUNET_YES == dv->core_visible))
6822 return; /* nothing changed, done */
6823 /* We lacked a confirmed connection to the neighbour
6824 before, so tell CORE about it (finally!) */
6825 cores_send_connect_info (&n->pid,
6827 ? GNUNET_BANDWIDTH_value_sum (dv->quota_out,
6834 * Incoming meessage. Process the request.
6836 * @param im the send message that was received
6839 handle_incoming_msg (void *cls,
6840 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6842 struct TransportClient *tc = cls;
6843 struct CommunicatorMessageContext *cmc =
6844 GNUNET_new (struct CommunicatorMessageContext);
6848 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
6853 * Given an inbound message @a msg from a communicator @a cmc,
6854 * demultiplex it based on the type calling the right handler.
6856 * @param cmc context for demultiplexing
6857 * @param msg message to demultiplex
6860 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
6861 const struct GNUNET_MessageHeader *msg)
6863 struct GNUNET_MQ_MessageHandler handlers[] =
6864 {GNUNET_MQ_hd_var_size (fragment_box,
6865 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
6866 struct TransportFragmentBoxMessage,
6868 GNUNET_MQ_hd_var_size (reliability_box,
6869 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
6870 struct TransportReliabilityBoxMessage,
6872 GNUNET_MQ_hd_var_size (reliability_ack,
6873 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
6874 struct TransportReliabilityAckMessage,
6876 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
6877 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
6878 struct TransportBackchannelEncapsulationMessage,
6880 GNUNET_MQ_hd_var_size (dv_learn,
6881 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
6882 struct TransportDVLearnMessage,
6884 GNUNET_MQ_hd_var_size (dv_box,
6885 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
6886 struct TransportDVBoxMessage,
6888 GNUNET_MQ_hd_fixed_size (
6889 validation_challenge,
6890 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
6891 struct TransportValidationChallengeMessage,
6893 GNUNET_MQ_hd_fixed_size (
6894 validation_response,
6895 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
6896 struct TransportValidationResponseMessage,
6898 GNUNET_MQ_handler_end ()};
6901 ret = GNUNET_MQ_handle_message (handlers, msg);
6902 if (GNUNET_SYSERR == ret)
6905 GNUNET_SERVICE_client_drop (cmc->tc->client);
6909 if (GNUNET_NO == ret)
6911 /* unencapsulated 'raw' message */
6912 handle_raw_message (&cmc, msg);
6918 * New queue became available. Check message.
6920 * @param cls the client
6921 * @param aqm the send message that was sent
6924 check_add_queue_message (void *cls,
6925 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6927 struct TransportClient *tc = cls;
6929 if (CT_COMMUNICATOR != tc->type)
6932 return GNUNET_SYSERR;
6934 GNUNET_MQ_check_zero_termination (aqm);
6940 * Bandwidth tracker informs us that the delay until we should receive
6943 * @param cls a `struct Queue` for which the delay changed
6946 tracker_update_in_cb (void *cls)
6948 struct Queue *queue = cls;
6949 struct GNUNET_TIME_Relative in_delay;
6952 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
6953 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
6954 // FIXME: how exactly do we do inbound flow control?
6959 * If necessary, generates the UUID for a @a pm
6961 * @param pm pending message to generate UUID for.
6964 set_pending_message_uuid (struct PendingMessage *pm)
6966 if (pm->msg_uuid_set)
6968 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6970 sizeof (pm->msg_uuid));
6971 pm->msg_uuid_set = GNUNET_YES;
6976 * Setup data structure waiting for acknowledgements.
6978 * @param queue queue the @a pm will be sent over
6979 * @param dvh path the message will take, may be NULL
6980 * @param pm the pending message for transmission
6981 * @return corresponding fresh pending acknowledgement
6983 static struct PendingAcknowledgement *
6984 prepare_pending_acknowledgement (struct Queue *queue,
6985 struct DistanceVectorHop *dvh,
6986 struct PendingMessage *pm)
6988 struct PendingAcknowledgement *pa;
6990 pa = GNUNET_new (struct PendingAcknowledgement);
6996 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6998 sizeof (pa->ack_uuid));
6999 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7001 &pa->ack_uuid.value,
7003 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7004 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7005 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7007 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7008 pa->transmission_time = GNUNET_TIME_absolute_get ();
7009 pa->message_size = pm->bytes_msg;
7015 * Fragment the given @a pm to the given @a mtu. Adds
7016 * additional fragments to the neighbour as well. If the
7017 * @a mtu is too small, generates and error for the @a pm
7020 * @param queue which queue to fragment for
7021 * @param dvh path the message will take, or NULL
7022 * @param pm pending message to fragment for transmission
7023 * @return new message to transmit
7025 static struct PendingMessage *
7026 fragment_message (struct Queue *queue,
7027 struct DistanceVectorHop *dvh,
7028 struct PendingMessage *pm)
7030 struct PendingAcknowledgement *pa;
7031 struct PendingMessage *ff;
7034 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7035 mtu = (0 == queue->mtu)
7036 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7038 set_pending_message_uuid (pm);
7040 /* This invariant is established in #handle_add_queue_message() */
7041 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7043 /* select fragment for transmission, descending the tree if it has
7044 been expanded until we are at a leaf or at a fragment that is small
7048 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7049 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7051 ff = ff->head_frag; /* descent into fragmented fragments */
7054 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7056 /* Did not yet calculate all fragments, calculate next fragment */
7057 struct PendingMessage *frag;
7058 struct TransportFragmentBoxMessage tfb;
7066 orig = (const char *) &ff[1];
7067 msize = ff->bytes_msg;
7070 const struct TransportFragmentBoxMessage *tfbo;
7072 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7073 orig += sizeof (struct TransportFragmentBoxMessage);
7074 msize -= sizeof (struct TransportFragmentBoxMessage);
7075 xoff = ntohs (tfbo->frag_off);
7077 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7078 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7080 GNUNET_malloc (sizeof (struct PendingMessage) +
7081 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7082 frag->target = pm->target;
7083 frag->frag_parent = ff;
7084 frag->timeout = pm->timeout;
7085 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7086 frag->pmt = PMT_FRAGMENT_BOX;
7087 msg = (char *) &frag[1];
7088 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7090 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7091 tfb.ack_uuid = pa->ack_uuid;
7092 tfb.msg_uuid = pm->msg_uuid;
7093 tfb.frag_off = htons (ff->frag_off + xoff);
7094 tfb.msg_size = htons (pm->bytes_msg);
7095 memcpy (msg, &tfb, sizeof (tfb));
7096 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7097 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7098 ff->frag_off += fragsize;
7102 /* Move head to the tail and return it */
7103 GNUNET_CONTAINER_MDLL_remove (frag,
7104 ff->frag_parent->head_frag,
7105 ff->frag_parent->tail_frag,
7107 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7108 ff->frag_parent->head_frag,
7109 ff->frag_parent->tail_frag,
7116 * Reliability-box the given @a pm. On error (can there be any), NULL
7117 * may be returned, otherwise the "replacement" for @a pm (which
7118 * should then be added to the respective neighbour's queue instead of
7119 * @a pm). If the @a pm is already fragmented or reliability boxed,
7120 * or itself an ACK, this function simply returns @a pm.
7122 * @param queue which queue to prepare transmission for
7123 * @param dvh path the message will take, or NULL
7124 * @param pm pending message to box for transmission over unreliabile queue
7125 * @return new message to transmit
7127 static struct PendingMessage *
7128 reliability_box_message (struct Queue *queue,
7129 struct DistanceVectorHop *dvh,
7130 struct PendingMessage *pm)
7132 struct TransportReliabilityBoxMessage rbox;
7133 struct PendingAcknowledgement *pa;
7134 struct PendingMessage *bpm;
7137 if (PMT_CORE != pm->pmt)
7138 return pm; /* already fragmented or reliability boxed, or control message:
7140 if (NULL != pm->bpm)
7141 return pm->bpm; /* already computed earlier: do nothing */
7142 GNUNET_assert (NULL == pm->head_frag);
7143 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7147 client_send_response (pm, GNUNET_NO, 0);
7150 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7152 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7154 bpm->target = pm->target;
7155 bpm->frag_parent = pm;
7156 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7157 bpm->timeout = pm->timeout;
7158 bpm->pmt = PMT_RELIABILITY_BOX;
7159 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7160 set_pending_message_uuid (bpm);
7161 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7162 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7163 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7165 rbox.ack_uuid = pa->ack_uuid;
7166 msg = (char *) &bpm[1];
7167 memcpy (msg, &rbox, sizeof (rbox));
7168 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7175 * Change the value of the `next_attempt` field of @a pm
7176 * to @a next_attempt and re-order @a pm in the transmission
7177 * list as required by the new timestmap.
7179 * @param pm a pending message to update
7180 * @param next_attempt timestamp to use
7183 update_pm_next_attempt (struct PendingMessage *pm,
7184 struct GNUNET_TIME_Absolute next_attempt)
7186 struct Neighbour *neighbour = pm->target;
7188 pm->next_attempt = next_attempt;
7189 if (NULL == pm->frag_parent)
7191 struct PendingMessage *pos;
7193 /* re-insert sort in neighbour list */
7194 GNUNET_CONTAINER_MDLL_remove (neighbour,
7195 neighbour->pending_msg_head,
7196 neighbour->pending_msg_tail,
7198 pos = neighbour->pending_msg_tail;
7199 while ((NULL != pos) &&
7200 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7201 pos = pos->prev_neighbour;
7202 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7203 neighbour->pending_msg_head,
7204 neighbour->pending_msg_tail,
7210 /* re-insert sort in fragment list */
7211 struct PendingMessage *fp = pm->frag_parent;
7212 struct PendingMessage *pos;
7214 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7215 pos = fp->tail_frag;
7216 while ((NULL != pos) &&
7217 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7218 pos = pos->prev_frag;
7219 GNUNET_CONTAINER_MDLL_insert_after (frag,
7229 * We believe we are ready to transmit a message on a queue. Double-checks
7230 * with the queue's "tracker_out" and then gives the message to the
7231 * communicator for transmission (updating the tracker, and re-scheduling
7232 * itself if applicable).
7234 * @param cls the `struct Queue` to process transmissions for
7237 transmit_on_queue (void *cls)
7239 struct Queue *queue = cls;
7240 struct Neighbour *n = queue->neighbour;
7241 struct PendingMessage *pm;
7242 struct PendingMessage *s;
7245 queue->transmit_task = NULL;
7246 if (NULL == (pm = n->pending_msg_head))
7248 /* no message pending, nothing to do here! */
7253 /* message still pending with communciator!
7254 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7257 schedule_transmit_on_queue (queue, GNUNET_YES);
7258 if (NULL != queue->transmit_task)
7259 return; /* do it later */
7261 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7262 overhead += sizeof (struct TransportReliabilityBoxMessage);
7264 if ( ( (0 != queue->mtu) &&
7265 (pm->bytes_msg + overhead > queue->mtu) ) ||
7266 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7267 (NULL != pm->head_frag /* fragments already exist, should
7268 respect that even if MTU is 0 for
7270 s = fragment_message (queue, NULL /*FIXME! */, s);
7273 /* Fragmentation failed, try next message... */
7274 schedule_transmit_on_queue (queue, GNUNET_NO);
7277 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7278 s = reliability_box_message (queue, NULL /* FIXME! */, s);
7281 /* Reliability boxing failed, try next message... */
7282 schedule_transmit_on_queue (queue, GNUNET_NO);
7286 /* Pass 's' for transission to the communicator */
7287 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7288 // FIXME: do something similar to the logic below
7289 // in defragmentation / reliability ACK handling!
7291 /* Check if this transmission somehow conclusively finished handing 'pm'
7292 even without any explicit ACKs */
7293 if ((PMT_CORE == s->pmt) &&
7294 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7296 /* Full message sent, and over reliabile channel */
7297 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
7299 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7300 queue->tc->details.communicator.cc) &&
7301 (PMT_FRAGMENT_BOX == s->pmt))
7303 struct PendingMessage *pos;
7305 /* Fragment sent over reliabile channel */
7306 free_fragment_tree (s);
7307 pos = s->frag_parent;
7308 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7310 /* check if subtree is done */
7311 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7315 pos = s->frag_parent;
7316 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7320 /* Was this the last applicable fragmment? */
7321 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7322 client_send_response (
7325 pm->bytes_msg /* FIXME: calculate and add overheads! */);
7327 else if (PMT_CORE != pm->pmt)
7329 /* This was an acknowledgement of some type, always free */
7330 free_pending_message (pm);
7334 /* Message not finished, waiting for acknowledgement.
7335 Update time by which we might retransmit 's' based on queue
7336 characteristics (i.e. RTT); it takes one RTT for the message to
7337 arrive and the ACK to come back in the best case; but the other
7338 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7339 retransmitting. Note that in the future this heuristic should
7340 likely be improved further (measure RTT stability, consider
7341 message urgency and size when delaying ACKs, etc.) */
7342 update_pm_next_attempt (s,
7343 GNUNET_TIME_relative_to_absolute (
7344 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7348 /* finally, re-schedule queue transmission task itself */
7349 schedule_transmit_on_queue (queue, GNUNET_NO);
7354 * Bandwidth tracker informs us that the delay until we
7355 * can transmit again changed.
7357 * @param cls a `struct Queue` for which the delay changed
7360 tracker_update_out_cb (void *cls)
7362 struct Queue *queue = cls;
7363 struct Neighbour *n = queue->neighbour;
7365 if (NULL == n->pending_msg_head)
7367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7368 "Bandwidth allocation updated for empty transmission queue `%s'\n",
7370 return; /* no message pending, nothing to do here! */
7372 GNUNET_SCHEDULER_cancel (queue->transmit_task);
7373 queue->transmit_task = NULL;
7374 schedule_transmit_on_queue (queue, GNUNET_NO);
7379 * Bandwidth tracker informs us that excessive outbound bandwidth was
7380 * allocated which is not being used.
7382 * @param cls a `struct Queue` for which the excess was noted
7385 tracker_excess_out_cb (void *cls)
7389 /* FIXME: trigger excess bandwidth report to core? Right now,
7390 this is done internally within transport_api2_core already,
7391 but we probably want to change the logic and trigger it
7392 from here via a message instead! */
7393 /* TODO: maybe inform someone at this point? */
7394 GNUNET_STATISTICS_update (GST_stats,
7395 "# Excess outbound bandwidth reported",
7402 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
7403 * which is not being used.
7405 * @param cls a `struct Queue` for which the excess was noted
7408 tracker_excess_in_cb (void *cls)
7412 /* TODO: maybe inform somone at this point? */
7413 GNUNET_STATISTICS_update (GST_stats,
7414 "# Excess inbound bandwidth reported",
7421 * Queue to a peer went down. Process the request.
7423 * @param cls the client
7424 * @param dqm the send message that was sent
7427 handle_del_queue_message (void *cls,
7428 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7430 struct TransportClient *tc = cls;
7432 if (CT_COMMUNICATOR != tc->type)
7435 GNUNET_SERVICE_client_drop (tc->client);
7438 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7439 queue = queue->next_client)
7441 struct Neighbour *neighbour = queue->neighbour;
7443 if ((dqm->qid != queue->qid) ||
7444 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7447 GNUNET_SERVICE_client_continue (tc->client);
7451 GNUNET_SERVICE_client_drop (tc->client);
7456 * Message was transmitted. Process the request.
7458 * @param cls the client
7459 * @param sma the send message that was sent
7462 handle_send_message_ack (void *cls,
7463 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7465 struct TransportClient *tc = cls;
7466 struct QueueEntry *qe;
7467 struct PendingMessage *pm;
7469 if (CT_COMMUNICATOR != tc->type)
7472 GNUNET_SERVICE_client_drop (tc->client);
7476 /* find our queue entry matching the ACK */
7478 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7479 queue = queue->next_client)
7481 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7483 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7486 if (qep->mid != sma->mid)
7495 /* this should never happen */
7497 GNUNET_SERVICE_client_drop (tc->client);
7500 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7501 qe->queue->queue_tail,
7503 qe->queue->queue_length--;
7504 tc->details.communicator.total_queue_length--;
7505 GNUNET_SERVICE_client_continue (tc->client);
7507 /* if applicable, resume transmissions that waited on ACK */
7508 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7509 tc->details.communicator.total_queue_length)
7511 /* Communicator dropped below threshold, resume all queues
7512 incident with this client! */
7513 GNUNET_STATISTICS_update (
7515 "# Transmission throttled due to communicator queue limit",
7518 for (struct Queue *queue = tc->details.communicator.queue_head;
7520 queue = queue->next_client)
7521 schedule_transmit_on_queue (queue, GNUNET_NO);
7523 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7525 /* queue dropped below threshold; only resume this one queue */
7526 GNUNET_STATISTICS_update (GST_stats,
7527 "# Transmission throttled due to queue queue limit",
7530 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7533 if (NULL != (pm = qe->pm))
7535 struct Neighbour *n;
7537 GNUNET_assert (qe == pm->qe);
7539 /* If waiting for this communicator may have blocked transmission
7540 of pm on other queues for this neighbour, force schedule
7541 transmit on queue for queues of the neighbour */
7543 if (n->pending_msg_head == pm)
7545 for (struct Queue *queue = n->queue_head; NULL != queue;
7546 queue = queue->next_neighbour)
7547 schedule_transmit_on_queue (queue, GNUNET_NO);
7549 if (GNUNET_OK != ntohl (sma->status))
7552 GNUNET_ERROR_TYPE_INFO,
7553 "Queue failed in transmission, will try retransmission immediately\n");
7554 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7562 * Iterator telling new MONITOR client about all existing
7565 * @param cls the new `struct TransportClient`
7566 * @param pid a connected peer
7567 * @param value the `struct Neighbour` with more information
7568 * @return #GNUNET_OK (continue to iterate)
7571 notify_client_queues (void *cls,
7572 const struct GNUNET_PeerIdentity *pid,
7575 struct TransportClient *tc = cls;
7576 struct Neighbour *neighbour = value;
7578 GNUNET_assert (CT_MONITOR == tc->type);
7579 for (struct Queue *q = neighbour->queue_head; NULL != q;
7580 q = q->next_neighbour)
7582 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7584 .num_msg_pending = q->num_msg_pending,
7585 .num_bytes_pending = q->num_bytes_pending};
7587 notify_monitor (tc, pid, q->address, q->nt, &me);
7594 * Initialize a monitor client.
7596 * @param cls the client
7597 * @param start the start message that was sent
7600 handle_monitor_start (void *cls,
7601 const struct GNUNET_TRANSPORT_MonitorStart *start)
7603 struct TransportClient *tc = cls;
7605 if (CT_NONE != tc->type)
7608 GNUNET_SERVICE_client_drop (tc->client);
7611 tc->type = CT_MONITOR;
7612 tc->details.monitor.peer = start->peer;
7613 tc->details.monitor.one_shot = ntohl (start->one_shot);
7614 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
7615 GNUNET_SERVICE_client_mark_monitor (tc->client);
7616 GNUNET_SERVICE_client_continue (tc->client);
7621 * Find transport client providing communication service
7622 * for the protocol @a prefix.
7624 * @param prefix communicator name
7625 * @return NULL if no such transport client is available
7627 static struct TransportClient *
7628 lookup_communicator (const char *prefix)
7630 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7632 if (CT_COMMUNICATOR != tc->type)
7634 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
7638 GNUNET_ERROR_TYPE_WARNING,
7639 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
7646 * Signature of a function called with a communicator @a address of a peer
7647 * @a pid that an application wants us to connect to.
7649 * @param pid target peer
7650 * @param address the address to try
7653 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
7655 static uint32_t idgen;
7656 struct TransportClient *tc;
7658 struct GNUNET_TRANSPORT_CreateQueue *cqm;
7659 struct GNUNET_MQ_Envelope *env;
7662 prefix = GNUNET_HELLO_address_to_prefix (address);
7665 GNUNET_break (0); /* We got an invalid address!? */
7668 tc = lookup_communicator (prefix);
7671 GNUNET_STATISTICS_update (GST_stats,
7672 "# Suggestions ignored due to missing communicator",
7677 /* forward suggestion for queue creation to communicator */
7678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7679 "Request #%u for `%s' communicator to create queue to `%s'\n",
7680 (unsigned int) idgen,
7683 alen = strlen (address) + 1;
7685 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
7686 cqm->request_id = htonl (idgen++);
7687 cqm->receiver = *pid;
7688 memcpy (&cqm[1], address, alen);
7689 GNUNET_MQ_send (tc->mq, env);
7694 * The queue @a q (which matches the peer and address in @a vs) is
7695 * ready for queueing. We should now queue the validation request.
7697 * @param q queue to send on
7698 * @param vs state to derive validation challenge from
7701 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
7703 struct TransportValidationChallengeMessage tvc;
7705 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
7707 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
7708 tvc.header.size = htons (sizeof (tvc));
7709 tvc.reserved = htonl (0);
7710 tvc.challenge = vs->challenge;
7711 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
7712 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7717 * Task run periodically to validate some address based on #validation_heap.
7722 validation_start_cb (void *cls)
7724 struct ValidationState *vs;
7728 validation_task = NULL;
7729 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7730 /* drop validations past their expiration */
7733 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7735 free_validation_state (vs);
7736 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7739 return; /* woopsie, no more addresses known, should only
7740 happen if we're really a lonely peer */
7741 q = find_queue (&vs->pid, vs->address);
7744 vs->awaiting_queue = GNUNET_YES;
7745 suggest_to_connect (&vs->pid, vs->address);
7748 validation_transmit_on_queue (q, vs);
7749 /* Finally, reschedule next attempt */
7750 vs->challenge_backoff =
7751 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
7752 MAX_VALIDATION_CHALLENGE_FREQ);
7753 update_next_challenge_time (vs,
7754 GNUNET_TIME_relative_to_absolute (
7755 vs->challenge_backoff));
7760 * Closure for #check_connection_quality.
7762 struct QueueQualityContext
7765 * Set to the @e k'th queue encountered.
7770 * Set to the number of quality queues encountered.
7772 unsigned int quality_count;
7775 * Set to the total number of queues encountered.
7777 unsigned int num_queues;
7780 * Decremented for each queue, for selection of the
7781 * k-th queue in @e q.
7788 * Check whether any queue to the given neighbour is
7789 * of a good "quality" and if so, increment the counter.
7790 * Also counts the total number of queues, and returns
7791 * the k-th queue found.
7793 * @param cls a `struct QueueQualityContext *` with counters
7794 * @param pid peer this is about
7795 * @param value a `struct Neighbour`
7796 * @return #GNUNET_OK (continue to iterate)
7799 check_connection_quality (void *cls,
7800 const struct GNUNET_PeerIdentity *pid,
7803 struct QueueQualityContext *ctx = cls;
7804 struct Neighbour *n = value;
7809 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7814 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
7815 statistics and consider those as well here? */
7816 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
7817 do_inc = GNUNET_YES;
7819 if (GNUNET_YES == do_inc)
7820 ctx->quality_count++;
7826 * Task run when we CONSIDER initiating a DV learn
7827 * process. We first check that sending out a message is
7828 * even possible (queues exist), then that it is desirable
7829 * (if not, reschedule the task for later), and finally
7830 * we may then begin the job. If there are too many
7831 * entries in the #dvlearn_map, we purge the oldest entry
7837 start_dv_learn (void *cls)
7839 struct LearnLaunchEntry *lle;
7840 struct QueueQualityContext qqc;
7841 struct TransportDVLearnMessage dvl;
7844 dvlearn_task = NULL;
7845 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
7846 return; /* lost all connectivity, cannot do learning */
7847 qqc.quality_count = 0;
7849 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7850 &check_connection_quality,
7852 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
7854 struct GNUNET_TIME_Relative delay;
7855 unsigned int factor;
7857 /* scale our retries by how far we are above the threshold */
7858 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
7859 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
7860 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
7863 /* remove old entries in #dvlearn_map if it has grown too big */
7864 while (MAX_DV_LEARN_PENDING >=
7865 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
7868 GNUNET_assert (GNUNET_YES ==
7869 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
7870 &lle->challenge.value,
7872 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7875 /* setup data structure for learning */
7876 lle = GNUNET_new (struct LearnLaunchEntry);
7877 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7879 sizeof (lle->challenge));
7880 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
7881 GNUNET_break (GNUNET_YES ==
7882 GNUNET_CONTAINER_multishortmap_put (
7884 &lle->challenge.value,
7886 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7887 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
7888 dvl.header.size = htons (sizeof (dvl));
7889 dvl.num_hops = htons (0);
7890 dvl.bidirectional = htons (0);
7891 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
7893 struct DvInitPS dvip = {.purpose.purpose = htonl (
7894 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
7895 .purpose.size = htonl (sizeof (dvip)),
7896 .challenge = lle->challenge};
7898 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7902 dvl.initiator = GST_my_identity;
7903 dvl.challenge = lle->challenge;
7905 qqc.quality_count = 0;
7906 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
7909 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7910 &check_connection_quality,
7912 GNUNET_assert (NULL != qqc.q);
7914 /* Do this as close to transmission time as possible! */
7915 lle->launch_time = GNUNET_TIME_absolute_get ();
7917 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
7918 /* reschedule this job, randomizing the time it runs (but no
7920 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
7921 DV_LEARN_BASE_FREQUENCY),
7928 * A new queue has been created, check if any address validation
7929 * requests have been waiting for it.
7931 * @param cls a `struct Queue`
7932 * @param pid peer concerned (unused)
7933 * @param value a `struct ValidationState`
7934 * @return #GNUNET_NO if a match was found and we can stop looking
7937 check_validation_request_pending (void *cls,
7938 const struct GNUNET_PeerIdentity *pid,
7941 struct Queue *q = cls;
7942 struct ValidationState *vs = value;
7945 if ((GNUNET_YES == vs->awaiting_queue) &&
7946 (0 == strcmp (vs->address, q->address)))
7948 vs->awaiting_queue = GNUNET_NO;
7949 validation_transmit_on_queue (q, vs);
7957 * New queue became available. Process the request.
7959 * @param cls the client
7960 * @param aqm the send message that was sent
7963 handle_add_queue_message (void *cls,
7964 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7966 struct TransportClient *tc = cls;
7967 struct Queue *queue;
7968 struct Neighbour *neighbour;
7972 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
7974 /* MTU so small as to be useless for transmissions,
7975 required for #fragment_message()! */
7976 GNUNET_break_op (0);
7977 GNUNET_SERVICE_client_drop (tc->client);
7980 neighbour = lookup_neighbour (&aqm->receiver);
7981 if (NULL == neighbour)
7983 neighbour = GNUNET_new (struct Neighbour);
7984 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
7985 neighbour->pid = aqm->receiver;
7986 GNUNET_assert (GNUNET_OK ==
7987 GNUNET_CONTAINER_multipeermap_put (
7991 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7993 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
7994 addr = (const char *) &aqm[1];
7996 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
7998 queue->address = (const char *) &queue[1];
7999 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8000 queue->qid = aqm->qid;
8001 queue->mtu = ntohl (aqm->mtu);
8002 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8003 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8004 queue->neighbour = neighbour;
8005 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
8006 &tracker_update_in_cb,
8008 GNUNET_BANDWIDTH_ZERO,
8009 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
8010 &tracker_excess_in_cb,
8012 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
8013 &tracker_update_out_cb,
8015 GNUNET_BANDWIDTH_ZERO,
8016 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
8017 &tracker_excess_out_cb,
8019 memcpy (&queue[1], addr, addr_len);
8020 /* notify monitors about new queue */
8022 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8024 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8026 GNUNET_CONTAINER_MDLL_insert (neighbour,
8027 neighbour->queue_head,
8028 neighbour->queue_tail,
8030 GNUNET_CONTAINER_MDLL_insert (client,
8031 tc->details.communicator.queue_head,
8032 tc->details.communicator.queue_tail,
8034 /* check if valdiations are waiting for the queue */
8036 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8038 &check_validation_request_pending,
8040 /* might be our first queue, try launching DV learning */
8041 if (NULL == dvlearn_task)
8042 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8043 GNUNET_SERVICE_client_continue (tc->client);
8048 * Communicator tells us that our request to create a queue "worked", that
8049 * is setting up the queue is now in process.
8051 * @param cls the `struct TransportClient`
8052 * @param cqr confirmation message
8055 handle_queue_create_ok (void *cls,
8056 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8058 struct TransportClient *tc = cls;
8060 if (CT_COMMUNICATOR != tc->type)
8063 GNUNET_SERVICE_client_drop (tc->client);
8066 GNUNET_STATISTICS_update (GST_stats,
8067 "# Suggestions succeeded at communicator",
8070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8071 "Request #%u for communicator to create queue succeeded\n",
8072 (unsigned int) ntohs (cqr->request_id));
8073 GNUNET_SERVICE_client_continue (tc->client);
8078 * Communicator tells us that our request to create a queue failed. This
8079 * usually indicates that the provided address is simply invalid or that the
8080 * communicator's resources are exhausted.
8082 * @param cls the `struct TransportClient`
8083 * @param cqr failure message
8086 handle_queue_create_fail (
8088 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8090 struct TransportClient *tc = cls;
8092 if (CT_COMMUNICATOR != tc->type)
8095 GNUNET_SERVICE_client_drop (tc->client);
8098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8099 "Request #%u for communicator to create queue failed\n",
8100 (unsigned int) ntohs (cqr->request_id));
8101 GNUNET_STATISTICS_update (GST_stats,
8102 "# Suggestions failed in queue creation at communicator",
8105 GNUNET_SERVICE_client_continue (tc->client);
8110 * We have received a `struct ExpressPreferenceMessage` from an application
8113 * @param cls handle to the client
8114 * @param msg the start message
8117 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8119 struct TransportClient *tc = cls;
8120 struct PeerRequest *pr;
8122 if (CT_APPLICATION != tc->type)
8125 GNUNET_SERVICE_client_drop (tc->client);
8128 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8133 GNUNET_SERVICE_client_drop (tc->client);
8136 (void) stop_peer_request (tc, &pr->pid, pr);
8137 GNUNET_SERVICE_client_continue (tc->client);
8142 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8143 * messages. We do nothing here, real verification is done later.
8145 * @param cls a `struct TransportClient *`
8146 * @param msg message to verify
8147 * @return #GNUNET_OK
8150 check_address_consider_verify (
8152 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8161 * Closure for #check_known_address.
8163 struct CheckKnownAddressContext
8166 * Set to the address we are looking for.
8168 const char *address;
8171 * Set to a matching validation state, if one was found.
8173 struct ValidationState *vs;
8178 * Test if the validation state in @a value matches the
8179 * address from @a cls.
8181 * @param cls a `struct CheckKnownAddressContext`
8182 * @param pid unused (must match though)
8183 * @param value a `struct ValidationState`
8184 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8187 check_known_address (void *cls,
8188 const struct GNUNET_PeerIdentity *pid,
8191 struct CheckKnownAddressContext *ckac = cls;
8192 struct ValidationState *vs = value;
8195 if (0 != strcmp (vs->address, ckac->address))
8203 * Start address validation.
8205 * @param pid peer the @a address is for
8206 * @param address an address to reach @a pid (presumably)
8207 * @param expiration when did @a pid claim @a address will become invalid
8210 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8211 const char *address,
8212 struct GNUNET_TIME_Absolute expiration)
8214 struct GNUNET_TIME_Absolute now;
8215 struct ValidationState *vs;
8216 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8218 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
8219 return; /* expired */
8220 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8222 &check_known_address,
8224 if (NULL != (vs = ckac.vs))
8226 /* if 'vs' is not currently valid, we need to speed up retrying the
8228 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8230 /* reduce backoff as we got a fresh advertisement */
8231 vs->challenge_backoff =
8232 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8233 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8235 update_next_challenge_time (vs,
8236 GNUNET_TIME_relative_to_absolute (
8237 vs->challenge_backoff));
8241 now = GNUNET_TIME_absolute_get ();
8242 vs = GNUNET_new (struct ValidationState);
8244 vs->valid_until = expiration;
8245 vs->first_challenge_use = now;
8246 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8247 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8249 sizeof (vs->challenge));
8250 vs->address = GNUNET_strdup (address);
8251 GNUNET_assert (GNUNET_YES ==
8252 GNUNET_CONTAINER_multipeermap_put (
8256 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8257 update_next_challenge_time (vs, now);
8262 * Function called by PEERSTORE for each matching record.
8264 * @param cls closure
8265 * @param record peerstore record information
8266 * @param emsg error message, or NULL if no errors
8269 handle_hello (void *cls,
8270 const struct GNUNET_PEERSTORE_Record *record,
8273 struct PeerRequest *pr = cls;
8278 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8279 "Got failure from PEERSTORE: %s\n",
8283 val = record->value;
8284 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8289 start_address_validation (&pr->pid,
8290 (const char *) record->value,
8296 * We have received a `struct ExpressPreferenceMessage` from an application
8299 * @param cls handle to the client
8300 * @param msg the start message
8303 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8305 struct TransportClient *tc = cls;
8306 struct PeerRequest *pr;
8308 if (CT_NONE == tc->type)
8310 tc->type = CT_APPLICATION;
8311 tc->details.application.requests =
8312 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8314 if (CT_APPLICATION != tc->type)
8317 GNUNET_SERVICE_client_drop (tc->client);
8320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8321 "Client suggested we talk to %s with preference %d at rate %u\n",
8322 GNUNET_i2s (&msg->peer),
8323 (int) ntohl (msg->pk),
8324 (int) ntohl (msg->bw.value__));
8325 pr = GNUNET_new (struct PeerRequest);
8327 pr->pid = msg->peer;
8329 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
8330 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8331 tc->details.application.requests,
8334 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8338 GNUNET_SERVICE_client_drop (tc->client);
8341 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8344 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8347 GNUNET_SERVICE_client_continue (tc->client);
8352 * Given another peers address, consider checking it for validity
8353 * and then adding it to the Peerstore.
8355 * @param cls a `struct TransportClient`
8356 * @param hdr message containing the raw address data and
8357 * signature in the body, see #GNUNET_HELLO_extract_address()
8360 handle_address_consider_verify (
8362 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8364 struct TransportClient *tc = cls;
8366 enum GNUNET_NetworkType nt;
8367 struct GNUNET_TIME_Absolute expiration;
8370 // OPTIMIZE-FIXME: checking that we know this address already should
8371 // be done BEFORE checking the signature => HELLO API change!
8372 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8375 GNUNET_HELLO_extract_address (&hdr[1],
8376 ntohs (hdr->header.size) - sizeof (*hdr),
8380 if (NULL == address)
8382 GNUNET_break_op (0);
8385 start_address_validation (&hdr->peer, address, expiration);
8386 GNUNET_free (address);
8387 GNUNET_SERVICE_client_continue (tc->client);
8392 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8395 * @param cls a `struct TransportClient *`
8396 * @param m message to verify
8397 * @return #GNUNET_OK on success
8400 check_request_hello_validation (void *cls,
8401 const struct RequestHelloValidationMessage *m)
8404 GNUNET_MQ_check_zero_termination (m);
8410 * A client encountered an address of another peer. Consider validating it,
8411 * and if validation succeeds, persist it to PEERSTORE.
8413 * @param cls a `struct TransportClient *`
8414 * @param m message to verify
8417 handle_request_hello_validation (void *cls,
8418 const struct RequestHelloValidationMessage *m)
8420 struct TransportClient *tc = cls;
8422 start_address_validation (&m->peer,
8423 (const char *) &m[1],
8424 GNUNET_TIME_absolute_ntoh (m->expiration));
8425 GNUNET_SERVICE_client_continue (tc->client);
8430 * Free neighbour entry.
8434 * @param value a `struct Neighbour`
8435 * @return #GNUNET_OK (always)
8438 free_neighbour_cb (void *cls,
8439 const struct GNUNET_PeerIdentity *pid,
8442 struct Neighbour *neighbour = value;
8446 GNUNET_break (0); // should this ever happen?
8447 free_neighbour (neighbour);
8454 * Free DV route entry.
8458 * @param value a `struct DistanceVector`
8459 * @return #GNUNET_OK (always)
8462 free_dv_routes_cb (void *cls,
8463 const struct GNUNET_PeerIdentity *pid,
8466 struct DistanceVector *dv = value;
8477 * Free ephemeral entry.
8481 * @param value a `struct EphemeralCacheEntry`
8482 * @return #GNUNET_OK (always)
8485 free_ephemeral_cb (void *cls,
8486 const struct GNUNET_PeerIdentity *pid,
8489 struct EphemeralCacheEntry *ece = value;
8493 free_ephemeral (ece);
8499 * Free validation state.
8503 * @param value a `struct ValidationState`
8504 * @return #GNUNET_OK (always)
8507 free_validation_state_cb (void *cls,
8508 const struct GNUNET_PeerIdentity *pid,
8511 struct ValidationState *vs = value;
8515 free_validation_state (vs);
8521 * Free pending acknowledgement.
8525 * @param value a `struct PendingAcknowledgement`
8526 * @return #GNUNET_OK (always)
8529 free_pending_ack_cb (void *cls,
8530 const struct GNUNET_ShortHashCode *key,
8533 struct PendingAcknowledgement *pa = value;
8537 free_pending_acknowledgement (pa);
8543 * Free acknowledgement cummulator.
8547 * @param value a `struct AcknowledgementCummulator`
8548 * @return #GNUNET_OK (always)
8551 free_ack_cummulator_cb (void *cls,
8552 const struct GNUNET_PeerIdentity *pid,
8555 struct AcknowledgementCummulator *ac = value;
8565 * Function called when the service shuts down. Unloads our plugins
8566 * and cancels pending validations.
8568 * @param cls closure, unused
8571 do_shutdown (void *cls)
8573 struct LearnLaunchEntry *lle;
8576 if (NULL != ephemeral_task)
8578 GNUNET_SCHEDULER_cancel (ephemeral_task);
8579 ephemeral_task = NULL;
8581 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
8582 if (NULL != peerstore)
8584 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
8587 if (NULL != GST_stats)
8589 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
8592 if (NULL != GST_my_private_key)
8594 GNUNET_free (GST_my_private_key);
8595 GST_my_private_key = NULL;
8597 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
8598 &free_ack_cummulator_cb,
8600 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
8601 ack_cummulators = NULL;
8602 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
8603 &free_pending_ack_cb,
8605 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
8606 pending_acks = NULL;
8607 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
8609 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
8610 &free_backtalker_cb,
8612 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
8614 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
8615 &free_validation_state_cb,
8617 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
8618 validation_map = NULL;
8619 while (NULL != (lle = lle_head))
8621 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8624 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
8626 GNUNET_CONTAINER_heap_destroy (validation_heap);
8627 validation_heap = NULL;
8628 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
8629 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
8631 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
8634 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
8635 ephemeral_map = NULL;
8636 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
8637 ephemeral_heap = NULL;
8642 * Initiate transport service.
8644 * @param cls closure
8645 * @param c configuration to use
8646 * @param service the initialized service
8650 const struct GNUNET_CONFIGURATION_Handle *c,
8651 struct GNUNET_SERVICE_Handle *service)
8657 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8658 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
8659 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
8660 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8661 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8662 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
8664 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8665 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
8667 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8669 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8670 GST_my_private_key =
8671 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
8672 if (NULL == GST_my_private_key)
8675 GNUNET_ERROR_TYPE_ERROR,
8677 "Transport service is lacking key configuration settings. Exiting.\n"));
8678 GNUNET_SCHEDULER_shutdown ();
8681 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
8682 &GST_my_identity.public_key);
8683 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8684 "My identity is `%s'\n",
8685 GNUNET_i2s_full (&GST_my_identity));
8686 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
8687 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
8688 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
8689 if (NULL == peerstore)
8692 GNUNET_SCHEDULER_shutdown ();
8699 * Define "main" method using service macro.
8701 GNUNET_SERVICE_MAIN (
8703 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
8706 &client_disconnect_cb,
8708 /* communication with applications */
8709 GNUNET_MQ_hd_fixed_size (suggest,
8710 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
8711 struct ExpressPreferenceMessage,
8713 GNUNET_MQ_hd_fixed_size (suggest_cancel,
8714 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
8715 struct ExpressPreferenceMessage,
8717 GNUNET_MQ_hd_var_size (request_hello_validation,
8718 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
8719 struct RequestHelloValidationMessage,
8721 /* communication with core */
8722 GNUNET_MQ_hd_fixed_size (client_start,
8723 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
8724 struct StartMessage,
8726 GNUNET_MQ_hd_var_size (client_send,
8727 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
8728 struct OutboundMessage,
8730 /* communication with communicators */
8731 GNUNET_MQ_hd_var_size (communicator_available,
8732 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
8733 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
8735 GNUNET_MQ_hd_var_size (communicator_backchannel,
8736 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
8737 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
8739 GNUNET_MQ_hd_var_size (add_address,
8740 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
8741 struct GNUNET_TRANSPORT_AddAddressMessage,
8743 GNUNET_MQ_hd_fixed_size (del_address,
8744 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
8745 struct GNUNET_TRANSPORT_DelAddressMessage,
8747 GNUNET_MQ_hd_var_size (incoming_msg,
8748 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
8749 struct GNUNET_TRANSPORT_IncomingMessage,
8751 GNUNET_MQ_hd_fixed_size (queue_create_ok,
8752 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
8753 struct GNUNET_TRANSPORT_CreateQueueResponse,
8755 GNUNET_MQ_hd_fixed_size (queue_create_fail,
8756 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
8757 struct GNUNET_TRANSPORT_CreateQueueResponse,
8759 GNUNET_MQ_hd_var_size (add_queue_message,
8760 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
8761 struct GNUNET_TRANSPORT_AddQueueMessage,
8763 GNUNET_MQ_hd_var_size (address_consider_verify,
8764 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
8765 struct GNUNET_TRANSPORT_AddressToVerify,
8767 GNUNET_MQ_hd_fixed_size (del_queue_message,
8768 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
8769 struct GNUNET_TRANSPORT_DelQueueMessage,
8771 GNUNET_MQ_hd_fixed_size (send_message_ack,
8772 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
8773 struct GNUNET_TRANSPORT_SendMessageToAck,
8775 /* communication with monitors */
8776 GNUNET_MQ_hd_fixed_size (monitor_start,
8777 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
8778 struct GNUNET_TRANSPORT_MonitorStart,
8780 GNUNET_MQ_handler_end ());
8783 /* end of file gnunet-service-transport.c */