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?
1761 enum GNUNET_MQ_PreferenceKind pk;
1764 * How much bandwidth would this @e tc like to see?
1766 struct GNUNET_BANDWIDTH_Value32NBO bw;
1771 * Types of different pending messages.
1773 enum PendingMessageType
1777 * Ordinary message received from the CORE service.
1784 PMT_FRAGMENT_BOX = 1,
1789 PMT_RELIABILITY_BOX = 2,
1792 * Any type of acknowledgement.
1794 PMT_ACKNOWLEDGEMENT = 3,
1797 * Control traffic generated by the TRANSPORT service itself.
1805 * Transmission request that is awaiting delivery. The original
1806 * transmission requests from CORE may be too big for some queues.
1807 * In this case, a *tree* of fragments is created. At each
1808 * level of the tree, fragments are kept in a DLL ordered by which
1809 * fragment should be sent next (at the head). The tree is searched
1810 * top-down, with the original message at the root.
1812 * To select a node for transmission, first it is checked if the
1813 * current node's message fits with the MTU. If it does not, we
1814 * either calculate the next fragment (based on @e frag_off) from the
1815 * current node, or, if all fragments have already been created,
1816 * descend to the @e head_frag. Even though the node was already
1817 * fragmented, the fragment may be too big if the fragment was
1818 * generated for a queue with a larger MTU. In this case, the node
1819 * may be fragmented again, thus creating a tree.
1821 * When acknowledgements for fragments are received, the tree
1822 * must be pruned, removing those parts that were already
1823 * acknowledged. When fragments are sent over a reliable
1824 * channel, they can be immediately removed.
1826 * If a message is ever fragmented, then the original "full" message
1827 * is never again transmitted (even if it fits below the MTU), and
1828 * only (remaining) fragments are sent.
1830 struct PendingMessage
1833 * Kept in a MDLL of messages for this @a target.
1835 struct PendingMessage *next_neighbour;
1838 * Kept in a MDLL of messages for this @a target.
1840 struct PendingMessage *prev_neighbour;
1843 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1845 struct PendingMessage *next_client;
1848 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1850 struct PendingMessage *prev_client;
1853 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1854 * #PMT_FRAGMENT_BOx)
1856 struct PendingMessage *next_frag;
1859 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1860 * #PMT_FRAGMENT_BOX)
1862 struct PendingMessage *prev_frag;
1865 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1868 struct PendingMessage *next_dvh;
1871 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1874 struct PendingMessage *prev_dvh;
1877 * Head of DLL of PAs for this pending message.
1879 struct PendingAcknowledgement *pa_head;
1882 * Tail of DLL of PAs for this pending message.
1884 struct PendingAcknowledgement *pa_tail;
1887 * This message, reliability boxed. Only possibly available if @e pmt is
1890 struct PendingMessage *bpm;
1893 * Target of the request (for transmission, may not be ultimate
1896 struct Neighbour *target;
1899 * Distance vector path selected for this message, or
1900 * NULL if transmitted directly.
1902 struct DistanceVectorHop *dvh;
1905 * Set to non-NULL value if this message is currently being given to a
1906 * communicator and we are awaiting that communicator's acknowledgement.
1907 * Note that we must not retransmit a pending message while we're still
1908 * in the process of giving it to a communicator. If a pending message
1909 * is free'd while this entry is non-NULL, the @e qe reference to us
1910 * should simply be set to NULL.
1912 struct QueueEntry *qe;
1915 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1917 struct TransportClient *client;
1920 * Head of a MDLL of fragments created for this core message.
1922 struct PendingMessage *head_frag;
1925 * Tail of a MDLL of fragments created for this core message.
1927 struct PendingMessage *tail_frag;
1930 * Our parent in the fragmentation tree.
1932 struct PendingMessage *frag_parent;
1935 * At what time should we give up on the transmission (and no longer retry)?
1937 struct GNUNET_TIME_Absolute timeout;
1940 * What is the earliest time for us to retry transmission of this message?
1942 struct GNUNET_TIME_Absolute next_attempt;
1945 * UUID to use for this message (used for reassembly of fragments, only
1946 * initialized if @e msg_uuid_set is #GNUNET_YES).
1948 struct MessageUUIDP msg_uuid;
1951 * Type of the pending message.
1953 enum PendingMessageType pmt;
1956 * Size of the original message.
1961 * Offset at which we should generate the next fragment.
1966 * #GNUNET_YES once @e msg_uuid was initialized
1968 int16_t msg_uuid_set;
1970 /* Followed by @e bytes_msg to transmit */
1975 * Acknowledgement payload.
1977 struct TransportCummulativeAckPayload
1980 * When did we receive the message we are ACKing? Used to calculate
1981 * the delay we introduced by cummulating ACKs.
1983 struct GNUNET_TIME_Absolute receive_time;
1986 * UUID of a message being acknowledged.
1988 struct AcknowledgementUUIDP ack_uuid;
1993 * Data structure in which we track acknowledgements still to
1996 struct AcknowledgementCummulator
1999 * Target peer for which we are accumulating ACKs here.
2001 struct GNUNET_PeerIdentity target;
2004 * ACK data being accumulated. Only @e num_acks slots are valid.
2006 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2009 * Task scheduled either to transmit the cummulative ACK message,
2010 * or to clean up this data structure after extended periods of
2011 * inactivity (if @e num_acks is zero).
2013 struct GNUNET_SCHEDULER_Task *task;
2016 * When is @e task run (only used if @e num_acks is non-zero)?
2018 struct GNUNET_TIME_Absolute min_transmission_time;
2021 * Counter to produce the `ack_counter` in the `struct
2022 * TransportReliabilityAckMessage`. Allows the receiver to detect
2023 * lost ACK messages. Incremented by @e num_acks upon transmission.
2025 uint32_t ack_counter;
2028 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2030 unsigned int num_acks;
2035 * One of the addresses of this peer.
2037 struct AddressListEntry
2043 struct AddressListEntry *next;
2048 struct AddressListEntry *prev;
2051 * Which communicator provides this address?
2053 struct TransportClient *tc;
2056 * The actual address.
2058 const char *address;
2061 * Current context for storing this address in the peerstore.
2063 struct GNUNET_PEERSTORE_StoreContext *sc;
2066 * Task to periodically do @e st operation.
2068 struct GNUNET_SCHEDULER_Task *st;
2071 * What is a typical lifetime the communicator expects this
2072 * address to have? (Always from now.)
2074 struct GNUNET_TIME_Relative expiration;
2077 * Address identifier used by the communicator.
2082 * Network type offered by this address.
2084 enum GNUNET_NetworkType nt;
2089 * Client connected to the transport service.
2091 struct TransportClient
2097 struct TransportClient *next;
2102 struct TransportClient *prev;
2105 * Handle to the client.
2107 struct GNUNET_SERVICE_Client *client;
2110 * Message queue to the client.
2112 struct GNUNET_MQ_Handle *mq;
2115 * What type of client is this?
2117 enum ClientType type;
2123 * Information for @e type #CT_CORE.
2129 * Head of list of messages pending for this client, sorted by
2130 * transmission time ("next_attempt" + possibly internal prioritization).
2132 struct PendingMessage *pending_msg_head;
2135 * Tail of list of messages pending for this client.
2137 struct PendingMessage *pending_msg_tail;
2142 * Information for @e type #CT_MONITOR.
2148 * Peer identity to monitor the addresses of.
2149 * Zero to monitor all neighbours. Valid if
2150 * @e type is #CT_MONITOR.
2152 struct GNUNET_PeerIdentity peer;
2155 * Is this a one-shot monitor?
2163 * Information for @e type #CT_COMMUNICATOR.
2168 * If @e type is #CT_COMMUNICATOR, this communicator
2169 * supports communicating using these addresses.
2171 char *address_prefix;
2174 * Head of DLL of queues offered by this communicator.
2176 struct Queue *queue_head;
2179 * Tail of DLL of queues offered by this communicator.
2181 struct Queue *queue_tail;
2184 * Head of list of the addresses of this peer offered by this
2187 struct AddressListEntry *addr_head;
2190 * Tail of list of the addresses of this peer offered by this
2193 struct AddressListEntry *addr_tail;
2196 * Number of queue entries in all queues to this communicator. Used
2197 * throttle sending to a communicator if we see that the communicator
2198 * is globally unable to keep up.
2200 unsigned int total_queue_length;
2203 * Characteristics of this communicator.
2205 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2210 * Information for @e type #CT_APPLICATION
2216 * Map of requests for peers the given client application would like to
2217 * see connections for. Maps from PIDs to `struct PeerRequest`.
2219 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2228 * State we keep for validation activities. Each of these
2229 * is both in the #validation_heap and the #validation_map.
2231 struct ValidationState
2235 * For which peer is @a address to be validated (or possibly valid)?
2236 * Serves as key in the #validation_map.
2238 struct GNUNET_PeerIdentity pid;
2241 * How long did the peer claim this @e address to be valid? Capped at
2242 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2243 * were told about the address and the value claimed by the other peer at
2244 * that time. May be updated similarly when validation succeeds.
2246 struct GNUNET_TIME_Absolute valid_until;
2249 * How long do *we* consider this @e address to be valid?
2250 * In the past or zero if we have not yet validated it.
2252 struct GNUNET_TIME_Absolute validated_until;
2255 * When did we FIRST use the current @e challenge in a message?
2256 * Used to sanity-check @code{origin_time} in the response when
2257 * calculating the RTT. If the @code{origin_time} is not in
2258 * the expected range, the response is discarded as malicious.
2260 struct GNUNET_TIME_Absolute first_challenge_use;
2263 * When did we LAST 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 last_challenge_use;
2271 * Next time we will send the @e challenge to the peer, if this time is past
2272 * @e valid_until, this validation state is released at this time. If the
2273 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2274 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2275 * to re-validate before the validity actually expires.
2277 struct GNUNET_TIME_Absolute next_challenge;
2280 * Current backoff factor we're applying for sending the @a challenge.
2281 * Reset to 0 if the @a challenge is confirmed upon validation.
2282 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2283 * existing value if we receive an unvalidated address again over
2284 * another channel (and thus should consider the information "fresh").
2285 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2287 struct GNUNET_TIME_Relative challenge_backoff;
2290 * Initially set to "forever". Once @e validated_until is set, this value is
2291 * set to the RTT that tells us how long it took to receive the validation.
2293 struct GNUNET_TIME_Relative validation_rtt;
2296 * The challenge we sent to the peer to get it to validate the address. Note
2297 * that we rotate the challenge whenever we update @e validated_until to
2298 * avoid attacks where a peer simply replays an old challenge in the future.
2299 * (We must not rotate more often as otherwise we may discard valid answers
2300 * due to packet losses, latency and reorderings on the network).
2302 struct ChallengeNonceP challenge;
2305 * Claimed address of the peer.
2310 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2311 * heap is used to figure out when the next validation activity should be
2314 struct GNUNET_CONTAINER_HeapNode *hn;
2317 * Handle to a PEERSTORE store operation for this @e address. NULL if
2318 * no PEERSTORE operation is pending.
2320 struct GNUNET_PEERSTORE_StoreContext *sc;
2323 * We are technically ready to send the challenge, but we are waiting for
2324 * the respective queue to become available for transmission.
2331 * A Backtalker is a peer sending us backchannel messages. We use this
2332 * struct to detect monotonic time violations, cache ephemeral key
2333 * material (to avoid repeatedly checking signatures), and to synchronize
2334 * monotonic time with the PEERSTORE.
2339 * Peer this is about.
2341 struct GNUNET_PeerIdentity pid;
2344 * Last (valid) monotonic time received from this sender.
2346 struct GNUNET_TIME_Absolute monotonic_time;
2349 * When will this entry time out?
2351 struct GNUNET_TIME_Absolute timeout;
2354 * Last (valid) ephemeral key received from this sender.
2356 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2359 * Task associated with this backtalker. Can be for timeout,
2360 * or other asynchronous operations.
2362 struct GNUNET_SCHEDULER_Task *task;
2365 * Communicator context waiting on this backchannel's @e get, or NULL.
2367 struct CommunicatorMessageContext *cmc;
2370 * Handle for an operation to fetch @e monotonic_time information from the
2371 * PEERSTORE, or NULL.
2373 struct GNUNET_PEERSTORE_IterateContext *get;
2376 * Handle to a PEERSTORE store operation for this @e pid's @e
2377 * monotonic_time. NULL if no PEERSTORE operation is pending.
2379 struct GNUNET_PEERSTORE_StoreContext *sc;
2382 * Number of bytes of the original message body that follows after this
2390 * Head of linked list of all clients to this service.
2392 static struct TransportClient *clients_head;
2395 * Tail of linked list of all clients to this service.
2397 static struct TransportClient *clients_tail;
2400 * Statistics handle.
2402 static struct GNUNET_STATISTICS_Handle *GST_stats;
2405 * Configuration handle.
2407 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2412 static struct GNUNET_PeerIdentity GST_my_identity;
2417 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2420 * Map from PIDs to `struct Neighbour` entries. A peer is
2421 * a neighbour if we have an MQ to it from some communicator.
2423 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2426 * Map from PIDs to `struct Backtalker` entries. A peer is
2427 * a backtalker if it recently send us backchannel messages.
2429 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2432 * Map from PIDs to `struct AcknowledgementCummulator`s.
2433 * Here we track the cummulative ACKs for transmission.
2435 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2438 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2439 * a `struct PendingAcknowledgement`.
2441 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2444 * Map from PIDs to `struct DistanceVector` entries describing
2445 * known paths to the peer.
2447 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2450 * Map from PIDs to `struct ValidationState` entries describing
2451 * addresses we are aware of and their validity state.
2453 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2456 * Map from PIDs to `struct VirtualLink` entries describing
2457 * links CORE knows to exist.
2459 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2462 * Map from challenges to `struct LearnLaunchEntry` values.
2464 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2467 * Head of a DLL sorted by launch time.
2469 static struct LearnLaunchEntry *lle_head;
2472 * Tail of a DLL sorted by launch time.
2474 static struct LearnLaunchEntry *lle_tail;
2477 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2478 * sorting addresses we are aware of by when we should next try to (re)validate
2481 static struct GNUNET_CONTAINER_Heap *validation_heap;
2484 * Database for peer's HELLOs.
2486 static struct GNUNET_PEERSTORE_Handle *peerstore;
2489 * Heap sorting `struct EphemeralCacheEntry` by their
2490 * key/signature validity.
2492 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2495 * Hash map for looking up `struct EphemeralCacheEntry`s
2496 * by peer identity. (We may have ephemerals in our
2497 * cache for which we do not have a neighbour entry,
2498 * and similar many neighbours may not need ephemerals,
2499 * so we use a second map.)
2501 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2504 * Task to free expired ephemerals.
2506 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2509 * Task run to initiate DV learning.
2511 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2514 * Task to run address validation.
2516 static struct GNUNET_SCHEDULER_Task *validation_task;
2519 * The most recent PA we have created, head of DLL.
2520 * The length of the DLL is kept in #pa_count.
2522 static struct PendingAcknowledgement *pa_head;
2525 * The oldest PA we have created, tail of DLL.
2526 * The length of the DLL is kept in #pa_count.
2528 static struct PendingAcknowledgement *pa_tail;
2531 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2532 * limit the size of the data structure.
2534 static unsigned int pa_count;
2537 * Monotonic time we use for HELLOs generated at this time. TODO: we
2538 * should increase this value from time to time (i.e. whenever a
2539 * `struct AddressListEntry` actually expires), but IF we do this, we
2540 * must also update *all* (remaining) addresses in the PEERSTORE at
2541 * that time! (So for now only increased when the peer is restarted,
2542 * which hopefully roughly matches whenever our addresses change.)
2544 static struct GNUNET_TIME_Absolute hello_mono_time;
2548 * Get an offset into the transmission history buffer for `struct
2549 * PerformanceData`. Note that the caller must perform the required
2550 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2553 * An 'age' lasts 15 minute slots.
2555 * @return current age of the world
2560 struct GNUNET_TIME_Absolute now;
2562 now = GNUNET_TIME_absolute_get ();
2563 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2568 * Release @a pa data structure.
2570 * @param pa data structure to release
2573 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2575 struct Queue *q = pa->queue;
2576 struct PendingMessage *pm = pa->pm;
2577 struct DistanceVectorHop *dvh = pa->dvh;
2579 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2583 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2588 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2593 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2596 GNUNET_assert (GNUNET_YES ==
2597 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2598 &pa->ack_uuid.value,
2605 * Free cached ephemeral key.
2607 * @param ece cached signature to free
2610 free_ephemeral (struct EphemeralCacheEntry *ece)
2612 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2613 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2619 * Free virtual link.
2621 * @param vl link data to free
2624 free_virtual_link (struct VirtualLink *vl)
2626 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2627 if (NULL != vl->visibility_task)
2629 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2630 vl->visibility_task = NULL;
2632 GNUNET_break (NULL == vl->n);
2633 GNUNET_break (NULL == vl->dv);
2639 * Free validation state.
2641 * @param vs validation state to free
2644 free_validation_state (struct ValidationState *vs)
2646 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2647 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2651 GNUNET_PEERSTORE_store_cancel (vs->sc);
2654 GNUNET_free (vs->address);
2660 * Lookup neighbour record for peer @a pid.
2662 * @param pid neighbour to look for
2663 * @return NULL if we do not have this peer as a neighbour
2665 static struct Neighbour *
2666 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2668 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2673 * Details about what to notify monitors about.
2678 * @deprecated To be discussed if we keep these...
2680 struct GNUNET_TIME_Absolute last_validation;
2681 struct GNUNET_TIME_Absolute valid_until;
2682 struct GNUNET_TIME_Absolute next_validation;
2685 * Current round-trip time estimate.
2687 struct GNUNET_TIME_Relative rtt;
2690 * Connection status.
2692 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2697 uint32_t num_msg_pending;
2702 uint32_t num_bytes_pending;
2707 * Free a @dvh. Callers MAY want to check if this was the last path to the
2708 * `target`, and if so call #free_dv_route to also free the associated DV
2709 * entry in #dv_routes (if not, the associated scheduler job should eventually
2712 * @param dvh hop to free
2715 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2717 struct Neighbour *n = dvh->next_hop;
2718 struct DistanceVector *dv = dvh->dv;
2719 struct PendingAcknowledgement *pa;
2720 struct PendingMessage *pm;
2722 while (NULL != (pm = dvh->pending_msg_head))
2724 GNUNET_CONTAINER_MDLL_remove (dvh,
2725 dvh->pending_msg_head,
2726 dvh->pending_msg_tail,
2730 while (NULL != (pa = dvh->pa_head))
2732 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2735 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2736 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2742 * Free entry in #dv_routes. First frees all hops to the target, and
2743 * if there are no entries left, frees @a dv as well.
2745 * @param dv route to free
2748 free_dv_route (struct DistanceVector *dv)
2750 struct DistanceVectorHop *dvh;
2752 while (NULL != (dvh = dv->dv_head))
2753 free_distance_vector_hop (dvh);
2754 if (NULL == dv->dv_head)
2758 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2759 if (NULL != dv->timeout_task)
2760 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2767 * Notify monitor @a tc about an event. That @a tc
2768 * cares about the event has already been checked.
2770 * Send @a tc information in @a me about a @a peer's status with
2771 * respect to some @a address to all monitors that care.
2773 * @param tc monitor to inform
2774 * @param peer peer the information is about
2775 * @param address address the information is about
2776 * @param nt network type associated with @a address
2777 * @param me detailed information to transmit
2780 notify_monitor (struct TransportClient *tc,
2781 const struct GNUNET_PeerIdentity *peer,
2782 const char *address,
2783 enum GNUNET_NetworkType nt,
2784 const struct MonitorEvent *me)
2786 struct GNUNET_MQ_Envelope *env;
2787 struct GNUNET_TRANSPORT_MonitorData *md;
2788 size_t addr_len = strlen (address) + 1;
2790 env = GNUNET_MQ_msg_extra (md,
2792 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2793 md->nt = htonl ((uint32_t) nt);
2795 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2796 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2797 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2798 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2799 md->cs = htonl ((uint32_t) me->cs);
2800 md->num_msg_pending = htonl (me->num_msg_pending);
2801 md->num_bytes_pending = htonl (me->num_bytes_pending);
2802 memcpy (&md[1], address, addr_len);
2803 GNUNET_MQ_send (tc->mq, env);
2808 * Send information in @a me about a @a peer's status with respect
2809 * to some @a address to all monitors that care.
2811 * @param peer peer the information is about
2812 * @param address address the information is about
2813 * @param nt network type associated with @a address
2814 * @param me detailed information to transmit
2817 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2818 const char *address,
2819 enum GNUNET_NetworkType nt,
2820 const struct MonitorEvent *me)
2822 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2824 if (CT_MONITOR != tc->type)
2826 if (tc->details.monitor.one_shot)
2828 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2829 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2831 notify_monitor (tc, peer, address, nt, me);
2837 * Called whenever a client connects. Allocates our
2838 * data structures associated with that client.
2840 * @param cls closure, NULL
2841 * @param client identification of the client
2842 * @param mq message queue for the client
2843 * @return our `struct TransportClient`
2846 client_connect_cb (void *cls,
2847 struct GNUNET_SERVICE_Client *client,
2848 struct GNUNET_MQ_Handle *mq)
2850 struct TransportClient *tc;
2853 tc = GNUNET_new (struct TransportClient);
2854 tc->client = client;
2856 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2865 * @param rc data structure to free
2868 free_reassembly_context (struct ReassemblyContext *rc)
2870 struct Neighbour *n = rc->neighbour;
2872 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2873 GNUNET_assert (GNUNET_OK ==
2874 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2882 * Task run to clean up reassembly context of a neighbour that have expired.
2884 * @param cls a `struct Neighbour`
2887 reassembly_cleanup_task (void *cls)
2889 struct Neighbour *n = cls;
2890 struct ReassemblyContext *rc;
2892 n->reassembly_timeout_task = NULL;
2893 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2895 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2898 free_reassembly_context (rc);
2901 GNUNET_assert (NULL == n->reassembly_timeout_task);
2902 n->reassembly_timeout_task =
2903 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2904 &reassembly_cleanup_task,
2912 * function called to #free_reassembly_context().
2916 * @param value a `struct ReassemblyContext` to free
2917 * @return #GNUNET_OK (continue iteration)
2920 free_reassembly_cb (void *cls, uint32_t key, void *value)
2922 struct ReassemblyContext *rc = value;
2926 free_reassembly_context (rc);
2932 * Release memory used by @a neighbour.
2934 * @param neighbour neighbour entry to free
2937 free_neighbour (struct Neighbour *neighbour)
2939 struct DistanceVectorHop *dvh;
2941 GNUNET_assert (NULL == neighbour->queue_head);
2942 GNUNET_assert (GNUNET_YES ==
2943 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2946 if (NULL != neighbour->reassembly_map)
2948 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2949 &free_reassembly_cb,
2951 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2952 neighbour->reassembly_map = NULL;
2953 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2954 neighbour->reassembly_heap = NULL;
2956 while (NULL != (dvh = neighbour->dv_head))
2958 struct DistanceVector *dv = dvh->dv;
2960 free_distance_vector_hop (dvh);
2961 if (NULL == dv->dv_head)
2964 if (NULL != neighbour->reassembly_timeout_task)
2966 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2967 neighbour->reassembly_timeout_task = NULL;
2969 if (NULL != neighbour->get)
2971 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2972 neighbour->get = NULL;
2974 if (NULL != neighbour->sc)
2976 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2977 neighbour->sc = NULL;
2979 GNUNET_free (neighbour);
2984 * Send message to CORE clients that we lost a connection.
2986 * @param tc client to inform (must be CORE client)
2987 * @param pid peer the connection is for
2990 core_send_connect_info (struct TransportClient *tc,
2991 const struct GNUNET_PeerIdentity *pid)
2993 struct GNUNET_MQ_Envelope *env;
2994 struct ConnectInfoMessage *cim;
2996 GNUNET_assert (CT_CORE == tc->type);
2997 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2999 GNUNET_MQ_send (tc->mq, env);
3004 * Send message to CORE clients that we gained a connection
3006 * @param pid peer the queue was for
3009 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3012 "Informing CORE clients about connection to %s\n",
3014 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3016 if (CT_CORE != tc->type)
3018 core_send_connect_info (tc, pid);
3024 * Send message to CORE clients that we lost a connection.
3026 * @param pid peer the connection was for
3029 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3032 "Informing CORE clients about disconnect from %s\n",
3034 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3036 struct GNUNET_MQ_Envelope *env;
3037 struct DisconnectInfoMessage *dim;
3039 if (CT_CORE != tc->type)
3041 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3043 GNUNET_MQ_send (tc->mq, env);
3049 * We believe we are ready to transmit a message on a queue. Gives the
3050 * message to the communicator for transmission (updating the tracker,
3051 * and re-scheduling itself if applicable).
3053 * @param cls the `struct Queue` to process transmissions for
3056 transmit_on_queue (void *cls);
3060 * Schedule next run of #transmit_on_queue(). Does NOTHING if
3061 * we should run immediately or if the message queue is empty.
3062 * Test for no task being added AND queue not being empty to
3063 * transmit immediately afterwards! This function must only
3064 * be called if the message queue is non-empty!
3066 * @param queue the queue to do scheduling for
3067 * @param inside_job set to #GNUNET_YES if called from
3068 * #transmit_on_queue() itself and NOT setting
3069 * the task means running immediately
3072 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3074 struct Neighbour *n = queue->neighbour;
3075 struct PendingMessage *pm = n->pending_msg_head;
3076 struct GNUNET_TIME_Relative out_delay;
3078 GNUNET_assert (NULL != pm);
3079 if (queue->tc->details.communicator.total_queue_length >=
3080 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3082 GNUNET_STATISTICS_update (
3084 "# Transmission throttled due to communicator queue limit",
3089 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3091 GNUNET_STATISTICS_update (GST_stats,
3092 "# Transmission throttled due to queue queue limit",
3098 out_delay = GNUNET_TIME_absolute_get_remaining (pm->next_attempt);
3099 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3102 GNUNET_ERROR_TYPE_DEBUG,
3103 "Schedule transmission on queue %llu of %s decides to run immediately\n",
3104 (unsigned long long) queue->qid,
3105 GNUNET_i2s (&n->pid));
3106 return; /* we should run immediately! */
3108 /* queue has changed since we were scheduled, reschedule again */
3109 queue->transmit_task =
3110 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3111 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3112 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3113 "Next transmission on queue `%s' in %s (high delay)\n",
3115 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3118 "Next transmission on queue `%s' in %s\n",
3120 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3125 * Task run to check whether the hops of the @a cls still
3126 * are validated, or if we need to core about disconnection.
3128 * @param cls a `struct VirtualLink`
3131 check_link_down (void *cls)
3133 struct VirtualLink *vl = cls;
3134 struct DistanceVector *dv = vl->dv;
3135 struct Neighbour *n = vl->n;
3136 struct GNUNET_TIME_Absolute dvh_timeout;
3137 struct GNUNET_TIME_Absolute q_timeout;
3139 vl->visibility_task = NULL;
3140 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3141 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3143 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3144 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3146 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3147 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3148 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3149 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3151 if ((NULL == vl->n) && (NULL == vl->dv))
3153 cores_send_disconnect_info (&dv->target);
3154 free_virtual_link (vl);
3157 vl->visibility_task =
3158 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3167 * @param queue the queue to free
3170 free_queue (struct Queue *queue)
3172 struct Neighbour *neighbour = queue->neighbour;
3173 struct TransportClient *tc = queue->tc;
3174 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3175 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3176 struct QueueEntry *qe;
3178 struct PendingAcknowledgement *pa;
3179 struct VirtualLink *vl;
3181 if (NULL != queue->transmit_task)
3183 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3184 queue->transmit_task = NULL;
3186 while (NULL != (pa = queue->pa_head))
3188 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3192 GNUNET_CONTAINER_MDLL_remove (neighbour,
3193 neighbour->queue_head,
3194 neighbour->queue_tail,
3196 GNUNET_CONTAINER_MDLL_remove (client,
3197 tc->details.communicator.queue_head,
3198 tc->details.communicator.queue_tail,
3200 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3201 tc->details.communicator.total_queue_length);
3202 while (NULL != (qe = queue->queue_head))
3204 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3205 queue->queue_length--;
3206 tc->details.communicator.total_queue_length--;
3209 GNUNET_assert (qe == qe->pm->qe);
3214 GNUNET_assert (0 == queue->queue_length);
3215 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3216 tc->details.communicator.total_queue_length))
3218 /* Communicator dropped below threshold, resume all queues */
3219 GNUNET_STATISTICS_update (
3221 "# Transmission throttled due to communicator queue limit",
3224 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3226 schedule_transmit_on_queue (s, GNUNET_NO);
3228 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3229 GNUNET_free (queue);
3231 vl = GNUNET_CONTAINER_multipeermap_get (links, &neighbour->pid);
3232 if ((NULL != vl) && (neighbour == vl->n))
3234 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3235 check_link_down (vl);
3237 if (NULL == neighbour->queue_head)
3239 free_neighbour (neighbour);
3247 * @param ale address list entry to free
3250 free_address_list_entry (struct AddressListEntry *ale)
3252 struct TransportClient *tc = ale->tc;
3254 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3255 tc->details.communicator.addr_tail,
3257 if (NULL != ale->sc)
3259 GNUNET_PEERSTORE_store_cancel (ale->sc);
3262 if (NULL != ale->st)
3264 GNUNET_SCHEDULER_cancel (ale->st);
3272 * Stop the peer request in @a value.
3274 * @param cls a `struct TransportClient` that no longer makes the request
3275 * @param pid the peer's identity
3276 * @param value a `struct PeerRequest`
3277 * @return #GNUNET_YES (always)
3280 stop_peer_request (void *cls,
3281 const struct GNUNET_PeerIdentity *pid,
3284 struct TransportClient *tc = cls;
3285 struct PeerRequest *pr = value;
3287 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3290 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3300 * Called whenever a client is disconnected. Frees our
3301 * resources associated with that client.
3303 * @param cls closure, NULL
3304 * @param client identification of the client
3305 * @param app_ctx our `struct TransportClient`
3308 client_disconnect_cb (void *cls,
3309 struct GNUNET_SERVICE_Client *client,
3312 struct TransportClient *tc = app_ctx;
3316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3317 "Client %p disconnected, cleaning up.\n",
3319 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3325 struct PendingMessage *pm;
3327 while (NULL != (pm = tc->details.core.pending_msg_head))
3329 GNUNET_CONTAINER_MDLL_remove (client,
3330 tc->details.core.pending_msg_head,
3331 tc->details.core.pending_msg_tail,
3339 case CT_COMMUNICATOR: {
3341 struct AddressListEntry *ale;
3343 while (NULL != (q = tc->details.communicator.queue_head))
3345 while (NULL != (ale = tc->details.communicator.addr_head))
3346 free_address_list_entry (ale);
3347 GNUNET_free (tc->details.communicator.address_prefix);
3350 case CT_APPLICATION:
3351 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3354 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3362 * Iterator telling new CORE client about all existing
3363 * connections to peers.
3365 * @param cls the new `struct TransportClient`
3366 * @param pid a connected peer
3367 * @param value the `struct Neighbour` with more information
3368 * @return #GNUNET_OK (continue to iterate)
3371 notify_client_connect_info (void *cls,
3372 const struct GNUNET_PeerIdentity *pid,
3375 struct TransportClient *tc = cls;
3378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3379 "Telling new CORE client about existing connection to %s\n",
3381 core_send_connect_info (tc, pid);
3387 * Initialize a "CORE" client. We got a start message from this
3388 * client, so add it to the list of clients for broadcasting of
3391 * @param cls the client
3392 * @param start the start message that was sent
3395 handle_client_start (void *cls, const struct StartMessage *start)
3397 struct TransportClient *tc = cls;
3400 options = ntohl (start->options);
3401 if ((0 != (1 & options)) &&
3402 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3404 /* client thinks this is a different peer, reject */
3406 GNUNET_SERVICE_client_drop (tc->client);
3409 if (CT_NONE != tc->type)
3412 GNUNET_SERVICE_client_drop (tc->client);
3416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3417 "New CORE client with PID %s registered\n",
3418 GNUNET_i2s (&start->self));
3419 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3420 ¬ify_client_connect_info,
3422 GNUNET_SERVICE_client_continue (tc->client);
3427 * Client asked for transmission to a peer. Process the request.
3429 * @param cls the client
3430 * @param obm the send message that was sent
3433 check_client_send (void *cls, const struct OutboundMessage *obm)
3435 struct TransportClient *tc = cls;
3437 const struct GNUNET_MessageHeader *obmm;
3439 if (CT_CORE != tc->type)
3442 return GNUNET_SYSERR;
3444 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3445 if (size < sizeof (struct GNUNET_MessageHeader))
3448 return GNUNET_SYSERR;
3450 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3451 if (size != ntohs (obmm->size))
3454 return GNUNET_SYSERR;
3461 * Free fragment tree below @e root, excluding @e root itself.
3462 * FIXME: this does NOT seem to have the intended semantics
3463 * based on how this is called. Seems we generally DO expect
3464 * @a root to be free'ed itself as well!
3466 * @param root root of the tree to free
3469 free_fragment_tree (struct PendingMessage *root)
3471 struct PendingMessage *frag;
3473 while (NULL != (frag = root->head_frag))
3475 struct PendingAcknowledgement *pa;
3477 free_fragment_tree (frag);
3478 while (NULL != (pa = frag->pa_head))
3480 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3483 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3490 * Release memory associated with @a pm and remove @a pm from associated
3491 * data structures. @a pm must be a top-level pending message and not
3492 * a fragment in the tree. The entire tree is freed (if applicable).
3494 * @param pm the pending message to free
3497 free_pending_message (struct PendingMessage *pm)
3499 struct TransportClient *tc = pm->client;
3500 struct Neighbour *target = pm->target;
3501 struct DistanceVectorHop *dvh = pm->dvh;
3502 struct PendingAcknowledgement *pa;
3506 GNUNET_CONTAINER_MDLL_remove (client,
3507 tc->details.core.pending_msg_head,
3508 tc->details.core.pending_msg_tail,
3513 GNUNET_CONTAINER_MDLL_remove (dvh,
3514 dvh->pending_msg_head,
3515 dvh->pending_msg_tail,
3518 GNUNET_CONTAINER_MDLL_remove (neighbour,
3519 target->pending_msg_head,
3520 target->pending_msg_tail,
3522 while (NULL != (pa = pm->pa_head))
3524 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3528 free_fragment_tree (pm);
3531 GNUNET_assert (pm == pm->qe->pm);
3534 GNUNET_free_non_null (pm->bpm);
3540 * Send a response to the @a pm that we have processed a "send"
3541 * request. Sends a confirmation to the "core" client responsible for
3542 * the original request and free's @a pm.
3544 * @param pm handle to the original pending message
3547 client_send_response (struct PendingMessage *pm)
3549 struct TransportClient *tc = pm->client;
3550 struct Neighbour *target = pm->target;
3551 struct GNUNET_MQ_Envelope *env;
3552 struct SendOkMessage *som;
3556 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3557 som->peer = target->pid;
3558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3559 "Confirming transmission to %s\n",
3560 GNUNET_i2s (&pm->target->pid));
3561 GNUNET_MQ_send (tc->mq, env);
3563 free_pending_message (pm);
3568 * Create a DV Box message.
3570 * @param total_hops how many hops did the message take so far
3571 * @param num_hops length of the @a hops array
3572 * @param origin origin of the message
3573 * @param hops next peer(s) to the destination, including destination
3574 * @param payload payload of the box
3575 * @param payload_size number of bytes in @a payload
3576 * @return boxed message (caller must #GNUNET_free() it).
3578 static struct TransportDVBoxMessage *
3579 create_dv_box (uint16_t total_hops,
3580 const struct GNUNET_PeerIdentity *origin,
3581 const struct GNUNET_PeerIdentity *target,
3583 const struct GNUNET_PeerIdentity *hops,
3584 const void *payload,
3585 uint16_t payload_size)
3587 struct TransportDVBoxMessage *dvb;
3588 struct GNUNET_PeerIdentity *dhops;
3590 GNUNET_assert (UINT16_MAX <
3591 sizeof (struct TransportDVBoxMessage) +
3592 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3594 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3595 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3598 htons (sizeof (struct TransportDVBoxMessage) +
3599 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3600 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3601 dvb->total_hops = htons (total_hops);
3602 dvb->num_hops = htons (num_hops + 1);
3603 dvb->origin = *origin;
3604 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3605 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3606 dhops[num_hops] = *target;
3607 memcpy (&dhops[num_hops + 1], payload, payload_size);
3609 if (GNUNET_EXTRA_LOGGING > 0)
3613 path = GNUNET_strdup (GNUNET_i2s (&dvb->origin));
3614 for (unsigned int i = 0; i <= num_hops; i++)
3618 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
3622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3623 "Creating DVBox for %u bytes of payload via %s\n",
3624 (unsigned int) payload_size,
3634 * Pick @a hops_array_length random DV paths satisfying @a options
3636 * @param dv data structure to pick paths from
3637 * @param options constraints to satisfy
3638 * @param hops_array[out] set to the result
3639 * @param hops_array_length length of the @a hops_array
3640 * @return number of entries set in @a hops_array
3643 pick_random_dv_hops (const struct DistanceVector *dv,
3644 enum RouteMessageOptions options,
3645 struct DistanceVectorHop **hops_array,
3646 unsigned int hops_array_length)
3648 uint64_t choices[hops_array_length];
3650 unsigned int dv_count;
3652 /* Pick random vectors, but weighted by distance, giving more weight
3653 to shorter vectors */
3656 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3659 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3660 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3661 .rel_value_us == 0))
3662 continue; /* pos unconfirmed and confirmed required */
3663 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3668 if (dv_count <= hops_array_length)
3671 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3673 hops_array[dv_count++] = pos;
3676 for (unsigned int i = 0; i < hops_array_length; i++)
3679 while (GNUNET_NO == ok)
3682 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3684 for (unsigned int j = 0; j < i; j++)
3685 if (choices[i] == choices[j])
3694 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3697 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3699 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3700 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3701 .rel_value_us == 0))
3702 continue; /* pos unconfirmed and confirmed required */
3703 for (unsigned int i = 0; i < hops_array_length; i++)
3704 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3705 hops_array[dv_count++] = pos;
3713 * Client asked for transmission to a peer. Process the request.
3715 * @param cls the client
3716 * @param obm the send message that was sent
3719 handle_client_send (void *cls, const struct OutboundMessage *obm)
3721 struct TransportClient *tc = cls;
3722 struct PendingMessage *pm;
3723 const struct GNUNET_MessageHeader *obmm;
3724 struct Neighbour *target;
3725 struct DistanceVector *dv;
3726 struct DistanceVectorHop *dvh;
3729 const void *payload;
3730 size_t payload_size;
3731 struct TransportDVBoxMessage *dvb;
3732 struct VirtualLink *vl;
3733 enum GNUNET_MQ_PriorityPreferences pp;
3735 GNUNET_assert (CT_CORE == tc->type);
3736 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3737 bytes_msg = ntohs (obmm->size);
3738 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
3739 /* FIXME: actually make use of pp */ (void) pp;
3740 vl = GNUNET_CONTAINER_multipeermap_get (links, &obm->peer);
3743 /* Failure: don't have this peer as a neighbour (anymore).
3744 Might have gone down asynchronously, so this is NOT
3745 a protocol violation by CORE. Still count the event,
3746 as this should be rare. */
3747 GNUNET_SERVICE_client_continue (tc->client);
3748 GNUNET_STATISTICS_update (GST_stats,
3749 "# messages dropped (neighbour unknown)",
3754 target = lookup_neighbour (&obm->peer);
3756 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3759 GNUNET_assert ((NULL != target) || (NULL != dv));
3760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3761 "Sending %u bytes to %s using %s\n",
3763 GNUNET_i2s (&obm->peer),
3764 (NULL == target) ? "distance vector path" : "direct queue");
3768 struct DistanceVectorHop *dvh;
3770 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3771 GNUNET_assert (1 == res);
3772 target = dvh->next_hop;
3773 dvb = create_dv_box (0,
3781 payload_size = ntohs (dvb->header.size);
3788 payload_size = bytes_msg;
3791 was_empty = (NULL == target->pending_msg_head);
3792 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3794 pm->target = target;
3795 pm->bytes_msg = payload_size;
3796 memcpy (&pm[1], payload, payload_size);
3797 GNUNET_free_non_null (dvb);
3802 GNUNET_CONTAINER_MDLL_insert (dvh,
3803 dvh->pending_msg_head,
3804 dvh->pending_msg_tail,
3807 GNUNET_CONTAINER_MDLL_insert (neighbour,
3808 target->pending_msg_head,
3809 target->pending_msg_tail,
3811 GNUNET_CONTAINER_MDLL_insert (client,
3812 tc->details.core.pending_msg_head,
3813 tc->details.core.pending_msg_tail,
3816 return; /* all queues must already be busy */
3817 for (struct Queue *queue = target->queue_head; NULL != queue;
3818 queue = queue->next_neighbour)
3820 /* try transmission on any queue that is idle */
3821 if (NULL == queue->transmit_task)
3823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3824 "Queue %llu to %s is idle, triggering transmission\n",
3825 (unsigned long long) queue->qid,
3826 GNUNET_i2s (&queue->neighbour->pid));
3827 queue->transmit_task =
3828 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3835 * Communicator started. Test message is well-formed.
3837 * @param cls the client
3838 * @param cam the send message that was sent
3841 check_communicator_available (
3843 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3845 struct TransportClient *tc = cls;
3848 if (CT_NONE != tc->type)
3851 return GNUNET_SYSERR;
3853 tc->type = CT_COMMUNICATOR;
3854 size = ntohs (cam->header.size) - sizeof (*cam);
3856 return GNUNET_OK; /* receive-only communicator */
3857 GNUNET_MQ_check_zero_termination (cam);
3863 * Send ACK to communicator (if requested) and free @a cmc.
3865 * @param cmc context for which we are done handling the message
3868 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3870 if (0 != ntohl (cmc->im.fc_on))
3872 /* send ACK when done to communicator for flow control! */
3873 struct GNUNET_MQ_Envelope *env;
3874 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3876 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3877 ack->reserved = htonl (0);
3878 ack->fc_id = cmc->im.fc_id;
3879 ack->sender = cmc->im.sender;
3880 GNUNET_MQ_send (cmc->tc->mq, env);
3882 GNUNET_SERVICE_client_continue (cmc->tc->client);
3888 * Client confirms that it is done handling message(s) to a particular
3889 * peer. We may now provide more messages to CORE for this peer.
3891 * Notifies the respective queues that more messages can now be received.
3893 * @param cls the client
3894 * @param rom the message that was sent
3897 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
3899 struct TransportClient *tc = cls;
3900 struct VirtualLink *vl;
3902 struct CommunicatorMessageContext *cmc;
3904 if (CT_CORE != tc->type)
3907 GNUNET_SERVICE_client_drop (tc->client);
3910 vl = GNUNET_CONTAINER_multipeermap_get (links, &rom->peer);
3913 GNUNET_STATISTICS_update (GST_stats,
3914 "# RECV_OK dropped: virtual link unknown",
3917 GNUNET_SERVICE_client_continue (tc->client);
3920 delta = ntohl (rom->increase_window_delta);
3921 vl->core_recv_window += delta;
3922 if (vl->core_recv_window <= 0)
3924 /* resume communicators */
3925 while (NULL != (cmc = vl->cmc_tail))
3927 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
3928 finish_cmc_handling (cmc);
3934 * Communicator started. Process the request.
3936 * @param cls the client
3937 * @param cam the send message that was sent
3940 handle_communicator_available (
3942 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3944 struct TransportClient *tc = cls;
3947 size = ntohs (cam->header.size) - sizeof (*cam);
3950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3951 "Receive-only communicator connected\n");
3952 return; /* receive-only communicator */
3954 tc->details.communicator.address_prefix =
3955 GNUNET_strdup ((const char *) &cam[1]);
3956 tc->details.communicator.cc =
3957 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3959 "Communicator with prefix `%s' connected\n",
3960 tc->details.communicator.address_prefix);
3961 GNUNET_SERVICE_client_continue (tc->client);
3966 * Communicator requests backchannel transmission. Check the request.
3968 * @param cls the client
3969 * @param cb the send message that was sent
3970 * @return #GNUNET_OK if message is well-formed
3973 check_communicator_backchannel (
3975 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3977 const struct GNUNET_MessageHeader *inbox;
3983 msize = ntohs (cb->header.size) - sizeof (*cb);
3984 if (((size_t) (UINT16_MAX - msize)) >
3985 sizeof (struct TransportBackchannelEncapsulationMessage) +
3986 sizeof (struct TransportBackchannelRequestPayloadP))
3989 return GNUNET_SYSERR;
3991 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3992 isize = ntohs (inbox->size);
3996 return GNUNET_SYSERR;
3998 is = (const char *) inbox;
4001 GNUNET_assert (msize > 0);
4002 if ('\0' != is[msize - 1])
4005 return GNUNET_SYSERR;
4012 * Remove memory used by expired ephemeral keys.
4017 expire_ephemerals (void *cls)
4019 struct EphemeralCacheEntry *ece;
4022 ephemeral_task = NULL;
4023 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
4025 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4028 free_ephemeral (ece);
4031 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4040 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists,
4041 * generate one, cache it and return it.
4043 * @param pid peer to look up ephemeral for
4044 * @param private_key[out] set to the private key
4045 * @param ephemeral_key[out] set to the key
4046 * @param ephemeral_sender_sig[out] set to the signature
4047 * @param monotime[out] set to the monotime used for the signature
4050 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
4051 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
4052 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
4053 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
4054 struct GNUNET_TIME_Absolute *monotime)
4056 struct EphemeralCacheEntry *ece;
4057 struct EphemeralConfirmationPS ec;
4059 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
4060 if ((NULL != ece) &&
4061 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4064 free_ephemeral (ece);
4069 ece = GNUNET_new (struct EphemeralCacheEntry);
4071 ece->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4072 ece->ephemeral_validity =
4073 GNUNET_TIME_absolute_add (ece->monotime, EPHEMERAL_VALIDITY);
4074 GNUNET_assert (GNUNET_OK ==
4075 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
4076 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
4077 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4078 ec.purpose.size = htonl (sizeof (ec));
4080 ec.ephemeral_key = ece->ephemeral_key;
4081 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4085 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
4087 ece->ephemeral_validity.abs_value_us);
4088 GNUNET_assert (GNUNET_OK ==
4089 GNUNET_CONTAINER_multipeermap_put (
4093 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4094 if (NULL == ephemeral_task)
4095 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4099 *private_key = ece->private_key;
4100 *ephemeral_key = ece->ephemeral_key;
4101 *ephemeral_sender_sig = ece->sender_sig;
4102 *monotime = ece->monotime;
4107 * Send the control message @a payload on @a queue.
4109 * @param queue the queue to use for transmission
4110 * @param pm pending message to update once transmission is done, may be NULL!
4111 * @param payload the payload to send (encapsulated in a
4112 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4113 * @param payload_size number of bytes in @a payload
4116 queue_send_msg (struct Queue *queue,
4117 struct PendingMessage *pm,
4118 const void *payload,
4119 size_t payload_size)
4121 struct Neighbour *n = queue->neighbour;
4122 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4123 struct GNUNET_MQ_Envelope *env;
4125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4126 "Queueing %u bytes of payload for transmission on queue %llu to %s\n",
4127 (unsigned int) payload_size,
4128 (unsigned long long) queue->qid,
4129 GNUNET_i2s (&queue->neighbour->pid));
4130 env = GNUNET_MQ_msg_extra (smt,
4132 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4133 smt->qid = queue->qid;
4134 smt->mid = queue->mid_gen;
4135 smt->receiver = n->pid;
4136 memcpy (&smt[1], payload, payload_size);
4138 /* Pass the env to the communicator of queue for transmission. */
4139 struct QueueEntry *qe;
4141 qe = GNUNET_new (struct QueueEntry);
4142 qe->mid = queue->mid_gen++;
4147 GNUNET_assert (NULL == pm->qe);
4150 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4151 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4152 queue->queue_length++;
4153 queue->tc->details.communicator.total_queue_length++;
4154 GNUNET_MQ_send (queue->tc->mq, env);
4159 // FIXME: improve logging after this point!
4162 * Pick a queue of @a n under constraints @a options and schedule
4163 * transmission of @a hdr.
4165 * @param n neighbour to send to
4166 * @param hdr message to send as payload
4167 * @param options whether queues must be confirmed or not,
4168 * and whether we may pick multiple (2) queues
4171 route_via_neighbour (const struct Neighbour *n,
4172 const struct GNUNET_MessageHeader *hdr,
4173 enum RouteMessageOptions options)
4175 struct GNUNET_TIME_Absolute now;
4176 unsigned int candidates;
4180 /* Pick one or two 'random' queues from n (under constraints of options) */
4181 now = GNUNET_TIME_absolute_get ();
4182 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4183 weight in the future; weight could be assigned by observed
4184 bandwidth (note: not sure if we should do this for this type
4185 of control traffic though). */
4187 for (struct Queue *pos = n->queue_head; NULL != pos;
4188 pos = pos->next_neighbour)
4190 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4191 (pos->validated_until.abs_value_us > now.abs_value_us))
4194 if (0 == candidates)
4196 /* This can happen rarely if the last confirmed queue timed
4197 out just as we were beginning to process this message. */
4198 GNUNET_STATISTICS_update (GST_stats,
4199 "# route selection failed (all no valid queue)",
4204 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4205 if (0 == (options & RMO_REDUNDANT))
4206 sel2 = candidates; /* picks none! */
4208 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4210 for (struct Queue *pos = n->queue_head; NULL != pos;
4211 pos = pos->next_neighbour)
4213 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4214 (pos->validated_until.abs_value_us > now.abs_value_us))
4216 if ((sel1 == candidates) || (sel2 == candidates))
4217 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4225 * Given a distance vector path @a dvh route @a payload to
4226 * the ultimate destination respecting @a options.
4227 * Sets up the boxed message and queues it at the next hop.
4229 * @param dvh choice of the path for the message
4230 * @param payload body to transmit
4231 * @param options options to use for control
4234 forward_via_dvh (const struct DistanceVectorHop *dvh,
4235 const struct GNUNET_MessageHeader *payload,
4236 enum RouteMessageOptions options)
4238 struct TransportDVBoxMessage *dvb;
4240 dvb = create_dv_box (0,
4246 ntohs (payload->size));
4247 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4253 * Pick a path of @a dv under constraints @a options and schedule
4254 * transmission of @a hdr.
4256 * @param n neighbour to send to
4257 * @param hdr message to send as payload
4258 * @param options whether path must be confirmed or not
4259 * and whether we may pick multiple (2) paths
4262 route_via_dv (const struct DistanceVector *dv,
4263 const struct GNUNET_MessageHeader *hdr,
4264 enum RouteMessageOptions options)
4266 struct DistanceVectorHop *hops[2];
4269 res = pick_random_dv_hops (dv,
4272 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4273 for (unsigned int i = 0; i < res; i++)
4274 forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT));
4279 * We need to transmit @a hdr to @a target. If necessary, this may
4280 * involve DV routing.
4282 * @param target peer to receive @a hdr
4283 * @param hdr header of the message to route and #GNUNET_free()
4284 * @param options which transmission channels are allowed
4287 route_message (const struct GNUNET_PeerIdentity *target,
4288 struct GNUNET_MessageHeader *hdr,
4289 enum RouteMessageOptions options)
4291 struct VirtualLink *vl;
4292 struct Neighbour *n;
4293 struct DistanceVector *dv;
4295 vl = GNUNET_CONTAINER_multipeermap_get (links, target);
4297 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4298 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4300 /* if confirmed is required, and we do not have anything
4301 confirmed, drop respective options */
4303 n = lookup_neighbour (target);
4304 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4305 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4307 if ((NULL == n) && (NULL == dv))
4309 GNUNET_STATISTICS_update (GST_stats,
4310 "# Messages dropped in routing: no acceptable method",
4316 /* If both dv and n are possible and we must choose:
4317 flip a coin for the choice between the two; for now 50/50 */
4318 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4320 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4325 if ((NULL != n) && (NULL != dv))
4326 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4327 enough for redunancy, so clear the flag. */
4330 route_via_neighbour (n, hdr, options);
4334 route_via_dv (dv, hdr, options);
4341 * Structure of the key material used to encrypt backchannel messages.
4343 struct BackchannelKeyState
4346 * State of our block cipher.
4348 gcry_cipher_hd_t cipher;
4351 * Actual key material.
4357 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4359 struct GNUNET_CRYPTO_AuthKey hmac_key;
4362 * Symmetric key to use for encryption.
4364 char aes_key[256 / 8];
4367 * Counter value to use during setup.
4369 char aes_ctr[128 / 8];
4376 * Given the key material in @a km and the initialization vector
4377 * @a iv, setup the key material for the backchannel in @a key.
4379 * @param km raw master secret
4380 * @param iv initialization vector
4381 * @param key[out] symmetric cipher and HMAC state to generate
4384 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4385 const struct GNUNET_ShortHashCode *iv,
4386 struct BackchannelKeyState *key)
4388 /* must match #dh_key_derive_eph_pub */
4389 GNUNET_assert (GNUNET_YES ==
4390 GNUNET_CRYPTO_kdf (&key->material,
4391 sizeof (key->material),
4392 "transport-backchannel-key",
4393 strlen ("transport-backchannel-key"),
4398 gcry_cipher_open (&key->cipher,
4399 GCRY_CIPHER_AES256 /* low level: go for speed */,
4400 GCRY_CIPHER_MODE_CTR,
4402 gcry_cipher_setkey (key->cipher,
4403 &key->material.aes_key,
4404 sizeof (key->material.aes_key));
4405 gcry_cipher_setctr (key->cipher,
4406 &key->material.aes_ctr,
4407 sizeof (key->material.aes_ctr));
4412 * Derive backchannel encryption key material from @a priv_ephemeral
4413 * and @a target and @a iv.
4415 * @param priv_ephemeral ephemeral private key to use
4416 * @param target the target peer to encrypt to
4417 * @param iv unique IV to use
4418 * @param key[out] set to the key material
4421 dh_key_derive_eph_pid (
4422 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4423 const struct GNUNET_PeerIdentity *target,
4424 const struct GNUNET_ShortHashCode *iv,
4425 struct BackchannelKeyState *key)
4427 struct GNUNET_HashCode km;
4429 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4430 &target->public_key,
4432 bc_setup_key_state_from_km (&km, iv, key);
4437 * Derive backchannel encryption key material from #GST_my_private_key
4438 * and @a pub_ephemeral and @a iv.
4440 * @param priv_ephemeral ephemeral private key to use
4441 * @param target the target peer to encrypt to
4442 * @param iv unique IV to use
4443 * @param key[out] set to the key material
4446 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4447 const struct GNUNET_ShortHashCode *iv,
4448 struct BackchannelKeyState *key)
4450 struct GNUNET_HashCode km;
4452 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4455 bc_setup_key_state_from_km (&km, iv, key);
4460 * Do HMAC calculation for backchannel messages over @a data using key
4461 * material from @a key.
4463 * @param key key material (from DH)
4464 * @param hmac[out] set to the HMAC
4465 * @param data data to perform HMAC calculation over
4466 * @param data_size number of bytes in @a data
4469 bc_hmac (const struct BackchannelKeyState *key,
4470 struct GNUNET_HashCode *hmac,
4474 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4479 * Perform backchannel encryption using symmetric secret in @a key
4480 * to encrypt data from @a in to @a dst.
4482 * @param key[in,out] key material to use
4483 * @param dst where to write the result
4484 * @param in input data to encrypt (plaintext)
4485 * @param in_size number of bytes of input in @a in and available at @a dst
4488 bc_encrypt (struct BackchannelKeyState *key,
4494 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4499 * Perform backchannel encryption using symmetric secret in @a key
4500 * to encrypt data from @a in to @a dst.
4502 * @param key[in,out] key material to use
4503 * @param ciph cipher text to decrypt
4504 * @param out[out] output data to generate (plaintext)
4505 * @param out_size number of bytes of input in @a ciph and available in @a out
4508 bc_decrypt (struct BackchannelKeyState *key,
4514 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4519 * Clean up key material in @a key.
4521 * @param key key material to clean up (memory must not be free'd!)
4524 bc_key_clean (struct BackchannelKeyState *key)
4526 gcry_cipher_close (key->cipher);
4527 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4532 * Communicator requests backchannel transmission. Process the request.
4534 * @param cls the client
4535 * @param cb the send message that was sent
4538 handle_communicator_backchannel (
4540 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4542 struct TransportClient *tc = cls;
4543 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4544 struct GNUNET_TIME_Absolute monotime;
4545 struct TransportBackchannelEncapsulationMessage *enc;
4546 struct TransportBackchannelRequestPayloadP ppay;
4547 struct BackchannelKeyState key;
4551 /* encapsulate and encrypt message */
4552 msize = ntohs (cb->header.size) - sizeof (*cb) +
4553 sizeof (struct TransportBackchannelRequestPayloadP);
4554 enc = GNUNET_malloc (sizeof (*enc) + msize);
4556 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4557 enc->header.size = htons (sizeof (*enc) + msize);
4558 enc->target = cb->pid;
4559 lookup_ephemeral (&cb->pid,
4561 &enc->ephemeral_key,
4564 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4567 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4568 ppay.monotonic_time = GNUNET_TIME_absolute_hton (monotime);
4569 mpos = (char *) &enc[1];
4570 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4573 &mpos[sizeof (ppay)],
4574 ntohs (cb->header.size) - sizeof (*cb));
4578 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4579 bc_key_clean (&key);
4580 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4581 GNUNET_SERVICE_client_continue (tc->client);
4586 * Address of our peer added. Test message is well-formed.
4588 * @param cls the client
4589 * @param aam the send message that was sent
4590 * @return #GNUNET_OK if message is well-formed
4593 check_add_address (void *cls,
4594 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4596 struct TransportClient *tc = cls;
4598 if (CT_COMMUNICATOR != tc->type)
4601 return GNUNET_SYSERR;
4603 GNUNET_MQ_check_zero_termination (aam);
4609 * Ask peerstore to store our address.
4611 * @param cls an `struct AddressListEntry *`
4614 store_pi (void *cls);
4618 * Function called when peerstore is done storing our address.
4620 * @param cls a `struct AddressListEntry`
4621 * @param success #GNUNET_YES if peerstore was successful
4624 peerstore_store_own_cb (void *cls, int success)
4626 struct AddressListEntry *ale = cls;
4629 if (GNUNET_YES != success)
4630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4631 "Failed to store our own address `%s' in peerstore!\n",
4633 /* refresh period is 1/4 of expiration time, that should be plenty
4634 without being excessive. */
4636 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4644 * Ask peerstore to store our address.
4646 * @param cls an `struct AddressListEntry *`
4649 store_pi (void *cls)
4651 struct AddressListEntry *ale = cls;
4654 struct GNUNET_TIME_Absolute expiration;
4657 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4658 GNUNET_HELLO_sign_address (ale->address,
4664 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4667 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4671 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4672 &peerstore_store_own_cb,
4675 if (NULL == ale->sc)
4677 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4678 "Failed to store our address `%s' with peerstore\n",
4681 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4687 * Address of our peer added. Process the request.
4689 * @param cls the client
4690 * @param aam the send message that was sent
4693 handle_add_address (void *cls,
4694 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4696 struct TransportClient *tc = cls;
4697 struct AddressListEntry *ale;
4700 slen = ntohs (aam->header.size) - sizeof (*aam);
4701 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4703 ale->address = (const char *) &ale[1];
4704 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4705 ale->aid = aam->aid;
4706 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4707 memcpy (&ale[1], &aam[1], slen);
4708 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4709 tc->details.communicator.addr_tail,
4711 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4712 GNUNET_SERVICE_client_continue (tc->client);
4717 * Address of our peer deleted. Process the request.
4719 * @param cls the client
4720 * @param dam the send message that was sent
4723 handle_del_address (void *cls,
4724 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4726 struct TransportClient *tc = cls;
4728 if (CT_COMMUNICATOR != tc->type)
4731 GNUNET_SERVICE_client_drop (tc->client);
4734 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4738 if (dam->aid != ale->aid)
4740 GNUNET_assert (ale->tc == tc);
4741 free_address_list_entry (ale);
4742 GNUNET_SERVICE_client_continue (tc->client);
4745 GNUNET_SERVICE_client_drop (tc->client);
4750 * Given an inbound message @a msg from a communicator @a cmc,
4751 * demultiplex it based on the type calling the right handler.
4753 * @param cmc context for demultiplexing
4754 * @param msg message to demultiplex
4757 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4758 const struct GNUNET_MessageHeader *msg);
4762 * Communicator gave us an unencapsulated message to pass as-is to
4763 * CORE. Process the request.
4765 * @param cls a `struct CommunicatorMessageContext` (must call
4766 * #finish_cmc_handling() when done)
4767 * @param mh the message that was received
4770 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4772 struct CommunicatorMessageContext *cmc = cls;
4773 struct VirtualLink *vl;
4774 uint16_t size = ntohs (mh->size);
4776 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4777 (size < sizeof (struct GNUNET_MessageHeader)))
4779 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4782 finish_cmc_handling (cmc);
4783 GNUNET_SERVICE_client_drop (client);
4786 vl = GNUNET_CONTAINER_multipeermap_get (links, &cmc->im.sender);
4789 /* FIXME: sender is giving us messages for CORE but we don't have
4790 the link up yet! I *suspect* this can happen right now (i.e.
4791 sender has verified us, but we didn't verify sender), but if
4792 we pass this on, CORE would be confused (link down, messages
4793 arrive). We should investigate more if this happens often,
4794 or in a persistent manner, and possibly do "something" about
4795 it. Thus logging as error for now. */
4796 GNUNET_break_op (0);
4797 GNUNET_STATISTICS_update (GST_stats,
4798 "# CORE messages droped (virtual link still down)",
4802 finish_cmc_handling (cmc);
4805 /* Forward to all CORE clients */
4806 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4808 struct GNUNET_MQ_Envelope *env;
4809 struct InboundMessage *im;
4811 if (CT_CORE != tc->type)
4813 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4814 im->peer = cmc->im.sender;
4815 memcpy (&im[1], mh, size);
4816 GNUNET_MQ_send (tc->mq, env);
4818 vl->core_recv_window--;
4819 if (vl->core_recv_window > 0)
4821 finish_cmc_handling (cmc);
4824 /* Wait with calling #finish_cmc_handling(cmc) until the message
4825 was processed by CORE MQs (for CORE flow control)! */
4826 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
4831 * Communicator gave us a fragment box. Check the message.
4833 * @param cls a `struct CommunicatorMessageContext`
4834 * @param fb the send message that was sent
4835 * @return #GNUNET_YES if message is well-formed
4838 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4840 uint16_t size = ntohs (fb->header.size);
4841 uint16_t bsize = size - sizeof (*fb);
4846 GNUNET_break_op (0);
4847 return GNUNET_SYSERR;
4849 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4851 GNUNET_break_op (0);
4852 return GNUNET_SYSERR;
4854 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4856 GNUNET_break_op (0);
4857 return GNUNET_SYSERR;
4864 * Clean up an idle cummulative acknowledgement data structure.
4866 * @param cls a `struct AcknowledgementCummulator *`
4869 destroy_ack_cummulator (void *cls)
4871 struct AcknowledgementCummulator *ac = cls;
4874 GNUNET_assert (0 == ac->num_acks);
4877 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4883 * Do the transmission of a cummulative acknowledgement now.
4885 * @param cls a `struct AcknowledgementCummulator *`
4888 transmit_cummulative_ack_cb (void *cls)
4890 struct AcknowledgementCummulator *ac = cls;
4891 struct TransportReliabilityAckMessage *ack;
4892 struct TransportCummulativeAckPayloadP *ap;
4895 GNUNET_assert (0 < ac->ack_counter);
4896 ack = GNUNET_malloc (sizeof (*ack) +
4898 sizeof (struct TransportCummulativeAckPayloadP));
4899 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4901 htons (sizeof (*ack) +
4902 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4903 ack->ack_counter = htonl (ac->ack_counter++);
4904 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4905 for (unsigned int i = 0; i < ac->ack_counter; i++)
4907 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4908 ap[i].ack_delay = GNUNET_TIME_relative_hton (
4909 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
4911 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
4913 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
4914 &destroy_ack_cummulator,
4920 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
4921 * transmission by at most @a ack_delay.
4923 * @param pid target peer
4924 * @param ack_uuid UUID to ack
4925 * @param max_delay how long can the ACK wait
4928 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
4929 const struct AcknowledgementUUIDP *ack_uuid,
4930 struct GNUNET_TIME_Absolute max_delay)
4932 struct AcknowledgementCummulator *ac;
4934 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
4937 ac = GNUNET_new (struct AcknowledgementCummulator);
4939 ac->min_transmission_time = max_delay;
4940 GNUNET_assert (GNUNET_YES ==
4941 GNUNET_CONTAINER_multipeermap_put (
4945 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4949 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
4951 /* must run immediately, ack buffer full! */
4952 GNUNET_SCHEDULER_cancel (ac->task);
4953 transmit_cummulative_ack_cb (ac);
4955 GNUNET_SCHEDULER_cancel (ac->task);
4956 ac->min_transmission_time =
4957 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
4959 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
4960 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
4961 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
4963 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
4964 &transmit_cummulative_ack_cb,
4970 * Closure for #find_by_message_uuid.
4972 struct FindByMessageUuidContext
4977 struct MessageUUIDP message_uuid;
4980 * Set to the reassembly context if found.
4982 struct ReassemblyContext *rc;
4987 * Iterator called to find a reassembly context by the message UUID in the
4990 * @param cls a `struct FindByMessageUuidContext`
4991 * @param key a key (unused)
4992 * @param value a `struct ReassemblyContext`
4993 * @return #GNUNET_YES if not found, #GNUNET_NO if found
4996 find_by_message_uuid (void *cls, uint32_t key, void *value)
4998 struct FindByMessageUuidContext *fc = cls;
4999 struct ReassemblyContext *rc = value;
5002 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5012 * Communicator gave us a fragment. Process the request.
5014 * @param cls a `struct CommunicatorMessageContext` (must call
5015 * #finish_cmc_handling() when done)
5016 * @param fb the message that was received
5019 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5021 struct CommunicatorMessageContext *cmc = cls;
5022 struct Neighbour *n;
5023 struct ReassemblyContext *rc;
5024 const struct GNUNET_MessageHeader *msg;
5029 struct GNUNET_TIME_Relative cdelay;
5030 struct FindByMessageUuidContext fc;
5032 n = lookup_neighbour (&cmc->im.sender);
5035 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5038 finish_cmc_handling (cmc);
5039 GNUNET_SERVICE_client_drop (client);
5042 if (NULL == n->reassembly_map)
5044 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5045 n->reassembly_heap =
5046 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5047 n->reassembly_timeout_task =
5048 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5049 &reassembly_cleanup_task,
5052 msize = ntohs (fb->msg_size);
5053 fc.message_uuid = fb->msg_uuid;
5055 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5057 &find_by_message_uuid,
5059 if (NULL == (rc = fc.rc))
5061 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5062 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5063 rc->msg_uuid = fb->msg_uuid;
5065 rc->msg_size = msize;
5066 rc->reassembly_timeout =
5067 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5068 rc->last_frag = GNUNET_TIME_absolute_get ();
5069 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5071 rc->reassembly_timeout.abs_value_us);
5072 GNUNET_assert (GNUNET_OK ==
5073 GNUNET_CONTAINER_multihashmap32_put (
5077 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5078 target = (char *) &rc[1];
5079 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5080 rc->msg_missing = rc->msg_size;
5084 target = (char *) &rc[1];
5086 if (msize != rc->msg_size)
5089 finish_cmc_handling (cmc);
5094 fsize = ntohs (fb->header.size) - sizeof (*fb);
5098 finish_cmc_handling (cmc);
5101 frag_off = ntohs (fb->frag_off);
5102 memcpy (&target[frag_off], &fb[1], fsize);
5103 /* update bitfield and msg_missing */
5104 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5106 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5108 rc->bitfield[i / 8] |= (1 << (i % 8));
5113 /* Compute cummulative ACK */
5114 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5115 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5116 if (0 == rc->msg_missing)
5117 cdelay = GNUNET_TIME_UNIT_ZERO;
5118 cummulative_ack (&cmc->im.sender,
5120 GNUNET_TIME_relative_to_absolute (cdelay));
5121 rc->last_frag = GNUNET_TIME_absolute_get ();
5122 /* is reassembly complete? */
5123 if (0 != rc->msg_missing)
5125 finish_cmc_handling (cmc);
5128 /* reassembly is complete, verify result */
5129 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5130 if (ntohs (msg->size) != rc->msg_size)
5133 free_reassembly_context (rc);
5134 finish_cmc_handling (cmc);
5137 /* successful reassembly */
5138 demultiplex_with_cmc (cmc, msg);
5139 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5140 en-route and we forget that we finished this reassembly immediately!
5141 -> keep around until timeout?
5142 -> shorten timeout based on ACK? */
5143 free_reassembly_context (rc);
5148 * Communicator gave us a reliability box. Check the message.
5150 * @param cls a `struct CommunicatorMessageContext`
5151 * @param rb the send message that was sent
5152 * @return #GNUNET_YES if message is well-formed
5155 check_reliability_box (void *cls,
5156 const struct TransportReliabilityBoxMessage *rb)
5159 GNUNET_MQ_check_boxed_message (rb);
5165 * Communicator gave us a reliability box. Process the request.
5167 * @param cls a `struct CommunicatorMessageContext` (must call
5168 * #finish_cmc_handling() when done)
5169 * @param rb the message that was received
5172 handle_reliability_box (void *cls,
5173 const struct TransportReliabilityBoxMessage *rb)
5175 struct CommunicatorMessageContext *cmc = cls;
5176 const struct GNUNET_MessageHeader *inbox =
5177 (const struct GNUNET_MessageHeader *) &rb[1];
5179 // FIXME: call cummulative_ack(), have ack_countdown influence max_delay!
5180 (void) (0 == ntohl (rb->ack_countdown));
5181 /* continue with inner message */
5182 demultiplex_with_cmc (cmc, inbox);
5187 * Check if we have advanced to another age since the last time. If
5188 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5191 * @param pd[in,out] data to update
5192 * @param age current age
5195 update_pd_age (struct PerformanceData *pd, unsigned int age)
5199 if (age == pd->last_age)
5200 return; /* nothing to do */
5201 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5202 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5204 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5206 the->bytes_sent = 0;
5207 the->bytes_received = 0;
5214 * Update @a pd based on the latest @a rtt and the number of bytes
5215 * that were confirmed to be successfully transmitted.
5217 * @param pd[in,out] data to update
5218 * @param rtt latest round-trip time
5219 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5222 update_performance_data (struct PerformanceData *pd,
5223 struct GNUNET_TIME_Relative rtt,
5224 uint16_t bytes_transmitted_ok)
5226 uint64_t nval = rtt.rel_value_us;
5227 uint64_t oval = pd->aged_rtt.rel_value_us;
5228 unsigned int age = get_age ();
5229 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5231 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5234 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5235 update_pd_age (pd, age);
5236 the->bytes_received += bytes_transmitted_ok;
5241 * We have successfully transmitted data via @a q, update metrics.
5243 * @param q queue to update
5244 * @param rtt round trip time observed
5245 * @param bytes_transmitted_ok number of bytes successfully transmitted
5248 update_queue_performance (struct Queue *q,
5249 struct GNUNET_TIME_Relative rtt,
5250 uint16_t bytes_transmitted_ok)
5252 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5257 * We have successfully transmitted data via @a dvh, update metrics.
5259 * @param dvh distance vector path data to update
5260 * @param rtt round trip time observed
5261 * @param bytes_transmitted_ok number of bytes successfully transmitted
5264 update_dvh_performance (struct DistanceVectorHop *dvh,
5265 struct GNUNET_TIME_Relative rtt,
5266 uint16_t bytes_transmitted_ok)
5268 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5273 * The @a pa was acknowledged, process the acknowledgement.
5275 * @param pa the pending acknowledgement that was satisfied
5276 * @param ack_delay artificial delay from cummulative acks created by the
5280 handle_acknowledged (struct PendingAcknowledgement *pa,
5281 struct GNUNET_TIME_Relative ack_delay)
5283 struct PendingMessage *pm = pa->pm;
5284 struct GNUNET_TIME_Relative delay;
5286 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5287 if (delay.rel_value_us > ack_delay.rel_value_us)
5288 delay = GNUNET_TIME_UNIT_ZERO;
5290 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5291 if (NULL != pa->queue)
5292 update_queue_performance (pa->queue, delay, pa->message_size);
5293 if (NULL != pa->dvh)
5294 update_dvh_performance (pa->dvh, delay, pa->message_size);
5297 if (NULL != pm->frag_parent)
5299 pm = pm->frag_parent;
5300 free_fragment_tree (pa->pm);
5302 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5304 struct PendingMessage *parent = pm->frag_parent;
5306 free_fragment_tree (pm);
5309 if (NULL != pm->head_frag)
5310 pm = NULL; /* we are done, otherwise free 'pm' below */
5313 free_pending_message (pm);
5314 free_pending_acknowledgement (pa);
5319 * Communicator gave us a reliability ack. Check it is well-formed.
5321 * @param cls a `struct CommunicatorMessageContext` (unused)
5322 * @param ra the message that was received
5323 * @return #GNUNET_Ok if @a ra is well-formed
5326 check_reliability_ack (void *cls,
5327 const struct TransportReliabilityAckMessage *ra)
5329 unsigned int n_acks;
5332 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5333 sizeof (struct TransportCummulativeAckPayloadP);
5336 GNUNET_break_op (0);
5337 return GNUNET_SYSERR;
5339 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5340 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5342 GNUNET_break_op (0);
5343 return GNUNET_SYSERR;
5350 * Communicator gave us a reliability ack. Process the request.
5352 * @param cls a `struct CommunicatorMessageContext` (must call
5353 * #finish_cmc_handling() when done)
5354 * @param ra the message that was received
5357 handle_reliability_ack (void *cls,
5358 const struct TransportReliabilityAckMessage *ra)
5360 struct CommunicatorMessageContext *cmc = cls;
5361 const struct TransportCummulativeAckPayloadP *ack;
5362 struct PendingAcknowledgement *pa;
5363 unsigned int n_acks;
5364 uint32_t ack_counter;
5366 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5367 sizeof (struct TransportCummulativeAckPayloadP);
5368 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5369 for (unsigned int i = 0; i < n_acks; i++)
5372 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5375 GNUNET_STATISTICS_update (
5377 "# FRAGMENT_ACKS dropped, no matching pending message",
5382 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5385 ack_counter = htonl (ra->ack_counter);
5386 (void) ack_counter; /* silence compiler warning for now */
5387 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5388 // (DV and/or Neighbour?)
5389 finish_cmc_handling (cmc);
5394 * Communicator gave us a backchannel encapsulation. Check the message.
5396 * @param cls a `struct CommunicatorMessageContext`
5397 * @param be the send message that was sent
5398 * @return #GNUNET_YES if message is well-formed
5401 check_backchannel_encapsulation (
5403 const struct TransportBackchannelEncapsulationMessage *be)
5405 uint16_t size = ntohs (be->header.size);
5408 if ((size - sizeof (*be)) <
5409 (sizeof (struct TransportBackchannelRequestPayloadP) +
5410 sizeof (struct GNUNET_MessageHeader)))
5412 GNUNET_break_op (0);
5413 return GNUNET_SYSERR;
5420 * We received the plaintext @a msg from backtalker @a b. Forward
5421 * it to the respective communicator.
5423 * @param b a backtalker
5424 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5425 * followed by the target name of the communicator
5426 * @param msg_size number of bytes in @a msg
5429 forward_backchannel_payload (struct Backtalker *b,
5433 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5434 struct GNUNET_MQ_Envelope *env;
5435 struct TransportClient *tc;
5436 const struct GNUNET_MessageHeader *mh;
5437 const char *target_communicator;
5440 /* Determine target_communicator and check @a msg is well-formed */
5442 mhs = ntohs (mh->size);
5443 if (mhs <= msg_size)
5445 GNUNET_break_op (0);
5448 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5449 if ('\0' != target_communicator[msg_size - mhs - 1])
5451 GNUNET_break_op (0);
5454 /* Find client providing this communicator */
5455 for (tc = clients_head; NULL != tc; tc = tc->next)
5456 if ((CT_COMMUNICATOR == tc->type) &&
5458 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5466 "# Backchannel message dropped: target communicator `%s' unknown",
5467 target_communicator);
5468 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5469 GNUNET_free (stastr);
5472 /* Finally, deliver backchannel message to communicator */
5473 env = GNUNET_MQ_msg_extra (
5476 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5478 memcpy (&cbi[1], msg, msg_size);
5479 GNUNET_MQ_send (tc->mq, env);
5484 * Free data structures associated with @a b.
5486 * @param b data structure to release
5489 free_backtalker (struct Backtalker *b)
5493 GNUNET_PEERSTORE_iterate_cancel (b->get);
5495 GNUNET_assert (NULL != b->cmc);
5496 finish_cmc_handling (b->cmc);
5499 if (NULL != b->task)
5501 GNUNET_SCHEDULER_cancel (b->task);
5506 GNUNET_PEERSTORE_store_cancel (b->sc);
5511 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5517 * Callback to free backtalker records.
5521 * @param value a `struct Backtalker`
5522 * @return #GNUNET_OK (always)
5525 free_backtalker_cb (void *cls,
5526 const struct GNUNET_PeerIdentity *pid,
5529 struct Backtalker *b = value;
5533 free_backtalker (b);
5539 * Function called when it is time to clean up a backtalker.
5541 * @param cls a `struct Backtalker`
5544 backtalker_timeout_cb (void *cls)
5546 struct Backtalker *b = cls;
5549 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5551 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5554 GNUNET_assert (NULL == b->sc);
5555 free_backtalker (b);
5560 * Function called with the monotonic time of a backtalker
5561 * by PEERSTORE. Updates the time and continues processing.
5563 * @param cls a `struct Backtalker`
5564 * @param record the information found, NULL for the last call
5565 * @param emsg error message
5568 backtalker_monotime_cb (void *cls,
5569 const struct GNUNET_PEERSTORE_Record *record,
5572 struct Backtalker *b = cls;
5573 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5574 struct GNUNET_TIME_Absolute mt;
5579 /* we're done with #backtalker_monotime_cb() invocations,
5580 continue normal processing */
5582 GNUNET_assert (NULL != b->cmc);
5583 finish_cmc_handling (b->cmc);
5585 if (0 != b->body_size)
5586 forward_backchannel_payload (b, &b[1], b->body_size);
5589 if (sizeof (*mtbe) != record->value_size)
5594 mtbe = record->value;
5595 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5596 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5598 GNUNET_STATISTICS_update (
5600 "# Backchannel messages dropped: monotonic time not increasing",
5603 b->monotonic_time = mt;
5604 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5613 * Function called by PEERSTORE when the store operation of
5614 * a backtalker's monotonic time is complete.
5616 * @param cls the `struct Backtalker`
5617 * @param success #GNUNET_OK on success
5620 backtalker_monotime_store_cb (void *cls, int success)
5622 struct Backtalker *b = cls;
5624 if (GNUNET_OK != success)
5626 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5627 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5630 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5635 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5637 * @param b a backtalker with updated monotonic time
5640 update_backtalker_monotime (struct Backtalker *b)
5642 struct GNUNET_TIME_AbsoluteNBO mtbe;
5646 GNUNET_PEERSTORE_store_cancel (b->sc);
5651 GNUNET_SCHEDULER_cancel (b->task);
5654 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5656 GNUNET_PEERSTORE_store (peerstore,
5659 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5662 GNUNET_TIME_UNIT_FOREVER_ABS,
5663 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5664 &backtalker_monotime_store_cb,
5670 * Communicator gave us a backchannel encapsulation. Process the request.
5671 * (We are not the origin of the backchannel here, the communicator simply
5672 * received a backchannel message and we are expected to forward it.)
5674 * @param cls a `struct CommunicatorMessageContext` (must call
5675 * #finish_cmc_handling() when done)
5676 * @param be the message that was received
5679 handle_backchannel_encapsulation (
5681 const struct TransportBackchannelEncapsulationMessage *be)
5683 struct CommunicatorMessageContext *cmc = cls;
5684 struct BackchannelKeyState key;
5685 struct GNUNET_HashCode hmac;
5689 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5691 /* not for me, try to route to target */
5692 route_message (&be->target,
5693 GNUNET_copy_message (&be->header),
5695 finish_cmc_handling (cmc);
5698 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5699 hdr = (const char *) &be[1];
5700 hdr_len = ntohs (be->header.size) - sizeof (*be);
5701 bc_hmac (&key, &hmac, hdr, hdr_len);
5702 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5704 /* HMAC missmatch, disard! */
5705 GNUNET_break_op (0);
5706 finish_cmc_handling (cmc);
5709 /* begin actual decryption */
5711 struct Backtalker *b;
5712 struct GNUNET_TIME_Absolute monotime;
5713 struct TransportBackchannelRequestPayloadP ppay;
5714 char body[hdr_len - sizeof (ppay)];
5716 GNUNET_assert (hdr_len >=
5717 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5718 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5719 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5720 bc_key_clean (&key);
5721 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5722 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5723 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5725 GNUNET_STATISTICS_update (
5727 "# Backchannel messages dropped: monotonic time not increasing",
5730 finish_cmc_handling (cmc);
5734 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5736 /* Check signature */
5737 struct EphemeralConfirmationPS ec;
5739 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5740 ec.purpose.size = htonl (sizeof (ec));
5741 ec.target = GST_my_identity;
5742 ec.ephemeral_key = be->ephemeral_key;
5745 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5748 &ppay.sender.public_key))
5750 /* Signature invalid, disard! */
5751 GNUNET_break_op (0);
5752 finish_cmc_handling (cmc);
5758 /* update key cache and mono time */
5759 b->last_ephemeral = be->ephemeral_key;
5760 b->monotonic_time = monotime;
5761 update_backtalker_monotime (b);
5762 forward_backchannel_payload (b, body, sizeof (body));
5764 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5765 finish_cmc_handling (cmc);
5768 /* setup data structure to cache signature AND check
5769 monotonic time with PEERSTORE before forwarding backchannel payload */
5770 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5771 b->pid = ppay.sender;
5772 b->body_size = sizeof (body);
5773 memcpy (&b[1], body, sizeof (body));
5774 GNUNET_assert (GNUNET_YES ==
5775 GNUNET_CONTAINER_multipeermap_put (
5779 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5780 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5783 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5784 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5786 GNUNET_PEERSTORE_iterate (peerstore,
5789 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5790 &backtalker_monotime_cb,
5797 * Task called when we should check if any of the DV paths
5798 * we have learned to a target are due for garbage collection.
5800 * Collects stale paths, and possibly frees the entire DV
5801 * entry if no paths are left. Otherwise re-schedules itself.
5803 * @param cls a `struct DistanceVector`
5806 path_cleanup_cb (void *cls)
5808 struct DistanceVector *dv = cls;
5809 struct DistanceVectorHop *pos;
5811 dv->timeout_task = NULL;
5812 while (NULL != (pos = dv->dv_head))
5814 GNUNET_assert (dv == pos->dv);
5815 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5817 free_distance_vector_hop (pos);
5825 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5830 * The @a hop is a validated path to the respective target
5831 * peer and we should tell core about it -- and schedule
5832 * a job to revoke the state.
5834 * @param hop a path to some peer that is the reason for activation
5837 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5839 struct DistanceVector *dv = hop->dv;
5840 struct VirtualLink *vl;
5842 vl = GNUNET_CONTAINER_multipeermap_get (links, &dv->target);
5845 /* Link was already up, remember dv is also now available and we are done */
5849 vl = GNUNET_new (struct VirtualLink);
5850 vl->target = dv->target;
5852 vl->core_recv_window = RECV_WINDOW_SIZE;
5853 vl->visibility_task =
5854 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
5855 GNUNET_break (GNUNET_YES ==
5856 GNUNET_CONTAINER_multipeermap_put (
5860 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5861 /* We lacked a confirmed connection to the target
5862 before, so tell CORE about it (finally!) */
5863 cores_send_connect_info (&dv->target);
5868 * We have learned a @a path through the network to some other peer, add it to
5869 * our DV data structure (returning #GNUNET_YES on success).
5871 * We do not add paths if we have a sufficient number of shorter
5872 * paths to this target already (returning #GNUNET_NO).
5874 * We also do not add problematic paths, like those where we lack the first
5875 * hop in our neighbour list (i.e. due to a topology change) or where some
5876 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5878 * @param path the path we learned, path[0] should be us,
5879 * and then path contains a valid path from us to
5880 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
5881 * @param path_len number of entries on the @a path, at least three!
5882 * @param network_latency how long does the message take from us to
5883 * `path[path_len-1]`? set to "forever" if unknown
5884 * @param path_valid_until how long is this path considered validated? Maybe
5886 * @return #GNUNET_YES on success,
5887 * #GNUNET_NO if we have better path(s) to the target
5888 * #GNUNET_SYSERR if the path is useless and/or invalid
5889 * (i.e. path[1] not a direct neighbour
5890 * or path[i+1] is a direct neighbour for i>0)
5893 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5894 unsigned int path_len,
5895 struct GNUNET_TIME_Relative network_latency,
5896 struct GNUNET_TIME_Absolute path_valid_until)
5898 struct DistanceVectorHop *hop;
5899 struct DistanceVector *dv;
5900 struct Neighbour *next_hop;
5901 unsigned int shorter_distance;
5905 /* what a boring path! not allowed! */
5907 return GNUNET_SYSERR;
5909 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5910 next_hop = lookup_neighbour (&path[1]);
5911 if (NULL == next_hop)
5913 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5915 return GNUNET_SYSERR;
5917 for (unsigned int i = 2; i < path_len; i++)
5918 if (NULL != lookup_neighbour (&path[i]))
5920 /* Useless path, we have a direct connection to some hop
5921 in the middle of the path, so this one doesn't even
5922 seem terribly useful for redundancy */
5923 return GNUNET_SYSERR;
5925 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5928 dv = GNUNET_new (struct DistanceVector);
5929 dv->target = path[path_len - 1];
5930 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5933 GNUNET_assert (GNUNET_OK ==
5934 GNUNET_CONTAINER_multipeermap_put (
5938 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5940 /* Check if we have this path already! */
5941 shorter_distance = 0;
5942 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5945 if (pos->distance < path_len - 2)
5947 /* Note that the distances in 'pos' excludes us (path[0]) and
5948 the next_hop (path[1]), so we need to subtract two
5949 and check next_hop explicitly */
5950 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5952 int match = GNUNET_YES;
5954 for (unsigned int i = 0; i < pos->distance; i++)
5956 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5962 if (GNUNET_YES == match)
5964 struct GNUNET_TIME_Relative last_timeout;
5966 /* Re-discovered known path, update timeout */
5967 GNUNET_STATISTICS_update (GST_stats,
5968 "# Known DV path refreshed",
5971 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5973 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5974 pos->path_valid_until =
5975 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5976 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5977 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5979 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
5980 activate_core_visible_dv_path (pos);
5981 if (last_timeout.rel_value_us <
5982 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5983 DV_PATH_DISCOVERY_FREQUENCY)
5986 /* Some peer send DV learn messages too often, we are learning
5987 the same path faster than it would be useful; do not forward! */
5994 /* Count how many shorter paths we have (incl. direct
5995 neighbours) before simply giving up on this one! */
5996 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
5998 /* We have a shorter path already! */
6001 /* create new DV path entry */
6002 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6003 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6004 hop->next_hop = next_hop;
6006 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6009 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6010 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6011 hop->path_valid_until = path_valid_until;
6012 hop->distance = path_len - 2;
6013 hop->pd.aged_rtt = network_latency;
6014 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6015 GNUNET_CONTAINER_MDLL_insert (neighbour,
6019 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6020 activate_core_visible_dv_path (hop);
6026 * Communicator gave us a DV learn message. Check the message.
6028 * @param cls a `struct CommunicatorMessageContext`
6029 * @param dvl the send message that was sent
6030 * @return #GNUNET_YES if message is well-formed
6033 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6035 uint16_t size = ntohs (dvl->header.size);
6036 uint16_t num_hops = ntohs (dvl->num_hops);
6037 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6040 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6042 GNUNET_break_op (0);
6043 return GNUNET_SYSERR;
6045 if (num_hops > MAX_DV_HOPS_ALLOWED)
6047 GNUNET_break_op (0);
6048 return GNUNET_SYSERR;
6050 for (unsigned int i = 0; i < num_hops; i++)
6052 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6054 GNUNET_break_op (0);
6055 return GNUNET_SYSERR;
6057 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6059 GNUNET_break_op (0);
6060 return GNUNET_SYSERR;
6068 * Build and forward a DV learn message to @a next_hop.
6070 * @param next_hop peer to send the message to
6071 * @param msg message received
6072 * @param bi_history bitmask specifying hops on path that were bidirectional
6073 * @param nhops length of the @a hops array
6074 * @param hops path the message traversed so far
6075 * @param in_time when did we receive the message, used to calculate network
6079 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6080 const struct TransportDVLearnMessage *msg,
6081 uint16_t bi_history,
6083 const struct DVPathEntryP *hops,
6084 struct GNUNET_TIME_Absolute in_time)
6086 struct DVPathEntryP *dhops;
6087 struct TransportDVLearnMessage *fwd;
6088 struct GNUNET_TIME_Relative nnd;
6090 /* compute message for forwarding */
6091 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6092 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
6093 (nhops + 1) * sizeof (struct DVPathEntryP));
6094 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6095 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6096 (nhops + 1) * sizeof (struct DVPathEntryP));
6097 fwd->num_hops = htons (nhops + 1);
6098 fwd->bidirectional = htons (bi_history);
6099 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6100 GNUNET_TIME_relative_ntoh (
6101 msg->non_network_delay));
6102 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6103 fwd->init_sig = msg->init_sig;
6104 fwd->initiator = msg->initiator;
6105 fwd->challenge = msg->challenge;
6106 dhops = (struct DVPathEntryP *) &fwd[1];
6107 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6108 dhops[nhops].hop = GST_my_identity;
6110 struct DvHopPS dhp = {.purpose.purpose =
6111 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6112 .purpose.size = htonl (sizeof (dhp)),
6113 .pred = dhops[nhops - 1].hop,
6115 .challenge = msg->challenge};
6117 GNUNET_assert (GNUNET_OK ==
6118 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6120 &dhops[nhops].hop_sig));
6122 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6127 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6129 * @param sender_monotonic_time monotonic time of the initiator
6130 * @param init the signer
6131 * @param challenge the challenge that was signed
6132 * @param init_sig signature presumably by @a init
6133 * @return #GNUNET_OK if the signature is valid
6136 validate_dv_initiator_signature (
6137 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6138 const struct GNUNET_PeerIdentity *init,
6139 const struct ChallengeNonceP *challenge,
6140 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6142 struct DvInitPS ip = {.purpose.purpose = htonl (
6143 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6144 .purpose.size = htonl (sizeof (ip)),
6145 .monotonic_time = sender_monotonic_time,
6146 .challenge = *challenge};
6150 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6155 GNUNET_break_op (0);
6156 return GNUNET_SYSERR;
6163 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6165 struct NeighbourSelectionContext
6168 * Original message we received.
6170 const struct TransportDVLearnMessage *dvl;
6175 const struct DVPathEntryP *hops;
6178 * Time we received the message.
6180 struct GNUNET_TIME_Absolute in_time;
6183 * Offsets of the selected peers.
6185 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6188 * Number of peers eligible for selection.
6190 unsigned int num_eligible;
6193 * Number of peers that were selected for forwarding.
6195 unsigned int num_selections;
6198 * Number of hops in @e hops
6203 * Bitmap of bidirectional connections encountered.
6205 uint16_t bi_history;
6210 * Function called for each neighbour during #handle_dv_learn.
6212 * @param cls a `struct NeighbourSelectionContext *`
6213 * @param pid identity of the peer
6214 * @param value a `struct Neighbour`
6215 * @return #GNUNET_YES (always)
6218 dv_neighbour_selection (void *cls,
6219 const struct GNUNET_PeerIdentity *pid,
6222 struct NeighbourSelectionContext *nsc = cls;
6225 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6226 return GNUNET_YES; /* skip initiator */
6227 for (unsigned int i = 0; i < nsc->nhops; i++)
6228 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6229 return GNUNET_YES; /* skip peers on path */
6230 nsc->num_eligible++;
6236 * Function called for each neighbour during #handle_dv_learn.
6237 * We call #forward_dv_learn() on the neighbour(s) selected
6238 * during #dv_neighbour_selection().
6240 * @param cls a `struct NeighbourSelectionContext *`
6241 * @param pid identity of the peer
6242 * @param value a `struct Neighbour`
6243 * @return #GNUNET_YES (always)
6246 dv_neighbour_transmission (void *cls,
6247 const struct GNUNET_PeerIdentity *pid,
6250 struct NeighbourSelectionContext *nsc = cls;
6253 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6254 return GNUNET_YES; /* skip initiator */
6255 for (unsigned int i = 0; i < nsc->nhops; i++)
6256 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6257 return GNUNET_YES; /* skip peers on path */
6258 for (unsigned int i = 0; i < nsc->num_selections; i++)
6260 if (nsc->selections[i] == nsc->num_eligible)
6262 forward_dv_learn (pid,
6271 nsc->num_eligible++;
6277 * Computes the number of neighbours we should forward a DVInit
6278 * message to given that it has so far taken @a hops_taken hops
6279 * though the network and that the number of neighbours we have
6280 * in total is @a neighbour_count, out of which @a eligible_count
6281 * are not yet on the path.
6283 * NOTE: technically we might want to include NSE in the formula to
6284 * get a better grip on the overall network size. However, for now
6285 * using NSE here would create a dependency issue in the build system.
6286 * => Left for later, hardcoded to 50 for now.
6288 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6289 * peers via DV (`target_total`). We want the reach to be spread out
6290 * over various distances to the origin, with a bias towards shorter
6293 * We make the strong assumption that the network topology looks
6294 * "similar" at other hops, in particular the @a neighbour_count
6295 * should be comparable at other hops.
6297 * If the local neighbourhood is densely connected, we expect that @a
6298 * eligible_count is close to @a neighbour_count minus @a hops_taken
6299 * as a lot of the path is already known. In that case, we should
6300 * forward to few(er) peers to try to find a path out of the
6301 * neighbourhood. OTOH, if @a eligible_count is close to @a
6302 * neighbour_count, we should forward to many peers as we are either
6303 * still close to the origin (i.e. @a hops_taken is small) or because
6304 * we managed to get beyond a local cluster. We express this as
6305 * the `boost_factor` using the square of the fraction of eligible
6306 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6307 * 99% are eligible, the 'boost' will be almost 1).
6309 * Second, the more hops we have taken, the larger the problem of an
6310 * exponential traffic explosion gets. So we take the `target_total`,
6311 * and compute our degree such that at each distance d 2^{-d} peers
6312 * are selected (corrected by the `boost_factor`).
6314 * @param hops_taken number of hops DVInit has travelled so far
6315 * @param neighbour_count number of neighbours we have in total
6316 * @param eligible_count number of neighbours we could in
6320 calculate_fork_degree (unsigned int hops_taken,
6321 unsigned int neighbour_count,
6322 unsigned int eligible_count)
6324 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6325 double eligible_ratio =
6326 ((double) eligible_count) / ((double) neighbour_count);
6327 double boost_factor = eligible_ratio * eligible_ratio;
6331 if (hops_taken >= 64)
6332 return 0; /* precaution given bitshift below */
6333 for (unsigned int i = 1; i < hops_taken; i++)
6335 /* For each hop, subtract the expected number of targets
6336 reached at distance d (so what remains divided by 2^d) */
6337 target_total -= (target_total * boost_factor / (1LLU << i));
6340 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6341 /* round up or down probabilistically depending on how close we were
6342 when floor()ing to rnd */
6343 left = target_total - (double) rnd;
6344 if (UINT32_MAX * left >
6345 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6346 rnd++; /* round up */
6352 * Function called when peerstore is done storing a DV monotonic time.
6354 * @param cls a `struct Neighbour`
6355 * @param success #GNUNET_YES if peerstore was successful
6358 neighbour_store_dvmono_cb (void *cls, int success)
6360 struct Neighbour *n = cls;
6363 if (GNUNET_YES != success)
6364 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6365 "Failed to store other peer's monotonic time in peerstore!\n");
6370 * Communicator gave us a DV learn message. Process the request.
6372 * @param cls a `struct CommunicatorMessageContext` (must call
6373 * #finish_cmc_handling() when done)
6374 * @param dvl the message that was received
6377 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6379 struct CommunicatorMessageContext *cmc = cls;
6380 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6383 uint16_t bi_history;
6384 const struct DVPathEntryP *hops;
6387 struct GNUNET_TIME_Absolute in_time;
6388 struct Neighbour *n;
6390 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6391 bi_history = ntohs (dvl->bidirectional);
6392 hops = (const struct DVPathEntryP *) &dvl[1];
6396 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6399 finish_cmc_handling (cmc);
6406 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6409 finish_cmc_handling (cmc);
6414 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6415 cc = cmc->tc->details.communicator.cc;
6416 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6417 cc); // FIXME: add bi-directional flag to cc?
6418 in_time = GNUNET_TIME_absolute_get ();
6420 /* continue communicator here, everything else can happen asynchronous! */
6421 finish_cmc_handling (cmc);
6423 n = lookup_neighbour (&dvl->initiator);
6426 if ((n->dv_monotime_available == GNUNET_YES) &&
6427 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6428 n->last_dv_learn_monotime.abs_value_us))
6430 GNUNET_STATISTICS_update (GST_stats,
6431 "# DV learn discarded due to time travel",
6436 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6441 GNUNET_break_op (0);
6444 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6445 if (GNUNET_YES == n->dv_monotime_available)
6448 GNUNET_PEERSTORE_store_cancel (n->sc);
6450 GNUNET_PEERSTORE_store (peerstore,
6453 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6454 &dvl->monotonic_time,
6455 sizeof (dvl->monotonic_time),
6456 GNUNET_TIME_UNIT_FOREVER_ABS,
6457 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6458 &neighbour_store_dvmono_cb,
6462 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6463 If signature verification load too high, implement random drop strategy */
6464 for (unsigned int i = 0; i < nhops; i++)
6466 struct DvHopPS dhp = {.purpose.purpose =
6467 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6468 .purpose.size = htonl (sizeof (dhp)),
6469 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6470 .succ = (nhops - 1 == i) ? GST_my_identity
6472 .challenge = dvl->challenge};
6475 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6478 &hops[i].hop.public_key))
6480 GNUNET_break_op (0);
6485 do_fwd = GNUNET_YES;
6486 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6488 struct GNUNET_PeerIdentity path[nhops + 1];
6489 struct GNUNET_TIME_Relative host_latency_sum;
6490 struct GNUNET_TIME_Relative latency;
6491 struct GNUNET_TIME_Relative network_latency;
6493 /* We initiated this, learn the forward path! */
6494 path[0] = GST_my_identity;
6495 path[1] = hops[0].hop;
6496 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6498 // Need also something to lookup initiation time
6499 // to compute RTT! -> add RTT argument here?
6500 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6501 // (based on dvl->challenge, we can identify time of origin!)
6503 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6504 /* assumption: latency on all links is the same */
6505 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6507 for (unsigned int i = 2; i <= nhops; i++)
6509 struct GNUNET_TIME_Relative ilat;
6511 /* assumption: linear latency increase per hop */
6512 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6513 path[i] = hops[i - 1].hop;
6514 learn_dv_path (path,
6517 GNUNET_TIME_relative_to_absolute (
6518 ADDRESS_VALIDATION_LIFETIME));
6520 /* as we initiated, do not forward again (would be circular!) */
6526 /* last hop was bi-directional, we could learn something here! */
6527 struct GNUNET_PeerIdentity path[nhops + 2];
6529 path[0] = GST_my_identity;
6530 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6531 for (unsigned int i = 0; i < nhops; i++)
6535 if (0 == (bi_history & (1 << i)))
6536 break; /* i-th hop not bi-directional, stop learning! */
6539 path[i + 2] = dvl->initiator;
6543 path[i + 2] = hops[nhops - i - 2].hop;
6546 iret = learn_dv_path (path,
6548 GNUNET_TIME_UNIT_FOREVER_REL,
6549 GNUNET_TIME_UNIT_ZERO_ABS);
6550 if (GNUNET_SYSERR == iret)
6552 /* path invalid or too long to be interesting for US, thus should also
6553 not be interesting to our neighbours, cut path when forwarding to
6554 'i' hops, except of course for the one that goes back to the
6556 GNUNET_STATISTICS_update (GST_stats,
6557 "# DV learn not forwarded due invalidity of path",
6563 if ((GNUNET_NO == iret) && (nhops == i + 1))
6565 /* we have better paths, and this is the longest target,
6566 so there cannot be anything interesting later */
6567 GNUNET_STATISTICS_update (GST_stats,
6568 "# DV learn not forwarded, got better paths",
6577 if (MAX_DV_HOPS_ALLOWED == nhops)
6579 /* At limit, we're out of here! */
6580 finish_cmc_handling (cmc);
6584 /* Forward to initiator, if path non-trivial and possible */
6585 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6586 did_initiator = GNUNET_NO;
6589 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6591 /* send back to origin! */
6592 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6593 did_initiator = GNUNET_YES;
6595 /* We forward under two conditions: either we still learned something
6596 ourselves (do_fwd), or the path was darn short and thus the initiator is
6597 likely to still be very interested in this (and we did NOT already
6598 send it back to the initiator) */
6599 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6600 (GNUNET_NO == did_initiator)))
6602 /* Pick random neighbours that are not yet on the path */
6603 struct NeighbourSelectionContext nsc;
6606 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6609 nsc.bi_history = bi_history;
6611 nsc.in_time = in_time;
6612 nsc.num_eligible = 0;
6613 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6614 &dv_neighbour_selection,
6616 if (0 == nsc.num_eligible)
6617 return; /* done here, cannot forward to anyone else */
6618 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6619 nsc.num_selections =
6620 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6621 for (unsigned int i = 0; i < nsc.num_selections; i++)
6623 (nsc.num_selections == n_cnt)
6624 ? i /* all were selected, avoid collisions by chance */
6625 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6626 nsc.num_eligible = 0;
6627 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6628 &dv_neighbour_transmission,
6635 * Communicator gave us a DV box. Check the message.
6637 * @param cls a `struct CommunicatorMessageContext`
6638 * @param dvb the send message that was sent
6639 * @return #GNUNET_YES if message is well-formed
6642 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6644 uint16_t size = ntohs (dvb->header.size);
6645 uint16_t num_hops = ntohs (dvb->num_hops);
6646 const struct GNUNET_PeerIdentity *hops =
6647 (const struct GNUNET_PeerIdentity *) &dvb[1];
6648 const struct GNUNET_MessageHeader *inbox =
6649 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6654 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6655 sizeof (struct GNUNET_MessageHeader))
6657 GNUNET_break_op (0);
6658 return GNUNET_SYSERR;
6660 isize = ntohs (inbox->size);
6662 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6664 GNUNET_break_op (0);
6665 return GNUNET_SYSERR;
6667 itype = ntohs (inbox->type);
6668 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6669 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6671 GNUNET_break_op (0);
6672 return GNUNET_SYSERR;
6674 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6676 GNUNET_break_op (0);
6677 return GNUNET_SYSERR;
6684 * Create a DV Box message and queue it for transmission to
6687 * @param next_hop peer to receive the message next
6688 * @param total_hops how many hops did the message take so far
6689 * @param num_hops length of the @a hops array
6690 * @param origin origin of the message
6691 * @param hops next peer(s) to the destination, including destination
6692 * @param payload payload of the box
6693 * @param payload_size number of bytes in @a payload
6696 forward_dv_box (struct Neighbour *next_hop,
6697 uint16_t total_hops,
6699 const struct GNUNET_PeerIdentity *origin,
6700 const struct GNUNET_PeerIdentity *hops,
6701 const void *payload,
6702 uint16_t payload_size)
6704 struct TransportDVBoxMessage *dvb;
6706 dvb = create_dv_box (total_hops,
6708 &hops[num_hops - 1] /* == target */,
6709 num_hops - 1 /* do not count target twice */,
6713 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6719 * Communicator gave us a DV box. Process the request.
6721 * @param cls a `struct CommunicatorMessageContext` (must call
6722 * #finish_cmc_handling() when done)
6723 * @param dvb the message that was received
6726 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6728 struct CommunicatorMessageContext *cmc = cls;
6729 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6730 uint16_t num_hops = ntohs (dvb->num_hops);
6731 const struct GNUNET_PeerIdentity *hops =
6732 (const struct GNUNET_PeerIdentity *) &dvb[1];
6733 const struct GNUNET_MessageHeader *inbox =
6734 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6738 /* We're trying from the end of the hops array, as we may be
6739 able to find a shortcut unknown to the origin that way */
6740 for (int i = num_hops - 1; i >= 0; i--)
6742 struct Neighbour *n;
6744 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6746 GNUNET_break_op (0);
6747 finish_cmc_handling (cmc);
6750 n = lookup_neighbour (&hops[i]);
6754 ntohs (dvb->total_hops) + 1,
6755 num_hops - i - 1, /* number of hops left */
6757 &hops[i + 1], /* remaining hops */
6758 (const void *) &dvb[1],
6760 finish_cmc_handling (cmc);
6763 /* Woopsie, next hop not in neighbours, drop! */
6764 GNUNET_STATISTICS_update (GST_stats,
6765 "# DV Boxes dropped: next hop unknown",
6768 finish_cmc_handling (cmc);
6771 /* We are the target. Unbox and handle message. */
6772 cmc->im.sender = dvb->origin;
6773 cmc->total_hops = ntohs (dvb->total_hops);
6774 demultiplex_with_cmc (cmc, inbox);
6779 * Client notified us about transmission from a peer. Process the request.
6781 * @param cls a `struct TransportClient` which sent us the message
6782 * @param obm the send message that was sent
6783 * @return #GNUNET_YES if message is well-formed
6786 check_incoming_msg (void *cls,
6787 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6789 struct TransportClient *tc = cls;
6791 if (CT_COMMUNICATOR != tc->type)
6794 return GNUNET_SYSERR;
6796 GNUNET_MQ_check_boxed_message (im);
6802 * Communicator gave us a transport address validation challenge. Process the
6805 * @param cls a `struct CommunicatorMessageContext` (must call
6806 * #finish_cmc_handling() when done)
6807 * @param tvc the message that was received
6810 handle_validation_challenge (
6812 const struct TransportValidationChallengeMessage *tvc)
6814 struct CommunicatorMessageContext *cmc = cls;
6815 struct TransportValidationResponseMessage *tvr;
6817 if (cmc->total_hops > 0)
6819 /* DV routing is not allowed for validation challenges! */
6820 GNUNET_break_op (0);
6821 finish_cmc_handling (cmc);
6824 tvr = GNUNET_new (struct TransportValidationResponseMessage);
6826 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
6827 tvr->header.size = htons (sizeof (*tvr));
6828 tvr->challenge = tvc->challenge;
6829 tvr->origin_time = tvc->sender_time;
6830 tvr->validity_duration = cmc->im.expected_address_validity;
6832 /* create signature */
6833 struct TransportValidationPS tvp =
6834 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6835 .purpose.size = htonl (sizeof (tvp)),
6836 .validity_duration = tvr->validity_duration,
6837 .challenge = tvc->challenge};
6839 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6843 route_message (&cmc->im.sender,
6845 RMO_ANYTHING_GOES | RMO_REDUNDANT);
6846 finish_cmc_handling (cmc);
6851 * Closure for #check_known_challenge.
6853 struct CheckKnownChallengeContext
6856 * Set to the challenge we are looking for.
6858 const struct ChallengeNonceP *challenge;
6861 * Set to a matching validation state, if one was found.
6863 struct ValidationState *vs;
6868 * Test if the validation state in @a value matches the
6869 * challenge from @a cls.
6871 * @param cls a `struct CheckKnownChallengeContext`
6872 * @param pid unused (must match though)
6873 * @param value a `struct ValidationState`
6874 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6877 check_known_challenge (void *cls,
6878 const struct GNUNET_PeerIdentity *pid,
6881 struct CheckKnownChallengeContext *ckac = cls;
6882 struct ValidationState *vs = value;
6885 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
6893 * Function called when peerstore is done storing a
6894 * validated address.
6896 * @param cls a `struct ValidationState`
6897 * @param success #GNUNET_YES on success
6900 peerstore_store_validation_cb (void *cls, int success)
6902 struct ValidationState *vs = cls;
6905 if (GNUNET_YES == success)
6907 GNUNET_STATISTICS_update (GST_stats,
6908 "# Peerstore failed to store foreign address",
6915 * Task run periodically to validate some address based on #validation_heap.
6920 validation_start_cb (void *cls);
6924 * Set the time for next_challenge of @a vs to @a new_time.
6925 * Updates the heap and if necessary reschedules the job.
6927 * @param vs validation state to update
6928 * @param new_time new time for revalidation
6931 update_next_challenge_time (struct ValidationState *vs,
6932 struct GNUNET_TIME_Absolute new_time)
6934 struct GNUNET_TIME_Relative delta;
6936 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
6937 return; /* be lazy */
6938 vs->next_challenge = new_time;
6941 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
6943 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
6944 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
6945 (NULL != validation_task))
6947 if (NULL != validation_task)
6948 GNUNET_SCHEDULER_cancel (validation_task);
6949 /* randomize a bit */
6950 delta.rel_value_us =
6951 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6952 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
6953 new_time = GNUNET_TIME_absolute_add (new_time, delta);
6955 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
6960 * Find the queue matching @a pid and @a address.
6962 * @param pid peer the queue must go to
6963 * @param address address the queue must use
6964 * @return NULL if no such queue exists
6966 static struct Queue *
6967 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
6969 struct Neighbour *n;
6971 n = lookup_neighbour (pid);
6974 for (struct Queue *pos = n->queue_head; NULL != pos;
6975 pos = pos->next_neighbour)
6977 if (0 == strcmp (pos->address, address))
6985 * Communicator gave us a transport address validation response. Process the
6988 * @param cls a `struct CommunicatorMessageContext` (must call
6989 * #finish_cmc_handling() when done)
6990 * @param tvr the message that was received
6993 handle_validation_response (
6995 const struct TransportValidationResponseMessage *tvr)
6997 struct CommunicatorMessageContext *cmc = cls;
6998 struct ValidationState *vs;
6999 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7001 struct GNUNET_TIME_Absolute origin_time;
7003 struct Neighbour *n;
7004 struct VirtualLink *vl;
7006 /* check this is one of our challenges */
7007 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7009 &check_known_challenge,
7011 if (NULL == (vs = ckac.vs))
7013 /* This can happen simply if we 'forgot' the challenge by now,
7014 i.e. because we received the validation response twice */
7015 GNUNET_STATISTICS_update (GST_stats,
7016 "# Validations dropped, challenge unknown",
7019 finish_cmc_handling (cmc);
7023 /* sanity check on origin time */
7024 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7025 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7026 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7028 GNUNET_break_op (0);
7029 finish_cmc_handling (cmc);
7034 /* check signature */
7035 struct TransportValidationPS tvp =
7036 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7037 .purpose.size = htonl (sizeof (tvp)),
7038 .validity_duration = tvr->validity_duration,
7039 .challenge = tvr->challenge};
7043 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7046 &cmc->im.sender.public_key))
7048 GNUNET_break_op (0);
7049 finish_cmc_handling (cmc);
7054 /* validity is capped by our willingness to keep track of the
7055 validation entry and the maximum the other peer allows */
7056 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7057 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7058 tvr->validity_duration),
7059 MAX_ADDRESS_VALID_UNTIL));
7060 vs->validated_until =
7061 GNUNET_TIME_absolute_min (vs->valid_until,
7062 GNUNET_TIME_relative_to_absolute (
7063 ADDRESS_VALIDATION_LIFETIME));
7064 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7065 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7066 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7068 sizeof (vs->challenge));
7069 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7070 vs->validated_until,
7071 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7072 VALIDATION_RTT_BUFFER_FACTOR));
7073 vs->last_challenge_use =
7074 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7075 update_next_challenge_time (vs, vs->first_challenge_use);
7076 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7079 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7081 strlen (vs->address) + 1,
7083 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7084 &peerstore_store_validation_cb,
7086 finish_cmc_handling (cmc);
7088 /* Finally, we now possibly have a confirmed (!) working queue,
7089 update queue status (if queue still is around) */
7090 q = find_queue (&vs->pid, vs->address);
7093 GNUNET_STATISTICS_update (GST_stats,
7094 "# Queues lost at time of successful validation",
7099 q->validated_until = vs->validated_until;
7100 q->pd.aged_rtt = vs->validation_rtt;
7102 vl = GNUNET_CONTAINER_multipeermap_get (links, &vs->pid);
7105 /* Link was already up, remember n is also now available and we are done */
7109 vl = GNUNET_new (struct VirtualLink);
7110 vl->target = n->pid;
7112 vl->core_recv_window = RECV_WINDOW_SIZE;
7113 vl->visibility_task =
7114 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7115 GNUNET_break (GNUNET_YES ==
7116 GNUNET_CONTAINER_multipeermap_put (
7120 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7121 /* We lacked a confirmed connection to the target
7122 before, so tell CORE about it (finally!) */
7123 cores_send_connect_info (&n->pid);
7128 * Incoming meessage. Process the request.
7130 * @param im the send message that was received
7133 handle_incoming_msg (void *cls,
7134 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7136 struct TransportClient *tc = cls;
7137 struct CommunicatorMessageContext *cmc =
7138 GNUNET_new (struct CommunicatorMessageContext);
7142 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7147 * Given an inbound message @a msg from a communicator @a cmc,
7148 * demultiplex it based on the type calling the right handler.
7150 * @param cmc context for demultiplexing
7151 * @param msg message to demultiplex
7154 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7155 const struct GNUNET_MessageHeader *msg)
7157 struct GNUNET_MQ_MessageHandler handlers[] =
7158 {GNUNET_MQ_hd_var_size (fragment_box,
7159 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7160 struct TransportFragmentBoxMessage,
7162 GNUNET_MQ_hd_var_size (reliability_box,
7163 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7164 struct TransportReliabilityBoxMessage,
7166 GNUNET_MQ_hd_var_size (reliability_ack,
7167 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7168 struct TransportReliabilityAckMessage,
7170 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7171 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7172 struct TransportBackchannelEncapsulationMessage,
7174 GNUNET_MQ_hd_var_size (dv_learn,
7175 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7176 struct TransportDVLearnMessage,
7178 GNUNET_MQ_hd_var_size (dv_box,
7179 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7180 struct TransportDVBoxMessage,
7182 GNUNET_MQ_hd_fixed_size (
7183 validation_challenge,
7184 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7185 struct TransportValidationChallengeMessage,
7187 GNUNET_MQ_hd_fixed_size (
7188 validation_response,
7189 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7190 struct TransportValidationResponseMessage,
7192 GNUNET_MQ_handler_end ()};
7195 ret = GNUNET_MQ_handle_message (handlers, msg);
7196 if (GNUNET_SYSERR == ret)
7199 GNUNET_SERVICE_client_drop (cmc->tc->client);
7203 if (GNUNET_NO == ret)
7205 /* unencapsulated 'raw' message */
7206 handle_raw_message (&cmc, msg);
7212 * New queue became available. Check message.
7214 * @param cls the client
7215 * @param aqm the send message that was sent
7218 check_add_queue_message (void *cls,
7219 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7221 struct TransportClient *tc = cls;
7223 if (CT_COMMUNICATOR != tc->type)
7226 return GNUNET_SYSERR;
7228 GNUNET_MQ_check_zero_termination (aqm);
7234 * If necessary, generates the UUID for a @a pm
7236 * @param pm pending message to generate UUID for.
7239 set_pending_message_uuid (struct PendingMessage *pm)
7241 if (pm->msg_uuid_set)
7243 pm->msg_uuid.uuid = pm->target->message_uuid_ctr++;
7244 pm->msg_uuid_set = GNUNET_YES;
7249 * Setup data structure waiting for acknowledgements.
7251 * @param queue queue the @a pm will be sent over
7252 * @param dvh path the message will take, may be NULL
7253 * @param pm the pending message for transmission
7254 * @return corresponding fresh pending acknowledgement
7256 static struct PendingAcknowledgement *
7257 prepare_pending_acknowledgement (struct Queue *queue,
7258 struct DistanceVectorHop *dvh,
7259 struct PendingMessage *pm)
7261 struct PendingAcknowledgement *pa;
7263 pa = GNUNET_new (struct PendingAcknowledgement);
7269 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7271 sizeof (pa->ack_uuid));
7272 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7274 &pa->ack_uuid.value,
7276 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7277 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7278 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7280 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7281 pa->transmission_time = GNUNET_TIME_absolute_get ();
7282 pa->message_size = pm->bytes_msg;
7288 * Fragment the given @a pm to the given @a mtu. Adds
7289 * additional fragments to the neighbour as well. If the
7290 * @a mtu is too small, generates and error for the @a pm
7293 * @param queue which queue to fragment for
7294 * @param dvh path the message will take, or NULL
7295 * @param pm pending message to fragment for transmission
7296 * @return new message to transmit
7298 static struct PendingMessage *
7299 fragment_message (struct Queue *queue,
7300 struct DistanceVectorHop *dvh,
7301 struct PendingMessage *pm)
7303 struct PendingAcknowledgement *pa;
7304 struct PendingMessage *ff;
7307 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7308 mtu = (0 == queue->mtu)
7309 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7311 set_pending_message_uuid (pm);
7313 /* This invariant is established in #handle_add_queue_message() */
7314 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7316 /* select fragment for transmission, descending the tree if it has
7317 been expanded until we are at a leaf or at a fragment that is small
7321 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7322 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7324 ff = ff->head_frag; /* descent into fragmented fragments */
7327 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7329 /* Did not yet calculate all fragments, calculate next fragment */
7330 struct PendingMessage *frag;
7331 struct TransportFragmentBoxMessage tfb;
7339 orig = (const char *) &ff[1];
7340 msize = ff->bytes_msg;
7343 const struct TransportFragmentBoxMessage *tfbo;
7345 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7346 orig += sizeof (struct TransportFragmentBoxMessage);
7347 msize -= sizeof (struct TransportFragmentBoxMessage);
7348 xoff = ntohs (tfbo->frag_off);
7350 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7351 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7353 GNUNET_malloc (sizeof (struct PendingMessage) +
7354 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7355 frag->target = pm->target;
7356 frag->frag_parent = ff;
7357 frag->timeout = pm->timeout;
7358 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7359 frag->pmt = PMT_FRAGMENT_BOX;
7360 msg = (char *) &frag[1];
7361 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7363 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7364 tfb.ack_uuid = pa->ack_uuid;
7365 tfb.msg_uuid = pm->msg_uuid;
7366 tfb.frag_off = htons (ff->frag_off + xoff);
7367 tfb.msg_size = htons (pm->bytes_msg);
7368 memcpy (msg, &tfb, sizeof (tfb));
7369 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7370 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7371 ff->frag_off += fragsize;
7375 /* Move head to the tail and return it */
7376 GNUNET_CONTAINER_MDLL_remove (frag,
7377 ff->frag_parent->head_frag,
7378 ff->frag_parent->tail_frag,
7380 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7381 ff->frag_parent->head_frag,
7382 ff->frag_parent->tail_frag,
7389 * Reliability-box the given @a pm. On error (can there be any), NULL
7390 * may be returned, otherwise the "replacement" for @a pm (which
7391 * should then be added to the respective neighbour's queue instead of
7392 * @a pm). If the @a pm is already fragmented or reliability boxed,
7393 * or itself an ACK, this function simply returns @a pm.
7395 * @param queue which queue to prepare transmission for
7396 * @param dvh path the message will take, or NULL
7397 * @param pm pending message to box for transmission over unreliabile queue
7398 * @return new message to transmit
7400 static struct PendingMessage *
7401 reliability_box_message (struct Queue *queue,
7402 struct DistanceVectorHop *dvh,
7403 struct PendingMessage *pm)
7405 struct TransportReliabilityBoxMessage rbox;
7406 struct PendingAcknowledgement *pa;
7407 struct PendingMessage *bpm;
7410 if (PMT_CORE != pm->pmt)
7411 return pm; /* already fragmented or reliability boxed, or control message:
7413 if (NULL != pm->bpm)
7414 return pm->bpm; /* already computed earlier: do nothing */
7415 GNUNET_assert (NULL == pm->head_frag);
7416 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7420 client_send_response (pm);
7423 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7425 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7427 bpm->target = pm->target;
7428 bpm->frag_parent = pm;
7429 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7430 bpm->timeout = pm->timeout;
7431 bpm->pmt = PMT_RELIABILITY_BOX;
7432 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7433 set_pending_message_uuid (bpm);
7434 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7435 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7436 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7438 rbox.ack_uuid = pa->ack_uuid;
7439 msg = (char *) &bpm[1];
7440 memcpy (msg, &rbox, sizeof (rbox));
7441 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7448 * Change the value of the `next_attempt` field of @a pm
7449 * to @a next_attempt and re-order @a pm in the transmission
7450 * list as required by the new timestmap.
7452 * @param pm a pending message to update
7453 * @param next_attempt timestamp to use
7456 update_pm_next_attempt (struct PendingMessage *pm,
7457 struct GNUNET_TIME_Absolute next_attempt)
7459 struct Neighbour *neighbour = pm->target;
7461 pm->next_attempt = next_attempt;
7462 if (NULL == pm->frag_parent)
7464 struct PendingMessage *pos;
7466 /* re-insert sort in neighbour list */
7467 GNUNET_CONTAINER_MDLL_remove (neighbour,
7468 neighbour->pending_msg_head,
7469 neighbour->pending_msg_tail,
7471 pos = neighbour->pending_msg_tail;
7472 while ((NULL != pos) &&
7473 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7474 pos = pos->prev_neighbour;
7475 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7476 neighbour->pending_msg_head,
7477 neighbour->pending_msg_tail,
7483 /* re-insert sort in fragment list */
7484 struct PendingMessage *fp = pm->frag_parent;
7485 struct PendingMessage *pos;
7487 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7488 pos = fp->tail_frag;
7489 while ((NULL != pos) &&
7490 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7491 pos = pos->prev_frag;
7492 GNUNET_CONTAINER_MDLL_insert_after (frag,
7502 * We believe we are ready to transmit a message on a queue.
7503 * Gives the message to the
7504 * communicator for transmission (updating the tracker, and re-scheduling
7505 * itself if applicable).
7507 * @param cls the `struct Queue` to process transmissions for
7510 transmit_on_queue (void *cls)
7512 struct Queue *queue = cls;
7513 struct Neighbour *n = queue->neighbour;
7514 struct PendingMessage *pm;
7515 struct PendingMessage *s;
7518 queue->transmit_task = NULL;
7519 if (NULL == (pm = n->pending_msg_head))
7521 /* no message pending, nothing to do here! */
7526 /* message still pending with communciator!
7527 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7530 schedule_transmit_on_queue (queue, GNUNET_YES);
7531 if (NULL != queue->transmit_task)
7532 return; /* do it later */
7534 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7535 overhead += sizeof (struct TransportReliabilityBoxMessage);
7537 if ( ( (0 != queue->mtu) &&
7538 (pm->bytes_msg + overhead > queue->mtu) ) ||
7539 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7540 (NULL != pm->head_frag /* fragments already exist, should
7541 respect that even if MTU is 0 for
7543 s = fragment_message (queue, pm->dvh, s);
7546 /* Fragmentation failed, try next message... */
7547 schedule_transmit_on_queue (queue, GNUNET_NO);
7550 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7551 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7552 s = reliability_box_message (queue, pm->dvh, s);
7555 /* Reliability boxing failed, try next message... */
7556 schedule_transmit_on_queue (queue, GNUNET_NO);
7560 /* Pass 's' for transission to the communicator */
7561 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7562 // FIXME: do something similar to the logic below
7563 // in defragmentation / reliability ACK handling!
7565 /* Check if this transmission somehow conclusively finished handing 'pm'
7566 even without any explicit ACKs */
7567 if ((PMT_CORE == s->pmt) &&
7568 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7570 /* Full message sent, and over reliabile channel */
7571 client_send_response (pm);
7573 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7574 queue->tc->details.communicator.cc) &&
7575 (PMT_FRAGMENT_BOX == s->pmt))
7577 struct PendingMessage *pos;
7579 /* Fragment sent over reliabile channel */
7580 free_fragment_tree (s);
7581 pos = s->frag_parent;
7582 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7584 /* check if subtree is done */
7585 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7589 pos = s->frag_parent;
7590 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7594 /* Was this the last applicable fragmment? */
7595 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7596 client_send_response (pm);
7598 else if (PMT_CORE != pm->pmt)
7600 /* This was an acknowledgement of some type, always free */
7601 free_pending_message (pm);
7605 /* Message not finished, waiting for acknowledgement.
7606 Update time by which we might retransmit 's' based on queue
7607 characteristics (i.e. RTT); it takes one RTT for the message to
7608 arrive and the ACK to come back in the best case; but the other
7609 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7610 retransmitting. Note that in the future this heuristic should
7611 likely be improved further (measure RTT stability, consider
7612 message urgency and size when delaying ACKs, etc.) */
7613 update_pm_next_attempt (s,
7614 GNUNET_TIME_relative_to_absolute (
7615 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7619 /* finally, re-schedule queue transmission task itself */
7620 schedule_transmit_on_queue (queue, GNUNET_NO);
7625 * Queue to a peer went down. Process the request.
7627 * @param cls the client
7628 * @param dqm the send message that was sent
7631 handle_del_queue_message (void *cls,
7632 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7634 struct TransportClient *tc = cls;
7636 if (CT_COMMUNICATOR != tc->type)
7639 GNUNET_SERVICE_client_drop (tc->client);
7642 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7643 queue = queue->next_client)
7645 struct Neighbour *neighbour = queue->neighbour;
7647 if ((dqm->qid != queue->qid) ||
7648 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7651 GNUNET_SERVICE_client_continue (tc->client);
7655 GNUNET_SERVICE_client_drop (tc->client);
7660 * Message was transmitted. Process the request.
7662 * @param cls the client
7663 * @param sma the send message that was sent
7666 handle_send_message_ack (void *cls,
7667 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7669 struct TransportClient *tc = cls;
7670 struct QueueEntry *qe;
7671 struct PendingMessage *pm;
7673 if (CT_COMMUNICATOR != tc->type)
7676 GNUNET_SERVICE_client_drop (tc->client);
7680 /* find our queue entry matching the ACK */
7682 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7683 queue = queue->next_client)
7685 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7687 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7690 if (qep->mid != sma->mid)
7699 /* this should never happen */
7701 GNUNET_SERVICE_client_drop (tc->client);
7704 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7705 qe->queue->queue_tail,
7707 qe->queue->queue_length--;
7708 tc->details.communicator.total_queue_length--;
7709 GNUNET_SERVICE_client_continue (tc->client);
7711 /* if applicable, resume transmissions that waited on ACK */
7712 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7713 tc->details.communicator.total_queue_length)
7715 /* Communicator dropped below threshold, resume all queues
7716 incident with this client! */
7717 GNUNET_STATISTICS_update (
7719 "# Transmission throttled due to communicator queue limit",
7722 for (struct Queue *queue = tc->details.communicator.queue_head;
7724 queue = queue->next_client)
7725 schedule_transmit_on_queue (queue, GNUNET_NO);
7727 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7729 /* queue dropped below threshold; only resume this one queue */
7730 GNUNET_STATISTICS_update (GST_stats,
7731 "# Transmission throttled due to queue queue limit",
7734 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7737 if (NULL != (pm = qe->pm))
7739 struct Neighbour *n;
7741 GNUNET_assert (qe == pm->qe);
7743 /* If waiting for this communicator may have blocked transmission
7744 of pm on other queues for this neighbour, force schedule
7745 transmit on queue for queues of the neighbour */
7747 if (n->pending_msg_head == pm)
7749 for (struct Queue *queue = n->queue_head; NULL != queue;
7750 queue = queue->next_neighbour)
7751 schedule_transmit_on_queue (queue, GNUNET_NO);
7753 if (GNUNET_OK != ntohl (sma->status))
7756 GNUNET_ERROR_TYPE_INFO,
7757 "Queue failed in transmission, will try retransmission immediately\n");
7758 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7766 * Iterator telling new MONITOR client about all existing
7769 * @param cls the new `struct TransportClient`
7770 * @param pid a connected peer
7771 * @param value the `struct Neighbour` with more information
7772 * @return #GNUNET_OK (continue to iterate)
7775 notify_client_queues (void *cls,
7776 const struct GNUNET_PeerIdentity *pid,
7779 struct TransportClient *tc = cls;
7780 struct Neighbour *neighbour = value;
7782 GNUNET_assert (CT_MONITOR == tc->type);
7783 for (struct Queue *q = neighbour->queue_head; NULL != q;
7784 q = q->next_neighbour)
7786 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7788 .num_msg_pending = q->num_msg_pending,
7789 .num_bytes_pending = q->num_bytes_pending};
7791 notify_monitor (tc, pid, q->address, q->nt, &me);
7798 * Initialize a monitor client.
7800 * @param cls the client
7801 * @param start the start message that was sent
7804 handle_monitor_start (void *cls,
7805 const struct GNUNET_TRANSPORT_MonitorStart *start)
7807 struct TransportClient *tc = cls;
7809 if (CT_NONE != tc->type)
7812 GNUNET_SERVICE_client_drop (tc->client);
7815 tc->type = CT_MONITOR;
7816 tc->details.monitor.peer = start->peer;
7817 tc->details.monitor.one_shot = ntohl (start->one_shot);
7818 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
7819 GNUNET_SERVICE_client_mark_monitor (tc->client);
7820 GNUNET_SERVICE_client_continue (tc->client);
7825 * Find transport client providing communication service
7826 * for the protocol @a prefix.
7828 * @param prefix communicator name
7829 * @return NULL if no such transport client is available
7831 static struct TransportClient *
7832 lookup_communicator (const char *prefix)
7834 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7836 if (CT_COMMUNICATOR != tc->type)
7838 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
7842 GNUNET_ERROR_TYPE_WARNING,
7843 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
7850 * Signature of a function called with a communicator @a address of a peer
7851 * @a pid that an application wants us to connect to.
7853 * @param pid target peer
7854 * @param address the address to try
7857 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
7859 static uint32_t idgen;
7860 struct TransportClient *tc;
7862 struct GNUNET_TRANSPORT_CreateQueue *cqm;
7863 struct GNUNET_MQ_Envelope *env;
7866 prefix = GNUNET_HELLO_address_to_prefix (address);
7869 GNUNET_break (0); /* We got an invalid address!? */
7872 tc = lookup_communicator (prefix);
7875 GNUNET_STATISTICS_update (GST_stats,
7876 "# Suggestions ignored due to missing communicator",
7881 /* forward suggestion for queue creation to communicator */
7882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7883 "Request #%u for `%s' communicator to create queue to `%s'\n",
7884 (unsigned int) idgen,
7887 alen = strlen (address) + 1;
7889 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
7890 cqm->request_id = htonl (idgen++);
7891 cqm->receiver = *pid;
7892 memcpy (&cqm[1], address, alen);
7893 GNUNET_MQ_send (tc->mq, env);
7898 * The queue @a q (which matches the peer and address in @a vs) is
7899 * ready for queueing. We should now queue the validation request.
7901 * @param q queue to send on
7902 * @param vs state to derive validation challenge from
7905 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
7907 struct TransportValidationChallengeMessage tvc;
7909 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
7911 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
7912 tvc.header.size = htons (sizeof (tvc));
7913 tvc.reserved = htonl (0);
7914 tvc.challenge = vs->challenge;
7915 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
7916 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7921 * Task run periodically to validate some address based on #validation_heap.
7926 validation_start_cb (void *cls)
7928 struct ValidationState *vs;
7932 validation_task = NULL;
7933 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7934 /* drop validations past their expiration */
7937 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7939 free_validation_state (vs);
7940 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7943 return; /* woopsie, no more addresses known, should only
7944 happen if we're really a lonely peer */
7945 q = find_queue (&vs->pid, vs->address);
7948 vs->awaiting_queue = GNUNET_YES;
7949 suggest_to_connect (&vs->pid, vs->address);
7952 validation_transmit_on_queue (q, vs);
7953 /* Finally, reschedule next attempt */
7954 vs->challenge_backoff =
7955 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
7956 MAX_VALIDATION_CHALLENGE_FREQ);
7957 update_next_challenge_time (vs,
7958 GNUNET_TIME_relative_to_absolute (
7959 vs->challenge_backoff));
7964 * Closure for #check_connection_quality.
7966 struct QueueQualityContext
7969 * Set to the @e k'th queue encountered.
7974 * Set to the number of quality queues encountered.
7976 unsigned int quality_count;
7979 * Set to the total number of queues encountered.
7981 unsigned int num_queues;
7984 * Decremented for each queue, for selection of the
7985 * k-th queue in @e q.
7992 * Check whether any queue to the given neighbour is
7993 * of a good "quality" and if so, increment the counter.
7994 * Also counts the total number of queues, and returns
7995 * the k-th queue found.
7997 * @param cls a `struct QueueQualityContext *` with counters
7998 * @param pid peer this is about
7999 * @param value a `struct Neighbour`
8000 * @return #GNUNET_OK (continue to iterate)
8003 check_connection_quality (void *cls,
8004 const struct GNUNET_PeerIdentity *pid,
8007 struct QueueQualityContext *ctx = cls;
8008 struct Neighbour *n = value;
8013 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8018 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
8019 statistics and consider those as well here? */
8020 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
8021 do_inc = GNUNET_YES;
8023 if (GNUNET_YES == do_inc)
8024 ctx->quality_count++;
8030 * Task run when we CONSIDER initiating a DV learn
8031 * process. We first check that sending out a message is
8032 * even possible (queues exist), then that it is desirable
8033 * (if not, reschedule the task for later), and finally
8034 * we may then begin the job. If there are too many
8035 * entries in the #dvlearn_map, we purge the oldest entry
8041 start_dv_learn (void *cls)
8043 struct LearnLaunchEntry *lle;
8044 struct QueueQualityContext qqc;
8045 struct TransportDVLearnMessage dvl;
8048 dvlearn_task = NULL;
8049 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8050 return; /* lost all connectivity, cannot do learning */
8051 qqc.quality_count = 0;
8053 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8054 &check_connection_quality,
8056 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8058 struct GNUNET_TIME_Relative delay;
8059 unsigned int factor;
8061 /* scale our retries by how far we are above the threshold */
8062 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8063 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8064 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8067 /* remove old entries in #dvlearn_map if it has grown too big */
8068 while (MAX_DV_LEARN_PENDING >=
8069 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8072 GNUNET_assert (GNUNET_YES ==
8073 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8074 &lle->challenge.value,
8076 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8079 /* setup data structure for learning */
8080 lle = GNUNET_new (struct LearnLaunchEntry);
8081 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8083 sizeof (lle->challenge));
8084 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8085 GNUNET_break (GNUNET_YES ==
8086 GNUNET_CONTAINER_multishortmap_put (
8088 &lle->challenge.value,
8090 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8091 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8092 dvl.header.size = htons (sizeof (dvl));
8093 dvl.num_hops = htons (0);
8094 dvl.bidirectional = htons (0);
8095 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8096 dvl.monotonic_time =
8097 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8099 struct DvInitPS dvip = {.purpose.purpose = htonl (
8100 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8101 .purpose.size = htonl (sizeof (dvip)),
8102 .monotonic_time = dvl.monotonic_time,
8103 .challenge = lle->challenge};
8105 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8109 dvl.initiator = GST_my_identity;
8110 dvl.challenge = lle->challenge;
8112 qqc.quality_count = 0;
8113 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8116 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8117 &check_connection_quality,
8119 GNUNET_assert (NULL != qqc.q);
8121 /* Do this as close to transmission time as possible! */
8122 lle->launch_time = GNUNET_TIME_absolute_get ();
8124 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8125 /* reschedule this job, randomizing the time it runs (but no
8127 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8128 DV_LEARN_BASE_FREQUENCY),
8135 * A new queue has been created, check if any address validation
8136 * requests have been waiting for it.
8138 * @param cls a `struct Queue`
8139 * @param pid peer concerned (unused)
8140 * @param value a `struct ValidationState`
8141 * @return #GNUNET_NO if a match was found and we can stop looking
8144 check_validation_request_pending (void *cls,
8145 const struct GNUNET_PeerIdentity *pid,
8148 struct Queue *q = cls;
8149 struct ValidationState *vs = value;
8152 if ((GNUNET_YES == vs->awaiting_queue) &&
8153 (0 == strcmp (vs->address, q->address)))
8155 vs->awaiting_queue = GNUNET_NO;
8156 validation_transmit_on_queue (q, vs);
8164 * Function called with the monotonic time of a DV initiator
8165 * by PEERSTORE. Updates the time.
8167 * @param cls a `struct Neighbour`
8168 * @param record the information found, NULL for the last call
8169 * @param emsg error message
8172 neighbour_dv_monotime_cb (void *cls,
8173 const struct GNUNET_PEERSTORE_Record *record,
8176 struct Neighbour *n = cls;
8177 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8182 /* we're done with #neighbour_dv_monotime_cb() invocations,
8183 continue normal processing */
8185 n->dv_monotime_available = GNUNET_YES;
8188 if (sizeof (*mtbe) != record->value_size)
8193 mtbe = record->value;
8194 n->last_dv_learn_monotime =
8195 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8196 GNUNET_TIME_absolute_ntoh (*mtbe));
8201 * New queue became available. Process the request.
8203 * @param cls the client
8204 * @param aqm the send message that was sent
8207 handle_add_queue_message (void *cls,
8208 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8210 struct TransportClient *tc = cls;
8211 struct Queue *queue;
8212 struct Neighbour *neighbour;
8216 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8218 /* MTU so small as to be useless for transmissions,
8219 required for #fragment_message()! */
8220 GNUNET_break_op (0);
8221 GNUNET_SERVICE_client_drop (tc->client);
8224 neighbour = lookup_neighbour (&aqm->receiver);
8225 if (NULL == neighbour)
8227 neighbour = GNUNET_new (struct Neighbour);
8228 neighbour->message_uuid_ctr =
8229 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8230 neighbour->pid = aqm->receiver;
8231 GNUNET_assert (GNUNET_OK ==
8232 GNUNET_CONTAINER_multipeermap_put (
8236 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8238 GNUNET_PEERSTORE_iterate (peerstore,
8241 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8242 &neighbour_dv_monotime_cb,
8245 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8246 addr = (const char *) &aqm[1];
8248 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8250 queue->address = (const char *) &queue[1];
8251 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8252 queue->qid = aqm->qid;
8253 queue->mtu = ntohl (aqm->mtu);
8254 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8255 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8256 queue->neighbour = neighbour;
8257 memcpy (&queue[1], addr, addr_len);
8258 /* notify monitors about new queue */
8260 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8262 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8264 GNUNET_CONTAINER_MDLL_insert (neighbour,
8265 neighbour->queue_head,
8266 neighbour->queue_tail,
8268 GNUNET_CONTAINER_MDLL_insert (client,
8269 tc->details.communicator.queue_head,
8270 tc->details.communicator.queue_tail,
8272 /* check if valdiations are waiting for the queue */
8274 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8276 &check_validation_request_pending,
8278 /* might be our first queue, try launching DV learning */
8279 if (NULL == dvlearn_task)
8280 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8281 GNUNET_SERVICE_client_continue (tc->client);
8286 * Communicator tells us that our request to create a queue "worked", that
8287 * is setting up the queue is now in process.
8289 * @param cls the `struct TransportClient`
8290 * @param cqr confirmation message
8293 handle_queue_create_ok (void *cls,
8294 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8296 struct TransportClient *tc = cls;
8298 if (CT_COMMUNICATOR != tc->type)
8301 GNUNET_SERVICE_client_drop (tc->client);
8304 GNUNET_STATISTICS_update (GST_stats,
8305 "# Suggestions succeeded at communicator",
8308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8309 "Request #%u for communicator to create queue succeeded\n",
8310 (unsigned int) ntohs (cqr->request_id));
8311 GNUNET_SERVICE_client_continue (tc->client);
8316 * Communicator tells us that our request to create a queue failed. This
8317 * usually indicates that the provided address is simply invalid or that the
8318 * communicator's resources are exhausted.
8320 * @param cls the `struct TransportClient`
8321 * @param cqr failure message
8324 handle_queue_create_fail (
8326 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8328 struct TransportClient *tc = cls;
8330 if (CT_COMMUNICATOR != tc->type)
8333 GNUNET_SERVICE_client_drop (tc->client);
8336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8337 "Request #%u for communicator to create queue failed\n",
8338 (unsigned int) ntohs (cqr->request_id));
8339 GNUNET_STATISTICS_update (GST_stats,
8340 "# Suggestions failed in queue creation at communicator",
8343 GNUNET_SERVICE_client_continue (tc->client);
8348 * We have received a `struct ExpressPreferenceMessage` from an application
8351 * @param cls handle to the client
8352 * @param msg the start message
8355 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8357 struct TransportClient *tc = cls;
8358 struct PeerRequest *pr;
8360 if (CT_APPLICATION != tc->type)
8363 GNUNET_SERVICE_client_drop (tc->client);
8366 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8371 GNUNET_SERVICE_client_drop (tc->client);
8374 (void) stop_peer_request (tc, &pr->pid, pr);
8375 GNUNET_SERVICE_client_continue (tc->client);
8380 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8381 * messages. We do nothing here, real verification is done later.
8383 * @param cls a `struct TransportClient *`
8384 * @param msg message to verify
8385 * @return #GNUNET_OK
8388 check_address_consider_verify (
8390 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8399 * Closure for #check_known_address.
8401 struct CheckKnownAddressContext
8404 * Set to the address we are looking for.
8406 const char *address;
8409 * Set to a matching validation state, if one was found.
8411 struct ValidationState *vs;
8416 * Test if the validation state in @a value matches the
8417 * address from @a cls.
8419 * @param cls a `struct CheckKnownAddressContext`
8420 * @param pid unused (must match though)
8421 * @param value a `struct ValidationState`
8422 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8425 check_known_address (void *cls,
8426 const struct GNUNET_PeerIdentity *pid,
8429 struct CheckKnownAddressContext *ckac = cls;
8430 struct ValidationState *vs = value;
8433 if (0 != strcmp (vs->address, ckac->address))
8441 * Start address validation.
8443 * @param pid peer the @a address is for
8444 * @param address an address to reach @a pid (presumably)
8447 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8448 const char *address)
8450 struct GNUNET_TIME_Absolute now;
8451 struct ValidationState *vs;
8452 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8454 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8456 &check_known_address,
8458 if (NULL != (vs = ckac.vs))
8460 /* if 'vs' is not currently valid, we need to speed up retrying the
8462 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8464 /* reduce backoff as we got a fresh advertisement */
8465 vs->challenge_backoff =
8466 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8467 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8469 update_next_challenge_time (vs,
8470 GNUNET_TIME_relative_to_absolute (
8471 vs->challenge_backoff));
8475 now = GNUNET_TIME_absolute_get ();
8476 vs = GNUNET_new (struct ValidationState);
8479 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8480 vs->first_challenge_use = now;
8481 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8482 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8484 sizeof (vs->challenge));
8485 vs->address = GNUNET_strdup (address);
8486 GNUNET_assert (GNUNET_YES ==
8487 GNUNET_CONTAINER_multipeermap_put (
8491 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8492 update_next_challenge_time (vs, now);
8497 * Function called by PEERSTORE for each matching record.
8499 * @param cls closure
8500 * @param record peerstore record information
8501 * @param emsg error message, or NULL if no errors
8504 handle_hello (void *cls,
8505 const struct GNUNET_PEERSTORE_Record *record,
8508 struct PeerRequest *pr = cls;
8513 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8514 "Got failure from PEERSTORE: %s\n",
8518 val = record->value;
8519 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8524 start_address_validation (&pr->pid, (const char *) record->value);
8529 * We have received a `struct ExpressPreferenceMessage` from an application
8532 * @param cls handle to the client
8533 * @param msg the start message
8536 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8538 struct TransportClient *tc = cls;
8539 struct PeerRequest *pr;
8541 if (CT_NONE == tc->type)
8543 tc->type = CT_APPLICATION;
8544 tc->details.application.requests =
8545 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8547 if (CT_APPLICATION != tc->type)
8550 GNUNET_SERVICE_client_drop (tc->client);
8553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8554 "Client suggested we talk to %s with preference %d at rate %u\n",
8555 GNUNET_i2s (&msg->peer),
8556 (int) ntohl (msg->pk),
8557 (int) ntohl (msg->bw.value__));
8558 pr = GNUNET_new (struct PeerRequest);
8560 pr->pid = msg->peer;
8562 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
8563 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8564 tc->details.application.requests,
8567 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8571 GNUNET_SERVICE_client_drop (tc->client);
8574 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8577 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8580 GNUNET_SERVICE_client_continue (tc->client);
8585 * Given another peers address, consider checking it for validity
8586 * and then adding it to the Peerstore.
8588 * @param cls a `struct TransportClient`
8589 * @param hdr message containing the raw address data and
8590 * signature in the body, see #GNUNET_HELLO_extract_address()
8593 handle_address_consider_verify (
8595 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8597 struct TransportClient *tc = cls;
8599 enum GNUNET_NetworkType nt;
8600 struct GNUNET_TIME_Absolute mono_time;
8603 // OPTIMIZE-FIXME: checking that we know this address already should
8604 // be done BEFORE checking the signature => HELLO API change!
8605 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8608 GNUNET_HELLO_extract_address (&hdr[1],
8609 ntohs (hdr->header.size) - sizeof (*hdr),
8613 if (NULL == address)
8615 GNUNET_break_op (0);
8618 start_address_validation (&hdr->peer, address);
8619 GNUNET_free (address);
8620 GNUNET_SERVICE_client_continue (tc->client);
8625 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8628 * @param cls a `struct TransportClient *`
8629 * @param m message to verify
8630 * @return #GNUNET_OK on success
8633 check_request_hello_validation (void *cls,
8634 const struct RequestHelloValidationMessage *m)
8637 GNUNET_MQ_check_zero_termination (m);
8643 * A client encountered an address of another peer. Consider validating it,
8644 * and if validation succeeds, persist it to PEERSTORE.
8646 * @param cls a `struct TransportClient *`
8647 * @param m message to verify
8650 handle_request_hello_validation (void *cls,
8651 const struct RequestHelloValidationMessage *m)
8653 struct TransportClient *tc = cls;
8655 start_address_validation (&m->peer, (const char *) &m[1]);
8656 GNUNET_SERVICE_client_continue (tc->client);
8661 * Free neighbour entry.
8665 * @param value a `struct Neighbour`
8666 * @return #GNUNET_OK (always)
8669 free_neighbour_cb (void *cls,
8670 const struct GNUNET_PeerIdentity *pid,
8673 struct Neighbour *neighbour = value;
8677 GNUNET_break (0); // should this ever happen?
8678 free_neighbour (neighbour);
8685 * Free DV route entry.
8689 * @param value a `struct DistanceVector`
8690 * @return #GNUNET_OK (always)
8693 free_dv_routes_cb (void *cls,
8694 const struct GNUNET_PeerIdentity *pid,
8697 struct DistanceVector *dv = value;
8708 * Free ephemeral entry.
8712 * @param value a `struct EphemeralCacheEntry`
8713 * @return #GNUNET_OK (always)
8716 free_ephemeral_cb (void *cls,
8717 const struct GNUNET_PeerIdentity *pid,
8720 struct EphemeralCacheEntry *ece = value;
8724 free_ephemeral (ece);
8730 * Free validation state.
8734 * @param value a `struct ValidationState`
8735 * @return #GNUNET_OK (always)
8738 free_validation_state_cb (void *cls,
8739 const struct GNUNET_PeerIdentity *pid,
8742 struct ValidationState *vs = value;
8746 free_validation_state (vs);
8752 * Free pending acknowledgement.
8756 * @param value a `struct PendingAcknowledgement`
8757 * @return #GNUNET_OK (always)
8760 free_pending_ack_cb (void *cls,
8761 const struct GNUNET_ShortHashCode *key,
8764 struct PendingAcknowledgement *pa = value;
8768 free_pending_acknowledgement (pa);
8774 * Free acknowledgement cummulator.
8778 * @param value a `struct AcknowledgementCummulator`
8779 * @return #GNUNET_OK (always)
8782 free_ack_cummulator_cb (void *cls,
8783 const struct GNUNET_PeerIdentity *pid,
8786 struct AcknowledgementCummulator *ac = value;
8796 * Function called when the service shuts down. Unloads our plugins
8797 * and cancels pending validations.
8799 * @param cls closure, unused
8802 do_shutdown (void *cls)
8804 struct LearnLaunchEntry *lle;
8807 if (NULL != ephemeral_task)
8809 GNUNET_SCHEDULER_cancel (ephemeral_task);
8810 ephemeral_task = NULL;
8812 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
8813 if (NULL != peerstore)
8815 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
8818 if (NULL != GST_stats)
8820 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
8823 if (NULL != GST_my_private_key)
8825 GNUNET_free (GST_my_private_key);
8826 GST_my_private_key = NULL;
8828 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
8829 &free_ack_cummulator_cb,
8831 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
8832 ack_cummulators = NULL;
8833 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
8834 &free_pending_ack_cb,
8836 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
8837 pending_acks = NULL;
8838 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
8839 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
8841 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
8842 GNUNET_CONTAINER_multipeermap_destroy (links);
8844 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
8845 &free_backtalker_cb,
8847 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
8849 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
8850 &free_validation_state_cb,
8852 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
8853 validation_map = NULL;
8854 while (NULL != (lle = lle_head))
8856 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8859 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
8861 GNUNET_CONTAINER_heap_destroy (validation_heap);
8862 validation_heap = NULL;
8863 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
8864 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
8866 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
8869 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
8870 ephemeral_map = NULL;
8871 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
8872 ephemeral_heap = NULL;
8877 * Initiate transport service.
8879 * @param cls closure
8880 * @param c configuration to use
8881 * @param service the initialized service
8885 const struct GNUNET_CONFIGURATION_Handle *c,
8886 struct GNUNET_SERVICE_Handle *service)
8891 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
8893 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8894 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
8895 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
8896 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8897 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
8898 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8899 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
8901 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8902 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
8904 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8906 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8907 GST_my_private_key =
8908 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
8909 if (NULL == GST_my_private_key)
8912 GNUNET_ERROR_TYPE_ERROR,
8914 "Transport service is lacking key configuration settings. Exiting.\n"));
8915 GNUNET_SCHEDULER_shutdown ();
8918 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
8919 &GST_my_identity.public_key);
8920 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8921 "My identity is `%s'\n",
8922 GNUNET_i2s_full (&GST_my_identity));
8923 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
8924 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
8925 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
8926 if (NULL == peerstore)
8929 GNUNET_SCHEDULER_shutdown ();
8936 * Define "main" method using service macro.
8938 GNUNET_SERVICE_MAIN (
8940 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
8943 &client_disconnect_cb,
8945 /* communication with applications */
8946 GNUNET_MQ_hd_fixed_size (suggest,
8947 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
8948 struct ExpressPreferenceMessage,
8950 GNUNET_MQ_hd_fixed_size (suggest_cancel,
8951 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
8952 struct ExpressPreferenceMessage,
8954 GNUNET_MQ_hd_var_size (request_hello_validation,
8955 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
8956 struct RequestHelloValidationMessage,
8958 /* communication with core */
8959 GNUNET_MQ_hd_fixed_size (client_start,
8960 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
8961 struct StartMessage,
8963 GNUNET_MQ_hd_var_size (client_send,
8964 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
8965 struct OutboundMessage,
8967 GNUNET_MQ_hd_fixed_size (client_recv_ok,
8968 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
8969 struct RecvOkMessage,
8971 /* communication with communicators */
8972 GNUNET_MQ_hd_var_size (communicator_available,
8973 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
8974 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
8976 GNUNET_MQ_hd_var_size (communicator_backchannel,
8977 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
8978 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
8980 GNUNET_MQ_hd_var_size (add_address,
8981 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
8982 struct GNUNET_TRANSPORT_AddAddressMessage,
8984 GNUNET_MQ_hd_fixed_size (del_address,
8985 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
8986 struct GNUNET_TRANSPORT_DelAddressMessage,
8988 GNUNET_MQ_hd_var_size (incoming_msg,
8989 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
8990 struct GNUNET_TRANSPORT_IncomingMessage,
8992 GNUNET_MQ_hd_fixed_size (queue_create_ok,
8993 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
8994 struct GNUNET_TRANSPORT_CreateQueueResponse,
8996 GNUNET_MQ_hd_fixed_size (queue_create_fail,
8997 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
8998 struct GNUNET_TRANSPORT_CreateQueueResponse,
9000 GNUNET_MQ_hd_var_size (add_queue_message,
9001 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
9002 struct GNUNET_TRANSPORT_AddQueueMessage,
9004 GNUNET_MQ_hd_var_size (address_consider_verify,
9005 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
9006 struct GNUNET_TRANSPORT_AddressToVerify,
9008 GNUNET_MQ_hd_fixed_size (del_queue_message,
9009 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
9010 struct GNUNET_TRANSPORT_DelQueueMessage,
9012 GNUNET_MQ_hd_fixed_size (send_message_ack,
9013 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
9014 struct GNUNET_TRANSPORT_SendMessageToAck,
9016 /* communication with monitors */
9017 GNUNET_MQ_hd_fixed_size (monitor_start,
9018 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
9019 struct GNUNET_TRANSPORT_MonitorStart,
9021 GNUNET_MQ_handler_end ());
9024 /* end of file gnunet-service-transport.c */