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 * - add (more) logging
28 * - change transport-core API to specify transmission preferences (latency,
29 * reliability, etc.) per message!
30 * - review retransmission logic, right now there is no smartness there!
31 * => congestion control, flow control, etc [PERFORMANCE-BASICS]
34 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
35 * => Need 128 bit hash map though! [BANDWIDTH, MEMORY]
36 * - queue_send_msg and route_message both by API design have to make copies
37 * of the payload, and route_message on top of that requires a malloc/free.
38 * Change design to approximate "zero" copy better... [CPU]
39 * - could avoid copying body of message into each fragment and keep
40 * fragments as just pointers into the original message and only
41 * fully build fragments just before transmission (optimization, should
42 * reduce CPU and memory use) [CPU, MEMORY]
43 * - if messages are below MTU, consider adding ACKs and other stuff
44 * to the same transmission to avoid tiny messages (requires planning at
45 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
46 * - When we passively learned DV (with unconfirmed freshness), we
47 * right now add the path to our list but with a zero path_valid_until
48 * time and only use it for unconfirmed routes. However, we could consider
49 * triggering an explicit validation mechansim ourselves, specifically routing
50 * a challenge-response message over the path [ROUTING]
51 * - Track ACK losses based on ACK-counter [ROUTING]
53 * Design realizations / discussion:
54 * - communicators do flow control by calling MQ "notify sent"
55 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
56 * or explicitly via backchannel FC ACKs. As long as the
57 * channel is not full, they may 'notify sent' even if the other
58 * peer has not yet confirmed receipt. The other peer confirming
59 * is _only_ for FC, not for more reliable transmission; reliable
60 * transmission (i.e. of fragments) is left to _transport_.
61 * - ACKs sent back in uni-directional communicators are done via
62 * the background channel API; here transport _may_ initially
63 * broadcast (with bounded # hops) if no path is known;
64 * - transport should _integrate_ DV-routing and build a view of
65 * the network; then background channel traffic can be
66 * routed via DV as well as explicit "DV" traffic.
67 * - background channel is also used for ACKs and NAT traversal support
68 * - transport service is responsible for AEAD'ing the background
69 * channel, timestamps and monotonic time are used against replay
70 * of old messages -> peerstore needs to be supplied with
71 * "latest timestamps seen" data
72 * - if transport implements DV, we likely need a 3rd peermap
73 * in addition to ephemerals and (direct) neighbours
74 * ==> check if stuff needs to be moved out of "Neighbour"
75 * - transport should encapsualte core-level messages and do its
76 * own ACKing for RTT/goodput/loss measurements _and_ fragment
80 #include "gnunet_util_lib.h"
81 #include "gnunet_statistics_service.h"
82 #include "gnunet_transport_monitor_service.h"
83 #include "gnunet_peerstore_service.h"
84 #include "gnunet_hello_lib.h"
85 #include "gnunet_signatures.h"
86 #include "transport.h"
89 * Maximum number of messages we acknowledge together in one
90 * cummulative ACK. Larger values may save a bit of bandwidth.
92 #define MAX_CUMMULATIVE_ACKS 64
95 * What is the size we assume for a read operation in the
96 * absence of an MTU for the purpose of flow control?
98 #define IN_PACKET_SIZE_WITHOUT_MTU 128
101 * Number of slots we keep of historic data for computation of
102 * goodput / message loss ratio.
104 #define GOODPUT_AGING_SLOTS 4
107 * Maximum number of peers we select for forwarding DVInit
108 * messages at the same time (excluding initiator).
110 #define MAX_DV_DISCOVERY_SELECTION 16
113 * Window size. How many messages to the same target do we pass
114 * to CORE without a RECV_OK in between? Small values limit
115 * thoughput, large values will increase latency.
117 * FIXME-OPTIMIZE: find out what good values are experimentally,
118 * maybe set adaptively (i.e. to observed available bandwidth).
120 #define RECV_WINDOW_SIZE 4
123 * Minimum number of hops we should forward DV learn messages
124 * even if they are NOT useful for us in hope of looping
125 * back to the initiator?
127 * FIXME: allow initiator some control here instead?
129 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
132 * Maximum DV distance allowed ever.
134 #define MAX_DV_HOPS_ALLOWED 16
137 * Maximum number of DV learning activities we may
138 * have pending at the same time.
140 #define MAX_DV_LEARN_PENDING 64
143 * Maximum number of DV paths we keep simultaneously to the same target.
145 #define MAX_DV_PATHS_TO_TARGET 3
148 * If a queue delays the next message by more than this number
149 * of seconds we log a warning. Note: this is for testing,
150 * the value chosen here might be too aggressively low!
152 #define DELAY_WARN_THRESHOLD \
153 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
156 * We only consider queues as "quality" connections when
157 * suppressing the generation of DV initiation messages if
158 * the latency of the queue is below this threshold.
160 #define DV_QUALITY_RTT_THRESHOLD \
161 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
164 * How long do we consider a DV path valid if we see no
165 * further updates on it? Note: the value chosen here might be too low!
167 #define DV_PATH_VALIDITY_TIMEOUT \
168 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
171 * How long do we cache backchannel (struct Backtalker) information
172 * after a backchannel goes inactive?
174 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
175 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
178 * How long before paths expire would we like to (re)discover DV paths? Should
179 * be below #DV_PATH_VALIDITY_TIMEOUT.
181 #define DV_PATH_DISCOVERY_FREQUENCY \
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
185 * How long are ephemeral keys valid?
187 #define EPHEMERAL_VALIDITY \
188 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
191 * How long do we keep partially reassembled messages around before giving up?
193 #define REASSEMBLY_EXPIRATION \
194 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
197 * What is the fastest rate at which we send challenges *if* we keep learning
198 * an address (gossip, DHT, etc.)?
200 #define FAST_VALIDATION_CHALLENGE_FREQ \
201 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
204 * What is the slowest rate at which we send challenges?
206 #define MAX_VALIDATION_CHALLENGE_FREQ \
207 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
210 * How long until we forget about historic accumulators and thus
211 * reset the ACK counter? Should exceed the maximum time an
212 * active connection experiences without an ACK.
214 #define ACK_CUMMULATOR_TIMEOUT \
215 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
218 * What is the non-randomized base frequency at which we
219 * would initiate DV learn messages?
221 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
224 * How many good connections (confirmed, bi-directional, not DV)
225 * do we need to have to suppress initiating DV learn messages?
227 #define DV_LEARN_QUALITY_THRESHOLD 100
230 * When do we forget an invalid address for sure?
232 #define MAX_ADDRESS_VALID_UNTIL \
233 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
236 * How long do we consider an address valid if we just checked?
238 #define ADDRESS_VALIDATION_LIFETIME \
239 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
242 * What is the maximum frequency at which we do address validation?
243 * A random value between 0 and this value is added when scheduling
244 * the #validation_task (both to ensure we do not validate too often,
245 * and to randomize a bit).
247 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
250 * How many network RTTs before an address validation expires should we begin
251 * trying to revalidate? (Note that the RTT used here is the one that we
252 * experienced during the last validation, not necessarily the latest RTT
255 #define VALIDATION_RTT_BUFFER_FACTOR 3
258 * How many messages can we have pending for a given communicator
259 * process before we start to throttle that communicator?
261 * Used if a communicator might be CPU-bound and cannot handle the traffic.
263 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
266 * How many messages can we have pending for a given queue (queue to
267 * a particular peer via a communicator) process before we start to
268 * throttle that queue?
270 #define QUEUE_LENGTH_LIMIT 32
273 GNUNET_NETWORK_STRUCT_BEGIN
276 * Unique identifier we attach to a message.
281 * Unique value, generated by incrementing the
282 * `message_uuid_ctr` of `struct Neighbour`.
284 uint64_t uuid GNUNET_PACKED;
289 * Unique identifier to map an acknowledgement to a transmission.
291 struct AcknowledgementUUIDP
294 * The UUID value. Not actually a hash, but a random value.
296 struct GNUNET_ShortHashCode value;
301 * Type of a nonce used for challenges.
303 struct ChallengeNonceP
306 * The value of the nonce. Note that this is NOT a hash.
308 struct GNUNET_ShortHashCode value;
313 * Outer layer of an encapsulated backchannel message.
315 struct TransportBackchannelEncapsulationMessage
318 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
320 struct GNUNET_MessageHeader header;
323 * Reserved, always zero.
325 uint32_t reserved GNUNET_PACKED;
328 * Target's peer identity (as backchannels may be transmitted
329 * indirectly, or even be broadcast).
331 struct GNUNET_PeerIdentity target;
334 * Ephemeral key setup by the sender for @e target, used
335 * to encrypt the payload.
337 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
340 * We use an IV here as the @e ephemeral_key is re-used for
341 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
343 struct GNUNET_ShortHashCode iv;
346 * HMAC over the ciphertext of the encrypted, variable-size
347 * body that follows. Verified via DH of @e target and
350 struct GNUNET_HashCode hmac;
352 /* Followed by encrypted, variable-size payload */
357 * Body by which a peer confirms that it is using an ephemeral key.
359 struct EphemeralConfirmationPS
363 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
365 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
368 * How long is this signature over the ephemeral key valid?
370 * Note that the receiver MUST IGNORE the absolute time, and only interpret
371 * the value as a mononic time and reject "older" values than the last one
372 * observed. This is necessary as we do not want to require synchronized
373 * clocks and may not have a bidirectional communication channel.
375 * Even with this, there is no real guarantee against replay achieved here,
376 * unless the latest timestamp is persisted. While persistence should be
377 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
378 * communicators must protect against replay attacks when using backchannel
381 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
384 * Target's peer identity.
386 struct GNUNET_PeerIdentity target;
389 * Ephemeral key setup by the sender for @e target, used
390 * to encrypt the payload.
392 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
397 * Plaintext of the variable-size payload that is encrypted
398 * within a `struct TransportBackchannelEncapsulationMessage`
400 struct TransportBackchannelRequestPayloadP
404 * Sender's peer identity.
406 struct GNUNET_PeerIdentity sender;
409 * Signature of the sender over an
410 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
412 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
415 * Current monotonic time of the sending transport service. Used to
416 * detect replayed messages. Note that the receiver should remember
417 * a list of the recently seen timestamps and only reject messages
418 * if the timestamp is in the list, or the list is "full" and the
419 * timestamp is smaller than the lowest in the list.
421 * Like the @e ephemeral_validity, the list of timestamps per peer should be
422 * persisted to guard against replays after restarts.
424 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
426 /* Followed by a `struct GNUNET_MessageHeader` with a message
427 for a communicator */
429 /* Followed by a 0-termianted string specifying the name of
430 the communicator which is to receive the message */
435 * Outer layer of an encapsulated unfragmented application message sent
436 * over an unreliable channel.
438 struct TransportReliabilityBoxMessage
441 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
443 struct GNUNET_MessageHeader header;
446 * Number of messages still to be sent before a commulative
447 * ACK is requested. Zero if an ACK is requested immediately.
448 * In NBO. Note that the receiver may send the ACK faster
449 * if it believes that is reasonable.
451 uint32_t ack_countdown GNUNET_PACKED;
454 * Unique ID of the message used for signalling receipt of
455 * messages sent over possibly unreliable channels. Should
458 struct AcknowledgementUUIDP ack_uuid;
463 * Acknowledgement payload.
465 struct TransportCummulativeAckPayloadP
468 * How long was the ACK delayed for generating cummulative ACKs?
469 * Used to calculate the correct network RTT by taking the receipt
470 * time of the ack minus the transmission time of the sender minus
473 struct GNUNET_TIME_RelativeNBO ack_delay;
476 * UUID of a message being acknowledged.
478 struct AcknowledgementUUIDP ack_uuid;
483 * Confirmation that the receiver got a
484 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
485 * confirmation may be transmitted over a completely different queue,
486 * so ACKs are identified by a combination of PID of sender and
487 * message UUID, without the queue playing any role!
489 struct TransportReliabilityAckMessage
492 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
494 struct GNUNET_MessageHeader header;
497 * Counter of ACKs transmitted by the sender to us. Incremented
498 * by one for each ACK, used to detect how many ACKs were lost.
500 uint32_t ack_counter GNUNET_PACKED;
502 /* followed by any number of `struct TransportCummulativeAckPayloadP`
503 messages providing ACKs */
508 * Outer layer of an encapsulated fragmented application message.
510 struct TransportFragmentBoxMessage
513 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
515 struct GNUNET_MessageHeader header;
518 * Offset of this fragment in the overall message.
520 uint16_t frag_off GNUNET_PACKED;
523 * Total size of the message that is being fragmented.
525 uint16_t msg_size GNUNET_PACKED;
528 * Unique ID of this fragment (and fragment transmission!). Will
529 * change even if a fragement is retransmitted to make each
530 * transmission attempt unique! If a client receives a duplicate
531 * fragment (same @e frag_off for same @a msg_uuid, it must send
532 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
534 struct AcknowledgementUUIDP ack_uuid;
537 * Original message ID for of the message that all the fragments
538 * belong to. Must be the same for all fragments.
540 struct MessageUUIDP msg_uuid;
545 * Content signed by the initator during DV learning.
547 * The signature is required to prevent DDoS attacks. A peer sending out this
548 * message is potentially generating a lot of traffic that will go back to the
549 * initator, as peers receiving this message will try to let the initiator
550 * know that they got the message.
552 * Without this signature, an attacker could abuse this mechanism for traffic
553 * amplification, sending a lot of traffic to a peer by putting out this type
554 * of message with the victim's peer identity.
556 * Even with just a signature, traffic amplification would be possible via
557 * replay attacks. The @e monotonic_time limits such replay attacks, as every
558 * potential amplificator will check the @e monotonic_time and only respond
559 * (at most) once per message.
564 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
566 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
569 * Time at the initiator when generating the signature.
571 * Note that the receiver MUST IGNORE the absolute time, and only interpret
572 * the value as a mononic time and reject "older" values than the last one
573 * observed. This is necessary as we do not want to require synchronized
574 * clocks and may not have a bidirectional communication channel.
576 * Even with this, there is no real guarantee against replay achieved here,
577 * unless the latest timestamp is persisted. Persistence should be
578 * provided via PEERSTORE if possible.
580 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
583 * Challenge value used by the initiator to re-identify the path.
585 struct ChallengeNonceP challenge;
590 * Content signed by each peer during DV learning.
592 * This assues the initiator of the DV learning operation that the hop from @e
593 * pred via the signing peer to @e succ actually exists. This makes it
594 * impossible for an adversary to supply the network with bogus routes.
596 * The @e challenge is included to provide replay protection for the
597 * initiator. This way, the initiator knows that the hop existed after the
598 * original @e challenge was first transmitted, providing a freshness metric.
600 * Peers other than the initiator that passively learn paths by observing
601 * these messages do NOT benefit from this. Here, an adversary may indeed
602 * replay old messages. Thus, passively learned paths should always be
603 * immediately marked as "potentially stale".
608 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
610 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
613 * Identity of the previous peer on the path.
615 struct GNUNET_PeerIdentity pred;
618 * Identity of the next peer on the path.
620 struct GNUNET_PeerIdentity succ;
623 * Challenge value used by the initiator to re-identify the path.
625 struct ChallengeNonceP challenge;
630 * An entry describing a peer on a path in a
631 * `struct TransportDVLearnMessage` message.
636 * Identity of a peer on the path.
638 struct GNUNET_PeerIdentity hop;
641 * Signature of this hop over the path, of purpose
642 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
644 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
649 * Internal message used by transport for distance vector learning.
650 * If @e num_hops does not exceed the threshold, peers should append
651 * themselves to the peer list and flood the message (possibly only
652 * to a subset of their neighbours to limit discoverability of the
653 * network topology). To the extend that the @e bidirectional bits
654 * are set, peers may learn the inverse paths even if they did not
657 * Unless received on a bidirectional queue and @e num_hops just
658 * zero, peers that can forward to the initator should always try to
659 * forward to the initiator.
661 struct TransportDVLearnMessage
664 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
666 struct GNUNET_MessageHeader header;
669 * Number of hops this messages has travelled, in NBO. Zero if
672 uint16_t num_hops GNUNET_PACKED;
675 * Bitmask of the last 16 hops indicating whether they are confirmed
676 * available (without DV) in both directions or not, in NBO. Used
677 * to possibly instantly learn a path in both directions. Each peer
678 * should shift this value by one to the left, and then set the
679 * lowest bit IF the current sender can be reached from it (without
682 uint16_t bidirectional GNUNET_PACKED;
685 * Peers receiving this message and delaying forwarding to other
686 * peers for any reason should increment this value by the non-network
687 * delay created by the peer.
689 struct GNUNET_TIME_RelativeNBO non_network_delay;
692 * Time at the initiator when generating the signature.
694 * Note that the receiver MUST IGNORE the absolute time, and only interpret
695 * the value as a mononic time and reject "older" values than the last one
696 * observed. This is necessary as we do not want to require synchronized
697 * clocks and may not have a bidirectional communication channel.
699 * Even with this, there is no real guarantee against replay achieved here,
700 * unless the latest timestamp is persisted. Persistence should be
701 * provided via PEERSTORE if possible.
703 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
706 * Signature of this hop over the path, of purpose
707 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
709 struct GNUNET_CRYPTO_EddsaSignature init_sig;
712 * Identity of the peer that started this learning activity.
714 struct GNUNET_PeerIdentity initiator;
717 * Challenge value used by the initiator to re-identify the path.
719 struct ChallengeNonceP challenge;
721 /* Followed by @e num_hops `struct DVPathEntryP` values,
722 excluding the initiator of the DV trace; the last entry is the
723 current sender; the current peer must not be included. */
728 * Outer layer of an encapsulated message send over multiple hops.
729 * The path given only includes the identities of the subsequent
730 * peers, i.e. it will be empty if we are the receiver. Each
731 * forwarding peer should scan the list from the end, and if it can,
732 * forward to the respective peer. The list should then be shortened
733 * by all the entries up to and including that peer. Each hop should
734 * also increment @e total_hops to allow the receiver to get a precise
735 * estimate on the number of hops the message travelled. Senders must
736 * provide a learned path that thus should work, but intermediaries
737 * know of a shortcut, they are allowed to send the message via that
740 * If a peer finds itself still on the list, it must drop the message.
742 struct TransportDVBoxMessage
745 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
747 struct GNUNET_MessageHeader header;
750 * Number of total hops this messages travelled. In NBO.
751 * @e origin sets this to zero, to be incremented at
754 uint16_t total_hops GNUNET_PACKED;
757 * Number of hops this messages includes. In NBO.
759 uint16_t num_hops GNUNET_PACKED;
762 * Identity of the peer that originated the message.
764 struct GNUNET_PeerIdentity origin;
766 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
767 excluding the @e origin and the current peer, the last must be
768 the ultimate target; if @e num_hops is zero, the receiver of this
769 message is the ultimate target. */
771 /* Followed by the actual message, which itself may be
772 another box, but not a DV_LEARN or DV_BOX message! */
777 * Message send to another peer to validate that it can indeed
778 * receive messages at a particular address.
780 struct TransportValidationChallengeMessage
784 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
786 struct GNUNET_MessageHeader header;
791 uint32_t reserved GNUNET_PACKED;
794 * Challenge to be signed by the receiving peer.
796 struct ChallengeNonceP challenge;
799 * Timestamp of the sender, to be copied into the reply
800 * to allow sender to calculate RTT.
802 struct GNUNET_TIME_AbsoluteNBO sender_time;
807 * Message signed by a peer to confirm that it can indeed
808 * receive messages at a particular address.
810 struct TransportValidationPS
814 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
816 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
819 * How long does the sender believe the address on
820 * which the challenge was received to remain valid?
822 struct GNUNET_TIME_RelativeNBO validity_duration;
825 * Challenge signed by the receiving peer.
827 struct ChallengeNonceP challenge;
832 * Message send to a peer to respond to a
833 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
835 struct TransportValidationResponseMessage
839 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
841 struct GNUNET_MessageHeader header;
846 uint32_t reserved GNUNET_PACKED;
849 * The peer's signature matching the
850 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
852 struct GNUNET_CRYPTO_EddsaSignature signature;
855 * The challenge that was signed by the receiving peer.
857 struct ChallengeNonceP challenge;
860 * Original timestamp of the sender (was @code{sender_time}),
861 * copied into the reply to allow sender to calculate RTT.
863 struct GNUNET_TIME_AbsoluteNBO origin_time;
866 * How long does the sender believe this address to remain
869 struct GNUNET_TIME_RelativeNBO validity_duration;
873 GNUNET_NETWORK_STRUCT_END
877 * What type of client is the `struct TransportClient` about?
882 * We do not know yet (client is fresh).
887 * Is the CORE service, we need to forward traffic to it.
892 * It is a monitor, forward monitor data.
897 * It is a communicator, use for communication.
902 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
909 * Which transmission options are allowable for transmission?
910 * Interpreted bit-wise!
912 enum RouteMessageOptions
915 * Only confirmed, non-DV direct neighbours.
920 * We are allowed to use DV routing for this @a hdr
925 * We are allowed to use unconfirmed queues or DV routes for this message
927 RMO_UNCONFIRMED_ALLOWED = 2,
930 * Reliable and unreliable, DV and non-DV are all acceptable.
932 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
935 * If we have multiple choices, it is OK to send this message
936 * over multiple channels at the same time to improve loss tolerance.
937 * (We do at most 2 transmissions.)
944 * When did we launch this DV learning activity?
946 struct LearnLaunchEntry
950 * Kept (also) in a DLL sorted by launch time.
952 struct LearnLaunchEntry *prev;
955 * Kept (also) in a DLL sorted by launch time.
957 struct LearnLaunchEntry *next;
960 * Challenge that uniquely identifies this activity.
962 struct ChallengeNonceP challenge;
965 * When did we transmit the DV learn message (used to calculate RTT) and
966 * determine freshness of paths learned via this operation.
968 struct GNUNET_TIME_Absolute launch_time;
973 * Entry in our cache of ephemeral keys we currently use. This way, we only
974 * sign an ephemeral once per @e target, and then can re-use it over multiple
975 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
976 * signing is expensive and in some cases we may use backchannel messages a
979 struct EphemeralCacheEntry
983 * Target's peer identity (we don't re-use ephemerals
984 * to limit linkability of messages).
986 struct GNUNET_PeerIdentity target;
989 * Signature affirming @e ephemeral_key of type
990 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
992 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
995 * How long is @e sender_sig valid
997 struct GNUNET_TIME_Absolute ephemeral_validity;
1000 * What time was @e sender_sig created
1002 struct GNUNET_TIME_Absolute monotime;
1005 * Our ephemeral key.
1007 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1010 * Our private ephemeral key.
1012 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1015 * Node in the ephemeral cache for this entry.
1016 * Used for expiration.
1018 struct GNUNET_CONTAINER_HeapNode *hn;
1023 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1024 * (or current) transmission performance.
1026 struct TransmissionHistoryEntry
1029 * Number of bytes actually sent in the interval.
1031 uint64_t bytes_sent;
1034 * Number of bytes received and acknowledged by the other peer in
1037 uint64_t bytes_received;
1042 * Performance data for a transmission possibility.
1044 struct PerformanceData
1047 * Weighted average for the RTT.
1049 struct GNUNET_TIME_Relative aged_rtt;
1052 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1055 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1058 * What was the last age when we wrote to @e the? Used to clear
1059 * old entries when the age advances.
1061 unsigned int last_age;
1066 * Client connected to the transport service.
1068 struct TransportClient;
1071 * A neighbour that at least one communicator is connected to.
1076 * Entry in our #dv_routes table, representing a (set of) distance
1077 * vector routes to a particular peer.
1079 struct DistanceVector;
1082 * A queue is a message queue provided by a communicator
1083 * via which we can reach a particular neighbour.
1088 * Message awaiting transmission. See detailed comments below.
1090 struct PendingMessage;
1093 * One possible hop towards a DV target.
1095 struct DistanceVectorHop;
1099 * Context from #handle_incoming_msg(). Closure for many
1100 * message handlers below.
1102 struct CommunicatorMessageContext
1106 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1107 * flow control to unchoke.
1109 struct CommunicatorMessageContext *next;
1112 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1113 * flow control to unchoke.
1115 struct CommunicatorMessageContext *prev;
1118 * Which communicator provided us with the message.
1120 struct TransportClient *tc;
1123 * Additional information for flow control and about the sender.
1125 struct GNUNET_TRANSPORT_IncomingMessage im;
1128 * Number of hops the message has travelled (if DV-routed).
1129 * FIXME: make use of this in ACK handling!
1131 uint16_t total_hops;
1136 * A virtual link is another reachable peer that is known to CORE. It
1137 * can be either a `struct Neighbour` with at least one confirmed
1138 * `struct Queue`, or a `struct DistanceVector` with at least one
1139 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1140 * data that is per neighbour that is not specific to how the
1141 * connectivity is established.
1146 * Identity of the peer at the other end of the link.
1148 struct GNUNET_PeerIdentity target;
1151 * Communicators blocked for receiving on @e target as we are waiting
1152 * on the @e core_recv_window to increase.
1154 struct CommunicatorMessageContext *cmc_head;
1157 * Communicators blocked for receiving on @e target as we are waiting
1158 * on the @e core_recv_window to increase.
1160 struct CommunicatorMessageContext *cmc_tail;
1163 * Task scheduled to possibly notfiy core that this peer is no
1164 * longer counting as confirmed. Runs the #core_visibility_check(),
1165 * which checks that some DV-path or a queue exists that is still
1166 * considered confirmed.
1168 struct GNUNET_SCHEDULER_Task *visibility_task;
1171 * Neighbour used by this virtual link, NULL if @e dv is used.
1173 struct Neighbour *n;
1176 * Distance vector used by this virtual link, NULL if @e n is used.
1178 struct DistanceVector *dv;
1181 * How many more messages can we send to core before we exhaust
1182 * the receive window of CORE for this peer? If this hits zero,
1183 * we must tell communicators to stop providing us more messages
1184 * for this peer. In fact, the window can go negative as we
1185 * have multiple communicators, so per communicator we can go
1186 * down by one into the negative range.
1188 int core_recv_window;
1193 * Data structure kept when we are waiting for an acknowledgement.
1195 struct PendingAcknowledgement
1199 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1200 * is kept in relation to its pending message.
1202 struct PendingAcknowledgement *next_pm;
1205 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1206 * is kept in relation to its pending message.
1208 struct PendingAcknowledgement *prev_pm;
1211 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1212 * is kept in relation to the queue that was used to transmit the
1215 struct PendingAcknowledgement *next_queue;
1218 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1219 * is kept in relation to the queue that was used to transmit the
1222 struct PendingAcknowledgement *prev_queue;
1225 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1226 * is kept in relation to the DVH that was used to transmit the
1229 struct PendingAcknowledgement *next_dvh;
1232 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1233 * is kept in relation to the DVH that was used to transmit the
1236 struct PendingAcknowledgement *prev_dvh;
1239 * Pointers for the DLL of all pending acknowledgements.
1240 * This list is sorted by @e transmission time. If the list gets too
1241 * long, the oldest entries are discarded.
1243 struct PendingAcknowledgement *next_pa;
1246 * Pointers for the DLL of all pending acknowledgements.
1247 * This list is sorted by @e transmission time. If the list gets too
1248 * long, the oldest entries are discarded.
1250 struct PendingAcknowledgement *prev_pa;
1253 * Unique identifier for this transmission operation.
1255 struct AcknowledgementUUIDP ack_uuid;
1258 * Message that was transmitted, may be NULL if the message was ACKed
1259 * via another channel.
1261 struct PendingMessage *pm;
1264 * Distance vector path chosen for this transmission, NULL if transmission
1265 * was to a direct neighbour OR if the path was forgotten in the meantime.
1267 struct DistanceVectorHop *dvh;
1270 * Queue used for transmission, NULL if the queue has been destroyed
1271 * (which may happen before we get an acknowledgement).
1273 struct Queue *queue;
1276 * Time of the transmission, for RTT calculation.
1278 struct GNUNET_TIME_Absolute transmission_time;
1281 * Number of bytes of the original message (to calculate bandwidth).
1283 uint16_t message_size;
1288 * One possible hop towards a DV target.
1290 struct DistanceVectorHop
1294 * Kept in a MDLL, sorted by @e timeout.
1296 struct DistanceVectorHop *next_dv;
1299 * Kept in a MDLL, sorted by @e timeout.
1301 struct DistanceVectorHop *prev_dv;
1306 struct DistanceVectorHop *next_neighbour;
1311 struct DistanceVectorHop *prev_neighbour;
1314 * Head of MDLL of messages routed via this path.
1316 struct PendingMessage *pending_msg_head;
1319 * Tail of MDLL of messages routed via this path.
1321 struct PendingMessage *pending_msg_tail;
1324 * Head of DLL of PAs that used our @a path.
1326 struct PendingAcknowledgement *pa_head;
1329 * Tail of DLL of PAs that used our @a path.
1331 struct PendingAcknowledgement *pa_tail;
1334 * What would be the next hop to @e target?
1336 struct Neighbour *next_hop;
1339 * Distance vector entry this hop belongs with.
1341 struct DistanceVector *dv;
1344 * Array of @e distance hops to the target, excluding @e next_hop.
1345 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1346 * at the end of this struct. Excludes the target itself!
1348 const struct GNUNET_PeerIdentity *path;
1351 * At what time do we forget about this path unless we see it again
1354 struct GNUNET_TIME_Absolute timeout;
1357 * For how long is the validation of this path considered
1359 * Set to ZERO if the path is learned by snooping on DV learn messages
1360 * initiated by other peers, and to the time at which we generated the
1361 * challenge for DV learn operations this peer initiated.
1363 struct GNUNET_TIME_Absolute path_valid_until;
1366 * Performance data for this transmission possibility.
1368 struct PerformanceData pd;
1371 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1372 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1375 unsigned int distance;
1380 * Entry in our #dv_routes table, representing a (set of) distance
1381 * vector routes to a particular peer.
1383 struct DistanceVector
1387 * To which peer is this a route?
1389 struct GNUNET_PeerIdentity target;
1392 * Known paths to @e target.
1394 struct DistanceVectorHop *dv_head;
1397 * Known paths to @e target.
1399 struct DistanceVectorHop *dv_tail;
1402 * Task scheduled to purge expired paths from @e dv_head MDLL.
1404 struct GNUNET_SCHEDULER_Task *timeout_task;
1407 * Do we have a confirmed working queue and are thus visible to
1408 * CORE? If so, this is the virtual link, otherwise NULL.
1410 struct VirtualLink *link;
1415 * Entry identifying transmission in one of our `struct
1416 * Queue` which still awaits an ACK. This is used to
1417 * ensure we do not overwhelm a communicator and limit the number of
1418 * messages outstanding per communicator (say in case communicator is
1419 * CPU bound) and per queue (in case bandwidth allocation exceeds
1420 * what the communicator can actually provide towards a particular
1429 struct QueueEntry *next;
1434 struct QueueEntry *prev;
1437 * Queue this entry is queued with.
1439 struct Queue *queue;
1442 * Pending message this entry is for, or NULL for none.
1444 struct PendingMessage *pm;
1447 * Message ID used for this message with the queue used for transmission.
1454 * A queue is a message queue provided by a communicator
1455 * via which we can reach a particular neighbour.
1462 struct Queue *next_neighbour;
1467 struct Queue *prev_neighbour;
1472 struct Queue *prev_client;
1477 struct Queue *next_client;
1480 * Head of DLL of PAs that used this queue.
1482 struct PendingAcknowledgement *pa_head;
1485 * Tail of DLL of PAs that used this queue.
1487 struct PendingAcknowledgement *pa_tail;
1490 * Head of DLL of unacked transmission requests.
1492 struct QueueEntry *queue_head;
1495 * End of DLL of unacked transmission requests.
1497 struct QueueEntry *queue_tail;
1500 * Which neighbour is this queue for?
1502 struct Neighbour *neighbour;
1505 * Which communicator offers this queue?
1507 struct TransportClient *tc;
1510 * Address served by the queue.
1512 const char *address;
1515 * Task scheduled for the time when this queue can (likely) transmit the
1518 struct GNUNET_SCHEDULER_Task *transmit_task;
1521 * How long do *we* consider this @e address to be valid? In the past or
1522 * zero if we have not yet validated it. Can be updated based on
1523 * challenge-response validations (via address validation logic), or when we
1524 * receive ACKs that we can definitively map to transmissions via this
1527 struct GNUNET_TIME_Absolute validated_until;
1530 * Performance data for this queue.
1532 struct PerformanceData pd;
1535 * Message ID generator for transmissions on this queue to the
1541 * Unique identifier of this queue with the communicator.
1546 * Maximum transmission unit supported by this queue.
1553 uint32_t num_msg_pending;
1558 uint32_t num_bytes_pending;
1561 * Length of the DLL starting at @e queue_head.
1563 unsigned int queue_length;
1566 * Network type offered by this queue.
1568 enum GNUNET_NetworkType nt;
1571 * Connection status for this queue.
1573 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1578 * Information we keep for a message that we are reassembling.
1580 struct ReassemblyContext
1584 * Original message ID for of the message that all the fragments
1587 struct MessageUUIDP msg_uuid;
1590 * Which neighbour is this context for?
1592 struct Neighbour *neighbour;
1595 * Entry in the reassembly heap (sorted by expiration).
1597 struct GNUNET_CONTAINER_HeapNode *hn;
1600 * Bitfield with @e msg_size bits representing the positions
1601 * where we have received fragments. When we receive a fragment,
1602 * we check the bits in @e bitfield before incrementing @e msg_missing.
1604 * Allocated after the reassembled message.
1609 * At what time will we give up reassembly of this message?
1611 struct GNUNET_TIME_Absolute reassembly_timeout;
1614 * Time we received the last fragment. @e avg_ack_delay must be
1615 * incremented by now - @e last_frag multiplied by @e num_acks.
1617 struct GNUNET_TIME_Absolute last_frag;
1620 * How big is the message we are reassembling in total?
1625 * How many bytes of the message are still missing? Defragmentation
1626 * is complete when @e msg_missing == 0.
1628 uint16_t msg_missing;
1630 /* Followed by @e msg_size bytes of the (partially) defragmented original
1633 /* Followed by @e bitfield data */
1638 * A neighbour that at least one communicator is connected to.
1644 * Which peer is this about?
1646 struct GNUNET_PeerIdentity pid;
1649 * Map with `struct ReassemblyContext` structs for fragments under
1650 * reassembly. May be NULL if we currently have no fragments from
1651 * this @e pid (lazy initialization).
1653 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1656 * Heap with `struct ReassemblyContext` structs for fragments under
1657 * reassembly. May be NULL if we currently have no fragments from
1658 * this @e pid (lazy initialization).
1660 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1663 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1665 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1668 * Head of list of messages pending for this neighbour.
1670 struct PendingMessage *pending_msg_head;
1673 * Tail of list of messages pending for this neighbour.
1675 struct PendingMessage *pending_msg_tail;
1678 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1679 * purged if this neighbour goes down.
1681 struct DistanceVectorHop *dv_head;
1684 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1685 * purged if this neighbour goes down.
1687 struct DistanceVectorHop *dv_tail;
1690 * Head of DLL of queues to this peer.
1692 struct Queue *queue_head;
1695 * Tail of DLL of queues to this peer.
1697 struct Queue *queue_tail;
1700 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1701 * the PEERSTORE, or NULL.
1703 struct GNUNET_PEERSTORE_IterateContext *get;
1706 * Handle to a PEERSTORE store operation to store this @e pid's @e
1707 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1709 struct GNUNET_PEERSTORE_StoreContext *sc;
1712 * Do we have a confirmed working queue and are thus visible to
1713 * CORE? If so, this is the virtual link, otherwise NULL.
1715 struct VirtualLink *link;
1718 * Latest DVLearn monotonic time seen from this peer. Initialized only
1719 * if @e dl_monotime_available is #GNUNET_YES.
1721 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1724 * Used to generate unique UUIDs for messages that are being
1727 uint64_t message_uuid_ctr;
1730 * Do we have the lastest value for @e last_dv_learn_monotime from
1731 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1733 int dv_monotime_available;
1738 * A peer that an application (client) would like us to talk to directly.
1744 * Which peer is this about?
1746 struct GNUNET_PeerIdentity pid;
1749 * Client responsible for the request.
1751 struct TransportClient *tc;
1754 * Handle for watching the peerstore for HELLOs for this peer.
1756 struct GNUNET_PEERSTORE_WatchContext *wc;
1759 * What kind of performance preference does this @e tc have?
1763 enum GNUNET_MQ_PriorityPreferences pk;
1766 * How much bandwidth would this @e tc like to see?
1768 struct GNUNET_BANDWIDTH_Value32NBO bw;
1773 * Types of different pending messages.
1775 enum PendingMessageType
1779 * Ordinary message received from the CORE service.
1786 PMT_FRAGMENT_BOX = 1,
1791 PMT_RELIABILITY_BOX = 2,
1794 * Any type of acknowledgement.
1796 PMT_ACKNOWLEDGEMENT = 3,
1799 * Control traffic generated by the TRANSPORT service itself.
1807 * Transmission request that is awaiting delivery. The original
1808 * transmission requests from CORE may be too big for some queues.
1809 * In this case, a *tree* of fragments is created. At each
1810 * level of the tree, fragments are kept in a DLL ordered by which
1811 * fragment should be sent next (at the head). The tree is searched
1812 * top-down, with the original message at the root.
1814 * To select a node for transmission, first it is checked if the
1815 * current node's message fits with the MTU. If it does not, we
1816 * either calculate the next fragment (based on @e frag_off) from the
1817 * current node, or, if all fragments have already been created,
1818 * descend to the @e head_frag. Even though the node was already
1819 * fragmented, the fragment may be too big if the fragment was
1820 * generated for a queue with a larger MTU. In this case, the node
1821 * may be fragmented again, thus creating a tree.
1823 * When acknowledgements for fragments are received, the tree
1824 * must be pruned, removing those parts that were already
1825 * acknowledged. When fragments are sent over a reliable
1826 * channel, they can be immediately removed.
1828 * If a message is ever fragmented, then the original "full" message
1829 * is never again transmitted (even if it fits below the MTU), and
1830 * only (remaining) fragments are sent.
1832 struct PendingMessage
1835 * Kept in a MDLL of messages for this @a target.
1837 struct PendingMessage *next_neighbour;
1840 * Kept in a MDLL of messages for this @a target.
1842 struct PendingMessage *prev_neighbour;
1845 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1847 struct PendingMessage *next_client;
1850 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1852 struct PendingMessage *prev_client;
1855 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1856 * #PMT_FRAGMENT_BOx)
1858 struct PendingMessage *next_frag;
1861 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1862 * #PMT_FRAGMENT_BOX)
1864 struct PendingMessage *prev_frag;
1867 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1870 struct PendingMessage *next_dvh;
1873 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1876 struct PendingMessage *prev_dvh;
1879 * Head of DLL of PAs for this pending message.
1881 struct PendingAcknowledgement *pa_head;
1884 * Tail of DLL of PAs for this pending message.
1886 struct PendingAcknowledgement *pa_tail;
1889 * This message, reliability boxed. Only possibly available if @e pmt is
1892 struct PendingMessage *bpm;
1895 * Target of the request (for transmission, may not be ultimate
1898 struct Neighbour *target;
1901 * Distance vector path selected for this message, or
1902 * NULL if transmitted directly.
1904 struct DistanceVectorHop *dvh;
1907 * Set to non-NULL value if this message is currently being given to a
1908 * communicator and we are awaiting that communicator's acknowledgement.
1909 * Note that we must not retransmit a pending message while we're still
1910 * in the process of giving it to a communicator. If a pending message
1911 * is free'd while this entry is non-NULL, the @e qe reference to us
1912 * should simply be set to NULL.
1914 struct QueueEntry *qe;
1917 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1919 struct TransportClient *client;
1922 * Head of a MDLL of fragments created for this core message.
1924 struct PendingMessage *head_frag;
1927 * Tail of a MDLL of fragments created for this core message.
1929 struct PendingMessage *tail_frag;
1932 * Our parent in the fragmentation tree.
1934 struct PendingMessage *frag_parent;
1937 * At what time should we give up on the transmission (and no longer retry)?
1939 struct GNUNET_TIME_Absolute timeout;
1942 * What is the earliest time for us to retry transmission of this message?
1944 struct GNUNET_TIME_Absolute next_attempt;
1947 * UUID to use for this message (used for reassembly of fragments, only
1948 * initialized if @e msg_uuid_set is #GNUNET_YES).
1950 struct MessageUUIDP msg_uuid;
1953 * Type of the pending message.
1955 enum PendingMessageType pmt;
1958 * Preferences for this message.
1959 * TODO: actually use this!
1961 enum GNUNET_MQ_PriorityPreferences prefs;
1964 * Size of the original message.
1969 * Offset at which we should generate the next fragment.
1974 * #GNUNET_YES once @e msg_uuid was initialized
1976 int16_t msg_uuid_set;
1978 /* Followed by @e bytes_msg to transmit */
1983 * Acknowledgement payload.
1985 struct TransportCummulativeAckPayload
1988 * When did we receive the message we are ACKing? Used to calculate
1989 * the delay we introduced by cummulating ACKs.
1991 struct GNUNET_TIME_Absolute receive_time;
1994 * UUID of a message being acknowledged.
1996 struct AcknowledgementUUIDP ack_uuid;
2001 * Data structure in which we track acknowledgements still to
2004 struct AcknowledgementCummulator
2007 * Target peer for which we are accumulating ACKs here.
2009 struct GNUNET_PeerIdentity target;
2012 * ACK data being accumulated. Only @e num_acks slots are valid.
2014 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2017 * Task scheduled either to transmit the cummulative ACK message,
2018 * or to clean up this data structure after extended periods of
2019 * inactivity (if @e num_acks is zero).
2021 struct GNUNET_SCHEDULER_Task *task;
2024 * When is @e task run (only used if @e num_acks is non-zero)?
2026 struct GNUNET_TIME_Absolute min_transmission_time;
2029 * Counter to produce the `ack_counter` in the `struct
2030 * TransportReliabilityAckMessage`. Allows the receiver to detect
2031 * lost ACK messages. Incremented by @e num_acks upon transmission.
2033 uint32_t ack_counter;
2036 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2038 unsigned int num_acks;
2043 * One of the addresses of this peer.
2045 struct AddressListEntry
2051 struct AddressListEntry *next;
2056 struct AddressListEntry *prev;
2059 * Which communicator provides this address?
2061 struct TransportClient *tc;
2064 * The actual address.
2066 const char *address;
2069 * Current context for storing this address in the peerstore.
2071 struct GNUNET_PEERSTORE_StoreContext *sc;
2074 * Task to periodically do @e st operation.
2076 struct GNUNET_SCHEDULER_Task *st;
2079 * What is a typical lifetime the communicator expects this
2080 * address to have? (Always from now.)
2082 struct GNUNET_TIME_Relative expiration;
2085 * Address identifier used by the communicator.
2090 * Network type offered by this address.
2092 enum GNUNET_NetworkType nt;
2097 * Client connected to the transport service.
2099 struct TransportClient
2105 struct TransportClient *next;
2110 struct TransportClient *prev;
2113 * Handle to the client.
2115 struct GNUNET_SERVICE_Client *client;
2118 * Message queue to the client.
2120 struct GNUNET_MQ_Handle *mq;
2123 * What type of client is this?
2125 enum ClientType type;
2131 * Information for @e type #CT_CORE.
2137 * Head of list of messages pending for this client, sorted by
2138 * transmission time ("next_attempt" + possibly internal prioritization).
2140 struct PendingMessage *pending_msg_head;
2143 * Tail of list of messages pending for this client.
2145 struct PendingMessage *pending_msg_tail;
2150 * Information for @e type #CT_MONITOR.
2156 * Peer identity to monitor the addresses of.
2157 * Zero to monitor all neighbours. Valid if
2158 * @e type is #CT_MONITOR.
2160 struct GNUNET_PeerIdentity peer;
2163 * Is this a one-shot monitor?
2171 * Information for @e type #CT_COMMUNICATOR.
2176 * If @e type is #CT_COMMUNICATOR, this communicator
2177 * supports communicating using these addresses.
2179 char *address_prefix;
2182 * Head of DLL of queues offered by this communicator.
2184 struct Queue *queue_head;
2187 * Tail of DLL of queues offered by this communicator.
2189 struct Queue *queue_tail;
2192 * Head of list of the addresses of this peer offered by this
2195 struct AddressListEntry *addr_head;
2198 * Tail of list of the addresses of this peer offered by this
2201 struct AddressListEntry *addr_tail;
2204 * Number of queue entries in all queues to this communicator. Used
2205 * throttle sending to a communicator if we see that the communicator
2206 * is globally unable to keep up.
2208 unsigned int total_queue_length;
2211 * Characteristics of this communicator.
2213 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2218 * Information for @e type #CT_APPLICATION
2224 * Map of requests for peers the given client application would like to
2225 * see connections for. Maps from PIDs to `struct PeerRequest`.
2227 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2236 * State we keep for validation activities. Each of these
2237 * is both in the #validation_heap and the #validation_map.
2239 struct ValidationState
2243 * For which peer is @a address to be validated (or possibly valid)?
2244 * Serves as key in the #validation_map.
2246 struct GNUNET_PeerIdentity pid;
2249 * How long did the peer claim this @e address to be valid? Capped at
2250 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2251 * were told about the address and the value claimed by the other peer at
2252 * that time. May be updated similarly when validation succeeds.
2254 struct GNUNET_TIME_Absolute valid_until;
2257 * How long do *we* consider this @e address to be valid?
2258 * In the past or zero if we have not yet validated it.
2260 struct GNUNET_TIME_Absolute validated_until;
2263 * When did we FIRST use the current @e challenge in a message?
2264 * Used to sanity-check @code{origin_time} in the response when
2265 * calculating the RTT. If the @code{origin_time} is not in
2266 * the expected range, the response is discarded as malicious.
2268 struct GNUNET_TIME_Absolute first_challenge_use;
2271 * When did we LAST use the current @e challenge in a message?
2272 * Used to sanity-check @code{origin_time} in the response when
2273 * calculating the RTT. If the @code{origin_time} is not in
2274 * the expected range, the response is discarded as malicious.
2276 struct GNUNET_TIME_Absolute last_challenge_use;
2279 * Next time we will send the @e challenge to the peer, if this time is past
2280 * @e valid_until, this validation state is released at this time. If the
2281 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2282 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2283 * to re-validate before the validity actually expires.
2285 struct GNUNET_TIME_Absolute next_challenge;
2288 * Current backoff factor we're applying for sending the @a challenge.
2289 * Reset to 0 if the @a challenge is confirmed upon validation.
2290 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2291 * existing value if we receive an unvalidated address again over
2292 * another channel (and thus should consider the information "fresh").
2293 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2295 struct GNUNET_TIME_Relative challenge_backoff;
2298 * Initially set to "forever". Once @e validated_until is set, this value is
2299 * set to the RTT that tells us how long it took to receive the validation.
2301 struct GNUNET_TIME_Relative validation_rtt;
2304 * The challenge we sent to the peer to get it to validate the address. Note
2305 * that we rotate the challenge whenever we update @e validated_until to
2306 * avoid attacks where a peer simply replays an old challenge in the future.
2307 * (We must not rotate more often as otherwise we may discard valid answers
2308 * due to packet losses, latency and reorderings on the network).
2310 struct ChallengeNonceP challenge;
2313 * Claimed address of the peer.
2318 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2319 * heap is used to figure out when the next validation activity should be
2322 struct GNUNET_CONTAINER_HeapNode *hn;
2325 * Handle to a PEERSTORE store operation for this @e address. NULL if
2326 * no PEERSTORE operation is pending.
2328 struct GNUNET_PEERSTORE_StoreContext *sc;
2331 * We are technically ready to send the challenge, but we are waiting for
2332 * the respective queue to become available for transmission.
2339 * A Backtalker is a peer sending us backchannel messages. We use this
2340 * struct to detect monotonic time violations, cache ephemeral key
2341 * material (to avoid repeatedly checking signatures), and to synchronize
2342 * monotonic time with the PEERSTORE.
2347 * Peer this is about.
2349 struct GNUNET_PeerIdentity pid;
2352 * Last (valid) monotonic time received from this sender.
2354 struct GNUNET_TIME_Absolute monotonic_time;
2357 * When will this entry time out?
2359 struct GNUNET_TIME_Absolute timeout;
2362 * Last (valid) ephemeral key received from this sender.
2364 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2367 * Task associated with this backtalker. Can be for timeout,
2368 * or other asynchronous operations.
2370 struct GNUNET_SCHEDULER_Task *task;
2373 * Communicator context waiting on this backchannel's @e get, or NULL.
2375 struct CommunicatorMessageContext *cmc;
2378 * Handle for an operation to fetch @e monotonic_time information from the
2379 * PEERSTORE, or NULL.
2381 struct GNUNET_PEERSTORE_IterateContext *get;
2384 * Handle to a PEERSTORE store operation for this @e pid's @e
2385 * monotonic_time. NULL if no PEERSTORE operation is pending.
2387 struct GNUNET_PEERSTORE_StoreContext *sc;
2390 * Number of bytes of the original message body that follows after this
2398 * Head of linked list of all clients to this service.
2400 static struct TransportClient *clients_head;
2403 * Tail of linked list of all clients to this service.
2405 static struct TransportClient *clients_tail;
2408 * Statistics handle.
2410 static struct GNUNET_STATISTICS_Handle *GST_stats;
2413 * Configuration handle.
2415 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2420 static struct GNUNET_PeerIdentity GST_my_identity;
2425 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2428 * Map from PIDs to `struct Neighbour` entries. A peer is
2429 * a neighbour if we have an MQ to it from some communicator.
2431 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2434 * Map from PIDs to `struct Backtalker` entries. A peer is
2435 * a backtalker if it recently send us backchannel messages.
2437 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2440 * Map from PIDs to `struct AcknowledgementCummulator`s.
2441 * Here we track the cummulative ACKs for transmission.
2443 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2446 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2447 * a `struct PendingAcknowledgement`.
2449 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2452 * Map from PIDs to `struct DistanceVector` entries describing
2453 * known paths to the peer.
2455 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2458 * Map from PIDs to `struct ValidationState` entries describing
2459 * addresses we are aware of and their validity state.
2461 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2464 * Map from PIDs to `struct VirtualLink` entries describing
2465 * links CORE knows to exist.
2467 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2470 * Map from challenges to `struct LearnLaunchEntry` values.
2472 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2475 * Head of a DLL sorted by launch time.
2477 static struct LearnLaunchEntry *lle_head;
2480 * Tail of a DLL sorted by launch time.
2482 static struct LearnLaunchEntry *lle_tail;
2485 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2486 * sorting addresses we are aware of by when we should next try to (re)validate
2489 static struct GNUNET_CONTAINER_Heap *validation_heap;
2492 * Database for peer's HELLOs.
2494 static struct GNUNET_PEERSTORE_Handle *peerstore;
2497 * Heap sorting `struct EphemeralCacheEntry` by their
2498 * key/signature validity.
2500 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2503 * Hash map for looking up `struct EphemeralCacheEntry`s
2504 * by peer identity. (We may have ephemerals in our
2505 * cache for which we do not have a neighbour entry,
2506 * and similar many neighbours may not need ephemerals,
2507 * so we use a second map.)
2509 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2512 * Task to free expired ephemerals.
2514 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2517 * Task run to initiate DV learning.
2519 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2522 * Task to run address validation.
2524 static struct GNUNET_SCHEDULER_Task *validation_task;
2527 * The most recent PA we have created, head of DLL.
2528 * The length of the DLL is kept in #pa_count.
2530 static struct PendingAcknowledgement *pa_head;
2533 * The oldest PA we have created, tail of DLL.
2534 * The length of the DLL is kept in #pa_count.
2536 static struct PendingAcknowledgement *pa_tail;
2539 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2540 * limit the size of the data structure.
2542 static unsigned int pa_count;
2545 * Monotonic time we use for HELLOs generated at this time. TODO: we
2546 * should increase this value from time to time (i.e. whenever a
2547 * `struct AddressListEntry` actually expires), but IF we do this, we
2548 * must also update *all* (remaining) addresses in the PEERSTORE at
2549 * that time! (So for now only increased when the peer is restarted,
2550 * which hopefully roughly matches whenever our addresses change.)
2552 static struct GNUNET_TIME_Absolute hello_mono_time;
2556 * Get an offset into the transmission history buffer for `struct
2557 * PerformanceData`. Note that the caller must perform the required
2558 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2561 * An 'age' lasts 15 minute slots.
2563 * @return current age of the world
2568 struct GNUNET_TIME_Absolute now;
2570 now = GNUNET_TIME_absolute_get ();
2571 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2576 * Release @a pa data structure.
2578 * @param pa data structure to release
2581 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2583 struct Queue *q = pa->queue;
2584 struct PendingMessage *pm = pa->pm;
2585 struct DistanceVectorHop *dvh = pa->dvh;
2587 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2591 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2596 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2601 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2604 GNUNET_assert (GNUNET_YES ==
2605 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2606 &pa->ack_uuid.value,
2613 * Free cached ephemeral key.
2615 * @param ece cached signature to free
2618 free_ephemeral (struct EphemeralCacheEntry *ece)
2620 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2621 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2627 * Free virtual link.
2629 * @param vl link data to free
2632 free_virtual_link (struct VirtualLink *vl)
2634 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2635 if (NULL != vl->visibility_task)
2637 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2638 vl->visibility_task = NULL;
2640 GNUNET_break (NULL == vl->n);
2641 GNUNET_break (NULL == vl->dv);
2647 * Free validation state.
2649 * @param vs validation state to free
2652 free_validation_state (struct ValidationState *vs)
2654 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2655 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2659 GNUNET_PEERSTORE_store_cancel (vs->sc);
2662 GNUNET_free (vs->address);
2668 * Lookup neighbour record for peer @a pid.
2670 * @param pid neighbour to look for
2671 * @return NULL if we do not have this peer as a neighbour
2673 static struct Neighbour *
2674 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2676 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2681 * Details about what to notify monitors about.
2686 * @deprecated To be discussed if we keep these...
2688 struct GNUNET_TIME_Absolute last_validation;
2689 struct GNUNET_TIME_Absolute valid_until;
2690 struct GNUNET_TIME_Absolute next_validation;
2693 * Current round-trip time estimate.
2695 struct GNUNET_TIME_Relative rtt;
2698 * Connection status.
2700 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2705 uint32_t num_msg_pending;
2710 uint32_t num_bytes_pending;
2715 * Free a @dvh. Callers MAY want to check if this was the last path to the
2716 * `target`, and if so call #free_dv_route to also free the associated DV
2717 * entry in #dv_routes (if not, the associated scheduler job should eventually
2720 * @param dvh hop to free
2723 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2725 struct Neighbour *n = dvh->next_hop;
2726 struct DistanceVector *dv = dvh->dv;
2727 struct PendingAcknowledgement *pa;
2728 struct PendingMessage *pm;
2730 while (NULL != (pm = dvh->pending_msg_head))
2732 GNUNET_CONTAINER_MDLL_remove (dvh,
2733 dvh->pending_msg_head,
2734 dvh->pending_msg_tail,
2738 while (NULL != (pa = dvh->pa_head))
2740 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2743 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2744 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2750 * Free entry in #dv_routes. First frees all hops to the target, and
2751 * if there are no entries left, frees @a dv as well.
2753 * @param dv route to free
2756 free_dv_route (struct DistanceVector *dv)
2758 struct DistanceVectorHop *dvh;
2760 while (NULL != (dvh = dv->dv_head))
2761 free_distance_vector_hop (dvh);
2762 if (NULL == dv->dv_head)
2766 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2767 if (NULL != dv->timeout_task)
2768 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2775 * Notify monitor @a tc about an event. That @a tc
2776 * cares about the event has already been checked.
2778 * Send @a tc information in @a me about a @a peer's status with
2779 * respect to some @a address to all monitors that care.
2781 * @param tc monitor to inform
2782 * @param peer peer the information is about
2783 * @param address address the information is about
2784 * @param nt network type associated with @a address
2785 * @param me detailed information to transmit
2788 notify_monitor (struct TransportClient *tc,
2789 const struct GNUNET_PeerIdentity *peer,
2790 const char *address,
2791 enum GNUNET_NetworkType nt,
2792 const struct MonitorEvent *me)
2794 struct GNUNET_MQ_Envelope *env;
2795 struct GNUNET_TRANSPORT_MonitorData *md;
2796 size_t addr_len = strlen (address) + 1;
2798 env = GNUNET_MQ_msg_extra (md,
2800 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2801 md->nt = htonl ((uint32_t) nt);
2803 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2804 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2805 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2806 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2807 md->cs = htonl ((uint32_t) me->cs);
2808 md->num_msg_pending = htonl (me->num_msg_pending);
2809 md->num_bytes_pending = htonl (me->num_bytes_pending);
2810 memcpy (&md[1], address, addr_len);
2811 GNUNET_MQ_send (tc->mq, env);
2816 * Send information in @a me about a @a peer's status with respect
2817 * to some @a address to all monitors that care.
2819 * @param peer peer the information is about
2820 * @param address address the information is about
2821 * @param nt network type associated with @a address
2822 * @param me detailed information to transmit
2825 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2826 const char *address,
2827 enum GNUNET_NetworkType nt,
2828 const struct MonitorEvent *me)
2830 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2832 if (CT_MONITOR != tc->type)
2834 if (tc->details.monitor.one_shot)
2836 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2837 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2839 notify_monitor (tc, peer, address, nt, me);
2845 * Called whenever a client connects. Allocates our
2846 * data structures associated with that client.
2848 * @param cls closure, NULL
2849 * @param client identification of the client
2850 * @param mq message queue for the client
2851 * @return our `struct TransportClient`
2854 client_connect_cb (void *cls,
2855 struct GNUNET_SERVICE_Client *client,
2856 struct GNUNET_MQ_Handle *mq)
2858 struct TransportClient *tc;
2861 tc = GNUNET_new (struct TransportClient);
2862 tc->client = client;
2864 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2873 * @param rc data structure to free
2876 free_reassembly_context (struct ReassemblyContext *rc)
2878 struct Neighbour *n = rc->neighbour;
2880 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2881 GNUNET_assert (GNUNET_OK ==
2882 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2890 * Task run to clean up reassembly context of a neighbour that have expired.
2892 * @param cls a `struct Neighbour`
2895 reassembly_cleanup_task (void *cls)
2897 struct Neighbour *n = cls;
2898 struct ReassemblyContext *rc;
2900 n->reassembly_timeout_task = NULL;
2901 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2903 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2906 free_reassembly_context (rc);
2909 GNUNET_assert (NULL == n->reassembly_timeout_task);
2910 n->reassembly_timeout_task =
2911 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2912 &reassembly_cleanup_task,
2920 * function called to #free_reassembly_context().
2924 * @param value a `struct ReassemblyContext` to free
2925 * @return #GNUNET_OK (continue iteration)
2928 free_reassembly_cb (void *cls, uint32_t key, void *value)
2930 struct ReassemblyContext *rc = value;
2934 free_reassembly_context (rc);
2940 * Release memory used by @a neighbour.
2942 * @param neighbour neighbour entry to free
2945 free_neighbour (struct Neighbour *neighbour)
2947 struct DistanceVectorHop *dvh;
2949 GNUNET_assert (NULL == neighbour->queue_head);
2950 GNUNET_assert (GNUNET_YES ==
2951 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2954 if (NULL != neighbour->reassembly_map)
2956 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2957 &free_reassembly_cb,
2959 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2960 neighbour->reassembly_map = NULL;
2961 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2962 neighbour->reassembly_heap = NULL;
2964 while (NULL != (dvh = neighbour->dv_head))
2966 struct DistanceVector *dv = dvh->dv;
2968 free_distance_vector_hop (dvh);
2969 if (NULL == dv->dv_head)
2972 if (NULL != neighbour->reassembly_timeout_task)
2974 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2975 neighbour->reassembly_timeout_task = NULL;
2977 if (NULL != neighbour->get)
2979 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2980 neighbour->get = NULL;
2982 if (NULL != neighbour->sc)
2984 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2985 neighbour->sc = NULL;
2987 GNUNET_free (neighbour);
2992 * Send message to CORE clients that we lost a connection.
2994 * @param tc client to inform (must be CORE client)
2995 * @param pid peer the connection is for
2998 core_send_connect_info (struct TransportClient *tc,
2999 const struct GNUNET_PeerIdentity *pid)
3001 struct GNUNET_MQ_Envelope *env;
3002 struct ConnectInfoMessage *cim;
3004 GNUNET_assert (CT_CORE == tc->type);
3005 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3007 GNUNET_MQ_send (tc->mq, env);
3012 * Send message to CORE clients that we gained a connection
3014 * @param pid peer the queue was for
3017 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3019 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3020 "Informing CORE clients about connection to %s\n",
3022 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3024 if (CT_CORE != tc->type)
3026 core_send_connect_info (tc, pid);
3032 * Send message to CORE clients that we lost a connection.
3034 * @param pid peer the connection was for
3037 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3040 "Informing CORE clients about disconnect from %s\n",
3042 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3044 struct GNUNET_MQ_Envelope *env;
3045 struct DisconnectInfoMessage *dim;
3047 if (CT_CORE != tc->type)
3049 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3051 GNUNET_MQ_send (tc->mq, env);
3057 * We believe we are ready to transmit a message on a queue. Gives the
3058 * message to the communicator for transmission (updating the tracker,
3059 * and re-scheduling itself if applicable).
3061 * @param cls the `struct Queue` to process transmissions for
3064 transmit_on_queue (void *cls);
3068 * Schedule next run of #transmit_on_queue(). Does NOTHING if
3069 * we should run immediately or if the message queue is empty.
3070 * Test for no task being added AND queue not being empty to
3071 * transmit immediately afterwards! This function must only
3072 * be called if the message queue is non-empty!
3074 * @param queue the queue to do scheduling for
3075 * @param inside_job set to #GNUNET_YES if called from
3076 * #transmit_on_queue() itself and NOT setting
3077 * the task means running immediately
3080 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3082 struct Neighbour *n = queue->neighbour;
3083 struct PendingMessage *pm = n->pending_msg_head;
3084 struct GNUNET_TIME_Relative out_delay;
3086 GNUNET_assert (NULL != pm);
3087 if (queue->tc->details.communicator.total_queue_length >=
3088 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3090 GNUNET_STATISTICS_update (
3092 "# Transmission throttled due to communicator queue limit",
3097 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3099 GNUNET_STATISTICS_update (GST_stats,
3100 "# Transmission throttled due to queue queue limit",
3106 out_delay = GNUNET_TIME_absolute_get_remaining (pm->next_attempt);
3107 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3110 GNUNET_ERROR_TYPE_DEBUG,
3111 "Schedule transmission on queue %llu of %s decides to run immediately\n",
3112 (unsigned long long) queue->qid,
3113 GNUNET_i2s (&n->pid));
3114 return; /* we should run immediately! */
3116 /* queue has changed since we were scheduled, reschedule again */
3117 queue->transmit_task =
3118 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3119 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3120 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3121 "Next transmission on queue `%s' in %s (high delay)\n",
3123 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3126 "Next transmission on queue `%s' in %s\n",
3128 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3133 * Task run to check whether the hops of the @a cls still
3134 * are validated, or if we need to core about disconnection.
3136 * @param cls a `struct VirtualLink`
3139 check_link_down (void *cls)
3141 struct VirtualLink *vl = cls;
3142 struct DistanceVector *dv = vl->dv;
3143 struct Neighbour *n = vl->n;
3144 struct GNUNET_TIME_Absolute dvh_timeout;
3145 struct GNUNET_TIME_Absolute q_timeout;
3147 vl->visibility_task = NULL;
3148 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3149 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3151 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3152 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3154 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3155 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3156 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3157 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3159 if ((NULL == vl->n) && (NULL == vl->dv))
3161 cores_send_disconnect_info (&dv->target);
3162 free_virtual_link (vl);
3165 vl->visibility_task =
3166 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3175 * @param queue the queue to free
3178 free_queue (struct Queue *queue)
3180 struct Neighbour *neighbour = queue->neighbour;
3181 struct TransportClient *tc = queue->tc;
3182 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3183 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3184 struct QueueEntry *qe;
3186 struct PendingAcknowledgement *pa;
3187 struct VirtualLink *vl;
3189 if (NULL != queue->transmit_task)
3191 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3192 queue->transmit_task = NULL;
3194 while (NULL != (pa = queue->pa_head))
3196 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3200 GNUNET_CONTAINER_MDLL_remove (neighbour,
3201 neighbour->queue_head,
3202 neighbour->queue_tail,
3204 GNUNET_CONTAINER_MDLL_remove (client,
3205 tc->details.communicator.queue_head,
3206 tc->details.communicator.queue_tail,
3208 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3209 tc->details.communicator.total_queue_length);
3210 while (NULL != (qe = queue->queue_head))
3212 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3213 queue->queue_length--;
3214 tc->details.communicator.total_queue_length--;
3217 GNUNET_assert (qe == qe->pm->qe);
3222 GNUNET_assert (0 == queue->queue_length);
3223 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3224 tc->details.communicator.total_queue_length))
3226 /* Communicator dropped below threshold, resume all queues */
3227 GNUNET_STATISTICS_update (
3229 "# Transmission throttled due to communicator queue limit",
3232 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3234 schedule_transmit_on_queue (s, GNUNET_NO);
3236 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3237 GNUNET_free (queue);
3239 vl = GNUNET_CONTAINER_multipeermap_get (links, &neighbour->pid);
3240 if ((NULL != vl) && (neighbour == vl->n))
3242 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3243 check_link_down (vl);
3245 if (NULL == neighbour->queue_head)
3247 free_neighbour (neighbour);
3255 * @param ale address list entry to free
3258 free_address_list_entry (struct AddressListEntry *ale)
3260 struct TransportClient *tc = ale->tc;
3262 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3263 tc->details.communicator.addr_tail,
3265 if (NULL != ale->sc)
3267 GNUNET_PEERSTORE_store_cancel (ale->sc);
3270 if (NULL != ale->st)
3272 GNUNET_SCHEDULER_cancel (ale->st);
3280 * Stop the peer request in @a value.
3282 * @param cls a `struct TransportClient` that no longer makes the request
3283 * @param pid the peer's identity
3284 * @param value a `struct PeerRequest`
3285 * @return #GNUNET_YES (always)
3288 stop_peer_request (void *cls,
3289 const struct GNUNET_PeerIdentity *pid,
3292 struct TransportClient *tc = cls;
3293 struct PeerRequest *pr = value;
3295 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3298 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3308 * Called whenever a client is disconnected. Frees our
3309 * resources associated with that client.
3311 * @param cls closure, NULL
3312 * @param client identification of the client
3313 * @param app_ctx our `struct TransportClient`
3316 client_disconnect_cb (void *cls,
3317 struct GNUNET_SERVICE_Client *client,
3320 struct TransportClient *tc = app_ctx;
3324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3325 "Client %p disconnected, cleaning up.\n",
3327 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3333 struct PendingMessage *pm;
3335 while (NULL != (pm = tc->details.core.pending_msg_head))
3337 GNUNET_CONTAINER_MDLL_remove (client,
3338 tc->details.core.pending_msg_head,
3339 tc->details.core.pending_msg_tail,
3347 case CT_COMMUNICATOR: {
3349 struct AddressListEntry *ale;
3351 while (NULL != (q = tc->details.communicator.queue_head))
3353 while (NULL != (ale = tc->details.communicator.addr_head))
3354 free_address_list_entry (ale);
3355 GNUNET_free (tc->details.communicator.address_prefix);
3358 case CT_APPLICATION:
3359 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3362 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3370 * Iterator telling new CORE client about all existing
3371 * connections to peers.
3373 * @param cls the new `struct TransportClient`
3374 * @param pid a connected peer
3375 * @param value the `struct Neighbour` with more information
3376 * @return #GNUNET_OK (continue to iterate)
3379 notify_client_connect_info (void *cls,
3380 const struct GNUNET_PeerIdentity *pid,
3383 struct TransportClient *tc = cls;
3386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3387 "Telling new CORE client about existing connection to %s\n",
3389 core_send_connect_info (tc, pid);
3395 * Initialize a "CORE" client. We got a start message from this
3396 * client, so add it to the list of clients for broadcasting of
3399 * @param cls the client
3400 * @param start the start message that was sent
3403 handle_client_start (void *cls, const struct StartMessage *start)
3405 struct TransportClient *tc = cls;
3408 options = ntohl (start->options);
3409 if ((0 != (1 & options)) &&
3410 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3412 /* client thinks this is a different peer, reject */
3414 GNUNET_SERVICE_client_drop (tc->client);
3417 if (CT_NONE != tc->type)
3420 GNUNET_SERVICE_client_drop (tc->client);
3424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3425 "New CORE client with PID %s registered\n",
3426 GNUNET_i2s (&start->self));
3427 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3428 ¬ify_client_connect_info,
3430 GNUNET_SERVICE_client_continue (tc->client);
3435 * Client asked for transmission to a peer. Process the request.
3437 * @param cls the client
3438 * @param obm the send message that was sent
3441 check_client_send (void *cls, const struct OutboundMessage *obm)
3443 struct TransportClient *tc = cls;
3445 const struct GNUNET_MessageHeader *obmm;
3447 if (CT_CORE != tc->type)
3450 return GNUNET_SYSERR;
3452 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3453 if (size < sizeof (struct GNUNET_MessageHeader))
3456 return GNUNET_SYSERR;
3458 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3459 if (size != ntohs (obmm->size))
3462 return GNUNET_SYSERR;
3469 * Free fragment tree below @e root, excluding @e root itself.
3470 * FIXME: this does NOT seem to have the intended semantics
3471 * based on how this is called. Seems we generally DO expect
3472 * @a root to be free'ed itself as well!
3474 * @param root root of the tree to free
3477 free_fragment_tree (struct PendingMessage *root)
3479 struct PendingMessage *frag;
3481 while (NULL != (frag = root->head_frag))
3483 struct PendingAcknowledgement *pa;
3485 free_fragment_tree (frag);
3486 while (NULL != (pa = frag->pa_head))
3488 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3491 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3498 * Release memory associated with @a pm and remove @a pm from associated
3499 * data structures. @a pm must be a top-level pending message and not
3500 * a fragment in the tree. The entire tree is freed (if applicable).
3502 * @param pm the pending message to free
3505 free_pending_message (struct PendingMessage *pm)
3507 struct TransportClient *tc = pm->client;
3508 struct Neighbour *target = pm->target;
3509 struct DistanceVectorHop *dvh = pm->dvh;
3510 struct PendingAcknowledgement *pa;
3514 GNUNET_CONTAINER_MDLL_remove (client,
3515 tc->details.core.pending_msg_head,
3516 tc->details.core.pending_msg_tail,
3521 GNUNET_CONTAINER_MDLL_remove (dvh,
3522 dvh->pending_msg_head,
3523 dvh->pending_msg_tail,
3526 GNUNET_CONTAINER_MDLL_remove (neighbour,
3527 target->pending_msg_head,
3528 target->pending_msg_tail,
3530 while (NULL != (pa = pm->pa_head))
3532 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3536 free_fragment_tree (pm);
3539 GNUNET_assert (pm == pm->qe->pm);
3542 GNUNET_free_non_null (pm->bpm);
3548 * Send a response to the @a pm that we have processed a "send"
3549 * request. Sends a confirmation to the "core" client responsible for
3550 * the original request and free's @a pm.
3552 * @param pm handle to the original pending message
3555 client_send_response (struct PendingMessage *pm)
3557 struct TransportClient *tc = pm->client;
3558 struct Neighbour *target = pm->target;
3559 struct GNUNET_MQ_Envelope *env;
3560 struct SendOkMessage *som;
3564 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3565 som->peer = target->pid;
3566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3567 "Confirming transmission to %s\n",
3568 GNUNET_i2s (&pm->target->pid));
3569 GNUNET_MQ_send (tc->mq, env);
3571 free_pending_message (pm);
3576 * Create a DV Box message.
3578 * @param total_hops how many hops did the message take so far
3579 * @param num_hops length of the @a hops array
3580 * @param origin origin of the message
3581 * @param hops next peer(s) to the destination, including destination
3582 * @param payload payload of the box
3583 * @param payload_size number of bytes in @a payload
3584 * @return boxed message (caller must #GNUNET_free() it).
3586 static struct TransportDVBoxMessage *
3587 create_dv_box (uint16_t total_hops,
3588 const struct GNUNET_PeerIdentity *origin,
3589 const struct GNUNET_PeerIdentity *target,
3591 const struct GNUNET_PeerIdentity *hops,
3592 const void *payload,
3593 uint16_t payload_size)
3595 struct TransportDVBoxMessage *dvb;
3596 struct GNUNET_PeerIdentity *dhops;
3598 GNUNET_assert (UINT16_MAX <
3599 sizeof (struct TransportDVBoxMessage) +
3600 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3602 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3603 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3606 htons (sizeof (struct TransportDVBoxMessage) +
3607 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3608 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3609 dvb->total_hops = htons (total_hops);
3610 dvb->num_hops = htons (num_hops + 1);
3611 dvb->origin = *origin;
3612 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3613 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3614 dhops[num_hops] = *target;
3615 memcpy (&dhops[num_hops + 1], payload, payload_size);
3617 if (GNUNET_EXTRA_LOGGING > 0)
3621 path = GNUNET_strdup (GNUNET_i2s (&dvb->origin));
3622 for (unsigned int i = 0; i <= num_hops; i++)
3626 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
3630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3631 "Creating DVBox for %u bytes of payload via %s\n",
3632 (unsigned int) payload_size,
3642 * Pick @a hops_array_length random DV paths satisfying @a options
3644 * @param dv data structure to pick paths from
3645 * @param options constraints to satisfy
3646 * @param hops_array[out] set to the result
3647 * @param hops_array_length length of the @a hops_array
3648 * @return number of entries set in @a hops_array
3651 pick_random_dv_hops (const struct DistanceVector *dv,
3652 enum RouteMessageOptions options,
3653 struct DistanceVectorHop **hops_array,
3654 unsigned int hops_array_length)
3656 uint64_t choices[hops_array_length];
3658 unsigned int dv_count;
3660 /* Pick random vectors, but weighted by distance, giving more weight
3661 to shorter vectors */
3664 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3667 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3668 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3669 .rel_value_us == 0))
3670 continue; /* pos unconfirmed and confirmed required */
3671 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3676 if (dv_count <= hops_array_length)
3679 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3681 hops_array[dv_count++] = pos;
3684 for (unsigned int i = 0; i < hops_array_length; i++)
3687 while (GNUNET_NO == ok)
3690 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3692 for (unsigned int j = 0; j < i; j++)
3693 if (choices[i] == choices[j])
3702 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3705 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3707 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3708 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3709 .rel_value_us == 0))
3710 continue; /* pos unconfirmed and confirmed required */
3711 for (unsigned int i = 0; i < hops_array_length; i++)
3712 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3713 hops_array[dv_count++] = pos;
3721 * Client asked for transmission to a peer. Process the request.
3723 * @param cls the client
3724 * @param obm the send message that was sent
3727 handle_client_send (void *cls, const struct OutboundMessage *obm)
3729 struct TransportClient *tc = cls;
3730 struct PendingMessage *pm;
3731 const struct GNUNET_MessageHeader *obmm;
3732 struct Neighbour *target;
3733 struct DistanceVector *dv;
3734 struct DistanceVectorHop *dvh;
3737 const void *payload;
3738 size_t payload_size;
3739 struct TransportDVBoxMessage *dvb;
3740 struct VirtualLink *vl;
3741 enum GNUNET_MQ_PriorityPreferences pp;
3743 GNUNET_assert (CT_CORE == tc->type);
3744 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3745 bytes_msg = ntohs (obmm->size);
3746 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
3747 vl = GNUNET_CONTAINER_multipeermap_get (links, &obm->peer);
3750 /* Failure: don't have this peer as a neighbour (anymore).
3751 Might have gone down asynchronously, so this is NOT
3752 a protocol violation by CORE. Still count the event,
3753 as this should be rare. */
3754 GNUNET_SERVICE_client_continue (tc->client);
3755 GNUNET_STATISTICS_update (GST_stats,
3756 "# messages dropped (neighbour unknown)",
3761 target = lookup_neighbour (&obm->peer);
3763 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3766 GNUNET_assert ((NULL != target) || (NULL != dv));
3767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3768 "Sending %u bytes to %s using %s\n",
3770 GNUNET_i2s (&obm->peer),
3771 (NULL == target) ? "distance vector path" : "direct queue");
3775 struct DistanceVectorHop *dvh;
3777 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3778 GNUNET_assert (1 == res);
3779 target = dvh->next_hop;
3780 dvb = create_dv_box (0,
3788 payload_size = ntohs (dvb->header.size);
3795 payload_size = bytes_msg;
3798 was_empty = (NULL == target->pending_msg_head);
3799 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3802 pm->target = target;
3803 pm->bytes_msg = payload_size;
3804 memcpy (&pm[1], payload, payload_size);
3805 GNUNET_free_non_null (dvb);
3810 GNUNET_CONTAINER_MDLL_insert (dvh,
3811 dvh->pending_msg_head,
3812 dvh->pending_msg_tail,
3815 GNUNET_CONTAINER_MDLL_insert (neighbour,
3816 target->pending_msg_head,
3817 target->pending_msg_tail,
3819 GNUNET_CONTAINER_MDLL_insert (client,
3820 tc->details.core.pending_msg_head,
3821 tc->details.core.pending_msg_tail,
3824 return; /* all queues must already be busy */
3825 for (struct Queue *queue = target->queue_head; NULL != queue;
3826 queue = queue->next_neighbour)
3828 /* try transmission on any queue that is idle */
3829 if (NULL == queue->transmit_task)
3831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3832 "Queue %llu to %s is idle, triggering transmission\n",
3833 (unsigned long long) queue->qid,
3834 GNUNET_i2s (&queue->neighbour->pid));
3835 queue->transmit_task =
3836 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3843 * Communicator started. Test message is well-formed.
3845 * @param cls the client
3846 * @param cam the send message that was sent
3849 check_communicator_available (
3851 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3853 struct TransportClient *tc = cls;
3856 if (CT_NONE != tc->type)
3859 return GNUNET_SYSERR;
3861 tc->type = CT_COMMUNICATOR;
3862 size = ntohs (cam->header.size) - sizeof (*cam);
3864 return GNUNET_OK; /* receive-only communicator */
3865 GNUNET_MQ_check_zero_termination (cam);
3871 * Send ACK to communicator (if requested) and free @a cmc.
3873 * @param cmc context for which we are done handling the message
3876 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3878 if (0 != ntohl (cmc->im.fc_on))
3880 /* send ACK when done to communicator for flow control! */
3881 struct GNUNET_MQ_Envelope *env;
3882 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3884 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3885 ack->reserved = htonl (0);
3886 ack->fc_id = cmc->im.fc_id;
3887 ack->sender = cmc->im.sender;
3888 GNUNET_MQ_send (cmc->tc->mq, env);
3890 GNUNET_SERVICE_client_continue (cmc->tc->client);
3896 * Client confirms that it is done handling message(s) to a particular
3897 * peer. We may now provide more messages to CORE for this peer.
3899 * Notifies the respective queues that more messages can now be received.
3901 * @param cls the client
3902 * @param rom the message that was sent
3905 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
3907 struct TransportClient *tc = cls;
3908 struct VirtualLink *vl;
3910 struct CommunicatorMessageContext *cmc;
3912 if (CT_CORE != tc->type)
3915 GNUNET_SERVICE_client_drop (tc->client);
3918 vl = GNUNET_CONTAINER_multipeermap_get (links, &rom->peer);
3921 GNUNET_STATISTICS_update (GST_stats,
3922 "# RECV_OK dropped: virtual link unknown",
3925 GNUNET_SERVICE_client_continue (tc->client);
3928 delta = ntohl (rom->increase_window_delta);
3929 vl->core_recv_window += delta;
3930 if (vl->core_recv_window <= 0)
3932 /* resume communicators */
3933 while (NULL != (cmc = vl->cmc_tail))
3935 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
3936 finish_cmc_handling (cmc);
3942 * Communicator started. Process the request.
3944 * @param cls the client
3945 * @param cam the send message that was sent
3948 handle_communicator_available (
3950 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3952 struct TransportClient *tc = cls;
3955 size = ntohs (cam->header.size) - sizeof (*cam);
3958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3959 "Receive-only communicator connected\n");
3960 return; /* receive-only communicator */
3962 tc->details.communicator.address_prefix =
3963 GNUNET_strdup ((const char *) &cam[1]);
3964 tc->details.communicator.cc =
3965 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3967 "Communicator with prefix `%s' connected\n",
3968 tc->details.communicator.address_prefix);
3969 GNUNET_SERVICE_client_continue (tc->client);
3974 * Communicator requests backchannel transmission. Check the request.
3976 * @param cls the client
3977 * @param cb the send message that was sent
3978 * @return #GNUNET_OK if message is well-formed
3981 check_communicator_backchannel (
3983 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3985 const struct GNUNET_MessageHeader *inbox;
3991 msize = ntohs (cb->header.size) - sizeof (*cb);
3992 if (((size_t) (UINT16_MAX - msize)) >
3993 sizeof (struct TransportBackchannelEncapsulationMessage) +
3994 sizeof (struct TransportBackchannelRequestPayloadP))
3997 return GNUNET_SYSERR;
3999 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4000 isize = ntohs (inbox->size);
4004 return GNUNET_SYSERR;
4006 is = (const char *) inbox;
4009 GNUNET_assert (msize > 0);
4010 if ('\0' != is[msize - 1])
4013 return GNUNET_SYSERR;
4020 * Remove memory used by expired ephemeral keys.
4025 expire_ephemerals (void *cls)
4027 struct EphemeralCacheEntry *ece;
4030 ephemeral_task = NULL;
4031 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
4033 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4036 free_ephemeral (ece);
4039 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4048 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists,
4049 * generate one, cache it and return it.
4051 * @param pid peer to look up ephemeral for
4052 * @param private_key[out] set to the private key
4053 * @param ephemeral_key[out] set to the key
4054 * @param ephemeral_sender_sig[out] set to the signature
4055 * @param monotime[out] set to the monotime used for the signature
4058 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
4059 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
4060 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
4061 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
4062 struct GNUNET_TIME_Absolute *monotime)
4064 struct EphemeralCacheEntry *ece;
4065 struct EphemeralConfirmationPS ec;
4067 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
4068 if ((NULL != ece) &&
4069 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4072 free_ephemeral (ece);
4077 ece = GNUNET_new (struct EphemeralCacheEntry);
4079 ece->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4080 ece->ephemeral_validity =
4081 GNUNET_TIME_absolute_add (ece->monotime, EPHEMERAL_VALIDITY);
4082 GNUNET_assert (GNUNET_OK ==
4083 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
4084 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
4085 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4086 ec.purpose.size = htonl (sizeof (ec));
4088 ec.ephemeral_key = ece->ephemeral_key;
4089 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4093 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
4095 ece->ephemeral_validity.abs_value_us);
4096 GNUNET_assert (GNUNET_OK ==
4097 GNUNET_CONTAINER_multipeermap_put (
4101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4102 if (NULL == ephemeral_task)
4103 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4107 *private_key = ece->private_key;
4108 *ephemeral_key = ece->ephemeral_key;
4109 *ephemeral_sender_sig = ece->sender_sig;
4110 *monotime = ece->monotime;
4115 * Send the control message @a payload on @a queue.
4117 * @param queue the queue to use for transmission
4118 * @param pm pending message to update once transmission is done, may be NULL!
4119 * @param payload the payload to send (encapsulated in a
4120 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4121 * @param payload_size number of bytes in @a payload
4124 queue_send_msg (struct Queue *queue,
4125 struct PendingMessage *pm,
4126 const void *payload,
4127 size_t payload_size)
4129 struct Neighbour *n = queue->neighbour;
4130 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4131 struct GNUNET_MQ_Envelope *env;
4133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4134 "Queueing %u bytes of payload for transmission on queue %llu to %s\n",
4135 (unsigned int) payload_size,
4136 (unsigned long long) queue->qid,
4137 GNUNET_i2s (&queue->neighbour->pid));
4138 env = GNUNET_MQ_msg_extra (smt,
4140 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4141 smt->qid = queue->qid;
4142 smt->mid = queue->mid_gen;
4143 smt->receiver = n->pid;
4144 memcpy (&smt[1], payload, payload_size);
4146 /* Pass the env to the communicator of queue for transmission. */
4147 struct QueueEntry *qe;
4149 qe = GNUNET_new (struct QueueEntry);
4150 qe->mid = queue->mid_gen++;
4155 GNUNET_assert (NULL == pm->qe);
4158 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4159 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4160 queue->queue_length++;
4161 queue->tc->details.communicator.total_queue_length++;
4162 GNUNET_MQ_send (queue->tc->mq, env);
4167 // FIXME: improve logging after this point!
4170 * Pick a queue of @a n under constraints @a options and schedule
4171 * transmission of @a hdr.
4173 * @param n neighbour to send to
4174 * @param hdr message to send as payload
4175 * @param options whether queues must be confirmed or not,
4176 * and whether we may pick multiple (2) queues
4179 route_via_neighbour (const struct Neighbour *n,
4180 const struct GNUNET_MessageHeader *hdr,
4181 enum RouteMessageOptions options)
4183 struct GNUNET_TIME_Absolute now;
4184 unsigned int candidates;
4188 /* Pick one or two 'random' queues from n (under constraints of options) */
4189 now = GNUNET_TIME_absolute_get ();
4190 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4191 weight in the future; weight could be assigned by observed
4192 bandwidth (note: not sure if we should do this for this type
4193 of control traffic though). */
4195 for (struct Queue *pos = n->queue_head; NULL != pos;
4196 pos = pos->next_neighbour)
4198 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4199 (pos->validated_until.abs_value_us > now.abs_value_us))
4202 if (0 == candidates)
4204 /* This can happen rarely if the last confirmed queue timed
4205 out just as we were beginning to process this message. */
4206 GNUNET_STATISTICS_update (GST_stats,
4207 "# route selection failed (all no valid queue)",
4212 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4213 if (0 == (options & RMO_REDUNDANT))
4214 sel2 = candidates; /* picks none! */
4216 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4218 for (struct Queue *pos = n->queue_head; NULL != pos;
4219 pos = pos->next_neighbour)
4221 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4222 (pos->validated_until.abs_value_us > now.abs_value_us))
4224 if ((sel1 == candidates) || (sel2 == candidates))
4225 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4233 * Given a distance vector path @a dvh route @a payload to
4234 * the ultimate destination respecting @a options.
4235 * Sets up the boxed message and queues it at the next hop.
4237 * @param dvh choice of the path for the message
4238 * @param payload body to transmit
4239 * @param options options to use for control
4242 forward_via_dvh (const struct DistanceVectorHop *dvh,
4243 const struct GNUNET_MessageHeader *payload,
4244 enum RouteMessageOptions options)
4246 struct TransportDVBoxMessage *dvb;
4248 dvb = create_dv_box (0,
4254 ntohs (payload->size));
4255 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4261 * Pick a path of @a dv under constraints @a options and schedule
4262 * transmission of @a hdr.
4264 * @param n neighbour to send to
4265 * @param hdr message to send as payload
4266 * @param options whether path must be confirmed or not
4267 * and whether we may pick multiple (2) paths
4270 route_via_dv (const struct DistanceVector *dv,
4271 const struct GNUNET_MessageHeader *hdr,
4272 enum RouteMessageOptions options)
4274 struct DistanceVectorHop *hops[2];
4277 res = pick_random_dv_hops (dv,
4280 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4281 for (unsigned int i = 0; i < res; i++)
4282 forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT));
4287 * We need to transmit @a hdr to @a target. If necessary, this may
4288 * involve DV routing.
4290 * @param target peer to receive @a hdr
4291 * @param hdr header of the message to route and #GNUNET_free()
4292 * @param options which transmission channels are allowed
4295 route_message (const struct GNUNET_PeerIdentity *target,
4296 struct GNUNET_MessageHeader *hdr,
4297 enum RouteMessageOptions options)
4299 struct VirtualLink *vl;
4300 struct Neighbour *n;
4301 struct DistanceVector *dv;
4303 vl = GNUNET_CONTAINER_multipeermap_get (links, target);
4305 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4306 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4308 /* if confirmed is required, and we do not have anything
4309 confirmed, drop respective options */
4311 n = lookup_neighbour (target);
4312 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4313 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4315 if ((NULL == n) && (NULL == dv))
4317 GNUNET_STATISTICS_update (GST_stats,
4318 "# Messages dropped in routing: no acceptable method",
4324 /* If both dv and n are possible and we must choose:
4325 flip a coin for the choice between the two; for now 50/50 */
4326 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4328 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4333 if ((NULL != n) && (NULL != dv))
4334 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4335 enough for redunancy, so clear the flag. */
4338 route_via_neighbour (n, hdr, options);
4342 route_via_dv (dv, hdr, options);
4349 * Structure of the key material used to encrypt backchannel messages.
4351 struct BackchannelKeyState
4354 * State of our block cipher.
4356 gcry_cipher_hd_t cipher;
4359 * Actual key material.
4365 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4367 struct GNUNET_CRYPTO_AuthKey hmac_key;
4370 * Symmetric key to use for encryption.
4372 char aes_key[256 / 8];
4375 * Counter value to use during setup.
4377 char aes_ctr[128 / 8];
4384 * Given the key material in @a km and the initialization vector
4385 * @a iv, setup the key material for the backchannel in @a key.
4387 * @param km raw master secret
4388 * @param iv initialization vector
4389 * @param key[out] symmetric cipher and HMAC state to generate
4392 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4393 const struct GNUNET_ShortHashCode *iv,
4394 struct BackchannelKeyState *key)
4396 /* must match #dh_key_derive_eph_pub */
4397 GNUNET_assert (GNUNET_YES ==
4398 GNUNET_CRYPTO_kdf (&key->material,
4399 sizeof (key->material),
4400 "transport-backchannel-key",
4401 strlen ("transport-backchannel-key"),
4406 gcry_cipher_open (&key->cipher,
4407 GCRY_CIPHER_AES256 /* low level: go for speed */,
4408 GCRY_CIPHER_MODE_CTR,
4410 gcry_cipher_setkey (key->cipher,
4411 &key->material.aes_key,
4412 sizeof (key->material.aes_key));
4413 gcry_cipher_setctr (key->cipher,
4414 &key->material.aes_ctr,
4415 sizeof (key->material.aes_ctr));
4420 * Derive backchannel encryption key material from @a priv_ephemeral
4421 * and @a target and @a iv.
4423 * @param priv_ephemeral ephemeral private key to use
4424 * @param target the target peer to encrypt to
4425 * @param iv unique IV to use
4426 * @param key[out] set to the key material
4429 dh_key_derive_eph_pid (
4430 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4431 const struct GNUNET_PeerIdentity *target,
4432 const struct GNUNET_ShortHashCode *iv,
4433 struct BackchannelKeyState *key)
4435 struct GNUNET_HashCode km;
4437 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4438 &target->public_key,
4440 bc_setup_key_state_from_km (&km, iv, key);
4445 * Derive backchannel encryption key material from #GST_my_private_key
4446 * and @a pub_ephemeral and @a iv.
4448 * @param priv_ephemeral ephemeral private key to use
4449 * @param target the target peer to encrypt to
4450 * @param iv unique IV to use
4451 * @param key[out] set to the key material
4454 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4455 const struct GNUNET_ShortHashCode *iv,
4456 struct BackchannelKeyState *key)
4458 struct GNUNET_HashCode km;
4460 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4463 bc_setup_key_state_from_km (&km, iv, key);
4468 * Do HMAC calculation for backchannel messages over @a data using key
4469 * material from @a key.
4471 * @param key key material (from DH)
4472 * @param hmac[out] set to the HMAC
4473 * @param data data to perform HMAC calculation over
4474 * @param data_size number of bytes in @a data
4477 bc_hmac (const struct BackchannelKeyState *key,
4478 struct GNUNET_HashCode *hmac,
4482 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4487 * Perform backchannel encryption using symmetric secret in @a key
4488 * to encrypt data from @a in to @a dst.
4490 * @param key[in,out] key material to use
4491 * @param dst where to write the result
4492 * @param in input data to encrypt (plaintext)
4493 * @param in_size number of bytes of input in @a in and available at @a dst
4496 bc_encrypt (struct BackchannelKeyState *key,
4502 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4507 * Perform backchannel encryption using symmetric secret in @a key
4508 * to encrypt data from @a in to @a dst.
4510 * @param key[in,out] key material to use
4511 * @param ciph cipher text to decrypt
4512 * @param out[out] output data to generate (plaintext)
4513 * @param out_size number of bytes of input in @a ciph and available in @a out
4516 bc_decrypt (struct BackchannelKeyState *key,
4522 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4527 * Clean up key material in @a key.
4529 * @param key key material to clean up (memory must not be free'd!)
4532 bc_key_clean (struct BackchannelKeyState *key)
4534 gcry_cipher_close (key->cipher);
4535 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4540 * Communicator requests backchannel transmission. Process the request.
4542 * @param cls the client
4543 * @param cb the send message that was sent
4546 handle_communicator_backchannel (
4548 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4550 struct TransportClient *tc = cls;
4551 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4552 struct GNUNET_TIME_Absolute monotime;
4553 struct TransportBackchannelEncapsulationMessage *enc;
4554 struct TransportBackchannelRequestPayloadP ppay;
4555 struct BackchannelKeyState key;
4559 /* encapsulate and encrypt message */
4560 msize = ntohs (cb->header.size) - sizeof (*cb) +
4561 sizeof (struct TransportBackchannelRequestPayloadP);
4562 enc = GNUNET_malloc (sizeof (*enc) + msize);
4564 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4565 enc->header.size = htons (sizeof (*enc) + msize);
4566 enc->target = cb->pid;
4567 lookup_ephemeral (&cb->pid,
4569 &enc->ephemeral_key,
4572 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4575 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4576 ppay.monotonic_time = GNUNET_TIME_absolute_hton (monotime);
4577 mpos = (char *) &enc[1];
4578 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4581 &mpos[sizeof (ppay)],
4582 ntohs (cb->header.size) - sizeof (*cb));
4586 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4587 bc_key_clean (&key);
4588 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4589 GNUNET_SERVICE_client_continue (tc->client);
4594 * Address of our peer added. Test message is well-formed.
4596 * @param cls the client
4597 * @param aam the send message that was sent
4598 * @return #GNUNET_OK if message is well-formed
4601 check_add_address (void *cls,
4602 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4604 struct TransportClient *tc = cls;
4606 if (CT_COMMUNICATOR != tc->type)
4609 return GNUNET_SYSERR;
4611 GNUNET_MQ_check_zero_termination (aam);
4617 * Ask peerstore to store our address.
4619 * @param cls an `struct AddressListEntry *`
4622 store_pi (void *cls);
4626 * Function called when peerstore is done storing our address.
4628 * @param cls a `struct AddressListEntry`
4629 * @param success #GNUNET_YES if peerstore was successful
4632 peerstore_store_own_cb (void *cls, int success)
4634 struct AddressListEntry *ale = cls;
4637 if (GNUNET_YES != success)
4638 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4639 "Failed to store our own address `%s' in peerstore!\n",
4641 /* refresh period is 1/4 of expiration time, that should be plenty
4642 without being excessive. */
4644 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4652 * Ask peerstore to store our address.
4654 * @param cls an `struct AddressListEntry *`
4657 store_pi (void *cls)
4659 struct AddressListEntry *ale = cls;
4662 struct GNUNET_TIME_Absolute expiration;
4665 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4666 GNUNET_HELLO_sign_address (ale->address,
4672 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4675 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4679 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4680 &peerstore_store_own_cb,
4683 if (NULL == ale->sc)
4685 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4686 "Failed to store our address `%s' with peerstore\n",
4689 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4695 * Address of our peer added. Process the request.
4697 * @param cls the client
4698 * @param aam the send message that was sent
4701 handle_add_address (void *cls,
4702 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4704 struct TransportClient *tc = cls;
4705 struct AddressListEntry *ale;
4708 slen = ntohs (aam->header.size) - sizeof (*aam);
4709 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4711 ale->address = (const char *) &ale[1];
4712 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4713 ale->aid = aam->aid;
4714 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4715 memcpy (&ale[1], &aam[1], slen);
4716 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4717 tc->details.communicator.addr_tail,
4719 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4720 GNUNET_SERVICE_client_continue (tc->client);
4725 * Address of our peer deleted. Process the request.
4727 * @param cls the client
4728 * @param dam the send message that was sent
4731 handle_del_address (void *cls,
4732 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4734 struct TransportClient *tc = cls;
4736 if (CT_COMMUNICATOR != tc->type)
4739 GNUNET_SERVICE_client_drop (tc->client);
4742 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4746 if (dam->aid != ale->aid)
4748 GNUNET_assert (ale->tc == tc);
4749 free_address_list_entry (ale);
4750 GNUNET_SERVICE_client_continue (tc->client);
4753 GNUNET_SERVICE_client_drop (tc->client);
4758 * Given an inbound message @a msg from a communicator @a cmc,
4759 * demultiplex it based on the type calling the right handler.
4761 * @param cmc context for demultiplexing
4762 * @param msg message to demultiplex
4765 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4766 const struct GNUNET_MessageHeader *msg);
4770 * Communicator gave us an unencapsulated message to pass as-is to
4771 * CORE. Process the request.
4773 * @param cls a `struct CommunicatorMessageContext` (must call
4774 * #finish_cmc_handling() when done)
4775 * @param mh the message that was received
4778 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4780 struct CommunicatorMessageContext *cmc = cls;
4781 struct VirtualLink *vl;
4782 uint16_t size = ntohs (mh->size);
4784 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4785 (size < sizeof (struct GNUNET_MessageHeader)))
4787 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4790 finish_cmc_handling (cmc);
4791 GNUNET_SERVICE_client_drop (client);
4794 vl = GNUNET_CONTAINER_multipeermap_get (links, &cmc->im.sender);
4797 /* FIXME: sender is giving us messages for CORE but we don't have
4798 the link up yet! I *suspect* this can happen right now (i.e.
4799 sender has verified us, but we didn't verify sender), but if
4800 we pass this on, CORE would be confused (link down, messages
4801 arrive). We should investigate more if this happens often,
4802 or in a persistent manner, and possibly do "something" about
4803 it. Thus logging as error for now. */
4804 GNUNET_break_op (0);
4805 GNUNET_STATISTICS_update (GST_stats,
4806 "# CORE messages droped (virtual link still down)",
4810 finish_cmc_handling (cmc);
4813 /* Forward to all CORE clients */
4814 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4816 struct GNUNET_MQ_Envelope *env;
4817 struct InboundMessage *im;
4819 if (CT_CORE != tc->type)
4821 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4822 im->peer = cmc->im.sender;
4823 memcpy (&im[1], mh, size);
4824 GNUNET_MQ_send (tc->mq, env);
4826 vl->core_recv_window--;
4827 if (vl->core_recv_window > 0)
4829 finish_cmc_handling (cmc);
4832 /* Wait with calling #finish_cmc_handling(cmc) until the message
4833 was processed by CORE MQs (for CORE flow control)! */
4834 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
4839 * Communicator gave us a fragment box. Check the message.
4841 * @param cls a `struct CommunicatorMessageContext`
4842 * @param fb the send message that was sent
4843 * @return #GNUNET_YES if message is well-formed
4846 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4848 uint16_t size = ntohs (fb->header.size);
4849 uint16_t bsize = size - sizeof (*fb);
4854 GNUNET_break_op (0);
4855 return GNUNET_SYSERR;
4857 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4859 GNUNET_break_op (0);
4860 return GNUNET_SYSERR;
4862 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4864 GNUNET_break_op (0);
4865 return GNUNET_SYSERR;
4872 * Clean up an idle cummulative acknowledgement data structure.
4874 * @param cls a `struct AcknowledgementCummulator *`
4877 destroy_ack_cummulator (void *cls)
4879 struct AcknowledgementCummulator *ac = cls;
4882 GNUNET_assert (0 == ac->num_acks);
4885 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4891 * Do the transmission of a cummulative acknowledgement now.
4893 * @param cls a `struct AcknowledgementCummulator *`
4896 transmit_cummulative_ack_cb (void *cls)
4898 struct AcknowledgementCummulator *ac = cls;
4899 struct TransportReliabilityAckMessage *ack;
4900 struct TransportCummulativeAckPayloadP *ap;
4903 GNUNET_assert (0 < ac->ack_counter);
4904 ack = GNUNET_malloc (sizeof (*ack) +
4906 sizeof (struct TransportCummulativeAckPayloadP));
4907 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4909 htons (sizeof (*ack) +
4910 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4911 ack->ack_counter = htonl (ac->ack_counter++);
4912 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4913 for (unsigned int i = 0; i < ac->ack_counter; i++)
4915 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4916 ap[i].ack_delay = GNUNET_TIME_relative_hton (
4917 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
4919 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
4921 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
4922 &destroy_ack_cummulator,
4928 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
4929 * transmission by at most @a ack_delay.
4931 * @param pid target peer
4932 * @param ack_uuid UUID to ack
4933 * @param max_delay how long can the ACK wait
4936 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
4937 const struct AcknowledgementUUIDP *ack_uuid,
4938 struct GNUNET_TIME_Absolute max_delay)
4940 struct AcknowledgementCummulator *ac;
4942 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
4945 ac = GNUNET_new (struct AcknowledgementCummulator);
4947 ac->min_transmission_time = max_delay;
4948 GNUNET_assert (GNUNET_YES ==
4949 GNUNET_CONTAINER_multipeermap_put (
4953 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4957 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
4959 /* must run immediately, ack buffer full! */
4960 GNUNET_SCHEDULER_cancel (ac->task);
4961 transmit_cummulative_ack_cb (ac);
4963 GNUNET_SCHEDULER_cancel (ac->task);
4964 ac->min_transmission_time =
4965 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
4967 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
4968 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
4969 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
4971 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
4972 &transmit_cummulative_ack_cb,
4978 * Closure for #find_by_message_uuid.
4980 struct FindByMessageUuidContext
4985 struct MessageUUIDP message_uuid;
4988 * Set to the reassembly context if found.
4990 struct ReassemblyContext *rc;
4995 * Iterator called to find a reassembly context by the message UUID in the
4998 * @param cls a `struct FindByMessageUuidContext`
4999 * @param key a key (unused)
5000 * @param value a `struct ReassemblyContext`
5001 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5004 find_by_message_uuid (void *cls, uint32_t key, void *value)
5006 struct FindByMessageUuidContext *fc = cls;
5007 struct ReassemblyContext *rc = value;
5010 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5020 * Communicator gave us a fragment. Process the request.
5022 * @param cls a `struct CommunicatorMessageContext` (must call
5023 * #finish_cmc_handling() when done)
5024 * @param fb the message that was received
5027 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5029 struct CommunicatorMessageContext *cmc = cls;
5030 struct Neighbour *n;
5031 struct ReassemblyContext *rc;
5032 const struct GNUNET_MessageHeader *msg;
5037 struct GNUNET_TIME_Relative cdelay;
5038 struct FindByMessageUuidContext fc;
5040 n = lookup_neighbour (&cmc->im.sender);
5043 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5046 finish_cmc_handling (cmc);
5047 GNUNET_SERVICE_client_drop (client);
5050 if (NULL == n->reassembly_map)
5052 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5053 n->reassembly_heap =
5054 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5055 n->reassembly_timeout_task =
5056 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5057 &reassembly_cleanup_task,
5060 msize = ntohs (fb->msg_size);
5061 fc.message_uuid = fb->msg_uuid;
5063 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5065 &find_by_message_uuid,
5067 if (NULL == (rc = fc.rc))
5069 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5070 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5071 rc->msg_uuid = fb->msg_uuid;
5073 rc->msg_size = msize;
5074 rc->reassembly_timeout =
5075 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5076 rc->last_frag = GNUNET_TIME_absolute_get ();
5077 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5079 rc->reassembly_timeout.abs_value_us);
5080 GNUNET_assert (GNUNET_OK ==
5081 GNUNET_CONTAINER_multihashmap32_put (
5085 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5086 target = (char *) &rc[1];
5087 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5088 rc->msg_missing = rc->msg_size;
5092 target = (char *) &rc[1];
5094 if (msize != rc->msg_size)
5097 finish_cmc_handling (cmc);
5102 fsize = ntohs (fb->header.size) - sizeof (*fb);
5106 finish_cmc_handling (cmc);
5109 frag_off = ntohs (fb->frag_off);
5110 memcpy (&target[frag_off], &fb[1], fsize);
5111 /* update bitfield and msg_missing */
5112 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5114 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5116 rc->bitfield[i / 8] |= (1 << (i % 8));
5121 /* Compute cummulative ACK */
5122 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5123 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5124 if (0 == rc->msg_missing)
5125 cdelay = GNUNET_TIME_UNIT_ZERO;
5126 cummulative_ack (&cmc->im.sender,
5128 GNUNET_TIME_relative_to_absolute (cdelay));
5129 rc->last_frag = GNUNET_TIME_absolute_get ();
5130 /* is reassembly complete? */
5131 if (0 != rc->msg_missing)
5133 finish_cmc_handling (cmc);
5136 /* reassembly is complete, verify result */
5137 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5138 if (ntohs (msg->size) != rc->msg_size)
5141 free_reassembly_context (rc);
5142 finish_cmc_handling (cmc);
5145 /* successful reassembly */
5146 demultiplex_with_cmc (cmc, msg);
5147 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5148 en-route and we forget that we finished this reassembly immediately!
5149 -> keep around until timeout?
5150 -> shorten timeout based on ACK? */
5151 free_reassembly_context (rc);
5156 * Communicator gave us a reliability box. Check the message.
5158 * @param cls a `struct CommunicatorMessageContext`
5159 * @param rb the send message that was sent
5160 * @return #GNUNET_YES if message is well-formed
5163 check_reliability_box (void *cls,
5164 const struct TransportReliabilityBoxMessage *rb)
5167 GNUNET_MQ_check_boxed_message (rb);
5173 * Communicator gave us a reliability box. Process the request.
5175 * @param cls a `struct CommunicatorMessageContext` (must call
5176 * #finish_cmc_handling() when done)
5177 * @param rb the message that was received
5180 handle_reliability_box (void *cls,
5181 const struct TransportReliabilityBoxMessage *rb)
5183 struct CommunicatorMessageContext *cmc = cls;
5184 const struct GNUNET_MessageHeader *inbox =
5185 (const struct GNUNET_MessageHeader *) &rb[1];
5187 // FIXME: call cummulative_ack(), have ack_countdown influence max_delay!
5188 (void) (0 == ntohl (rb->ack_countdown));
5189 /* continue with inner message */
5190 demultiplex_with_cmc (cmc, inbox);
5195 * Check if we have advanced to another age since the last time. If
5196 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5199 * @param pd[in,out] data to update
5200 * @param age current age
5203 update_pd_age (struct PerformanceData *pd, unsigned int age)
5207 if (age == pd->last_age)
5208 return; /* nothing to do */
5209 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5210 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5212 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5214 the->bytes_sent = 0;
5215 the->bytes_received = 0;
5222 * Update @a pd based on the latest @a rtt and the number of bytes
5223 * that were confirmed to be successfully transmitted.
5225 * @param pd[in,out] data to update
5226 * @param rtt latest round-trip time
5227 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5230 update_performance_data (struct PerformanceData *pd,
5231 struct GNUNET_TIME_Relative rtt,
5232 uint16_t bytes_transmitted_ok)
5234 uint64_t nval = rtt.rel_value_us;
5235 uint64_t oval = pd->aged_rtt.rel_value_us;
5236 unsigned int age = get_age ();
5237 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5239 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5242 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5243 update_pd_age (pd, age);
5244 the->bytes_received += bytes_transmitted_ok;
5249 * We have successfully transmitted data via @a q, update metrics.
5251 * @param q queue to update
5252 * @param rtt round trip time observed
5253 * @param bytes_transmitted_ok number of bytes successfully transmitted
5256 update_queue_performance (struct Queue *q,
5257 struct GNUNET_TIME_Relative rtt,
5258 uint16_t bytes_transmitted_ok)
5260 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5265 * We have successfully transmitted data via @a dvh, update metrics.
5267 * @param dvh distance vector path data to update
5268 * @param rtt round trip time observed
5269 * @param bytes_transmitted_ok number of bytes successfully transmitted
5272 update_dvh_performance (struct DistanceVectorHop *dvh,
5273 struct GNUNET_TIME_Relative rtt,
5274 uint16_t bytes_transmitted_ok)
5276 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5281 * The @a pa was acknowledged, process the acknowledgement.
5283 * @param pa the pending acknowledgement that was satisfied
5284 * @param ack_delay artificial delay from cummulative acks created by the
5288 handle_acknowledged (struct PendingAcknowledgement *pa,
5289 struct GNUNET_TIME_Relative ack_delay)
5291 struct PendingMessage *pm = pa->pm;
5292 struct GNUNET_TIME_Relative delay;
5294 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5295 if (delay.rel_value_us > ack_delay.rel_value_us)
5296 delay = GNUNET_TIME_UNIT_ZERO;
5298 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5299 if (NULL != pa->queue)
5300 update_queue_performance (pa->queue, delay, pa->message_size);
5301 if (NULL != pa->dvh)
5302 update_dvh_performance (pa->dvh, delay, pa->message_size);
5305 if (NULL != pm->frag_parent)
5307 pm = pm->frag_parent;
5308 free_fragment_tree (pa->pm);
5310 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5312 struct PendingMessage *parent = pm->frag_parent;
5314 free_fragment_tree (pm);
5317 if (NULL != pm->head_frag)
5318 pm = NULL; /* we are done, otherwise free 'pm' below */
5321 free_pending_message (pm);
5322 free_pending_acknowledgement (pa);
5327 * Communicator gave us a reliability ack. Check it is well-formed.
5329 * @param cls a `struct CommunicatorMessageContext` (unused)
5330 * @param ra the message that was received
5331 * @return #GNUNET_Ok if @a ra is well-formed
5334 check_reliability_ack (void *cls,
5335 const struct TransportReliabilityAckMessage *ra)
5337 unsigned int n_acks;
5340 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5341 sizeof (struct TransportCummulativeAckPayloadP);
5344 GNUNET_break_op (0);
5345 return GNUNET_SYSERR;
5347 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5348 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5350 GNUNET_break_op (0);
5351 return GNUNET_SYSERR;
5358 * Communicator gave us a reliability ack. Process the request.
5360 * @param cls a `struct CommunicatorMessageContext` (must call
5361 * #finish_cmc_handling() when done)
5362 * @param ra the message that was received
5365 handle_reliability_ack (void *cls,
5366 const struct TransportReliabilityAckMessage *ra)
5368 struct CommunicatorMessageContext *cmc = cls;
5369 const struct TransportCummulativeAckPayloadP *ack;
5370 struct PendingAcknowledgement *pa;
5371 unsigned int n_acks;
5372 uint32_t ack_counter;
5374 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5375 sizeof (struct TransportCummulativeAckPayloadP);
5376 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5377 for (unsigned int i = 0; i < n_acks; i++)
5380 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5383 GNUNET_STATISTICS_update (
5385 "# FRAGMENT_ACKS dropped, no matching pending message",
5390 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5393 ack_counter = htonl (ra->ack_counter);
5394 (void) ack_counter; /* silence compiler warning for now */
5395 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5396 // (DV and/or Neighbour?)
5397 finish_cmc_handling (cmc);
5402 * Communicator gave us a backchannel encapsulation. Check the message.
5404 * @param cls a `struct CommunicatorMessageContext`
5405 * @param be the send message that was sent
5406 * @return #GNUNET_YES if message is well-formed
5409 check_backchannel_encapsulation (
5411 const struct TransportBackchannelEncapsulationMessage *be)
5413 uint16_t size = ntohs (be->header.size);
5416 if ((size - sizeof (*be)) <
5417 (sizeof (struct TransportBackchannelRequestPayloadP) +
5418 sizeof (struct GNUNET_MessageHeader)))
5420 GNUNET_break_op (0);
5421 return GNUNET_SYSERR;
5428 * We received the plaintext @a msg from backtalker @a b. Forward
5429 * it to the respective communicator.
5431 * @param b a backtalker
5432 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5433 * followed by the target name of the communicator
5434 * @param msg_size number of bytes in @a msg
5437 forward_backchannel_payload (struct Backtalker *b,
5441 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5442 struct GNUNET_MQ_Envelope *env;
5443 struct TransportClient *tc;
5444 const struct GNUNET_MessageHeader *mh;
5445 const char *target_communicator;
5448 /* Determine target_communicator and check @a msg is well-formed */
5450 mhs = ntohs (mh->size);
5451 if (mhs <= msg_size)
5453 GNUNET_break_op (0);
5456 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5457 if ('\0' != target_communicator[msg_size - mhs - 1])
5459 GNUNET_break_op (0);
5462 /* Find client providing this communicator */
5463 for (tc = clients_head; NULL != tc; tc = tc->next)
5464 if ((CT_COMMUNICATOR == tc->type) &&
5466 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5474 "# Backchannel message dropped: target communicator `%s' unknown",
5475 target_communicator);
5476 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5477 GNUNET_free (stastr);
5480 /* Finally, deliver backchannel message to communicator */
5481 env = GNUNET_MQ_msg_extra (
5484 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5486 memcpy (&cbi[1], msg, msg_size);
5487 GNUNET_MQ_send (tc->mq, env);
5492 * Free data structures associated with @a b.
5494 * @param b data structure to release
5497 free_backtalker (struct Backtalker *b)
5501 GNUNET_PEERSTORE_iterate_cancel (b->get);
5503 GNUNET_assert (NULL != b->cmc);
5504 finish_cmc_handling (b->cmc);
5507 if (NULL != b->task)
5509 GNUNET_SCHEDULER_cancel (b->task);
5514 GNUNET_PEERSTORE_store_cancel (b->sc);
5519 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5525 * Callback to free backtalker records.
5529 * @param value a `struct Backtalker`
5530 * @return #GNUNET_OK (always)
5533 free_backtalker_cb (void *cls,
5534 const struct GNUNET_PeerIdentity *pid,
5537 struct Backtalker *b = value;
5541 free_backtalker (b);
5547 * Function called when it is time to clean up a backtalker.
5549 * @param cls a `struct Backtalker`
5552 backtalker_timeout_cb (void *cls)
5554 struct Backtalker *b = cls;
5557 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5559 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5562 GNUNET_assert (NULL == b->sc);
5563 free_backtalker (b);
5568 * Function called with the monotonic time of a backtalker
5569 * by PEERSTORE. Updates the time and continues processing.
5571 * @param cls a `struct Backtalker`
5572 * @param record the information found, NULL for the last call
5573 * @param emsg error message
5576 backtalker_monotime_cb (void *cls,
5577 const struct GNUNET_PEERSTORE_Record *record,
5580 struct Backtalker *b = cls;
5581 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5582 struct GNUNET_TIME_Absolute mt;
5587 /* we're done with #backtalker_monotime_cb() invocations,
5588 continue normal processing */
5590 GNUNET_assert (NULL != b->cmc);
5591 finish_cmc_handling (b->cmc);
5593 if (0 != b->body_size)
5594 forward_backchannel_payload (b, &b[1], b->body_size);
5597 if (sizeof (*mtbe) != record->value_size)
5602 mtbe = record->value;
5603 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5604 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5606 GNUNET_STATISTICS_update (
5608 "# Backchannel messages dropped: monotonic time not increasing",
5611 b->monotonic_time = mt;
5612 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5621 * Function called by PEERSTORE when the store operation of
5622 * a backtalker's monotonic time is complete.
5624 * @param cls the `struct Backtalker`
5625 * @param success #GNUNET_OK on success
5628 backtalker_monotime_store_cb (void *cls, int success)
5630 struct Backtalker *b = cls;
5632 if (GNUNET_OK != success)
5634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5635 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5638 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5643 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5645 * @param b a backtalker with updated monotonic time
5648 update_backtalker_monotime (struct Backtalker *b)
5650 struct GNUNET_TIME_AbsoluteNBO mtbe;
5654 GNUNET_PEERSTORE_store_cancel (b->sc);
5659 GNUNET_SCHEDULER_cancel (b->task);
5662 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5664 GNUNET_PEERSTORE_store (peerstore,
5667 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5670 GNUNET_TIME_UNIT_FOREVER_ABS,
5671 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5672 &backtalker_monotime_store_cb,
5678 * Communicator gave us a backchannel encapsulation. Process the request.
5679 * (We are not the origin of the backchannel here, the communicator simply
5680 * received a backchannel message and we are expected to forward it.)
5682 * @param cls a `struct CommunicatorMessageContext` (must call
5683 * #finish_cmc_handling() when done)
5684 * @param be the message that was received
5687 handle_backchannel_encapsulation (
5689 const struct TransportBackchannelEncapsulationMessage *be)
5691 struct CommunicatorMessageContext *cmc = cls;
5692 struct BackchannelKeyState key;
5693 struct GNUNET_HashCode hmac;
5697 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5699 /* not for me, try to route to target */
5700 route_message (&be->target,
5701 GNUNET_copy_message (&be->header),
5703 finish_cmc_handling (cmc);
5706 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5707 hdr = (const char *) &be[1];
5708 hdr_len = ntohs (be->header.size) - sizeof (*be);
5709 bc_hmac (&key, &hmac, hdr, hdr_len);
5710 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5712 /* HMAC missmatch, disard! */
5713 GNUNET_break_op (0);
5714 finish_cmc_handling (cmc);
5717 /* begin actual decryption */
5719 struct Backtalker *b;
5720 struct GNUNET_TIME_Absolute monotime;
5721 struct TransportBackchannelRequestPayloadP ppay;
5722 char body[hdr_len - sizeof (ppay)];
5724 GNUNET_assert (hdr_len >=
5725 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5726 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5727 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5728 bc_key_clean (&key);
5729 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5730 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5731 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5733 GNUNET_STATISTICS_update (
5735 "# Backchannel messages dropped: monotonic time not increasing",
5738 finish_cmc_handling (cmc);
5742 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5744 /* Check signature */
5745 struct EphemeralConfirmationPS ec;
5747 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5748 ec.purpose.size = htonl (sizeof (ec));
5749 ec.target = GST_my_identity;
5750 ec.ephemeral_key = be->ephemeral_key;
5753 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5756 &ppay.sender.public_key))
5758 /* Signature invalid, disard! */
5759 GNUNET_break_op (0);
5760 finish_cmc_handling (cmc);
5766 /* update key cache and mono time */
5767 b->last_ephemeral = be->ephemeral_key;
5768 b->monotonic_time = monotime;
5769 update_backtalker_monotime (b);
5770 forward_backchannel_payload (b, body, sizeof (body));
5772 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5773 finish_cmc_handling (cmc);
5776 /* setup data structure to cache signature AND check
5777 monotonic time with PEERSTORE before forwarding backchannel payload */
5778 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5779 b->pid = ppay.sender;
5780 b->body_size = sizeof (body);
5781 memcpy (&b[1], body, sizeof (body));
5782 GNUNET_assert (GNUNET_YES ==
5783 GNUNET_CONTAINER_multipeermap_put (
5787 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5788 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5791 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5792 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5794 GNUNET_PEERSTORE_iterate (peerstore,
5797 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5798 &backtalker_monotime_cb,
5805 * Task called when we should check if any of the DV paths
5806 * we have learned to a target are due for garbage collection.
5808 * Collects stale paths, and possibly frees the entire DV
5809 * entry if no paths are left. Otherwise re-schedules itself.
5811 * @param cls a `struct DistanceVector`
5814 path_cleanup_cb (void *cls)
5816 struct DistanceVector *dv = cls;
5817 struct DistanceVectorHop *pos;
5819 dv->timeout_task = NULL;
5820 while (NULL != (pos = dv->dv_head))
5822 GNUNET_assert (dv == pos->dv);
5823 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5825 free_distance_vector_hop (pos);
5833 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5838 * The @a hop is a validated path to the respective target
5839 * peer and we should tell core about it -- and schedule
5840 * a job to revoke the state.
5842 * @param hop a path to some peer that is the reason for activation
5845 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5847 struct DistanceVector *dv = hop->dv;
5848 struct VirtualLink *vl;
5850 vl = GNUNET_CONTAINER_multipeermap_get (links, &dv->target);
5853 /* Link was already up, remember dv is also now available and we are done */
5857 vl = GNUNET_new (struct VirtualLink);
5858 vl->target = dv->target;
5860 vl->core_recv_window = RECV_WINDOW_SIZE;
5861 vl->visibility_task =
5862 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
5863 GNUNET_break (GNUNET_YES ==
5864 GNUNET_CONTAINER_multipeermap_put (
5868 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5869 /* We lacked a confirmed connection to the target
5870 before, so tell CORE about it (finally!) */
5871 cores_send_connect_info (&dv->target);
5876 * We have learned a @a path through the network to some other peer, add it to
5877 * our DV data structure (returning #GNUNET_YES on success).
5879 * We do not add paths if we have a sufficient number of shorter
5880 * paths to this target already (returning #GNUNET_NO).
5882 * We also do not add problematic paths, like those where we lack the first
5883 * hop in our neighbour list (i.e. due to a topology change) or where some
5884 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5886 * @param path the path we learned, path[0] should be us,
5887 * and then path contains a valid path from us to
5888 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
5889 * @param path_len number of entries on the @a path, at least three!
5890 * @param network_latency how long does the message take from us to
5891 * `path[path_len-1]`? set to "forever" if unknown
5892 * @param path_valid_until how long is this path considered validated? Maybe
5894 * @return #GNUNET_YES on success,
5895 * #GNUNET_NO if we have better path(s) to the target
5896 * #GNUNET_SYSERR if the path is useless and/or invalid
5897 * (i.e. path[1] not a direct neighbour
5898 * or path[i+1] is a direct neighbour for i>0)
5901 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5902 unsigned int path_len,
5903 struct GNUNET_TIME_Relative network_latency,
5904 struct GNUNET_TIME_Absolute path_valid_until)
5906 struct DistanceVectorHop *hop;
5907 struct DistanceVector *dv;
5908 struct Neighbour *next_hop;
5909 unsigned int shorter_distance;
5913 /* what a boring path! not allowed! */
5915 return GNUNET_SYSERR;
5917 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5918 next_hop = lookup_neighbour (&path[1]);
5919 if (NULL == next_hop)
5921 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5923 return GNUNET_SYSERR;
5925 for (unsigned int i = 2; i < path_len; i++)
5926 if (NULL != lookup_neighbour (&path[i]))
5928 /* Useless path, we have a direct connection to some hop
5929 in the middle of the path, so this one doesn't even
5930 seem terribly useful for redundancy */
5931 return GNUNET_SYSERR;
5933 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5936 dv = GNUNET_new (struct DistanceVector);
5937 dv->target = path[path_len - 1];
5938 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5941 GNUNET_assert (GNUNET_OK ==
5942 GNUNET_CONTAINER_multipeermap_put (
5946 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5948 /* Check if we have this path already! */
5949 shorter_distance = 0;
5950 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5953 if (pos->distance < path_len - 2)
5955 /* Note that the distances in 'pos' excludes us (path[0]) and
5956 the next_hop (path[1]), so we need to subtract two
5957 and check next_hop explicitly */
5958 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5960 int match = GNUNET_YES;
5962 for (unsigned int i = 0; i < pos->distance; i++)
5964 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5970 if (GNUNET_YES == match)
5972 struct GNUNET_TIME_Relative last_timeout;
5974 /* Re-discovered known path, update timeout */
5975 GNUNET_STATISTICS_update (GST_stats,
5976 "# Known DV path refreshed",
5979 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5981 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5982 pos->path_valid_until =
5983 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5984 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5985 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5987 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
5988 activate_core_visible_dv_path (pos);
5989 if (last_timeout.rel_value_us <
5990 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5991 DV_PATH_DISCOVERY_FREQUENCY)
5994 /* Some peer send DV learn messages too often, we are learning
5995 the same path faster than it would be useful; do not forward! */
6002 /* Count how many shorter paths we have (incl. direct
6003 neighbours) before simply giving up on this one! */
6004 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6006 /* We have a shorter path already! */
6009 /* create new DV path entry */
6010 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6011 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6012 hop->next_hop = next_hop;
6014 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6017 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6018 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6019 hop->path_valid_until = path_valid_until;
6020 hop->distance = path_len - 2;
6021 hop->pd.aged_rtt = network_latency;
6022 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6023 GNUNET_CONTAINER_MDLL_insert (neighbour,
6027 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6028 activate_core_visible_dv_path (hop);
6034 * Communicator gave us a DV learn message. Check the message.
6036 * @param cls a `struct CommunicatorMessageContext`
6037 * @param dvl the send message that was sent
6038 * @return #GNUNET_YES if message is well-formed
6041 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6043 uint16_t size = ntohs (dvl->header.size);
6044 uint16_t num_hops = ntohs (dvl->num_hops);
6045 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6048 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6050 GNUNET_break_op (0);
6051 return GNUNET_SYSERR;
6053 if (num_hops > MAX_DV_HOPS_ALLOWED)
6055 GNUNET_break_op (0);
6056 return GNUNET_SYSERR;
6058 for (unsigned int i = 0; i < num_hops; i++)
6060 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6062 GNUNET_break_op (0);
6063 return GNUNET_SYSERR;
6065 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6067 GNUNET_break_op (0);
6068 return GNUNET_SYSERR;
6076 * Build and forward a DV learn message to @a next_hop.
6078 * @param next_hop peer to send the message to
6079 * @param msg message received
6080 * @param bi_history bitmask specifying hops on path that were bidirectional
6081 * @param nhops length of the @a hops array
6082 * @param hops path the message traversed so far
6083 * @param in_time when did we receive the message, used to calculate network
6087 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6088 const struct TransportDVLearnMessage *msg,
6089 uint16_t bi_history,
6091 const struct DVPathEntryP *hops,
6092 struct GNUNET_TIME_Absolute in_time)
6094 struct DVPathEntryP *dhops;
6095 struct TransportDVLearnMessage *fwd;
6096 struct GNUNET_TIME_Relative nnd;
6098 /* compute message for forwarding */
6099 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6100 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
6101 (nhops + 1) * sizeof (struct DVPathEntryP));
6102 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6103 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6104 (nhops + 1) * sizeof (struct DVPathEntryP));
6105 fwd->num_hops = htons (nhops + 1);
6106 fwd->bidirectional = htons (bi_history);
6107 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6108 GNUNET_TIME_relative_ntoh (
6109 msg->non_network_delay));
6110 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6111 fwd->init_sig = msg->init_sig;
6112 fwd->initiator = msg->initiator;
6113 fwd->challenge = msg->challenge;
6114 dhops = (struct DVPathEntryP *) &fwd[1];
6115 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6116 dhops[nhops].hop = GST_my_identity;
6118 struct DvHopPS dhp = {.purpose.purpose =
6119 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6120 .purpose.size = htonl (sizeof (dhp)),
6121 .pred = dhops[nhops - 1].hop,
6123 .challenge = msg->challenge};
6125 GNUNET_assert (GNUNET_OK ==
6126 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6128 &dhops[nhops].hop_sig));
6130 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6135 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6137 * @param sender_monotonic_time monotonic time of the initiator
6138 * @param init the signer
6139 * @param challenge the challenge that was signed
6140 * @param init_sig signature presumably by @a init
6141 * @return #GNUNET_OK if the signature is valid
6144 validate_dv_initiator_signature (
6145 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6146 const struct GNUNET_PeerIdentity *init,
6147 const struct ChallengeNonceP *challenge,
6148 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6150 struct DvInitPS ip = {.purpose.purpose = htonl (
6151 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6152 .purpose.size = htonl (sizeof (ip)),
6153 .monotonic_time = sender_monotonic_time,
6154 .challenge = *challenge};
6158 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6163 GNUNET_break_op (0);
6164 return GNUNET_SYSERR;
6171 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6173 struct NeighbourSelectionContext
6176 * Original message we received.
6178 const struct TransportDVLearnMessage *dvl;
6183 const struct DVPathEntryP *hops;
6186 * Time we received the message.
6188 struct GNUNET_TIME_Absolute in_time;
6191 * Offsets of the selected peers.
6193 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6196 * Number of peers eligible for selection.
6198 unsigned int num_eligible;
6201 * Number of peers that were selected for forwarding.
6203 unsigned int num_selections;
6206 * Number of hops in @e hops
6211 * Bitmap of bidirectional connections encountered.
6213 uint16_t bi_history;
6218 * Function called for each neighbour during #handle_dv_learn.
6220 * @param cls a `struct NeighbourSelectionContext *`
6221 * @param pid identity of the peer
6222 * @param value a `struct Neighbour`
6223 * @return #GNUNET_YES (always)
6226 dv_neighbour_selection (void *cls,
6227 const struct GNUNET_PeerIdentity *pid,
6230 struct NeighbourSelectionContext *nsc = cls;
6233 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6234 return GNUNET_YES; /* skip initiator */
6235 for (unsigned int i = 0; i < nsc->nhops; i++)
6236 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6237 return GNUNET_YES; /* skip peers on path */
6238 nsc->num_eligible++;
6244 * Function called for each neighbour during #handle_dv_learn.
6245 * We call #forward_dv_learn() on the neighbour(s) selected
6246 * during #dv_neighbour_selection().
6248 * @param cls a `struct NeighbourSelectionContext *`
6249 * @param pid identity of the peer
6250 * @param value a `struct Neighbour`
6251 * @return #GNUNET_YES (always)
6254 dv_neighbour_transmission (void *cls,
6255 const struct GNUNET_PeerIdentity *pid,
6258 struct NeighbourSelectionContext *nsc = cls;
6261 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6262 return GNUNET_YES; /* skip initiator */
6263 for (unsigned int i = 0; i < nsc->nhops; i++)
6264 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6265 return GNUNET_YES; /* skip peers on path */
6266 for (unsigned int i = 0; i < nsc->num_selections; i++)
6268 if (nsc->selections[i] == nsc->num_eligible)
6270 forward_dv_learn (pid,
6279 nsc->num_eligible++;
6285 * Computes the number of neighbours we should forward a DVInit
6286 * message to given that it has so far taken @a hops_taken hops
6287 * though the network and that the number of neighbours we have
6288 * in total is @a neighbour_count, out of which @a eligible_count
6289 * are not yet on the path.
6291 * NOTE: technically we might want to include NSE in the formula to
6292 * get a better grip on the overall network size. However, for now
6293 * using NSE here would create a dependency issue in the build system.
6294 * => Left for later, hardcoded to 50 for now.
6296 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6297 * peers via DV (`target_total`). We want the reach to be spread out
6298 * over various distances to the origin, with a bias towards shorter
6301 * We make the strong assumption that the network topology looks
6302 * "similar" at other hops, in particular the @a neighbour_count
6303 * should be comparable at other hops.
6305 * If the local neighbourhood is densely connected, we expect that @a
6306 * eligible_count is close to @a neighbour_count minus @a hops_taken
6307 * as a lot of the path is already known. In that case, we should
6308 * forward to few(er) peers to try to find a path out of the
6309 * neighbourhood. OTOH, if @a eligible_count is close to @a
6310 * neighbour_count, we should forward to many peers as we are either
6311 * still close to the origin (i.e. @a hops_taken is small) or because
6312 * we managed to get beyond a local cluster. We express this as
6313 * the `boost_factor` using the square of the fraction of eligible
6314 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6315 * 99% are eligible, the 'boost' will be almost 1).
6317 * Second, the more hops we have taken, the larger the problem of an
6318 * exponential traffic explosion gets. So we take the `target_total`,
6319 * and compute our degree such that at each distance d 2^{-d} peers
6320 * are selected (corrected by the `boost_factor`).
6322 * @param hops_taken number of hops DVInit has travelled so far
6323 * @param neighbour_count number of neighbours we have in total
6324 * @param eligible_count number of neighbours we could in
6328 calculate_fork_degree (unsigned int hops_taken,
6329 unsigned int neighbour_count,
6330 unsigned int eligible_count)
6332 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6333 double eligible_ratio =
6334 ((double) eligible_count) / ((double) neighbour_count);
6335 double boost_factor = eligible_ratio * eligible_ratio;
6339 if (hops_taken >= 64)
6340 return 0; /* precaution given bitshift below */
6341 for (unsigned int i = 1; i < hops_taken; i++)
6343 /* For each hop, subtract the expected number of targets
6344 reached at distance d (so what remains divided by 2^d) */
6345 target_total -= (target_total * boost_factor / (1LLU << i));
6348 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6349 /* round up or down probabilistically depending on how close we were
6350 when floor()ing to rnd */
6351 left = target_total - (double) rnd;
6352 if (UINT32_MAX * left >
6353 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6354 rnd++; /* round up */
6360 * Function called when peerstore is done storing a DV monotonic time.
6362 * @param cls a `struct Neighbour`
6363 * @param success #GNUNET_YES if peerstore was successful
6366 neighbour_store_dvmono_cb (void *cls, int success)
6368 struct Neighbour *n = cls;
6371 if (GNUNET_YES != success)
6372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6373 "Failed to store other peer's monotonic time in peerstore!\n");
6378 * Communicator gave us a DV learn message. Process the request.
6380 * @param cls a `struct CommunicatorMessageContext` (must call
6381 * #finish_cmc_handling() when done)
6382 * @param dvl the message that was received
6385 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6387 struct CommunicatorMessageContext *cmc = cls;
6388 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6391 uint16_t bi_history;
6392 const struct DVPathEntryP *hops;
6395 struct GNUNET_TIME_Absolute in_time;
6396 struct Neighbour *n;
6398 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6399 bi_history = ntohs (dvl->bidirectional);
6400 hops = (const struct DVPathEntryP *) &dvl[1];
6404 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6407 finish_cmc_handling (cmc);
6414 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6417 finish_cmc_handling (cmc);
6422 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6423 cc = cmc->tc->details.communicator.cc;
6424 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6425 cc); // FIXME: add bi-directional flag to cc?
6426 in_time = GNUNET_TIME_absolute_get ();
6428 /* continue communicator here, everything else can happen asynchronous! */
6429 finish_cmc_handling (cmc);
6431 n = lookup_neighbour (&dvl->initiator);
6434 if ((n->dv_monotime_available == GNUNET_YES) &&
6435 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6436 n->last_dv_learn_monotime.abs_value_us))
6438 GNUNET_STATISTICS_update (GST_stats,
6439 "# DV learn discarded due to time travel",
6444 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6449 GNUNET_break_op (0);
6452 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6453 if (GNUNET_YES == n->dv_monotime_available)
6456 GNUNET_PEERSTORE_store_cancel (n->sc);
6458 GNUNET_PEERSTORE_store (peerstore,
6461 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6462 &dvl->monotonic_time,
6463 sizeof (dvl->monotonic_time),
6464 GNUNET_TIME_UNIT_FOREVER_ABS,
6465 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6466 &neighbour_store_dvmono_cb,
6470 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6471 If signature verification load too high, implement random drop strategy */
6472 for (unsigned int i = 0; i < nhops; i++)
6474 struct DvHopPS dhp = {.purpose.purpose =
6475 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6476 .purpose.size = htonl (sizeof (dhp)),
6477 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6478 .succ = (nhops - 1 == i) ? GST_my_identity
6480 .challenge = dvl->challenge};
6483 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6486 &hops[i].hop.public_key))
6488 GNUNET_break_op (0);
6493 do_fwd = GNUNET_YES;
6494 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6496 struct GNUNET_PeerIdentity path[nhops + 1];
6497 struct GNUNET_TIME_Relative host_latency_sum;
6498 struct GNUNET_TIME_Relative latency;
6499 struct GNUNET_TIME_Relative network_latency;
6501 /* We initiated this, learn the forward path! */
6502 path[0] = GST_my_identity;
6503 path[1] = hops[0].hop;
6504 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6506 // Need also something to lookup initiation time
6507 // to compute RTT! -> add RTT argument here?
6508 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6509 // (based on dvl->challenge, we can identify time of origin!)
6511 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6512 /* assumption: latency on all links is the same */
6513 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6515 for (unsigned int i = 2; i <= nhops; i++)
6517 struct GNUNET_TIME_Relative ilat;
6519 /* assumption: linear latency increase per hop */
6520 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6521 path[i] = hops[i - 1].hop;
6522 learn_dv_path (path,
6525 GNUNET_TIME_relative_to_absolute (
6526 ADDRESS_VALIDATION_LIFETIME));
6528 /* as we initiated, do not forward again (would be circular!) */
6534 /* last hop was bi-directional, we could learn something here! */
6535 struct GNUNET_PeerIdentity path[nhops + 2];
6537 path[0] = GST_my_identity;
6538 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6539 for (unsigned int i = 0; i < nhops; i++)
6543 if (0 == (bi_history & (1 << i)))
6544 break; /* i-th hop not bi-directional, stop learning! */
6547 path[i + 2] = dvl->initiator;
6551 path[i + 2] = hops[nhops - i - 2].hop;
6554 iret = learn_dv_path (path,
6556 GNUNET_TIME_UNIT_FOREVER_REL,
6557 GNUNET_TIME_UNIT_ZERO_ABS);
6558 if (GNUNET_SYSERR == iret)
6560 /* path invalid or too long to be interesting for US, thus should also
6561 not be interesting to our neighbours, cut path when forwarding to
6562 'i' hops, except of course for the one that goes back to the
6564 GNUNET_STATISTICS_update (GST_stats,
6565 "# DV learn not forwarded due invalidity of path",
6571 if ((GNUNET_NO == iret) && (nhops == i + 1))
6573 /* we have better paths, and this is the longest target,
6574 so there cannot be anything interesting later */
6575 GNUNET_STATISTICS_update (GST_stats,
6576 "# DV learn not forwarded, got better paths",
6585 if (MAX_DV_HOPS_ALLOWED == nhops)
6587 /* At limit, we're out of here! */
6588 finish_cmc_handling (cmc);
6592 /* Forward to initiator, if path non-trivial and possible */
6593 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6594 did_initiator = GNUNET_NO;
6597 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6599 /* send back to origin! */
6600 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6601 did_initiator = GNUNET_YES;
6603 /* We forward under two conditions: either we still learned something
6604 ourselves (do_fwd), or the path was darn short and thus the initiator is
6605 likely to still be very interested in this (and we did NOT already
6606 send it back to the initiator) */
6607 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6608 (GNUNET_NO == did_initiator)))
6610 /* Pick random neighbours that are not yet on the path */
6611 struct NeighbourSelectionContext nsc;
6614 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6617 nsc.bi_history = bi_history;
6619 nsc.in_time = in_time;
6620 nsc.num_eligible = 0;
6621 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6622 &dv_neighbour_selection,
6624 if (0 == nsc.num_eligible)
6625 return; /* done here, cannot forward to anyone else */
6626 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6627 nsc.num_selections =
6628 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6629 for (unsigned int i = 0; i < nsc.num_selections; i++)
6631 (nsc.num_selections == n_cnt)
6632 ? i /* all were selected, avoid collisions by chance */
6633 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6634 nsc.num_eligible = 0;
6635 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6636 &dv_neighbour_transmission,
6643 * Communicator gave us a DV box. Check the message.
6645 * @param cls a `struct CommunicatorMessageContext`
6646 * @param dvb the send message that was sent
6647 * @return #GNUNET_YES if message is well-formed
6650 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6652 uint16_t size = ntohs (dvb->header.size);
6653 uint16_t num_hops = ntohs (dvb->num_hops);
6654 const struct GNUNET_PeerIdentity *hops =
6655 (const struct GNUNET_PeerIdentity *) &dvb[1];
6656 const struct GNUNET_MessageHeader *inbox =
6657 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6662 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6663 sizeof (struct GNUNET_MessageHeader))
6665 GNUNET_break_op (0);
6666 return GNUNET_SYSERR;
6668 isize = ntohs (inbox->size);
6670 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6672 GNUNET_break_op (0);
6673 return GNUNET_SYSERR;
6675 itype = ntohs (inbox->type);
6676 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6677 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6679 GNUNET_break_op (0);
6680 return GNUNET_SYSERR;
6682 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6684 GNUNET_break_op (0);
6685 return GNUNET_SYSERR;
6692 * Create a DV Box message and queue it for transmission to
6695 * @param next_hop peer to receive the message next
6696 * @param total_hops how many hops did the message take so far
6697 * @param num_hops length of the @a hops array
6698 * @param origin origin of the message
6699 * @param hops next peer(s) to the destination, including destination
6700 * @param payload payload of the box
6701 * @param payload_size number of bytes in @a payload
6704 forward_dv_box (struct Neighbour *next_hop,
6705 uint16_t total_hops,
6707 const struct GNUNET_PeerIdentity *origin,
6708 const struct GNUNET_PeerIdentity *hops,
6709 const void *payload,
6710 uint16_t payload_size)
6712 struct TransportDVBoxMessage *dvb;
6714 dvb = create_dv_box (total_hops,
6716 &hops[num_hops - 1] /* == target */,
6717 num_hops - 1 /* do not count target twice */,
6721 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6727 * Communicator gave us a DV box. Process the request.
6729 * @param cls a `struct CommunicatorMessageContext` (must call
6730 * #finish_cmc_handling() when done)
6731 * @param dvb the message that was received
6734 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6736 struct CommunicatorMessageContext *cmc = cls;
6737 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6738 uint16_t num_hops = ntohs (dvb->num_hops);
6739 const struct GNUNET_PeerIdentity *hops =
6740 (const struct GNUNET_PeerIdentity *) &dvb[1];
6741 const struct GNUNET_MessageHeader *inbox =
6742 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6746 /* We're trying from the end of the hops array, as we may be
6747 able to find a shortcut unknown to the origin that way */
6748 for (int i = num_hops - 1; i >= 0; i--)
6750 struct Neighbour *n;
6752 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6754 GNUNET_break_op (0);
6755 finish_cmc_handling (cmc);
6758 n = lookup_neighbour (&hops[i]);
6762 ntohs (dvb->total_hops) + 1,
6763 num_hops - i - 1, /* number of hops left */
6765 &hops[i + 1], /* remaining hops */
6766 (const void *) &dvb[1],
6768 finish_cmc_handling (cmc);
6771 /* Woopsie, next hop not in neighbours, drop! */
6772 GNUNET_STATISTICS_update (GST_stats,
6773 "# DV Boxes dropped: next hop unknown",
6776 finish_cmc_handling (cmc);
6779 /* We are the target. Unbox and handle message. */
6780 cmc->im.sender = dvb->origin;
6781 cmc->total_hops = ntohs (dvb->total_hops);
6782 demultiplex_with_cmc (cmc, inbox);
6787 * Client notified us about transmission from a peer. Process the request.
6789 * @param cls a `struct TransportClient` which sent us the message
6790 * @param obm the send message that was sent
6791 * @return #GNUNET_YES if message is well-formed
6794 check_incoming_msg (void *cls,
6795 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6797 struct TransportClient *tc = cls;
6799 if (CT_COMMUNICATOR != tc->type)
6802 return GNUNET_SYSERR;
6804 GNUNET_MQ_check_boxed_message (im);
6810 * Communicator gave us a transport address validation challenge. Process the
6813 * @param cls a `struct CommunicatorMessageContext` (must call
6814 * #finish_cmc_handling() when done)
6815 * @param tvc the message that was received
6818 handle_validation_challenge (
6820 const struct TransportValidationChallengeMessage *tvc)
6822 struct CommunicatorMessageContext *cmc = cls;
6823 struct TransportValidationResponseMessage *tvr;
6825 if (cmc->total_hops > 0)
6827 /* DV routing is not allowed for validation challenges! */
6828 GNUNET_break_op (0);
6829 finish_cmc_handling (cmc);
6832 tvr = GNUNET_new (struct TransportValidationResponseMessage);
6834 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
6835 tvr->header.size = htons (sizeof (*tvr));
6836 tvr->challenge = tvc->challenge;
6837 tvr->origin_time = tvc->sender_time;
6838 tvr->validity_duration = cmc->im.expected_address_validity;
6840 /* create signature */
6841 struct TransportValidationPS tvp =
6842 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6843 .purpose.size = htonl (sizeof (tvp)),
6844 .validity_duration = tvr->validity_duration,
6845 .challenge = tvc->challenge};
6847 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6851 route_message (&cmc->im.sender,
6853 RMO_ANYTHING_GOES | RMO_REDUNDANT);
6854 finish_cmc_handling (cmc);
6859 * Closure for #check_known_challenge.
6861 struct CheckKnownChallengeContext
6864 * Set to the challenge we are looking for.
6866 const struct ChallengeNonceP *challenge;
6869 * Set to a matching validation state, if one was found.
6871 struct ValidationState *vs;
6876 * Test if the validation state in @a value matches the
6877 * challenge from @a cls.
6879 * @param cls a `struct CheckKnownChallengeContext`
6880 * @param pid unused (must match though)
6881 * @param value a `struct ValidationState`
6882 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6885 check_known_challenge (void *cls,
6886 const struct GNUNET_PeerIdentity *pid,
6889 struct CheckKnownChallengeContext *ckac = cls;
6890 struct ValidationState *vs = value;
6893 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
6901 * Function called when peerstore is done storing a
6902 * validated address.
6904 * @param cls a `struct ValidationState`
6905 * @param success #GNUNET_YES on success
6908 peerstore_store_validation_cb (void *cls, int success)
6910 struct ValidationState *vs = cls;
6913 if (GNUNET_YES == success)
6915 GNUNET_STATISTICS_update (GST_stats,
6916 "# Peerstore failed to store foreign address",
6923 * Task run periodically to validate some address based on #validation_heap.
6928 validation_start_cb (void *cls);
6932 * Set the time for next_challenge of @a vs to @a new_time.
6933 * Updates the heap and if necessary reschedules the job.
6935 * @param vs validation state to update
6936 * @param new_time new time for revalidation
6939 update_next_challenge_time (struct ValidationState *vs,
6940 struct GNUNET_TIME_Absolute new_time)
6942 struct GNUNET_TIME_Relative delta;
6944 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
6945 return; /* be lazy */
6946 vs->next_challenge = new_time;
6949 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
6951 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
6952 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
6953 (NULL != validation_task))
6955 if (NULL != validation_task)
6956 GNUNET_SCHEDULER_cancel (validation_task);
6957 /* randomize a bit */
6958 delta.rel_value_us =
6959 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6960 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
6961 new_time = GNUNET_TIME_absolute_add (new_time, delta);
6963 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
6968 * Find the queue matching @a pid and @a address.
6970 * @param pid peer the queue must go to
6971 * @param address address the queue must use
6972 * @return NULL if no such queue exists
6974 static struct Queue *
6975 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
6977 struct Neighbour *n;
6979 n = lookup_neighbour (pid);
6982 for (struct Queue *pos = n->queue_head; NULL != pos;
6983 pos = pos->next_neighbour)
6985 if (0 == strcmp (pos->address, address))
6993 * Communicator gave us a transport address validation response. Process the
6996 * @param cls a `struct CommunicatorMessageContext` (must call
6997 * #finish_cmc_handling() when done)
6998 * @param tvr the message that was received
7001 handle_validation_response (
7003 const struct TransportValidationResponseMessage *tvr)
7005 struct CommunicatorMessageContext *cmc = cls;
7006 struct ValidationState *vs;
7007 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7009 struct GNUNET_TIME_Absolute origin_time;
7011 struct Neighbour *n;
7012 struct VirtualLink *vl;
7014 /* check this is one of our challenges */
7015 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7017 &check_known_challenge,
7019 if (NULL == (vs = ckac.vs))
7021 /* This can happen simply if we 'forgot' the challenge by now,
7022 i.e. because we received the validation response twice */
7023 GNUNET_STATISTICS_update (GST_stats,
7024 "# Validations dropped, challenge unknown",
7027 finish_cmc_handling (cmc);
7031 /* sanity check on origin time */
7032 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7033 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7034 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7036 GNUNET_break_op (0);
7037 finish_cmc_handling (cmc);
7042 /* check signature */
7043 struct TransportValidationPS tvp =
7044 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7045 .purpose.size = htonl (sizeof (tvp)),
7046 .validity_duration = tvr->validity_duration,
7047 .challenge = tvr->challenge};
7051 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7054 &cmc->im.sender.public_key))
7056 GNUNET_break_op (0);
7057 finish_cmc_handling (cmc);
7062 /* validity is capped by our willingness to keep track of the
7063 validation entry and the maximum the other peer allows */
7064 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7065 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7066 tvr->validity_duration),
7067 MAX_ADDRESS_VALID_UNTIL));
7068 vs->validated_until =
7069 GNUNET_TIME_absolute_min (vs->valid_until,
7070 GNUNET_TIME_relative_to_absolute (
7071 ADDRESS_VALIDATION_LIFETIME));
7072 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7073 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7074 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7076 sizeof (vs->challenge));
7077 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7078 vs->validated_until,
7079 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7080 VALIDATION_RTT_BUFFER_FACTOR));
7081 vs->last_challenge_use =
7082 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7083 update_next_challenge_time (vs, vs->first_challenge_use);
7084 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7087 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7089 strlen (vs->address) + 1,
7091 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7092 &peerstore_store_validation_cb,
7094 finish_cmc_handling (cmc);
7096 /* Finally, we now possibly have a confirmed (!) working queue,
7097 update queue status (if queue still is around) */
7098 q = find_queue (&vs->pid, vs->address);
7101 GNUNET_STATISTICS_update (GST_stats,
7102 "# Queues lost at time of successful validation",
7107 q->validated_until = vs->validated_until;
7108 q->pd.aged_rtt = vs->validation_rtt;
7110 vl = GNUNET_CONTAINER_multipeermap_get (links, &vs->pid);
7113 /* Link was already up, remember n is also now available and we are done */
7117 vl = GNUNET_new (struct VirtualLink);
7118 vl->target = n->pid;
7120 vl->core_recv_window = RECV_WINDOW_SIZE;
7121 vl->visibility_task =
7122 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7123 GNUNET_break (GNUNET_YES ==
7124 GNUNET_CONTAINER_multipeermap_put (
7128 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7129 /* We lacked a confirmed connection to the target
7130 before, so tell CORE about it (finally!) */
7131 cores_send_connect_info (&n->pid);
7136 * Incoming meessage. Process the request.
7138 * @param im the send message that was received
7141 handle_incoming_msg (void *cls,
7142 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7144 struct TransportClient *tc = cls;
7145 struct CommunicatorMessageContext *cmc =
7146 GNUNET_new (struct CommunicatorMessageContext);
7150 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7155 * Given an inbound message @a msg from a communicator @a cmc,
7156 * demultiplex it based on the type calling the right handler.
7158 * @param cmc context for demultiplexing
7159 * @param msg message to demultiplex
7162 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7163 const struct GNUNET_MessageHeader *msg)
7165 struct GNUNET_MQ_MessageHandler handlers[] =
7166 {GNUNET_MQ_hd_var_size (fragment_box,
7167 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7168 struct TransportFragmentBoxMessage,
7170 GNUNET_MQ_hd_var_size (reliability_box,
7171 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7172 struct TransportReliabilityBoxMessage,
7174 GNUNET_MQ_hd_var_size (reliability_ack,
7175 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7176 struct TransportReliabilityAckMessage,
7178 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7179 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7180 struct TransportBackchannelEncapsulationMessage,
7182 GNUNET_MQ_hd_var_size (dv_learn,
7183 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7184 struct TransportDVLearnMessage,
7186 GNUNET_MQ_hd_var_size (dv_box,
7187 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7188 struct TransportDVBoxMessage,
7190 GNUNET_MQ_hd_fixed_size (
7191 validation_challenge,
7192 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7193 struct TransportValidationChallengeMessage,
7195 GNUNET_MQ_hd_fixed_size (
7196 validation_response,
7197 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7198 struct TransportValidationResponseMessage,
7200 GNUNET_MQ_handler_end ()};
7203 ret = GNUNET_MQ_handle_message (handlers, msg);
7204 if (GNUNET_SYSERR == ret)
7207 GNUNET_SERVICE_client_drop (cmc->tc->client);
7211 if (GNUNET_NO == ret)
7213 /* unencapsulated 'raw' message */
7214 handle_raw_message (&cmc, msg);
7220 * New queue became available. Check message.
7222 * @param cls the client
7223 * @param aqm the send message that was sent
7226 check_add_queue_message (void *cls,
7227 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7229 struct TransportClient *tc = cls;
7231 if (CT_COMMUNICATOR != tc->type)
7234 return GNUNET_SYSERR;
7236 GNUNET_MQ_check_zero_termination (aqm);
7242 * If necessary, generates the UUID for a @a pm
7244 * @param pm pending message to generate UUID for.
7247 set_pending_message_uuid (struct PendingMessage *pm)
7249 if (pm->msg_uuid_set)
7251 pm->msg_uuid.uuid = pm->target->message_uuid_ctr++;
7252 pm->msg_uuid_set = GNUNET_YES;
7257 * Setup data structure waiting for acknowledgements.
7259 * @param queue queue the @a pm will be sent over
7260 * @param dvh path the message will take, may be NULL
7261 * @param pm the pending message for transmission
7262 * @return corresponding fresh pending acknowledgement
7264 static struct PendingAcknowledgement *
7265 prepare_pending_acknowledgement (struct Queue *queue,
7266 struct DistanceVectorHop *dvh,
7267 struct PendingMessage *pm)
7269 struct PendingAcknowledgement *pa;
7271 pa = GNUNET_new (struct PendingAcknowledgement);
7277 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7279 sizeof (pa->ack_uuid));
7280 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7282 &pa->ack_uuid.value,
7284 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7285 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7286 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7288 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7289 pa->transmission_time = GNUNET_TIME_absolute_get ();
7290 pa->message_size = pm->bytes_msg;
7296 * Fragment the given @a pm to the given @a mtu. Adds
7297 * additional fragments to the neighbour as well. If the
7298 * @a mtu is too small, generates and error for the @a pm
7301 * @param queue which queue to fragment for
7302 * @param dvh path the message will take, or NULL
7303 * @param pm pending message to fragment for transmission
7304 * @return new message to transmit
7306 static struct PendingMessage *
7307 fragment_message (struct Queue *queue,
7308 struct DistanceVectorHop *dvh,
7309 struct PendingMessage *pm)
7311 struct PendingAcknowledgement *pa;
7312 struct PendingMessage *ff;
7315 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7316 mtu = (0 == queue->mtu)
7317 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7319 set_pending_message_uuid (pm);
7321 /* This invariant is established in #handle_add_queue_message() */
7322 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7324 /* select fragment for transmission, descending the tree if it has
7325 been expanded until we are at a leaf or at a fragment that is small
7329 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7330 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7332 ff = ff->head_frag; /* descent into fragmented fragments */
7335 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7337 /* Did not yet calculate all fragments, calculate next fragment */
7338 struct PendingMessage *frag;
7339 struct TransportFragmentBoxMessage tfb;
7347 orig = (const char *) &ff[1];
7348 msize = ff->bytes_msg;
7351 const struct TransportFragmentBoxMessage *tfbo;
7353 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7354 orig += sizeof (struct TransportFragmentBoxMessage);
7355 msize -= sizeof (struct TransportFragmentBoxMessage);
7356 xoff = ntohs (tfbo->frag_off);
7358 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7359 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7361 GNUNET_malloc (sizeof (struct PendingMessage) +
7362 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7363 frag->target = pm->target;
7364 frag->frag_parent = ff;
7365 frag->timeout = pm->timeout;
7366 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7367 frag->pmt = PMT_FRAGMENT_BOX;
7368 msg = (char *) &frag[1];
7369 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7371 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7372 tfb.ack_uuid = pa->ack_uuid;
7373 tfb.msg_uuid = pm->msg_uuid;
7374 tfb.frag_off = htons (ff->frag_off + xoff);
7375 tfb.msg_size = htons (pm->bytes_msg);
7376 memcpy (msg, &tfb, sizeof (tfb));
7377 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7378 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7379 ff->frag_off += fragsize;
7383 /* Move head to the tail and return it */
7384 GNUNET_CONTAINER_MDLL_remove (frag,
7385 ff->frag_parent->head_frag,
7386 ff->frag_parent->tail_frag,
7388 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7389 ff->frag_parent->head_frag,
7390 ff->frag_parent->tail_frag,
7397 * Reliability-box the given @a pm. On error (can there be any), NULL
7398 * may be returned, otherwise the "replacement" for @a pm (which
7399 * should then be added to the respective neighbour's queue instead of
7400 * @a pm). If the @a pm is already fragmented or reliability boxed,
7401 * or itself an ACK, this function simply returns @a pm.
7403 * @param queue which queue to prepare transmission for
7404 * @param dvh path the message will take, or NULL
7405 * @param pm pending message to box for transmission over unreliabile queue
7406 * @return new message to transmit
7408 static struct PendingMessage *
7409 reliability_box_message (struct Queue *queue,
7410 struct DistanceVectorHop *dvh,
7411 struct PendingMessage *pm)
7413 struct TransportReliabilityBoxMessage rbox;
7414 struct PendingAcknowledgement *pa;
7415 struct PendingMessage *bpm;
7418 if (PMT_CORE != pm->pmt)
7419 return pm; /* already fragmented or reliability boxed, or control message:
7421 if (NULL != pm->bpm)
7422 return pm->bpm; /* already computed earlier: do nothing */
7423 GNUNET_assert (NULL == pm->head_frag);
7424 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7428 client_send_response (pm);
7431 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7433 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7435 bpm->target = pm->target;
7436 bpm->frag_parent = pm;
7437 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7438 bpm->timeout = pm->timeout;
7439 bpm->pmt = PMT_RELIABILITY_BOX;
7440 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7441 set_pending_message_uuid (bpm);
7442 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7443 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7444 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7446 rbox.ack_uuid = pa->ack_uuid;
7447 msg = (char *) &bpm[1];
7448 memcpy (msg, &rbox, sizeof (rbox));
7449 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7456 * Change the value of the `next_attempt` field of @a pm
7457 * to @a next_attempt and re-order @a pm in the transmission
7458 * list as required by the new timestmap.
7460 * @param pm a pending message to update
7461 * @param next_attempt timestamp to use
7464 update_pm_next_attempt (struct PendingMessage *pm,
7465 struct GNUNET_TIME_Absolute next_attempt)
7467 struct Neighbour *neighbour = pm->target;
7469 pm->next_attempt = next_attempt;
7470 if (NULL == pm->frag_parent)
7472 struct PendingMessage *pos;
7474 /* re-insert sort in neighbour list */
7475 GNUNET_CONTAINER_MDLL_remove (neighbour,
7476 neighbour->pending_msg_head,
7477 neighbour->pending_msg_tail,
7479 pos = neighbour->pending_msg_tail;
7480 while ((NULL != pos) &&
7481 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7482 pos = pos->prev_neighbour;
7483 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7484 neighbour->pending_msg_head,
7485 neighbour->pending_msg_tail,
7491 /* re-insert sort in fragment list */
7492 struct PendingMessage *fp = pm->frag_parent;
7493 struct PendingMessage *pos;
7495 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7496 pos = fp->tail_frag;
7497 while ((NULL != pos) &&
7498 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7499 pos = pos->prev_frag;
7500 GNUNET_CONTAINER_MDLL_insert_after (frag,
7510 * We believe we are ready to transmit a message on a queue.
7511 * Gives the message to the
7512 * communicator for transmission (updating the tracker, and re-scheduling
7513 * itself if applicable).
7515 * @param cls the `struct Queue` to process transmissions for
7518 transmit_on_queue (void *cls)
7520 struct Queue *queue = cls;
7521 struct Neighbour *n = queue->neighbour;
7522 struct PendingMessage *pm;
7523 struct PendingMessage *s;
7526 queue->transmit_task = NULL;
7527 if (NULL == (pm = n->pending_msg_head))
7529 /* no message pending, nothing to do here! */
7534 /* message still pending with communciator!
7535 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7538 schedule_transmit_on_queue (queue, GNUNET_YES);
7539 if (NULL != queue->transmit_task)
7540 return; /* do it later */
7542 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7543 overhead += sizeof (struct TransportReliabilityBoxMessage);
7545 if ( ( (0 != queue->mtu) &&
7546 (pm->bytes_msg + overhead > queue->mtu) ) ||
7547 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7548 (NULL != pm->head_frag /* fragments already exist, should
7549 respect that even if MTU is 0 for
7551 s = fragment_message (queue, pm->dvh, s);
7554 /* Fragmentation failed, try next message... */
7555 schedule_transmit_on_queue (queue, GNUNET_NO);
7558 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7559 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7560 s = reliability_box_message (queue, pm->dvh, s);
7563 /* Reliability boxing failed, try next message... */
7564 schedule_transmit_on_queue (queue, GNUNET_NO);
7568 /* Pass 's' for transission to the communicator */
7569 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7570 // FIXME: do something similar to the logic below
7571 // in defragmentation / reliability ACK handling!
7573 /* Check if this transmission somehow conclusively finished handing 'pm'
7574 even without any explicit ACKs */
7575 if ((PMT_CORE == s->pmt) &&
7576 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7578 /* Full message sent, and over reliabile channel */
7579 client_send_response (pm);
7581 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7582 queue->tc->details.communicator.cc) &&
7583 (PMT_FRAGMENT_BOX == s->pmt))
7585 struct PendingMessage *pos;
7587 /* Fragment sent over reliabile channel */
7588 free_fragment_tree (s);
7589 pos = s->frag_parent;
7590 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7592 /* check if subtree is done */
7593 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7597 pos = s->frag_parent;
7598 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7602 /* Was this the last applicable fragmment? */
7603 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7604 client_send_response (pm);
7606 else if (PMT_CORE != pm->pmt)
7608 /* This was an acknowledgement of some type, always free */
7609 free_pending_message (pm);
7613 /* Message not finished, waiting for acknowledgement.
7614 Update time by which we might retransmit 's' based on queue
7615 characteristics (i.e. RTT); it takes one RTT for the message to
7616 arrive and the ACK to come back in the best case; but the other
7617 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7618 retransmitting. Note that in the future this heuristic should
7619 likely be improved further (measure RTT stability, consider
7620 message urgency and size when delaying ACKs, etc.) */
7621 update_pm_next_attempt (s,
7622 GNUNET_TIME_relative_to_absolute (
7623 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7627 /* finally, re-schedule queue transmission task itself */
7628 schedule_transmit_on_queue (queue, GNUNET_NO);
7633 * Queue to a peer went down. Process the request.
7635 * @param cls the client
7636 * @param dqm the send message that was sent
7639 handle_del_queue_message (void *cls,
7640 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7642 struct TransportClient *tc = cls;
7644 if (CT_COMMUNICATOR != tc->type)
7647 GNUNET_SERVICE_client_drop (tc->client);
7650 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7651 queue = queue->next_client)
7653 struct Neighbour *neighbour = queue->neighbour;
7655 if ((dqm->qid != queue->qid) ||
7656 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7659 GNUNET_SERVICE_client_continue (tc->client);
7663 GNUNET_SERVICE_client_drop (tc->client);
7668 * Message was transmitted. Process the request.
7670 * @param cls the client
7671 * @param sma the send message that was sent
7674 handle_send_message_ack (void *cls,
7675 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7677 struct TransportClient *tc = cls;
7678 struct QueueEntry *qe;
7679 struct PendingMessage *pm;
7681 if (CT_COMMUNICATOR != tc->type)
7684 GNUNET_SERVICE_client_drop (tc->client);
7688 /* find our queue entry matching the ACK */
7690 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7691 queue = queue->next_client)
7693 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7695 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7698 if (qep->mid != sma->mid)
7707 /* this should never happen */
7709 GNUNET_SERVICE_client_drop (tc->client);
7712 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7713 qe->queue->queue_tail,
7715 qe->queue->queue_length--;
7716 tc->details.communicator.total_queue_length--;
7717 GNUNET_SERVICE_client_continue (tc->client);
7719 /* if applicable, resume transmissions that waited on ACK */
7720 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7721 tc->details.communicator.total_queue_length)
7723 /* Communicator dropped below threshold, resume all queues
7724 incident with this client! */
7725 GNUNET_STATISTICS_update (
7727 "# Transmission throttled due to communicator queue limit",
7730 for (struct Queue *queue = tc->details.communicator.queue_head;
7732 queue = queue->next_client)
7733 schedule_transmit_on_queue (queue, GNUNET_NO);
7735 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7737 /* queue dropped below threshold; only resume this one queue */
7738 GNUNET_STATISTICS_update (GST_stats,
7739 "# Transmission throttled due to queue queue limit",
7742 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7745 if (NULL != (pm = qe->pm))
7747 struct Neighbour *n;
7749 GNUNET_assert (qe == pm->qe);
7751 /* If waiting for this communicator may have blocked transmission
7752 of pm on other queues for this neighbour, force schedule
7753 transmit on queue for queues of the neighbour */
7755 if (n->pending_msg_head == pm)
7757 for (struct Queue *queue = n->queue_head; NULL != queue;
7758 queue = queue->next_neighbour)
7759 schedule_transmit_on_queue (queue, GNUNET_NO);
7761 if (GNUNET_OK != ntohl (sma->status))
7764 GNUNET_ERROR_TYPE_INFO,
7765 "Queue failed in transmission, will try retransmission immediately\n");
7766 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7774 * Iterator telling new MONITOR client about all existing
7777 * @param cls the new `struct TransportClient`
7778 * @param pid a connected peer
7779 * @param value the `struct Neighbour` with more information
7780 * @return #GNUNET_OK (continue to iterate)
7783 notify_client_queues (void *cls,
7784 const struct GNUNET_PeerIdentity *pid,
7787 struct TransportClient *tc = cls;
7788 struct Neighbour *neighbour = value;
7790 GNUNET_assert (CT_MONITOR == tc->type);
7791 for (struct Queue *q = neighbour->queue_head; NULL != q;
7792 q = q->next_neighbour)
7794 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7796 .num_msg_pending = q->num_msg_pending,
7797 .num_bytes_pending = q->num_bytes_pending};
7799 notify_monitor (tc, pid, q->address, q->nt, &me);
7806 * Initialize a monitor client.
7808 * @param cls the client
7809 * @param start the start message that was sent
7812 handle_monitor_start (void *cls,
7813 const struct GNUNET_TRANSPORT_MonitorStart *start)
7815 struct TransportClient *tc = cls;
7817 if (CT_NONE != tc->type)
7820 GNUNET_SERVICE_client_drop (tc->client);
7823 tc->type = CT_MONITOR;
7824 tc->details.monitor.peer = start->peer;
7825 tc->details.monitor.one_shot = ntohl (start->one_shot);
7826 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
7827 GNUNET_SERVICE_client_mark_monitor (tc->client);
7828 GNUNET_SERVICE_client_continue (tc->client);
7833 * Find transport client providing communication service
7834 * for the protocol @a prefix.
7836 * @param prefix communicator name
7837 * @return NULL if no such transport client is available
7839 static struct TransportClient *
7840 lookup_communicator (const char *prefix)
7842 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7844 if (CT_COMMUNICATOR != tc->type)
7846 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
7850 GNUNET_ERROR_TYPE_WARNING,
7851 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
7858 * Signature of a function called with a communicator @a address of a peer
7859 * @a pid that an application wants us to connect to.
7861 * @param pid target peer
7862 * @param address the address to try
7865 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
7867 static uint32_t idgen;
7868 struct TransportClient *tc;
7870 struct GNUNET_TRANSPORT_CreateQueue *cqm;
7871 struct GNUNET_MQ_Envelope *env;
7874 prefix = GNUNET_HELLO_address_to_prefix (address);
7877 GNUNET_break (0); /* We got an invalid address!? */
7880 tc = lookup_communicator (prefix);
7883 GNUNET_STATISTICS_update (GST_stats,
7884 "# Suggestions ignored due to missing communicator",
7889 /* forward suggestion for queue creation to communicator */
7890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7891 "Request #%u for `%s' communicator to create queue to `%s'\n",
7892 (unsigned int) idgen,
7895 alen = strlen (address) + 1;
7897 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
7898 cqm->request_id = htonl (idgen++);
7899 cqm->receiver = *pid;
7900 memcpy (&cqm[1], address, alen);
7901 GNUNET_MQ_send (tc->mq, env);
7906 * The queue @a q (which matches the peer and address in @a vs) is
7907 * ready for queueing. We should now queue the validation request.
7909 * @param q queue to send on
7910 * @param vs state to derive validation challenge from
7913 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
7915 struct TransportValidationChallengeMessage tvc;
7917 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
7919 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
7920 tvc.header.size = htons (sizeof (tvc));
7921 tvc.reserved = htonl (0);
7922 tvc.challenge = vs->challenge;
7923 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
7924 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7929 * Task run periodically to validate some address based on #validation_heap.
7934 validation_start_cb (void *cls)
7936 struct ValidationState *vs;
7940 validation_task = NULL;
7941 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7942 /* drop validations past their expiration */
7945 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7947 free_validation_state (vs);
7948 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7951 return; /* woopsie, no more addresses known, should only
7952 happen if we're really a lonely peer */
7953 q = find_queue (&vs->pid, vs->address);
7956 vs->awaiting_queue = GNUNET_YES;
7957 suggest_to_connect (&vs->pid, vs->address);
7960 validation_transmit_on_queue (q, vs);
7961 /* Finally, reschedule next attempt */
7962 vs->challenge_backoff =
7963 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
7964 MAX_VALIDATION_CHALLENGE_FREQ);
7965 update_next_challenge_time (vs,
7966 GNUNET_TIME_relative_to_absolute (
7967 vs->challenge_backoff));
7972 * Closure for #check_connection_quality.
7974 struct QueueQualityContext
7977 * Set to the @e k'th queue encountered.
7982 * Set to the number of quality queues encountered.
7984 unsigned int quality_count;
7987 * Set to the total number of queues encountered.
7989 unsigned int num_queues;
7992 * Decremented for each queue, for selection of the
7993 * k-th queue in @e q.
8000 * Check whether any queue to the given neighbour is
8001 * of a good "quality" and if so, increment the counter.
8002 * Also counts the total number of queues, and returns
8003 * the k-th queue found.
8005 * @param cls a `struct QueueQualityContext *` with counters
8006 * @param pid peer this is about
8007 * @param value a `struct Neighbour`
8008 * @return #GNUNET_OK (continue to iterate)
8011 check_connection_quality (void *cls,
8012 const struct GNUNET_PeerIdentity *pid,
8015 struct QueueQualityContext *ctx = cls;
8016 struct Neighbour *n = value;
8021 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8026 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
8027 statistics and consider those as well here? */
8028 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
8029 do_inc = GNUNET_YES;
8031 if (GNUNET_YES == do_inc)
8032 ctx->quality_count++;
8038 * Task run when we CONSIDER initiating a DV learn
8039 * process. We first check that sending out a message is
8040 * even possible (queues exist), then that it is desirable
8041 * (if not, reschedule the task for later), and finally
8042 * we may then begin the job. If there are too many
8043 * entries in the #dvlearn_map, we purge the oldest entry
8049 start_dv_learn (void *cls)
8051 struct LearnLaunchEntry *lle;
8052 struct QueueQualityContext qqc;
8053 struct TransportDVLearnMessage dvl;
8056 dvlearn_task = NULL;
8057 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8058 return; /* lost all connectivity, cannot do learning */
8059 qqc.quality_count = 0;
8061 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8062 &check_connection_quality,
8064 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8066 struct GNUNET_TIME_Relative delay;
8067 unsigned int factor;
8069 /* scale our retries by how far we are above the threshold */
8070 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8071 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8072 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8075 /* remove old entries in #dvlearn_map if it has grown too big */
8076 while (MAX_DV_LEARN_PENDING >=
8077 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8080 GNUNET_assert (GNUNET_YES ==
8081 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8082 &lle->challenge.value,
8084 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8087 /* setup data structure for learning */
8088 lle = GNUNET_new (struct LearnLaunchEntry);
8089 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8091 sizeof (lle->challenge));
8092 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8093 GNUNET_break (GNUNET_YES ==
8094 GNUNET_CONTAINER_multishortmap_put (
8096 &lle->challenge.value,
8098 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8099 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8100 dvl.header.size = htons (sizeof (dvl));
8101 dvl.num_hops = htons (0);
8102 dvl.bidirectional = htons (0);
8103 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8104 dvl.monotonic_time =
8105 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8107 struct DvInitPS dvip = {.purpose.purpose = htonl (
8108 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8109 .purpose.size = htonl (sizeof (dvip)),
8110 .monotonic_time = dvl.monotonic_time,
8111 .challenge = lle->challenge};
8113 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8117 dvl.initiator = GST_my_identity;
8118 dvl.challenge = lle->challenge;
8120 qqc.quality_count = 0;
8121 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8124 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8125 &check_connection_quality,
8127 GNUNET_assert (NULL != qqc.q);
8129 /* Do this as close to transmission time as possible! */
8130 lle->launch_time = GNUNET_TIME_absolute_get ();
8132 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8133 /* reschedule this job, randomizing the time it runs (but no
8135 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8136 DV_LEARN_BASE_FREQUENCY),
8143 * A new queue has been created, check if any address validation
8144 * requests have been waiting for it.
8146 * @param cls a `struct Queue`
8147 * @param pid peer concerned (unused)
8148 * @param value a `struct ValidationState`
8149 * @return #GNUNET_NO if a match was found and we can stop looking
8152 check_validation_request_pending (void *cls,
8153 const struct GNUNET_PeerIdentity *pid,
8156 struct Queue *q = cls;
8157 struct ValidationState *vs = value;
8160 if ((GNUNET_YES == vs->awaiting_queue) &&
8161 (0 == strcmp (vs->address, q->address)))
8163 vs->awaiting_queue = GNUNET_NO;
8164 validation_transmit_on_queue (q, vs);
8172 * Function called with the monotonic time of a DV initiator
8173 * by PEERSTORE. Updates the time.
8175 * @param cls a `struct Neighbour`
8176 * @param record the information found, NULL for the last call
8177 * @param emsg error message
8180 neighbour_dv_monotime_cb (void *cls,
8181 const struct GNUNET_PEERSTORE_Record *record,
8184 struct Neighbour *n = cls;
8185 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8190 /* we're done with #neighbour_dv_monotime_cb() invocations,
8191 continue normal processing */
8193 n->dv_monotime_available = GNUNET_YES;
8196 if (sizeof (*mtbe) != record->value_size)
8201 mtbe = record->value;
8202 n->last_dv_learn_monotime =
8203 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8204 GNUNET_TIME_absolute_ntoh (*mtbe));
8209 * New queue became available. Process the request.
8211 * @param cls the client
8212 * @param aqm the send message that was sent
8215 handle_add_queue_message (void *cls,
8216 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8218 struct TransportClient *tc = cls;
8219 struct Queue *queue;
8220 struct Neighbour *neighbour;
8224 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8226 /* MTU so small as to be useless for transmissions,
8227 required for #fragment_message()! */
8228 GNUNET_break_op (0);
8229 GNUNET_SERVICE_client_drop (tc->client);
8232 neighbour = lookup_neighbour (&aqm->receiver);
8233 if (NULL == neighbour)
8235 neighbour = GNUNET_new (struct Neighbour);
8236 neighbour->message_uuid_ctr =
8237 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8238 neighbour->pid = aqm->receiver;
8239 GNUNET_assert (GNUNET_OK ==
8240 GNUNET_CONTAINER_multipeermap_put (
8244 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8246 GNUNET_PEERSTORE_iterate (peerstore,
8249 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8250 &neighbour_dv_monotime_cb,
8253 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8254 addr = (const char *) &aqm[1];
8256 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8258 queue->address = (const char *) &queue[1];
8259 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8260 queue->qid = aqm->qid;
8261 queue->mtu = ntohl (aqm->mtu);
8262 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8263 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8264 queue->neighbour = neighbour;
8265 memcpy (&queue[1], addr, addr_len);
8266 /* notify monitors about new queue */
8268 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8270 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8272 GNUNET_CONTAINER_MDLL_insert (neighbour,
8273 neighbour->queue_head,
8274 neighbour->queue_tail,
8276 GNUNET_CONTAINER_MDLL_insert (client,
8277 tc->details.communicator.queue_head,
8278 tc->details.communicator.queue_tail,
8280 /* check if valdiations are waiting for the queue */
8282 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8284 &check_validation_request_pending,
8286 /* might be our first queue, try launching DV learning */
8287 if (NULL == dvlearn_task)
8288 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8289 GNUNET_SERVICE_client_continue (tc->client);
8294 * Communicator tells us that our request to create a queue "worked", that
8295 * is setting up the queue is now in process.
8297 * @param cls the `struct TransportClient`
8298 * @param cqr confirmation message
8301 handle_queue_create_ok (void *cls,
8302 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8304 struct TransportClient *tc = cls;
8306 if (CT_COMMUNICATOR != tc->type)
8309 GNUNET_SERVICE_client_drop (tc->client);
8312 GNUNET_STATISTICS_update (GST_stats,
8313 "# Suggestions succeeded at communicator",
8316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8317 "Request #%u for communicator to create queue succeeded\n",
8318 (unsigned int) ntohs (cqr->request_id));
8319 GNUNET_SERVICE_client_continue (tc->client);
8324 * Communicator tells us that our request to create a queue failed. This
8325 * usually indicates that the provided address is simply invalid or that the
8326 * communicator's resources are exhausted.
8328 * @param cls the `struct TransportClient`
8329 * @param cqr failure message
8332 handle_queue_create_fail (
8334 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8336 struct TransportClient *tc = cls;
8338 if (CT_COMMUNICATOR != tc->type)
8341 GNUNET_SERVICE_client_drop (tc->client);
8344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8345 "Request #%u for communicator to create queue failed\n",
8346 (unsigned int) ntohs (cqr->request_id));
8347 GNUNET_STATISTICS_update (GST_stats,
8348 "# Suggestions failed in queue creation at communicator",
8351 GNUNET_SERVICE_client_continue (tc->client);
8356 * We have received a `struct ExpressPreferenceMessage` from an application
8359 * @param cls handle to the client
8360 * @param msg the start message
8363 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8365 struct TransportClient *tc = cls;
8366 struct PeerRequest *pr;
8368 if (CT_APPLICATION != tc->type)
8371 GNUNET_SERVICE_client_drop (tc->client);
8374 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8379 GNUNET_SERVICE_client_drop (tc->client);
8382 (void) stop_peer_request (tc, &pr->pid, pr);
8383 GNUNET_SERVICE_client_continue (tc->client);
8388 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8389 * messages. We do nothing here, real verification is done later.
8391 * @param cls a `struct TransportClient *`
8392 * @param msg message to verify
8393 * @return #GNUNET_OK
8396 check_address_consider_verify (
8398 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8407 * Closure for #check_known_address.
8409 struct CheckKnownAddressContext
8412 * Set to the address we are looking for.
8414 const char *address;
8417 * Set to a matching validation state, if one was found.
8419 struct ValidationState *vs;
8424 * Test if the validation state in @a value matches the
8425 * address from @a cls.
8427 * @param cls a `struct CheckKnownAddressContext`
8428 * @param pid unused (must match though)
8429 * @param value a `struct ValidationState`
8430 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8433 check_known_address (void *cls,
8434 const struct GNUNET_PeerIdentity *pid,
8437 struct CheckKnownAddressContext *ckac = cls;
8438 struct ValidationState *vs = value;
8441 if (0 != strcmp (vs->address, ckac->address))
8449 * Start address validation.
8451 * @param pid peer the @a address is for
8452 * @param address an address to reach @a pid (presumably)
8455 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8456 const char *address)
8458 struct GNUNET_TIME_Absolute now;
8459 struct ValidationState *vs;
8460 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8462 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8464 &check_known_address,
8466 if (NULL != (vs = ckac.vs))
8468 /* if 'vs' is not currently valid, we need to speed up retrying the
8470 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8472 /* reduce backoff as we got a fresh advertisement */
8473 vs->challenge_backoff =
8474 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8475 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8477 update_next_challenge_time (vs,
8478 GNUNET_TIME_relative_to_absolute (
8479 vs->challenge_backoff));
8483 now = GNUNET_TIME_absolute_get ();
8484 vs = GNUNET_new (struct ValidationState);
8487 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8488 vs->first_challenge_use = now;
8489 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8490 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8492 sizeof (vs->challenge));
8493 vs->address = GNUNET_strdup (address);
8494 GNUNET_assert (GNUNET_YES ==
8495 GNUNET_CONTAINER_multipeermap_put (
8499 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8500 update_next_challenge_time (vs, now);
8505 * Function called by PEERSTORE for each matching record.
8507 * @param cls closure
8508 * @param record peerstore record information
8509 * @param emsg error message, or NULL if no errors
8512 handle_hello (void *cls,
8513 const struct GNUNET_PEERSTORE_Record *record,
8516 struct PeerRequest *pr = cls;
8521 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8522 "Got failure from PEERSTORE: %s\n",
8526 val = record->value;
8527 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8532 start_address_validation (&pr->pid, (const char *) record->value);
8537 * We have received a `struct ExpressPreferenceMessage` from an application
8540 * @param cls handle to the client
8541 * @param msg the start message
8544 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8546 struct TransportClient *tc = cls;
8547 struct PeerRequest *pr;
8549 if (CT_NONE == tc->type)
8551 tc->type = CT_APPLICATION;
8552 tc->details.application.requests =
8553 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8555 if (CT_APPLICATION != tc->type)
8558 GNUNET_SERVICE_client_drop (tc->client);
8561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8562 "Client suggested we talk to %s with preference %d at rate %u\n",
8563 GNUNET_i2s (&msg->peer),
8564 (int) ntohl (msg->pk),
8565 (int) ntohl (msg->bw.value__));
8566 pr = GNUNET_new (struct PeerRequest);
8568 pr->pid = msg->peer;
8570 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
8571 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8572 tc->details.application.requests,
8575 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8579 GNUNET_SERVICE_client_drop (tc->client);
8582 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8585 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8588 GNUNET_SERVICE_client_continue (tc->client);
8593 * Given another peers address, consider checking it for validity
8594 * and then adding it to the Peerstore.
8596 * @param cls a `struct TransportClient`
8597 * @param hdr message containing the raw address data and
8598 * signature in the body, see #GNUNET_HELLO_extract_address()
8601 handle_address_consider_verify (
8603 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8605 struct TransportClient *tc = cls;
8607 enum GNUNET_NetworkType nt;
8608 struct GNUNET_TIME_Absolute mono_time;
8611 // OPTIMIZE-FIXME: checking that we know this address already should
8612 // be done BEFORE checking the signature => HELLO API change!
8613 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8616 GNUNET_HELLO_extract_address (&hdr[1],
8617 ntohs (hdr->header.size) - sizeof (*hdr),
8621 if (NULL == address)
8623 GNUNET_break_op (0);
8626 start_address_validation (&hdr->peer, address);
8627 GNUNET_free (address);
8628 GNUNET_SERVICE_client_continue (tc->client);
8633 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8636 * @param cls a `struct TransportClient *`
8637 * @param m message to verify
8638 * @return #GNUNET_OK on success
8641 check_request_hello_validation (void *cls,
8642 const struct RequestHelloValidationMessage *m)
8645 GNUNET_MQ_check_zero_termination (m);
8651 * A client encountered an address of another peer. Consider validating it,
8652 * and if validation succeeds, persist it to PEERSTORE.
8654 * @param cls a `struct TransportClient *`
8655 * @param m message to verify
8658 handle_request_hello_validation (void *cls,
8659 const struct RequestHelloValidationMessage *m)
8661 struct TransportClient *tc = cls;
8663 start_address_validation (&m->peer, (const char *) &m[1]);
8664 GNUNET_SERVICE_client_continue (tc->client);
8669 * Free neighbour entry.
8673 * @param value a `struct Neighbour`
8674 * @return #GNUNET_OK (always)
8677 free_neighbour_cb (void *cls,
8678 const struct GNUNET_PeerIdentity *pid,
8681 struct Neighbour *neighbour = value;
8685 GNUNET_break (0); // should this ever happen?
8686 free_neighbour (neighbour);
8693 * Free DV route entry.
8697 * @param value a `struct DistanceVector`
8698 * @return #GNUNET_OK (always)
8701 free_dv_routes_cb (void *cls,
8702 const struct GNUNET_PeerIdentity *pid,
8705 struct DistanceVector *dv = value;
8716 * Free ephemeral entry.
8720 * @param value a `struct EphemeralCacheEntry`
8721 * @return #GNUNET_OK (always)
8724 free_ephemeral_cb (void *cls,
8725 const struct GNUNET_PeerIdentity *pid,
8728 struct EphemeralCacheEntry *ece = value;
8732 free_ephemeral (ece);
8738 * Free validation state.
8742 * @param value a `struct ValidationState`
8743 * @return #GNUNET_OK (always)
8746 free_validation_state_cb (void *cls,
8747 const struct GNUNET_PeerIdentity *pid,
8750 struct ValidationState *vs = value;
8754 free_validation_state (vs);
8760 * Free pending acknowledgement.
8764 * @param value a `struct PendingAcknowledgement`
8765 * @return #GNUNET_OK (always)
8768 free_pending_ack_cb (void *cls,
8769 const struct GNUNET_ShortHashCode *key,
8772 struct PendingAcknowledgement *pa = value;
8776 free_pending_acknowledgement (pa);
8782 * Free acknowledgement cummulator.
8786 * @param value a `struct AcknowledgementCummulator`
8787 * @return #GNUNET_OK (always)
8790 free_ack_cummulator_cb (void *cls,
8791 const struct GNUNET_PeerIdentity *pid,
8794 struct AcknowledgementCummulator *ac = value;
8804 * Function called when the service shuts down. Unloads our plugins
8805 * and cancels pending validations.
8807 * @param cls closure, unused
8810 do_shutdown (void *cls)
8812 struct LearnLaunchEntry *lle;
8815 if (NULL != ephemeral_task)
8817 GNUNET_SCHEDULER_cancel (ephemeral_task);
8818 ephemeral_task = NULL;
8820 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
8821 if (NULL != peerstore)
8823 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
8826 if (NULL != GST_stats)
8828 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
8831 if (NULL != GST_my_private_key)
8833 GNUNET_free (GST_my_private_key);
8834 GST_my_private_key = NULL;
8836 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
8837 &free_ack_cummulator_cb,
8839 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
8840 ack_cummulators = NULL;
8841 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
8842 &free_pending_ack_cb,
8844 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
8845 pending_acks = NULL;
8846 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
8847 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
8849 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
8850 GNUNET_CONTAINER_multipeermap_destroy (links);
8852 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
8853 &free_backtalker_cb,
8855 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
8857 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
8858 &free_validation_state_cb,
8860 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
8861 validation_map = NULL;
8862 while (NULL != (lle = lle_head))
8864 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8867 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
8869 GNUNET_CONTAINER_heap_destroy (validation_heap);
8870 validation_heap = NULL;
8871 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
8872 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
8874 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
8877 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
8878 ephemeral_map = NULL;
8879 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
8880 ephemeral_heap = NULL;
8885 * Initiate transport service.
8887 * @param cls closure
8888 * @param c configuration to use
8889 * @param service the initialized service
8893 const struct GNUNET_CONFIGURATION_Handle *c,
8894 struct GNUNET_SERVICE_Handle *service)
8899 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
8901 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8902 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
8903 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
8904 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8905 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
8906 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8907 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
8909 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8910 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
8912 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8914 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8915 GST_my_private_key =
8916 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
8917 if (NULL == GST_my_private_key)
8920 GNUNET_ERROR_TYPE_ERROR,
8922 "Transport service is lacking key configuration settings. Exiting.\n"));
8923 GNUNET_SCHEDULER_shutdown ();
8926 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
8927 &GST_my_identity.public_key);
8928 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8929 "My identity is `%s'\n",
8930 GNUNET_i2s_full (&GST_my_identity));
8931 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
8932 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
8933 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
8934 if (NULL == peerstore)
8937 GNUNET_SCHEDULER_shutdown ();
8944 * Define "main" method using service macro.
8946 GNUNET_SERVICE_MAIN (
8948 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
8951 &client_disconnect_cb,
8953 /* communication with applications */
8954 GNUNET_MQ_hd_fixed_size (suggest,
8955 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
8956 struct ExpressPreferenceMessage,
8958 GNUNET_MQ_hd_fixed_size (suggest_cancel,
8959 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
8960 struct ExpressPreferenceMessage,
8962 GNUNET_MQ_hd_var_size (request_hello_validation,
8963 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
8964 struct RequestHelloValidationMessage,
8966 /* communication with core */
8967 GNUNET_MQ_hd_fixed_size (client_start,
8968 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
8969 struct StartMessage,
8971 GNUNET_MQ_hd_var_size (client_send,
8972 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
8973 struct OutboundMessage,
8975 GNUNET_MQ_hd_fixed_size (client_recv_ok,
8976 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
8977 struct RecvOkMessage,
8979 /* communication with communicators */
8980 GNUNET_MQ_hd_var_size (communicator_available,
8981 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
8982 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
8984 GNUNET_MQ_hd_var_size (communicator_backchannel,
8985 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
8986 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
8988 GNUNET_MQ_hd_var_size (add_address,
8989 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
8990 struct GNUNET_TRANSPORT_AddAddressMessage,
8992 GNUNET_MQ_hd_fixed_size (del_address,
8993 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
8994 struct GNUNET_TRANSPORT_DelAddressMessage,
8996 GNUNET_MQ_hd_var_size (incoming_msg,
8997 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
8998 struct GNUNET_TRANSPORT_IncomingMessage,
9000 GNUNET_MQ_hd_fixed_size (queue_create_ok,
9001 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
9002 struct GNUNET_TRANSPORT_CreateQueueResponse,
9004 GNUNET_MQ_hd_fixed_size (queue_create_fail,
9005 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
9006 struct GNUNET_TRANSPORT_CreateQueueResponse,
9008 GNUNET_MQ_hd_var_size (add_queue_message,
9009 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
9010 struct GNUNET_TRANSPORT_AddQueueMessage,
9012 GNUNET_MQ_hd_var_size (address_consider_verify,
9013 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
9014 struct GNUNET_TRANSPORT_AddressToVerify,
9016 GNUNET_MQ_hd_fixed_size (del_queue_message,
9017 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
9018 struct GNUNET_TRANSPORT_DelQueueMessage,
9020 GNUNET_MQ_hd_fixed_size (send_message_ack,
9021 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
9022 struct GNUNET_TRANSPORT_SendMessageToAck,
9024 /* communication with monitors */
9025 GNUNET_MQ_hd_fixed_size (monitor_start,
9026 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
9027 struct GNUNET_TRANSPORT_MonitorStart,
9029 GNUNET_MQ_handler_end ());
9032 /* end of file gnunet-service-transport.c */