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 * - dv hop-by-hop signature verification (at least at initiator)
28 * - change transport-core API to provide proper flow control in both
29 * directions, allow multiple messages per peer simultaneously (tag
30 * confirmations with unique message ID), and replace quota-out with
31 * proper flow control; specify transmission preferences (latency,
32 * reliability, etc.) per message!
36 * - review retransmission logic, right now there is no smartness there!
37 * => congestion control, flow control, etc
40 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
41 * => Need 128 bit hash map though!
42 * - queue_send_msg and route_message both by API design have to make copies
43 * of the payload, and route_message on top of that requires a malloc/free.
44 * Change design to approximate "zero" copy better...
45 * - could avoid copying body of message into each fragment and keep
46 * fragments as just pointers into the original message and only
47 * fully build fragments just before transmission (optimization, should
48 * reduce CPU and memory use)
49 * - if messages are below MTU, consider adding ACKs and other stuff
50 * (requires planning at receiver, and additional MST-style demultiplex
52 * - When we passively learned DV (with unconfirmed freshness), we
53 * right now add the path to our list but with a zero path_valid_until
54 * time and only use it for unconfirmed routes. However, we could consider
55 * triggering an explicit validation mechansim ourselves, specifically routing
56 * a challenge-response message over the path (OPTIMIZATION-FIXME).
58 * Design realizations / discussion:
59 * - communicators do flow control by calling MQ "notify sent"
60 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
61 * or explicitly via backchannel FC ACKs. As long as the
62 * channel is not full, they may 'notify sent' even if the other
63 * peer has not yet confirmed receipt. The other peer confirming
64 * is _only_ for FC, not for more reliable transmission; reliable
65 * transmission (i.e. of fragments) is left to _transport_.
66 * - ACKs sent back in uni-directional communicators are done via
67 * the background channel API; here transport _may_ initially
68 * broadcast (with bounded # hops) if no path is known;
69 * - transport should _integrate_ DV-routing and build a view of
70 * the network; then background channel traffic can be
71 * routed via DV as well as explicit "DV" traffic.
72 * - background channel is also used for ACKs and NAT traversal support
73 * - transport service is responsible for AEAD'ing the background
74 * channel, timestamps and monotonic time are used against replay
75 * of old messages -> peerstore needs to be supplied with
76 * "latest timestamps seen" data
77 * - if transport implements DV, we likely need a 3rd peermap
78 * in addition to ephemerals and (direct) neighbours
79 * ==> check if stuff needs to be moved out of "Neighbour"
80 * - transport should encapsualte core-level messages and do its
81 * own ACKing for RTT/goodput/loss measurements _and_ fragment
85 #include "gnunet_util_lib.h"
86 #include "gnunet_statistics_service.h"
87 #include "gnunet_transport_monitor_service.h"
88 #include "gnunet_peerstore_service.h"
89 #include "gnunet_hello_lib.h"
90 #include "gnunet_signatures.h"
91 #include "transport.h"
94 * Maximum number of messages we acknowledge together in one
95 * cummulative ACK. Larger values may save a bit of bandwidth.
97 #define MAX_CUMMULATIVE_ACKS 64
100 * What is the size we assume for a read operation in the
101 * absence of an MTU for the purpose of flow control?
103 #define IN_PACKET_SIZE_WITHOUT_MTU 128
106 * Number of slots we keep of historic data for computation of
107 * goodput / message loss ratio.
109 #define GOODPUT_AGING_SLOTS 4
112 * Maximum number of peers we select for forwarding DVInit
113 * messages at the same time (excluding initiator).
115 #define MAX_DV_DISCOVERY_SELECTION 16
118 * Minimum number of hops we should forward DV learn messages
119 * even if they are NOT useful for us in hope of looping
120 * back to the initiator?
122 * FIXME: allow initiator some control here instead?
124 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
127 * Maximum DV distance allowed ever.
129 #define MAX_DV_HOPS_ALLOWED 16
132 * Maximum number of DV learning activities we may
133 * have pending at the same time.
135 #define MAX_DV_LEARN_PENDING 64
138 * Maximum number of DV paths we keep simultaneously to the same target.
140 #define MAX_DV_PATHS_TO_TARGET 3
143 * If a queue delays the next message by more than this number
144 * of seconds we log a warning. Note: this is for testing,
145 * the value chosen here might be too aggressively low!
147 #define DELAY_WARN_THRESHOLD \
148 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
151 * We only consider queues as "quality" connections when
152 * suppressing the generation of DV initiation messages if
153 * the latency of the queue is below this threshold.
155 #define DV_QUALITY_RTT_THRESHOLD \
156 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
159 * How long do we consider a DV path valid if we see no
160 * further updates on it? Note: the value chosen here might be too low!
162 #define DV_PATH_VALIDITY_TIMEOUT \
163 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
166 * How long do we cache backchannel (struct Backtalker) information
167 * after a backchannel goes inactive?
169 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
170 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
173 * How long before paths expire would we like to (re)discover DV paths? Should
174 * be below #DV_PATH_VALIDITY_TIMEOUT.
176 #define DV_PATH_DISCOVERY_FREQUENCY \
177 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
180 * How long are ephemeral keys valid?
182 #define EPHEMERAL_VALIDITY \
183 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
186 * How long do we keep partially reassembled messages around before giving up?
188 #define REASSEMBLY_EXPIRATION \
189 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
192 * What is the fastest rate at which we send challenges *if* we keep learning
193 * an address (gossip, DHT, etc.)?
195 #define FAST_VALIDATION_CHALLENGE_FREQ \
196 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
199 * What is the slowest rate at which we send challenges?
201 #define MAX_VALIDATION_CHALLENGE_FREQ \
202 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
205 * How long until we forget about historic accumulators and thus
206 * reset the ACK counter? Should exceed the maximum time an
207 * active connection experiences without an ACK.
209 #define ACK_CUMMULATOR_TIMEOUT \
210 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
213 * What is the non-randomized base frequency at which we
214 * would initiate DV learn messages?
216 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
219 * How many good connections (confirmed, bi-directional, not DV)
220 * do we need to have to suppress initiating DV learn messages?
222 #define DV_LEARN_QUALITY_THRESHOLD 100
225 * When do we forget an invalid address for sure?
227 #define MAX_ADDRESS_VALID_UNTIL \
228 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
231 * How long do we consider an address valid if we just checked?
233 #define ADDRESS_VALIDATION_LIFETIME \
234 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
237 * What is the maximum frequency at which we do address validation?
238 * A random value between 0 and this value is added when scheduling
239 * the #validation_task (both to ensure we do not validate too often,
240 * and to randomize a bit).
242 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
245 * How many network RTTs before an address validation expires should we begin
246 * trying to revalidate? (Note that the RTT used here is the one that we
247 * experienced during the last validation, not necessarily the latest RTT
250 #define VALIDATION_RTT_BUFFER_FACTOR 3
253 * How many messages can we have pending for a given communicator
254 * process before we start to throttle that communicator?
256 * Used if a communicator might be CPU-bound and cannot handle the traffic.
258 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
261 * How many messages can we have pending for a given queue (queue to
262 * a particular peer via a communicator) process before we start to
263 * throttle that queue?
265 #define QUEUE_LENGTH_LIMIT 32
268 GNUNET_NETWORK_STRUCT_BEGIN
271 * Unique identifier we attach to a message.
276 * Unique value, generated by incrementing the
277 * `message_uuid_ctr` of `struct Neighbour`.
279 uint64_t uuid GNUNET_PACKED;
284 * Unique identifier to map an acknowledgement to a transmission.
286 struct AcknowledgementUUIDP
289 * The UUID value. Not actually a hash, but a random value.
291 struct GNUNET_ShortHashCode value;
296 * Unique identifier we attach to a message.
301 * Unique value identifying a fragment, in NBO.
303 uint32_t uuid GNUNET_PACKED;
308 * Type of a nonce used for challenges.
310 struct ChallengeNonceP
313 * The value of the nonce. Note that this is NOT a hash.
315 struct GNUNET_ShortHashCode value;
320 * Outer layer of an encapsulated backchannel message.
322 struct TransportBackchannelEncapsulationMessage
325 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
327 struct GNUNET_MessageHeader header;
330 * Reserved, always zero.
332 uint32_t reserved GNUNET_PACKED;
335 * Target's peer identity (as backchannels may be transmitted
336 * indirectly, or even be broadcast).
338 struct GNUNET_PeerIdentity target;
341 * Ephemeral key setup by the sender for @e target, used
342 * to encrypt the payload.
344 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
347 * We use an IV here as the @e ephemeral_key is re-used for
348 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
350 struct GNUNET_ShortHashCode iv;
353 * HMAC over the ciphertext of the encrypted, variable-size
354 * body that follows. Verified via DH of @e target and
357 struct GNUNET_HashCode hmac;
359 /* Followed by encrypted, variable-size payload */
364 * Body by which a peer confirms that it is using an ephemeral key.
366 struct EphemeralConfirmationPS
370 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
372 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
375 * How long is this signature over the ephemeral key valid?
377 * Note that the receiver MUST IGNORE the absolute time, and only interpret
378 * the value as a mononic time and reject "older" values than the last one
379 * observed. This is necessary as we do not want to require synchronized
380 * clocks and may not have a bidirectional communication channel.
382 * Even with this, there is no real guarantee against replay achieved here,
383 * unless the latest timestamp is persisted. While persistence should be
384 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
385 * communicators must protect against replay attacks when using backchannel
388 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
391 * Target's peer identity.
393 struct GNUNET_PeerIdentity target;
396 * Ephemeral key setup by the sender for @e target, used
397 * to encrypt the payload.
399 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
404 * Plaintext of the variable-size payload that is encrypted
405 * within a `struct TransportBackchannelEncapsulationMessage`
407 struct TransportBackchannelRequestPayloadP
411 * Sender's peer identity.
413 struct GNUNET_PeerIdentity sender;
416 * Signature of the sender over an
417 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
419 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
422 * Current monotonic time of the sending transport service. Used to
423 * detect replayed messages. Note that the receiver should remember
424 * a list of the recently seen timestamps and only reject messages
425 * if the timestamp is in the list, or the list is "full" and the
426 * timestamp is smaller than the lowest in the list.
428 * Like the @e ephemeral_validity, the list of timestamps per peer should be
429 * persisted to guard against replays after restarts.
431 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
433 /* Followed by a `struct GNUNET_MessageHeader` with a message
434 for a communicator */
436 /* Followed by a 0-termianted string specifying the name of
437 the communicator which is to receive the message */
442 * Outer layer of an encapsulated unfragmented application message sent
443 * over an unreliable channel.
445 struct TransportReliabilityBoxMessage
448 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
450 struct GNUNET_MessageHeader header;
453 * Number of messages still to be sent before a commulative
454 * ACK is requested. Zero if an ACK is requested immediately.
455 * In NBO. Note that the receiver may send the ACK faster
456 * if it believes that is reasonable.
458 uint32_t ack_countdown GNUNET_PACKED;
461 * Unique ID of the message used for signalling receipt of
462 * messages sent over possibly unreliable channels. Should
465 struct AcknowledgementUUIDP ack_uuid;
470 * Acknowledgement payload.
472 struct TransportCummulativeAckPayloadP
475 * How long was the ACK delayed for generating cummulative ACKs?
476 * Used to calculate the correct network RTT by taking the receipt
477 * time of the ack minus the transmission time of the sender minus
480 struct GNUNET_TIME_RelativeNBO ack_delay;
483 * UUID of a message being acknowledged.
485 struct AcknowledgementUUIDP ack_uuid;
490 * Confirmation that the receiver got a
491 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
492 * confirmation may be transmitted over a completely different queue,
493 * so ACKs are identified by a combination of PID of sender and
494 * message UUID, without the queue playing any role!
496 struct TransportReliabilityAckMessage
499 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
501 struct GNUNET_MessageHeader header;
504 * Counter of ACKs transmitted by the sender to us. Incremented
505 * by one for each ACK, used to detect how many ACKs were lost.
507 uint32_t ack_counter GNUNET_PACKED;
509 /* followed by any number of `struct TransportCummulativeAckPayloadP`
510 messages providing ACKs */
515 * Outer layer of an encapsulated fragmented application message.
517 struct TransportFragmentBoxMessage
520 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
522 struct GNUNET_MessageHeader header;
525 * Unique ID of this fragment (and fragment transmission!). Will
526 * change even if a fragement is retransmitted to make each
527 * transmission attempt unique! If a client receives a duplicate
528 * fragment (same @e frag_off for same @a msg_uuid, it must send
529 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
531 struct AcknowledgementUUIDP ack_uuid;
534 * Original message ID for of the message that all the fragments
535 * belong to. Must be the same for all fragments.
537 struct MessageUUIDP msg_uuid;
540 * Offset of this fragment in the overall message.
542 uint16_t frag_off GNUNET_PACKED;
545 * Total size of the message that is being fragmented.
547 uint16_t msg_size GNUNET_PACKED;
552 * Content signed by the initator during DV learning.
554 * The signature is required to prevent DDoS attacks. A peer sending out this
555 * message is potentially generating a lot of traffic that will go back to the
556 * initator, as peers receiving this message will try to let the initiator
557 * know that they got the message.
559 * Without this signature, an attacker could abuse this mechanism for traffic
560 * amplification, sending a lot of traffic to a peer by putting out this type
561 * of message with the victim's peer identity.
563 * Even with just a signature, traffic amplification would be possible via
564 * replay attacks. The @e monotonic_time limits such replay attacks, as every
565 * potential amplificator will check the @e monotonic_time and only respond
566 * (at most) once per message.
571 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
573 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
576 * Time at the initiator when generating the signature.
578 * Note that the receiver MUST IGNORE the absolute time, and only interpret
579 * the value as a mononic time and reject "older" values than the last one
580 * observed. This is necessary as we do not want to require synchronized
581 * clocks and may not have a bidirectional communication channel.
583 * Even with this, there is no real guarantee against replay achieved here,
584 * unless the latest timestamp is persisted. Persistence should be
585 * provided via PEERSTORE if possible.
587 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
590 * Challenge value used by the initiator to re-identify the path.
592 struct ChallengeNonceP challenge;
597 * Content signed by each peer during DV learning.
599 * This assues the initiator of the DV learning operation that the hop from @e
600 * pred via the signing peer to @e succ actually exists. This makes it
601 * impossible for an adversary to supply the network with bogus routes.
603 * The @e challenge is included to provide replay protection for the
604 * initiator. This way, the initiator knows that the hop existed after the
605 * original @e challenge was first transmitted, providing a freshness metric.
607 * Peers other than the initiator that passively learn paths by observing
608 * these messages do NOT benefit from this. Here, an adversary may indeed
609 * replay old messages. Thus, passively learned paths should always be
610 * immediately marked as "potentially stale".
615 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
617 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
620 * Identity of the previous peer on the path.
622 struct GNUNET_PeerIdentity pred;
625 * Identity of the next peer on the path.
627 struct GNUNET_PeerIdentity succ;
630 * Challenge value used by the initiator to re-identify the path.
632 struct ChallengeNonceP challenge;
637 * An entry describing a peer on a path in a
638 * `struct TransportDVLearnMessage` message.
643 * Identity of a peer on the path.
645 struct GNUNET_PeerIdentity hop;
648 * Signature of this hop over the path, of purpose
649 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
651 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
656 * Internal message used by transport for distance vector learning.
657 * If @e num_hops does not exceed the threshold, peers should append
658 * themselves to the peer list and flood the message (possibly only
659 * to a subset of their neighbours to limit discoverability of the
660 * network topology). To the extend that the @e bidirectional bits
661 * are set, peers may learn the inverse paths even if they did not
664 * Unless received on a bidirectional queue and @e num_hops just
665 * zero, peers that can forward to the initator should always try to
666 * forward to the initiator.
668 struct TransportDVLearnMessage
671 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
673 struct GNUNET_MessageHeader header;
676 * Number of hops this messages has travelled, in NBO. Zero if
679 uint16_t num_hops GNUNET_PACKED;
682 * Bitmask of the last 16 hops indicating whether they are confirmed
683 * available (without DV) in both directions or not, in NBO. Used
684 * to possibly instantly learn a path in both directions. Each peer
685 * should shift this value by one to the left, and then set the
686 * lowest bit IF the current sender can be reached from it (without
689 uint16_t bidirectional GNUNET_PACKED;
692 * Peers receiving this message and delaying forwarding to other
693 * peers for any reason should increment this value by the non-network
694 * delay created by the peer.
696 struct GNUNET_TIME_RelativeNBO non_network_delay;
699 * Time at the initiator when generating the signature.
701 * Note that the receiver MUST IGNORE the absolute time, and only interpret
702 * the value as a mononic time and reject "older" values than the last one
703 * observed. This is necessary as we do not want to require synchronized
704 * clocks and may not have a bidirectional communication channel.
706 * Even with this, there is no real guarantee against replay achieved here,
707 * unless the latest timestamp is persisted. Persistence should be
708 * provided via PEERSTORE if possible.
710 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
713 * Signature of this hop over the path, of purpose
714 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
716 struct GNUNET_CRYPTO_EddsaSignature init_sig;
719 * Identity of the peer that started this learning activity.
721 struct GNUNET_PeerIdentity initiator;
724 * Challenge value used by the initiator to re-identify the path.
726 struct ChallengeNonceP challenge;
728 /* Followed by @e num_hops `struct DVPathEntryP` values,
729 excluding the initiator of the DV trace; the last entry is the
730 current sender; the current peer must not be included. */
735 * Outer layer of an encapsulated message send over multiple hops.
736 * The path given only includes the identities of the subsequent
737 * peers, i.e. it will be empty if we are the receiver. Each
738 * forwarding peer should scan the list from the end, and if it can,
739 * forward to the respective peer. The list should then be shortened
740 * by all the entries up to and including that peer. Each hop should
741 * also increment @e total_hops to allow the receiver to get a precise
742 * estimate on the number of hops the message travelled. Senders must
743 * provide a learned path that thus should work, but intermediaries
744 * know of a shortcut, they are allowed to send the message via that
747 * If a peer finds itself still on the list, it must drop the message.
749 struct TransportDVBoxMessage
752 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
754 struct GNUNET_MessageHeader header;
757 * Number of total hops this messages travelled. In NBO.
758 * @e origin sets this to zero, to be incremented at
761 uint16_t total_hops GNUNET_PACKED;
764 * Number of hops this messages includes. In NBO.
766 uint16_t num_hops GNUNET_PACKED;
769 * Identity of the peer that originated the message.
771 struct GNUNET_PeerIdentity origin;
773 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
774 excluding the @e origin and the current peer, the last must be
775 the ultimate target; if @e num_hops is zero, the receiver of this
776 message is the ultimate target. */
778 /* Followed by the actual message, which itself may be
779 another box, but not a DV_LEARN or DV_BOX message! */
784 * Message send to another peer to validate that it can indeed
785 * receive messages at a particular address.
787 struct TransportValidationChallengeMessage
791 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
793 struct GNUNET_MessageHeader header;
798 uint32_t reserved GNUNET_PACKED;
801 * Challenge to be signed by the receiving peer.
803 struct ChallengeNonceP challenge;
806 * Timestamp of the sender, to be copied into the reply
807 * to allow sender to calculate RTT.
809 struct GNUNET_TIME_AbsoluteNBO sender_time;
814 * Message signed by a peer to confirm that it can indeed
815 * receive messages at a particular address.
817 struct TransportValidationPS
821 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
823 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
826 * How long does the sender believe the address on
827 * which the challenge was received to remain valid?
829 struct GNUNET_TIME_RelativeNBO validity_duration;
832 * Challenge signed by the receiving peer.
834 struct ChallengeNonceP challenge;
839 * Message send to a peer to respond to a
840 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
842 struct TransportValidationResponseMessage
846 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
848 struct GNUNET_MessageHeader header;
853 uint32_t reserved GNUNET_PACKED;
856 * The peer's signature matching the
857 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
859 struct GNUNET_CRYPTO_EddsaSignature signature;
862 * The challenge that was signed by the receiving peer.
864 struct ChallengeNonceP challenge;
867 * Original timestamp of the sender (was @code{sender_time}),
868 * copied into the reply to allow sender to calculate RTT.
870 struct GNUNET_TIME_AbsoluteNBO origin_time;
873 * How long does the sender believe this address to remain
876 struct GNUNET_TIME_RelativeNBO validity_duration;
880 GNUNET_NETWORK_STRUCT_END
884 * What type of client is the `struct TransportClient` about?
889 * We do not know yet (client is fresh).
894 * Is the CORE service, we need to forward traffic to it.
899 * It is a monitor, forward monitor data.
904 * It is a communicator, use for communication.
909 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
916 * Which transmission options are allowable for transmission?
917 * Interpreted bit-wise!
919 enum RouteMessageOptions
922 * Only confirmed, non-DV direct neighbours.
927 * We are allowed to use DV routing for this @a hdr
932 * We are allowed to use unconfirmed queues or DV routes for this message
934 RMO_UNCONFIRMED_ALLOWED = 2,
937 * Reliable and unreliable, DV and non-DV are all acceptable.
939 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
942 * If we have multiple choices, it is OK to send this message
943 * over multiple channels at the same time to improve loss tolerance.
944 * (We do at most 2 transmissions.)
951 * When did we launch this DV learning activity?
953 struct LearnLaunchEntry
957 * Kept (also) in a DLL sorted by launch time.
959 struct LearnLaunchEntry *prev;
962 * Kept (also) in a DLL sorted by launch time.
964 struct LearnLaunchEntry *next;
967 * Challenge that uniquely identifies this activity.
969 struct ChallengeNonceP challenge;
972 * When did we transmit the DV learn message (used to calculate RTT) and
973 * determine freshness of paths learned via this operation.
975 struct GNUNET_TIME_Absolute launch_time;
980 * Entry in our cache of ephemeral keys we currently use. This way, we only
981 * sign an ephemeral once per @e target, and then can re-use it over multiple
982 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
983 * signing is expensive and in some cases we may use backchannel messages a
986 struct EphemeralCacheEntry
990 * Target's peer identity (we don't re-use ephemerals
991 * to limit linkability of messages).
993 struct GNUNET_PeerIdentity target;
996 * Signature affirming @e ephemeral_key of type
997 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
999 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1002 * How long is @e sender_sig valid
1004 struct GNUNET_TIME_Absolute ephemeral_validity;
1007 * What time was @e sender_sig created
1009 struct GNUNET_TIME_Absolute monotime;
1012 * Our ephemeral key.
1014 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1017 * Our private ephemeral key.
1019 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1022 * Node in the ephemeral cache for this entry.
1023 * Used for expiration.
1025 struct GNUNET_CONTAINER_HeapNode *hn;
1030 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1031 * (or current) transmission performance.
1033 struct TransmissionHistoryEntry
1036 * Number of bytes actually sent in the interval.
1038 uint64_t bytes_sent;
1041 * Number of bytes received and acknowledged by the other peer in
1044 uint64_t bytes_received;
1049 * Performance data for a transmission possibility.
1051 struct PerformanceData
1054 * Weighted average for the RTT.
1056 struct GNUNET_TIME_Relative aged_rtt;
1059 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1062 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1065 * What was the last age when we wrote to @e the? Used to clear
1066 * old entries when the age advances.
1068 unsigned int last_age;
1073 * Client connected to the transport service.
1075 struct TransportClient;
1078 * A neighbour that at least one communicator is connected to.
1083 * Entry in our #dv_routes table, representing a (set of) distance
1084 * vector routes to a particular peer.
1086 struct DistanceVector;
1089 * A queue is a message queue provided by a communicator
1090 * via which we can reach a particular neighbour.
1095 * Message awaiting transmission. See detailed comments below.
1097 struct PendingMessage;
1100 * One possible hop towards a DV target.
1102 struct DistanceVectorHop;
1106 * Data structure kept when we are waiting for an acknowledgement.
1108 struct PendingAcknowledgement
1112 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1113 * is kept in relation to its pending message.
1115 struct PendingAcknowledgement *next_pm;
1118 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1119 * is kept in relation to its pending message.
1121 struct PendingAcknowledgement *prev_pm;
1124 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1125 * is kept in relation to the queue that was used to transmit the
1128 struct PendingAcknowledgement *next_queue;
1131 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1132 * is kept in relation to the queue that was used to transmit the
1135 struct PendingAcknowledgement *prev_queue;
1138 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1139 * is kept in relation to the DVH that was used to transmit the
1142 struct PendingAcknowledgement *next_dvh;
1145 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1146 * is kept in relation to the DVH that was used to transmit the
1149 struct PendingAcknowledgement *prev_dvh;
1152 * Pointers for the DLL of all pending acknowledgements.
1153 * This list is sorted by @e transmission time. If the list gets too
1154 * long, the oldest entries are discarded.
1156 struct PendingAcknowledgement *next_pa;
1159 * Pointers for the DLL of all pending acknowledgements.
1160 * This list is sorted by @e transmission time. If the list gets too
1161 * long, the oldest entries are discarded.
1163 struct PendingAcknowledgement *prev_pa;
1166 * Unique identifier for this transmission operation.
1168 struct AcknowledgementUUIDP ack_uuid;
1171 * Message that was transmitted, may be NULL if the message was ACKed
1172 * via another channel.
1174 struct PendingMessage *pm;
1177 * Distance vector path chosen for this transmission, NULL if transmission
1178 * was to a direct neighbour OR if the path was forgotten in the meantime.
1180 struct DistanceVectorHop *dvh;
1183 * Queue used for transmission, NULL if the queue has been destroyed
1184 * (which may happen before we get an acknowledgement).
1186 struct Queue *queue;
1189 * Time of the transmission, for RTT calculation.
1191 struct GNUNET_TIME_Absolute transmission_time;
1194 * Number of bytes of the original message (to calculate bandwidth).
1196 uint16_t message_size;
1201 * One possible hop towards a DV target.
1203 struct DistanceVectorHop
1207 * Kept in a MDLL, sorted by @e timeout.
1209 struct DistanceVectorHop *next_dv;
1212 * Kept in a MDLL, sorted by @e timeout.
1214 struct DistanceVectorHop *prev_dv;
1219 struct DistanceVectorHop *next_neighbour;
1224 struct DistanceVectorHop *prev_neighbour;
1227 * Head of MDLL of messages routed via this path.
1229 struct PendingMessage *pending_msg_head;
1232 * Tail of MDLL of messages routed via this path.
1234 struct PendingMessage *pending_msg_tail;
1237 * Head of DLL of PAs that used our @a path.
1239 struct PendingAcknowledgement *pa_head;
1242 * Tail of DLL of PAs that used our @a path.
1244 struct PendingAcknowledgement *pa_tail;
1247 * What would be the next hop to @e target?
1249 struct Neighbour *next_hop;
1252 * Distance vector entry this hop belongs with.
1254 struct DistanceVector *dv;
1257 * Array of @e distance hops to the target, excluding @e next_hop.
1258 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1259 * at the end of this struct. Excludes the target itself!
1261 const struct GNUNET_PeerIdentity *path;
1264 * At what time do we forget about this path unless we see it again
1267 struct GNUNET_TIME_Absolute timeout;
1270 * For how long is the validation of this path considered
1272 * Set to ZERO if the path is learned by snooping on DV learn messages
1273 * initiated by other peers, and to the time at which we generated the
1274 * challenge for DV learn operations this peer initiated.
1276 struct GNUNET_TIME_Absolute path_valid_until;
1279 * Performance data for this transmission possibility.
1281 struct PerformanceData pd;
1284 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1285 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1288 unsigned int distance;
1293 * Entry in our #dv_routes table, representing a (set of) distance
1294 * vector routes to a particular peer.
1296 struct DistanceVector
1300 * To which peer is this a route?
1302 struct GNUNET_PeerIdentity target;
1305 * Known paths to @e target.
1307 struct DistanceVectorHop *dv_head;
1310 * Known paths to @e target.
1312 struct DistanceVectorHop *dv_tail;
1315 * Task scheduled to purge expired paths from @e dv_head MDLL.
1317 struct GNUNET_SCHEDULER_Task *timeout_task;
1320 * Task scheduled to possibly notfiy core that this queue is no longer
1321 * counting as confirmed. Runs the #core_queue_visibility_check().
1323 struct GNUNET_SCHEDULER_Task *visibility_task;
1326 * Quota at which CORE is allowed to transmit to this peer
1327 * (note that the value CORE should actually be told is this
1328 * value plus the respective value in `struct Neighbour`).
1329 * Should match the sum of the quotas of all of the paths.
1331 * FIXME: not yet set, tricky to get right given multiple paths,
1332 * many of which may be inactive! (=> Idea: measure???)
1333 * FIXME: how do we set this value initially when we tell CORE?
1334 * Options: start at a minimum value or at literally zero?
1335 * (=> Current thought: clean would be zero!)
1337 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1340 * Is one of the DV paths in this struct 'confirmed' and thus
1341 * the cause for CORE to see this peer as connected? (Note that
1342 * the same may apply to a `struct Neighbour` at the same time.)
1349 * Entry identifying transmission in one of our `struct
1350 * Queue` which still awaits an ACK. This is used to
1351 * ensure we do not overwhelm a communicator and limit the number of
1352 * messages outstanding per communicator (say in case communicator is
1353 * CPU bound) and per queue (in case bandwidth allocation exceeds
1354 * what the communicator can actually provide towards a particular
1363 struct QueueEntry *next;
1368 struct QueueEntry *prev;
1371 * Queue this entry is queued with.
1373 struct Queue *queue;
1376 * Pending message this entry is for, or NULL for none.
1378 struct PendingMessage *pm;
1381 * Message ID used for this message with the queue used for transmission.
1388 * A queue is a message queue provided by a communicator
1389 * via which we can reach a particular neighbour.
1396 struct Queue *next_neighbour;
1401 struct Queue *prev_neighbour;
1406 struct Queue *prev_client;
1411 struct Queue *next_client;
1414 * Head of DLL of PAs that used this queue.
1416 struct PendingAcknowledgement *pa_head;
1419 * Tail of DLL of PAs that used this queue.
1421 struct PendingAcknowledgement *pa_tail;
1424 * Head of DLL of unacked transmission requests.
1426 struct QueueEntry *queue_head;
1429 * End of DLL of unacked transmission requests.
1431 struct QueueEntry *queue_tail;
1434 * Which neighbour is this queue for?
1436 struct Neighbour *neighbour;
1439 * Which communicator offers this queue?
1441 struct TransportClient *tc;
1444 * Address served by the queue.
1446 const char *address;
1449 * Task scheduled for the time when this queue can (likely) transmit the
1452 struct GNUNET_SCHEDULER_Task *transmit_task;
1455 * Task scheduled to possibly notfiy core that this queue is no longer
1456 * counting as confirmed. Runs the #core_queue_visibility_check().
1458 struct GNUNET_SCHEDULER_Task *visibility_task;
1461 * How long do *we* consider this @e address to be valid? In the past or
1462 * zero if we have not yet validated it. Can be updated based on
1463 * challenge-response validations (via address validation logic), or when we
1464 * receive ACKs that we can definitively map to transmissions via this
1467 struct GNUNET_TIME_Absolute validated_until;
1470 * Performance data for this queue.
1472 struct PerformanceData pd;
1475 * Message ID generator for transmissions on this queue to the
1481 * Unique identifier of this queue with the communicator.
1486 * Maximum transmission unit supported by this queue.
1493 uint32_t num_msg_pending;
1498 uint32_t num_bytes_pending;
1501 * Length of the DLL starting at @e queue_head.
1503 unsigned int queue_length;
1506 * Network type offered by this queue.
1508 enum GNUNET_NetworkType nt;
1511 * Connection status for this queue.
1513 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1518 * Information we keep for a message that we are reassembling.
1520 struct ReassemblyContext
1524 * Original message ID for of the message that all the fragments
1527 struct MessageUUIDP msg_uuid;
1530 * Which neighbour is this context for?
1532 struct Neighbour *neighbour;
1535 * Entry in the reassembly heap (sorted by expiration).
1537 struct GNUNET_CONTAINER_HeapNode *hn;
1540 * Bitfield with @e msg_size bits representing the positions
1541 * where we have received fragments. When we receive a fragment,
1542 * we check the bits in @e bitfield before incrementing @e msg_missing.
1544 * Allocated after the reassembled message.
1549 * Task for sending ACK. We may send ACKs either because of hitting
1550 * the @e extra_acks limit, or based on time and @e num_acks. This
1551 * task is for the latter case.
1553 struct GNUNET_SCHEDULER_Task *ack_task;
1556 * At what time will we give up reassembly of this message?
1558 struct GNUNET_TIME_Absolute reassembly_timeout;
1561 * Time we received the last fragment. @e avg_ack_delay must be
1562 * incremented by now - @e last_frag multiplied by @e num_acks.
1564 struct GNUNET_TIME_Absolute last_frag;
1567 * How big is the message we are reassembling in total?
1572 * How many bytes of the message are still missing? Defragmentation
1573 * is complete when @e msg_missing == 0.
1575 uint16_t msg_missing;
1577 /* Followed by @e msg_size bytes of the (partially) defragmented original
1580 /* Followed by @e bitfield data */
1585 * A neighbour that at least one communicator is connected to.
1591 * Which peer is this about?
1593 struct GNUNET_PeerIdentity pid;
1596 * Map with `struct ReassemblyContext` structs for fragments under
1597 * reassembly. May be NULL if we currently have no fragments from
1598 * this @e pid (lazy initialization).
1600 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1603 * Heap with `struct ReassemblyContext` structs for fragments under
1604 * reassembly. May be NULL if we currently have no fragments from
1605 * this @e pid (lazy initialization).
1607 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1610 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1612 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1615 * Head of list of messages pending for this neighbour.
1617 struct PendingMessage *pending_msg_head;
1620 * Tail of list of messages pending for this neighbour.
1622 struct PendingMessage *pending_msg_tail;
1625 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1626 * purged if this neighbour goes down.
1628 struct DistanceVectorHop *dv_head;
1631 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1632 * purged if this neighbour goes down.
1634 struct DistanceVectorHop *dv_tail;
1637 * Head of DLL of queues to this peer.
1639 struct Queue *queue_head;
1642 * Tail of DLL of queues to this peer.
1644 struct Queue *queue_tail;
1647 * Task run to cleanup pending messages that have exceeded their timeout.
1649 struct GNUNET_SCHEDULER_Task *timeout_task;
1652 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1653 * the PEERSTORE, or NULL.
1655 struct GNUNET_PEERSTORE_IterateContext *get;
1658 * Handle to a PEERSTORE store operation to store this @e pid's @e
1659 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1661 struct GNUNET_PEERSTORE_StoreContext *sc;
1664 * Quota at which CORE is allowed to transmit to this peer
1665 * (note that the value CORE should actually be told is this
1666 * value plus the respective value in `struct DistanceVector`).
1667 * Should match the sum of the quotas of all of the queues.
1669 * FIXME: not yet set, tricky to get right given multiple queues!
1670 * (=> Idea: measure???)
1671 * FIXME: how do we set this value initially when we tell CORE?
1672 * Options: start at a minimum value or at literally zero?
1673 * (=> Current thought: clean would be zero!)
1675 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1678 * Latest DVLearn monotonic time seen from this peer. Initialized only
1679 * if @e dl_monotime_available is #GNUNET_YES.
1681 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1684 * What is the earliest timeout of any message in @e pending_msg_tail?
1686 struct GNUNET_TIME_Absolute earliest_timeout;
1689 * Do we have a confirmed working queue and are thus visible to
1695 * Do we have the lastest value for @e last_dv_learn_monotime from
1696 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1698 int dv_monotime_available;
1703 * A peer that an application (client) would like us to talk to directly.
1709 * Which peer is this about?
1711 struct GNUNET_PeerIdentity pid;
1714 * Client responsible for the request.
1716 struct TransportClient *tc;
1719 * Handle for watching the peerstore for HELLOs for this peer.
1721 struct GNUNET_PEERSTORE_WatchContext *wc;
1724 * What kind of performance preference does this @e tc have?
1726 enum GNUNET_MQ_PreferenceKind pk;
1729 * How much bandwidth would this @e tc like to see?
1731 struct GNUNET_BANDWIDTH_Value32NBO bw;
1736 * Types of different pending messages.
1738 enum PendingMessageType
1742 * Ordinary message received from the CORE service.
1749 PMT_FRAGMENT_BOX = 1,
1754 PMT_RELIABILITY_BOX = 2,
1757 * Any type of acknowledgement.
1759 PMT_ACKNOWLEDGEMENT = 3,
1762 * Control traffic generated by the TRANSPORT service itself.
1770 * Transmission request that is awaiting delivery. The original
1771 * transmission requests from CORE may be too big for some queues.
1772 * In this case, a *tree* of fragments is created. At each
1773 * level of the tree, fragments are kept in a DLL ordered by which
1774 * fragment should be sent next (at the head). The tree is searched
1775 * top-down, with the original message at the root.
1777 * To select a node for transmission, first it is checked if the
1778 * current node's message fits with the MTU. If it does not, we
1779 * either calculate the next fragment (based on @e frag_off) from the
1780 * current node, or, if all fragments have already been created,
1781 * descend to the @e head_frag. Even though the node was already
1782 * fragmented, the fragment may be too big if the fragment was
1783 * generated for a queue with a larger MTU. In this case, the node
1784 * may be fragmented again, thus creating a tree.
1786 * When acknowledgements for fragments are received, the tree
1787 * must be pruned, removing those parts that were already
1788 * acknowledged. When fragments are sent over a reliable
1789 * channel, they can be immediately removed.
1791 * If a message is ever fragmented, then the original "full" message
1792 * is never again transmitted (even if it fits below the MTU), and
1793 * only (remaining) fragments are sent.
1795 struct PendingMessage
1798 * Kept in a MDLL of messages for this @a target.
1800 struct PendingMessage *next_neighbour;
1803 * Kept in a MDLL of messages for this @a target.
1805 struct PendingMessage *prev_neighbour;
1808 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1810 struct PendingMessage *next_client;
1813 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1815 struct PendingMessage *prev_client;
1818 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1819 * #PMT_FRAGMENT_BOx)
1821 struct PendingMessage *next_frag;
1824 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1825 * #PMT_FRAGMENT_BOX)
1827 struct PendingMessage *prev_frag;
1830 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1833 struct PendingMessage *next_dvh;
1836 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1839 struct PendingMessage *prev_dvh;
1842 * Head of DLL of PAs for this pending message.
1844 struct PendingAcknowledgement *pa_head;
1847 * Tail of DLL of PAs for this pending message.
1849 struct PendingAcknowledgement *pa_tail;
1852 * This message, reliability boxed. Only possibly available if @e pmt is
1855 struct PendingMessage *bpm;
1858 * Target of the request (for transmission, may not be ultimate
1861 struct Neighbour *target;
1864 * Distance vector path selected for this message, or
1865 * NULL if transmitted directly.
1867 struct DistanceVectorHop *dvh;
1870 * Set to non-NULL value if this message is currently being given to a
1871 * communicator and we are awaiting that communicator's acknowledgement.
1872 * Note that we must not retransmit a pending message while we're still
1873 * in the process of giving it to a communicator. If a pending message
1874 * is free'd while this entry is non-NULL, the @e qe reference to us
1875 * should simply be set to NULL.
1877 struct QueueEntry *qe;
1880 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1882 struct TransportClient *client;
1885 * Head of a MDLL of fragments created for this core message.
1887 struct PendingMessage *head_frag;
1890 * Tail of a MDLL of fragments created for this core message.
1892 struct PendingMessage *tail_frag;
1895 * Our parent in the fragmentation tree.
1897 struct PendingMessage *frag_parent;
1900 * At what time should we give up on the transmission (and no longer retry)?
1902 struct GNUNET_TIME_Absolute timeout;
1905 * What is the earliest time for us to retry transmission of this message?
1907 struct GNUNET_TIME_Absolute next_attempt;
1910 * UUID to use for this message (used for reassembly of fragments, only
1911 * initialized if @e msg_uuid_set is #GNUNET_YES).
1913 struct MessageUUIDP msg_uuid;
1916 * Type of the pending message.
1918 enum PendingMessageType pmt;
1921 * Size of the original message.
1926 * Offset at which we should generate the next fragment.
1931 * #GNUNET_YES once @e msg_uuid was initialized
1933 int16_t msg_uuid_set;
1935 /* Followed by @e bytes_msg to transmit */
1940 * Acknowledgement payload.
1942 struct TransportCummulativeAckPayload
1945 * When did we receive the message we are ACKing? Used to calculate
1946 * the delay we introduced by cummulating ACKs.
1948 struct GNUNET_TIME_Absolute receive_time;
1951 * UUID of a message being acknowledged.
1953 struct AcknowledgementUUIDP ack_uuid;
1958 * Data structure in which we track acknowledgements still to
1961 struct AcknowledgementCummulator
1964 * Target peer for which we are accumulating ACKs here.
1966 struct GNUNET_PeerIdentity target;
1969 * ACK data being accumulated. Only @e num_acks slots are valid.
1971 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
1974 * Task scheduled either to transmit the cummulative ACK message,
1975 * or to clean up this data structure after extended periods of
1976 * inactivity (if @e num_acks is zero).
1978 struct GNUNET_SCHEDULER_Task *task;
1981 * When is @e task run (only used if @e num_acks is non-zero)?
1983 struct GNUNET_TIME_Absolute min_transmission_time;
1986 * Counter to produce the `ack_counter` in the `struct
1987 * TransportReliabilityAckMessage`. Allows the receiver to detect
1988 * lost ACK messages. Incremented by @e num_acks upon transmission.
1990 uint32_t ack_counter;
1993 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
1995 unsigned int num_acks;
2000 * One of the addresses of this peer.
2002 struct AddressListEntry
2008 struct AddressListEntry *next;
2013 struct AddressListEntry *prev;
2016 * Which communicator provides this address?
2018 struct TransportClient *tc;
2021 * The actual address.
2023 const char *address;
2026 * Current context for storing this address in the peerstore.
2028 struct GNUNET_PEERSTORE_StoreContext *sc;
2031 * Task to periodically do @e st operation.
2033 struct GNUNET_SCHEDULER_Task *st;
2036 * What is a typical lifetime the communicator expects this
2037 * address to have? (Always from now.)
2039 struct GNUNET_TIME_Relative expiration;
2042 * Address identifier used by the communicator.
2047 * Network type offered by this address.
2049 enum GNUNET_NetworkType nt;
2054 * Client connected to the transport service.
2056 struct TransportClient
2062 struct TransportClient *next;
2067 struct TransportClient *prev;
2070 * Handle to the client.
2072 struct GNUNET_SERVICE_Client *client;
2075 * Message queue to the client.
2077 struct GNUNET_MQ_Handle *mq;
2080 * What type of client is this?
2082 enum ClientType type;
2088 * Information for @e type #CT_CORE.
2094 * Head of list of messages pending for this client, sorted by
2095 * transmission time ("next_attempt" + possibly internal prioritization).
2097 struct PendingMessage *pending_msg_head;
2100 * Tail of list of messages pending for this client.
2102 struct PendingMessage *pending_msg_tail;
2107 * Information for @e type #CT_MONITOR.
2113 * Peer identity to monitor the addresses of.
2114 * Zero to monitor all neighbours. Valid if
2115 * @e type is #CT_MONITOR.
2117 struct GNUNET_PeerIdentity peer;
2120 * Is this a one-shot monitor?
2128 * Information for @e type #CT_COMMUNICATOR.
2133 * If @e type is #CT_COMMUNICATOR, this communicator
2134 * supports communicating using these addresses.
2136 char *address_prefix;
2139 * Head of DLL of queues offered by this communicator.
2141 struct Queue *queue_head;
2144 * Tail of DLL of queues offered by this communicator.
2146 struct Queue *queue_tail;
2149 * Head of list of the addresses of this peer offered by this
2152 struct AddressListEntry *addr_head;
2155 * Tail of list of the addresses of this peer offered by this
2158 struct AddressListEntry *addr_tail;
2161 * Number of queue entries in all queues to this communicator. Used
2162 * throttle sending to a communicator if we see that the communicator
2163 * is globally unable to keep up.
2165 unsigned int total_queue_length;
2168 * Characteristics of this communicator.
2170 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2175 * Information for @e type #CT_APPLICATION
2181 * Map of requests for peers the given client application would like to
2182 * see connections for. Maps from PIDs to `struct PeerRequest`.
2184 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2193 * State we keep for validation activities. Each of these
2194 * is both in the #validation_heap and the #validation_map.
2196 struct ValidationState
2200 * For which peer is @a address to be validated (or possibly valid)?
2201 * Serves as key in the #validation_map.
2203 struct GNUNET_PeerIdentity pid;
2206 * How long did the peer claim this @e address to be valid? Capped at
2207 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2208 * were told about the address and the value claimed by the other peer at
2209 * that time. May be updated similarly when validation succeeds.
2211 struct GNUNET_TIME_Absolute valid_until;
2214 * How long do *we* consider this @e address to be valid?
2215 * In the past or zero if we have not yet validated it.
2217 struct GNUNET_TIME_Absolute validated_until;
2220 * When did we FIRST use the current @e challenge in a message?
2221 * Used to sanity-check @code{origin_time} in the response when
2222 * calculating the RTT. If the @code{origin_time} is not in
2223 * the expected range, the response is discarded as malicious.
2225 struct GNUNET_TIME_Absolute first_challenge_use;
2228 * When did we LAST use the current @e challenge in a message?
2229 * Used to sanity-check @code{origin_time} in the response when
2230 * calculating the RTT. If the @code{origin_time} is not in
2231 * the expected range, the response is discarded as malicious.
2233 struct GNUNET_TIME_Absolute last_challenge_use;
2236 * Next time we will send the @e challenge to the peer, if this time is past
2237 * @e valid_until, this validation state is released at this time. If the
2238 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2239 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2240 * to re-validate before the validity actually expires.
2242 struct GNUNET_TIME_Absolute next_challenge;
2245 * Current backoff factor we're applying for sending the @a challenge.
2246 * Reset to 0 if the @a challenge is confirmed upon validation.
2247 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2248 * existing value if we receive an unvalidated address again over
2249 * another channel (and thus should consider the information "fresh").
2250 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2252 struct GNUNET_TIME_Relative challenge_backoff;
2255 * Initially set to "forever". Once @e validated_until is set, this value is
2256 * set to the RTT that tells us how long it took to receive the validation.
2258 struct GNUNET_TIME_Relative validation_rtt;
2261 * The challenge we sent to the peer to get it to validate the address. Note
2262 * that we rotate the challenge whenever we update @e validated_until to
2263 * avoid attacks where a peer simply replays an old challenge in the future.
2264 * (We must not rotate more often as otherwise we may discard valid answers
2265 * due to packet losses, latency and reorderings on the network).
2267 struct ChallengeNonceP challenge;
2270 * Claimed address of the peer.
2275 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2276 * heap is used to figure out when the next validation activity should be
2279 struct GNUNET_CONTAINER_HeapNode *hn;
2282 * Handle to a PEERSTORE store operation for this @e address. NULL if
2283 * no PEERSTORE operation is pending.
2285 struct GNUNET_PEERSTORE_StoreContext *sc;
2288 * We are technically ready to send the challenge, but we are waiting for
2289 * the respective queue to become available for transmission.
2296 * A Backtalker is a peer sending us backchannel messages. We use this
2297 * struct to detect monotonic time violations, cache ephemeral key
2298 * material (to avoid repeatedly checking signatures), and to synchronize
2299 * monotonic time with the PEERSTORE.
2304 * Peer this is about.
2306 struct GNUNET_PeerIdentity pid;
2309 * Last (valid) monotonic time received from this sender.
2311 struct GNUNET_TIME_Absolute monotonic_time;
2314 * When will this entry time out?
2316 struct GNUNET_TIME_Absolute timeout;
2319 * Last (valid) ephemeral key received from this sender.
2321 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2324 * Task associated with this backtalker. Can be for timeout,
2325 * or other asynchronous operations.
2327 struct GNUNET_SCHEDULER_Task *task;
2330 * Communicator context waiting on this backchannel's @e get, or NULL.
2332 struct CommunicatorMessageContext *cmc;
2335 * Handle for an operation to fetch @e monotonic_time information from the
2336 * PEERSTORE, or NULL.
2338 struct GNUNET_PEERSTORE_IterateContext *get;
2341 * Handle to a PEERSTORE store operation for this @e pid's @e
2342 * monotonic_time. NULL if no PEERSTORE operation is pending.
2344 struct GNUNET_PEERSTORE_StoreContext *sc;
2347 * Number of bytes of the original message body that follows after this
2355 * Head of linked list of all clients to this service.
2357 static struct TransportClient *clients_head;
2360 * Tail of linked list of all clients to this service.
2362 static struct TransportClient *clients_tail;
2365 * Statistics handle.
2367 static struct GNUNET_STATISTICS_Handle *GST_stats;
2370 * Configuration handle.
2372 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2377 static struct GNUNET_PeerIdentity GST_my_identity;
2382 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2385 * Map from PIDs to `struct Neighbour` entries. A peer is
2386 * a neighbour if we have an MQ to it from some communicator.
2388 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2391 * Map from PIDs to `struct Backtalker` entries. A peer is
2392 * a backtalker if it recently send us backchannel messages.
2394 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2397 * Map from PIDs to `struct AcknowledgementCummulator`s.
2398 * Here we track the cummulative ACKs for transmission.
2400 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2403 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2404 * a `struct PendingAcknowledgement`.
2406 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2409 * Map from PIDs to `struct DistanceVector` entries describing
2410 * known paths to the peer.
2412 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2415 * Map from PIDs to `struct ValidationState` entries describing
2416 * addresses we are aware of and their validity state.
2418 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2421 * Map from challenges to `struct LearnLaunchEntry` values.
2423 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2426 * Head of a DLL sorted by launch time.
2428 static struct LearnLaunchEntry *lle_head;
2431 * Tail of a DLL sorted by launch time.
2433 static struct LearnLaunchEntry *lle_tail;
2436 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2437 * sorting addresses we are aware of by when we should next try to (re)validate
2440 static struct GNUNET_CONTAINER_Heap *validation_heap;
2443 * Database for peer's HELLOs.
2445 static struct GNUNET_PEERSTORE_Handle *peerstore;
2448 * Heap sorting `struct EphemeralCacheEntry` by their
2449 * key/signature validity.
2451 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2454 * Hash map for looking up `struct EphemeralCacheEntry`s
2455 * by peer identity. (We may have ephemerals in our
2456 * cache for which we do not have a neighbour entry,
2457 * and similar many neighbours may not need ephemerals,
2458 * so we use a second map.)
2460 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2463 * Task to free expired ephemerals.
2465 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2468 * Task run to initiate DV learning.
2470 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2473 * Task to run address validation.
2475 static struct GNUNET_SCHEDULER_Task *validation_task;
2478 * The most recent PA we have created, head of DLL.
2479 * The length of the DLL is kept in #pa_count.
2481 static struct PendingAcknowledgement *pa_head;
2484 * The oldest PA we have created, tail of DLL.
2485 * The length of the DLL is kept in #pa_count.
2487 static struct PendingAcknowledgement *pa_tail;
2490 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2491 * limit the size of the data structure.
2493 static unsigned int pa_count;
2497 * Get an offset into the transmission history buffer for `struct
2498 * PerformanceData`. Note that the caller must perform the required
2499 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2502 * An 'age' lasts 15 minute slots.
2504 * @return current age of the world
2509 struct GNUNET_TIME_Absolute now;
2511 now = GNUNET_TIME_absolute_get ();
2512 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2517 * Release @a pa data structure.
2519 * @param pa data structure to release
2522 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2524 struct Queue *q = pa->queue;
2525 struct PendingMessage *pm = pa->pm;
2526 struct DistanceVectorHop *dvh = pa->dvh;
2528 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2532 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2537 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2542 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2545 GNUNET_assert (GNUNET_YES ==
2546 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2547 &pa->ack_uuid.value,
2554 * Free cached ephemeral key.
2556 * @param ece cached signature to free
2559 free_ephemeral (struct EphemeralCacheEntry *ece)
2561 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2562 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2568 * Free validation state.
2570 * @param vs validation state to free
2573 free_validation_state (struct ValidationState *vs)
2575 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2576 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2580 GNUNET_PEERSTORE_store_cancel (vs->sc);
2583 GNUNET_free (vs->address);
2589 * Lookup neighbour record for peer @a pid.
2591 * @param pid neighbour to look for
2592 * @return NULL if we do not have this peer as a neighbour
2594 static struct Neighbour *
2595 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2597 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2602 * Details about what to notify monitors about.
2607 * @deprecated To be discussed if we keep these...
2609 struct GNUNET_TIME_Absolute last_validation;
2610 struct GNUNET_TIME_Absolute valid_until;
2611 struct GNUNET_TIME_Absolute next_validation;
2614 * Current round-trip time estimate.
2616 struct GNUNET_TIME_Relative rtt;
2619 * Connection status.
2621 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2626 uint32_t num_msg_pending;
2631 uint32_t num_bytes_pending;
2636 * Free a @dvh. Callers MAY want to check if this was the last path to the
2637 * `target`, and if so call #free_dv_route to also free the associated DV
2638 * entry in #dv_routes (if not, the associated scheduler job should eventually
2641 * @param dvh hop to free
2644 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2646 struct Neighbour *n = dvh->next_hop;
2647 struct DistanceVector *dv = dvh->dv;
2648 struct PendingAcknowledgement *pa;
2649 struct PendingMessage *pm;
2651 while (NULL != (pm = dvh->pending_msg_head))
2653 GNUNET_CONTAINER_MDLL_remove (dvh,
2654 dvh->pending_msg_head,
2655 dvh->pending_msg_tail,
2659 while (NULL != (pa = dvh->pa_head))
2661 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2664 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2665 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2671 * Free entry in #dv_routes. First frees all hops to the target, and
2672 * if there are no entries left, frees @a dv as well.
2674 * @param dv route to free
2677 free_dv_route (struct DistanceVector *dv)
2679 struct DistanceVectorHop *dvh;
2681 while (NULL != (dvh = dv->dv_head))
2682 free_distance_vector_hop (dvh);
2683 if (NULL == dv->dv_head)
2687 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2688 if (NULL != dv->visibility_task)
2689 GNUNET_SCHEDULER_cancel (dv->visibility_task);
2690 if (NULL != dv->timeout_task)
2691 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2698 * Notify monitor @a tc about an event. That @a tc
2699 * cares about the event has already been checked.
2701 * Send @a tc information in @a me about a @a peer's status with
2702 * respect to some @a address to all monitors that care.
2704 * @param tc monitor to inform
2705 * @param peer peer the information is about
2706 * @param address address the information is about
2707 * @param nt network type associated with @a address
2708 * @param me detailed information to transmit
2711 notify_monitor (struct TransportClient *tc,
2712 const struct GNUNET_PeerIdentity *peer,
2713 const char *address,
2714 enum GNUNET_NetworkType nt,
2715 const struct MonitorEvent *me)
2717 struct GNUNET_MQ_Envelope *env;
2718 struct GNUNET_TRANSPORT_MonitorData *md;
2719 size_t addr_len = strlen (address) + 1;
2721 env = GNUNET_MQ_msg_extra (md,
2723 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2724 md->nt = htonl ((uint32_t) nt);
2726 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2727 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2728 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2729 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2730 md->cs = htonl ((uint32_t) me->cs);
2731 md->num_msg_pending = htonl (me->num_msg_pending);
2732 md->num_bytes_pending = htonl (me->num_bytes_pending);
2733 memcpy (&md[1], address, addr_len);
2734 GNUNET_MQ_send (tc->mq, env);
2739 * Send information in @a me about a @a peer's status with respect
2740 * to some @a address to all monitors that care.
2742 * @param peer peer the information is about
2743 * @param address address the information is about
2744 * @param nt network type associated with @a address
2745 * @param me detailed information to transmit
2748 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2749 const char *address,
2750 enum GNUNET_NetworkType nt,
2751 const struct MonitorEvent *me)
2753 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2755 if (CT_MONITOR != tc->type)
2757 if (tc->details.monitor.one_shot)
2759 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2760 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2762 notify_monitor (tc, peer, address, nt, me);
2768 * Called whenever a client connects. Allocates our
2769 * data structures associated with that client.
2771 * @param cls closure, NULL
2772 * @param client identification of the client
2773 * @param mq message queue for the client
2774 * @return our `struct TransportClient`
2777 client_connect_cb (void *cls,
2778 struct GNUNET_SERVICE_Client *client,
2779 struct GNUNET_MQ_Handle *mq)
2781 struct TransportClient *tc;
2784 tc = GNUNET_new (struct TransportClient);
2785 tc->client = client;
2787 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2796 * @param rc data structure to free
2799 free_reassembly_context (struct ReassemblyContext *rc)
2801 struct Neighbour *n = rc->neighbour;
2803 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2804 GNUNET_assert (GNUNET_OK ==
2805 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2813 * Task run to clean up reassembly context of a neighbour that have expired.
2815 * @param cls a `struct Neighbour`
2818 reassembly_cleanup_task (void *cls)
2820 struct Neighbour *n = cls;
2821 struct ReassemblyContext *rc;
2823 n->reassembly_timeout_task = NULL;
2824 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2826 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2829 free_reassembly_context (rc);
2832 GNUNET_assert (NULL == n->reassembly_timeout_task);
2833 n->reassembly_timeout_task =
2834 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2835 &reassembly_cleanup_task,
2843 * function called to #free_reassembly_context().
2847 * @param value a `struct ReassemblyContext` to free
2848 * @return #GNUNET_OK (continue iteration)
2851 free_reassembly_cb (void *cls, uint32_t key, void *value)
2853 struct ReassemblyContext *rc = value;
2857 free_reassembly_context (rc);
2863 * Release memory used by @a neighbour.
2865 * @param neighbour neighbour entry to free
2868 free_neighbour (struct Neighbour *neighbour)
2870 struct DistanceVectorHop *dvh;
2872 GNUNET_assert (NULL == neighbour->queue_head);
2873 GNUNET_assert (GNUNET_YES ==
2874 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2877 if (NULL != neighbour->timeout_task)
2878 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2879 if (NULL != neighbour->reassembly_map)
2881 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2882 &free_reassembly_cb,
2884 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2885 neighbour->reassembly_map = NULL;
2886 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2887 neighbour->reassembly_heap = NULL;
2889 while (NULL != (dvh = neighbour->dv_head))
2891 struct DistanceVector *dv = dvh->dv;
2893 free_distance_vector_hop (dvh);
2894 if (NULL == dv->dv_head)
2897 if (NULL != neighbour->reassembly_timeout_task)
2899 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2900 neighbour->reassembly_timeout_task = NULL;
2902 if (NULL != neighbour->get)
2904 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2905 neighbour->get = NULL;
2907 if (NULL != neighbour->sc)
2909 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2910 neighbour->sc = NULL;
2912 GNUNET_free (neighbour);
2917 * Send message to CORE clients that we lost a connection.
2919 * @param tc client to inform (must be CORE client)
2920 * @param pid peer the connection is for
2921 * @param quota_out current quota for the peer
2924 core_send_connect_info (struct TransportClient *tc,
2925 const struct GNUNET_PeerIdentity *pid,
2926 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2928 struct GNUNET_MQ_Envelope *env;
2929 struct ConnectInfoMessage *cim;
2931 GNUNET_assert (CT_CORE == tc->type);
2932 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2933 cim->quota_out = quota_out;
2935 GNUNET_MQ_send (tc->mq, env);
2940 * Send message to CORE clients that we gained a connection
2942 * @param pid peer the queue was for
2943 * @param quota_out current quota for the peer
2946 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2947 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2950 "Informing CORE clients about connection to %s\n",
2952 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2954 if (CT_CORE != tc->type)
2956 core_send_connect_info (tc, pid, quota_out);
2962 * Send message to CORE clients that we lost a connection.
2964 * @param pid peer the connection was for
2967 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2970 "Informing CORE clients about disconnect from %s\n",
2972 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2974 struct GNUNET_MQ_Envelope *env;
2975 struct DisconnectInfoMessage *dim;
2977 if (CT_CORE != tc->type)
2979 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2981 GNUNET_MQ_send (tc->mq, env);
2987 * We believe we are ready to transmit a message on a queue. Gives the
2988 * message to the communicator for transmission (updating the tracker,
2989 * and re-scheduling itself if applicable).
2991 * @param cls the `struct Queue` to process transmissions for
2994 transmit_on_queue (void *cls);
2998 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2999 * we should run immediately or if the message queue is empty.
3000 * Test for no task being added AND queue not being empty to
3001 * transmit immediately afterwards! This function must only
3002 * be called if the message queue is non-empty!
3004 * @param queue the queue to do scheduling for
3005 * @param inside_job set to #GNUNET_YES if called from
3006 * #transmit_on_queue() itself and NOT setting
3007 * the task means running immediately
3010 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3012 struct Neighbour *n = queue->neighbour;
3013 struct PendingMessage *pm = n->pending_msg_head;
3014 struct GNUNET_TIME_Relative out_delay;
3016 GNUNET_assert (NULL != pm);
3017 if (queue->tc->details.communicator.total_queue_length >=
3018 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3020 GNUNET_STATISTICS_update (
3022 "# Transmission throttled due to communicator queue limit",
3027 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3029 GNUNET_STATISTICS_update (GST_stats,
3030 "# Transmission throttled due to queue queue limit",
3036 out_delay = GNUNET_TIME_absolute_get_remaining (pm->next_attempt);
3037 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3040 GNUNET_ERROR_TYPE_DEBUG,
3041 "Schedule transmission on queue %llu of %s decides to run immediately\n",
3042 (unsigned long long) queue->qid,
3043 GNUNET_i2s (&n->pid));
3044 return; /* we should run immediately! */
3046 /* queue has changed since we were scheduled, reschedule again */
3047 queue->transmit_task =
3048 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3049 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3050 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3051 "Next transmission on queue `%s' in %s (high delay)\n",
3053 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3056 "Next transmission on queue `%s' in %s\n",
3058 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3063 * Check whether the CORE visibility of @a n changed. If so,
3064 * check whether we need to notify CORE.
3066 * @param n neighbour to perform the check for
3069 update_neighbour_core_visibility (struct Neighbour *n);
3075 * @param queue the queue to free
3078 free_queue (struct Queue *queue)
3080 struct Neighbour *neighbour = queue->neighbour;
3081 struct TransportClient *tc = queue->tc;
3082 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3083 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3084 struct QueueEntry *qe;
3086 struct PendingAcknowledgement *pa;
3088 if (NULL != queue->transmit_task)
3090 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3091 queue->transmit_task = NULL;
3093 if (NULL != queue->visibility_task)
3095 GNUNET_SCHEDULER_cancel (queue->visibility_task);
3096 queue->visibility_task = NULL;
3098 while (NULL != (pa = queue->pa_head))
3100 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3104 GNUNET_CONTAINER_MDLL_remove (neighbour,
3105 neighbour->queue_head,
3106 neighbour->queue_tail,
3108 GNUNET_CONTAINER_MDLL_remove (client,
3109 tc->details.communicator.queue_head,
3110 tc->details.communicator.queue_tail,
3112 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3113 tc->details.communicator.total_queue_length);
3114 while (NULL != (qe = queue->queue_head))
3116 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3117 queue->queue_length--;
3118 tc->details.communicator.total_queue_length--;
3121 GNUNET_assert (qe == qe->pm->qe);
3126 GNUNET_assert (0 == queue->queue_length);
3127 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3128 tc->details.communicator.total_queue_length))
3130 /* Communicator dropped below threshold, resume all queues */
3131 GNUNET_STATISTICS_update (
3133 "# Transmission throttled due to communicator queue limit",
3136 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3138 schedule_transmit_on_queue (s, GNUNET_NO);
3140 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3141 GNUNET_free (queue);
3143 update_neighbour_core_visibility (neighbour);
3144 cores_send_disconnect_info (&neighbour->pid);
3146 if (NULL == neighbour->queue_head)
3148 free_neighbour (neighbour);
3156 * @param ale address list entry to free
3159 free_address_list_entry (struct AddressListEntry *ale)
3161 struct TransportClient *tc = ale->tc;
3163 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3164 tc->details.communicator.addr_tail,
3166 if (NULL != ale->sc)
3168 GNUNET_PEERSTORE_store_cancel (ale->sc);
3171 if (NULL != ale->st)
3173 GNUNET_SCHEDULER_cancel (ale->st);
3181 * Stop the peer request in @a value.
3183 * @param cls a `struct TransportClient` that no longer makes the request
3184 * @param pid the peer's identity
3185 * @param value a `struct PeerRequest`
3186 * @return #GNUNET_YES (always)
3189 stop_peer_request (void *cls,
3190 const struct GNUNET_PeerIdentity *pid,
3193 struct TransportClient *tc = cls;
3194 struct PeerRequest *pr = value;
3196 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3199 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3209 * Called whenever a client is disconnected. Frees our
3210 * resources associated with that client.
3212 * @param cls closure, NULL
3213 * @param client identification of the client
3214 * @param app_ctx our `struct TransportClient`
3217 client_disconnect_cb (void *cls,
3218 struct GNUNET_SERVICE_Client *client,
3221 struct TransportClient *tc = app_ctx;
3225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3226 "Client %p disconnected, cleaning up.\n",
3228 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3234 struct PendingMessage *pm;
3236 while (NULL != (pm = tc->details.core.pending_msg_head))
3238 GNUNET_CONTAINER_MDLL_remove (client,
3239 tc->details.core.pending_msg_head,
3240 tc->details.core.pending_msg_tail,
3248 case CT_COMMUNICATOR: {
3250 struct AddressListEntry *ale;
3252 while (NULL != (q = tc->details.communicator.queue_head))
3254 while (NULL != (ale = tc->details.communicator.addr_head))
3255 free_address_list_entry (ale);
3256 GNUNET_free (tc->details.communicator.address_prefix);
3259 case CT_APPLICATION:
3260 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3263 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3271 * Iterator telling new CORE client about all existing
3272 * connections to peers.
3274 * @param cls the new `struct TransportClient`
3275 * @param pid a connected peer
3276 * @param value the `struct Neighbour` with more information
3277 * @return #GNUNET_OK (continue to iterate)
3280 notify_client_connect_info (void *cls,
3281 const struct GNUNET_PeerIdentity *pid,
3284 struct TransportClient *tc = cls;
3285 struct Neighbour *neighbour = value;
3287 core_send_connect_info (tc, pid, neighbour->quota_out);
3293 * Initialize a "CORE" client. We got a start message from this
3294 * client, so add it to the list of clients for broadcasting of
3297 * @param cls the client
3298 * @param start the start message that was sent
3301 handle_client_start (void *cls, const struct StartMessage *start)
3303 struct TransportClient *tc = cls;
3306 options = ntohl (start->options);
3307 if ((0 != (1 & options)) &&
3308 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3310 /* client thinks this is a different peer, reject */
3312 GNUNET_SERVICE_client_drop (tc->client);
3315 if (CT_NONE != tc->type)
3318 GNUNET_SERVICE_client_drop (tc->client);
3322 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3323 ¬ify_client_connect_info,
3325 GNUNET_SERVICE_client_continue (tc->client);
3330 * Client asked for transmission to a peer. Process the request.
3332 * @param cls the client
3333 * @param obm the send message that was sent
3336 check_client_send (void *cls, const struct OutboundMessage *obm)
3338 struct TransportClient *tc = cls;
3340 const struct GNUNET_MessageHeader *obmm;
3342 if (CT_CORE != tc->type)
3345 return GNUNET_SYSERR;
3347 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3348 if (size < sizeof (struct GNUNET_MessageHeader))
3351 return GNUNET_SYSERR;
3353 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3354 if (size != ntohs (obmm->size))
3357 return GNUNET_SYSERR;
3364 * Free fragment tree below @e root, excluding @e root itself.
3365 * FIXME: this does NOT seem to have the intended semantics
3366 * based on how this is called. Seems we generally DO expect
3367 * @a root to be free'ed itself as well!
3369 * @param root root of the tree to free
3372 free_fragment_tree (struct PendingMessage *root)
3374 struct PendingMessage *frag;
3376 while (NULL != (frag = root->head_frag))
3378 struct PendingAcknowledgement *pa;
3380 free_fragment_tree (frag);
3381 while (NULL != (pa = frag->pa_head))
3383 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3386 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3393 * Release memory associated with @a pm and remove @a pm from associated
3394 * data structures. @a pm must be a top-level pending message and not
3395 * a fragment in the tree. The entire tree is freed (if applicable).
3397 * @param pm the pending message to free
3400 free_pending_message (struct PendingMessage *pm)
3402 struct TransportClient *tc = pm->client;
3403 struct Neighbour *target = pm->target;
3404 struct DistanceVectorHop *dvh = pm->dvh;
3405 struct PendingAcknowledgement *pa;
3409 GNUNET_CONTAINER_MDLL_remove (client,
3410 tc->details.core.pending_msg_head,
3411 tc->details.core.pending_msg_tail,
3416 GNUNET_CONTAINER_MDLL_remove (dvh,
3417 dvh->pending_msg_head,
3418 dvh->pending_msg_tail,
3421 GNUNET_CONTAINER_MDLL_remove (neighbour,
3422 target->pending_msg_head,
3423 target->pending_msg_tail,
3425 while (NULL != (pa = pm->pa_head))
3427 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3431 free_fragment_tree (pm);
3434 GNUNET_assert (pm == pm->qe->pm);
3437 GNUNET_free_non_null (pm->bpm);
3443 * Send a response to the @a pm that we have processed a
3444 * "send" request with status @a success. We
3445 * transmitted @a bytes_physical on the actual wire.
3446 * Sends a confirmation to the "core" client responsible
3447 * for the original request and free's @a pm.
3449 * @param pm handle to the original pending message
3450 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
3451 * for transmission failure
3452 * @param bytes_physical amount of bandwidth consumed
3455 client_send_response (struct PendingMessage *pm,
3457 uint32_t bytes_physical)
3459 struct TransportClient *tc = pm->client;
3460 struct Neighbour *target = pm->target;
3461 struct GNUNET_MQ_Envelope *env;
3462 struct SendOkMessage *som;
3466 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3467 som->success = htonl ((uint32_t) success);
3468 som->bytes_msg = htons (pm->bytes_msg);
3469 som->bytes_physical = htonl (bytes_physical);
3470 som->peer = target->pid;
3471 GNUNET_MQ_send (tc->mq, env);
3473 free_pending_message (pm);
3478 * Checks the message queue for a neighbour for messages that have timed
3479 * out and purges them.
3481 * @param cls a `struct Neighbour`
3484 check_queue_timeouts (void *cls)
3486 struct Neighbour *n = cls;
3487 struct PendingMessage *pm;
3488 struct GNUNET_TIME_Absolute now;
3489 struct GNUNET_TIME_Absolute earliest_timeout;
3491 n->timeout_task = NULL;
3492 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
3493 now = GNUNET_TIME_absolute_get ();
3494 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
3496 pm = pos->next_neighbour;
3497 if (pos->timeout.abs_value_us <= now.abs_value_us)
3499 GNUNET_STATISTICS_update (GST_stats,
3500 "# messages dropped (timeout before confirmation)",
3503 client_send_response (pm, GNUNET_NO, 0);
3507 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
3509 n->earliest_timeout = earliest_timeout;
3510 if (NULL != n->pending_msg_head)
3512 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
3517 * Create a DV Box message.
3519 * @param total_hops how many hops did the message take so far
3520 * @param num_hops length of the @a hops array
3521 * @param origin origin of the message
3522 * @param hops next peer(s) to the destination, including destination
3523 * @param payload payload of the box
3524 * @param payload_size number of bytes in @a payload
3525 * @return boxed message (caller must #GNUNET_free() it).
3527 static struct TransportDVBoxMessage *
3528 create_dv_box (uint16_t total_hops,
3529 const struct GNUNET_PeerIdentity *origin,
3530 const struct GNUNET_PeerIdentity *target,
3532 const struct GNUNET_PeerIdentity *hops,
3533 const void *payload,
3534 uint16_t payload_size)
3536 struct TransportDVBoxMessage *dvb;
3537 struct GNUNET_PeerIdentity *dhops;
3539 GNUNET_assert (UINT16_MAX <
3540 sizeof (struct TransportDVBoxMessage) +
3541 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3543 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3544 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3547 htons (sizeof (struct TransportDVBoxMessage) +
3548 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3549 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3550 dvb->total_hops = htons (total_hops);
3551 dvb->num_hops = htons (num_hops + 1);
3552 dvb->origin = *origin;
3553 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3554 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3555 dhops[num_hops] = *target;
3556 memcpy (&dhops[num_hops + 1], payload, payload_size);
3562 * Pick @a hops_array_length random DV paths satisfying @a options
3564 * @param dv data structure to pick paths from
3565 * @param options constraints to satisfy
3566 * @param hops_array[out] set to the result
3567 * @param hops_array_length length of the @a hops_array
3568 * @return number of entries set in @a hops_array
3571 pick_random_dv_hops (const struct DistanceVector *dv,
3572 enum RouteMessageOptions options,
3573 struct DistanceVectorHop **hops_array,
3574 unsigned int hops_array_length)
3576 uint64_t choices[hops_array_length];
3578 unsigned int dv_count;
3580 /* Pick random vectors, but weighted by distance, giving more weight
3581 to shorter vectors */
3584 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3587 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3588 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3589 .rel_value_us == 0))
3590 continue; /* pos unconfirmed and confirmed required */
3591 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3596 if (dv_count <= hops_array_length)
3599 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3601 hops_array[dv_count++] = pos;
3604 for (unsigned int i = 0; i < hops_array_length; i++)
3607 while (GNUNET_NO == ok)
3610 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3612 for (unsigned int j = 0; j < i; j++)
3613 if (choices[i] == choices[j])
3622 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3625 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3627 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3628 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3629 .rel_value_us == 0))
3630 continue; /* pos unconfirmed and confirmed required */
3631 for (unsigned int i = 0; i < hops_array_length; i++)
3632 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3633 hops_array[dv_count++] = pos;
3641 * Client asked for transmission to a peer. Process the request.
3643 * @param cls the client
3644 * @param obm the send message that was sent
3647 handle_client_send (void *cls, const struct OutboundMessage *obm)
3649 struct TransportClient *tc = cls;
3650 struct PendingMessage *pm;
3651 const struct GNUNET_MessageHeader *obmm;
3652 struct Neighbour *target;
3653 struct DistanceVector *dv;
3654 struct DistanceVectorHop *dvh;
3657 const void *payload;
3658 size_t payload_size;
3659 struct TransportDVBoxMessage *dvb;
3661 GNUNET_assert (CT_CORE == tc->type);
3662 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3663 bytes_msg = ntohs (obmm->size);
3664 target = lookup_neighbour (&obm->peer);
3666 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3669 if ((NULL == target) && ((NULL == dv) || (GNUNET_NO == dv->core_visible)))
3671 /* Failure: don't have this peer as a neighbour (anymore).
3672 Might have gone down asynchronously, so this is NOT
3673 a protocol violation by CORE. Still count the event,
3674 as this should be rare. */
3675 struct GNUNET_MQ_Envelope *env;
3676 struct SendOkMessage *som;
3678 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3679 som->success = htonl (GNUNET_SYSERR);
3680 som->bytes_msg = htonl (bytes_msg);
3681 som->bytes_physical = htonl (0);
3682 som->peer = obm->peer;
3683 GNUNET_MQ_send (tc->mq, env);
3684 GNUNET_SERVICE_client_continue (tc->client);
3685 GNUNET_STATISTICS_update (GST_stats,
3686 "# messages dropped (neighbour unknown)",
3694 struct DistanceVectorHop *dvh;
3696 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3697 GNUNET_assert (1 == res);
3698 target = dvh->next_hop;
3699 dvb = create_dv_box (0,
3707 payload_size = ntohs (dvb->header.size);
3714 payload_size = bytes_msg;
3717 was_empty = (NULL == target->pending_msg_head);
3718 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3720 pm->target = target;
3721 pm->bytes_msg = payload_size;
3723 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
3724 memcpy (&pm[1], payload, payload_size);
3725 GNUNET_free_non_null (dvb);
3730 GNUNET_CONTAINER_MDLL_insert (dvh,
3731 dvh->pending_msg_head,
3732 dvh->pending_msg_tail,
3735 GNUNET_CONTAINER_MDLL_insert (neighbour,
3736 target->pending_msg_head,
3737 target->pending_msg_tail,
3739 GNUNET_CONTAINER_MDLL_insert (client,
3740 tc->details.core.pending_msg_head,
3741 tc->details.core.pending_msg_tail,
3743 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3745 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3746 if (NULL != target->timeout_task)
3747 GNUNET_SCHEDULER_cancel (target->timeout_task);
3748 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3749 &check_queue_timeouts,
3753 return; /* all queues must already be busy */
3754 for (struct Queue *queue = target->queue_head; NULL != queue;
3755 queue = queue->next_neighbour)
3757 /* try transmission on any queue that is idle */
3758 if (NULL == queue->transmit_task)
3759 queue->transmit_task =
3760 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3766 * Communicator started. Test message is well-formed.
3768 * @param cls the client
3769 * @param cam the send message that was sent
3772 check_communicator_available (
3774 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3776 struct TransportClient *tc = cls;
3779 if (CT_NONE != tc->type)
3782 return GNUNET_SYSERR;
3784 tc->type = CT_COMMUNICATOR;
3785 size = ntohs (cam->header.size) - sizeof (*cam);
3787 return GNUNET_OK; /* receive-only communicator */
3788 GNUNET_MQ_check_zero_termination (cam);
3794 * Communicator started. Process the request.
3796 * @param cls the client
3797 * @param cam the send message that was sent
3800 handle_communicator_available (
3802 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3804 struct TransportClient *tc = cls;
3807 size = ntohs (cam->header.size) - sizeof (*cam);
3809 return; /* receive-only communicator */
3810 tc->details.communicator.address_prefix =
3811 GNUNET_strdup ((const char *) &cam[1]);
3812 tc->details.communicator.cc =
3813 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3814 GNUNET_SERVICE_client_continue (tc->client);
3819 * Communicator requests backchannel transmission. Check the request.
3821 * @param cls the client
3822 * @param cb the send message that was sent
3823 * @return #GNUNET_OK if message is well-formed
3826 check_communicator_backchannel (
3828 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3830 const struct GNUNET_MessageHeader *inbox;
3836 msize = ntohs (cb->header.size) - sizeof (*cb);
3837 if (((size_t) (UINT16_MAX - msize)) >
3838 sizeof (struct TransportBackchannelEncapsulationMessage) +
3839 sizeof (struct TransportBackchannelRequestPayloadP))
3842 return GNUNET_SYSERR;
3844 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3845 isize = ntohs (inbox->size);
3849 return GNUNET_SYSERR;
3851 is = (const char *) inbox;
3854 GNUNET_assert (msize > 0);
3855 if ('\0' != is[msize - 1])
3858 return GNUNET_SYSERR;
3865 * Remove memory used by expired ephemeral keys.
3870 expire_ephemerals (void *cls)
3872 struct EphemeralCacheEntry *ece;
3875 ephemeral_task = NULL;
3876 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3878 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3881 free_ephemeral (ece);
3884 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3893 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3894 * one, cache it and return it.
3896 * @param pid peer to look up ephemeral for
3897 * @param private_key[out] set to the private key
3898 * @param ephemeral_key[out] set to the key
3899 * @param ephemeral_sender_sig[out] set to the signature
3900 * @param monotime[out] set to the monotime used for the signature
3903 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3904 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3905 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3906 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3907 struct GNUNET_TIME_Absolute *monotime)
3909 struct EphemeralCacheEntry *ece;
3910 struct EphemeralConfirmationPS ec;
3912 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3913 if ((NULL != ece) &&
3914 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3917 free_ephemeral (ece);
3922 ece = GNUNET_new (struct EphemeralCacheEntry);
3924 ece->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
3925 ece->ephemeral_validity =
3926 GNUNET_TIME_absolute_add (ece->monotime, EPHEMERAL_VALIDITY);
3927 GNUNET_assert (GNUNET_OK ==
3928 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3929 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3930 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3931 ec.purpose.size = htonl (sizeof (ec));
3933 ec.ephemeral_key = ece->ephemeral_key;
3934 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3938 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3940 ece->ephemeral_validity.abs_value_us);
3941 GNUNET_assert (GNUNET_OK ==
3942 GNUNET_CONTAINER_multipeermap_put (
3946 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3947 if (NULL == ephemeral_task)
3948 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3952 *private_key = ece->private_key;
3953 *ephemeral_key = ece->ephemeral_key;
3954 *ephemeral_sender_sig = ece->sender_sig;
3955 *monotime = ece->monotime;
3960 * Send the control message @a payload on @a queue.
3962 * @param queue the queue to use for transmission
3963 * @param pm pending message to update once transmission is done, may be NULL!
3964 * @param payload the payload to send (encapsulated in a
3965 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3966 * @param payload_size number of bytes in @a payload
3969 queue_send_msg (struct Queue *queue,
3970 struct PendingMessage *pm,
3971 const void *payload,
3972 size_t payload_size)
3974 struct Neighbour *n = queue->neighbour;
3975 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3976 struct GNUNET_MQ_Envelope *env;
3978 env = GNUNET_MQ_msg_extra (smt,
3980 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3981 smt->qid = queue->qid;
3982 smt->mid = queue->mid_gen;
3983 smt->receiver = n->pid;
3984 memcpy (&smt[1], payload, payload_size);
3986 /* Pass the env to the communicator of queue for transmission. */
3987 struct QueueEntry *qe;
3989 qe = GNUNET_new (struct QueueEntry);
3990 qe->mid = queue->mid_gen++;
3995 GNUNET_assert (NULL == pm->qe);
3998 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3999 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4000 queue->queue_length++;
4001 queue->tc->details.communicator.total_queue_length++;
4002 GNUNET_MQ_send (queue->tc->mq, env);
4008 * Pick a queue of @a n under constraints @a options and schedule
4009 * transmission of @a hdr.
4011 * @param n neighbour to send to
4012 * @param hdr message to send as payload
4013 * @param options whether queues must be confirmed or not,
4014 * and whether we may pick multiple (2) queues
4017 route_via_neighbour (const struct Neighbour *n,
4018 const struct GNUNET_MessageHeader *hdr,
4019 enum RouteMessageOptions options)
4021 struct GNUNET_TIME_Absolute now;
4022 unsigned int candidates;
4026 /* Pick one or two 'random' queues from n (under constraints of options) */
4027 now = GNUNET_TIME_absolute_get ();
4028 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4029 weight in the future; weight could be assigned by observed
4030 bandwidth (note: not sure if we should do this for this type
4031 of control traffic though). */
4033 for (struct Queue *pos = n->queue_head; NULL != pos;
4034 pos = pos->next_neighbour)
4036 /* Count the queue with the visibility task in all cases, as
4037 otherwise we may end up with no queues just because the
4038 time for the visibility task just expired but the scheduler
4039 just ran this task first */
4040 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4041 (pos->validated_until.abs_value_us > now.abs_value_us) ||
4042 (NULL != pos->visibility_task))
4045 if (0 == candidates)
4047 /* Given that we above check for pos->visibility task,
4048 this should be strictly impossible. */
4052 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4053 if (0 == (options & RMO_REDUNDANT))
4054 sel2 = candidates; /* picks none! */
4056 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4058 for (struct Queue *pos = n->queue_head; NULL != pos;
4059 pos = pos->next_neighbour)
4061 /* Count the queue with the visibility task in all cases, as
4062 otherwise we may end up with no queues just because the
4063 time for the visibility task just expired but the scheduler
4064 just ran this task first */
4065 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
4066 (NULL != pos->visibility_task))
4068 if ((sel1 == candidates) || (sel2 == candidates))
4069 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4077 * Given a distance vector path @a dvh route @a payload to
4078 * the ultimate destination respecting @a options.
4079 * Sets up the boxed message and queues it at the next hop.
4081 * @param dvh choice of the path for the message
4082 * @param payload body to transmit
4083 * @param options options to use for control
4086 forward_via_dvh (const struct DistanceVectorHop *dvh,
4087 const struct GNUNET_MessageHeader *payload,
4088 enum RouteMessageOptions options)
4090 struct TransportDVBoxMessage *dvb;
4092 dvb = create_dv_box (0,
4098 ntohs (payload->size));
4099 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4105 * Pick a path of @a dv under constraints @a options and schedule
4106 * transmission of @a hdr.
4108 * @param n neighbour to send to
4109 * @param hdr message to send as payload
4110 * @param options whether path must be confirmed or not
4111 * and whether we may pick multiple (2) paths
4114 route_via_dv (const struct DistanceVector *dv,
4115 const struct GNUNET_MessageHeader *hdr,
4116 enum RouteMessageOptions options)
4118 struct DistanceVectorHop *hops[2];
4121 res = pick_random_dv_hops (dv,
4124 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4125 for (unsigned int i = 0; i < res; i++)
4126 forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT));
4131 * We need to transmit @a hdr to @a target. If necessary, this may
4132 * involve DV routing.
4134 * @param target peer to receive @a hdr
4135 * @param hdr header of the message to route and #GNUNET_free()
4136 * @param options which transmission channels are allowed
4139 route_message (const struct GNUNET_PeerIdentity *target,
4140 struct GNUNET_MessageHeader *hdr,
4141 enum RouteMessageOptions options)
4143 struct Neighbour *n;
4144 struct DistanceVector *dv;
4146 n = lookup_neighbour (target);
4147 dv = (0 != (options & RMO_DV_ALLOWED))
4148 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
4150 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4152 /* if confirmed is required, and we do not have anything
4153 confirmed, drop respective options */
4154 if ((NULL != n) && (GNUNET_NO == n->core_visible))
4156 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
4159 if ((NULL == n) && (NULL == dv))
4161 GNUNET_STATISTICS_update (GST_stats,
4162 "# Messages dropped in routing: no acceptable method",
4168 /* If both dv and n are possible and we must choose:
4169 flip a coin for the choice between the two; for now 50/50 */
4170 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4172 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4177 if ((NULL != n) && (NULL != dv))
4178 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4179 enough for redunancy, so clear the flag. */
4182 route_via_neighbour (n, hdr, options);
4186 route_via_dv (dv, hdr, options);
4193 * Structure of the key material used to encrypt backchannel messages.
4195 struct BackchannelKeyState
4198 * State of our block cipher.
4200 gcry_cipher_hd_t cipher;
4203 * Actual key material.
4209 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4211 struct GNUNET_CRYPTO_AuthKey hmac_key;
4214 * Symmetric key to use for encryption.
4216 char aes_key[256 / 8];
4219 * Counter value to use during setup.
4221 char aes_ctr[128 / 8];
4228 * Given the key material in @a km and the initialization vector
4229 * @a iv, setup the key material for the backchannel in @a key.
4231 * @param km raw master secret
4232 * @param iv initialization vector
4233 * @param key[out] symmetric cipher and HMAC state to generate
4236 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4237 const struct GNUNET_ShortHashCode *iv,
4238 struct BackchannelKeyState *key)
4240 /* must match #dh_key_derive_eph_pub */
4241 GNUNET_assert (GNUNET_YES ==
4242 GNUNET_CRYPTO_kdf (&key->material,
4243 sizeof (key->material),
4244 "transport-backchannel-key",
4245 strlen ("transport-backchannel-key"),
4250 gcry_cipher_open (&key->cipher,
4251 GCRY_CIPHER_AES256 /* low level: go for speed */,
4252 GCRY_CIPHER_MODE_CTR,
4254 gcry_cipher_setkey (key->cipher,
4255 &key->material.aes_key,
4256 sizeof (key->material.aes_key));
4257 gcry_cipher_setctr (key->cipher,
4258 &key->material.aes_ctr,
4259 sizeof (key->material.aes_ctr));
4264 * Derive backchannel encryption key material from @a priv_ephemeral
4265 * and @a target and @a iv.
4267 * @param priv_ephemeral ephemeral private key to use
4268 * @param target the target peer to encrypt to
4269 * @param iv unique IV to use
4270 * @param key[out] set to the key material
4273 dh_key_derive_eph_pid (
4274 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4275 const struct GNUNET_PeerIdentity *target,
4276 const struct GNUNET_ShortHashCode *iv,
4277 struct BackchannelKeyState *key)
4279 struct GNUNET_HashCode km;
4281 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4282 &target->public_key,
4284 bc_setup_key_state_from_km (&km, iv, key);
4289 * Derive backchannel encryption key material from #GST_my_private_key
4290 * and @a pub_ephemeral and @a iv.
4292 * @param priv_ephemeral ephemeral private key to use
4293 * @param target the target peer to encrypt to
4294 * @param iv unique IV to use
4295 * @param key[out] set to the key material
4298 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4299 const struct GNUNET_ShortHashCode *iv,
4300 struct BackchannelKeyState *key)
4302 struct GNUNET_HashCode km;
4304 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4307 bc_setup_key_state_from_km (&km, iv, key);
4312 * Do HMAC calculation for backchannel messages over @a data using key
4313 * material from @a key.
4315 * @param key key material (from DH)
4316 * @param hmac[out] set to the HMAC
4317 * @param data data to perform HMAC calculation over
4318 * @param data_size number of bytes in @a data
4321 bc_hmac (const struct BackchannelKeyState *key,
4322 struct GNUNET_HashCode *hmac,
4326 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4331 * Perform backchannel encryption using symmetric secret in @a key
4332 * to encrypt data from @a in to @a dst.
4334 * @param key[in,out] key material to use
4335 * @param dst where to write the result
4336 * @param in input data to encrypt (plaintext)
4337 * @param in_size number of bytes of input in @a in and available at @a dst
4340 bc_encrypt (struct BackchannelKeyState *key,
4346 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4351 * Perform backchannel encryption using symmetric secret in @a key
4352 * to encrypt data from @a in to @a dst.
4354 * @param key[in,out] key material to use
4355 * @param ciph cipher text to decrypt
4356 * @param out[out] output data to generate (plaintext)
4357 * @param out_size number of bytes of input in @a ciph and available in @a out
4360 bc_decrypt (struct BackchannelKeyState *key,
4366 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4371 * Clean up key material in @a key.
4373 * @param key key material to clean up (memory must not be free'd!)
4376 bc_key_clean (struct BackchannelKeyState *key)
4378 gcry_cipher_close (key->cipher);
4379 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4384 * Communicator requests backchannel transmission. Process the request.
4386 * @param cls the client
4387 * @param cb the send message that was sent
4390 handle_communicator_backchannel (
4392 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4394 struct TransportClient *tc = cls;
4395 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4396 struct GNUNET_TIME_Absolute monotime;
4397 struct TransportBackchannelEncapsulationMessage *enc;
4398 struct TransportBackchannelRequestPayloadP ppay;
4399 struct BackchannelKeyState key;
4403 /* encapsulate and encrypt message */
4404 msize = ntohs (cb->header.size) - sizeof (*cb) +
4405 sizeof (struct TransportBackchannelRequestPayloadP);
4406 enc = GNUNET_malloc (sizeof (*enc) + msize);
4408 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4409 enc->header.size = htons (sizeof (*enc) + msize);
4410 enc->target = cb->pid;
4411 lookup_ephemeral (&cb->pid,
4413 &enc->ephemeral_key,
4416 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4419 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4420 ppay.monotonic_time = GNUNET_TIME_absolute_hton (monotime);
4421 mpos = (char *) &enc[1];
4422 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4425 &mpos[sizeof (ppay)],
4426 ntohs (cb->header.size) - sizeof (*cb));
4430 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4431 bc_key_clean (&key);
4432 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4433 GNUNET_SERVICE_client_continue (tc->client);
4438 * Address of our peer added. Test message is well-formed.
4440 * @param cls the client
4441 * @param aam the send message that was sent
4442 * @return #GNUNET_OK if message is well-formed
4445 check_add_address (void *cls,
4446 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4448 struct TransportClient *tc = cls;
4450 if (CT_COMMUNICATOR != tc->type)
4453 return GNUNET_SYSERR;
4455 GNUNET_MQ_check_zero_termination (aam);
4461 * Ask peerstore to store our address.
4463 * @param cls an `struct AddressListEntry *`
4466 store_pi (void *cls);
4470 * Function called when peerstore is done storing our address.
4472 * @param cls a `struct AddressListEntry`
4473 * @param success #GNUNET_YES if peerstore was successful
4476 peerstore_store_own_cb (void *cls, int success)
4478 struct AddressListEntry *ale = cls;
4481 if (GNUNET_YES != success)
4482 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4483 "Failed to store our own address `%s' in peerstore!\n",
4485 /* refresh period is 1/4 of expiration time, that should be plenty
4486 without being excessive. */
4488 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4496 * Ask peerstore to store our address.
4498 * @param cls an `struct AddressListEntry *`
4501 store_pi (void *cls)
4503 struct AddressListEntry *ale = cls;
4506 struct GNUNET_TIME_Absolute expiration;
4509 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4510 GNUNET_HELLO_sign_address (ale->address,
4516 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4519 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4523 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4524 &peerstore_store_own_cb,
4527 if (NULL == ale->sc)
4529 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4530 "Failed to store our address `%s' with peerstore\n",
4533 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4539 * Address of our peer added. Process the request.
4541 * @param cls the client
4542 * @param aam the send message that was sent
4545 handle_add_address (void *cls,
4546 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4548 struct TransportClient *tc = cls;
4549 struct AddressListEntry *ale;
4552 slen = ntohs (aam->header.size) - sizeof (*aam);
4553 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4555 ale->address = (const char *) &ale[1];
4556 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4557 ale->aid = aam->aid;
4558 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4559 memcpy (&ale[1], &aam[1], slen);
4560 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4561 tc->details.communicator.addr_tail,
4563 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4564 GNUNET_SERVICE_client_continue (tc->client);
4569 * Address of our peer deleted. Process the request.
4571 * @param cls the client
4572 * @param dam the send message that was sent
4575 handle_del_address (void *cls,
4576 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4578 struct TransportClient *tc = cls;
4580 if (CT_COMMUNICATOR != tc->type)
4583 GNUNET_SERVICE_client_drop (tc->client);
4586 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4590 if (dam->aid != ale->aid)
4592 GNUNET_assert (ale->tc == tc);
4593 free_address_list_entry (ale);
4594 GNUNET_SERVICE_client_continue (tc->client);
4597 GNUNET_SERVICE_client_drop (tc->client);
4602 * Context from #handle_incoming_msg(). Closure for many
4603 * message handlers below.
4605 struct CommunicatorMessageContext
4608 * Which communicator provided us with the message.
4610 struct TransportClient *tc;
4613 * Additional information for flow control and about the sender.
4615 struct GNUNET_TRANSPORT_IncomingMessage im;
4618 * Number of hops the message has travelled (if DV-routed).
4619 * FIXME: make use of this in ACK handling!
4621 uint16_t total_hops;
4626 * Given an inbound message @a msg from a communicator @a cmc,
4627 * demultiplex it based on the type calling the right handler.
4629 * @param cmc context for demultiplexing
4630 * @param msg message to demultiplex
4633 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4634 const struct GNUNET_MessageHeader *msg);
4638 * Send ACK to communicator (if requested) and free @a cmc.
4640 * @param cmc context for which we are done handling the message
4643 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4645 if (0 != ntohl (cmc->im.fc_on))
4647 /* send ACK when done to communicator for flow control! */
4648 struct GNUNET_MQ_Envelope *env;
4649 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4651 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4652 ack->reserved = htonl (0);
4653 ack->fc_id = cmc->im.fc_id;
4654 ack->sender = cmc->im.sender;
4655 GNUNET_MQ_send (cmc->tc->mq, env);
4657 GNUNET_SERVICE_client_continue (cmc->tc->client);
4663 * Communicator gave us an unencapsulated message to pass as-is to
4664 * CORE. Process the request.
4666 * @param cls a `struct CommunicatorMessageContext` (must call
4667 * #finish_cmc_handling() when done)
4668 * @param mh the message that was received
4671 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4673 struct CommunicatorMessageContext *cmc = cls;
4674 uint16_t size = ntohs (mh->size);
4676 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4677 (size < sizeof (struct GNUNET_MessageHeader)))
4679 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4682 finish_cmc_handling (cmc);
4683 GNUNET_SERVICE_client_drop (client);
4686 /* Forward to all CORE clients */
4687 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4689 struct GNUNET_MQ_Envelope *env;
4690 struct InboundMessage *im;
4692 if (CT_CORE != tc->type)
4694 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4695 im->peer = cmc->im.sender;
4696 memcpy (&im[1], mh, size);
4697 GNUNET_MQ_send (tc->mq, env);
4699 /* FIXME: consider doing this _only_ once the message
4700 was drained from the CORE MQs to extend flow control to CORE!
4701 (basically, increment counter in cmc, decrement on MQ send continuation! */
4702 finish_cmc_handling (cmc);
4707 * Communicator gave us a fragment box. Check the message.
4709 * @param cls a `struct CommunicatorMessageContext`
4710 * @param fb the send message that was sent
4711 * @return #GNUNET_YES if message is well-formed
4714 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4716 uint16_t size = ntohs (fb->header.size);
4717 uint16_t bsize = size - sizeof (*fb);
4722 GNUNET_break_op (0);
4723 return GNUNET_SYSERR;
4725 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4727 GNUNET_break_op (0);
4728 return GNUNET_SYSERR;
4730 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4732 GNUNET_break_op (0);
4733 return GNUNET_SYSERR;
4740 * Clean up an idle cummulative acknowledgement data structure.
4742 * @param cls a `struct AcknowledgementCummulator *`
4745 destroy_ack_cummulator (void *cls)
4747 struct AcknowledgementCummulator *ac = cls;
4750 GNUNET_assert (0 == ac->num_acks);
4753 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4759 * Do the transmission of a cummulative acknowledgement now.
4761 * @param cls a `struct AcknowledgementCummulator *`
4764 transmit_cummulative_ack_cb (void *cls)
4766 struct AcknowledgementCummulator *ac = cls;
4767 struct TransportReliabilityAckMessage *ack;
4768 struct TransportCummulativeAckPayloadP *ap;
4771 GNUNET_assert (0 < ac->ack_counter);
4772 ack = GNUNET_malloc (sizeof (*ack) +
4774 sizeof (struct TransportCummulativeAckPayloadP));
4775 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4777 htons (sizeof (*ack) +
4778 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4779 ack->ack_counter = htonl (ac->ack_counter++);
4780 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4781 for (unsigned int i = 0; i < ac->ack_counter; i++)
4783 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4784 ap[i].ack_delay = GNUNET_TIME_relative_hton (
4785 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
4787 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
4789 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
4790 &destroy_ack_cummulator,
4796 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
4797 * transmission by at most @a ack_delay.
4799 * @param pid target peer
4800 * @param ack_uuid UUID to ack
4801 * @param max_delay how long can the ACK wait
4804 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
4805 const struct AcknowledgementUUIDP *ack_uuid,
4806 struct GNUNET_TIME_Absolute max_delay)
4808 struct AcknowledgementCummulator *ac;
4810 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
4813 ac = GNUNET_new (struct AcknowledgementCummulator);
4815 ac->min_transmission_time = max_delay;
4816 GNUNET_assert (GNUNET_YES ==
4817 GNUNET_CONTAINER_multipeermap_put (
4821 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4825 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
4827 /* must run immediately, ack buffer full! */
4828 GNUNET_SCHEDULER_cancel (ac->task);
4829 transmit_cummulative_ack_cb (ac);
4831 GNUNET_SCHEDULER_cancel (ac->task);
4832 ac->min_transmission_time =
4833 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
4835 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
4836 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
4837 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
4839 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
4840 &transmit_cummulative_ack_cb,
4846 * Closure for #find_by_message_uuid.
4848 struct FindByMessageUuidContext
4853 struct MessageUUIDP message_uuid;
4856 * Set to the reassembly context if found.
4858 struct ReassemblyContext *rc;
4863 * Iterator called to find a reassembly context by the message UUID in the
4866 * @param cls a `struct FindByMessageUuidContext`
4867 * @param key a key (unused)
4868 * @param value a `struct ReassemblyContext`
4869 * @return #GNUNET_YES if not found, #GNUNET_NO if found
4872 find_by_message_uuid (void *cls, uint32_t key, void *value)
4874 struct FindByMessageUuidContext *fc = cls;
4875 struct ReassemblyContext *rc = value;
4878 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
4888 * Communicator gave us a fragment. Process the request.
4890 * @param cls a `struct CommunicatorMessageContext` (must call
4891 * #finish_cmc_handling() when done)
4892 * @param fb the message that was received
4895 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4897 struct CommunicatorMessageContext *cmc = cls;
4898 struct Neighbour *n;
4899 struct ReassemblyContext *rc;
4900 const struct GNUNET_MessageHeader *msg;
4905 struct GNUNET_TIME_Relative cdelay;
4906 struct FindByMessageUuidContext fc;
4908 n = lookup_neighbour (&cmc->im.sender);
4911 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4914 finish_cmc_handling (cmc);
4915 GNUNET_SERVICE_client_drop (client);
4918 if (NULL == n->reassembly_map)
4920 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
4921 n->reassembly_heap =
4922 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4923 n->reassembly_timeout_task =
4924 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4925 &reassembly_cleanup_task,
4928 msize = ntohs (fb->msg_size);
4929 fc.message_uuid = fb->msg_uuid;
4931 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
4933 &find_by_message_uuid,
4935 if (NULL == (rc = fc.rc))
4937 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4938 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4939 rc->msg_uuid = fb->msg_uuid;
4941 rc->msg_size = msize;
4942 rc->reassembly_timeout =
4943 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4944 rc->last_frag = GNUNET_TIME_absolute_get ();
4945 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4947 rc->reassembly_timeout.abs_value_us);
4948 GNUNET_assert (GNUNET_OK ==
4949 GNUNET_CONTAINER_multihashmap32_put (
4953 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
4954 target = (char *) &rc[1];
4955 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4956 rc->msg_missing = rc->msg_size;
4960 target = (char *) &rc[1];
4962 if (msize != rc->msg_size)
4965 finish_cmc_handling (cmc);
4970 fsize = ntohs (fb->header.size) - sizeof (*fb);
4974 finish_cmc_handling (cmc);
4977 frag_off = ntohs (fb->frag_off);
4978 memcpy (&target[frag_off], &fb[1], fsize);
4979 /* update bitfield and msg_missing */
4980 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4982 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4984 rc->bitfield[i / 8] |= (1 << (i % 8));
4989 /* Compute cummulative ACK */
4990 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4991 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
4992 if (0 == rc->msg_missing)
4993 cdelay = GNUNET_TIME_UNIT_ZERO;
4994 cummulative_ack (&cmc->im.sender,
4996 GNUNET_TIME_relative_to_absolute (cdelay));
4997 rc->last_frag = GNUNET_TIME_absolute_get ();
4998 /* is reassembly complete? */
4999 if (0 != rc->msg_missing)
5001 finish_cmc_handling (cmc);
5004 /* reassembly is complete, verify result */
5005 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5006 if (ntohs (msg->size) != rc->msg_size)
5009 free_reassembly_context (rc);
5010 finish_cmc_handling (cmc);
5013 /* successful reassembly */
5014 demultiplex_with_cmc (cmc, msg);
5015 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5016 en-route and we forget that we finished this reassembly immediately!
5017 -> keep around until timeout?
5018 -> shorten timeout based on ACK? */
5019 free_reassembly_context (rc);
5024 * Communicator gave us a reliability box. Check the message.
5026 * @param cls a `struct CommunicatorMessageContext`
5027 * @param rb the send message that was sent
5028 * @return #GNUNET_YES if message is well-formed
5031 check_reliability_box (void *cls,
5032 const struct TransportReliabilityBoxMessage *rb)
5035 GNUNET_MQ_check_boxed_message (rb);
5041 * Communicator gave us a reliability box. Process the request.
5043 * @param cls a `struct CommunicatorMessageContext` (must call
5044 * #finish_cmc_handling() when done)
5045 * @param rb the message that was received
5048 handle_reliability_box (void *cls,
5049 const struct TransportReliabilityBoxMessage *rb)
5051 struct CommunicatorMessageContext *cmc = cls;
5052 const struct GNUNET_MessageHeader *inbox =
5053 (const struct GNUNET_MessageHeader *) &rb[1];
5055 // FIXME: call cummulative_ack(), have ack_countdown influence max_delay!
5056 (void) (0 == ntohl (rb->ack_countdown));
5057 /* continue with inner message */
5058 demultiplex_with_cmc (cmc, inbox);
5063 * Check if we have advanced to another age since the last time. If
5064 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5067 * @param pd[in,out] data to update
5068 * @param age current age
5071 update_pd_age (struct PerformanceData *pd, unsigned int age)
5075 if (age == pd->last_age)
5076 return; /* nothing to do */
5077 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5078 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5080 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5082 the->bytes_sent = 0;
5083 the->bytes_received = 0;
5090 * Update @a pd based on the latest @a rtt and the number of bytes
5091 * that were confirmed to be successfully transmitted.
5093 * @param pd[in,out] data to update
5094 * @param rtt latest round-trip time
5095 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5098 update_performance_data (struct PerformanceData *pd,
5099 struct GNUNET_TIME_Relative rtt,
5100 uint16_t bytes_transmitted_ok)
5102 uint64_t nval = rtt.rel_value_us;
5103 uint64_t oval = pd->aged_rtt.rel_value_us;
5104 unsigned int age = get_age ();
5105 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5107 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5110 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5111 update_pd_age (pd, age);
5112 the->bytes_received += bytes_transmitted_ok;
5117 * We have successfully transmitted data via @a q, update metrics.
5119 * @param q queue to update
5120 * @param rtt round trip time observed
5121 * @param bytes_transmitted_ok number of bytes successfully transmitted
5124 update_queue_performance (struct Queue *q,
5125 struct GNUNET_TIME_Relative rtt,
5126 uint16_t bytes_transmitted_ok)
5128 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5133 * We have successfully transmitted data via @a dvh, update metrics.
5135 * @param dvh distance vector path data to update
5136 * @param rtt round trip time observed
5137 * @param bytes_transmitted_ok number of bytes successfully transmitted
5140 update_dvh_performance (struct DistanceVectorHop *dvh,
5141 struct GNUNET_TIME_Relative rtt,
5142 uint16_t bytes_transmitted_ok)
5144 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5149 * The @a pa was acknowledged, process the acknowledgement.
5151 * @param pa the pending acknowledgement that was satisfied
5152 * @param ack_delay artificial delay from cummulative acks created by the other
5156 handle_acknowledged (struct PendingAcknowledgement *pa,
5157 struct GNUNET_TIME_Relative ack_delay)
5159 struct PendingMessage *pm = pa->pm;
5160 struct GNUNET_TIME_Relative delay;
5162 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5163 if (delay.rel_value_us > ack_delay.rel_value_us)
5164 delay = GNUNET_TIME_UNIT_ZERO;
5166 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5167 if (NULL != pa->queue)
5168 update_queue_performance (pa->queue, delay, pa->message_size);
5169 if (NULL != pa->dvh)
5170 update_dvh_performance (pa->dvh, delay, pa->message_size);
5173 if (NULL != pm->frag_parent)
5175 pm = pm->frag_parent;
5176 free_fragment_tree (pa->pm);
5178 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5180 struct PendingMessage *parent = pm->frag_parent;
5182 free_fragment_tree (pm);
5185 if (NULL != pm->head_frag)
5186 pm = NULL; /* we are done, otherwise free 'pm' below */
5189 free_pending_message (pm);
5190 free_pending_acknowledgement (pa);
5195 * Communicator gave us a reliability ack. Check it is well-formed.
5197 * @param cls a `struct CommunicatorMessageContext` (unused)
5198 * @param ra the message that was received
5199 * @return #GNUNET_Ok if @a ra is well-formed
5202 check_reliability_ack (void *cls,
5203 const struct TransportReliabilityAckMessage *ra)
5205 unsigned int n_acks;
5208 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5209 sizeof (struct TransportCummulativeAckPayloadP);
5212 GNUNET_break_op (0);
5213 return GNUNET_SYSERR;
5215 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5216 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5218 GNUNET_break_op (0);
5219 return GNUNET_SYSERR;
5226 * Communicator gave us a reliability ack. Process the request.
5228 * @param cls a `struct CommunicatorMessageContext` (must call
5229 * #finish_cmc_handling() when done)
5230 * @param ra the message that was received
5233 handle_reliability_ack (void *cls,
5234 const struct TransportReliabilityAckMessage *ra)
5236 struct CommunicatorMessageContext *cmc = cls;
5237 const struct TransportCummulativeAckPayloadP *ack;
5238 struct PendingAcknowledgement *pa;
5239 unsigned int n_acks;
5240 uint32_t ack_counter;
5242 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5243 sizeof (struct TransportCummulativeAckPayloadP);
5244 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5245 for (unsigned int i = 0; i < n_acks; i++)
5248 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5251 GNUNET_STATISTICS_update (
5253 "# FRAGMENT_ACKS dropped, no matching pending message",
5258 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5261 ack_counter = htonl (ra->ack_counter);
5262 // FIXME: track ACK losses based on ack_counter somewhere!
5263 // (DV and/or Neighbour?)
5264 finish_cmc_handling (cmc);
5269 * Communicator gave us a backchannel encapsulation. Check the message.
5271 * @param cls a `struct CommunicatorMessageContext`
5272 * @param be the send message that was sent
5273 * @return #GNUNET_YES if message is well-formed
5276 check_backchannel_encapsulation (
5278 const struct TransportBackchannelEncapsulationMessage *be)
5280 uint16_t size = ntohs (be->header.size);
5283 if ((size - sizeof (*be)) <
5284 (sizeof (struct TransportBackchannelRequestPayloadP) +
5285 sizeof (struct GNUNET_MessageHeader)))
5287 GNUNET_break_op (0);
5288 return GNUNET_SYSERR;
5295 * We received the plaintext @a msg from backtalker @a b. Forward
5296 * it to the respective communicator.
5298 * @param b a backtalker
5299 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5300 * followed by the target name of the communicator
5301 * @param msg_size number of bytes in @a msg
5304 forward_backchannel_payload (struct Backtalker *b,
5308 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5309 struct GNUNET_MQ_Envelope *env;
5310 struct TransportClient *tc;
5311 const struct GNUNET_MessageHeader *mh;
5312 const char *target_communicator;
5315 /* Determine target_communicator and check @a msg is well-formed */
5317 mhs = ntohs (mh->size);
5318 if (mhs <= msg_size)
5320 GNUNET_break_op (0);
5323 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5324 if ('\0' != target_communicator[msg_size - mhs - 1])
5326 GNUNET_break_op (0);
5329 /* Find client providing this communicator */
5330 for (tc = clients_head; NULL != tc; tc = tc->next)
5331 if ((CT_COMMUNICATOR == tc->type) &&
5333 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5341 "# Backchannel message dropped: target communicator `%s' unknown",
5342 target_communicator);
5343 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5344 GNUNET_free (stastr);
5347 /* Finally, deliver backchannel message to communicator */
5348 env = GNUNET_MQ_msg_extra (
5351 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5353 memcpy (&cbi[1], msg, msg_size);
5354 GNUNET_MQ_send (tc->mq, env);
5359 * Free data structures associated with @a b.
5361 * @param b data structure to release
5364 free_backtalker (struct Backtalker *b)
5368 GNUNET_PEERSTORE_iterate_cancel (b->get);
5370 GNUNET_assert (NULL != b->cmc);
5371 finish_cmc_handling (b->cmc);
5374 if (NULL != b->task)
5376 GNUNET_SCHEDULER_cancel (b->task);
5381 GNUNET_PEERSTORE_store_cancel (b->sc);
5386 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5392 * Callback to free backtalker records.
5396 * @param value a `struct Backtalker`
5397 * @return #GNUNET_OK (always)
5400 free_backtalker_cb (void *cls,
5401 const struct GNUNET_PeerIdentity *pid,
5404 struct Backtalker *b = value;
5408 free_backtalker (b);
5414 * Function called when it is time to clean up a backtalker.
5416 * @param cls a `struct Backtalker`
5419 backtalker_timeout_cb (void *cls)
5421 struct Backtalker *b = cls;
5424 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5426 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5429 GNUNET_assert (NULL == b->sc);
5430 free_backtalker (b);
5435 * Function called with the monotonic time of a backtalker
5436 * by PEERSTORE. Updates the time and continues processing.
5438 * @param cls a `struct Backtalker`
5439 * @param record the information found, NULL for the last call
5440 * @param emsg error message
5443 backtalker_monotime_cb (void *cls,
5444 const struct GNUNET_PEERSTORE_Record *record,
5447 struct Backtalker *b = cls;
5448 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5449 struct GNUNET_TIME_Absolute mt;
5454 /* we're done with #backtalker_monotime_cb() invocations,
5455 continue normal processing */
5457 GNUNET_assert (NULL != b->cmc);
5458 finish_cmc_handling (b->cmc);
5460 if (0 != b->body_size)
5461 forward_backchannel_payload (b, &b[1], b->body_size);
5464 if (sizeof (*mtbe) != record->value_size)
5469 mtbe = record->value;
5470 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5471 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5473 GNUNET_STATISTICS_update (
5475 "# Backchannel messages dropped: monotonic time not increasing",
5478 b->monotonic_time = mt;
5479 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5488 * Function called by PEERSTORE when the store operation of
5489 * a backtalker's monotonic time is complete.
5491 * @param cls the `struct Backtalker`
5492 * @param success #GNUNET_OK on success
5495 backtalker_monotime_store_cb (void *cls, int success)
5497 struct Backtalker *b = cls;
5499 if (GNUNET_OK != success)
5501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5502 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5505 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5510 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5512 * @param b a backtalker with updated monotonic time
5515 update_backtalker_monotime (struct Backtalker *b)
5517 struct GNUNET_TIME_AbsoluteNBO mtbe;
5521 GNUNET_PEERSTORE_store_cancel (b->sc);
5526 GNUNET_SCHEDULER_cancel (b->task);
5529 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5531 GNUNET_PEERSTORE_store (peerstore,
5534 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5537 GNUNET_TIME_UNIT_FOREVER_ABS,
5538 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5539 &backtalker_monotime_store_cb,
5545 * Communicator gave us a backchannel encapsulation. Process the request.
5546 * (We are not the origin of the backchannel here, the communicator simply
5547 * received a backchannel message and we are expected to forward it.)
5549 * @param cls a `struct CommunicatorMessageContext` (must call
5550 * #finish_cmc_handling() when done)
5551 * @param be the message that was received
5554 handle_backchannel_encapsulation (
5556 const struct TransportBackchannelEncapsulationMessage *be)
5558 struct CommunicatorMessageContext *cmc = cls;
5559 struct BackchannelKeyState key;
5560 struct GNUNET_HashCode hmac;
5564 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5566 /* not for me, try to route to target */
5567 route_message (&be->target,
5568 GNUNET_copy_message (&be->header),
5570 finish_cmc_handling (cmc);
5573 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5574 hdr = (const char *) &be[1];
5575 hdr_len = ntohs (be->header.size) - sizeof (*be);
5576 bc_hmac (&key, &hmac, hdr, hdr_len);
5577 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5579 /* HMAC missmatch, disard! */
5580 GNUNET_break_op (0);
5581 finish_cmc_handling (cmc);
5584 /* begin actual decryption */
5586 struct Backtalker *b;
5587 struct GNUNET_TIME_Absolute monotime;
5588 struct TransportBackchannelRequestPayloadP ppay;
5589 char body[hdr_len - sizeof (ppay)];
5591 GNUNET_assert (hdr_len >=
5592 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5593 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5594 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5595 bc_key_clean (&key);
5596 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5597 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5598 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5600 GNUNET_STATISTICS_update (
5602 "# Backchannel messages dropped: monotonic time not increasing",
5605 finish_cmc_handling (cmc);
5609 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5611 /* Check signature */
5612 struct EphemeralConfirmationPS ec;
5614 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5615 ec.purpose.size = htonl (sizeof (ec));
5616 ec.target = GST_my_identity;
5617 ec.ephemeral_key = be->ephemeral_key;
5620 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5623 &ppay.sender.public_key))
5625 /* Signature invalid, disard! */
5626 GNUNET_break_op (0);
5627 finish_cmc_handling (cmc);
5633 /* update key cache and mono time */
5634 b->last_ephemeral = be->ephemeral_key;
5635 b->monotonic_time = monotime;
5636 update_backtalker_monotime (b);
5637 forward_backchannel_payload (b, body, sizeof (body));
5639 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5640 finish_cmc_handling (cmc);
5643 /* setup data structure to cache signature AND check
5644 monotonic time with PEERSTORE before forwarding backchannel payload */
5645 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5646 b->pid = ppay.sender;
5647 b->body_size = sizeof (body);
5648 memcpy (&b[1], body, sizeof (body));
5649 GNUNET_assert (GNUNET_YES ==
5650 GNUNET_CONTAINER_multipeermap_put (
5654 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5655 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5658 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5659 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5661 GNUNET_PEERSTORE_iterate (peerstore,
5664 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5665 &backtalker_monotime_cb,
5672 * Task called when we should check if any of the DV paths
5673 * we have learned to a target are due for garbage collection.
5675 * Collects stale paths, and possibly frees the entire DV
5676 * entry if no paths are left. Otherwise re-schedules itself.
5678 * @param cls a `struct DistanceVector`
5681 path_cleanup_cb (void *cls)
5683 struct DistanceVector *dv = cls;
5684 struct DistanceVectorHop *pos;
5686 dv->timeout_task = NULL;
5687 while (NULL != (pos = dv->dv_head))
5689 GNUNET_assert (dv == pos->dv);
5690 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5692 free_distance_vector_hop (pos);
5700 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5704 * Task run to check whether the hops of the @a cls still
5705 * are validated, or if we need to core about disconnection.
5707 * @param cls a `struct DistanceVector` (with core_visible set!)
5710 check_dv_path_down (void *cls)
5712 struct DistanceVector *dv = cls;
5713 struct Neighbour *n;
5715 dv->visibility_task = NULL;
5716 GNUNET_assert (GNUNET_YES == dv->core_visible);
5717 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5721 GNUNET_TIME_absolute_get_remaining (pos->path_valid_until).rel_value_us)
5723 dv->visibility_task = GNUNET_SCHEDULER_add_at (pos->path_valid_until,
5724 &check_dv_path_down,
5729 /* all paths invalid, make dv core-invisible */
5730 dv->core_visible = GNUNET_NO;
5731 n = lookup_neighbour (&dv->target);
5732 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5733 return; /* no need to tell core, connection still up! */
5734 cores_send_disconnect_info (&dv->target);
5739 * The @a hop is a validated path to the respective target
5740 * peer and we should tell core about it -- and schedule
5741 * a job to revoke the state.
5743 * @param hop a path to some peer that is the reason for activation
5746 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5748 struct DistanceVector *dv = hop->dv;
5749 struct Neighbour *n;
5751 GNUNET_assert (GNUNET_NO == dv->core_visible);
5752 GNUNET_assert (NULL == dv->visibility_task);
5754 dv->core_visible = GNUNET_YES;
5755 dv->visibility_task =
5756 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_dv_path_down, dv);
5757 n = lookup_neighbour (&dv->target);
5758 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5759 return; /* no need to tell core, connection already up! */
5760 cores_send_connect_info (&dv->target,
5762 ? GNUNET_BANDWIDTH_value_sum (n->quota_out,
5769 * We have learned a @a path through the network to some other peer, add it to
5770 * our DV data structure (returning #GNUNET_YES on success).
5772 * We do not add paths if we have a sufficient number of shorter
5773 * paths to this target already (returning #GNUNET_NO).
5775 * We also do not add problematic paths, like those where we lack the first
5776 * hop in our neighbour list (i.e. due to a topology change) or where some
5777 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5779 * @param path the path we learned, path[0] should be us,
5780 * and then path contains a valid path from us to
5781 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
5782 * @param path_len number of entries on the @a path, at least three!
5783 * @param network_latency how long does the message take from us to
5784 * `path[path_len-1]`? set to "forever" if unknown
5785 * @param path_valid_until how long is this path considered validated? Maybe
5787 * @return #GNUNET_YES on success,
5788 * #GNUNET_NO if we have better path(s) to the target
5789 * #GNUNET_SYSERR if the path is useless and/or invalid
5790 * (i.e. path[1] not a direct neighbour
5791 * or path[i+1] is a direct neighbour for i>0)
5794 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5795 unsigned int path_len,
5796 struct GNUNET_TIME_Relative network_latency,
5797 struct GNUNET_TIME_Absolute path_valid_until)
5799 struct DistanceVectorHop *hop;
5800 struct DistanceVector *dv;
5801 struct Neighbour *next_hop;
5802 unsigned int shorter_distance;
5806 /* what a boring path! not allowed! */
5808 return GNUNET_SYSERR;
5810 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5811 next_hop = lookup_neighbour (&path[1]);
5812 if (NULL == next_hop)
5814 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5816 return GNUNET_SYSERR;
5818 for (unsigned int i = 2; i < path_len; i++)
5819 if (NULL != lookup_neighbour (&path[i]))
5821 /* Useless path, we have a direct connection to some hop
5822 in the middle of the path, so this one doesn't even
5823 seem terribly useful for redundancy */
5824 return GNUNET_SYSERR;
5826 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5829 dv = GNUNET_new (struct DistanceVector);
5830 dv->target = path[path_len - 1];
5831 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5834 GNUNET_assert (GNUNET_OK ==
5835 GNUNET_CONTAINER_multipeermap_put (
5839 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5841 /* Check if we have this path already! */
5842 shorter_distance = 0;
5843 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5846 if (pos->distance < path_len - 2)
5848 /* Note that the distances in 'pos' excludes us (path[0]) and
5849 the next_hop (path[1]), so we need to subtract two
5850 and check next_hop explicitly */
5851 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5853 int match = GNUNET_YES;
5855 for (unsigned int i = 0; i < pos->distance; i++)
5857 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5863 if (GNUNET_YES == match)
5865 struct GNUNET_TIME_Relative last_timeout;
5867 /* Re-discovered known path, update timeout */
5868 GNUNET_STATISTICS_update (GST_stats,
5869 "# Known DV path refreshed",
5872 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5874 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5875 pos->path_valid_until =
5876 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5877 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5878 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5879 if ((GNUNET_NO == dv->core_visible) &&
5880 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until)
5882 activate_core_visible_dv_path (pos);
5883 if (last_timeout.rel_value_us <
5884 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5885 DV_PATH_DISCOVERY_FREQUENCY)
5888 /* Some peer send DV learn messages too often, we are learning
5889 the same path faster than it would be useful; do not forward! */
5896 /* Count how many shorter paths we have (incl. direct
5897 neighbours) before simply giving up on this one! */
5898 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
5900 /* We have a shorter path already! */
5903 /* create new DV path entry */
5904 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
5905 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5906 hop->next_hop = next_hop;
5908 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
5911 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5912 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5913 hop->path_valid_until = path_valid_until;
5914 hop->distance = path_len - 2;
5915 hop->pd.aged_rtt = network_latency;
5916 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
5917 GNUNET_CONTAINER_MDLL_insert (neighbour,
5921 if ((GNUNET_NO == dv->core_visible) &&
5922 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us))
5923 activate_core_visible_dv_path (hop);
5929 * Communicator gave us a DV learn message. Check the message.
5931 * @param cls a `struct CommunicatorMessageContext`
5932 * @param dvl the send message that was sent
5933 * @return #GNUNET_YES if message is well-formed
5936 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
5938 uint16_t size = ntohs (dvl->header.size);
5939 uint16_t num_hops = ntohs (dvl->num_hops);
5940 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
5943 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
5945 GNUNET_break_op (0);
5946 return GNUNET_SYSERR;
5948 if (num_hops > MAX_DV_HOPS_ALLOWED)
5950 GNUNET_break_op (0);
5951 return GNUNET_SYSERR;
5953 for (unsigned int i = 0; i < num_hops; i++)
5955 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
5957 GNUNET_break_op (0);
5958 return GNUNET_SYSERR;
5960 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
5962 GNUNET_break_op (0);
5963 return GNUNET_SYSERR;
5971 * Build and forward a DV learn message to @a next_hop.
5973 * @param next_hop peer to send the message to
5974 * @param msg message received
5975 * @param bi_history bitmask specifying hops on path that were bidirectional
5976 * @param nhops length of the @a hops array
5977 * @param hops path the message traversed so far
5978 * @param in_time when did we receive the message, used to calculate network
5982 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
5983 const struct TransportDVLearnMessage *msg,
5984 uint16_t bi_history,
5986 const struct DVPathEntryP *hops,
5987 struct GNUNET_TIME_Absolute in_time)
5989 struct DVPathEntryP *dhops;
5990 struct TransportDVLearnMessage *fwd;
5991 struct GNUNET_TIME_Relative nnd;
5993 /* compute message for forwarding */
5994 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
5995 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
5996 (nhops + 1) * sizeof (struct DVPathEntryP));
5997 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
5998 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
5999 (nhops + 1) * sizeof (struct DVPathEntryP));
6000 fwd->num_hops = htons (nhops + 1);
6001 fwd->bidirectional = htons (bi_history);
6002 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6003 GNUNET_TIME_relative_ntoh (
6004 msg->non_network_delay));
6005 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6006 fwd->init_sig = msg->init_sig;
6007 fwd->initiator = msg->initiator;
6008 fwd->challenge = msg->challenge;
6009 dhops = (struct DVPathEntryP *) &fwd[1];
6010 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6011 dhops[nhops].hop = GST_my_identity;
6013 struct DvHopPS dhp = {.purpose.purpose =
6014 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6015 .purpose.size = htonl (sizeof (dhp)),
6016 .pred = dhops[nhops - 1].hop,
6018 .challenge = msg->challenge};
6020 GNUNET_assert (GNUNET_OK ==
6021 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6023 &dhops[nhops].hop_sig));
6025 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6030 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6032 * @param sender_monotonic_time monotonic time of the initiator
6033 * @param init the signer
6034 * @param challenge the challenge that was signed
6035 * @param init_sig signature presumably by @a init
6036 * @return #GNUNET_OK if the signature is valid
6039 validate_dv_initiator_signature (
6040 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6041 const struct GNUNET_PeerIdentity *init,
6042 const struct ChallengeNonceP *challenge,
6043 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6045 struct DvInitPS ip = {.purpose.purpose = htonl (
6046 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6047 .purpose.size = htonl (sizeof (ip)),
6048 .monotonic_time = sender_monotonic_time,
6049 .challenge = *challenge};
6053 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6058 GNUNET_break_op (0);
6059 return GNUNET_SYSERR;
6066 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6068 struct NeighbourSelectionContext
6071 * Original message we received.
6073 const struct TransportDVLearnMessage *dvl;
6078 const struct DVPathEntryP *hops;
6081 * Time we received the message.
6083 struct GNUNET_TIME_Absolute in_time;
6086 * Offsets of the selected peers.
6088 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6091 * Number of peers eligible for selection.
6093 unsigned int num_eligible;
6096 * Number of peers that were selected for forwarding.
6098 unsigned int num_selections;
6101 * Number of hops in @e hops
6106 * Bitmap of bidirectional connections encountered.
6108 uint16_t bi_history;
6113 * Function called for each neighbour during #handle_dv_learn.
6115 * @param cls a `struct NeighbourSelectionContext *`
6116 * @param pid identity of the peer
6117 * @param value a `struct Neighbour`
6118 * @return #GNUNET_YES (always)
6121 dv_neighbour_selection (void *cls,
6122 const struct GNUNET_PeerIdentity *pid,
6125 struct NeighbourSelectionContext *nsc = cls;
6128 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6129 return GNUNET_YES; /* skip initiator */
6130 for (unsigned int i = 0; i < nsc->nhops; i++)
6131 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6132 return GNUNET_YES; /* skip peers on path */
6133 nsc->num_eligible++;
6139 * Function called for each neighbour during #handle_dv_learn.
6140 * We call #forward_dv_learn() on the neighbour(s) selected
6141 * during #dv_neighbour_selection().
6143 * @param cls a `struct NeighbourSelectionContext *`
6144 * @param pid identity of the peer
6145 * @param value a `struct Neighbour`
6146 * @return #GNUNET_YES (always)
6149 dv_neighbour_transmission (void *cls,
6150 const struct GNUNET_PeerIdentity *pid,
6153 struct NeighbourSelectionContext *nsc = cls;
6156 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6157 return GNUNET_YES; /* skip initiator */
6158 for (unsigned int i = 0; i < nsc->nhops; i++)
6159 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6160 return GNUNET_YES; /* skip peers on path */
6161 for (unsigned int i = 0; i < nsc->num_selections; i++)
6163 if (nsc->selections[i] == nsc->num_eligible)
6165 forward_dv_learn (pid,
6174 nsc->num_eligible++;
6180 * Computes the number of neighbours we should forward a DVInit
6181 * message to given that it has so far taken @a hops_taken hops
6182 * though the network and that the number of neighbours we have
6183 * in total is @a neighbour_count, out of which @a eligible_count
6184 * are not yet on the path.
6186 * NOTE: technically we might want to include NSE in the formula to
6187 * get a better grip on the overall network size. However, for now
6188 * using NSE here would create a dependency issue in the build system.
6189 * => Left for later, hardcoded to 50 for now.
6191 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6192 * peers via DV (`target_total`). We want the reach to be spread out
6193 * over various distances to the origin, with a bias towards shorter
6196 * We make the strong assumption that the network topology looks
6197 * "similar" at other hops, in particular the @a neighbour_count
6198 * should be comparable at other hops.
6200 * If the local neighbourhood is densely connected, we expect that @a
6201 * eligible_count is close to @a neighbour_count minus @a hops_taken
6202 * as a lot of the path is already known. In that case, we should
6203 * forward to few(er) peers to try to find a path out of the
6204 * neighbourhood. OTOH, if @a eligible_count is close to @a
6205 * neighbour_count, we should forward to many peers as we are either
6206 * still close to the origin (i.e. @a hops_taken is small) or because
6207 * we managed to get beyond a local cluster. We express this as
6208 * the `boost_factor` using the square of the fraction of eligible
6209 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6210 * 99% are eligible, the 'boost' will be almost 1).
6212 * Second, the more hops we have taken, the larger the problem of an
6213 * exponential traffic explosion gets. So we take the `target_total`,
6214 * and compute our degree such that at each distance d 2^{-d} peers
6215 * are selected (corrected by the `boost_factor`).
6217 * @param hops_taken number of hops DVInit has travelled so far
6218 * @param neighbour_count number of neighbours we have in total
6219 * @param eligible_count number of neighbours we could in
6223 calculate_fork_degree (unsigned int hops_taken,
6224 unsigned int neighbour_count,
6225 unsigned int eligible_count)
6227 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6228 double eligible_ratio =
6229 ((double) eligible_count) / ((double) neighbour_count);
6230 double boost_factor = eligible_ratio * eligible_ratio;
6234 if (hops_taken >= 64)
6235 return 0; /* precaution given bitshift below */
6236 for (unsigned int i = 1; i < hops_taken; i++)
6238 /* For each hop, subtract the expected number of targets
6239 reached at distance d (so what remains divided by 2^d) */
6240 target_total -= (target_total * boost_factor / (1LLU << i));
6243 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6244 /* round up or down probabilistically depending on how close we were
6245 when floor()ing to rnd */
6246 left = target_total - (double) rnd;
6247 if (UINT32_MAX * left >
6248 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6249 rnd++; /* round up */
6255 * Function called when peerstore is done storing a DV monotonic time.
6257 * @param cls a `struct Neighbour`
6258 * @param success #GNUNET_YES if peerstore was successful
6261 neighbour_store_dvmono_cb (void *cls, int success)
6263 struct Neighbour *n = cls;
6266 if (GNUNET_YES != success)
6267 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6268 "Failed to store other peer's monotonic time in peerstore!\n");
6273 * Communicator gave us a DV learn message. Process the request.
6275 * @param cls a `struct CommunicatorMessageContext` (must call
6276 * #finish_cmc_handling() when done)
6277 * @param dvl the message that was received
6280 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6282 struct CommunicatorMessageContext *cmc = cls;
6283 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6286 uint16_t bi_history;
6287 const struct DVPathEntryP *hops;
6290 struct GNUNET_TIME_Absolute in_time;
6291 struct Neighbour *n;
6293 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6294 bi_history = ntohs (dvl->bidirectional);
6295 hops = (const struct DVPathEntryP *) &dvl[1];
6299 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6302 finish_cmc_handling (cmc);
6309 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6312 finish_cmc_handling (cmc);
6317 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6318 cc = cmc->tc->details.communicator.cc;
6319 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6320 cc); // FIXME: add bi-directional flag to cc?
6321 in_time = GNUNET_TIME_absolute_get ();
6323 /* continue communicator here, everything else can happen asynchronous! */
6324 finish_cmc_handling (cmc);
6326 n = lookup_neighbour (&dvl->initiator);
6329 if ((n->dv_monotime_available == GNUNET_YES) &&
6330 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6331 n->last_dv_learn_monotime.abs_value_us))
6333 GNUNET_STATISTICS_update (GST_stats,
6334 "# DV learn discarded due to time travel",
6339 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6344 GNUNET_break_op (0);
6347 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6348 if (GNUNET_YES == n->dv_monotime_available)
6351 GNUNET_PEERSTORE_store_cancel (n->sc);
6353 GNUNET_PEERSTORE_store (peerstore,
6356 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6357 &dvl->monotonic_time,
6358 sizeof (dvl->monotonic_time),
6359 GNUNET_TIME_UNIT_FOREVER_ABS,
6360 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6361 &neighbour_store_dvmono_cb,
6365 // FIXME: asynchronously (!) verify hop-by-hop signatures!
6366 // => if signature verification load too high, implement random drop
6369 do_fwd = GNUNET_YES;
6370 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6372 struct GNUNET_PeerIdentity path[nhops + 1];
6373 struct GNUNET_TIME_Relative host_latency_sum;
6374 struct GNUNET_TIME_Relative latency;
6375 struct GNUNET_TIME_Relative network_latency;
6377 /* We initiated this, learn the forward path! */
6378 path[0] = GST_my_identity;
6379 path[1] = hops[0].hop;
6380 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6382 // Need also something to lookup initiation time
6383 // to compute RTT! -> add RTT argument here?
6384 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6385 // (based on dvl->challenge, we can identify time of origin!)
6387 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6388 /* assumption: latency on all links is the same */
6389 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6391 for (unsigned int i = 2; i <= nhops; i++)
6393 struct GNUNET_TIME_Relative ilat;
6395 /* assumption: linear latency increase per hop */
6396 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6397 path[i] = hops[i - 1].hop;
6398 learn_dv_path (path,
6401 GNUNET_TIME_relative_to_absolute (
6402 ADDRESS_VALIDATION_LIFETIME));
6404 /* as we initiated, do not forward again (would be circular!) */
6410 /* last hop was bi-directional, we could learn something here! */
6411 struct GNUNET_PeerIdentity path[nhops + 2];
6413 path[0] = GST_my_identity;
6414 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6415 for (unsigned int i = 0; i < nhops; i++)
6419 if (0 == (bi_history & (1 << i)))
6420 break; /* i-th hop not bi-directional, stop learning! */
6423 path[i + 2] = dvl->initiator;
6427 path[i + 2] = hops[nhops - i - 2].hop;
6430 iret = learn_dv_path (path,
6432 GNUNET_TIME_UNIT_FOREVER_REL,
6433 GNUNET_TIME_UNIT_ZERO_ABS);
6434 if (GNUNET_SYSERR == iret)
6436 /* path invalid or too long to be interesting for US, thus should also
6437 not be interesting to our neighbours, cut path when forwarding to
6438 'i' hops, except of course for the one that goes back to the
6440 GNUNET_STATISTICS_update (GST_stats,
6441 "# DV learn not forwarded due invalidity of path",
6447 if ((GNUNET_NO == iret) && (nhops == i + 1))
6449 /* we have better paths, and this is the longest target,
6450 so there cannot be anything interesting later */
6451 GNUNET_STATISTICS_update (GST_stats,
6452 "# DV learn not forwarded, got better paths",
6461 if (MAX_DV_HOPS_ALLOWED == nhops)
6463 /* At limit, we're out of here! */
6464 finish_cmc_handling (cmc);
6468 /* Forward to initiator, if path non-trivial and possible */
6469 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6470 did_initiator = GNUNET_NO;
6473 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6475 /* send back to origin! */
6476 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6477 did_initiator = GNUNET_YES;
6479 /* We forward under two conditions: either we still learned something
6480 ourselves (do_fwd), or the path was darn short and thus the initiator is
6481 likely to still be very interested in this (and we did NOT already
6482 send it back to the initiator) */
6483 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6484 (GNUNET_NO == did_initiator)))
6486 /* Pick random neighbours that are not yet on the path */
6487 struct NeighbourSelectionContext nsc;
6490 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6493 nsc.bi_history = bi_history;
6495 nsc.in_time = in_time;
6496 nsc.num_eligible = 0;
6497 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6498 &dv_neighbour_selection,
6500 if (0 == nsc.num_eligible)
6501 return; /* done here, cannot forward to anyone else */
6502 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6503 nsc.num_selections =
6504 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6505 for (unsigned int i = 0; i < nsc.num_selections; i++)
6507 (nsc.num_selections == n_cnt)
6508 ? i /* all were selected, avoid collisions by chance */
6509 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6510 nsc.num_eligible = 0;
6511 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6512 &dv_neighbour_transmission,
6519 * Communicator gave us a DV box. Check the message.
6521 * @param cls a `struct CommunicatorMessageContext`
6522 * @param dvb the send message that was sent
6523 * @return #GNUNET_YES if message is well-formed
6526 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6528 uint16_t size = ntohs (dvb->header.size);
6529 uint16_t num_hops = ntohs (dvb->num_hops);
6530 const struct GNUNET_PeerIdentity *hops =
6531 (const struct GNUNET_PeerIdentity *) &dvb[1];
6532 const struct GNUNET_MessageHeader *inbox =
6533 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6538 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6539 sizeof (struct GNUNET_MessageHeader))
6541 GNUNET_break_op (0);
6542 return GNUNET_SYSERR;
6544 isize = ntohs (inbox->size);
6546 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6548 GNUNET_break_op (0);
6549 return GNUNET_SYSERR;
6551 itype = ntohs (inbox->type);
6552 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6553 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6555 GNUNET_break_op (0);
6556 return GNUNET_SYSERR;
6558 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6560 GNUNET_break_op (0);
6561 return GNUNET_SYSERR;
6568 * Create a DV Box message and queue it for transmission to
6571 * @param next_hop peer to receive the message next
6572 * @param total_hops how many hops did the message take so far
6573 * @param num_hops length of the @a hops array
6574 * @param origin origin of the message
6575 * @param hops next peer(s) to the destination, including destination
6576 * @param payload payload of the box
6577 * @param payload_size number of bytes in @a payload
6580 forward_dv_box (struct Neighbour *next_hop,
6581 uint16_t total_hops,
6583 const struct GNUNET_PeerIdentity *origin,
6584 const struct GNUNET_PeerIdentity *hops,
6585 const void *payload,
6586 uint16_t payload_size)
6588 struct TransportDVBoxMessage *dvb;
6590 dvb = create_dv_box (total_hops,
6592 &hops[num_hops - 1] /* == target */,
6593 num_hops - 1 /* do not count target twice */,
6597 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6603 * Communicator gave us a DV box. Process the request.
6605 * @param cls a `struct CommunicatorMessageContext` (must call
6606 * #finish_cmc_handling() when done)
6607 * @param dvb the message that was received
6610 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6612 struct CommunicatorMessageContext *cmc = cls;
6613 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6614 uint16_t num_hops = ntohs (dvb->num_hops);
6615 const struct GNUNET_PeerIdentity *hops =
6616 (const struct GNUNET_PeerIdentity *) &dvb[1];
6617 const struct GNUNET_MessageHeader *inbox =
6618 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6622 /* We're trying from the end of the hops array, as we may be
6623 able to find a shortcut unknown to the origin that way */
6624 for (int i = num_hops - 1; i >= 0; i--)
6626 struct Neighbour *n;
6628 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6630 GNUNET_break_op (0);
6631 finish_cmc_handling (cmc);
6634 n = lookup_neighbour (&hops[i]);
6638 ntohs (dvb->total_hops) + 1,
6639 num_hops - i - 1, /* number of hops left */
6641 &hops[i + 1], /* remaining hops */
6642 (const void *) &dvb[1],
6644 finish_cmc_handling (cmc);
6647 /* Woopsie, next hop not in neighbours, drop! */
6648 GNUNET_STATISTICS_update (GST_stats,
6649 "# DV Boxes dropped: next hop unknown",
6652 finish_cmc_handling (cmc);
6655 /* We are the target. Unbox and handle message. */
6656 cmc->im.sender = dvb->origin;
6657 cmc->total_hops = ntohs (dvb->total_hops);
6658 demultiplex_with_cmc (cmc, inbox);
6663 * Client notified us about transmission from a peer. Process the request.
6665 * @param cls a `struct TransportClient` which sent us the message
6666 * @param obm the send message that was sent
6667 * @return #GNUNET_YES if message is well-formed
6670 check_incoming_msg (void *cls,
6671 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6673 struct TransportClient *tc = cls;
6675 if (CT_COMMUNICATOR != tc->type)
6678 return GNUNET_SYSERR;
6680 GNUNET_MQ_check_boxed_message (im);
6686 * Communicator gave us a transport address validation challenge. Process the
6689 * @param cls a `struct CommunicatorMessageContext` (must call
6690 * #finish_cmc_handling() when done)
6691 * @param tvc the message that was received
6694 handle_validation_challenge (
6696 const struct TransportValidationChallengeMessage *tvc)
6698 struct CommunicatorMessageContext *cmc = cls;
6699 struct TransportValidationResponseMessage *tvr;
6701 if (cmc->total_hops > 0)
6703 /* DV routing is not allowed for validation challenges! */
6704 GNUNET_break_op (0);
6705 finish_cmc_handling (cmc);
6708 tvr = GNUNET_new (struct TransportValidationResponseMessage);
6710 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
6711 tvr->header.size = htons (sizeof (*tvr));
6712 tvr->challenge = tvc->challenge;
6713 tvr->origin_time = tvc->sender_time;
6714 tvr->validity_duration = cmc->im.expected_address_validity;
6716 /* create signature */
6717 struct TransportValidationPS tvp =
6718 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6719 .purpose.size = htonl (sizeof (tvp)),
6720 .validity_duration = tvr->validity_duration,
6721 .challenge = tvc->challenge};
6723 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6727 route_message (&cmc->im.sender,
6729 RMO_ANYTHING_GOES | RMO_REDUNDANT);
6730 finish_cmc_handling (cmc);
6735 * Closure for #check_known_challenge.
6737 struct CheckKnownChallengeContext
6740 * Set to the challenge we are looking for.
6742 const struct ChallengeNonceP *challenge;
6745 * Set to a matching validation state, if one was found.
6747 struct ValidationState *vs;
6752 * Test if the validation state in @a value matches the
6753 * challenge from @a cls.
6755 * @param cls a `struct CheckKnownChallengeContext`
6756 * @param pid unused (must match though)
6757 * @param value a `struct ValidationState`
6758 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6761 check_known_challenge (void *cls,
6762 const struct GNUNET_PeerIdentity *pid,
6765 struct CheckKnownChallengeContext *ckac = cls;
6766 struct ValidationState *vs = value;
6769 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
6777 * Function called when peerstore is done storing a
6778 * validated address.
6780 * @param cls a `struct ValidationState`
6781 * @param success #GNUNET_YES on success
6784 peerstore_store_validation_cb (void *cls, int success)
6786 struct ValidationState *vs = cls;
6789 if (GNUNET_YES == success)
6791 GNUNET_STATISTICS_update (GST_stats,
6792 "# Peerstore failed to store foreign address",
6799 * Task run periodically to validate some address based on #validation_heap.
6804 validation_start_cb (void *cls);
6808 * Set the time for next_challenge of @a vs to @a new_time.
6809 * Updates the heap and if necessary reschedules the job.
6811 * @param vs validation state to update
6812 * @param new_time new time for revalidation
6815 update_next_challenge_time (struct ValidationState *vs,
6816 struct GNUNET_TIME_Absolute new_time)
6818 struct GNUNET_TIME_Relative delta;
6820 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
6821 return; /* be lazy */
6822 vs->next_challenge = new_time;
6825 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
6827 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
6828 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
6829 (NULL != validation_task))
6831 if (NULL != validation_task)
6832 GNUNET_SCHEDULER_cancel (validation_task);
6833 /* randomize a bit */
6834 delta.rel_value_us =
6835 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6836 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
6837 new_time = GNUNET_TIME_absolute_add (new_time, delta);
6839 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
6844 * Find the queue matching @a pid and @a address.
6846 * @param pid peer the queue must go to
6847 * @param address address the queue must use
6848 * @return NULL if no such queue exists
6850 static struct Queue *
6851 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
6853 struct Neighbour *n;
6855 n = lookup_neighbour (pid);
6858 for (struct Queue *pos = n->queue_head; NULL != pos;
6859 pos = pos->next_neighbour)
6861 if (0 == strcmp (pos->address, address))
6869 * Task run periodically to check whether the validity of the given queue has
6870 * run its course. If so, finds either another queue to take over, or clears
6871 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
6872 * chance to take over, and if that fails, notifies CORE about the disconnect.
6874 * @param cls a `struct Queue`
6877 core_queue_visibility_check (void *cls)
6879 struct Queue *q = cls;
6881 q->visibility_task = NULL;
6882 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
6884 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
6885 &core_queue_visibility_check,
6889 update_neighbour_core_visibility (q->neighbour);
6894 * Check whether the CORE visibility of @a n should change. Finds either a
6895 * queue to preserve the visibility, or clears the neighbour's `core_visible`
6896 * flag. In the latter case, gives DV routes a chance to take over, and if
6897 * that fails, notifies CORE about the disconnect. If so, check whether we
6898 * need to notify CORE.
6900 * @param n neighbour to perform the check for
6903 update_neighbour_core_visibility (struct Neighbour *n)
6905 struct DistanceVector *dv;
6907 GNUNET_assert (GNUNET_YES == n->core_visible);
6908 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
6909 the #core_queue_visibility_check() task for that queue */
6910 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6913 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
6915 /* found a valid queue, use this one */
6916 q->visibility_task =
6917 GNUNET_SCHEDULER_add_at (q->validated_until,
6918 &core_queue_visibility_check,
6923 n->core_visible = GNUNET_NO;
6925 /* Check if _any_ DV route to this neighbour is currently
6926 valid, if so, do NOT tell core about the loss of direct
6927 connectivity (DV still counts!) */
6928 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
6929 if (GNUNET_YES == dv->core_visible)
6931 /* Nothing works anymore, need to tell CORE about the loss of
6933 cores_send_disconnect_info (&n->pid);
6938 * Communicator gave us a transport address validation response. Process the
6941 * @param cls a `struct CommunicatorMessageContext` (must call
6942 * #finish_cmc_handling() when done)
6943 * @param tvr the message that was received
6946 handle_validation_response (
6948 const struct TransportValidationResponseMessage *tvr)
6950 struct CommunicatorMessageContext *cmc = cls;
6951 struct ValidationState *vs;
6952 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
6954 struct GNUNET_TIME_Absolute origin_time;
6956 struct DistanceVector *dv;
6957 struct Neighbour *n;
6959 /* check this is one of our challenges */
6960 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6962 &check_known_challenge,
6964 if (NULL == (vs = ckac.vs))
6966 /* This can happen simply if we 'forgot' the challenge by now,
6967 i.e. because we received the validation response twice */
6968 GNUNET_STATISTICS_update (GST_stats,
6969 "# Validations dropped, challenge unknown",
6972 finish_cmc_handling (cmc);
6976 /* sanity check on origin time */
6977 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
6978 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
6979 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
6981 GNUNET_break_op (0);
6982 finish_cmc_handling (cmc);
6987 /* check signature */
6988 struct TransportValidationPS tvp =
6989 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6990 .purpose.size = htonl (sizeof (tvp)),
6991 .validity_duration = tvr->validity_duration,
6992 .challenge = tvr->challenge};
6996 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
6999 &cmc->im.sender.public_key))
7001 GNUNET_break_op (0);
7002 finish_cmc_handling (cmc);
7007 /* validity is capped by our willingness to keep track of the
7008 validation entry and the maximum the other peer allows */
7009 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7010 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7011 tvr->validity_duration),
7012 MAX_ADDRESS_VALID_UNTIL));
7013 vs->validated_until =
7014 GNUNET_TIME_absolute_min (vs->valid_until,
7015 GNUNET_TIME_relative_to_absolute (
7016 ADDRESS_VALIDATION_LIFETIME));
7017 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7018 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7019 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7021 sizeof (vs->challenge));
7022 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7023 vs->validated_until,
7024 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7025 VALIDATION_RTT_BUFFER_FACTOR));
7026 vs->last_challenge_use =
7027 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7028 update_next_challenge_time (vs, vs->first_challenge_use);
7029 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7032 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7034 strlen (vs->address) + 1,
7036 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7037 &peerstore_store_validation_cb,
7039 finish_cmc_handling (cmc);
7041 /* Finally, we now possibly have a confirmed (!) working queue,
7042 update queue status (if queue still is around) */
7043 q = find_queue (&vs->pid, vs->address);
7046 GNUNET_STATISTICS_update (GST_stats,
7047 "# Queues lost at time of successful validation",
7052 q->validated_until = vs->validated_until;
7053 q->pd.aged_rtt = vs->validation_rtt;
7055 if (GNUNET_NO != n->core_visible)
7056 return; /* nothing changed, we are done here */
7057 n->core_visible = GNUNET_YES;
7058 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
7059 &core_queue_visibility_check,
7061 /* Check if _any_ DV route to this neighbour is
7062 currently valid, if so, do NOT tell core anything! */
7063 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
7064 if ((NULL != dv) && (GNUNET_YES == dv->core_visible))
7065 return; /* nothing changed, done */
7066 /* We lacked a confirmed connection to the neighbour
7067 before, so tell CORE about it (finally!) */
7068 cores_send_connect_info (&n->pid,
7070 ? GNUNET_BANDWIDTH_value_sum (dv->quota_out,
7077 * Incoming meessage. Process the request.
7079 * @param im the send message that was received
7082 handle_incoming_msg (void *cls,
7083 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7085 struct TransportClient *tc = cls;
7086 struct CommunicatorMessageContext *cmc =
7087 GNUNET_new (struct CommunicatorMessageContext);
7091 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7096 * Given an inbound message @a msg from a communicator @a cmc,
7097 * demultiplex it based on the type calling the right handler.
7099 * @param cmc context for demultiplexing
7100 * @param msg message to demultiplex
7103 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7104 const struct GNUNET_MessageHeader *msg)
7106 struct GNUNET_MQ_MessageHandler handlers[] =
7107 {GNUNET_MQ_hd_var_size (fragment_box,
7108 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7109 struct TransportFragmentBoxMessage,
7111 GNUNET_MQ_hd_var_size (reliability_box,
7112 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7113 struct TransportReliabilityBoxMessage,
7115 GNUNET_MQ_hd_var_size (reliability_ack,
7116 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7117 struct TransportReliabilityAckMessage,
7119 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7120 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7121 struct TransportBackchannelEncapsulationMessage,
7123 GNUNET_MQ_hd_var_size (dv_learn,
7124 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7125 struct TransportDVLearnMessage,
7127 GNUNET_MQ_hd_var_size (dv_box,
7128 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7129 struct TransportDVBoxMessage,
7131 GNUNET_MQ_hd_fixed_size (
7132 validation_challenge,
7133 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7134 struct TransportValidationChallengeMessage,
7136 GNUNET_MQ_hd_fixed_size (
7137 validation_response,
7138 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7139 struct TransportValidationResponseMessage,
7141 GNUNET_MQ_handler_end ()};
7144 ret = GNUNET_MQ_handle_message (handlers, msg);
7145 if (GNUNET_SYSERR == ret)
7148 GNUNET_SERVICE_client_drop (cmc->tc->client);
7152 if (GNUNET_NO == ret)
7154 /* unencapsulated 'raw' message */
7155 handle_raw_message (&cmc, msg);
7161 * New queue became available. Check message.
7163 * @param cls the client
7164 * @param aqm the send message that was sent
7167 check_add_queue_message (void *cls,
7168 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7170 struct TransportClient *tc = cls;
7172 if (CT_COMMUNICATOR != tc->type)
7175 return GNUNET_SYSERR;
7177 GNUNET_MQ_check_zero_termination (aqm);
7183 * If necessary, generates the UUID for a @a pm
7185 * @param pm pending message to generate UUID for.
7188 set_pending_message_uuid (struct PendingMessage *pm)
7190 if (pm->msg_uuid_set)
7192 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7194 sizeof (pm->msg_uuid));
7195 pm->msg_uuid_set = GNUNET_YES;
7200 * Setup data structure waiting for acknowledgements.
7202 * @param queue queue the @a pm will be sent over
7203 * @param dvh path the message will take, may be NULL
7204 * @param pm the pending message for transmission
7205 * @return corresponding fresh pending acknowledgement
7207 static struct PendingAcknowledgement *
7208 prepare_pending_acknowledgement (struct Queue *queue,
7209 struct DistanceVectorHop *dvh,
7210 struct PendingMessage *pm)
7212 struct PendingAcknowledgement *pa;
7214 pa = GNUNET_new (struct PendingAcknowledgement);
7220 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7222 sizeof (pa->ack_uuid));
7223 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7225 &pa->ack_uuid.value,
7227 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7228 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7229 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7231 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7232 pa->transmission_time = GNUNET_TIME_absolute_get ();
7233 pa->message_size = pm->bytes_msg;
7239 * Fragment the given @a pm to the given @a mtu. Adds
7240 * additional fragments to the neighbour as well. If the
7241 * @a mtu is too small, generates and error for the @a pm
7244 * @param queue which queue to fragment for
7245 * @param dvh path the message will take, or NULL
7246 * @param pm pending message to fragment for transmission
7247 * @return new message to transmit
7249 static struct PendingMessage *
7250 fragment_message (struct Queue *queue,
7251 struct DistanceVectorHop *dvh,
7252 struct PendingMessage *pm)
7254 struct PendingAcknowledgement *pa;
7255 struct PendingMessage *ff;
7258 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7259 mtu = (0 == queue->mtu)
7260 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7262 set_pending_message_uuid (pm);
7264 /* This invariant is established in #handle_add_queue_message() */
7265 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7267 /* select fragment for transmission, descending the tree if it has
7268 been expanded until we are at a leaf or at a fragment that is small
7272 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7273 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7275 ff = ff->head_frag; /* descent into fragmented fragments */
7278 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7280 /* Did not yet calculate all fragments, calculate next fragment */
7281 struct PendingMessage *frag;
7282 struct TransportFragmentBoxMessage tfb;
7290 orig = (const char *) &ff[1];
7291 msize = ff->bytes_msg;
7294 const struct TransportFragmentBoxMessage *tfbo;
7296 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7297 orig += sizeof (struct TransportFragmentBoxMessage);
7298 msize -= sizeof (struct TransportFragmentBoxMessage);
7299 xoff = ntohs (tfbo->frag_off);
7301 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7302 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7304 GNUNET_malloc (sizeof (struct PendingMessage) +
7305 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7306 frag->target = pm->target;
7307 frag->frag_parent = ff;
7308 frag->timeout = pm->timeout;
7309 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7310 frag->pmt = PMT_FRAGMENT_BOX;
7311 msg = (char *) &frag[1];
7312 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7314 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7315 tfb.ack_uuid = pa->ack_uuid;
7316 tfb.msg_uuid = pm->msg_uuid;
7317 tfb.frag_off = htons (ff->frag_off + xoff);
7318 tfb.msg_size = htons (pm->bytes_msg);
7319 memcpy (msg, &tfb, sizeof (tfb));
7320 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7321 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7322 ff->frag_off += fragsize;
7326 /* Move head to the tail and return it */
7327 GNUNET_CONTAINER_MDLL_remove (frag,
7328 ff->frag_parent->head_frag,
7329 ff->frag_parent->tail_frag,
7331 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7332 ff->frag_parent->head_frag,
7333 ff->frag_parent->tail_frag,
7340 * Reliability-box the given @a pm. On error (can there be any), NULL
7341 * may be returned, otherwise the "replacement" for @a pm (which
7342 * should then be added to the respective neighbour's queue instead of
7343 * @a pm). If the @a pm is already fragmented or reliability boxed,
7344 * or itself an ACK, this function simply returns @a pm.
7346 * @param queue which queue to prepare transmission for
7347 * @param dvh path the message will take, or NULL
7348 * @param pm pending message to box for transmission over unreliabile queue
7349 * @return new message to transmit
7351 static struct PendingMessage *
7352 reliability_box_message (struct Queue *queue,
7353 struct DistanceVectorHop *dvh,
7354 struct PendingMessage *pm)
7356 struct TransportReliabilityBoxMessage rbox;
7357 struct PendingAcknowledgement *pa;
7358 struct PendingMessage *bpm;
7361 if (PMT_CORE != pm->pmt)
7362 return pm; /* already fragmented or reliability boxed, or control message:
7364 if (NULL != pm->bpm)
7365 return pm->bpm; /* already computed earlier: do nothing */
7366 GNUNET_assert (NULL == pm->head_frag);
7367 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7371 client_send_response (pm, GNUNET_NO, 0);
7374 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7376 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7378 bpm->target = pm->target;
7379 bpm->frag_parent = pm;
7380 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7381 bpm->timeout = pm->timeout;
7382 bpm->pmt = PMT_RELIABILITY_BOX;
7383 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7384 set_pending_message_uuid (bpm);
7385 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7386 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7387 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7389 rbox.ack_uuid = pa->ack_uuid;
7390 msg = (char *) &bpm[1];
7391 memcpy (msg, &rbox, sizeof (rbox));
7392 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7399 * Change the value of the `next_attempt` field of @a pm
7400 * to @a next_attempt and re-order @a pm in the transmission
7401 * list as required by the new timestmap.
7403 * @param pm a pending message to update
7404 * @param next_attempt timestamp to use
7407 update_pm_next_attempt (struct PendingMessage *pm,
7408 struct GNUNET_TIME_Absolute next_attempt)
7410 struct Neighbour *neighbour = pm->target;
7412 pm->next_attempt = next_attempt;
7413 if (NULL == pm->frag_parent)
7415 struct PendingMessage *pos;
7417 /* re-insert sort in neighbour list */
7418 GNUNET_CONTAINER_MDLL_remove (neighbour,
7419 neighbour->pending_msg_head,
7420 neighbour->pending_msg_tail,
7422 pos = neighbour->pending_msg_tail;
7423 while ((NULL != pos) &&
7424 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7425 pos = pos->prev_neighbour;
7426 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7427 neighbour->pending_msg_head,
7428 neighbour->pending_msg_tail,
7434 /* re-insert sort in fragment list */
7435 struct PendingMessage *fp = pm->frag_parent;
7436 struct PendingMessage *pos;
7438 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7439 pos = fp->tail_frag;
7440 while ((NULL != pos) &&
7441 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7442 pos = pos->prev_frag;
7443 GNUNET_CONTAINER_MDLL_insert_after (frag,
7453 * We believe we are ready to transmit a message on a queue.
7454 * Gives the message to the
7455 * communicator for transmission (updating the tracker, and re-scheduling
7456 * itself if applicable).
7458 * @param cls the `struct Queue` to process transmissions for
7461 transmit_on_queue (void *cls)
7463 struct Queue *queue = cls;
7464 struct Neighbour *n = queue->neighbour;
7465 struct PendingMessage *pm;
7466 struct PendingMessage *s;
7469 queue->transmit_task = NULL;
7470 if (NULL == (pm = n->pending_msg_head))
7472 /* no message pending, nothing to do here! */
7477 /* message still pending with communciator!
7478 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7481 schedule_transmit_on_queue (queue, GNUNET_YES);
7482 if (NULL != queue->transmit_task)
7483 return; /* do it later */
7485 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7486 overhead += sizeof (struct TransportReliabilityBoxMessage);
7488 if ( ( (0 != queue->mtu) &&
7489 (pm->bytes_msg + overhead > queue->mtu) ) ||
7490 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7491 (NULL != pm->head_frag /* fragments already exist, should
7492 respect that even if MTU is 0 for
7494 s = fragment_message (queue, pm->dvh, s);
7497 /* Fragmentation failed, try next message... */
7498 schedule_transmit_on_queue (queue, GNUNET_NO);
7501 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7502 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7503 s = reliability_box_message (queue, pm->dvh, s);
7506 /* Reliability boxing failed, try next message... */
7507 schedule_transmit_on_queue (queue, GNUNET_NO);
7511 /* Pass 's' for transission to the communicator */
7512 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7513 // FIXME: do something similar to the logic below
7514 // in defragmentation / reliability ACK handling!
7516 /* Check if this transmission somehow conclusively finished handing 'pm'
7517 even without any explicit ACKs */
7518 if ((PMT_CORE == s->pmt) &&
7519 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7521 /* Full message sent, and over reliabile channel */
7522 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
7524 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7525 queue->tc->details.communicator.cc) &&
7526 (PMT_FRAGMENT_BOX == s->pmt))
7528 struct PendingMessage *pos;
7530 /* Fragment sent over reliabile channel */
7531 free_fragment_tree (s);
7532 pos = s->frag_parent;
7533 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7535 /* check if subtree is done */
7536 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7540 pos = s->frag_parent;
7541 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7545 /* Was this the last applicable fragmment? */
7546 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7547 client_send_response (
7550 pm->bytes_msg /* FIXME: calculate and add overheads! */);
7552 else if (PMT_CORE != pm->pmt)
7554 /* This was an acknowledgement of some type, always free */
7555 free_pending_message (pm);
7559 /* Message not finished, waiting for acknowledgement.
7560 Update time by which we might retransmit 's' based on queue
7561 characteristics (i.e. RTT); it takes one RTT for the message to
7562 arrive and the ACK to come back in the best case; but the other
7563 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7564 retransmitting. Note that in the future this heuristic should
7565 likely be improved further (measure RTT stability, consider
7566 message urgency and size when delaying ACKs, etc.) */
7567 update_pm_next_attempt (s,
7568 GNUNET_TIME_relative_to_absolute (
7569 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7573 /* finally, re-schedule queue transmission task itself */
7574 schedule_transmit_on_queue (queue, GNUNET_NO);
7579 * Queue to a peer went down. Process the request.
7581 * @param cls the client
7582 * @param dqm the send message that was sent
7585 handle_del_queue_message (void *cls,
7586 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7588 struct TransportClient *tc = cls;
7590 if (CT_COMMUNICATOR != tc->type)
7593 GNUNET_SERVICE_client_drop (tc->client);
7596 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7597 queue = queue->next_client)
7599 struct Neighbour *neighbour = queue->neighbour;
7601 if ((dqm->qid != queue->qid) ||
7602 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7605 GNUNET_SERVICE_client_continue (tc->client);
7609 GNUNET_SERVICE_client_drop (tc->client);
7614 * Message was transmitted. Process the request.
7616 * @param cls the client
7617 * @param sma the send message that was sent
7620 handle_send_message_ack (void *cls,
7621 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7623 struct TransportClient *tc = cls;
7624 struct QueueEntry *qe;
7625 struct PendingMessage *pm;
7627 if (CT_COMMUNICATOR != tc->type)
7630 GNUNET_SERVICE_client_drop (tc->client);
7634 /* find our queue entry matching the ACK */
7636 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7637 queue = queue->next_client)
7639 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7641 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7644 if (qep->mid != sma->mid)
7653 /* this should never happen */
7655 GNUNET_SERVICE_client_drop (tc->client);
7658 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7659 qe->queue->queue_tail,
7661 qe->queue->queue_length--;
7662 tc->details.communicator.total_queue_length--;
7663 GNUNET_SERVICE_client_continue (tc->client);
7665 /* if applicable, resume transmissions that waited on ACK */
7666 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7667 tc->details.communicator.total_queue_length)
7669 /* Communicator dropped below threshold, resume all queues
7670 incident with this client! */
7671 GNUNET_STATISTICS_update (
7673 "# Transmission throttled due to communicator queue limit",
7676 for (struct Queue *queue = tc->details.communicator.queue_head;
7678 queue = queue->next_client)
7679 schedule_transmit_on_queue (queue, GNUNET_NO);
7681 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7683 /* queue dropped below threshold; only resume this one queue */
7684 GNUNET_STATISTICS_update (GST_stats,
7685 "# Transmission throttled due to queue queue limit",
7688 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7691 if (NULL != (pm = qe->pm))
7693 struct Neighbour *n;
7695 GNUNET_assert (qe == pm->qe);
7697 /* If waiting for this communicator may have blocked transmission
7698 of pm on other queues for this neighbour, force schedule
7699 transmit on queue for queues of the neighbour */
7701 if (n->pending_msg_head == pm)
7703 for (struct Queue *queue = n->queue_head; NULL != queue;
7704 queue = queue->next_neighbour)
7705 schedule_transmit_on_queue (queue, GNUNET_NO);
7707 if (GNUNET_OK != ntohl (sma->status))
7710 GNUNET_ERROR_TYPE_INFO,
7711 "Queue failed in transmission, will try retransmission immediately\n");
7712 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7720 * Iterator telling new MONITOR client about all existing
7723 * @param cls the new `struct TransportClient`
7724 * @param pid a connected peer
7725 * @param value the `struct Neighbour` with more information
7726 * @return #GNUNET_OK (continue to iterate)
7729 notify_client_queues (void *cls,
7730 const struct GNUNET_PeerIdentity *pid,
7733 struct TransportClient *tc = cls;
7734 struct Neighbour *neighbour = value;
7736 GNUNET_assert (CT_MONITOR == tc->type);
7737 for (struct Queue *q = neighbour->queue_head; NULL != q;
7738 q = q->next_neighbour)
7740 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7742 .num_msg_pending = q->num_msg_pending,
7743 .num_bytes_pending = q->num_bytes_pending};
7745 notify_monitor (tc, pid, q->address, q->nt, &me);
7752 * Initialize a monitor client.
7754 * @param cls the client
7755 * @param start the start message that was sent
7758 handle_monitor_start (void *cls,
7759 const struct GNUNET_TRANSPORT_MonitorStart *start)
7761 struct TransportClient *tc = cls;
7763 if (CT_NONE != tc->type)
7766 GNUNET_SERVICE_client_drop (tc->client);
7769 tc->type = CT_MONITOR;
7770 tc->details.monitor.peer = start->peer;
7771 tc->details.monitor.one_shot = ntohl (start->one_shot);
7772 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
7773 GNUNET_SERVICE_client_mark_monitor (tc->client);
7774 GNUNET_SERVICE_client_continue (tc->client);
7779 * Find transport client providing communication service
7780 * for the protocol @a prefix.
7782 * @param prefix communicator name
7783 * @return NULL if no such transport client is available
7785 static struct TransportClient *
7786 lookup_communicator (const char *prefix)
7788 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7790 if (CT_COMMUNICATOR != tc->type)
7792 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
7796 GNUNET_ERROR_TYPE_WARNING,
7797 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
7804 * Signature of a function called with a communicator @a address of a peer
7805 * @a pid that an application wants us to connect to.
7807 * @param pid target peer
7808 * @param address the address to try
7811 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
7813 static uint32_t idgen;
7814 struct TransportClient *tc;
7816 struct GNUNET_TRANSPORT_CreateQueue *cqm;
7817 struct GNUNET_MQ_Envelope *env;
7820 prefix = GNUNET_HELLO_address_to_prefix (address);
7823 GNUNET_break (0); /* We got an invalid address!? */
7826 tc = lookup_communicator (prefix);
7829 GNUNET_STATISTICS_update (GST_stats,
7830 "# Suggestions ignored due to missing communicator",
7835 /* forward suggestion for queue creation to communicator */
7836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7837 "Request #%u for `%s' communicator to create queue to `%s'\n",
7838 (unsigned int) idgen,
7841 alen = strlen (address) + 1;
7843 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
7844 cqm->request_id = htonl (idgen++);
7845 cqm->receiver = *pid;
7846 memcpy (&cqm[1], address, alen);
7847 GNUNET_MQ_send (tc->mq, env);
7852 * The queue @a q (which matches the peer and address in @a vs) is
7853 * ready for queueing. We should now queue the validation request.
7855 * @param q queue to send on
7856 * @param vs state to derive validation challenge from
7859 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
7861 struct TransportValidationChallengeMessage tvc;
7863 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
7865 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
7866 tvc.header.size = htons (sizeof (tvc));
7867 tvc.reserved = htonl (0);
7868 tvc.challenge = vs->challenge;
7869 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
7870 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7875 * Task run periodically to validate some address based on #validation_heap.
7880 validation_start_cb (void *cls)
7882 struct ValidationState *vs;
7886 validation_task = NULL;
7887 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7888 /* drop validations past their expiration */
7891 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7893 free_validation_state (vs);
7894 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7897 return; /* woopsie, no more addresses known, should only
7898 happen if we're really a lonely peer */
7899 q = find_queue (&vs->pid, vs->address);
7902 vs->awaiting_queue = GNUNET_YES;
7903 suggest_to_connect (&vs->pid, vs->address);
7906 validation_transmit_on_queue (q, vs);
7907 /* Finally, reschedule next attempt */
7908 vs->challenge_backoff =
7909 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
7910 MAX_VALIDATION_CHALLENGE_FREQ);
7911 update_next_challenge_time (vs,
7912 GNUNET_TIME_relative_to_absolute (
7913 vs->challenge_backoff));
7918 * Closure for #check_connection_quality.
7920 struct QueueQualityContext
7923 * Set to the @e k'th queue encountered.
7928 * Set to the number of quality queues encountered.
7930 unsigned int quality_count;
7933 * Set to the total number of queues encountered.
7935 unsigned int num_queues;
7938 * Decremented for each queue, for selection of the
7939 * k-th queue in @e q.
7946 * Check whether any queue to the given neighbour is
7947 * of a good "quality" and if so, increment the counter.
7948 * Also counts the total number of queues, and returns
7949 * the k-th queue found.
7951 * @param cls a `struct QueueQualityContext *` with counters
7952 * @param pid peer this is about
7953 * @param value a `struct Neighbour`
7954 * @return #GNUNET_OK (continue to iterate)
7957 check_connection_quality (void *cls,
7958 const struct GNUNET_PeerIdentity *pid,
7961 struct QueueQualityContext *ctx = cls;
7962 struct Neighbour *n = value;
7967 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7972 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
7973 statistics and consider those as well here? */
7974 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
7975 do_inc = GNUNET_YES;
7977 if (GNUNET_YES == do_inc)
7978 ctx->quality_count++;
7984 * Task run when we CONSIDER initiating a DV learn
7985 * process. We first check that sending out a message is
7986 * even possible (queues exist), then that it is desirable
7987 * (if not, reschedule the task for later), and finally
7988 * we may then begin the job. If there are too many
7989 * entries in the #dvlearn_map, we purge the oldest entry
7995 start_dv_learn (void *cls)
7997 struct LearnLaunchEntry *lle;
7998 struct QueueQualityContext qqc;
7999 struct TransportDVLearnMessage dvl;
8002 dvlearn_task = NULL;
8003 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8004 return; /* lost all connectivity, cannot do learning */
8005 qqc.quality_count = 0;
8007 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8008 &check_connection_quality,
8010 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8012 struct GNUNET_TIME_Relative delay;
8013 unsigned int factor;
8015 /* scale our retries by how far we are above the threshold */
8016 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8017 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8018 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8021 /* remove old entries in #dvlearn_map if it has grown too big */
8022 while (MAX_DV_LEARN_PENDING >=
8023 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8026 GNUNET_assert (GNUNET_YES ==
8027 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8028 &lle->challenge.value,
8030 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8033 /* setup data structure for learning */
8034 lle = GNUNET_new (struct LearnLaunchEntry);
8035 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8037 sizeof (lle->challenge));
8038 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8039 GNUNET_break (GNUNET_YES ==
8040 GNUNET_CONTAINER_multishortmap_put (
8042 &lle->challenge.value,
8044 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8045 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8046 dvl.header.size = htons (sizeof (dvl));
8047 dvl.num_hops = htons (0);
8048 dvl.bidirectional = htons (0);
8049 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8050 dvl.monotonic_time =
8051 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8053 struct DvInitPS dvip = {.purpose.purpose = htonl (
8054 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8055 .purpose.size = htonl (sizeof (dvip)),
8056 .monotonic_time = dvl.monotonic_time,
8057 .challenge = lle->challenge};
8059 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8063 dvl.initiator = GST_my_identity;
8064 dvl.challenge = lle->challenge;
8066 qqc.quality_count = 0;
8067 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8070 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8071 &check_connection_quality,
8073 GNUNET_assert (NULL != qqc.q);
8075 /* Do this as close to transmission time as possible! */
8076 lle->launch_time = GNUNET_TIME_absolute_get ();
8078 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8079 /* reschedule this job, randomizing the time it runs (but no
8081 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8082 DV_LEARN_BASE_FREQUENCY),
8089 * A new queue has been created, check if any address validation
8090 * requests have been waiting for it.
8092 * @param cls a `struct Queue`
8093 * @param pid peer concerned (unused)
8094 * @param value a `struct ValidationState`
8095 * @return #GNUNET_NO if a match was found and we can stop looking
8098 check_validation_request_pending (void *cls,
8099 const struct GNUNET_PeerIdentity *pid,
8102 struct Queue *q = cls;
8103 struct ValidationState *vs = value;
8106 if ((GNUNET_YES == vs->awaiting_queue) &&
8107 (0 == strcmp (vs->address, q->address)))
8109 vs->awaiting_queue = GNUNET_NO;
8110 validation_transmit_on_queue (q, vs);
8118 * Function called with the monotonic time of a DV initiator
8119 * by PEERSTORE. Updates the time.
8121 * @param cls a `struct Neighbour`
8122 * @param record the information found, NULL for the last call
8123 * @param emsg error message
8126 neighbour_dv_monotime_cb (void *cls,
8127 const struct GNUNET_PEERSTORE_Record *record,
8130 struct Neighbour *n = cls;
8131 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8136 /* we're done with #neighbour_dv_monotime_cb() invocations,
8137 continue normal processing */
8139 n->dv_monotime_available = GNUNET_YES;
8142 if (sizeof (*mtbe) != record->value_size)
8147 mtbe = record->value;
8148 n->last_dv_learn_monotime =
8149 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8150 GNUNET_TIME_absolute_ntoh (*mtbe));
8155 * New queue became available. Process the request.
8157 * @param cls the client
8158 * @param aqm the send message that was sent
8161 handle_add_queue_message (void *cls,
8162 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8164 struct TransportClient *tc = cls;
8165 struct Queue *queue;
8166 struct Neighbour *neighbour;
8170 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8172 /* MTU so small as to be useless for transmissions,
8173 required for #fragment_message()! */
8174 GNUNET_break_op (0);
8175 GNUNET_SERVICE_client_drop (tc->client);
8178 neighbour = lookup_neighbour (&aqm->receiver);
8179 if (NULL == neighbour)
8181 neighbour = GNUNET_new (struct Neighbour);
8182 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
8183 neighbour->pid = aqm->receiver;
8184 GNUNET_assert (GNUNET_OK ==
8185 GNUNET_CONTAINER_multipeermap_put (
8189 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8191 GNUNET_PEERSTORE_iterate (peerstore,
8194 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8195 &neighbour_dv_monotime_cb,
8198 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8199 addr = (const char *) &aqm[1];
8201 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8203 queue->address = (const char *) &queue[1];
8204 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8205 queue->qid = aqm->qid;
8206 queue->mtu = ntohl (aqm->mtu);
8207 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8208 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8209 queue->neighbour = neighbour;
8210 memcpy (&queue[1], addr, addr_len);
8211 /* notify monitors about new queue */
8213 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8215 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8217 GNUNET_CONTAINER_MDLL_insert (neighbour,
8218 neighbour->queue_head,
8219 neighbour->queue_tail,
8221 GNUNET_CONTAINER_MDLL_insert (client,
8222 tc->details.communicator.queue_head,
8223 tc->details.communicator.queue_tail,
8225 /* check if valdiations are waiting for the queue */
8227 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8229 &check_validation_request_pending,
8231 /* might be our first queue, try launching DV learning */
8232 if (NULL == dvlearn_task)
8233 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8234 GNUNET_SERVICE_client_continue (tc->client);
8239 * Communicator tells us that our request to create a queue "worked", that
8240 * is setting up the queue is now in process.
8242 * @param cls the `struct TransportClient`
8243 * @param cqr confirmation message
8246 handle_queue_create_ok (void *cls,
8247 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8249 struct TransportClient *tc = cls;
8251 if (CT_COMMUNICATOR != tc->type)
8254 GNUNET_SERVICE_client_drop (tc->client);
8257 GNUNET_STATISTICS_update (GST_stats,
8258 "# Suggestions succeeded at communicator",
8261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8262 "Request #%u for communicator to create queue succeeded\n",
8263 (unsigned int) ntohs (cqr->request_id));
8264 GNUNET_SERVICE_client_continue (tc->client);
8269 * Communicator tells us that our request to create a queue failed. This
8270 * usually indicates that the provided address is simply invalid or that the
8271 * communicator's resources are exhausted.
8273 * @param cls the `struct TransportClient`
8274 * @param cqr failure message
8277 handle_queue_create_fail (
8279 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8281 struct TransportClient *tc = cls;
8283 if (CT_COMMUNICATOR != tc->type)
8286 GNUNET_SERVICE_client_drop (tc->client);
8289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8290 "Request #%u for communicator to create queue failed\n",
8291 (unsigned int) ntohs (cqr->request_id));
8292 GNUNET_STATISTICS_update (GST_stats,
8293 "# Suggestions failed in queue creation at communicator",
8296 GNUNET_SERVICE_client_continue (tc->client);
8301 * We have received a `struct ExpressPreferenceMessage` from an application
8304 * @param cls handle to the client
8305 * @param msg the start message
8308 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8310 struct TransportClient *tc = cls;
8311 struct PeerRequest *pr;
8313 if (CT_APPLICATION != tc->type)
8316 GNUNET_SERVICE_client_drop (tc->client);
8319 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8324 GNUNET_SERVICE_client_drop (tc->client);
8327 (void) stop_peer_request (tc, &pr->pid, pr);
8328 GNUNET_SERVICE_client_continue (tc->client);
8333 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8334 * messages. We do nothing here, real verification is done later.
8336 * @param cls a `struct TransportClient *`
8337 * @param msg message to verify
8338 * @return #GNUNET_OK
8341 check_address_consider_verify (
8343 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8352 * Closure for #check_known_address.
8354 struct CheckKnownAddressContext
8357 * Set to the address we are looking for.
8359 const char *address;
8362 * Set to a matching validation state, if one was found.
8364 struct ValidationState *vs;
8369 * Test if the validation state in @a value matches the
8370 * address from @a cls.
8372 * @param cls a `struct CheckKnownAddressContext`
8373 * @param pid unused (must match though)
8374 * @param value a `struct ValidationState`
8375 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8378 check_known_address (void *cls,
8379 const struct GNUNET_PeerIdentity *pid,
8382 struct CheckKnownAddressContext *ckac = cls;
8383 struct ValidationState *vs = value;
8386 if (0 != strcmp (vs->address, ckac->address))
8394 * Start address validation.
8396 * @param pid peer the @a address is for
8397 * @param address an address to reach @a pid (presumably)
8398 * @param expiration when did @a pid claim @a address will become invalid
8401 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8402 const char *address,
8403 struct GNUNET_TIME_Absolute expiration)
8405 struct GNUNET_TIME_Absolute now;
8406 struct ValidationState *vs;
8407 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8409 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
8410 return; /* expired */
8411 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8413 &check_known_address,
8415 if (NULL != (vs = ckac.vs))
8417 /* if 'vs' is not currently valid, we need to speed up retrying the
8419 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8421 /* reduce backoff as we got a fresh advertisement */
8422 vs->challenge_backoff =
8423 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8424 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8426 update_next_challenge_time (vs,
8427 GNUNET_TIME_relative_to_absolute (
8428 vs->challenge_backoff));
8432 now = GNUNET_TIME_absolute_get ();
8433 vs = GNUNET_new (struct ValidationState);
8435 vs->valid_until = expiration;
8436 vs->first_challenge_use = now;
8437 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8438 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8440 sizeof (vs->challenge));
8441 vs->address = GNUNET_strdup (address);
8442 GNUNET_assert (GNUNET_YES ==
8443 GNUNET_CONTAINER_multipeermap_put (
8447 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8448 update_next_challenge_time (vs, now);
8453 * Function called by PEERSTORE for each matching record.
8455 * @param cls closure
8456 * @param record peerstore record information
8457 * @param emsg error message, or NULL if no errors
8460 handle_hello (void *cls,
8461 const struct GNUNET_PEERSTORE_Record *record,
8464 struct PeerRequest *pr = cls;
8469 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8470 "Got failure from PEERSTORE: %s\n",
8474 val = record->value;
8475 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8480 start_address_validation (&pr->pid,
8481 (const char *) record->value,
8487 * We have received a `struct ExpressPreferenceMessage` from an application
8490 * @param cls handle to the client
8491 * @param msg the start message
8494 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8496 struct TransportClient *tc = cls;
8497 struct PeerRequest *pr;
8499 if (CT_NONE == tc->type)
8501 tc->type = CT_APPLICATION;
8502 tc->details.application.requests =
8503 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8505 if (CT_APPLICATION != tc->type)
8508 GNUNET_SERVICE_client_drop (tc->client);
8511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8512 "Client suggested we talk to %s with preference %d at rate %u\n",
8513 GNUNET_i2s (&msg->peer),
8514 (int) ntohl (msg->pk),
8515 (int) ntohl (msg->bw.value__));
8516 pr = GNUNET_new (struct PeerRequest);
8518 pr->pid = msg->peer;
8520 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
8521 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8522 tc->details.application.requests,
8525 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8529 GNUNET_SERVICE_client_drop (tc->client);
8532 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8535 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8538 GNUNET_SERVICE_client_continue (tc->client);
8543 * Given another peers address, consider checking it for validity
8544 * and then adding it to the Peerstore.
8546 * @param cls a `struct TransportClient`
8547 * @param hdr message containing the raw address data and
8548 * signature in the body, see #GNUNET_HELLO_extract_address()
8551 handle_address_consider_verify (
8553 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8555 struct TransportClient *tc = cls;
8557 enum GNUNET_NetworkType nt;
8558 struct GNUNET_TIME_Absolute expiration;
8561 // OPTIMIZE-FIXME: checking that we know this address already should
8562 // be done BEFORE checking the signature => HELLO API change!
8563 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8566 GNUNET_HELLO_extract_address (&hdr[1],
8567 ntohs (hdr->header.size) - sizeof (*hdr),
8571 if (NULL == address)
8573 GNUNET_break_op (0);
8576 start_address_validation (&hdr->peer, address, expiration);
8577 GNUNET_free (address);
8578 GNUNET_SERVICE_client_continue (tc->client);
8583 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8586 * @param cls a `struct TransportClient *`
8587 * @param m message to verify
8588 * @return #GNUNET_OK on success
8591 check_request_hello_validation (void *cls,
8592 const struct RequestHelloValidationMessage *m)
8595 GNUNET_MQ_check_zero_termination (m);
8601 * A client encountered an address of another peer. Consider validating it,
8602 * and if validation succeeds, persist it to PEERSTORE.
8604 * @param cls a `struct TransportClient *`
8605 * @param m message to verify
8608 handle_request_hello_validation (void *cls,
8609 const struct RequestHelloValidationMessage *m)
8611 struct TransportClient *tc = cls;
8613 start_address_validation (&m->peer,
8614 (const char *) &m[1],
8615 GNUNET_TIME_absolute_ntoh (m->expiration));
8616 GNUNET_SERVICE_client_continue (tc->client);
8621 * Free neighbour entry.
8625 * @param value a `struct Neighbour`
8626 * @return #GNUNET_OK (always)
8629 free_neighbour_cb (void *cls,
8630 const struct GNUNET_PeerIdentity *pid,
8633 struct Neighbour *neighbour = value;
8637 GNUNET_break (0); // should this ever happen?
8638 free_neighbour (neighbour);
8645 * Free DV route entry.
8649 * @param value a `struct DistanceVector`
8650 * @return #GNUNET_OK (always)
8653 free_dv_routes_cb (void *cls,
8654 const struct GNUNET_PeerIdentity *pid,
8657 struct DistanceVector *dv = value;
8668 * Free ephemeral entry.
8672 * @param value a `struct EphemeralCacheEntry`
8673 * @return #GNUNET_OK (always)
8676 free_ephemeral_cb (void *cls,
8677 const struct GNUNET_PeerIdentity *pid,
8680 struct EphemeralCacheEntry *ece = value;
8684 free_ephemeral (ece);
8690 * Free validation state.
8694 * @param value a `struct ValidationState`
8695 * @return #GNUNET_OK (always)
8698 free_validation_state_cb (void *cls,
8699 const struct GNUNET_PeerIdentity *pid,
8702 struct ValidationState *vs = value;
8706 free_validation_state (vs);
8712 * Free pending acknowledgement.
8716 * @param value a `struct PendingAcknowledgement`
8717 * @return #GNUNET_OK (always)
8720 free_pending_ack_cb (void *cls,
8721 const struct GNUNET_ShortHashCode *key,
8724 struct PendingAcknowledgement *pa = value;
8728 free_pending_acknowledgement (pa);
8734 * Free acknowledgement cummulator.
8738 * @param value a `struct AcknowledgementCummulator`
8739 * @return #GNUNET_OK (always)
8742 free_ack_cummulator_cb (void *cls,
8743 const struct GNUNET_PeerIdentity *pid,
8746 struct AcknowledgementCummulator *ac = value;
8756 * Function called when the service shuts down. Unloads our plugins
8757 * and cancels pending validations.
8759 * @param cls closure, unused
8762 do_shutdown (void *cls)
8764 struct LearnLaunchEntry *lle;
8767 if (NULL != ephemeral_task)
8769 GNUNET_SCHEDULER_cancel (ephemeral_task);
8770 ephemeral_task = NULL;
8772 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
8773 if (NULL != peerstore)
8775 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
8778 if (NULL != GST_stats)
8780 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
8783 if (NULL != GST_my_private_key)
8785 GNUNET_free (GST_my_private_key);
8786 GST_my_private_key = NULL;
8788 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
8789 &free_ack_cummulator_cb,
8791 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
8792 ack_cummulators = NULL;
8793 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
8794 &free_pending_ack_cb,
8796 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
8797 pending_acks = NULL;
8798 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
8800 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
8801 &free_backtalker_cb,
8803 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
8805 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
8806 &free_validation_state_cb,
8808 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
8809 validation_map = NULL;
8810 while (NULL != (lle = lle_head))
8812 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8815 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
8817 GNUNET_CONTAINER_heap_destroy (validation_heap);
8818 validation_heap = NULL;
8819 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
8820 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
8822 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
8825 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
8826 ephemeral_map = NULL;
8827 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
8828 ephemeral_heap = NULL;
8833 * Initiate transport service.
8835 * @param cls closure
8836 * @param c configuration to use
8837 * @param service the initialized service
8841 const struct GNUNET_CONFIGURATION_Handle *c,
8842 struct GNUNET_SERVICE_Handle *service)
8848 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8849 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
8850 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
8851 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8852 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8853 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
8855 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8856 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
8858 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8860 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8861 GST_my_private_key =
8862 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
8863 if (NULL == GST_my_private_key)
8866 GNUNET_ERROR_TYPE_ERROR,
8868 "Transport service is lacking key configuration settings. Exiting.\n"));
8869 GNUNET_SCHEDULER_shutdown ();
8872 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
8873 &GST_my_identity.public_key);
8874 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8875 "My identity is `%s'\n",
8876 GNUNET_i2s_full (&GST_my_identity));
8877 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
8878 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
8879 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
8880 if (NULL == peerstore)
8883 GNUNET_SCHEDULER_shutdown ();
8890 * Define "main" method using service macro.
8892 GNUNET_SERVICE_MAIN (
8894 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
8897 &client_disconnect_cb,
8899 /* communication with applications */
8900 GNUNET_MQ_hd_fixed_size (suggest,
8901 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
8902 struct ExpressPreferenceMessage,
8904 GNUNET_MQ_hd_fixed_size (suggest_cancel,
8905 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
8906 struct ExpressPreferenceMessage,
8908 GNUNET_MQ_hd_var_size (request_hello_validation,
8909 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
8910 struct RequestHelloValidationMessage,
8912 /* communication with core */
8913 GNUNET_MQ_hd_fixed_size (client_start,
8914 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
8915 struct StartMessage,
8917 GNUNET_MQ_hd_var_size (client_send,
8918 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
8919 struct OutboundMessage,
8921 /* communication with communicators */
8922 GNUNET_MQ_hd_var_size (communicator_available,
8923 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
8924 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
8926 GNUNET_MQ_hd_var_size (communicator_backchannel,
8927 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
8928 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
8930 GNUNET_MQ_hd_var_size (add_address,
8931 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
8932 struct GNUNET_TRANSPORT_AddAddressMessage,
8934 GNUNET_MQ_hd_fixed_size (del_address,
8935 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
8936 struct GNUNET_TRANSPORT_DelAddressMessage,
8938 GNUNET_MQ_hd_var_size (incoming_msg,
8939 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
8940 struct GNUNET_TRANSPORT_IncomingMessage,
8942 GNUNET_MQ_hd_fixed_size (queue_create_ok,
8943 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
8944 struct GNUNET_TRANSPORT_CreateQueueResponse,
8946 GNUNET_MQ_hd_fixed_size (queue_create_fail,
8947 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
8948 struct GNUNET_TRANSPORT_CreateQueueResponse,
8950 GNUNET_MQ_hd_var_size (add_queue_message,
8951 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
8952 struct GNUNET_TRANSPORT_AddQueueMessage,
8954 GNUNET_MQ_hd_var_size (address_consider_verify,
8955 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
8956 struct GNUNET_TRANSPORT_AddressToVerify,
8958 GNUNET_MQ_hd_fixed_size (del_queue_message,
8959 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
8960 struct GNUNET_TRANSPORT_DelQueueMessage,
8962 GNUNET_MQ_hd_fixed_size (send_message_ack,
8963 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
8964 struct GNUNET_TRANSPORT_SendMessageToAck,
8966 /* communication with monitors */
8967 GNUNET_MQ_hd_fixed_size (monitor_start,
8968 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
8969 struct GNUNET_TRANSPORT_MonitorStart,
8971 GNUNET_MQ_handler_end ());
8974 /* end of file gnunet-service-transport.c */