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 * - persistence of monotonic time obtained from other peers
29 * in PEERSTORE (by message type) -- done for backchannel, needed elsewhere?
30 * - change transport-core API to provide proper flow control in both
31 * directions, allow multiple messages per peer simultaneously (tag
32 * confirmations with unique message ID), and replace quota-out with
33 * proper flow control; specify transmission preferences (latency,
34 * reliability, etc.) per message!
38 * - review retransmission logic, right now there is no smartness there!
39 * => congestion control, flow control, etc
42 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
43 * => Need 128 bit hash map though!
44 * - queue_send_msg and route_message both by API design have to make copies
45 * of the payload, and route_message on top of that requires a malloc/free.
46 * Change design to approximate "zero" copy better...
47 * - could avoid copying body of message into each fragment and keep
48 * fragments as just pointers into the original message and only
49 * fully build fragments just before transmission (optimization, should
50 * reduce CPU and memory use)
51 * - if messages are below MTU, consider adding ACKs and other stuff
52 * (requires planning at receiver, and additional MST-style demultiplex
54 * - When we passively learned DV (with unconfirmed freshness), we
55 * right now add the path to our list but with a zero path_valid_until
56 * time and only use it for unconfirmed routes. However, we could consider
57 * triggering an explicit validation mechansim ourselves, specifically routing
58 * a challenge-response message over the path (OPTIMIZATION-FIXME).
60 * Design realizations / discussion:
61 * - communicators do flow control by calling MQ "notify sent"
62 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
63 * or explicitly via backchannel FC ACKs. As long as the
64 * channel is not full, they may 'notify sent' even if the other
65 * peer has not yet confirmed receipt. The other peer confirming
66 * is _only_ for FC, not for more reliable transmission; reliable
67 * transmission (i.e. of fragments) is left to _transport_.
68 * - ACKs sent back in uni-directional communicators are done via
69 * the background channel API; here transport _may_ initially
70 * broadcast (with bounded # hops) if no path is known;
71 * - transport should _integrate_ DV-routing and build a view of
72 * the network; then background channel traffic can be
73 * routed via DV as well as explicit "DV" traffic.
74 * - background channel is also used for ACKs and NAT traversal support
75 * - transport service is responsible for AEAD'ing the background
76 * channel, timestamps and monotonic time are used against replay
77 * of old messages -> peerstore needs to be supplied with
78 * "latest timestamps seen" data
79 * - if transport implements DV, we likely need a 3rd peermap
80 * in addition to ephemerals and (direct) neighbours
81 * ==> check if stuff needs to be moved out of "Neighbour"
82 * - transport should encapsualte core-level messages and do its
83 * own ACKing for RTT/goodput/loss measurements _and_ fragment
87 #include "gnunet_util_lib.h"
88 #include "gnunet_statistics_service.h"
89 #include "gnunet_transport_monitor_service.h"
90 #include "gnunet_peerstore_service.h"
91 #include "gnunet_hello_lib.h"
92 #include "gnunet_signatures.h"
93 #include "transport.h"
96 * Maximum number of messages we acknowledge together in one
97 * cummulative ACK. Larger values may save a bit of bandwidth.
99 #define MAX_CUMMULATIVE_ACKS 64
102 * What is the size we assume for a read operation in the
103 * absence of an MTU for the purpose of flow control?
105 #define IN_PACKET_SIZE_WITHOUT_MTU 128
108 * Number of slots we keep of historic data for computation of
109 * goodput / message loss ratio.
111 #define GOODPUT_AGING_SLOTS 4
114 * Maximum number of peers we select for forwarding DVInit
115 * messages at the same time (excluding initiator).
117 #define MAX_DV_DISCOVERY_SELECTION 16
120 * Minimum number of hops we should forward DV learn messages
121 * even if they are NOT useful for us in hope of looping
122 * back to the initiator?
124 * FIXME: allow initiator some control here instead?
126 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
129 * Maximum DV distance allowed ever.
131 #define MAX_DV_HOPS_ALLOWED 16
134 * Maximum number of DV learning activities we may
135 * have pending at the same time.
137 #define MAX_DV_LEARN_PENDING 64
140 * Maximum number of DV paths we keep simultaneously to the same target.
142 #define MAX_DV_PATHS_TO_TARGET 3
145 * If a queue delays the next message by more than this number
146 * of seconds we log a warning. Note: this is for testing,
147 * the value chosen here might be too aggressively low!
149 #define DELAY_WARN_THRESHOLD \
150 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
153 * We only consider queues as "quality" connections when
154 * suppressing the generation of DV initiation messages if
155 * the latency of the queue is below this threshold.
157 #define DV_QUALITY_RTT_THRESHOLD \
158 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
161 * How long do we consider a DV path valid if we see no
162 * further updates on it? Note: the value chosen here might be too low!
164 #define DV_PATH_VALIDITY_TIMEOUT \
165 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
168 * How long do we cache backchannel (struct Backtalker) information
169 * after a backchannel goes inactive?
171 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
172 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
175 * How long before paths expire would we like to (re)discover DV paths? Should
176 * be below #DV_PATH_VALIDITY_TIMEOUT.
178 #define DV_PATH_DISCOVERY_FREQUENCY \
179 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
182 * How long are ephemeral keys valid?
184 #define EPHEMERAL_VALIDITY \
185 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
188 * How long do we keep partially reassembled messages around before giving up?
190 #define REASSEMBLY_EXPIRATION \
191 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
194 * What is the fastest rate at which we send challenges *if* we keep learning
195 * an address (gossip, DHT, etc.)?
197 #define FAST_VALIDATION_CHALLENGE_FREQ \
198 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
201 * What is the slowest rate at which we send challenges?
203 #define MAX_VALIDATION_CHALLENGE_FREQ \
204 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
207 * How long until we forget about historic accumulators and thus
208 * reset the ACK counter? Should exceed the maximum time an
209 * active connection experiences without an ACK.
211 #define ACK_CUMMULATOR_TIMEOUT \
212 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
215 * What is the non-randomized base frequency at which we
216 * would initiate DV learn messages?
218 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
221 * How many good connections (confirmed, bi-directional, not DV)
222 * do we need to have to suppress initiating DV learn messages?
224 #define DV_LEARN_QUALITY_THRESHOLD 100
227 * When do we forget an invalid address for sure?
229 #define MAX_ADDRESS_VALID_UNTIL \
230 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
233 * How long do we consider an address valid if we just checked?
235 #define ADDRESS_VALIDATION_LIFETIME \
236 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
239 * What is the maximum frequency at which we do address validation?
240 * A random value between 0 and this value is added when scheduling
241 * the #validation_task (both to ensure we do not validate too often,
242 * and to randomize a bit).
244 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
247 * How many network RTTs before an address validation expires should we begin
248 * trying to revalidate? (Note that the RTT used here is the one that we
249 * experienced during the last validation, not necessarily the latest RTT
252 #define VALIDATION_RTT_BUFFER_FACTOR 3
255 * How many messages can we have pending for a given communicator
256 * process before we start to throttle that communicator?
258 * Used if a communicator might be CPU-bound and cannot handle the traffic.
260 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
263 * How many messages can we have pending for a given queue (queue to
264 * a particular peer via a communicator) process before we start to
265 * throttle that queue?
267 #define QUEUE_LENGTH_LIMIT 32
270 GNUNET_NETWORK_STRUCT_BEGIN
273 * Unique identifier we attach to a message.
278 * Unique value, generated by incrementing the
279 * `message_uuid_ctr` of `struct Neighbour`.
281 uint64_t uuid GNUNET_PACKED;
286 * Unique identifier to map an acknowledgement to a transmission.
288 struct AcknowledgementUUIDP
291 * The UUID value. Not actually a hash, but a random value.
293 struct GNUNET_ShortHashCode value;
298 * Unique identifier we attach to a message.
303 * Unique value identifying a fragment, in NBO.
305 uint32_t uuid GNUNET_PACKED;
310 * Type of a nonce used for challenges.
312 struct ChallengeNonceP
315 * The value of the nonce. Note that this is NOT a hash.
317 struct GNUNET_ShortHashCode value;
322 * Outer layer of an encapsulated backchannel message.
324 struct TransportBackchannelEncapsulationMessage
327 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
329 struct GNUNET_MessageHeader header;
332 * Reserved, always zero.
334 uint32_t reserved GNUNET_PACKED;
337 * Target's peer identity (as backchannels may be transmitted
338 * indirectly, or even be broadcast).
340 struct GNUNET_PeerIdentity target;
343 * Ephemeral key setup by the sender for @e target, used
344 * to encrypt the payload.
346 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
349 * We use an IV here as the @e ephemeral_key is re-used for
350 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
352 struct GNUNET_ShortHashCode iv;
355 * HMAC over the ciphertext of the encrypted, variable-size
356 * body that follows. Verified via DH of @e target and
359 struct GNUNET_HashCode hmac;
361 /* Followed by encrypted, variable-size payload */
366 * Body by which a peer confirms that it is using an ephemeral key.
368 struct EphemeralConfirmationPS
372 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
374 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
377 * How long is this signature over the ephemeral key valid?
379 * Note that the receiver MUST IGNORE the absolute time, and only interpret
380 * the value as a mononic time and reject "older" values than the last one
381 * observed. This is necessary as we do not want to require synchronized
382 * clocks and may not have a bidirectional communication channel.
384 * Even with this, there is no real guarantee against replay achieved here,
385 * unless the latest timestamp is persisted. While persistence should be
386 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
387 * communicators must protect against replay attacks when using backchannel
390 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
393 * Target's peer identity.
395 struct GNUNET_PeerIdentity target;
398 * Ephemeral key setup by the sender for @e target, used
399 * to encrypt the payload.
401 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
406 * Plaintext of the variable-size payload that is encrypted
407 * within a `struct TransportBackchannelEncapsulationMessage`
409 struct TransportBackchannelRequestPayloadP
413 * Sender's peer identity.
415 struct GNUNET_PeerIdentity sender;
418 * Signature of the sender over an
419 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
421 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
424 * How long is this signature over the ephemeral key valid?
426 * Note that the receiver MUST IGNORE the absolute time, and only interpret
427 * the value as a mononic time and reject "older" values than the last one
428 * observed. This is necessary as we do not want to require synchronized
429 * clocks and may not have a bidirectional communication channel.
431 * Even with this, there is no real guarantee against replay achieved here,
432 * unless the latest timestamp is persisted. While persistence should be
433 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
434 * communicators must protect against replay attacks when using backchannel
437 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
440 * Current monotonic time of the sending transport service. Used to
441 * detect replayed messages. Note that the receiver should remember
442 * a list of the recently seen timestamps and only reject messages
443 * if the timestamp is in the list, or the list is "full" and the
444 * timestamp is smaller than the lowest in the list.
446 * Like the @e ephemeral_validity, the list of timestamps per peer should be
447 * persisted to guard against replays after restarts.
449 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
451 /* Followed by a `struct GNUNET_MessageHeader` with a message
452 for a communicator */
454 /* Followed by a 0-termianted string specifying the name of
455 the communicator which is to receive the message */
460 * Outer layer of an encapsulated unfragmented application message sent
461 * over an unreliable channel.
463 struct TransportReliabilityBoxMessage
466 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
468 struct GNUNET_MessageHeader header;
471 * Number of messages still to be sent before a commulative
472 * ACK is requested. Zero if an ACK is requested immediately.
473 * In NBO. Note that the receiver may send the ACK faster
474 * if it believes that is reasonable.
476 uint32_t ack_countdown GNUNET_PACKED;
479 * Unique ID of the message used for signalling receipt of
480 * messages sent over possibly unreliable channels. Should
483 struct AcknowledgementUUIDP ack_uuid;
488 * Acknowledgement payload.
490 struct TransportCummulativeAckPayloadP
493 * How long was the ACK delayed for generating cummulative ACKs?
494 * Used to calculate the correct network RTT by taking the receipt
495 * time of the ack minus the transmission time of the sender minus
498 struct GNUNET_TIME_RelativeNBO ack_delay;
501 * UUID of a message being acknowledged.
503 struct AcknowledgementUUIDP ack_uuid;
508 * Confirmation that the receiver got a
509 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
510 * confirmation may be transmitted over a completely different queue,
511 * so ACKs are identified by a combination of PID of sender and
512 * message UUID, without the queue playing any role!
514 struct TransportReliabilityAckMessage
517 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
519 struct GNUNET_MessageHeader header;
522 * Counter of ACKs transmitted by the sender to us. Incremented
523 * by one for each ACK, used to detect how many ACKs were lost.
525 uint32_t ack_counter GNUNET_PACKED;
527 /* followed by any number of `struct TransportCummulativeAckPayloadP`
528 messages providing ACKs */
533 * Outer layer of an encapsulated fragmented application message.
535 struct TransportFragmentBoxMessage
538 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
540 struct GNUNET_MessageHeader header;
543 * Unique ID of this fragment (and fragment transmission!). Will
544 * change even if a fragement is retransmitted to make each
545 * transmission attempt unique! If a client receives a duplicate
546 * fragment (same @e frag_off for same @a msg_uuid, it must send
547 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
549 struct AcknowledgementUUIDP ack_uuid;
552 * Original message ID for of the message that all the fragments
553 * belong to. Must be the same for all fragments.
555 struct MessageUUIDP msg_uuid;
558 * Offset of this fragment in the overall message.
560 uint16_t frag_off GNUNET_PACKED;
563 * Total size of the message that is being fragmented.
565 uint16_t msg_size GNUNET_PACKED;
570 * Content signed by the initator during DV learning.
572 * The signature is required to prevent DDoS attacks. A peer sending out this
573 * message is potentially generating a lot of traffic that will go back to the
574 * initator, as peers receiving this message will try to let the initiator
575 * know that they got the message.
577 * Without this signature, an attacker could abuse this mechanism for traffic
578 * amplification, sending a lot of traffic to a peer by putting out this type
579 * of message with the victim's peer identity.
581 * Even with just a signature, traffic amplification would be possible via
582 * replay attacks. The @e monotonic_time limits such replay attacks, as every
583 * potential amplificator will check the @e monotonic_time and only respond
584 * (at most) once per message.
589 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
591 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
594 * Time at the initiator when generating the signature.
596 * Note that the receiver MUST IGNORE the absolute time, and only interpret
597 * the value as a mononic time and reject "older" values than the last one
598 * observed. This is necessary as we do not want to require synchronized
599 * clocks and may not have a bidirectional communication channel.
601 * Even with this, there is no real guarantee against replay achieved here,
602 * unless the latest timestamp is persisted. Persistence should be
603 * provided via PEERSTORE if possible.
605 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
608 * Challenge value used by the initiator to re-identify the path.
610 struct ChallengeNonceP challenge;
615 * Content signed by each peer during DV learning.
617 * This assues the initiator of the DV learning operation that the hop from @e
618 * pred via the signing peer to @e succ actually exists. This makes it
619 * impossible for an adversary to supply the network with bogus routes.
621 * The @e challenge is included to provide replay protection for the
622 * initiator. This way, the initiator knows that the hop existed after the
623 * original @e challenge was first transmitted, providing a freshness metric.
625 * Peers other than the initiator that passively learn paths by observing
626 * these messages do NOT benefit from this. Here, an adversary may indeed
627 * replay old messages. Thus, passively learned paths should always be
628 * immediately marked as "potentially stale".
633 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
635 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
638 * Identity of the previous peer on the path.
640 struct GNUNET_PeerIdentity pred;
643 * Identity of the next peer on the path.
645 struct GNUNET_PeerIdentity succ;
648 * Challenge value used by the initiator to re-identify the path.
650 struct ChallengeNonceP challenge;
655 * An entry describing a peer on a path in a
656 * `struct TransportDVLearnMessage` message.
661 * Identity of a peer on the path.
663 struct GNUNET_PeerIdentity hop;
666 * Signature of this hop over the path, of purpose
667 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
669 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
674 * Internal message used by transport for distance vector learning.
675 * If @e num_hops does not exceed the threshold, peers should append
676 * themselves to the peer list and flood the message (possibly only
677 * to a subset of their neighbours to limit discoverability of the
678 * network topology). To the extend that the @e bidirectional bits
679 * are set, peers may learn the inverse paths even if they did not
682 * Unless received on a bidirectional queue and @e num_hops just
683 * zero, peers that can forward to the initator should always try to
684 * forward to the initiator.
686 struct TransportDVLearnMessage
689 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
691 struct GNUNET_MessageHeader header;
694 * Number of hops this messages has travelled, in NBO. Zero if
697 uint16_t num_hops GNUNET_PACKED;
700 * Bitmask of the last 16 hops indicating whether they are confirmed
701 * available (without DV) in both directions or not, in NBO. Used
702 * to possibly instantly learn a path in both directions. Each peer
703 * should shift this value by one to the left, and then set the
704 * lowest bit IF the current sender can be reached from it (without
707 uint16_t bidirectional GNUNET_PACKED;
710 * Peers receiving this message and delaying forwarding to other
711 * peers for any reason should increment this value by the non-network
712 * delay created by the peer.
714 struct GNUNET_TIME_RelativeNBO non_network_delay;
717 * Time at the initiator when generating the signature.
719 * Note that the receiver MUST IGNORE the absolute time, and only interpret
720 * the value as a mononic time and reject "older" values than the last one
721 * observed. This is necessary as we do not want to require synchronized
722 * clocks and may not have a bidirectional communication channel.
724 * Even with this, there is no real guarantee against replay achieved here,
725 * unless the latest timestamp is persisted. Persistence should be
726 * provided via PEERSTORE if possible.
728 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
731 * Signature of this hop over the path, of purpose
732 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
734 struct GNUNET_CRYPTO_EddsaSignature init_sig;
737 * Identity of the peer that started this learning activity.
739 struct GNUNET_PeerIdentity initiator;
742 * Challenge value used by the initiator to re-identify the path.
744 struct ChallengeNonceP challenge;
746 /* Followed by @e num_hops `struct DVPathEntryP` values,
747 excluding the initiator of the DV trace; the last entry is the
748 current sender; the current peer must not be included. */
753 * Outer layer of an encapsulated message send over multiple hops.
754 * The path given only includes the identities of the subsequent
755 * peers, i.e. it will be empty if we are the receiver. Each
756 * forwarding peer should scan the list from the end, and if it can,
757 * forward to the respective peer. The list should then be shortened
758 * by all the entries up to and including that peer. Each hop should
759 * also increment @e total_hops to allow the receiver to get a precise
760 * estimate on the number of hops the message travelled. Senders must
761 * provide a learned path that thus should work, but intermediaries
762 * know of a shortcut, they are allowed to send the message via that
765 * If a peer finds itself still on the list, it must drop the message.
767 struct TransportDVBoxMessage
770 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
772 struct GNUNET_MessageHeader header;
775 * Number of total hops this messages travelled. In NBO.
776 * @e origin sets this to zero, to be incremented at
779 uint16_t total_hops GNUNET_PACKED;
782 * Number of hops this messages includes. In NBO.
784 uint16_t num_hops GNUNET_PACKED;
787 * Identity of the peer that originated the message.
789 struct GNUNET_PeerIdentity origin;
791 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
792 excluding the @e origin and the current peer, the last must be
793 the ultimate target; if @e num_hops is zero, the receiver of this
794 message is the ultimate target. */
796 /* Followed by the actual message, which itself may be
797 another box, but not a DV_LEARN or DV_BOX message! */
802 * Message send to another peer to validate that it can indeed
803 * receive messages at a particular address.
805 struct TransportValidationChallengeMessage
809 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
811 struct GNUNET_MessageHeader header;
816 uint32_t reserved GNUNET_PACKED;
819 * Challenge to be signed by the receiving peer.
821 struct ChallengeNonceP challenge;
824 * Timestamp of the sender, to be copied into the reply
825 * to allow sender to calculate RTT.
827 struct GNUNET_TIME_AbsoluteNBO sender_time;
832 * Message signed by a peer to confirm that it can indeed
833 * receive messages at a particular address.
835 struct TransportValidationPS
839 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
841 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
844 * How long does the sender believe the address on
845 * which the challenge was received to remain valid?
847 struct GNUNET_TIME_RelativeNBO validity_duration;
850 * Challenge signed by the receiving peer.
852 struct ChallengeNonceP challenge;
857 * Message send to a peer to respond to a
858 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
860 struct TransportValidationResponseMessage
864 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
866 struct GNUNET_MessageHeader header;
871 uint32_t reserved GNUNET_PACKED;
874 * The peer's signature matching the
875 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
877 struct GNUNET_CRYPTO_EddsaSignature signature;
880 * The challenge that was signed by the receiving peer.
882 struct ChallengeNonceP challenge;
885 * Original timestamp of the sender (was @code{sender_time}),
886 * copied into the reply to allow sender to calculate RTT.
888 struct GNUNET_TIME_AbsoluteNBO origin_time;
891 * How long does the sender believe this address to remain
894 struct GNUNET_TIME_RelativeNBO validity_duration;
898 GNUNET_NETWORK_STRUCT_END
902 * What type of client is the `struct TransportClient` about?
907 * We do not know yet (client is fresh).
912 * Is the CORE service, we need to forward traffic to it.
917 * It is a monitor, forward monitor data.
922 * It is a communicator, use for communication.
927 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
934 * Which transmission options are allowable for transmission?
935 * Interpreted bit-wise!
937 enum RouteMessageOptions
940 * Only confirmed, non-DV direct neighbours.
945 * We are allowed to use DV routing for this @a hdr
950 * We are allowed to use unconfirmed queues or DV routes for this message
952 RMO_UNCONFIRMED_ALLOWED = 2,
955 * Reliable and unreliable, DV and non-DV are all acceptable.
957 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
960 * If we have multiple choices, it is OK to send this message
961 * over multiple channels at the same time to improve loss tolerance.
962 * (We do at most 2 transmissions.)
969 * When did we launch this DV learning activity?
971 struct LearnLaunchEntry
975 * Kept (also) in a DLL sorted by launch time.
977 struct LearnLaunchEntry *prev;
980 * Kept (also) in a DLL sorted by launch time.
982 struct LearnLaunchEntry *next;
985 * Challenge that uniquely identifies this activity.
987 struct ChallengeNonceP challenge;
990 * When did we transmit the DV learn message (used to calculate RTT) and
991 * determine freshness of paths learned via this operation.
993 struct GNUNET_TIME_Absolute launch_time;
998 * Entry in our cache of ephemeral keys we currently use. This way, we only
999 * sign an ephemeral once per @e target, and then can re-use it over multiple
1000 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
1001 * signing is expensive and in some cases we may use backchannel messages a
1004 struct EphemeralCacheEntry
1008 * Target's peer identity (we don't re-use ephemerals
1009 * to limit linkability of messages).
1011 struct GNUNET_PeerIdentity target;
1014 * Signature affirming @e ephemeral_key of type
1015 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1017 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1020 * How long is @e sender_sig valid
1022 struct GNUNET_TIME_Absolute ephemeral_validity;
1025 * Our ephemeral key.
1027 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1030 * Our private ephemeral key.
1032 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1035 * Node in the ephemeral cache for this entry.
1036 * Used for expiration.
1038 struct GNUNET_CONTAINER_HeapNode *hn;
1043 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1044 * (or current) transmission performance.
1046 struct TransmissionHistoryEntry
1049 * Number of bytes actually sent in the interval.
1051 uint64_t bytes_sent;
1054 * Number of bytes received and acknowledged by the other peer in
1057 uint64_t bytes_received;
1062 * Performance data for a transmission possibility.
1064 struct PerformanceData
1067 * Weighted average for the RTT.
1069 struct GNUNET_TIME_Relative aged_rtt;
1072 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1075 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1078 * What was the last age when we wrote to @e the? Used to clear
1079 * old entries when the age advances.
1081 unsigned int last_age;
1086 * Client connected to the transport service.
1088 struct TransportClient;
1091 * A neighbour that at least one communicator is connected to.
1096 * Entry in our #dv_routes table, representing a (set of) distance
1097 * vector routes to a particular peer.
1099 struct DistanceVector;
1102 * A queue is a message queue provided by a communicator
1103 * via which we can reach a particular neighbour.
1108 * Message awaiting transmission. See detailed comments below.
1110 struct PendingMessage;
1113 * One possible hop towards a DV target.
1115 struct DistanceVectorHop;
1119 * Data structure kept when we are waiting for an acknowledgement.
1121 struct PendingAcknowledgement
1125 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1126 * is kept in relation to its pending message.
1128 struct PendingAcknowledgement *next_pm;
1131 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1132 * is kept in relation to its pending message.
1134 struct PendingAcknowledgement *prev_pm;
1137 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1138 * is kept in relation to the queue that was used to transmit the
1141 struct PendingAcknowledgement *next_queue;
1144 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1145 * is kept in relation to the queue that was used to transmit the
1148 struct PendingAcknowledgement *prev_queue;
1151 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1152 * is kept in relation to the DVH that was used to transmit the
1155 struct PendingAcknowledgement *next_dvh;
1158 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1159 * is kept in relation to the DVH that was used to transmit the
1162 struct PendingAcknowledgement *prev_dvh;
1165 * Pointers for the DLL of all pending acknowledgements.
1166 * This list is sorted by @e transmission time. If the list gets too
1167 * long, the oldest entries are discarded.
1169 struct PendingAcknowledgement *next_pa;
1172 * Pointers for the DLL of all pending acknowledgements.
1173 * This list is sorted by @e transmission time. If the list gets too
1174 * long, the oldest entries are discarded.
1176 struct PendingAcknowledgement *prev_pa;
1179 * Unique identifier for this transmission operation.
1181 struct AcknowledgementUUIDP ack_uuid;
1184 * Message that was transmitted, may be NULL if the message was ACKed
1185 * via another channel.
1187 struct PendingMessage *pm;
1190 * Distance vector path chosen for this transmission, NULL if transmission
1191 * was to a direct neighbour OR if the path was forgotten in the meantime.
1193 struct DistanceVectorHop *dvh;
1196 * Queue used for transmission, NULL if the queue has been destroyed
1197 * (which may happen before we get an acknowledgement).
1199 struct Queue *queue;
1202 * Time of the transmission, for RTT calculation.
1204 struct GNUNET_TIME_Absolute transmission_time;
1207 * Number of bytes of the original message (to calculate bandwidth).
1209 uint16_t message_size;
1214 * One possible hop towards a DV target.
1216 struct DistanceVectorHop
1220 * Kept in a MDLL, sorted by @e timeout.
1222 struct DistanceVectorHop *next_dv;
1225 * Kept in a MDLL, sorted by @e timeout.
1227 struct DistanceVectorHop *prev_dv;
1232 struct DistanceVectorHop *next_neighbour;
1237 struct DistanceVectorHop *prev_neighbour;
1240 * Head of MDLL of messages routed via this path.
1242 struct PendingMessage *pending_msg_head;
1245 * Tail of MDLL of messages routed via this path.
1247 struct PendingMessage *pending_msg_tail;
1250 * Head of DLL of PAs that used our @a path.
1252 struct PendingAcknowledgement *pa_head;
1255 * Tail of DLL of PAs that used our @a path.
1257 struct PendingAcknowledgement *pa_tail;
1260 * What would be the next hop to @e target?
1262 struct Neighbour *next_hop;
1265 * Distance vector entry this hop belongs with.
1267 struct DistanceVector *dv;
1270 * Array of @e distance hops to the target, excluding @e next_hop.
1271 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1272 * at the end of this struct. Excludes the target itself!
1274 const struct GNUNET_PeerIdentity *path;
1277 * At what time do we forget about this path unless we see it again
1280 struct GNUNET_TIME_Absolute timeout;
1283 * For how long is the validation of this path considered
1285 * Set to ZERO if the path is learned by snooping on DV learn messages
1286 * initiated by other peers, and to the time at which we generated the
1287 * challenge for DV learn operations this peer initiated.
1289 struct GNUNET_TIME_Absolute path_valid_until;
1292 * Performance data for this transmission possibility.
1294 struct PerformanceData pd;
1297 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1298 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1301 unsigned int distance;
1306 * Entry in our #dv_routes table, representing a (set of) distance
1307 * vector routes to a particular peer.
1309 struct DistanceVector
1313 * To which peer is this a route?
1315 struct GNUNET_PeerIdentity target;
1318 * Known paths to @e target.
1320 struct DistanceVectorHop *dv_head;
1323 * Known paths to @e target.
1325 struct DistanceVectorHop *dv_tail;
1328 * Task scheduled to purge expired paths from @e dv_head MDLL.
1330 struct GNUNET_SCHEDULER_Task *timeout_task;
1333 * Task scheduled to possibly notfiy core that this queue is no longer
1334 * counting as confirmed. Runs the #core_queue_visibility_check().
1336 struct GNUNET_SCHEDULER_Task *visibility_task;
1339 * Quota at which CORE is allowed to transmit to this peer
1340 * (note that the value CORE should actually be told is this
1341 * value plus the respective value in `struct Neighbour`).
1342 * Should match the sum of the quotas of all of the paths.
1344 * FIXME: not yet set, tricky to get right given multiple paths,
1345 * many of which may be inactive! (=> Idea: measure???)
1346 * FIXME: how do we set this value initially when we tell CORE?
1347 * Options: start at a minimum value or at literally zero?
1348 * (=> Current thought: clean would be zero!)
1350 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1353 * Is one of the DV paths in this struct 'confirmed' and thus
1354 * the cause for CORE to see this peer as connected? (Note that
1355 * the same may apply to a `struct Neighbour` at the same time.)
1362 * Entry identifying transmission in one of our `struct
1363 * Queue` which still awaits an ACK. This is used to
1364 * ensure we do not overwhelm a communicator and limit the number of
1365 * messages outstanding per communicator (say in case communicator is
1366 * CPU bound) and per queue (in case bandwidth allocation exceeds
1367 * what the communicator can actually provide towards a particular
1376 struct QueueEntry *next;
1381 struct QueueEntry *prev;
1384 * Queue this entry is queued with.
1386 struct Queue *queue;
1389 * Pending message this entry is for, or NULL for none.
1391 struct PendingMessage *pm;
1394 * Message ID used for this message with the queue used for transmission.
1401 * A queue is a message queue provided by a communicator
1402 * via which we can reach a particular neighbour.
1409 struct Queue *next_neighbour;
1414 struct Queue *prev_neighbour;
1419 struct Queue *prev_client;
1424 struct Queue *next_client;
1427 * Head of DLL of PAs that used this queue.
1429 struct PendingAcknowledgement *pa_head;
1432 * Tail of DLL of PAs that used this queue.
1434 struct PendingAcknowledgement *pa_tail;
1437 * Head of DLL of unacked transmission requests.
1439 struct QueueEntry *queue_head;
1442 * End of DLL of unacked transmission requests.
1444 struct QueueEntry *queue_tail;
1447 * Which neighbour is this queue for?
1449 struct Neighbour *neighbour;
1452 * Which communicator offers this queue?
1454 struct TransportClient *tc;
1457 * Address served by the queue.
1459 const char *address;
1462 * Task scheduled for the time when this queue can (likely) transmit the
1463 * next message. Still needs to check with the @e tracker_out to be sure.
1465 struct GNUNET_SCHEDULER_Task *transmit_task;
1468 * Task scheduled to possibly notfiy core that this queue is no longer
1469 * counting as confirmed. Runs the #core_queue_visibility_check().
1471 struct GNUNET_SCHEDULER_Task *visibility_task;
1474 * How long do *we* consider this @e address to be valid? In the past or
1475 * zero if we have not yet validated it. Can be updated based on
1476 * challenge-response validations (via address validation logic), or when we
1477 * receive ACKs that we can definitively map to transmissions via this
1480 struct GNUNET_TIME_Absolute validated_until;
1483 * Performance data for this queue.
1485 struct PerformanceData pd;
1488 * Message ID generator for transmissions on this queue to the
1494 * Unique identifier of this queue with the communicator.
1499 * Maximum transmission unit supported by this queue.
1506 uint32_t num_msg_pending;
1511 uint32_t num_bytes_pending;
1514 * Length of the DLL starting at @e queue_head.
1516 unsigned int queue_length;
1519 * Network type offered by this queue.
1521 enum GNUNET_NetworkType nt;
1524 * Connection status for this queue.
1526 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1529 * How much outbound bandwidth do we have available for this queue?
1531 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1534 * How much inbound bandwidth do we have available for this queue?
1536 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1541 * Information we keep for a message that we are reassembling.
1543 struct ReassemblyContext
1547 * Original message ID for of the message that all the fragments
1550 struct MessageUUIDP msg_uuid;
1553 * Which neighbour is this context for?
1555 struct Neighbour *neighbour;
1558 * Entry in the reassembly heap (sorted by expiration).
1560 struct GNUNET_CONTAINER_HeapNode *hn;
1563 * Bitfield with @e msg_size bits representing the positions
1564 * where we have received fragments. When we receive a fragment,
1565 * we check the bits in @e bitfield before incrementing @e msg_missing.
1567 * Allocated after the reassembled message.
1572 * Task for sending ACK. We may send ACKs either because of hitting
1573 * the @e extra_acks limit, or based on time and @e num_acks. This
1574 * task is for the latter case.
1576 struct GNUNET_SCHEDULER_Task *ack_task;
1579 * At what time will we give up reassembly of this message?
1581 struct GNUNET_TIME_Absolute reassembly_timeout;
1584 * Time we received the last fragment. @e avg_ack_delay must be
1585 * incremented by now - @e last_frag multiplied by @e num_acks.
1587 struct GNUNET_TIME_Absolute last_frag;
1590 * How big is the message we are reassembling in total?
1595 * How many bytes of the message are still missing? Defragmentation
1596 * is complete when @e msg_missing == 0.
1598 uint16_t msg_missing;
1600 /* Followed by @e msg_size bytes of the (partially) defragmented original
1603 /* Followed by @e bitfield data */
1608 * A neighbour that at least one communicator is connected to.
1614 * Which peer is this about?
1616 struct GNUNET_PeerIdentity pid;
1619 * Map with `struct ReassemblyContext` structs for fragments under
1620 * reassembly. May be NULL if we currently have no fragments from
1621 * this @e pid (lazy initialization).
1623 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1626 * Heap with `struct ReassemblyContext` structs for fragments under
1627 * reassembly. May be NULL if we currently have no fragments from
1628 * this @e pid (lazy initialization).
1630 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1633 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1635 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1638 * Head of list of messages pending for this neighbour.
1640 struct PendingMessage *pending_msg_head;
1643 * Tail of list of messages pending for this neighbour.
1645 struct PendingMessage *pending_msg_tail;
1648 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1649 * purged if this neighbour goes down.
1651 struct DistanceVectorHop *dv_head;
1654 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1655 * purged if this neighbour goes down.
1657 struct DistanceVectorHop *dv_tail;
1660 * Head of DLL of queues to this peer.
1662 struct Queue *queue_head;
1665 * Tail of DLL of queues to this peer.
1667 struct Queue *queue_tail;
1670 * Task run to cleanup pending messages that have exceeded their timeout.
1672 struct GNUNET_SCHEDULER_Task *timeout_task;
1675 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1676 * the PEERSTORE, or NULL.
1678 struct GNUNET_PEERSTORE_IterateContext *get;
1681 * Handle to a PEERSTORE store operation to store this @e pid's @e
1682 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1684 struct GNUNET_PEERSTORE_StoreContext *sc;
1687 * Quota at which CORE is allowed to transmit to this peer
1688 * (note that the value CORE should actually be told is this
1689 * value plus the respective value in `struct DistanceVector`).
1690 * Should match the sum of the quotas of all of the queues.
1692 * FIXME: not yet set, tricky to get right given multiple queues!
1693 * (=> Idea: measure???)
1694 * FIXME: how do we set this value initially when we tell CORE?
1695 * Options: start at a minimum value or at literally zero?
1696 * (=> Current thought: clean would be zero!)
1698 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1701 * Latest DVLearn monotonic time seen from this peer. Initialized only
1702 * if @e dl_monotime_available is #GNUNET_YES.
1704 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1707 * What is the earliest timeout of any message in @e pending_msg_tail?
1709 struct GNUNET_TIME_Absolute earliest_timeout;
1712 * Do we have a confirmed working queue and are thus visible to
1718 * Do we have the lastest value for @e last_dv_learn_monotime from
1719 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1721 int dv_monotime_available;
1726 * A peer that an application (client) would like us to talk to directly.
1732 * Which peer is this about?
1734 struct GNUNET_PeerIdentity pid;
1737 * Client responsible for the request.
1739 struct TransportClient *tc;
1742 * Handle for watching the peerstore for HELLOs for this peer.
1744 struct GNUNET_PEERSTORE_WatchContext *wc;
1747 * What kind of performance preference does this @e tc have?
1749 enum GNUNET_MQ_PreferenceKind pk;
1752 * How much bandwidth would this @e tc like to see?
1754 struct GNUNET_BANDWIDTH_Value32NBO bw;
1759 * Types of different pending messages.
1761 enum PendingMessageType
1765 * Ordinary message received from the CORE service.
1772 PMT_FRAGMENT_BOX = 1,
1777 PMT_RELIABILITY_BOX = 2,
1780 * Any type of acknowledgement.
1782 PMT_ACKNOWLEDGEMENT = 3,
1785 * Control traffic generated by the TRANSPORT service itself.
1793 * Transmission request that is awaiting delivery. The original
1794 * transmission requests from CORE may be too big for some queues.
1795 * In this case, a *tree* of fragments is created. At each
1796 * level of the tree, fragments are kept in a DLL ordered by which
1797 * fragment should be sent next (at the head). The tree is searched
1798 * top-down, with the original message at the root.
1800 * To select a node for transmission, first it is checked if the
1801 * current node's message fits with the MTU. If it does not, we
1802 * either calculate the next fragment (based on @e frag_off) from the
1803 * current node, or, if all fragments have already been created,
1804 * descend to the @e head_frag. Even though the node was already
1805 * fragmented, the fragment may be too big if the fragment was
1806 * generated for a queue with a larger MTU. In this case, the node
1807 * may be fragmented again, thus creating a tree.
1809 * When acknowledgements for fragments are received, the tree
1810 * must be pruned, removing those parts that were already
1811 * acknowledged. When fragments are sent over a reliable
1812 * channel, they can be immediately removed.
1814 * If a message is ever fragmented, then the original "full" message
1815 * is never again transmitted (even if it fits below the MTU), and
1816 * only (remaining) fragments are sent.
1818 struct PendingMessage
1821 * Kept in a MDLL of messages for this @a target.
1823 struct PendingMessage *next_neighbour;
1826 * Kept in a MDLL of messages for this @a target.
1828 struct PendingMessage *prev_neighbour;
1831 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1833 struct PendingMessage *next_client;
1836 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1838 struct PendingMessage *prev_client;
1841 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1842 * #PMT_FRAGMENT_BOx)
1844 struct PendingMessage *next_frag;
1847 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1848 * #PMT_FRAGMENT_BOX)
1850 struct PendingMessage *prev_frag;
1853 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1856 struct PendingMessage *next_dvh;
1859 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1862 struct PendingMessage *prev_dvh;
1865 * Head of DLL of PAs for this pending message.
1867 struct PendingAcknowledgement *pa_head;
1870 * Tail of DLL of PAs for this pending message.
1872 struct PendingAcknowledgement *pa_tail;
1875 * This message, reliability boxed. Only possibly available if @e pmt is
1878 struct PendingMessage *bpm;
1881 * Target of the request (for transmission, may not be ultimate
1884 struct Neighbour *target;
1887 * Distance vector path selected for this message, or
1888 * NULL if transmitted directly.
1890 struct DistanceVectorHop *dvh;
1893 * Set to non-NULL value if this message is currently being given to a
1894 * communicator and we are awaiting that communicator's acknowledgement.
1895 * Note that we must not retransmit a pending message while we're still
1896 * in the process of giving it to a communicator. If a pending message
1897 * is free'd while this entry is non-NULL, the @e qe reference to us
1898 * should simply be set to NULL.
1900 struct QueueEntry *qe;
1903 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1905 struct TransportClient *client;
1908 * Head of a MDLL of fragments created for this core message.
1910 struct PendingMessage *head_frag;
1913 * Tail of a MDLL of fragments created for this core message.
1915 struct PendingMessage *tail_frag;
1918 * Our parent in the fragmentation tree.
1920 struct PendingMessage *frag_parent;
1923 * At what time should we give up on the transmission (and no longer retry)?
1925 struct GNUNET_TIME_Absolute timeout;
1928 * What is the earliest time for us to retry transmission of this message?
1930 struct GNUNET_TIME_Absolute next_attempt;
1933 * UUID to use for this message (used for reassembly of fragments, only
1934 * initialized if @e msg_uuid_set is #GNUNET_YES).
1936 struct MessageUUIDP msg_uuid;
1939 * Type of the pending message.
1941 enum PendingMessageType pmt;
1944 * Size of the original message.
1949 * Offset at which we should generate the next fragment.
1954 * #GNUNET_YES once @e msg_uuid was initialized
1956 int16_t msg_uuid_set;
1958 /* Followed by @e bytes_msg to transmit */
1963 * Acknowledgement payload.
1965 struct TransportCummulativeAckPayload
1968 * When did we receive the message we are ACKing? Used to calculate
1969 * the delay we introduced by cummulating ACKs.
1971 struct GNUNET_TIME_Absolute receive_time;
1974 * UUID of a message being acknowledged.
1976 struct AcknowledgementUUIDP ack_uuid;
1981 * Data structure in which we track acknowledgements still to
1984 struct AcknowledgementCummulator
1987 * Target peer for which we are accumulating ACKs here.
1989 struct GNUNET_PeerIdentity target;
1992 * ACK data being accumulated. Only @e num_acks slots are valid.
1994 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
1997 * Task scheduled either to transmit the cummulative ACK message,
1998 * or to clean up this data structure after extended periods of
1999 * inactivity (if @e num_acks is zero).
2001 struct GNUNET_SCHEDULER_Task *task;
2004 * When is @e task run (only used if @e num_acks is non-zero)?
2006 struct GNUNET_TIME_Absolute min_transmission_time;
2009 * Counter to produce the `ack_counter` in the `struct
2010 * TransportReliabilityAckMessage`. Allows the receiver to detect
2011 * lost ACK messages. Incremented by @e num_acks upon transmission.
2013 uint32_t ack_counter;
2016 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2018 unsigned int num_acks;
2023 * One of the addresses of this peer.
2025 struct AddressListEntry
2031 struct AddressListEntry *next;
2036 struct AddressListEntry *prev;
2039 * Which communicator provides this address?
2041 struct TransportClient *tc;
2044 * The actual address.
2046 const char *address;
2049 * Current context for storing this address in the peerstore.
2051 struct GNUNET_PEERSTORE_StoreContext *sc;
2054 * Task to periodically do @e st operation.
2056 struct GNUNET_SCHEDULER_Task *st;
2059 * What is a typical lifetime the communicator expects this
2060 * address to have? (Always from now.)
2062 struct GNUNET_TIME_Relative expiration;
2065 * Address identifier used by the communicator.
2070 * Network type offered by this address.
2072 enum GNUNET_NetworkType nt;
2077 * Client connected to the transport service.
2079 struct TransportClient
2085 struct TransportClient *next;
2090 struct TransportClient *prev;
2093 * Handle to the client.
2095 struct GNUNET_SERVICE_Client *client;
2098 * Message queue to the client.
2100 struct GNUNET_MQ_Handle *mq;
2103 * What type of client is this?
2105 enum ClientType type;
2111 * Information for @e type #CT_CORE.
2117 * Head of list of messages pending for this client, sorted by
2118 * transmission time ("next_attempt" + possibly internal prioritization).
2120 struct PendingMessage *pending_msg_head;
2123 * Tail of list of messages pending for this client.
2125 struct PendingMessage *pending_msg_tail;
2130 * Information for @e type #CT_MONITOR.
2136 * Peer identity to monitor the addresses of.
2137 * Zero to monitor all neighbours. Valid if
2138 * @e type is #CT_MONITOR.
2140 struct GNUNET_PeerIdentity peer;
2143 * Is this a one-shot monitor?
2151 * Information for @e type #CT_COMMUNICATOR.
2156 * If @e type is #CT_COMMUNICATOR, this communicator
2157 * supports communicating using these addresses.
2159 char *address_prefix;
2162 * Head of DLL of queues offered by this communicator.
2164 struct Queue *queue_head;
2167 * Tail of DLL of queues offered by this communicator.
2169 struct Queue *queue_tail;
2172 * Head of list of the addresses of this peer offered by this
2175 struct AddressListEntry *addr_head;
2178 * Tail of list of the addresses of this peer offered by this
2181 struct AddressListEntry *addr_tail;
2184 * Number of queue entries in all queues to this communicator. Used
2185 * throttle sending to a communicator if we see that the communicator
2186 * is globally unable to keep up.
2188 unsigned int total_queue_length;
2191 * Characteristics of this communicator.
2193 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2198 * Information for @e type #CT_APPLICATION
2204 * Map of requests for peers the given client application would like to
2205 * see connections for. Maps from PIDs to `struct PeerRequest`.
2207 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2216 * State we keep for validation activities. Each of these
2217 * is both in the #validation_heap and the #validation_map.
2219 struct ValidationState
2223 * For which peer is @a address to be validated (or possibly valid)?
2224 * Serves as key in the #validation_map.
2226 struct GNUNET_PeerIdentity pid;
2229 * How long did the peer claim this @e address to be valid? Capped at
2230 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2231 * were told about the address and the value claimed by the other peer at
2232 * that time. May be updated similarly when validation succeeds.
2234 struct GNUNET_TIME_Absolute valid_until;
2237 * How long do *we* consider this @e address to be valid?
2238 * In the past or zero if we have not yet validated it.
2240 struct GNUNET_TIME_Absolute validated_until;
2243 * When did we FIRST use the current @e challenge in a message?
2244 * Used to sanity-check @code{origin_time} in the response when
2245 * calculating the RTT. If the @code{origin_time} is not in
2246 * the expected range, the response is discarded as malicious.
2248 struct GNUNET_TIME_Absolute first_challenge_use;
2251 * When did we LAST use the current @e challenge in a message?
2252 * Used to sanity-check @code{origin_time} in the response when
2253 * calculating the RTT. If the @code{origin_time} is not in
2254 * the expected range, the response is discarded as malicious.
2256 struct GNUNET_TIME_Absolute last_challenge_use;
2259 * Next time we will send the @e challenge to the peer, if this time is past
2260 * @e valid_until, this validation state is released at this time. If the
2261 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2262 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2263 * to re-validate before the validity actually expires.
2265 struct GNUNET_TIME_Absolute next_challenge;
2268 * Current backoff factor we're applying for sending the @a challenge.
2269 * Reset to 0 if the @a challenge is confirmed upon validation.
2270 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2271 * existing value if we receive an unvalidated address again over
2272 * another channel (and thus should consider the information "fresh").
2273 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2275 struct GNUNET_TIME_Relative challenge_backoff;
2278 * Initially set to "forever". Once @e validated_until is set, this value is
2279 * set to the RTT that tells us how long it took to receive the validation.
2281 struct GNUNET_TIME_Relative validation_rtt;
2284 * The challenge we sent to the peer to get it to validate the address. Note
2285 * that we rotate the challenge whenever we update @e validated_until to
2286 * avoid attacks where a peer simply replays an old challenge in the future.
2287 * (We must not rotate more often as otherwise we may discard valid answers
2288 * due to packet losses, latency and reorderings on the network).
2290 struct ChallengeNonceP challenge;
2293 * Claimed address of the peer.
2298 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2299 * heap is used to figure out when the next validation activity should be
2302 struct GNUNET_CONTAINER_HeapNode *hn;
2305 * Handle to a PEERSTORE store operation for this @e address. NULL if
2306 * no PEERSTORE operation is pending.
2308 struct GNUNET_PEERSTORE_StoreContext *sc;
2311 * We are technically ready to send the challenge, but we are waiting for
2312 * the respective queue to become available for transmission.
2319 * A Backtalker is a peer sending us backchannel messages. We use this
2320 * struct to detect monotonic time violations, cache ephemeral key
2321 * material (to avoid repeatedly checking signatures), and to synchronize
2322 * monotonic time with the PEERSTORE.
2327 * Peer this is about.
2329 struct GNUNET_PeerIdentity pid;
2332 * Last (valid) monotonic time received from this sender.
2334 struct GNUNET_TIME_Absolute monotonic_time;
2337 * When will this entry time out?
2339 struct GNUNET_TIME_Absolute timeout;
2342 * Last (valid) ephemeral key received from this sender.
2344 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2347 * Task associated with this backtalker. Can be for timeout,
2348 * or other asynchronous operations.
2350 struct GNUNET_SCHEDULER_Task *task;
2353 * Communicator context waiting on this backchannel's @e get, or NULL.
2355 struct CommunicatorMessageContext *cmc;
2358 * Handle for an operation to fetch @e monotonic_time information from the
2359 * PEERSTORE, or NULL.
2361 struct GNUNET_PEERSTORE_IterateContext *get;
2364 * Handle to a PEERSTORE store operation for this @e pid's @e
2365 * monotonic_time. NULL if no PEERSTORE operation is pending.
2367 struct GNUNET_PEERSTORE_StoreContext *sc;
2370 * Number of bytes of the original message body that follows after this
2378 * Head of linked list of all clients to this service.
2380 static struct TransportClient *clients_head;
2383 * Tail of linked list of all clients to this service.
2385 static struct TransportClient *clients_tail;
2388 * Statistics handle.
2390 static struct GNUNET_STATISTICS_Handle *GST_stats;
2393 * Configuration handle.
2395 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2400 static struct GNUNET_PeerIdentity GST_my_identity;
2405 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2408 * Map from PIDs to `struct Neighbour` entries. A peer is
2409 * a neighbour if we have an MQ to it from some communicator.
2411 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2414 * Map from PIDs to `struct Backtalker` entries. A peer is
2415 * a backtalker if it recently send us backchannel messages.
2417 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2420 * Map from PIDs to `struct AcknowledgementCummulator`s.
2421 * Here we track the cummulative ACKs for transmission.
2423 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2426 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2427 * a `struct PendingAcknowledgement`.
2429 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2432 * Map from PIDs to `struct DistanceVector` entries describing
2433 * known paths to the peer.
2435 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2438 * Map from PIDs to `struct ValidationState` entries describing
2439 * addresses we are aware of and their validity state.
2441 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2444 * Map from challenges to `struct LearnLaunchEntry` values.
2446 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2449 * Head of a DLL sorted by launch time.
2451 static struct LearnLaunchEntry *lle_head;
2454 * Tail of a DLL sorted by launch time.
2456 static struct LearnLaunchEntry *lle_tail;
2459 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2460 * sorting addresses we are aware of by when we should next try to (re)validate
2463 static struct GNUNET_CONTAINER_Heap *validation_heap;
2466 * Database for peer's HELLOs.
2468 static struct GNUNET_PEERSTORE_Handle *peerstore;
2471 * Heap sorting `struct EphemeralCacheEntry` by their
2472 * key/signature validity.
2474 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2477 * Hash map for looking up `struct EphemeralCacheEntry`s
2478 * by peer identity. (We may have ephemerals in our
2479 * cache for which we do not have a neighbour entry,
2480 * and similar many neighbours may not need ephemerals,
2481 * so we use a second map.)
2483 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2486 * Task to free expired ephemerals.
2488 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2491 * Task run to initiate DV learning.
2493 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2496 * Task to run address validation.
2498 static struct GNUNET_SCHEDULER_Task *validation_task;
2501 * The most recent PA we have created, head of DLL.
2502 * The length of the DLL is kept in #pa_count.
2504 static struct PendingAcknowledgement *pa_head;
2507 * The oldest PA we have created, tail of DLL.
2508 * The length of the DLL is kept in #pa_count.
2510 static struct PendingAcknowledgement *pa_tail;
2513 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2514 * limit the size of the data structure.
2516 static unsigned int pa_count;
2520 * Get an offset into the transmission history buffer for `struct
2521 * PerformanceData`. Note that the caller must perform the required
2522 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2525 * An 'age' lasts 15 minute slots.
2527 * @return current age of the world
2532 struct GNUNET_TIME_Absolute now;
2534 now = GNUNET_TIME_absolute_get ();
2535 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2540 * Release @a pa data structure.
2542 * @param pa data structure to release
2545 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2547 struct Queue *q = pa->queue;
2548 struct PendingMessage *pm = pa->pm;
2549 struct DistanceVectorHop *dvh = pa->dvh;
2551 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2555 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2560 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2565 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2568 GNUNET_assert (GNUNET_YES ==
2569 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2570 &pa->ack_uuid.value,
2577 * Free cached ephemeral key.
2579 * @param ece cached signature to free
2582 free_ephemeral (struct EphemeralCacheEntry *ece)
2584 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2585 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2591 * Free validation state.
2593 * @param vs validation state to free
2596 free_validation_state (struct ValidationState *vs)
2598 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2599 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2603 GNUNET_PEERSTORE_store_cancel (vs->sc);
2606 GNUNET_free (vs->address);
2612 * Lookup neighbour record for peer @a pid.
2614 * @param pid neighbour to look for
2615 * @return NULL if we do not have this peer as a neighbour
2617 static struct Neighbour *
2618 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2620 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2625 * Details about what to notify monitors about.
2630 * @deprecated To be discussed if we keep these...
2632 struct GNUNET_TIME_Absolute last_validation;
2633 struct GNUNET_TIME_Absolute valid_until;
2634 struct GNUNET_TIME_Absolute next_validation;
2637 * Current round-trip time estimate.
2639 struct GNUNET_TIME_Relative rtt;
2642 * Connection status.
2644 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2649 uint32_t num_msg_pending;
2654 uint32_t num_bytes_pending;
2659 * Free a @dvh. Callers MAY want to check if this was the last path to the
2660 * `target`, and if so call #free_dv_route to also free the associated DV
2661 * entry in #dv_routes (if not, the associated scheduler job should eventually
2664 * @param dvh hop to free
2667 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2669 struct Neighbour *n = dvh->next_hop;
2670 struct DistanceVector *dv = dvh->dv;
2671 struct PendingAcknowledgement *pa;
2672 struct PendingMessage *pm;
2674 while (NULL != (pm = dvh->pending_msg_head))
2676 GNUNET_CONTAINER_MDLL_remove (dvh,
2677 dvh->pending_msg_head,
2678 dvh->pending_msg_tail,
2682 while (NULL != (pa = dvh->pa_head))
2684 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2687 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2688 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2694 * Free entry in #dv_routes. First frees all hops to the target, and
2695 * if there are no entries left, frees @a dv as well.
2697 * @param dv route to free
2700 free_dv_route (struct DistanceVector *dv)
2702 struct DistanceVectorHop *dvh;
2704 while (NULL != (dvh = dv->dv_head))
2705 free_distance_vector_hop (dvh);
2706 if (NULL == dv->dv_head)
2710 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2711 if (NULL != dv->visibility_task)
2712 GNUNET_SCHEDULER_cancel (dv->visibility_task);
2713 if (NULL != dv->timeout_task)
2714 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2721 * Notify monitor @a tc about an event. That @a tc
2722 * cares about the event has already been checked.
2724 * Send @a tc information in @a me about a @a peer's status with
2725 * respect to some @a address to all monitors that care.
2727 * @param tc monitor to inform
2728 * @param peer peer the information is about
2729 * @param address address the information is about
2730 * @param nt network type associated with @a address
2731 * @param me detailed information to transmit
2734 notify_monitor (struct TransportClient *tc,
2735 const struct GNUNET_PeerIdentity *peer,
2736 const char *address,
2737 enum GNUNET_NetworkType nt,
2738 const struct MonitorEvent *me)
2740 struct GNUNET_MQ_Envelope *env;
2741 struct GNUNET_TRANSPORT_MonitorData *md;
2742 size_t addr_len = strlen (address) + 1;
2744 env = GNUNET_MQ_msg_extra (md,
2746 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2747 md->nt = htonl ((uint32_t) nt);
2749 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2750 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2751 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2752 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2753 md->cs = htonl ((uint32_t) me->cs);
2754 md->num_msg_pending = htonl (me->num_msg_pending);
2755 md->num_bytes_pending = htonl (me->num_bytes_pending);
2756 memcpy (&md[1], address, addr_len);
2757 GNUNET_MQ_send (tc->mq, env);
2762 * Send information in @a me about a @a peer's status with respect
2763 * to some @a address to all monitors that care.
2765 * @param peer peer the information is about
2766 * @param address address the information is about
2767 * @param nt network type associated with @a address
2768 * @param me detailed information to transmit
2771 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2772 const char *address,
2773 enum GNUNET_NetworkType nt,
2774 const struct MonitorEvent *me)
2776 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2778 if (CT_MONITOR != tc->type)
2780 if (tc->details.monitor.one_shot)
2782 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2783 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2785 notify_monitor (tc, peer, address, nt, me);
2791 * Called whenever a client connects. Allocates our
2792 * data structures associated with that client.
2794 * @param cls closure, NULL
2795 * @param client identification of the client
2796 * @param mq message queue for the client
2797 * @return our `struct TransportClient`
2800 client_connect_cb (void *cls,
2801 struct GNUNET_SERVICE_Client *client,
2802 struct GNUNET_MQ_Handle *mq)
2804 struct TransportClient *tc;
2807 tc = GNUNET_new (struct TransportClient);
2808 tc->client = client;
2810 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2819 * @param rc data structure to free
2822 free_reassembly_context (struct ReassemblyContext *rc)
2824 struct Neighbour *n = rc->neighbour;
2826 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2827 GNUNET_assert (GNUNET_OK ==
2828 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2836 * Task run to clean up reassembly context of a neighbour that have expired.
2838 * @param cls a `struct Neighbour`
2841 reassembly_cleanup_task (void *cls)
2843 struct Neighbour *n = cls;
2844 struct ReassemblyContext *rc;
2846 n->reassembly_timeout_task = NULL;
2847 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2849 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2852 free_reassembly_context (rc);
2855 GNUNET_assert (NULL == n->reassembly_timeout_task);
2856 n->reassembly_timeout_task =
2857 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2858 &reassembly_cleanup_task,
2866 * function called to #free_reassembly_context().
2870 * @param value a `struct ReassemblyContext` to free
2871 * @return #GNUNET_OK (continue iteration)
2874 free_reassembly_cb (void *cls, uint32_t key, void *value)
2876 struct ReassemblyContext *rc = value;
2880 free_reassembly_context (rc);
2886 * Release memory used by @a neighbour.
2888 * @param neighbour neighbour entry to free
2891 free_neighbour (struct Neighbour *neighbour)
2893 struct DistanceVectorHop *dvh;
2895 GNUNET_assert (NULL == neighbour->queue_head);
2896 GNUNET_assert (GNUNET_YES ==
2897 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2900 if (NULL != neighbour->timeout_task)
2901 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2902 if (NULL != neighbour->reassembly_map)
2904 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2905 &free_reassembly_cb,
2907 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2908 neighbour->reassembly_map = NULL;
2909 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2910 neighbour->reassembly_heap = NULL;
2912 while (NULL != (dvh = neighbour->dv_head))
2914 struct DistanceVector *dv = dvh->dv;
2916 free_distance_vector_hop (dvh);
2917 if (NULL == dv->dv_head)
2920 if (NULL != neighbour->reassembly_timeout_task)
2922 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2923 neighbour->reassembly_timeout_task = NULL;
2925 if (NULL != neighbour->get)
2927 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2928 neighbour->get = NULL;
2930 if (NULL != neighbour->sc)
2932 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2933 neighbour->sc = NULL;
2935 GNUNET_free (neighbour);
2940 * Send message to CORE clients that we lost a connection.
2942 * @param tc client to inform (must be CORE client)
2943 * @param pid peer the connection is for
2944 * @param quota_out current quota for the peer
2947 core_send_connect_info (struct TransportClient *tc,
2948 const struct GNUNET_PeerIdentity *pid,
2949 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2951 struct GNUNET_MQ_Envelope *env;
2952 struct ConnectInfoMessage *cim;
2954 GNUNET_assert (CT_CORE == tc->type);
2955 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2956 cim->quota_out = quota_out;
2958 GNUNET_MQ_send (tc->mq, env);
2963 * Send message to CORE clients that we gained a connection
2965 * @param pid peer the queue was for
2966 * @param quota_out current quota for the peer
2969 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2970 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2972 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2974 if (CT_CORE != tc->type)
2976 core_send_connect_info (tc, pid, quota_out);
2982 * Send message to CORE clients that we lost a connection.
2984 * @param pid peer the connection was for
2987 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2989 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2991 struct GNUNET_MQ_Envelope *env;
2992 struct DisconnectInfoMessage *dim;
2994 if (CT_CORE != tc->type)
2996 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2998 GNUNET_MQ_send (tc->mq, env);
3004 * We believe we are ready to transmit a message on a queue. Double-checks
3005 * with the queue's "tracker_out" and then gives the message to the
3006 * communicator for transmission (updating the tracker, and re-scheduling
3007 * itself if applicable).
3009 * @param cls the `struct Queue` to process transmissions for
3012 transmit_on_queue (void *cls);
3016 * Schedule next run of #transmit_on_queue(). Does NOTHING if
3017 * we should run immediately or if the message queue is empty.
3018 * Test for no task being added AND queue not being empty to
3019 * transmit immediately afterwards! This function must only
3020 * be called if the message queue is non-empty!
3022 * @param queue the queue to do scheduling for
3023 * @param inside_job set to #GNUNET_YES if called from
3024 * #transmit_on_queue() itself and NOT setting
3025 * the task means running immediately
3028 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3030 struct Neighbour *n = queue->neighbour;
3031 struct PendingMessage *pm = n->pending_msg_head;
3032 struct GNUNET_TIME_Relative out_delay;
3035 GNUNET_assert (NULL != pm);
3036 if (queue->tc->details.communicator.total_queue_length >=
3037 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3039 GNUNET_STATISTICS_update (
3041 "# Transmission throttled due to communicator queue limit",
3046 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3048 GNUNET_STATISTICS_update (GST_stats,
3049 "# Transmission throttled due to queue queue limit",
3055 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
3057 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
3058 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
3061 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3062 return; /* we should run immediately! */
3063 /* queue has changed since we were scheduled, reschedule again */
3064 queue->transmit_task =
3065 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3066 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3067 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3068 "Next transmission on queue `%s' in %s (high delay)\n",
3070 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3073 "Next transmission on queue `%s' in %s\n",
3075 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3080 * Check whether the CORE visibility of @a n changed. If so,
3081 * check whether we need to notify CORE.
3083 * @param n neighbour to perform the check for
3086 update_neighbour_core_visibility (struct Neighbour *n);
3092 * @param queue the queue to free
3095 free_queue (struct Queue *queue)
3097 struct Neighbour *neighbour = queue->neighbour;
3098 struct TransportClient *tc = queue->tc;
3099 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3100 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3101 struct QueueEntry *qe;
3103 struct PendingAcknowledgement *pa;
3105 if (NULL != queue->transmit_task)
3107 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3108 queue->transmit_task = NULL;
3110 if (NULL != queue->visibility_task)
3112 GNUNET_SCHEDULER_cancel (queue->visibility_task);
3113 queue->visibility_task = NULL;
3115 while (NULL != (pa = queue->pa_head))
3117 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3121 GNUNET_CONTAINER_MDLL_remove (neighbour,
3122 neighbour->queue_head,
3123 neighbour->queue_tail,
3125 GNUNET_CONTAINER_MDLL_remove (client,
3126 tc->details.communicator.queue_head,
3127 tc->details.communicator.queue_tail,
3129 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3130 tc->details.communicator.total_queue_length);
3131 while (NULL != (qe = queue->queue_head))
3133 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3134 queue->queue_length--;
3135 tc->details.communicator.total_queue_length--;
3138 GNUNET_assert (qe == qe->pm->qe);
3143 GNUNET_assert (0 == queue->queue_length);
3144 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3145 tc->details.communicator.total_queue_length))
3147 /* Communicator dropped below threshold, resume all queues */
3148 GNUNET_STATISTICS_update (
3150 "# Transmission throttled due to communicator queue limit",
3153 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3155 schedule_transmit_on_queue (s, GNUNET_NO);
3157 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3158 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
3159 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
3160 GNUNET_free (queue);
3162 update_neighbour_core_visibility (neighbour);
3163 cores_send_disconnect_info (&neighbour->pid);
3165 if (NULL == neighbour->queue_head)
3167 free_neighbour (neighbour);
3175 * @param ale address list entry to free
3178 free_address_list_entry (struct AddressListEntry *ale)
3180 struct TransportClient *tc = ale->tc;
3182 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3183 tc->details.communicator.addr_tail,
3185 if (NULL != ale->sc)
3187 GNUNET_PEERSTORE_store_cancel (ale->sc);
3190 if (NULL != ale->st)
3192 GNUNET_SCHEDULER_cancel (ale->st);
3200 * Stop the peer request in @a value.
3202 * @param cls a `struct TransportClient` that no longer makes the request
3203 * @param pid the peer's identity
3204 * @param value a `struct PeerRequest`
3205 * @return #GNUNET_YES (always)
3208 stop_peer_request (void *cls,
3209 const struct GNUNET_PeerIdentity *pid,
3212 struct TransportClient *tc = cls;
3213 struct PeerRequest *pr = value;
3215 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3218 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3228 * Called whenever a client is disconnected. Frees our
3229 * resources associated with that client.
3231 * @param cls closure, NULL
3232 * @param client identification of the client
3233 * @param app_ctx our `struct TransportClient`
3236 client_disconnect_cb (void *cls,
3237 struct GNUNET_SERVICE_Client *client,
3240 struct TransportClient *tc = app_ctx;
3244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3245 "Client %p disconnected, cleaning up.\n",
3247 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3253 struct PendingMessage *pm;
3255 while (NULL != (pm = tc->details.core.pending_msg_head))
3257 GNUNET_CONTAINER_MDLL_remove (client,
3258 tc->details.core.pending_msg_head,
3259 tc->details.core.pending_msg_tail,
3267 case CT_COMMUNICATOR: {
3269 struct AddressListEntry *ale;
3271 while (NULL != (q = tc->details.communicator.queue_head))
3273 while (NULL != (ale = tc->details.communicator.addr_head))
3274 free_address_list_entry (ale);
3275 GNUNET_free (tc->details.communicator.address_prefix);
3278 case CT_APPLICATION:
3279 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3282 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3290 * Iterator telling new CORE client about all existing
3291 * connections to peers.
3293 * @param cls the new `struct TransportClient`
3294 * @param pid a connected peer
3295 * @param value the `struct Neighbour` with more information
3296 * @return #GNUNET_OK (continue to iterate)
3299 notify_client_connect_info (void *cls,
3300 const struct GNUNET_PeerIdentity *pid,
3303 struct TransportClient *tc = cls;
3304 struct Neighbour *neighbour = value;
3306 core_send_connect_info (tc, pid, neighbour->quota_out);
3312 * Initialize a "CORE" client. We got a start message from this
3313 * client, so add it to the list of clients for broadcasting of
3316 * @param cls the client
3317 * @param start the start message that was sent
3320 handle_client_start (void *cls, const struct StartMessage *start)
3322 struct TransportClient *tc = cls;
3325 options = ntohl (start->options);
3326 if ((0 != (1 & options)) &&
3327 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3329 /* client thinks this is a different peer, reject */
3331 GNUNET_SERVICE_client_drop (tc->client);
3334 if (CT_NONE != tc->type)
3337 GNUNET_SERVICE_client_drop (tc->client);
3341 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3342 ¬ify_client_connect_info,
3344 GNUNET_SERVICE_client_continue (tc->client);
3349 * Client asked for transmission to a peer. Process the request.
3351 * @param cls the client
3352 * @param obm the send message that was sent
3355 check_client_send (void *cls, const struct OutboundMessage *obm)
3357 struct TransportClient *tc = cls;
3359 const struct GNUNET_MessageHeader *obmm;
3361 if (CT_CORE != tc->type)
3364 return GNUNET_SYSERR;
3366 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3367 if (size < sizeof (struct GNUNET_MessageHeader))
3370 return GNUNET_SYSERR;
3372 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3373 if (size != ntohs (obmm->size))
3376 return GNUNET_SYSERR;
3383 * Free fragment tree below @e root, excluding @e root itself.
3384 * FIXME: this does NOT seem to have the intended semantics
3385 * based on how this is called. Seems we generally DO expect
3386 * @a root to be free'ed itself as well!
3388 * @param root root of the tree to free
3391 free_fragment_tree (struct PendingMessage *root)
3393 struct PendingMessage *frag;
3395 while (NULL != (frag = root->head_frag))
3397 struct PendingAcknowledgement *pa;
3399 free_fragment_tree (frag);
3400 while (NULL != (pa = frag->pa_head))
3402 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3405 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3412 * Release memory associated with @a pm and remove @a pm from associated
3413 * data structures. @a pm must be a top-level pending message and not
3414 * a fragment in the tree. The entire tree is freed (if applicable).
3416 * @param pm the pending message to free
3419 free_pending_message (struct PendingMessage *pm)
3421 struct TransportClient *tc = pm->client;
3422 struct Neighbour *target = pm->target;
3423 struct DistanceVectorHop *dvh = pm->dvh;
3424 struct PendingAcknowledgement *pa;
3428 GNUNET_CONTAINER_MDLL_remove (client,
3429 tc->details.core.pending_msg_head,
3430 tc->details.core.pending_msg_tail,
3435 GNUNET_CONTAINER_MDLL_remove (dvh,
3436 dvh->pending_msg_head,
3437 dvh->pending_msg_tail,
3440 GNUNET_CONTAINER_MDLL_remove (neighbour,
3441 target->pending_msg_head,
3442 target->pending_msg_tail,
3444 while (NULL != (pa = pm->pa_head))
3446 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3450 free_fragment_tree (pm);
3453 GNUNET_assert (pm == pm->qe->pm);
3456 GNUNET_free_non_null (pm->bpm);
3462 * Send a response to the @a pm that we have processed a
3463 * "send" request with status @a success. We
3464 * transmitted @a bytes_physical on the actual wire.
3465 * Sends a confirmation to the "core" client responsible
3466 * for the original request and free's @a pm.
3468 * @param pm handle to the original pending message
3469 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
3470 * for transmission failure
3471 * @param bytes_physical amount of bandwidth consumed
3474 client_send_response (struct PendingMessage *pm,
3476 uint32_t bytes_physical)
3478 struct TransportClient *tc = pm->client;
3479 struct Neighbour *target = pm->target;
3480 struct GNUNET_MQ_Envelope *env;
3481 struct SendOkMessage *som;
3485 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3486 som->success = htonl ((uint32_t) success);
3487 som->bytes_msg = htons (pm->bytes_msg);
3488 som->bytes_physical = htonl (bytes_physical);
3489 som->peer = target->pid;
3490 GNUNET_MQ_send (tc->mq, env);
3492 free_pending_message (pm);
3497 * Checks the message queue for a neighbour for messages that have timed
3498 * out and purges them.
3500 * @param cls a `struct Neighbour`
3503 check_queue_timeouts (void *cls)
3505 struct Neighbour *n = cls;
3506 struct PendingMessage *pm;
3507 struct GNUNET_TIME_Absolute now;
3508 struct GNUNET_TIME_Absolute earliest_timeout;
3510 n->timeout_task = NULL;
3511 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
3512 now = GNUNET_TIME_absolute_get ();
3513 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
3515 pm = pos->next_neighbour;
3516 if (pos->timeout.abs_value_us <= now.abs_value_us)
3518 GNUNET_STATISTICS_update (GST_stats,
3519 "# messages dropped (timeout before confirmation)",
3522 client_send_response (pm, GNUNET_NO, 0);
3526 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
3528 n->earliest_timeout = earliest_timeout;
3529 if (NULL != n->pending_msg_head)
3531 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
3536 * Create a DV Box message.
3538 * @param total_hops how many hops did the message take so far
3539 * @param num_hops length of the @a hops array
3540 * @param origin origin of the message
3541 * @param hops next peer(s) to the destination, including destination
3542 * @param payload payload of the box
3543 * @param payload_size number of bytes in @a payload
3544 * @return boxed message (caller must #GNUNET_free() it).
3546 static struct TransportDVBoxMessage *
3547 create_dv_box (uint16_t total_hops,
3548 const struct GNUNET_PeerIdentity *origin,
3549 const struct GNUNET_PeerIdentity *target,
3551 const struct GNUNET_PeerIdentity *hops,
3552 const void *payload,
3553 uint16_t payload_size)
3555 struct TransportDVBoxMessage *dvb;
3556 struct GNUNET_PeerIdentity *dhops;
3558 GNUNET_assert (UINT16_MAX <
3559 sizeof (struct TransportDVBoxMessage) +
3560 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3562 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3563 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3566 htons (sizeof (struct TransportDVBoxMessage) +
3567 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3568 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3569 dvb->total_hops = htons (total_hops);
3570 dvb->num_hops = htons (num_hops + 1);
3571 dvb->origin = *origin;
3572 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3573 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3574 dhops[num_hops] = *target;
3575 memcpy (&dhops[num_hops + 1], payload, payload_size);
3581 * Pick @a hops_array_length random DV paths satisfying @a options
3583 * @param dv data structure to pick paths from
3584 * @param options constraints to satisfy
3585 * @param hops_array[out] set to the result
3586 * @param hops_array_length length of the @a hops_array
3587 * @return number of entries set in @a hops_array
3590 pick_random_dv_hops (const struct DistanceVector *dv,
3591 enum RouteMessageOptions options,
3592 struct DistanceVectorHop **hops_array,
3593 unsigned int hops_array_length)
3595 uint64_t choices[hops_array_length];
3597 unsigned int dv_count;
3599 /* Pick random vectors, but weighted by distance, giving more weight
3600 to shorter vectors */
3603 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3606 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3607 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3608 .rel_value_us == 0))
3609 continue; /* pos unconfirmed and confirmed required */
3610 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3615 if (dv_count <= hops_array_length)
3618 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3620 hops_array[dv_count++] = pos;
3623 for (unsigned int i = 0; i < hops_array_length; i++)
3626 while (GNUNET_NO == ok)
3629 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3631 for (unsigned int j = 0; j < i; j++)
3632 if (choices[i] == choices[j])
3641 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3644 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3646 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3647 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3648 .rel_value_us == 0))
3649 continue; /* pos unconfirmed and confirmed required */
3650 for (unsigned int i = 0; i < hops_array_length; i++)
3651 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3652 hops_array[dv_count++] = pos;
3660 * Client asked for transmission to a peer. Process the request.
3662 * @param cls the client
3663 * @param obm the send message that was sent
3666 handle_client_send (void *cls, const struct OutboundMessage *obm)
3668 struct TransportClient *tc = cls;
3669 struct PendingMessage *pm;
3670 const struct GNUNET_MessageHeader *obmm;
3671 struct Neighbour *target;
3672 struct DistanceVector *dv;
3673 struct DistanceVectorHop *dvh;
3676 const void *payload;
3677 size_t payload_size;
3678 struct TransportDVBoxMessage *dvb;
3680 GNUNET_assert (CT_CORE == tc->type);
3681 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3682 bytes_msg = ntohs (obmm->size);
3683 target = lookup_neighbour (&obm->peer);
3685 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3688 if ((NULL == target) && ((NULL == dv) || (GNUNET_NO == dv->core_visible)))
3690 /* Failure: don't have this peer as a neighbour (anymore).
3691 Might have gone down asynchronously, so this is NOT
3692 a protocol violation by CORE. Still count the event,
3693 as this should be rare. */
3694 struct GNUNET_MQ_Envelope *env;
3695 struct SendOkMessage *som;
3697 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3698 som->success = htonl (GNUNET_SYSERR);
3699 som->bytes_msg = htonl (bytes_msg);
3700 som->bytes_physical = htonl (0);
3701 som->peer = obm->peer;
3702 GNUNET_MQ_send (tc->mq, env);
3703 GNUNET_SERVICE_client_continue (tc->client);
3704 GNUNET_STATISTICS_update (GST_stats,
3705 "# messages dropped (neighbour unknown)",
3713 struct DistanceVectorHop *dvh;
3715 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3716 GNUNET_assert (1 == res);
3717 target = dvh->next_hop;
3718 dvb = create_dv_box (0,
3726 payload_size = ntohs (dvb->header.size);
3733 payload_size = bytes_msg;
3736 was_empty = (NULL == target->pending_msg_head);
3737 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3739 pm->target = target;
3740 pm->bytes_msg = payload_size;
3742 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
3743 memcpy (&pm[1], payload, payload_size);
3744 GNUNET_free_non_null (dvb);
3749 GNUNET_CONTAINER_MDLL_insert (dvh,
3750 dvh->pending_msg_head,
3751 dvh->pending_msg_tail,
3754 GNUNET_CONTAINER_MDLL_insert (neighbour,
3755 target->pending_msg_head,
3756 target->pending_msg_tail,
3758 GNUNET_CONTAINER_MDLL_insert (client,
3759 tc->details.core.pending_msg_head,
3760 tc->details.core.pending_msg_tail,
3762 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3764 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3765 if (NULL != target->timeout_task)
3766 GNUNET_SCHEDULER_cancel (target->timeout_task);
3767 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3768 &check_queue_timeouts,
3772 return; /* all queues must already be busy */
3773 for (struct Queue *queue = target->queue_head; NULL != queue;
3774 queue = queue->next_neighbour)
3776 /* try transmission on any queue that is idle */
3777 if (NULL == queue->transmit_task)
3778 queue->transmit_task =
3779 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3785 * Communicator started. Test message is well-formed.
3787 * @param cls the client
3788 * @param cam the send message that was sent
3791 check_communicator_available (
3793 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3795 struct TransportClient *tc = cls;
3798 if (CT_NONE != tc->type)
3801 return GNUNET_SYSERR;
3803 tc->type = CT_COMMUNICATOR;
3804 size = ntohs (cam->header.size) - sizeof (*cam);
3806 return GNUNET_OK; /* receive-only communicator */
3807 GNUNET_MQ_check_zero_termination (cam);
3813 * Communicator started. Process the request.
3815 * @param cls the client
3816 * @param cam the send message that was sent
3819 handle_communicator_available (
3821 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3823 struct TransportClient *tc = cls;
3826 size = ntohs (cam->header.size) - sizeof (*cam);
3828 return; /* receive-only communicator */
3829 tc->details.communicator.address_prefix =
3830 GNUNET_strdup ((const char *) &cam[1]);
3831 tc->details.communicator.cc =
3832 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3833 GNUNET_SERVICE_client_continue (tc->client);
3838 * Communicator requests backchannel transmission. Check the request.
3840 * @param cls the client
3841 * @param cb the send message that was sent
3842 * @return #GNUNET_OK if message is well-formed
3845 check_communicator_backchannel (
3847 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3849 const struct GNUNET_MessageHeader *inbox;
3855 msize = ntohs (cb->header.size) - sizeof (*cb);
3856 if (((size_t) (UINT16_MAX - msize)) >
3857 sizeof (struct TransportBackchannelEncapsulationMessage) +
3858 sizeof (struct TransportBackchannelRequestPayloadP))
3861 return GNUNET_SYSERR;
3863 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3864 isize = ntohs (inbox->size);
3868 return GNUNET_SYSERR;
3870 is = (const char *) inbox;
3873 GNUNET_assert (msize > 0);
3874 if ('\0' != is[msize - 1])
3877 return GNUNET_SYSERR;
3884 * Remove memory used by expired ephemeral keys.
3889 expire_ephemerals (void *cls)
3891 struct EphemeralCacheEntry *ece;
3894 ephemeral_task = NULL;
3895 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3897 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3900 free_ephemeral (ece);
3903 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3912 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3913 * one, cache it and return it.
3915 * @param pid peer to look up ephemeral for
3916 * @param private_key[out] set to the private key
3917 * @param ephemeral_key[out] set to the key
3918 * @param ephemeral_sender_sig[out] set to the signature
3919 * @param ephemeral_validity[out] set to the validity expiration time
3922 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3923 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3924 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3925 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3926 struct GNUNET_TIME_Absolute *ephemeral_validity)
3928 struct EphemeralCacheEntry *ece;
3929 struct EphemeralConfirmationPS ec;
3931 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3932 if ((NULL != ece) &&
3933 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3936 free_ephemeral (ece);
3941 ece = GNUNET_new (struct EphemeralCacheEntry);
3943 ece->ephemeral_validity =
3944 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3945 EPHEMERAL_VALIDITY);
3946 GNUNET_assert (GNUNET_OK ==
3947 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3948 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3949 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3950 ec.purpose.size = htonl (sizeof (ec));
3952 ec.ephemeral_key = ece->ephemeral_key;
3953 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3957 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3959 ece->ephemeral_validity.abs_value_us);
3960 GNUNET_assert (GNUNET_OK ==
3961 GNUNET_CONTAINER_multipeermap_put (
3965 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3966 if (NULL == ephemeral_task)
3967 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3971 *private_key = ece->private_key;
3972 *ephemeral_key = ece->ephemeral_key;
3973 *ephemeral_sender_sig = ece->sender_sig;
3974 *ephemeral_validity = ece->ephemeral_validity;
3979 * Send the control message @a payload on @a queue.
3981 * @param queue the queue to use for transmission
3982 * @param pm pending message to update once transmission is done, may be NULL!
3983 * @param payload the payload to send (encapsulated in a
3984 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3985 * @param payload_size number of bytes in @a payload
3988 queue_send_msg (struct Queue *queue,
3989 struct PendingMessage *pm,
3990 const void *payload,
3991 size_t payload_size)
3993 struct Neighbour *n = queue->neighbour;
3994 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3995 struct GNUNET_MQ_Envelope *env;
3997 env = GNUNET_MQ_msg_extra (smt,
3999 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4000 smt->qid = queue->qid;
4001 smt->mid = queue->mid_gen;
4002 smt->receiver = n->pid;
4003 memcpy (&smt[1], payload, payload_size);
4005 /* Pass the env to the communicator of queue for transmission. */
4006 struct QueueEntry *qe;
4008 qe = GNUNET_new (struct QueueEntry);
4009 qe->mid = queue->mid_gen++;
4014 GNUNET_assert (NULL == pm->qe);
4017 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4018 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4019 queue->queue_length++;
4020 queue->tc->details.communicator.total_queue_length++;
4021 GNUNET_MQ_send (queue->tc->mq, env);
4027 * Pick a queue of @a n under constraints @a options and schedule
4028 * transmission of @a hdr.
4030 * @param n neighbour to send to
4031 * @param hdr message to send as payload
4032 * @param options whether queues must be confirmed or not,
4033 * and whether we may pick multiple (2) queues
4036 route_via_neighbour (const struct Neighbour *n,
4037 const struct GNUNET_MessageHeader *hdr,
4038 enum RouteMessageOptions options)
4040 struct GNUNET_TIME_Absolute now;
4041 unsigned int candidates;
4045 /* Pick one or two 'random' queues from n (under constraints of options) */
4046 now = GNUNET_TIME_absolute_get ();
4047 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4048 weight in the future; weight could be assigned by observed
4049 bandwidth (note: not sure if we should do this for this type
4050 of control traffic though). */
4052 for (struct Queue *pos = n->queue_head; NULL != pos;
4053 pos = pos->next_neighbour)
4055 /* Count the queue with the visibility task in all cases, as
4056 otherwise we may end up with no queues just because the
4057 time for the visibility task just expired but the scheduler
4058 just ran this task first */
4059 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4060 (pos->validated_until.abs_value_us > now.abs_value_us) ||
4061 (NULL != pos->visibility_task))
4064 if (0 == candidates)
4066 /* Given that we above check for pos->visibility task,
4067 this should be strictly impossible. */
4071 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4072 if (0 == (options & RMO_REDUNDANT))
4073 sel2 = candidates; /* picks none! */
4075 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4077 for (struct Queue *pos = n->queue_head; NULL != pos;
4078 pos = pos->next_neighbour)
4080 /* Count the queue with the visibility task in all cases, as
4081 otherwise we may end up with no queues just because the
4082 time for the visibility task just expired but the scheduler
4083 just ran this task first */
4084 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
4085 (NULL != pos->visibility_task))
4087 if ((sel1 == candidates) || (sel2 == candidates))
4088 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4096 * Given a distance vector path @a dvh route @a payload to
4097 * the ultimate destination respecting @a options.
4098 * Sets up the boxed message and queues it at the next hop.
4100 * @param dvh choice of the path for the message
4101 * @param payload body to transmit
4102 * @param options options to use for control
4105 forward_via_dvh (const struct DistanceVectorHop *dvh,
4106 const struct GNUNET_MessageHeader *payload,
4107 enum RouteMessageOptions options)
4109 struct TransportDVBoxMessage *dvb;
4111 dvb = create_dv_box (0,
4117 ntohs (payload->size));
4118 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4124 * Pick a path of @a dv under constraints @a options and schedule
4125 * transmission of @a hdr.
4127 * @param n neighbour to send to
4128 * @param hdr message to send as payload
4129 * @param options whether path must be confirmed or not
4130 * and whether we may pick multiple (2) paths
4133 route_via_dv (const struct DistanceVector *dv,
4134 const struct GNUNET_MessageHeader *hdr,
4135 enum RouteMessageOptions options)
4137 struct DistanceVectorHop *hops[2];
4140 res = pick_random_dv_hops (dv,
4143 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4144 for (unsigned int i = 0; i < res; i++)
4145 forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT));
4150 * We need to transmit @a hdr to @a target. If necessary, this may
4151 * involve DV routing.
4153 * @param target peer to receive @a hdr
4154 * @param hdr header of the message to route and #GNUNET_free()
4155 * @param options which transmission channels are allowed
4158 route_message (const struct GNUNET_PeerIdentity *target,
4159 struct GNUNET_MessageHeader *hdr,
4160 enum RouteMessageOptions options)
4162 struct Neighbour *n;
4163 struct DistanceVector *dv;
4165 n = lookup_neighbour (target);
4166 dv = (0 != (options & RMO_DV_ALLOWED))
4167 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
4169 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4171 /* if confirmed is required, and we do not have anything
4172 confirmed, drop respective options */
4173 if ((NULL != n) && (GNUNET_NO == n->core_visible))
4175 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
4178 if ((NULL == n) && (NULL == dv))
4180 GNUNET_STATISTICS_update (GST_stats,
4181 "# Messages dropped in routing: no acceptable method",
4187 /* If both dv and n are possible and we must choose:
4188 flip a coin for the choice between the two; for now 50/50 */
4189 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4191 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4196 if ((NULL != n) && (NULL != dv))
4197 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4198 enough for redunancy, so clear the flag. */
4201 route_via_neighbour (n, hdr, options);
4205 route_via_dv (dv, hdr, options);
4212 * Structure of the key material used to encrypt backchannel messages.
4214 struct BackchannelKeyState
4217 * State of our block cipher.
4219 gcry_cipher_hd_t cipher;
4222 * Actual key material.
4228 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4230 struct GNUNET_CRYPTO_AuthKey hmac_key;
4233 * Symmetric key to use for encryption.
4235 char aes_key[256 / 8];
4238 * Counter value to use during setup.
4240 char aes_ctr[128 / 8];
4247 * Given the key material in @a km and the initialization vector
4248 * @a iv, setup the key material for the backchannel in @a key.
4250 * @param km raw master secret
4251 * @param iv initialization vector
4252 * @param key[out] symmetric cipher and HMAC state to generate
4255 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4256 const struct GNUNET_ShortHashCode *iv,
4257 struct BackchannelKeyState *key)
4259 /* must match #dh_key_derive_eph_pub */
4260 GNUNET_assert (GNUNET_YES ==
4261 GNUNET_CRYPTO_kdf (&key->material,
4262 sizeof (key->material),
4263 "transport-backchannel-key",
4264 strlen ("transport-backchannel-key"),
4269 gcry_cipher_open (&key->cipher,
4270 GCRY_CIPHER_AES256 /* low level: go for speed */,
4271 GCRY_CIPHER_MODE_CTR,
4273 gcry_cipher_setkey (key->cipher,
4274 &key->material.aes_key,
4275 sizeof (key->material.aes_key));
4276 gcry_cipher_setctr (key->cipher,
4277 &key->material.aes_ctr,
4278 sizeof (key->material.aes_ctr));
4283 * Derive backchannel encryption key material from @a priv_ephemeral
4284 * and @a target and @a iv.
4286 * @param priv_ephemeral ephemeral private key to use
4287 * @param target the target peer to encrypt to
4288 * @param iv unique IV to use
4289 * @param key[out] set to the key material
4292 dh_key_derive_eph_pid (
4293 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4294 const struct GNUNET_PeerIdentity *target,
4295 const struct GNUNET_ShortHashCode *iv,
4296 struct BackchannelKeyState *key)
4298 struct GNUNET_HashCode km;
4300 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4301 &target->public_key,
4303 bc_setup_key_state_from_km (&km, iv, key);
4308 * Derive backchannel encryption key material from #GST_my_private_key
4309 * and @a pub_ephemeral and @a iv.
4311 * @param priv_ephemeral ephemeral private key to use
4312 * @param target the target peer to encrypt to
4313 * @param iv unique IV to use
4314 * @param key[out] set to the key material
4317 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4318 const struct GNUNET_ShortHashCode *iv,
4319 struct BackchannelKeyState *key)
4321 struct GNUNET_HashCode km;
4323 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4326 bc_setup_key_state_from_km (&km, iv, key);
4331 * Do HMAC calculation for backchannel messages over @a data using key
4332 * material from @a key.
4334 * @param key key material (from DH)
4335 * @param hmac[out] set to the HMAC
4336 * @param data data to perform HMAC calculation over
4337 * @param data_size number of bytes in @a data
4340 bc_hmac (const struct BackchannelKeyState *key,
4341 struct GNUNET_HashCode *hmac,
4345 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4350 * Perform backchannel encryption using symmetric secret in @a key
4351 * to encrypt data from @a in to @a dst.
4353 * @param key[in,out] key material to use
4354 * @param dst where to write the result
4355 * @param in input data to encrypt (plaintext)
4356 * @param in_size number of bytes of input in @a in and available at @a dst
4359 bc_encrypt (struct BackchannelKeyState *key,
4365 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4370 * Perform backchannel encryption using symmetric secret in @a key
4371 * to encrypt data from @a in to @a dst.
4373 * @param key[in,out] key material to use
4374 * @param ciph cipher text to decrypt
4375 * @param out[out] output data to generate (plaintext)
4376 * @param out_size number of bytes of input in @a ciph and available in @a out
4379 bc_decrypt (struct BackchannelKeyState *key,
4385 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4390 * Clean up key material in @a key.
4392 * @param key key material to clean up (memory must not be free'd!)
4395 bc_key_clean (struct BackchannelKeyState *key)
4397 gcry_cipher_close (key->cipher);
4398 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4403 * Communicator requests backchannel transmission. Process the request.
4405 * @param cls the client
4406 * @param cb the send message that was sent
4409 handle_communicator_backchannel (
4411 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4413 struct TransportClient *tc = cls;
4414 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4415 struct GNUNET_TIME_Absolute ephemeral_validity;
4416 struct TransportBackchannelEncapsulationMessage *enc;
4417 struct TransportBackchannelRequestPayloadP ppay;
4418 struct BackchannelKeyState key;
4422 /* encapsulate and encrypt message */
4423 msize = ntohs (cb->header.size) - sizeof (*cb) +
4424 sizeof (struct TransportBackchannelRequestPayloadP);
4425 enc = GNUNET_malloc (sizeof (*enc) + msize);
4427 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4428 enc->header.size = htons (sizeof (*enc) + msize);
4429 enc->target = cb->pid;
4430 lookup_ephemeral (&cb->pid,
4432 &enc->ephemeral_key,
4434 &ephemeral_validity);
4435 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4438 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4439 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
4440 ppay.monotonic_time =
4441 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
4442 mpos = (char *) &enc[1];
4443 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4446 &mpos[sizeof (ppay)],
4447 ntohs (cb->header.size) - sizeof (*cb));
4451 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4452 bc_key_clean (&key);
4453 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4454 GNUNET_SERVICE_client_continue (tc->client);
4459 * Address of our peer added. Test message is well-formed.
4461 * @param cls the client
4462 * @param aam the send message that was sent
4463 * @return #GNUNET_OK if message is well-formed
4466 check_add_address (void *cls,
4467 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4469 struct TransportClient *tc = cls;
4471 if (CT_COMMUNICATOR != tc->type)
4474 return GNUNET_SYSERR;
4476 GNUNET_MQ_check_zero_termination (aam);
4482 * Ask peerstore to store our address.
4484 * @param cls an `struct AddressListEntry *`
4487 store_pi (void *cls);
4491 * Function called when peerstore is done storing our address.
4493 * @param cls a `struct AddressListEntry`
4494 * @param success #GNUNET_YES if peerstore was successful
4497 peerstore_store_own_cb (void *cls, int success)
4499 struct AddressListEntry *ale = cls;
4502 if (GNUNET_YES != success)
4503 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4504 "Failed to store our own address `%s' in peerstore!\n",
4506 /* refresh period is 1/4 of expiration time, that should be plenty
4507 without being excessive. */
4509 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4517 * Ask peerstore to store our address.
4519 * @param cls an `struct AddressListEntry *`
4522 store_pi (void *cls)
4524 struct AddressListEntry *ale = cls;
4527 struct GNUNET_TIME_Absolute expiration;
4530 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4531 GNUNET_HELLO_sign_address (ale->address,
4537 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4540 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4544 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4545 &peerstore_store_own_cb,
4548 if (NULL == ale->sc)
4550 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4551 "Failed to store our address `%s' with peerstore\n",
4554 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4560 * Address of our peer added. Process the request.
4562 * @param cls the client
4563 * @param aam the send message that was sent
4566 handle_add_address (void *cls,
4567 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4569 struct TransportClient *tc = cls;
4570 struct AddressListEntry *ale;
4573 slen = ntohs (aam->header.size) - sizeof (*aam);
4574 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4576 ale->address = (const char *) &ale[1];
4577 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4578 ale->aid = aam->aid;
4579 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4580 memcpy (&ale[1], &aam[1], slen);
4581 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4582 tc->details.communicator.addr_tail,
4584 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4585 GNUNET_SERVICE_client_continue (tc->client);
4590 * Address of our peer deleted. Process the request.
4592 * @param cls the client
4593 * @param dam the send message that was sent
4596 handle_del_address (void *cls,
4597 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4599 struct TransportClient *tc = cls;
4601 if (CT_COMMUNICATOR != tc->type)
4604 GNUNET_SERVICE_client_drop (tc->client);
4607 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4611 if (dam->aid != ale->aid)
4613 GNUNET_assert (ale->tc == tc);
4614 free_address_list_entry (ale);
4615 GNUNET_SERVICE_client_continue (tc->client);
4618 GNUNET_SERVICE_client_drop (tc->client);
4623 * Context from #handle_incoming_msg(). Closure for many
4624 * message handlers below.
4626 struct CommunicatorMessageContext
4629 * Which communicator provided us with the message.
4631 struct TransportClient *tc;
4634 * Additional information for flow control and about the sender.
4636 struct GNUNET_TRANSPORT_IncomingMessage im;
4639 * Number of hops the message has travelled (if DV-routed).
4640 * FIXME: make use of this in ACK handling!
4642 uint16_t total_hops;
4647 * Given an inbound message @a msg from a communicator @a cmc,
4648 * demultiplex it based on the type calling the right handler.
4650 * @param cmc context for demultiplexing
4651 * @param msg message to demultiplex
4654 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4655 const struct GNUNET_MessageHeader *msg);
4659 * Send ACK to communicator (if requested) and free @a cmc.
4661 * @param cmc context for which we are done handling the message
4664 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4666 if (0 != ntohl (cmc->im.fc_on))
4668 /* send ACK when done to communicator for flow control! */
4669 struct GNUNET_MQ_Envelope *env;
4670 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4672 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4673 ack->reserved = htonl (0);
4674 ack->fc_id = cmc->im.fc_id;
4675 ack->sender = cmc->im.sender;
4676 GNUNET_MQ_send (cmc->tc->mq, env);
4678 GNUNET_SERVICE_client_continue (cmc->tc->client);
4684 * Communicator gave us an unencapsulated message to pass as-is to
4685 * CORE. Process the request.
4687 * @param cls a `struct CommunicatorMessageContext` (must call
4688 * #finish_cmc_handling() when done)
4689 * @param mh the message that was received
4692 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4694 struct CommunicatorMessageContext *cmc = cls;
4695 uint16_t size = ntohs (mh->size);
4697 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4698 (size < sizeof (struct GNUNET_MessageHeader)))
4700 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4703 finish_cmc_handling (cmc);
4704 GNUNET_SERVICE_client_drop (client);
4707 /* Forward to all CORE clients */
4708 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4710 struct GNUNET_MQ_Envelope *env;
4711 struct InboundMessage *im;
4713 if (CT_CORE != tc->type)
4715 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4716 im->peer = cmc->im.sender;
4717 memcpy (&im[1], mh, size);
4718 GNUNET_MQ_send (tc->mq, env);
4720 /* FIXME: consider doing this _only_ once the message
4721 was drained from the CORE MQs to extend flow control to CORE!
4722 (basically, increment counter in cmc, decrement on MQ send continuation! */
4723 finish_cmc_handling (cmc);
4728 * Communicator gave us a fragment box. Check the message.
4730 * @param cls a `struct CommunicatorMessageContext`
4731 * @param fb the send message that was sent
4732 * @return #GNUNET_YES if message is well-formed
4735 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4737 uint16_t size = ntohs (fb->header.size);
4738 uint16_t bsize = size - sizeof (*fb);
4743 GNUNET_break_op (0);
4744 return GNUNET_SYSERR;
4746 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4748 GNUNET_break_op (0);
4749 return GNUNET_SYSERR;
4751 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4753 GNUNET_break_op (0);
4754 return GNUNET_SYSERR;
4761 * Clean up an idle cummulative acknowledgement data structure.
4763 * @param cls a `struct AcknowledgementCummulator *`
4766 destroy_ack_cummulator (void *cls)
4768 struct AcknowledgementCummulator *ac = cls;
4771 GNUNET_assert (0 == ac->num_acks);
4774 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4780 * Do the transmission of a cummulative acknowledgement now.
4782 * @param cls a `struct AcknowledgementCummulator *`
4785 transmit_cummulative_ack_cb (void *cls)
4787 struct AcknowledgementCummulator *ac = cls;
4788 struct TransportReliabilityAckMessage *ack;
4789 struct TransportCummulativeAckPayloadP *ap;
4792 GNUNET_assert (0 < ac->ack_counter);
4793 ack = GNUNET_malloc (sizeof (*ack) +
4795 sizeof (struct TransportCummulativeAckPayloadP));
4796 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4798 htons (sizeof (*ack) +
4799 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4800 ack->ack_counter = htonl (ac->ack_counter++);
4801 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4802 for (unsigned int i = 0; i < ac->ack_counter; i++)
4804 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4805 ap[i].ack_delay = GNUNET_TIME_relative_hton (
4806 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
4808 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
4810 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
4811 &destroy_ack_cummulator,
4817 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
4818 * transmission by at most @a ack_delay.
4820 * @param pid target peer
4821 * @param ack_uuid UUID to ack
4822 * @param max_delay how long can the ACK wait
4825 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
4826 const struct AcknowledgementUUIDP *ack_uuid,
4827 struct GNUNET_TIME_Absolute max_delay)
4829 struct AcknowledgementCummulator *ac;
4831 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
4834 ac = GNUNET_new (struct AcknowledgementCummulator);
4836 ac->min_transmission_time = max_delay;
4837 GNUNET_assert (GNUNET_YES ==
4838 GNUNET_CONTAINER_multipeermap_put (
4842 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4846 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
4848 /* must run immediately, ack buffer full! */
4849 GNUNET_SCHEDULER_cancel (ac->task);
4850 transmit_cummulative_ack_cb (ac);
4852 GNUNET_SCHEDULER_cancel (ac->task);
4853 ac->min_transmission_time =
4854 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
4856 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
4857 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
4858 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
4860 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
4861 &transmit_cummulative_ack_cb,
4867 * Closure for #find_by_message_uuid.
4869 struct FindByMessageUuidContext
4874 struct MessageUUIDP message_uuid;
4877 * Set to the reassembly context if found.
4879 struct ReassemblyContext *rc;
4884 * Iterator called to find a reassembly context by the message UUID in the
4887 * @param cls a `struct FindByMessageUuidContext`
4888 * @param key a key (unused)
4889 * @param value a `struct ReassemblyContext`
4890 * @return #GNUNET_YES if not found, #GNUNET_NO if found
4893 find_by_message_uuid (void *cls, uint32_t key, void *value)
4895 struct FindByMessageUuidContext *fc = cls;
4896 struct ReassemblyContext *rc = value;
4899 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
4909 * Communicator gave us a fragment. Process the request.
4911 * @param cls a `struct CommunicatorMessageContext` (must call
4912 * #finish_cmc_handling() when done)
4913 * @param fb the message that was received
4916 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4918 struct CommunicatorMessageContext *cmc = cls;
4919 struct Neighbour *n;
4920 struct ReassemblyContext *rc;
4921 const struct GNUNET_MessageHeader *msg;
4926 struct GNUNET_TIME_Relative cdelay;
4927 struct FindByMessageUuidContext fc;
4929 n = lookup_neighbour (&cmc->im.sender);
4932 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4935 finish_cmc_handling (cmc);
4936 GNUNET_SERVICE_client_drop (client);
4939 if (NULL == n->reassembly_map)
4941 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
4942 n->reassembly_heap =
4943 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4944 n->reassembly_timeout_task =
4945 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4946 &reassembly_cleanup_task,
4949 msize = ntohs (fb->msg_size);
4950 fc.message_uuid = fb->msg_uuid;
4952 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
4954 &find_by_message_uuid,
4956 if (NULL == (rc = fc.rc))
4958 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4959 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4960 rc->msg_uuid = fb->msg_uuid;
4962 rc->msg_size = msize;
4963 rc->reassembly_timeout =
4964 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4965 rc->last_frag = GNUNET_TIME_absolute_get ();
4966 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4968 rc->reassembly_timeout.abs_value_us);
4969 GNUNET_assert (GNUNET_OK ==
4970 GNUNET_CONTAINER_multihashmap32_put (
4974 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
4975 target = (char *) &rc[1];
4976 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4977 rc->msg_missing = rc->msg_size;
4981 target = (char *) &rc[1];
4983 if (msize != rc->msg_size)
4986 finish_cmc_handling (cmc);
4991 fsize = ntohs (fb->header.size) - sizeof (*fb);
4995 finish_cmc_handling (cmc);
4998 frag_off = ntohs (fb->frag_off);
4999 memcpy (&target[frag_off], &fb[1], fsize);
5000 /* update bitfield and msg_missing */
5001 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5003 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5005 rc->bitfield[i / 8] |= (1 << (i % 8));
5010 /* Compute cummulative ACK */
5011 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5012 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5013 if (0 == rc->msg_missing)
5014 cdelay = GNUNET_TIME_UNIT_ZERO;
5015 cummulative_ack (&cmc->im.sender,
5017 GNUNET_TIME_relative_to_absolute (cdelay));
5018 rc->last_frag = GNUNET_TIME_absolute_get ();
5019 /* is reassembly complete? */
5020 if (0 != rc->msg_missing)
5022 finish_cmc_handling (cmc);
5025 /* reassembly is complete, verify result */
5026 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5027 if (ntohs (msg->size) != rc->msg_size)
5030 free_reassembly_context (rc);
5031 finish_cmc_handling (cmc);
5034 /* successful reassembly */
5035 demultiplex_with_cmc (cmc, msg);
5036 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5037 en-route and we forget that we finished this reassembly immediately!
5038 -> keep around until timeout?
5039 -> shorten timeout based on ACK? */
5040 free_reassembly_context (rc);
5045 * Communicator gave us a reliability box. Check the message.
5047 * @param cls a `struct CommunicatorMessageContext`
5048 * @param rb the send message that was sent
5049 * @return #GNUNET_YES if message is well-formed
5052 check_reliability_box (void *cls,
5053 const struct TransportReliabilityBoxMessage *rb)
5056 GNUNET_MQ_check_boxed_message (rb);
5062 * Communicator gave us a reliability box. Process the request.
5064 * @param cls a `struct CommunicatorMessageContext` (must call
5065 * #finish_cmc_handling() when done)
5066 * @param rb the message that was received
5069 handle_reliability_box (void *cls,
5070 const struct TransportReliabilityBoxMessage *rb)
5072 struct CommunicatorMessageContext *cmc = cls;
5073 const struct GNUNET_MessageHeader *inbox =
5074 (const struct GNUNET_MessageHeader *) &rb[1];
5076 // FIXME: call cummulative_ack(), have ack_countdown influence max_delay!
5077 (void) (0 == ntohl (rb->ack_countdown));
5078 /* continue with inner message */
5079 demultiplex_with_cmc (cmc, inbox);
5084 * Check if we have advanced to another age since the last time. If
5085 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5088 * @param pd[in,out] data to update
5089 * @param age current age
5092 update_pd_age (struct PerformanceData *pd, unsigned int age)
5096 if (age == pd->last_age)
5097 return; /* nothing to do */
5098 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5099 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5101 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5103 the->bytes_sent = 0;
5104 the->bytes_received = 0;
5111 * Update @a pd based on the latest @a rtt and the number of bytes
5112 * that were confirmed to be successfully transmitted.
5114 * @param pd[in,out] data to update
5115 * @param rtt latest round-trip time
5116 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5119 update_performance_data (struct PerformanceData *pd,
5120 struct GNUNET_TIME_Relative rtt,
5121 uint16_t bytes_transmitted_ok)
5123 uint64_t nval = rtt.rel_value_us;
5124 uint64_t oval = pd->aged_rtt.rel_value_us;
5125 unsigned int age = get_age ();
5126 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5128 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5131 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5132 update_pd_age (pd, age);
5133 the->bytes_received += bytes_transmitted_ok;
5138 * We have successfully transmitted data via @a q, update metrics.
5140 * @param q queue to update
5141 * @param rtt round trip time observed
5142 * @param bytes_transmitted_ok number of bytes successfully transmitted
5145 update_queue_performance (struct Queue *q,
5146 struct GNUNET_TIME_Relative rtt,
5147 uint16_t bytes_transmitted_ok)
5149 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5154 * We have successfully transmitted data via @a dvh, update metrics.
5156 * @param dvh distance vector path data to update
5157 * @param rtt round trip time observed
5158 * @param bytes_transmitted_ok number of bytes successfully transmitted
5161 update_dvh_performance (struct DistanceVectorHop *dvh,
5162 struct GNUNET_TIME_Relative rtt,
5163 uint16_t bytes_transmitted_ok)
5165 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5170 * The @a pa was acknowledged, process the acknowledgement.
5172 * @param pa the pending acknowledgement that was satisfied
5173 * @param ack_delay artificial delay from cummulative acks created by the other
5177 handle_acknowledged (struct PendingAcknowledgement *pa,
5178 struct GNUNET_TIME_Relative ack_delay)
5180 struct PendingMessage *pm = pa->pm;
5181 struct GNUNET_TIME_Relative delay;
5183 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5184 if (delay.rel_value_us > ack_delay.rel_value_us)
5185 delay = GNUNET_TIME_UNIT_ZERO;
5187 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5188 if (NULL != pa->queue)
5189 update_queue_performance (pa->queue, delay, pa->message_size);
5190 if (NULL != pa->dvh)
5191 update_dvh_performance (pa->dvh, delay, pa->message_size);
5194 if (NULL != pm->frag_parent)
5196 pm = pm->frag_parent;
5197 free_fragment_tree (pa->pm);
5199 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5201 struct PendingMessage *parent = pm->frag_parent;
5203 free_fragment_tree (pm);
5206 if (NULL != pm->head_frag)
5207 pm = NULL; /* we are done, otherwise free 'pm' below */
5210 free_pending_message (pm);
5211 free_pending_acknowledgement (pa);
5216 * Communicator gave us a reliability ack. Check it is well-formed.
5218 * @param cls a `struct CommunicatorMessageContext` (unused)
5219 * @param ra the message that was received
5220 * @return #GNUNET_Ok if @a ra is well-formed
5223 check_reliability_ack (void *cls,
5224 const struct TransportReliabilityAckMessage *ra)
5226 unsigned int n_acks;
5229 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5230 sizeof (struct TransportCummulativeAckPayloadP);
5233 GNUNET_break_op (0);
5234 return GNUNET_SYSERR;
5236 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5237 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5239 GNUNET_break_op (0);
5240 return GNUNET_SYSERR;
5247 * Communicator gave us a reliability ack. Process the request.
5249 * @param cls a `struct CommunicatorMessageContext` (must call
5250 * #finish_cmc_handling() when done)
5251 * @param ra the message that was received
5254 handle_reliability_ack (void *cls,
5255 const struct TransportReliabilityAckMessage *ra)
5257 struct CommunicatorMessageContext *cmc = cls;
5258 const struct TransportCummulativeAckPayloadP *ack;
5259 struct PendingAcknowledgement *pa;
5260 unsigned int n_acks;
5261 uint32_t ack_counter;
5263 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5264 sizeof (struct TransportCummulativeAckPayloadP);
5265 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5266 for (unsigned int i = 0; i < n_acks; i++)
5269 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5272 GNUNET_STATISTICS_update (
5274 "# FRAGMENT_ACKS dropped, no matching pending message",
5279 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5282 ack_counter = htonl (ra->ack_counter);
5283 // FIXME: track ACK losses based on ack_counter somewhere!
5284 // (DV and/or Neighbour?)
5285 finish_cmc_handling (cmc);
5290 * Communicator gave us a backchannel encapsulation. Check the message.
5292 * @param cls a `struct CommunicatorMessageContext`
5293 * @param be the send message that was sent
5294 * @return #GNUNET_YES if message is well-formed
5297 check_backchannel_encapsulation (
5299 const struct TransportBackchannelEncapsulationMessage *be)
5301 uint16_t size = ntohs (be->header.size);
5304 if ((size - sizeof (*be)) <
5305 (sizeof (struct TransportBackchannelRequestPayloadP) +
5306 sizeof (struct GNUNET_MessageHeader)))
5308 GNUNET_break_op (0);
5309 return GNUNET_SYSERR;
5316 * We received the plaintext @a msg from backtalker @a b. Forward
5317 * it to the respective communicator.
5319 * @param b a backtalker
5320 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5321 * followed by the target name of the communicator
5322 * @param msg_size number of bytes in @a msg
5325 forward_backchannel_payload (struct Backtalker *b,
5329 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5330 struct GNUNET_MQ_Envelope *env;
5331 struct TransportClient *tc;
5332 const struct GNUNET_MessageHeader *mh;
5333 const char *target_communicator;
5336 /* Determine target_communicator and check @a msg is well-formed */
5338 mhs = ntohs (mh->size);
5339 if (mhs <= msg_size)
5341 GNUNET_break_op (0);
5344 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5345 if ('\0' != target_communicator[msg_size - mhs - 1])
5347 GNUNET_break_op (0);
5350 /* Find client providing this communicator */
5351 for (tc = clients_head; NULL != tc; tc = tc->next)
5352 if ((CT_COMMUNICATOR == tc->type) &&
5354 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5362 "# Backchannel message dropped: target communicator `%s' unknown",
5363 target_communicator);
5364 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5365 GNUNET_free (stastr);
5368 /* Finally, deliver backchannel message to communicator */
5369 env = GNUNET_MQ_msg_extra (
5372 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5374 memcpy (&cbi[1], msg, msg_size);
5375 GNUNET_MQ_send (tc->mq, env);
5380 * Free data structures associated with @a b.
5382 * @param b data structure to release
5385 free_backtalker (struct Backtalker *b)
5389 GNUNET_PEERSTORE_iterate_cancel (b->get);
5391 GNUNET_assert (NULL != b->cmc);
5392 finish_cmc_handling (b->cmc);
5395 if (NULL != b->task)
5397 GNUNET_SCHEDULER_cancel (b->task);
5402 GNUNET_PEERSTORE_store_cancel (b->sc);
5407 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5413 * Callback to free backtalker records.
5417 * @param value a `struct Backtalker`
5418 * @return #GNUNET_OK (always)
5421 free_backtalker_cb (void *cls,
5422 const struct GNUNET_PeerIdentity *pid,
5425 struct Backtalker *b = value;
5429 free_backtalker (b);
5435 * Function called when it is time to clean up a backtalker.
5437 * @param cls a `struct Backtalker`
5440 backtalker_timeout_cb (void *cls)
5442 struct Backtalker *b = cls;
5445 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5447 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5450 GNUNET_assert (NULL == b->sc);
5451 free_backtalker (b);
5456 * Function called with the monotonic time of a backtalker
5457 * by PEERSTORE. Updates the time and continues processing.
5459 * @param cls a `struct Backtalker`
5460 * @param record the information found, NULL for the last call
5461 * @param emsg error message
5464 backtalker_monotime_cb (void *cls,
5465 const struct GNUNET_PEERSTORE_Record *record,
5468 struct Backtalker *b = cls;
5469 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5470 struct GNUNET_TIME_Absolute mt;
5475 /* we're done with #backtalker_monotime_cb() invocations,
5476 continue normal processing */
5478 GNUNET_assert (NULL != b->cmc);
5479 finish_cmc_handling (b->cmc);
5481 if (0 != b->body_size)
5482 forward_backchannel_payload (b, &b[1], b->body_size);
5485 if (sizeof (*mtbe) != record->value_size)
5490 mtbe = record->value;
5491 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5492 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5494 GNUNET_STATISTICS_update (
5496 "# Backchannel messages dropped: monotonic time not increasing",
5499 b->monotonic_time = mt;
5500 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5509 * Function called by PEERSTORE when the store operation of
5510 * a backtalker's monotonic time is complete.
5512 * @param cls the `struct Backtalker`
5513 * @param success #GNUNET_OK on success
5516 backtalker_monotime_store_cb (void *cls, int success)
5518 struct Backtalker *b = cls;
5520 if (GNUNET_OK != success)
5522 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5523 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5526 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5531 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5533 * @param b a backtalker with updated monotonic time
5536 update_backtalker_monotime (struct Backtalker *b)
5538 struct GNUNET_TIME_AbsoluteNBO mtbe;
5542 GNUNET_PEERSTORE_store_cancel (b->sc);
5547 GNUNET_SCHEDULER_cancel (b->task);
5550 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5552 GNUNET_PEERSTORE_store (peerstore,
5555 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5558 GNUNET_TIME_UNIT_FOREVER_ABS,
5559 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5560 &backtalker_monotime_store_cb,
5566 * Communicator gave us a backchannel encapsulation. Process the request.
5567 * (We are not the origin of the backchannel here, the communicator simply
5568 * received a backchannel message and we are expected to forward it.)
5570 * @param cls a `struct CommunicatorMessageContext` (must call
5571 * #finish_cmc_handling() when done)
5572 * @param be the message that was received
5575 handle_backchannel_encapsulation (
5577 const struct TransportBackchannelEncapsulationMessage *be)
5579 struct CommunicatorMessageContext *cmc = cls;
5580 struct BackchannelKeyState key;
5581 struct GNUNET_HashCode hmac;
5585 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5587 /* not for me, try to route to target */
5588 route_message (&be->target,
5589 GNUNET_copy_message (&be->header),
5591 finish_cmc_handling (cmc);
5594 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5595 hdr = (const char *) &be[1];
5596 hdr_len = ntohs (be->header.size) - sizeof (*be);
5597 bc_hmac (&key, &hmac, hdr, hdr_len);
5598 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5600 /* HMAC missmatch, disard! */
5601 GNUNET_break_op (0);
5602 finish_cmc_handling (cmc);
5605 /* begin actual decryption */
5607 struct Backtalker *b;
5608 struct GNUNET_TIME_Absolute monotime;
5609 struct TransportBackchannelRequestPayloadP ppay;
5610 char body[hdr_len - sizeof (ppay)];
5612 GNUNET_assert (hdr_len >=
5613 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5614 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5615 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5616 bc_key_clean (&key);
5617 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5618 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5619 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5621 GNUNET_STATISTICS_update (
5623 "# Backchannel messages dropped: monotonic time not increasing",
5626 finish_cmc_handling (cmc);
5630 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5632 /* Check signature */
5633 struct EphemeralConfirmationPS ec;
5635 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5636 ec.purpose.size = htonl (sizeof (ec));
5637 ec.target = GST_my_identity;
5638 ec.ephemeral_key = be->ephemeral_key;
5641 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5644 &ppay.sender.public_key))
5646 /* Signature invalid, disard! */
5647 GNUNET_break_op (0);
5648 finish_cmc_handling (cmc);
5654 /* update key cache and mono time */
5655 b->last_ephemeral = be->ephemeral_key;
5656 b->monotonic_time = monotime;
5657 update_backtalker_monotime (b);
5658 forward_backchannel_payload (b, body, sizeof (body));
5660 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5661 finish_cmc_handling (cmc);
5664 /* setup data structure to cache signature AND check
5665 monotonic time with PEERSTORE before forwarding backchannel payload */
5666 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5667 b->pid = ppay.sender;
5668 b->body_size = sizeof (body);
5669 memcpy (&b[1], body, sizeof (body));
5670 GNUNET_assert (GNUNET_YES ==
5671 GNUNET_CONTAINER_multipeermap_put (
5675 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5676 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5679 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5680 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5682 GNUNET_PEERSTORE_iterate (peerstore,
5685 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5686 &backtalker_monotime_cb,
5693 * Task called when we should check if any of the DV paths
5694 * we have learned to a target are due for garbage collection.
5696 * Collects stale paths, and possibly frees the entire DV
5697 * entry if no paths are left. Otherwise re-schedules itself.
5699 * @param cls a `struct DistanceVector`
5702 path_cleanup_cb (void *cls)
5704 struct DistanceVector *dv = cls;
5705 struct DistanceVectorHop *pos;
5707 dv->timeout_task = NULL;
5708 while (NULL != (pos = dv->dv_head))
5710 GNUNET_assert (dv == pos->dv);
5711 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5713 free_distance_vector_hop (pos);
5721 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5725 * Task run to check whether the hops of the @a cls still
5726 * are validated, or if we need to core about disconnection.
5728 * @param cls a `struct DistanceVector` (with core_visible set!)
5731 check_dv_path_down (void *cls)
5733 struct DistanceVector *dv = cls;
5734 struct Neighbour *n;
5736 dv->visibility_task = NULL;
5737 GNUNET_assert (GNUNET_YES == dv->core_visible);
5738 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5742 GNUNET_TIME_absolute_get_remaining (pos->path_valid_until).rel_value_us)
5744 dv->visibility_task = GNUNET_SCHEDULER_add_at (pos->path_valid_until,
5745 &check_dv_path_down,
5750 /* all paths invalid, make dv core-invisible */
5751 dv->core_visible = GNUNET_NO;
5752 n = lookup_neighbour (&dv->target);
5753 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5754 return; /* no need to tell core, connection still up! */
5755 cores_send_disconnect_info (&dv->target);
5760 * The @a hop is a validated path to the respective target
5761 * peer and we should tell core about it -- and schedule
5762 * a job to revoke the state.
5764 * @param hop a path to some peer that is the reason for activation
5767 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5769 struct DistanceVector *dv = hop->dv;
5770 struct Neighbour *n;
5772 GNUNET_assert (GNUNET_NO == dv->core_visible);
5773 GNUNET_assert (NULL == dv->visibility_task);
5775 dv->core_visible = GNUNET_YES;
5776 dv->visibility_task =
5777 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_dv_path_down, dv);
5778 n = lookup_neighbour (&dv->target);
5779 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5780 return; /* no need to tell core, connection already up! */
5781 cores_send_connect_info (&dv->target,
5783 ? GNUNET_BANDWIDTH_value_sum (n->quota_out,
5790 * We have learned a @a path through the network to some other peer, add it to
5791 * our DV data structure (returning #GNUNET_YES on success).
5793 * We do not add paths if we have a sufficient number of shorter
5794 * paths to this target already (returning #GNUNET_NO).
5796 * We also do not add problematic paths, like those where we lack the first
5797 * hop in our neighbour list (i.e. due to a topology change) or where some
5798 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5800 * @param path the path we learned, path[0] should be us,
5801 * and then path contains a valid path from us to
5802 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
5803 * @param path_len number of entries on the @a path, at least three!
5804 * @param network_latency how long does the message take from us to
5805 * `path[path_len-1]`? set to "forever" if unknown
5806 * @param path_valid_until how long is this path considered validated? Maybe
5808 * @return #GNUNET_YES on success,
5809 * #GNUNET_NO if we have better path(s) to the target
5810 * #GNUNET_SYSERR if the path is useless and/or invalid
5811 * (i.e. path[1] not a direct neighbour
5812 * or path[i+1] is a direct neighbour for i>0)
5815 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5816 unsigned int path_len,
5817 struct GNUNET_TIME_Relative network_latency,
5818 struct GNUNET_TIME_Absolute path_valid_until)
5820 struct DistanceVectorHop *hop;
5821 struct DistanceVector *dv;
5822 struct Neighbour *next_hop;
5823 unsigned int shorter_distance;
5827 /* what a boring path! not allowed! */
5829 return GNUNET_SYSERR;
5831 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5832 next_hop = lookup_neighbour (&path[1]);
5833 if (NULL == next_hop)
5835 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5837 return GNUNET_SYSERR;
5839 for (unsigned int i = 2; i < path_len; i++)
5840 if (NULL != lookup_neighbour (&path[i]))
5842 /* Useless path, we have a direct connection to some hop
5843 in the middle of the path, so this one doesn't even
5844 seem terribly useful for redundancy */
5845 return GNUNET_SYSERR;
5847 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5850 dv = GNUNET_new (struct DistanceVector);
5851 dv->target = path[path_len - 1];
5852 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5855 GNUNET_assert (GNUNET_OK ==
5856 GNUNET_CONTAINER_multipeermap_put (
5860 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5862 /* Check if we have this path already! */
5863 shorter_distance = 0;
5864 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5867 if (pos->distance < path_len - 2)
5869 /* Note that the distances in 'pos' excludes us (path[0]) and
5870 the next_hop (path[1]), so we need to subtract two
5871 and check next_hop explicitly */
5872 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5874 int match = GNUNET_YES;
5876 for (unsigned int i = 0; i < pos->distance; i++)
5878 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5884 if (GNUNET_YES == match)
5886 struct GNUNET_TIME_Relative last_timeout;
5888 /* Re-discovered known path, update timeout */
5889 GNUNET_STATISTICS_update (GST_stats,
5890 "# Known DV path refreshed",
5893 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5895 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5896 pos->path_valid_until =
5897 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5898 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5899 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5900 if ((GNUNET_NO == dv->core_visible) &&
5901 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until)
5903 activate_core_visible_dv_path (pos);
5904 if (last_timeout.rel_value_us <
5905 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5906 DV_PATH_DISCOVERY_FREQUENCY)
5909 /* Some peer send DV learn messages too often, we are learning
5910 the same path faster than it would be useful; do not forward! */
5917 /* Count how many shorter paths we have (incl. direct
5918 neighbours) before simply giving up on this one! */
5919 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
5921 /* We have a shorter path already! */
5924 /* create new DV path entry */
5925 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
5926 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5927 hop->next_hop = next_hop;
5929 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
5932 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5933 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5934 hop->path_valid_until = path_valid_until;
5935 hop->distance = path_len - 2;
5936 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
5937 GNUNET_CONTAINER_MDLL_insert (neighbour,
5941 if ((GNUNET_NO == dv->core_visible) &&
5942 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us))
5943 activate_core_visible_dv_path (hop);
5949 * Communicator gave us a DV learn message. Check the message.
5951 * @param cls a `struct CommunicatorMessageContext`
5952 * @param dvl the send message that was sent
5953 * @return #GNUNET_YES if message is well-formed
5956 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
5958 uint16_t size = ntohs (dvl->header.size);
5959 uint16_t num_hops = ntohs (dvl->num_hops);
5960 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
5963 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
5965 GNUNET_break_op (0);
5966 return GNUNET_SYSERR;
5968 if (num_hops > MAX_DV_HOPS_ALLOWED)
5970 GNUNET_break_op (0);
5971 return GNUNET_SYSERR;
5973 for (unsigned int i = 0; i < num_hops; i++)
5975 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
5977 GNUNET_break_op (0);
5978 return GNUNET_SYSERR;
5980 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
5982 GNUNET_break_op (0);
5983 return GNUNET_SYSERR;
5991 * Build and forward a DV learn message to @a next_hop.
5993 * @param next_hop peer to send the message to
5994 * @param msg message received
5995 * @param bi_history bitmask specifying hops on path that were bidirectional
5996 * @param nhops length of the @a hops array
5997 * @param hops path the message traversed so far
5998 * @param in_time when did we receive the message, used to calculate network
6002 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6003 const struct TransportDVLearnMessage *msg,
6004 uint16_t bi_history,
6006 const struct DVPathEntryP *hops,
6007 struct GNUNET_TIME_Absolute in_time)
6009 struct DVPathEntryP *dhops;
6010 struct TransportDVLearnMessage *fwd;
6011 struct GNUNET_TIME_Relative nnd;
6013 /* compute message for forwarding */
6014 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6015 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
6016 (nhops + 1) * sizeof (struct DVPathEntryP));
6017 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6018 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6019 (nhops + 1) * sizeof (struct DVPathEntryP));
6020 fwd->num_hops = htons (nhops + 1);
6021 fwd->bidirectional = htons (bi_history);
6022 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6023 GNUNET_TIME_relative_ntoh (
6024 msg->non_network_delay));
6025 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6026 fwd->init_sig = msg->init_sig;
6027 fwd->initiator = msg->initiator;
6028 fwd->challenge = msg->challenge;
6029 dhops = (struct DVPathEntryP *) &fwd[1];
6030 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6031 dhops[nhops].hop = GST_my_identity;
6033 struct DvHopPS dhp = {.purpose.purpose =
6034 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6035 .purpose.size = htonl (sizeof (dhp)),
6036 .pred = dhops[nhops - 1].hop,
6038 .challenge = msg->challenge};
6040 GNUNET_assert (GNUNET_OK ==
6041 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6043 &dhops[nhops].hop_sig));
6045 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6050 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6052 * @param sender_monotonic_time monotonic time of the initiator
6053 * @param init the signer
6054 * @param challenge the challenge that was signed
6055 * @param init_sig signature presumably by @a init
6056 * @return #GNUNET_OK if the signature is valid
6059 validate_dv_initiator_signature (
6060 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6061 const struct GNUNET_PeerIdentity *init,
6062 const struct ChallengeNonceP *challenge,
6063 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6065 struct DvInitPS ip = {.purpose.purpose = htonl (
6066 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6067 .purpose.size = htonl (sizeof (ip)),
6068 .monotonic_time = sender_monotonic_time,
6069 .challenge = *challenge};
6073 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6078 GNUNET_break_op (0);
6079 return GNUNET_SYSERR;
6086 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6088 struct NeighbourSelectionContext
6091 * Original message we received.
6093 const struct TransportDVLearnMessage *dvl;
6098 const struct DVPathEntryP *hops;
6101 * Time we received the message.
6103 struct GNUNET_TIME_Absolute in_time;
6106 * Offsets of the selected peers.
6108 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6111 * Number of peers eligible for selection.
6113 unsigned int num_eligible;
6116 * Number of peers that were selected for forwarding.
6118 unsigned int num_selections;
6121 * Number of hops in @e hops
6126 * Bitmap of bidirectional connections encountered.
6128 uint16_t bi_history;
6133 * Function called for each neighbour during #handle_dv_learn.
6135 * @param cls a `struct NeighbourSelectionContext *`
6136 * @param pid identity of the peer
6137 * @param value a `struct Neighbour`
6138 * @return #GNUNET_YES (always)
6141 dv_neighbour_selection (void *cls,
6142 const struct GNUNET_PeerIdentity *pid,
6145 struct NeighbourSelectionContext *nsc = cls;
6148 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6149 return GNUNET_YES; /* skip initiator */
6150 for (unsigned int i = 0; i < nsc->nhops; i++)
6151 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6152 return GNUNET_YES; /* skip peers on path */
6153 nsc->num_eligible++;
6159 * Function called for each neighbour during #handle_dv_learn.
6160 * We call #forward_dv_learn() on the neighbour(s) selected
6161 * during #dv_neighbour_selection().
6163 * @param cls a `struct NeighbourSelectionContext *`
6164 * @param pid identity of the peer
6165 * @param value a `struct Neighbour`
6166 * @return #GNUNET_YES (always)
6169 dv_neighbour_transmission (void *cls,
6170 const struct GNUNET_PeerIdentity *pid,
6173 struct NeighbourSelectionContext *nsc = cls;
6176 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6177 return GNUNET_YES; /* skip initiator */
6178 for (unsigned int i = 0; i < nsc->nhops; i++)
6179 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6180 return GNUNET_YES; /* skip peers on path */
6181 for (unsigned int i = 0; i < nsc->num_selections; i++)
6183 if (nsc->selections[i] == nsc->num_eligible)
6185 forward_dv_learn (pid,
6194 nsc->num_eligible++;
6200 * Computes the number of neighbours we should forward a DVInit
6201 * message to given that it has so far taken @a hops_taken hops
6202 * though the network and that the number of neighbours we have
6203 * in total is @a neighbour_count, out of which @a eligible_count
6204 * are not yet on the path.
6206 * NOTE: technically we might want to include NSE in the formula to
6207 * get a better grip on the overall network size. However, for now
6208 * using NSE here would create a dependency issue in the build system.
6209 * => Left for later, hardcoded to 50 for now.
6211 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6212 * peers via DV (`target_total`). We want the reach to be spread out
6213 * over various distances to the origin, with a bias towards shorter
6216 * We make the strong assumption that the network topology looks
6217 * "similar" at other hops, in particular the @a neighbour_count
6218 * should be comparable at other hops.
6220 * If the local neighbourhood is densely connected, we expect that @a
6221 * eligible_count is close to @a neighbour_count minus @a hops_taken
6222 * as a lot of the path is already known. In that case, we should
6223 * forward to few(er) peers to try to find a path out of the
6224 * neighbourhood. OTOH, if @a eligible_count is close to @a
6225 * neighbour_count, we should forward to many peers as we are either
6226 * still close to the origin (i.e. @a hops_taken is small) or because
6227 * we managed to get beyond a local cluster. We express this as
6228 * the `boost_factor` using the square of the fraction of eligible
6229 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6230 * 99% are eligible, the 'boost' will be almost 1).
6232 * Second, the more hops we have taken, the larger the problem of an
6233 * exponential traffic explosion gets. So we take the `target_total`,
6234 * and compute our degree such that at each distance d 2^{-d} peers
6235 * are selected (corrected by the `boost_factor`).
6237 * @param hops_taken number of hops DVInit has travelled so far
6238 * @param neighbour_count number of neighbours we have in total
6239 * @param eligible_count number of neighbours we could in
6243 calculate_fork_degree (unsigned int hops_taken,
6244 unsigned int neighbour_count,
6245 unsigned int eligible_count)
6247 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6248 double eligible_ratio =
6249 ((double) eligible_count) / ((double) neighbour_count);
6250 double boost_factor = eligible_ratio * eligible_ratio;
6254 if (hops_taken >= 64)
6255 return 0; /* precaution given bitshift below */
6256 for (unsigned int i = 1; i < hops_taken; i++)
6258 /* For each hop, subtract the expected number of targets
6259 reached at distance d (so what remains divided by 2^d) */
6260 target_total -= (target_total * boost_factor / (1LLU << i));
6263 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6264 /* round up or down probabilistically depending on how close we were
6265 when floor()ing to rnd */
6266 left = target_total - (double) rnd;
6267 if (UINT32_MAX * left >
6268 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6269 rnd++; /* round up */
6275 * Function called when peerstore is done storing a DV monotonic time.
6277 * @param cls a `struct Neighbour`
6278 * @param success #GNUNET_YES if peerstore was successful
6281 neighbour_store_dvmono_cb (void *cls, int success)
6283 struct Neighbour *n = cls;
6286 if (GNUNET_YES != success)
6287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6288 "Failed to store other peer's monotonic time in peerstore!\n");
6293 * Communicator gave us a DV learn message. Process the request.
6295 * @param cls a `struct CommunicatorMessageContext` (must call
6296 * #finish_cmc_handling() when done)
6297 * @param dvl the message that was received
6300 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6302 struct CommunicatorMessageContext *cmc = cls;
6303 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6306 uint16_t bi_history;
6307 const struct DVPathEntryP *hops;
6310 struct GNUNET_TIME_Absolute in_time;
6311 struct Neighbour *n;
6313 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6314 bi_history = ntohs (dvl->bidirectional);
6315 hops = (const struct DVPathEntryP *) &dvl[1];
6319 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6322 finish_cmc_handling (cmc);
6329 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6332 finish_cmc_handling (cmc);
6337 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6338 cc = cmc->tc->details.communicator.cc;
6339 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6340 cc); // FIXME: add bi-directional flag to cc?
6341 in_time = GNUNET_TIME_absolute_get ();
6343 /* continue communicator here, everything else can happen asynchronous! */
6344 finish_cmc_handling (cmc);
6346 n = lookup_neighbour (&dvl->initiator);
6349 if ((n->dv_monotime_available == GNUNET_YES) &&
6350 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6351 n->last_dv_learn_monotime.abs_value_us))
6353 GNUNET_STATISTICS_update (GST_stats,
6354 "# DV learn discarded due to time travel",
6359 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6364 GNUNET_break_op (0);
6367 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6368 if (GNUNET_YES == n->dv_monotime_available)
6371 GNUNET_PEERSTORE_store_cancel (n->sc);
6373 GNUNET_PEERSTORE_store (peerstore,
6376 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6377 &dvl->monotonic_time,
6378 sizeof (dvl->monotonic_time),
6379 GNUNET_TIME_UNIT_FOREVER_ABS,
6380 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6381 &neighbour_store_dvmono_cb,
6385 // FIXME: asynchronously (!) verify hop-by-hop signatures!
6386 // => if signature verification load too high, implement random drop
6389 do_fwd = GNUNET_YES;
6390 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6392 struct GNUNET_PeerIdentity path[nhops + 1];
6393 struct GNUNET_TIME_Relative host_latency_sum;
6394 struct GNUNET_TIME_Relative latency;
6395 struct GNUNET_TIME_Relative network_latency;
6397 /* We initiated this, learn the forward path! */
6398 path[0] = GST_my_identity;
6399 path[1] = hops[0].hop;
6400 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6402 // Need also something to lookup initiation time
6403 // to compute RTT! -> add RTT argument here?
6404 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6405 // (based on dvl->challenge, we can identify time of origin!)
6407 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6408 /* assumption: latency on all links is the same */
6409 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6411 for (unsigned int i = 2; i <= nhops; i++)
6413 struct GNUNET_TIME_Relative ilat;
6415 /* assumption: linear latency increase per hop */
6416 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6417 path[i] = hops[i - 1].hop;
6418 learn_dv_path (path,
6421 GNUNET_TIME_relative_to_absolute (
6422 ADDRESS_VALIDATION_LIFETIME));
6424 /* as we initiated, do not forward again (would be circular!) */
6430 /* last hop was bi-directional, we could learn something here! */
6431 struct GNUNET_PeerIdentity path[nhops + 2];
6433 path[0] = GST_my_identity;
6434 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6435 for (unsigned int i = 0; i < nhops; i++)
6439 if (0 == (bi_history & (1 << i)))
6440 break; /* i-th hop not bi-directional, stop learning! */
6443 path[i + 2] = dvl->initiator;
6447 path[i + 2] = hops[nhops - i - 2].hop;
6450 iret = learn_dv_path (path,
6452 GNUNET_TIME_UNIT_FOREVER_REL,
6453 GNUNET_TIME_UNIT_ZERO_ABS);
6454 if (GNUNET_SYSERR == iret)
6456 /* path invalid or too long to be interesting for US, thus should also
6457 not be interesting to our neighbours, cut path when forwarding to
6458 'i' hops, except of course for the one that goes back to the
6460 GNUNET_STATISTICS_update (GST_stats,
6461 "# DV learn not forwarded due invalidity of path",
6467 if ((GNUNET_NO == iret) && (nhops == i + 1))
6469 /* we have better paths, and this is the longest target,
6470 so there cannot be anything interesting later */
6471 GNUNET_STATISTICS_update (GST_stats,
6472 "# DV learn not forwarded, got better paths",
6481 if (MAX_DV_HOPS_ALLOWED == nhops)
6483 /* At limit, we're out of here! */
6484 finish_cmc_handling (cmc);
6488 /* Forward to initiator, if path non-trivial and possible */
6489 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6490 did_initiator = GNUNET_NO;
6493 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6495 /* send back to origin! */
6496 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6497 did_initiator = GNUNET_YES;
6499 /* We forward under two conditions: either we still learned something
6500 ourselves (do_fwd), or the path was darn short and thus the initiator is
6501 likely to still be very interested in this (and we did NOT already
6502 send it back to the initiator) */
6503 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6504 (GNUNET_NO == did_initiator)))
6506 /* Pick random neighbours that are not yet on the path */
6507 struct NeighbourSelectionContext nsc;
6510 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6513 nsc.bi_history = bi_history;
6515 nsc.in_time = in_time;
6516 nsc.num_eligible = 0;
6517 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6518 &dv_neighbour_selection,
6520 if (0 == nsc.num_eligible)
6521 return; /* done here, cannot forward to anyone else */
6522 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6523 nsc.num_selections =
6524 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6525 for (unsigned int i = 0; i < nsc.num_selections; i++)
6527 (nsc.num_selections == n_cnt)
6528 ? i /* all were selected, avoid collisions by chance */
6529 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6530 nsc.num_eligible = 0;
6531 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6532 &dv_neighbour_transmission,
6539 * Communicator gave us a DV box. Check the message.
6541 * @param cls a `struct CommunicatorMessageContext`
6542 * @param dvb the send message that was sent
6543 * @return #GNUNET_YES if message is well-formed
6546 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6548 uint16_t size = ntohs (dvb->header.size);
6549 uint16_t num_hops = ntohs (dvb->num_hops);
6550 const struct GNUNET_PeerIdentity *hops =
6551 (const struct GNUNET_PeerIdentity *) &dvb[1];
6552 const struct GNUNET_MessageHeader *inbox =
6553 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6558 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6559 sizeof (struct GNUNET_MessageHeader))
6561 GNUNET_break_op (0);
6562 return GNUNET_SYSERR;
6564 isize = ntohs (inbox->size);
6566 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6568 GNUNET_break_op (0);
6569 return GNUNET_SYSERR;
6571 itype = ntohs (inbox->type);
6572 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6573 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6575 GNUNET_break_op (0);
6576 return GNUNET_SYSERR;
6578 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6580 GNUNET_break_op (0);
6581 return GNUNET_SYSERR;
6588 * Create a DV Box message and queue it for transmission to
6591 * @param next_hop peer to receive the message next
6592 * @param total_hops how many hops did the message take so far
6593 * @param num_hops length of the @a hops array
6594 * @param origin origin of the message
6595 * @param hops next peer(s) to the destination, including destination
6596 * @param payload payload of the box
6597 * @param payload_size number of bytes in @a payload
6600 forward_dv_box (struct Neighbour *next_hop,
6601 uint16_t total_hops,
6603 const struct GNUNET_PeerIdentity *origin,
6604 const struct GNUNET_PeerIdentity *hops,
6605 const void *payload,
6606 uint16_t payload_size)
6608 struct TransportDVBoxMessage *dvb;
6610 dvb = create_dv_box (total_hops,
6612 &hops[num_hops - 1] /* == target */,
6613 num_hops - 1 /* do not count target twice */,
6617 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6623 * Communicator gave us a DV box. Process the request.
6625 * @param cls a `struct CommunicatorMessageContext` (must call
6626 * #finish_cmc_handling() when done)
6627 * @param dvb the message that was received
6630 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6632 struct CommunicatorMessageContext *cmc = cls;
6633 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6634 uint16_t num_hops = ntohs (dvb->num_hops);
6635 const struct GNUNET_PeerIdentity *hops =
6636 (const struct GNUNET_PeerIdentity *) &dvb[1];
6637 const struct GNUNET_MessageHeader *inbox =
6638 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6642 /* We're trying from the end of the hops array, as we may be
6643 able to find a shortcut unknown to the origin that way */
6644 for (int i = num_hops - 1; i >= 0; i--)
6646 struct Neighbour *n;
6648 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6650 GNUNET_break_op (0);
6651 finish_cmc_handling (cmc);
6654 n = lookup_neighbour (&hops[i]);
6658 ntohs (dvb->total_hops) + 1,
6659 num_hops - i - 1, /* number of hops left */
6661 &hops[i + 1], /* remaining hops */
6662 (const void *) &dvb[1],
6664 finish_cmc_handling (cmc);
6667 /* Woopsie, next hop not in neighbours, drop! */
6668 GNUNET_STATISTICS_update (GST_stats,
6669 "# DV Boxes dropped: next hop unknown",
6672 finish_cmc_handling (cmc);
6675 /* We are the target. Unbox and handle message. */
6676 cmc->im.sender = dvb->origin;
6677 cmc->total_hops = ntohs (dvb->total_hops);
6678 demultiplex_with_cmc (cmc, inbox);
6683 * Client notified us about transmission from a peer. Process the request.
6685 * @param cls a `struct TransportClient` which sent us the message
6686 * @param obm the send message that was sent
6687 * @return #GNUNET_YES if message is well-formed
6690 check_incoming_msg (void *cls,
6691 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6693 struct TransportClient *tc = cls;
6695 if (CT_COMMUNICATOR != tc->type)
6698 return GNUNET_SYSERR;
6700 GNUNET_MQ_check_boxed_message (im);
6706 * Communicator gave us a transport address validation challenge. Process the
6709 * @param cls a `struct CommunicatorMessageContext` (must call
6710 * #finish_cmc_handling() when done)
6711 * @param tvc the message that was received
6714 handle_validation_challenge (
6716 const struct TransportValidationChallengeMessage *tvc)
6718 struct CommunicatorMessageContext *cmc = cls;
6719 struct TransportValidationResponseMessage *tvr;
6721 if (cmc->total_hops > 0)
6723 /* DV routing is not allowed for validation challenges! */
6724 GNUNET_break_op (0);
6725 finish_cmc_handling (cmc);
6728 tvr = GNUNET_new (struct TransportValidationResponseMessage);
6730 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
6731 tvr->header.size = htons (sizeof (*tvr));
6732 tvr->challenge = tvc->challenge;
6733 tvr->origin_time = tvc->sender_time;
6734 tvr->validity_duration = cmc->im.expected_address_validity;
6736 /* create signature */
6737 struct TransportValidationPS tvp =
6738 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6739 .purpose.size = htonl (sizeof (tvp)),
6740 .validity_duration = tvr->validity_duration,
6741 .challenge = tvc->challenge};
6743 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6747 route_message (&cmc->im.sender,
6749 RMO_ANYTHING_GOES | RMO_REDUNDANT);
6750 finish_cmc_handling (cmc);
6755 * Closure for #check_known_challenge.
6757 struct CheckKnownChallengeContext
6760 * Set to the challenge we are looking for.
6762 const struct ChallengeNonceP *challenge;
6765 * Set to a matching validation state, if one was found.
6767 struct ValidationState *vs;
6772 * Test if the validation state in @a value matches the
6773 * challenge from @a cls.
6775 * @param cls a `struct CheckKnownChallengeContext`
6776 * @param pid unused (must match though)
6777 * @param value a `struct ValidationState`
6778 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6781 check_known_challenge (void *cls,
6782 const struct GNUNET_PeerIdentity *pid,
6785 struct CheckKnownChallengeContext *ckac = cls;
6786 struct ValidationState *vs = value;
6789 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
6797 * Function called when peerstore is done storing a
6798 * validated address.
6800 * @param cls a `struct ValidationState`
6801 * @param success #GNUNET_YES on success
6804 peerstore_store_validation_cb (void *cls, int success)
6806 struct ValidationState *vs = cls;
6809 if (GNUNET_YES == success)
6811 GNUNET_STATISTICS_update (GST_stats,
6812 "# Peerstore failed to store foreign address",
6819 * Task run periodically to validate some address based on #validation_heap.
6824 validation_start_cb (void *cls);
6828 * Set the time for next_challenge of @a vs to @a new_time.
6829 * Updates the heap and if necessary reschedules the job.
6831 * @param vs validation state to update
6832 * @param new_time new time for revalidation
6835 update_next_challenge_time (struct ValidationState *vs,
6836 struct GNUNET_TIME_Absolute new_time)
6838 struct GNUNET_TIME_Relative delta;
6840 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
6841 return; /* be lazy */
6842 vs->next_challenge = new_time;
6845 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
6847 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
6848 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
6849 (NULL != validation_task))
6851 if (NULL != validation_task)
6852 GNUNET_SCHEDULER_cancel (validation_task);
6853 /* randomize a bit */
6854 delta.rel_value_us =
6855 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6856 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
6857 new_time = GNUNET_TIME_absolute_add (new_time, delta);
6859 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
6864 * Find the queue matching @a pid and @a address.
6866 * @param pid peer the queue must go to
6867 * @param address address the queue must use
6868 * @return NULL if no such queue exists
6870 static struct Queue *
6871 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
6873 struct Neighbour *n;
6875 n = lookup_neighbour (pid);
6878 for (struct Queue *pos = n->queue_head; NULL != pos;
6879 pos = pos->next_neighbour)
6881 if (0 == strcmp (pos->address, address))
6889 * Task run periodically to check whether the validity of the given queue has
6890 * run its course. If so, finds either another queue to take over, or clears
6891 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
6892 * chance to take over, and if that fails, notifies CORE about the disconnect.
6894 * @param cls a `struct Queue`
6897 core_queue_visibility_check (void *cls)
6899 struct Queue *q = cls;
6901 q->visibility_task = NULL;
6902 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
6904 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
6905 &core_queue_visibility_check,
6909 update_neighbour_core_visibility (q->neighbour);
6914 * Check whether the CORE visibility of @a n should change. Finds either a
6915 * queue to preserve the visibility, or clears the neighbour's `core_visible`
6916 * flag. In the latter case, gives DV routes a chance to take over, and if
6917 * that fails, notifies CORE about the disconnect. If so, check whether we
6918 * need to notify CORE.
6920 * @param n neighbour to perform the check for
6923 update_neighbour_core_visibility (struct Neighbour *n)
6925 struct DistanceVector *dv;
6927 GNUNET_assert (GNUNET_YES == n->core_visible);
6928 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
6929 the #core_queue_visibility_check() task for that queue */
6930 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6933 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
6935 /* found a valid queue, use this one */
6936 q->visibility_task =
6937 GNUNET_SCHEDULER_add_at (q->validated_until,
6938 &core_queue_visibility_check,
6943 n->core_visible = GNUNET_NO;
6945 /* Check if _any_ DV route to this neighbour is currently
6946 valid, if so, do NOT tell core about the loss of direct
6947 connectivity (DV still counts!) */
6948 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
6949 if (GNUNET_YES == dv->core_visible)
6951 /* Nothing works anymore, need to tell CORE about the loss of
6953 cores_send_disconnect_info (&n->pid);
6958 * Communicator gave us a transport address validation response. Process the
6961 * @param cls a `struct CommunicatorMessageContext` (must call
6962 * #finish_cmc_handling() when done)
6963 * @param tvr the message that was received
6966 handle_validation_response (
6968 const struct TransportValidationResponseMessage *tvr)
6970 struct CommunicatorMessageContext *cmc = cls;
6971 struct ValidationState *vs;
6972 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
6974 struct GNUNET_TIME_Absolute origin_time;
6976 struct DistanceVector *dv;
6977 struct Neighbour *n;
6979 /* check this is one of our challenges */
6980 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6982 &check_known_challenge,
6984 if (NULL == (vs = ckac.vs))
6986 /* This can happen simply if we 'forgot' the challenge by now,
6987 i.e. because we received the validation response twice */
6988 GNUNET_STATISTICS_update (GST_stats,
6989 "# Validations dropped, challenge unknown",
6992 finish_cmc_handling (cmc);
6996 /* sanity check on origin time */
6997 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
6998 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
6999 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7001 GNUNET_break_op (0);
7002 finish_cmc_handling (cmc);
7007 /* check signature */
7008 struct TransportValidationPS tvp =
7009 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7010 .purpose.size = htonl (sizeof (tvp)),
7011 .validity_duration = tvr->validity_duration,
7012 .challenge = tvr->challenge};
7016 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7019 &cmc->im.sender.public_key))
7021 GNUNET_break_op (0);
7022 finish_cmc_handling (cmc);
7027 /* validity is capped by our willingness to keep track of the
7028 validation entry and the maximum the other peer allows */
7029 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7030 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7031 tvr->validity_duration),
7032 MAX_ADDRESS_VALID_UNTIL));
7033 vs->validated_until =
7034 GNUNET_TIME_absolute_min (vs->valid_until,
7035 GNUNET_TIME_relative_to_absolute (
7036 ADDRESS_VALIDATION_LIFETIME));
7037 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7038 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7039 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7041 sizeof (vs->challenge));
7042 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7043 vs->validated_until,
7044 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7045 VALIDATION_RTT_BUFFER_FACTOR));
7046 vs->last_challenge_use =
7047 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7048 update_next_challenge_time (vs, vs->first_challenge_use);
7049 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7052 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7054 strlen (vs->address) + 1,
7056 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7057 &peerstore_store_validation_cb,
7059 finish_cmc_handling (cmc);
7061 /* Finally, we now possibly have a confirmed (!) working queue,
7062 update queue status (if queue still is around) */
7063 q = find_queue (&vs->pid, vs->address);
7066 GNUNET_STATISTICS_update (GST_stats,
7067 "# Queues lost at time of successful validation",
7072 q->validated_until = vs->validated_until;
7073 q->pd.aged_rtt = vs->validation_rtt;
7075 if (GNUNET_NO != n->core_visible)
7076 return; /* nothing changed, we are done here */
7077 n->core_visible = GNUNET_YES;
7078 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
7079 &core_queue_visibility_check,
7081 /* Check if _any_ DV route to this neighbour is
7082 currently valid, if so, do NOT tell core anything! */
7083 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
7084 if ((NULL != dv) && (GNUNET_YES == dv->core_visible))
7085 return; /* nothing changed, done */
7086 /* We lacked a confirmed connection to the neighbour
7087 before, so tell CORE about it (finally!) */
7088 cores_send_connect_info (&n->pid,
7090 ? GNUNET_BANDWIDTH_value_sum (dv->quota_out,
7097 * Incoming meessage. Process the request.
7099 * @param im the send message that was received
7102 handle_incoming_msg (void *cls,
7103 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7105 struct TransportClient *tc = cls;
7106 struct CommunicatorMessageContext *cmc =
7107 GNUNET_new (struct CommunicatorMessageContext);
7111 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7116 * Given an inbound message @a msg from a communicator @a cmc,
7117 * demultiplex it based on the type calling the right handler.
7119 * @param cmc context for demultiplexing
7120 * @param msg message to demultiplex
7123 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7124 const struct GNUNET_MessageHeader *msg)
7126 struct GNUNET_MQ_MessageHandler handlers[] =
7127 {GNUNET_MQ_hd_var_size (fragment_box,
7128 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7129 struct TransportFragmentBoxMessage,
7131 GNUNET_MQ_hd_var_size (reliability_box,
7132 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7133 struct TransportReliabilityBoxMessage,
7135 GNUNET_MQ_hd_var_size (reliability_ack,
7136 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7137 struct TransportReliabilityAckMessage,
7139 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7140 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7141 struct TransportBackchannelEncapsulationMessage,
7143 GNUNET_MQ_hd_var_size (dv_learn,
7144 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7145 struct TransportDVLearnMessage,
7147 GNUNET_MQ_hd_var_size (dv_box,
7148 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7149 struct TransportDVBoxMessage,
7151 GNUNET_MQ_hd_fixed_size (
7152 validation_challenge,
7153 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7154 struct TransportValidationChallengeMessage,
7156 GNUNET_MQ_hd_fixed_size (
7157 validation_response,
7158 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7159 struct TransportValidationResponseMessage,
7161 GNUNET_MQ_handler_end ()};
7164 ret = GNUNET_MQ_handle_message (handlers, msg);
7165 if (GNUNET_SYSERR == ret)
7168 GNUNET_SERVICE_client_drop (cmc->tc->client);
7172 if (GNUNET_NO == ret)
7174 /* unencapsulated 'raw' message */
7175 handle_raw_message (&cmc, msg);
7181 * New queue became available. Check message.
7183 * @param cls the client
7184 * @param aqm the send message that was sent
7187 check_add_queue_message (void *cls,
7188 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7190 struct TransportClient *tc = cls;
7192 if (CT_COMMUNICATOR != tc->type)
7195 return GNUNET_SYSERR;
7197 GNUNET_MQ_check_zero_termination (aqm);
7203 * Bandwidth tracker informs us that the delay until we should receive
7206 * @param cls a `struct Queue` for which the delay changed
7209 tracker_update_in_cb (void *cls)
7211 struct Queue *queue = cls;
7212 struct GNUNET_TIME_Relative in_delay;
7215 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
7216 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
7217 // FIXME: how exactly do we do inbound flow control?
7222 * If necessary, generates the UUID for a @a pm
7224 * @param pm pending message to generate UUID for.
7227 set_pending_message_uuid (struct PendingMessage *pm)
7229 if (pm->msg_uuid_set)
7231 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7233 sizeof (pm->msg_uuid));
7234 pm->msg_uuid_set = GNUNET_YES;
7239 * Setup data structure waiting for acknowledgements.
7241 * @param queue queue the @a pm will be sent over
7242 * @param dvh path the message will take, may be NULL
7243 * @param pm the pending message for transmission
7244 * @return corresponding fresh pending acknowledgement
7246 static struct PendingAcknowledgement *
7247 prepare_pending_acknowledgement (struct Queue *queue,
7248 struct DistanceVectorHop *dvh,
7249 struct PendingMessage *pm)
7251 struct PendingAcknowledgement *pa;
7253 pa = GNUNET_new (struct PendingAcknowledgement);
7259 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7261 sizeof (pa->ack_uuid));
7262 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7264 &pa->ack_uuid.value,
7266 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7267 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7268 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7270 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7271 pa->transmission_time = GNUNET_TIME_absolute_get ();
7272 pa->message_size = pm->bytes_msg;
7278 * Fragment the given @a pm to the given @a mtu. Adds
7279 * additional fragments to the neighbour as well. If the
7280 * @a mtu is too small, generates and error for the @a pm
7283 * @param queue which queue to fragment for
7284 * @param dvh path the message will take, or NULL
7285 * @param pm pending message to fragment for transmission
7286 * @return new message to transmit
7288 static struct PendingMessage *
7289 fragment_message (struct Queue *queue,
7290 struct DistanceVectorHop *dvh,
7291 struct PendingMessage *pm)
7293 struct PendingAcknowledgement *pa;
7294 struct PendingMessage *ff;
7297 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7298 mtu = (0 == queue->mtu)
7299 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7301 set_pending_message_uuid (pm);
7303 /* This invariant is established in #handle_add_queue_message() */
7304 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7306 /* select fragment for transmission, descending the tree if it has
7307 been expanded until we are at a leaf or at a fragment that is small
7311 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7312 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7314 ff = ff->head_frag; /* descent into fragmented fragments */
7317 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7319 /* Did not yet calculate all fragments, calculate next fragment */
7320 struct PendingMessage *frag;
7321 struct TransportFragmentBoxMessage tfb;
7329 orig = (const char *) &ff[1];
7330 msize = ff->bytes_msg;
7333 const struct TransportFragmentBoxMessage *tfbo;
7335 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7336 orig += sizeof (struct TransportFragmentBoxMessage);
7337 msize -= sizeof (struct TransportFragmentBoxMessage);
7338 xoff = ntohs (tfbo->frag_off);
7340 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7341 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7343 GNUNET_malloc (sizeof (struct PendingMessage) +
7344 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7345 frag->target = pm->target;
7346 frag->frag_parent = ff;
7347 frag->timeout = pm->timeout;
7348 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7349 frag->pmt = PMT_FRAGMENT_BOX;
7350 msg = (char *) &frag[1];
7351 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7353 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7354 tfb.ack_uuid = pa->ack_uuid;
7355 tfb.msg_uuid = pm->msg_uuid;
7356 tfb.frag_off = htons (ff->frag_off + xoff);
7357 tfb.msg_size = htons (pm->bytes_msg);
7358 memcpy (msg, &tfb, sizeof (tfb));
7359 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7360 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7361 ff->frag_off += fragsize;
7365 /* Move head to the tail and return it */
7366 GNUNET_CONTAINER_MDLL_remove (frag,
7367 ff->frag_parent->head_frag,
7368 ff->frag_parent->tail_frag,
7370 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7371 ff->frag_parent->head_frag,
7372 ff->frag_parent->tail_frag,
7379 * Reliability-box the given @a pm. On error (can there be any), NULL
7380 * may be returned, otherwise the "replacement" for @a pm (which
7381 * should then be added to the respective neighbour's queue instead of
7382 * @a pm). If the @a pm is already fragmented or reliability boxed,
7383 * or itself an ACK, this function simply returns @a pm.
7385 * @param queue which queue to prepare transmission for
7386 * @param dvh path the message will take, or NULL
7387 * @param pm pending message to box for transmission over unreliabile queue
7388 * @return new message to transmit
7390 static struct PendingMessage *
7391 reliability_box_message (struct Queue *queue,
7392 struct DistanceVectorHop *dvh,
7393 struct PendingMessage *pm)
7395 struct TransportReliabilityBoxMessage rbox;
7396 struct PendingAcknowledgement *pa;
7397 struct PendingMessage *bpm;
7400 if (PMT_CORE != pm->pmt)
7401 return pm; /* already fragmented or reliability boxed, or control message:
7403 if (NULL != pm->bpm)
7404 return pm->bpm; /* already computed earlier: do nothing */
7405 GNUNET_assert (NULL == pm->head_frag);
7406 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7410 client_send_response (pm, GNUNET_NO, 0);
7413 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7415 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7417 bpm->target = pm->target;
7418 bpm->frag_parent = pm;
7419 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7420 bpm->timeout = pm->timeout;
7421 bpm->pmt = PMT_RELIABILITY_BOX;
7422 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7423 set_pending_message_uuid (bpm);
7424 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7425 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7426 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7428 rbox.ack_uuid = pa->ack_uuid;
7429 msg = (char *) &bpm[1];
7430 memcpy (msg, &rbox, sizeof (rbox));
7431 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7438 * Change the value of the `next_attempt` field of @a pm
7439 * to @a next_attempt and re-order @a pm in the transmission
7440 * list as required by the new timestmap.
7442 * @param pm a pending message to update
7443 * @param next_attempt timestamp to use
7446 update_pm_next_attempt (struct PendingMessage *pm,
7447 struct GNUNET_TIME_Absolute next_attempt)
7449 struct Neighbour *neighbour = pm->target;
7451 pm->next_attempt = next_attempt;
7452 if (NULL == pm->frag_parent)
7454 struct PendingMessage *pos;
7456 /* re-insert sort in neighbour list */
7457 GNUNET_CONTAINER_MDLL_remove (neighbour,
7458 neighbour->pending_msg_head,
7459 neighbour->pending_msg_tail,
7461 pos = neighbour->pending_msg_tail;
7462 while ((NULL != pos) &&
7463 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7464 pos = pos->prev_neighbour;
7465 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7466 neighbour->pending_msg_head,
7467 neighbour->pending_msg_tail,
7473 /* re-insert sort in fragment list */
7474 struct PendingMessage *fp = pm->frag_parent;
7475 struct PendingMessage *pos;
7477 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7478 pos = fp->tail_frag;
7479 while ((NULL != pos) &&
7480 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7481 pos = pos->prev_frag;
7482 GNUNET_CONTAINER_MDLL_insert_after (frag,
7492 * We believe we are ready to transmit a message on a queue. Double-checks
7493 * with the queue's "tracker_out" and then gives the message to the
7494 * communicator for transmission (updating the tracker, and re-scheduling
7495 * itself if applicable).
7497 * @param cls the `struct Queue` to process transmissions for
7500 transmit_on_queue (void *cls)
7502 struct Queue *queue = cls;
7503 struct Neighbour *n = queue->neighbour;
7504 struct PendingMessage *pm;
7505 struct PendingMessage *s;
7508 queue->transmit_task = NULL;
7509 if (NULL == (pm = n->pending_msg_head))
7511 /* no message pending, nothing to do here! */
7516 /* message still pending with communciator!
7517 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7520 schedule_transmit_on_queue (queue, GNUNET_YES);
7521 if (NULL != queue->transmit_task)
7522 return; /* do it later */
7524 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7525 overhead += sizeof (struct TransportReliabilityBoxMessage);
7527 if ( ( (0 != queue->mtu) &&
7528 (pm->bytes_msg + overhead > queue->mtu) ) ||
7529 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7530 (NULL != pm->head_frag /* fragments already exist, should
7531 respect that even if MTU is 0 for
7533 s = fragment_message (queue, pm->dvh, s);
7536 /* Fragmentation failed, try next message... */
7537 schedule_transmit_on_queue (queue, GNUNET_NO);
7540 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7541 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7542 s = reliability_box_message (queue, pm->dvh, s);
7545 /* Reliability boxing failed, try next message... */
7546 schedule_transmit_on_queue (queue, GNUNET_NO);
7550 /* Pass 's' for transission to the communicator */
7551 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7552 // FIXME: do something similar to the logic below
7553 // in defragmentation / reliability ACK handling!
7555 /* Check if this transmission somehow conclusively finished handing 'pm'
7556 even without any explicit ACKs */
7557 if ((PMT_CORE == s->pmt) &&
7558 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7560 /* Full message sent, and over reliabile channel */
7561 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
7563 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7564 queue->tc->details.communicator.cc) &&
7565 (PMT_FRAGMENT_BOX == s->pmt))
7567 struct PendingMessage *pos;
7569 /* Fragment sent over reliabile channel */
7570 free_fragment_tree (s);
7571 pos = s->frag_parent;
7572 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7574 /* check if subtree is done */
7575 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7579 pos = s->frag_parent;
7580 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7584 /* Was this the last applicable fragmment? */
7585 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7586 client_send_response (
7589 pm->bytes_msg /* FIXME: calculate and add overheads! */);
7591 else if (PMT_CORE != pm->pmt)
7593 /* This was an acknowledgement of some type, always free */
7594 free_pending_message (pm);
7598 /* Message not finished, waiting for acknowledgement.
7599 Update time by which we might retransmit 's' based on queue
7600 characteristics (i.e. RTT); it takes one RTT for the message to
7601 arrive and the ACK to come back in the best case; but the other
7602 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7603 retransmitting. Note that in the future this heuristic should
7604 likely be improved further (measure RTT stability, consider
7605 message urgency and size when delaying ACKs, etc.) */
7606 update_pm_next_attempt (s,
7607 GNUNET_TIME_relative_to_absolute (
7608 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7612 /* finally, re-schedule queue transmission task itself */
7613 schedule_transmit_on_queue (queue, GNUNET_NO);
7618 * Bandwidth tracker informs us that the delay until we
7619 * can transmit again changed.
7621 * @param cls a `struct Queue` for which the delay changed
7624 tracker_update_out_cb (void *cls)
7626 struct Queue *queue = cls;
7627 struct Neighbour *n = queue->neighbour;
7629 if (NULL == n->pending_msg_head)
7631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7632 "Bandwidth allocation updated for empty transmission queue `%s'\n",
7634 return; /* no message pending, nothing to do here! */
7636 GNUNET_SCHEDULER_cancel (queue->transmit_task);
7637 queue->transmit_task = NULL;
7638 schedule_transmit_on_queue (queue, GNUNET_NO);
7643 * Bandwidth tracker informs us that excessive outbound bandwidth was
7644 * allocated which is not being used.
7646 * @param cls a `struct Queue` for which the excess was noted
7649 tracker_excess_out_cb (void *cls)
7653 /* FIXME: trigger excess bandwidth report to core? Right now,
7654 this is done internally within transport_api2_core already,
7655 but we probably want to change the logic and trigger it
7656 from here via a message instead! */
7657 /* TODO: maybe inform someone at this point? */
7658 GNUNET_STATISTICS_update (GST_stats,
7659 "# Excess outbound bandwidth reported",
7666 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
7667 * which is not being used.
7669 * @param cls a `struct Queue` for which the excess was noted
7672 tracker_excess_in_cb (void *cls)
7676 /* TODO: maybe inform somone at this point? */
7677 GNUNET_STATISTICS_update (GST_stats,
7678 "# Excess inbound bandwidth reported",
7685 * Queue to a peer went down. Process the request.
7687 * @param cls the client
7688 * @param dqm the send message that was sent
7691 handle_del_queue_message (void *cls,
7692 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7694 struct TransportClient *tc = cls;
7696 if (CT_COMMUNICATOR != tc->type)
7699 GNUNET_SERVICE_client_drop (tc->client);
7702 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7703 queue = queue->next_client)
7705 struct Neighbour *neighbour = queue->neighbour;
7707 if ((dqm->qid != queue->qid) ||
7708 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7711 GNUNET_SERVICE_client_continue (tc->client);
7715 GNUNET_SERVICE_client_drop (tc->client);
7720 * Message was transmitted. Process the request.
7722 * @param cls the client
7723 * @param sma the send message that was sent
7726 handle_send_message_ack (void *cls,
7727 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7729 struct TransportClient *tc = cls;
7730 struct QueueEntry *qe;
7731 struct PendingMessage *pm;
7733 if (CT_COMMUNICATOR != tc->type)
7736 GNUNET_SERVICE_client_drop (tc->client);
7740 /* find our queue entry matching the ACK */
7742 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7743 queue = queue->next_client)
7745 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7747 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7750 if (qep->mid != sma->mid)
7759 /* this should never happen */
7761 GNUNET_SERVICE_client_drop (tc->client);
7764 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7765 qe->queue->queue_tail,
7767 qe->queue->queue_length--;
7768 tc->details.communicator.total_queue_length--;
7769 GNUNET_SERVICE_client_continue (tc->client);
7771 /* if applicable, resume transmissions that waited on ACK */
7772 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7773 tc->details.communicator.total_queue_length)
7775 /* Communicator dropped below threshold, resume all queues
7776 incident with this client! */
7777 GNUNET_STATISTICS_update (
7779 "# Transmission throttled due to communicator queue limit",
7782 for (struct Queue *queue = tc->details.communicator.queue_head;
7784 queue = queue->next_client)
7785 schedule_transmit_on_queue (queue, GNUNET_NO);
7787 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7789 /* queue dropped below threshold; only resume this one queue */
7790 GNUNET_STATISTICS_update (GST_stats,
7791 "# Transmission throttled due to queue queue limit",
7794 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7797 if (NULL != (pm = qe->pm))
7799 struct Neighbour *n;
7801 GNUNET_assert (qe == pm->qe);
7803 /* If waiting for this communicator may have blocked transmission
7804 of pm on other queues for this neighbour, force schedule
7805 transmit on queue for queues of the neighbour */
7807 if (n->pending_msg_head == pm)
7809 for (struct Queue *queue = n->queue_head; NULL != queue;
7810 queue = queue->next_neighbour)
7811 schedule_transmit_on_queue (queue, GNUNET_NO);
7813 if (GNUNET_OK != ntohl (sma->status))
7816 GNUNET_ERROR_TYPE_INFO,
7817 "Queue failed in transmission, will try retransmission immediately\n");
7818 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7826 * Iterator telling new MONITOR client about all existing
7829 * @param cls the new `struct TransportClient`
7830 * @param pid a connected peer
7831 * @param value the `struct Neighbour` with more information
7832 * @return #GNUNET_OK (continue to iterate)
7835 notify_client_queues (void *cls,
7836 const struct GNUNET_PeerIdentity *pid,
7839 struct TransportClient *tc = cls;
7840 struct Neighbour *neighbour = value;
7842 GNUNET_assert (CT_MONITOR == tc->type);
7843 for (struct Queue *q = neighbour->queue_head; NULL != q;
7844 q = q->next_neighbour)
7846 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7848 .num_msg_pending = q->num_msg_pending,
7849 .num_bytes_pending = q->num_bytes_pending};
7851 notify_monitor (tc, pid, q->address, q->nt, &me);
7858 * Initialize a monitor client.
7860 * @param cls the client
7861 * @param start the start message that was sent
7864 handle_monitor_start (void *cls,
7865 const struct GNUNET_TRANSPORT_MonitorStart *start)
7867 struct TransportClient *tc = cls;
7869 if (CT_NONE != tc->type)
7872 GNUNET_SERVICE_client_drop (tc->client);
7875 tc->type = CT_MONITOR;
7876 tc->details.monitor.peer = start->peer;
7877 tc->details.monitor.one_shot = ntohl (start->one_shot);
7878 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
7879 GNUNET_SERVICE_client_mark_monitor (tc->client);
7880 GNUNET_SERVICE_client_continue (tc->client);
7885 * Find transport client providing communication service
7886 * for the protocol @a prefix.
7888 * @param prefix communicator name
7889 * @return NULL if no such transport client is available
7891 static struct TransportClient *
7892 lookup_communicator (const char *prefix)
7894 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7896 if (CT_COMMUNICATOR != tc->type)
7898 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
7902 GNUNET_ERROR_TYPE_WARNING,
7903 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
7910 * Signature of a function called with a communicator @a address of a peer
7911 * @a pid that an application wants us to connect to.
7913 * @param pid target peer
7914 * @param address the address to try
7917 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
7919 static uint32_t idgen;
7920 struct TransportClient *tc;
7922 struct GNUNET_TRANSPORT_CreateQueue *cqm;
7923 struct GNUNET_MQ_Envelope *env;
7926 prefix = GNUNET_HELLO_address_to_prefix (address);
7929 GNUNET_break (0); /* We got an invalid address!? */
7932 tc = lookup_communicator (prefix);
7935 GNUNET_STATISTICS_update (GST_stats,
7936 "# Suggestions ignored due to missing communicator",
7941 /* forward suggestion for queue creation to communicator */
7942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7943 "Request #%u for `%s' communicator to create queue to `%s'\n",
7944 (unsigned int) idgen,
7947 alen = strlen (address) + 1;
7949 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
7950 cqm->request_id = htonl (idgen++);
7951 cqm->receiver = *pid;
7952 memcpy (&cqm[1], address, alen);
7953 GNUNET_MQ_send (tc->mq, env);
7958 * The queue @a q (which matches the peer and address in @a vs) is
7959 * ready for queueing. We should now queue the validation request.
7961 * @param q queue to send on
7962 * @param vs state to derive validation challenge from
7965 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
7967 struct TransportValidationChallengeMessage tvc;
7969 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
7971 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
7972 tvc.header.size = htons (sizeof (tvc));
7973 tvc.reserved = htonl (0);
7974 tvc.challenge = vs->challenge;
7975 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
7976 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7981 * Task run periodically to validate some address based on #validation_heap.
7986 validation_start_cb (void *cls)
7988 struct ValidationState *vs;
7992 validation_task = NULL;
7993 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7994 /* drop validations past their expiration */
7997 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7999 free_validation_state (vs);
8000 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
8003 return; /* woopsie, no more addresses known, should only
8004 happen if we're really a lonely peer */
8005 q = find_queue (&vs->pid, vs->address);
8008 vs->awaiting_queue = GNUNET_YES;
8009 suggest_to_connect (&vs->pid, vs->address);
8012 validation_transmit_on_queue (q, vs);
8013 /* Finally, reschedule next attempt */
8014 vs->challenge_backoff =
8015 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
8016 MAX_VALIDATION_CHALLENGE_FREQ);
8017 update_next_challenge_time (vs,
8018 GNUNET_TIME_relative_to_absolute (
8019 vs->challenge_backoff));
8024 * Closure for #check_connection_quality.
8026 struct QueueQualityContext
8029 * Set to the @e k'th queue encountered.
8034 * Set to the number of quality queues encountered.
8036 unsigned int quality_count;
8039 * Set to the total number of queues encountered.
8041 unsigned int num_queues;
8044 * Decremented for each queue, for selection of the
8045 * k-th queue in @e q.
8052 * Check whether any queue to the given neighbour is
8053 * of a good "quality" and if so, increment the counter.
8054 * Also counts the total number of queues, and returns
8055 * the k-th queue found.
8057 * @param cls a `struct QueueQualityContext *` with counters
8058 * @param pid peer this is about
8059 * @param value a `struct Neighbour`
8060 * @return #GNUNET_OK (continue to iterate)
8063 check_connection_quality (void *cls,
8064 const struct GNUNET_PeerIdentity *pid,
8067 struct QueueQualityContext *ctx = cls;
8068 struct Neighbour *n = value;
8073 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8078 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
8079 statistics and consider those as well here? */
8080 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
8081 do_inc = GNUNET_YES;
8083 if (GNUNET_YES == do_inc)
8084 ctx->quality_count++;
8090 * Task run when we CONSIDER initiating a DV learn
8091 * process. We first check that sending out a message is
8092 * even possible (queues exist), then that it is desirable
8093 * (if not, reschedule the task for later), and finally
8094 * we may then begin the job. If there are too many
8095 * entries in the #dvlearn_map, we purge the oldest entry
8101 start_dv_learn (void *cls)
8103 struct LearnLaunchEntry *lle;
8104 struct QueueQualityContext qqc;
8105 struct TransportDVLearnMessage dvl;
8108 dvlearn_task = NULL;
8109 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8110 return; /* lost all connectivity, cannot do learning */
8111 qqc.quality_count = 0;
8113 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8114 &check_connection_quality,
8116 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8118 struct GNUNET_TIME_Relative delay;
8119 unsigned int factor;
8121 /* scale our retries by how far we are above the threshold */
8122 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8123 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8124 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8127 /* remove old entries in #dvlearn_map if it has grown too big */
8128 while (MAX_DV_LEARN_PENDING >=
8129 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8132 GNUNET_assert (GNUNET_YES ==
8133 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8134 &lle->challenge.value,
8136 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8139 /* setup data structure for learning */
8140 lle = GNUNET_new (struct LearnLaunchEntry);
8141 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8143 sizeof (lle->challenge));
8144 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8145 GNUNET_break (GNUNET_YES ==
8146 GNUNET_CONTAINER_multishortmap_put (
8148 &lle->challenge.value,
8150 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8151 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8152 dvl.header.size = htons (sizeof (dvl));
8153 dvl.num_hops = htons (0);
8154 dvl.bidirectional = htons (0);
8155 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8156 dvl.monotonic_time =
8157 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8159 struct DvInitPS dvip = {.purpose.purpose = htonl (
8160 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8161 .purpose.size = htonl (sizeof (dvip)),
8162 .monotonic_time = dvl.monotonic_time,
8163 .challenge = lle->challenge};
8165 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8169 dvl.initiator = GST_my_identity;
8170 dvl.challenge = lle->challenge;
8172 qqc.quality_count = 0;
8173 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8176 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8177 &check_connection_quality,
8179 GNUNET_assert (NULL != qqc.q);
8181 /* Do this as close to transmission time as possible! */
8182 lle->launch_time = GNUNET_TIME_absolute_get ();
8184 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8185 /* reschedule this job, randomizing the time it runs (but no
8187 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8188 DV_LEARN_BASE_FREQUENCY),
8195 * A new queue has been created, check if any address validation
8196 * requests have been waiting for it.
8198 * @param cls a `struct Queue`
8199 * @param pid peer concerned (unused)
8200 * @param value a `struct ValidationState`
8201 * @return #GNUNET_NO if a match was found and we can stop looking
8204 check_validation_request_pending (void *cls,
8205 const struct GNUNET_PeerIdentity *pid,
8208 struct Queue *q = cls;
8209 struct ValidationState *vs = value;
8212 if ((GNUNET_YES == vs->awaiting_queue) &&
8213 (0 == strcmp (vs->address, q->address)))
8215 vs->awaiting_queue = GNUNET_NO;
8216 validation_transmit_on_queue (q, vs);
8224 * Function called with the monotonic time of a DV initiator
8225 * by PEERSTORE. Updates the time.
8227 * @param cls a `struct Neighbour`
8228 * @param record the information found, NULL for the last call
8229 * @param emsg error message
8232 neighbour_dv_monotime_cb (void *cls,
8233 const struct GNUNET_PEERSTORE_Record *record,
8236 struct Neighbour *n = cls;
8237 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8238 struct GNUNET_TIME_Absolute mt;
8243 /* we're done with #neighbour_dv_monotime_cb() invocations,
8244 continue normal processing */
8246 n->dv_monotime_available = GNUNET_YES;
8249 if (sizeof (*mtbe) != record->value_size)
8254 mtbe = record->value;
8255 n->last_dv_learn_monotime =
8256 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8257 GNUNET_TIME_absolute_ntoh (*mtbe));
8262 * New queue became available. Process the request.
8264 * @param cls the client
8265 * @param aqm the send message that was sent
8268 handle_add_queue_message (void *cls,
8269 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8271 struct TransportClient *tc = cls;
8272 struct Queue *queue;
8273 struct Neighbour *neighbour;
8277 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8279 /* MTU so small as to be useless for transmissions,
8280 required for #fragment_message()! */
8281 GNUNET_break_op (0);
8282 GNUNET_SERVICE_client_drop (tc->client);
8285 neighbour = lookup_neighbour (&aqm->receiver);
8286 if (NULL == neighbour)
8288 neighbour = GNUNET_new (struct Neighbour);
8289 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
8290 neighbour->pid = aqm->receiver;
8291 GNUNET_assert (GNUNET_OK ==
8292 GNUNET_CONTAINER_multipeermap_put (
8296 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8298 GNUNET_PEERSTORE_iterate (peerstore,
8301 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8302 &neighbour_dv_monotime_cb,
8305 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8306 addr = (const char *) &aqm[1];
8308 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8310 queue->address = (const char *) &queue[1];
8311 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8312 queue->qid = aqm->qid;
8313 queue->mtu = ntohl (aqm->mtu);
8314 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8315 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8316 queue->neighbour = neighbour;
8317 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
8318 &tracker_update_in_cb,
8320 GNUNET_BANDWIDTH_ZERO,
8321 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
8322 &tracker_excess_in_cb,
8324 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
8325 &tracker_update_out_cb,
8327 GNUNET_BANDWIDTH_ZERO,
8328 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
8329 &tracker_excess_out_cb,
8331 memcpy (&queue[1], addr, addr_len);
8332 /* notify monitors about new queue */
8334 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8336 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8338 GNUNET_CONTAINER_MDLL_insert (neighbour,
8339 neighbour->queue_head,
8340 neighbour->queue_tail,
8342 GNUNET_CONTAINER_MDLL_insert (client,
8343 tc->details.communicator.queue_head,
8344 tc->details.communicator.queue_tail,
8346 /* check if valdiations are waiting for the queue */
8348 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8350 &check_validation_request_pending,
8352 /* might be our first queue, try launching DV learning */
8353 if (NULL == dvlearn_task)
8354 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8355 GNUNET_SERVICE_client_continue (tc->client);
8360 * Communicator tells us that our request to create a queue "worked", that
8361 * is setting up the queue is now in process.
8363 * @param cls the `struct TransportClient`
8364 * @param cqr confirmation message
8367 handle_queue_create_ok (void *cls,
8368 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8370 struct TransportClient *tc = cls;
8372 if (CT_COMMUNICATOR != tc->type)
8375 GNUNET_SERVICE_client_drop (tc->client);
8378 GNUNET_STATISTICS_update (GST_stats,
8379 "# Suggestions succeeded at communicator",
8382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8383 "Request #%u for communicator to create queue succeeded\n",
8384 (unsigned int) ntohs (cqr->request_id));
8385 GNUNET_SERVICE_client_continue (tc->client);
8390 * Communicator tells us that our request to create a queue failed. This
8391 * usually indicates that the provided address is simply invalid or that the
8392 * communicator's resources are exhausted.
8394 * @param cls the `struct TransportClient`
8395 * @param cqr failure message
8398 handle_queue_create_fail (
8400 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8402 struct TransportClient *tc = cls;
8404 if (CT_COMMUNICATOR != tc->type)
8407 GNUNET_SERVICE_client_drop (tc->client);
8410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8411 "Request #%u for communicator to create queue failed\n",
8412 (unsigned int) ntohs (cqr->request_id));
8413 GNUNET_STATISTICS_update (GST_stats,
8414 "# Suggestions failed in queue creation at communicator",
8417 GNUNET_SERVICE_client_continue (tc->client);
8422 * We have received a `struct ExpressPreferenceMessage` from an application
8425 * @param cls handle to the client
8426 * @param msg the start message
8429 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8431 struct TransportClient *tc = cls;
8432 struct PeerRequest *pr;
8434 if (CT_APPLICATION != tc->type)
8437 GNUNET_SERVICE_client_drop (tc->client);
8440 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8445 GNUNET_SERVICE_client_drop (tc->client);
8448 (void) stop_peer_request (tc, &pr->pid, pr);
8449 GNUNET_SERVICE_client_continue (tc->client);
8454 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8455 * messages. We do nothing here, real verification is done later.
8457 * @param cls a `struct TransportClient *`
8458 * @param msg message to verify
8459 * @return #GNUNET_OK
8462 check_address_consider_verify (
8464 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8473 * Closure for #check_known_address.
8475 struct CheckKnownAddressContext
8478 * Set to the address we are looking for.
8480 const char *address;
8483 * Set to a matching validation state, if one was found.
8485 struct ValidationState *vs;
8490 * Test if the validation state in @a value matches the
8491 * address from @a cls.
8493 * @param cls a `struct CheckKnownAddressContext`
8494 * @param pid unused (must match though)
8495 * @param value a `struct ValidationState`
8496 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8499 check_known_address (void *cls,
8500 const struct GNUNET_PeerIdentity *pid,
8503 struct CheckKnownAddressContext *ckac = cls;
8504 struct ValidationState *vs = value;
8507 if (0 != strcmp (vs->address, ckac->address))
8515 * Start address validation.
8517 * @param pid peer the @a address is for
8518 * @param address an address to reach @a pid (presumably)
8519 * @param expiration when did @a pid claim @a address will become invalid
8522 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8523 const char *address,
8524 struct GNUNET_TIME_Absolute expiration)
8526 struct GNUNET_TIME_Absolute now;
8527 struct ValidationState *vs;
8528 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8530 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
8531 return; /* expired */
8532 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8534 &check_known_address,
8536 if (NULL != (vs = ckac.vs))
8538 /* if 'vs' is not currently valid, we need to speed up retrying the
8540 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8542 /* reduce backoff as we got a fresh advertisement */
8543 vs->challenge_backoff =
8544 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8545 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8547 update_next_challenge_time (vs,
8548 GNUNET_TIME_relative_to_absolute (
8549 vs->challenge_backoff));
8553 now = GNUNET_TIME_absolute_get ();
8554 vs = GNUNET_new (struct ValidationState);
8556 vs->valid_until = expiration;
8557 vs->first_challenge_use = now;
8558 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8559 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8561 sizeof (vs->challenge));
8562 vs->address = GNUNET_strdup (address);
8563 GNUNET_assert (GNUNET_YES ==
8564 GNUNET_CONTAINER_multipeermap_put (
8568 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8569 update_next_challenge_time (vs, now);
8574 * Function called by PEERSTORE for each matching record.
8576 * @param cls closure
8577 * @param record peerstore record information
8578 * @param emsg error message, or NULL if no errors
8581 handle_hello (void *cls,
8582 const struct GNUNET_PEERSTORE_Record *record,
8585 struct PeerRequest *pr = cls;
8590 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8591 "Got failure from PEERSTORE: %s\n",
8595 val = record->value;
8596 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8601 start_address_validation (&pr->pid,
8602 (const char *) record->value,
8608 * We have received a `struct ExpressPreferenceMessage` from an application
8611 * @param cls handle to the client
8612 * @param msg the start message
8615 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8617 struct TransportClient *tc = cls;
8618 struct PeerRequest *pr;
8620 if (CT_NONE == tc->type)
8622 tc->type = CT_APPLICATION;
8623 tc->details.application.requests =
8624 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8626 if (CT_APPLICATION != tc->type)
8629 GNUNET_SERVICE_client_drop (tc->client);
8632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8633 "Client suggested we talk to %s with preference %d at rate %u\n",
8634 GNUNET_i2s (&msg->peer),
8635 (int) ntohl (msg->pk),
8636 (int) ntohl (msg->bw.value__));
8637 pr = GNUNET_new (struct PeerRequest);
8639 pr->pid = msg->peer;
8641 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
8642 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8643 tc->details.application.requests,
8646 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8650 GNUNET_SERVICE_client_drop (tc->client);
8653 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8656 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8659 GNUNET_SERVICE_client_continue (tc->client);
8664 * Given another peers address, consider checking it for validity
8665 * and then adding it to the Peerstore.
8667 * @param cls a `struct TransportClient`
8668 * @param hdr message containing the raw address data and
8669 * signature in the body, see #GNUNET_HELLO_extract_address()
8672 handle_address_consider_verify (
8674 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8676 struct TransportClient *tc = cls;
8678 enum GNUNET_NetworkType nt;
8679 struct GNUNET_TIME_Absolute expiration;
8682 // OPTIMIZE-FIXME: checking that we know this address already should
8683 // be done BEFORE checking the signature => HELLO API change!
8684 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8687 GNUNET_HELLO_extract_address (&hdr[1],
8688 ntohs (hdr->header.size) - sizeof (*hdr),
8692 if (NULL == address)
8694 GNUNET_break_op (0);
8697 start_address_validation (&hdr->peer, address, expiration);
8698 GNUNET_free (address);
8699 GNUNET_SERVICE_client_continue (tc->client);
8704 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8707 * @param cls a `struct TransportClient *`
8708 * @param m message to verify
8709 * @return #GNUNET_OK on success
8712 check_request_hello_validation (void *cls,
8713 const struct RequestHelloValidationMessage *m)
8716 GNUNET_MQ_check_zero_termination (m);
8722 * A client encountered an address of another peer. Consider validating it,
8723 * and if validation succeeds, persist it to PEERSTORE.
8725 * @param cls a `struct TransportClient *`
8726 * @param m message to verify
8729 handle_request_hello_validation (void *cls,
8730 const struct RequestHelloValidationMessage *m)
8732 struct TransportClient *tc = cls;
8734 start_address_validation (&m->peer,
8735 (const char *) &m[1],
8736 GNUNET_TIME_absolute_ntoh (m->expiration));
8737 GNUNET_SERVICE_client_continue (tc->client);
8742 * Free neighbour entry.
8746 * @param value a `struct Neighbour`
8747 * @return #GNUNET_OK (always)
8750 free_neighbour_cb (void *cls,
8751 const struct GNUNET_PeerIdentity *pid,
8754 struct Neighbour *neighbour = value;
8758 GNUNET_break (0); // should this ever happen?
8759 free_neighbour (neighbour);
8766 * Free DV route entry.
8770 * @param value a `struct DistanceVector`
8771 * @return #GNUNET_OK (always)
8774 free_dv_routes_cb (void *cls,
8775 const struct GNUNET_PeerIdentity *pid,
8778 struct DistanceVector *dv = value;
8789 * Free ephemeral entry.
8793 * @param value a `struct EphemeralCacheEntry`
8794 * @return #GNUNET_OK (always)
8797 free_ephemeral_cb (void *cls,
8798 const struct GNUNET_PeerIdentity *pid,
8801 struct EphemeralCacheEntry *ece = value;
8805 free_ephemeral (ece);
8811 * Free validation state.
8815 * @param value a `struct ValidationState`
8816 * @return #GNUNET_OK (always)
8819 free_validation_state_cb (void *cls,
8820 const struct GNUNET_PeerIdentity *pid,
8823 struct ValidationState *vs = value;
8827 free_validation_state (vs);
8833 * Free pending acknowledgement.
8837 * @param value a `struct PendingAcknowledgement`
8838 * @return #GNUNET_OK (always)
8841 free_pending_ack_cb (void *cls,
8842 const struct GNUNET_ShortHashCode *key,
8845 struct PendingAcknowledgement *pa = value;
8849 free_pending_acknowledgement (pa);
8855 * Free acknowledgement cummulator.
8859 * @param value a `struct AcknowledgementCummulator`
8860 * @return #GNUNET_OK (always)
8863 free_ack_cummulator_cb (void *cls,
8864 const struct GNUNET_PeerIdentity *pid,
8867 struct AcknowledgementCummulator *ac = value;
8877 * Function called when the service shuts down. Unloads our plugins
8878 * and cancels pending validations.
8880 * @param cls closure, unused
8883 do_shutdown (void *cls)
8885 struct LearnLaunchEntry *lle;
8888 if (NULL != ephemeral_task)
8890 GNUNET_SCHEDULER_cancel (ephemeral_task);
8891 ephemeral_task = NULL;
8893 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
8894 if (NULL != peerstore)
8896 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
8899 if (NULL != GST_stats)
8901 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
8904 if (NULL != GST_my_private_key)
8906 GNUNET_free (GST_my_private_key);
8907 GST_my_private_key = NULL;
8909 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
8910 &free_ack_cummulator_cb,
8912 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
8913 ack_cummulators = NULL;
8914 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
8915 &free_pending_ack_cb,
8917 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
8918 pending_acks = NULL;
8919 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
8921 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
8922 &free_backtalker_cb,
8924 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
8926 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
8927 &free_validation_state_cb,
8929 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
8930 validation_map = NULL;
8931 while (NULL != (lle = lle_head))
8933 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8936 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
8938 GNUNET_CONTAINER_heap_destroy (validation_heap);
8939 validation_heap = NULL;
8940 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
8941 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
8943 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
8946 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
8947 ephemeral_map = NULL;
8948 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
8949 ephemeral_heap = NULL;
8954 * Initiate transport service.
8956 * @param cls closure
8957 * @param c configuration to use
8958 * @param service the initialized service
8962 const struct GNUNET_CONFIGURATION_Handle *c,
8963 struct GNUNET_SERVICE_Handle *service)
8969 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8970 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
8971 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
8972 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8973 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8974 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
8976 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8977 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
8979 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8981 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8982 GST_my_private_key =
8983 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
8984 if (NULL == GST_my_private_key)
8987 GNUNET_ERROR_TYPE_ERROR,
8989 "Transport service is lacking key configuration settings. Exiting.\n"));
8990 GNUNET_SCHEDULER_shutdown ();
8993 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
8994 &GST_my_identity.public_key);
8995 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8996 "My identity is `%s'\n",
8997 GNUNET_i2s_full (&GST_my_identity));
8998 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
8999 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
9000 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
9001 if (NULL == peerstore)
9004 GNUNET_SCHEDULER_shutdown ();
9011 * Define "main" method using service macro.
9013 GNUNET_SERVICE_MAIN (
9015 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
9018 &client_disconnect_cb,
9020 /* communication with applications */
9021 GNUNET_MQ_hd_fixed_size (suggest,
9022 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
9023 struct ExpressPreferenceMessage,
9025 GNUNET_MQ_hd_fixed_size (suggest_cancel,
9026 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
9027 struct ExpressPreferenceMessage,
9029 GNUNET_MQ_hd_var_size (request_hello_validation,
9030 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
9031 struct RequestHelloValidationMessage,
9033 /* communication with core */
9034 GNUNET_MQ_hd_fixed_size (client_start,
9035 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
9036 struct StartMessage,
9038 GNUNET_MQ_hd_var_size (client_send,
9039 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
9040 struct OutboundMessage,
9042 /* communication with communicators */
9043 GNUNET_MQ_hd_var_size (communicator_available,
9044 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
9045 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
9047 GNUNET_MQ_hd_var_size (communicator_backchannel,
9048 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
9049 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
9051 GNUNET_MQ_hd_var_size (add_address,
9052 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
9053 struct GNUNET_TRANSPORT_AddAddressMessage,
9055 GNUNET_MQ_hd_fixed_size (del_address,
9056 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
9057 struct GNUNET_TRANSPORT_DelAddressMessage,
9059 GNUNET_MQ_hd_var_size (incoming_msg,
9060 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
9061 struct GNUNET_TRANSPORT_IncomingMessage,
9063 GNUNET_MQ_hd_fixed_size (queue_create_ok,
9064 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
9065 struct GNUNET_TRANSPORT_CreateQueueResponse,
9067 GNUNET_MQ_hd_fixed_size (queue_create_fail,
9068 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
9069 struct GNUNET_TRANSPORT_CreateQueueResponse,
9071 GNUNET_MQ_hd_var_size (add_queue_message,
9072 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
9073 struct GNUNET_TRANSPORT_AddQueueMessage,
9075 GNUNET_MQ_hd_var_size (address_consider_verify,
9076 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
9077 struct GNUNET_TRANSPORT_AddressToVerify,
9079 GNUNET_MQ_hd_fixed_size (del_queue_message,
9080 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
9081 struct GNUNET_TRANSPORT_DelQueueMessage,
9083 GNUNET_MQ_hd_fixed_size (send_message_ack,
9084 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
9085 struct GNUNET_TRANSPORT_SendMessageToAck,
9087 /* communication with monitors */
9088 GNUNET_MQ_hd_fixed_size (monitor_start,
9089 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
9090 struct GNUNET_TRANSPORT_MonitorStart,
9092 GNUNET_MQ_handler_end ());
9095 /* end of file gnunet-service-transport.c */