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 (beyond line ~7500)
28 * - properly encrypt *all* DV traffic, not only backchannel;
29 * rename BackchannelEncapsulation logic to DVEncapsulation!
30 * - realize transport-to-transport flow control (needed in case
31 * communicators do not offer flow control). Note that we may not
32 * want to simply delay the ACKs as that may cause unnecessary
33 * re-transmissions. => Introduce proper flow and congestion window(s)!
34 * - review retransmission logic, right now there is no smartness there!
35 * => congestion control, flow control, etc [PERFORMANCE-BASICS]
38 * - When forwarding DV learn messages, if a peer is reached that
39 * has a *bidirectional* link to the origin beyond 1st hop,
40 * do NOT forward it to peers _other_ than the origin, as
41 * there is clearly a better path directly from the origin to
42 * whatever else we could reach.
43 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
44 * => Need 128 bit hash map though! [BANDWIDTH, MEMORY]
45 * - queue_send_msg and route_message both by API design have to make copies
46 * of the payload, and route_message on top of that requires a malloc/free.
47 * Change design to approximate "zero" copy better... [CPU]
48 * - could avoid copying body of message into each fragment and keep
49 * fragments as just pointers into the original message and only
50 * fully build fragments just before transmission (optimization, should
51 * reduce CPU and memory use) [CPU, MEMORY]
52 * - if messages are below MTU, consider adding ACKs and other stuff
53 * to the same transmission to avoid tiny messages (requires planning at
54 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
55 * - When we passively learned DV (with unconfirmed freshness), we
56 * right now add the path to our list but with a zero path_valid_until
57 * time and only use it for unconfirmed routes. However, we could consider
58 * triggering an explicit validation mechansim ourselves, specifically routing
59 * a challenge-response message over the path [ROUTING]
60 * - Track ACK losses based on ACK-counter [ROUTING]
62 * Design realizations / discussion:
63 * - communicators do flow control by calling MQ "notify sent"
64 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
65 * or explicitly via backchannel FC ACKs. As long as the
66 * channel is not full, they may 'notify sent' even if the other
67 * peer has not yet confirmed receipt. The other peer confirming
68 * is _only_ for FC, not for more reliable transmission; reliable
69 * transmission (i.e. of fragments) is left to _transport_.
70 * - ACKs sent back in uni-directional communicators are done via
71 * the background channel API; here transport _may_ initially
72 * broadcast (with bounded # hops) if no path is known;
73 * - transport should _integrate_ DV-routing and build a view of
74 * the network; then background channel traffic can be
75 * routed via DV as well as explicit "DV" traffic.
76 * - background channel is also used for ACKs and NAT traversal support
77 * - transport service is responsible for AEAD'ing the background
78 * channel, timestamps and monotonic time are used against replay
79 * of old messages -> peerstore needs to be supplied with
80 * "latest timestamps seen" data
81 * - if transport implements DV, we likely need a 3rd peermap
82 * in addition to ephemerals and (direct) neighbours
83 * ==> check if stuff needs to be moved out of "Neighbour"
84 * - transport should encapsualte core-level messages and do its
85 * own ACKing for RTT/goodput/loss measurements _and_ fragment
89 #include "gnunet_util_lib.h"
90 #include "gnunet_statistics_service.h"
91 #include "gnunet_transport_monitor_service.h"
92 #include "gnunet_peerstore_service.h"
93 #include "gnunet_hello_lib.h"
94 #include "gnunet_signatures.h"
95 #include "transport.h"
98 * Maximum number of messages we acknowledge together in one
99 * cummulative ACK. Larger values may save a bit of bandwidth.
101 #define MAX_CUMMULATIVE_ACKS 64
104 * What is the size we assume for a read operation in the
105 * absence of an MTU for the purpose of flow control?
107 #define IN_PACKET_SIZE_WITHOUT_MTU 128
110 * Number of slots we keep of historic data for computation of
111 * goodput / message loss ratio.
113 #define GOODPUT_AGING_SLOTS 4
116 * Maximum number of peers we select for forwarding DVInit
117 * messages at the same time (excluding initiator).
119 #define MAX_DV_DISCOVERY_SELECTION 16
122 * Window size. How many messages to the same target do we pass
123 * to CORE without a RECV_OK in between? Small values limit
124 * thoughput, large values will increase latency.
126 * FIXME-OPTIMIZE: find out what good values are experimentally,
127 * maybe set adaptively (i.e. to observed available bandwidth).
129 #define RECV_WINDOW_SIZE 4
132 * Minimum number of hops we should forward DV learn messages
133 * even if they are NOT useful for us in hope of looping
134 * back to the initiator?
136 * FIXME: allow initiator some control here instead?
138 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
141 * Maximum DV distance allowed ever.
143 #define MAX_DV_HOPS_ALLOWED 16
146 * Maximum number of DV learning activities we may
147 * have pending at the same time.
149 #define MAX_DV_LEARN_PENDING 64
152 * Maximum number of DV paths we keep simultaneously to the same target.
154 #define MAX_DV_PATHS_TO_TARGET 3
157 * If a queue delays the next message by more than this number
158 * of seconds we log a warning. Note: this is for testing,
159 * the value chosen here might be too aggressively low!
161 #define DELAY_WARN_THRESHOLD \
162 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
165 * We only consider queues as "quality" connections when
166 * suppressing the generation of DV initiation messages if
167 * the latency of the queue is below this threshold.
169 #define DV_QUALITY_RTT_THRESHOLD \
170 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
173 * How long do we consider a DV path valid if we see no
174 * further updates on it? Note: the value chosen here might be too low!
176 #define DV_PATH_VALIDITY_TIMEOUT \
177 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
180 * How long do we cache backchannel (struct Backtalker) information
181 * after a backchannel goes inactive?
183 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
184 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
187 * How long before paths expire would we like to (re)discover DV paths? Should
188 * be below #DV_PATH_VALIDITY_TIMEOUT.
190 #define DV_PATH_DISCOVERY_FREQUENCY \
191 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
194 * How long are ephemeral keys valid?
196 #define EPHEMERAL_VALIDITY \
197 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
200 * How long do we keep partially reassembled messages around before giving up?
202 #define REASSEMBLY_EXPIRATION \
203 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
206 * What is the fastest rate at which we send challenges *if* we keep learning
207 * an address (gossip, DHT, etc.)?
209 #define FAST_VALIDATION_CHALLENGE_FREQ \
210 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
213 * What is the slowest rate at which we send challenges?
215 #define MAX_VALIDATION_CHALLENGE_FREQ \
216 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
219 * How long until we forget about historic accumulators and thus
220 * reset the ACK counter? Should exceed the maximum time an
221 * active connection experiences without an ACK.
223 #define ACK_CUMMULATOR_TIMEOUT \
224 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
227 * What is the non-randomized base frequency at which we
228 * would initiate DV learn messages?
230 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
233 * How many good connections (confirmed, bi-directional, not DV)
234 * do we need to have to suppress initiating DV learn messages?
236 #define DV_LEARN_QUALITY_THRESHOLD 100
239 * When do we forget an invalid address for sure?
241 #define MAX_ADDRESS_VALID_UNTIL \
242 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
245 * How long do we consider an address valid if we just checked?
247 #define ADDRESS_VALIDATION_LIFETIME \
248 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
251 * What is the maximum frequency at which we do address validation?
252 * A random value between 0 and this value is added when scheduling
253 * the #validation_task (both to ensure we do not validate too often,
254 * and to randomize a bit).
256 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
259 * How many network RTTs before an address validation expires should we begin
260 * trying to revalidate? (Note that the RTT used here is the one that we
261 * experienced during the last validation, not necessarily the latest RTT
264 #define VALIDATION_RTT_BUFFER_FACTOR 3
267 * How many messages can we have pending for a given communicator
268 * process before we start to throttle that communicator?
270 * Used if a communicator might be CPU-bound and cannot handle the traffic.
272 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
275 * How many messages can we have pending for a given queue (queue to
276 * a particular peer via a communicator) process before we start to
277 * throttle that queue?
279 #define QUEUE_LENGTH_LIMIT 32
282 GNUNET_NETWORK_STRUCT_BEGIN
285 * Unique identifier we attach to a message.
290 * Unique value, generated by incrementing the
291 * `message_uuid_ctr` of `struct Neighbour`.
293 uint64_t uuid GNUNET_PACKED;
298 * Unique identifier to map an acknowledgement to a transmission.
300 struct AcknowledgementUUIDP
303 * The UUID value. Not actually a hash, but a random value.
305 struct GNUNET_ShortHashCode value;
310 * Type of a nonce used for challenges.
312 struct ChallengeNonceP
315 * The value of the nonce. Note that this is NOT a hash.
317 struct GNUNET_ShortHashCode value;
322 * Outer layer of an encapsulated backchannel message.
324 struct TransportBackchannelEncapsulationMessage
327 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
329 struct GNUNET_MessageHeader header;
332 * Reserved, always zero.
334 uint32_t reserved GNUNET_PACKED;
337 * Target's peer identity (as backchannels may be transmitted
338 * indirectly, or even be broadcast).
340 struct GNUNET_PeerIdentity target;
343 * Ephemeral key setup by the sender for @e target, used
344 * to encrypt the payload.
346 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
349 * We use an IV here as the @e ephemeral_key is re-used for
350 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
352 struct GNUNET_ShortHashCode iv;
355 * HMAC over the ciphertext of the encrypted, variable-size
356 * body that follows. Verified via DH of @e target and
359 struct GNUNET_HashCode hmac;
361 /* Followed by encrypted, variable-size payload */
366 * Body by which a peer confirms that it is using an ephemeral key.
368 struct EphemeralConfirmationPS
372 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
374 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
377 * How long is this signature over the ephemeral key valid?
379 * Note that the receiver MUST IGNORE the absolute time, and only interpret
380 * the value as a mononic time and reject "older" values than the last one
381 * observed. This is necessary as we do not want to require synchronized
382 * clocks and may not have a bidirectional communication channel.
384 * Even with this, there is no real guarantee against replay achieved here,
385 * unless the latest timestamp is persisted. While persistence should be
386 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
387 * communicators must protect against replay attacks when using backchannel
390 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
393 * Target's peer identity.
395 struct GNUNET_PeerIdentity target;
398 * Ephemeral key setup by the sender for @e target, used
399 * to encrypt the payload.
401 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
406 * Plaintext of the variable-size payload that is encrypted
407 * within a `struct TransportBackchannelEncapsulationMessage`
409 struct TransportBackchannelRequestPayloadP
413 * Sender's peer identity.
415 struct GNUNET_PeerIdentity sender;
418 * Signature of the sender over an
419 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
421 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
424 * Current monotonic time of the sending transport service. Used to
425 * detect replayed messages. Note that the receiver should remember
426 * a list of the recently seen timestamps and only reject messages
427 * if the timestamp is in the list, or the list is "full" and the
428 * timestamp is smaller than the lowest in the list.
430 * Like the @e ephemeral_validity, the list of timestamps per peer should be
431 * persisted to guard against replays after restarts.
433 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
435 /* Followed by a `struct GNUNET_MessageHeader` with a message
436 for a communicator */
438 /* Followed by a 0-termianted string specifying the name of
439 the communicator which is to receive the message */
444 * Outer layer of an encapsulated unfragmented application message sent
445 * over an unreliable channel.
447 struct TransportReliabilityBoxMessage
450 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
452 struct GNUNET_MessageHeader header;
455 * Number of messages still to be sent before a commulative
456 * ACK is requested. Zero if an ACK is requested immediately.
457 * In NBO. Note that the receiver may send the ACK faster
458 * if it believes that is reasonable.
460 uint32_t ack_countdown GNUNET_PACKED;
463 * Unique ID of the message used for signalling receipt of
464 * messages sent over possibly unreliable channels. Should
467 struct AcknowledgementUUIDP ack_uuid;
472 * Acknowledgement payload.
474 struct TransportCummulativeAckPayloadP
477 * How long was the ACK delayed for generating cummulative ACKs?
478 * Used to calculate the correct network RTT by taking the receipt
479 * time of the ack minus the transmission time of the sender minus
482 struct GNUNET_TIME_RelativeNBO ack_delay;
485 * UUID of a message being acknowledged.
487 struct AcknowledgementUUIDP ack_uuid;
492 * Confirmation that the receiver got a
493 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
494 * confirmation may be transmitted over a completely different queue,
495 * so ACKs are identified by a combination of PID of sender and
496 * message UUID, without the queue playing any role!
498 struct TransportReliabilityAckMessage
501 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
503 struct GNUNET_MessageHeader header;
506 * Counter of ACKs transmitted by the sender to us. Incremented
507 * by one for each ACK, used to detect how many ACKs were lost.
509 uint32_t ack_counter GNUNET_PACKED;
511 /* followed by any number of `struct TransportCummulativeAckPayloadP`
512 messages providing ACKs */
517 * Outer layer of an encapsulated fragmented application message.
519 struct TransportFragmentBoxMessage
522 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
524 struct GNUNET_MessageHeader header;
527 * Offset of this fragment in the overall message.
529 uint16_t frag_off GNUNET_PACKED;
532 * Total size of the message that is being fragmented.
534 uint16_t msg_size GNUNET_PACKED;
537 * Unique ID of this fragment (and fragment transmission!). Will
538 * change even if a fragement is retransmitted to make each
539 * transmission attempt unique! If a client receives a duplicate
540 * fragment (same @e frag_off for same @a msg_uuid, it must send
541 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
543 struct AcknowledgementUUIDP ack_uuid;
546 * Original message ID for of the message that all the fragments
547 * belong to. Must be the same for all fragments.
549 struct MessageUUIDP msg_uuid;
554 * Content signed by the initator during DV learning.
556 * The signature is required to prevent DDoS attacks. A peer sending out this
557 * message is potentially generating a lot of traffic that will go back to the
558 * initator, as peers receiving this message will try to let the initiator
559 * know that they got the message.
561 * Without this signature, an attacker could abuse this mechanism for traffic
562 * amplification, sending a lot of traffic to a peer by putting out this type
563 * of message with the victim's peer identity.
565 * Even with just a signature, traffic amplification would be possible via
566 * replay attacks. The @e monotonic_time limits such replay attacks, as every
567 * potential amplificator will check the @e monotonic_time and only respond
568 * (at most) once per message.
573 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
575 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
578 * Time at the initiator when generating the signature.
580 * Note that the receiver MUST IGNORE the absolute time, and only interpret
581 * the value as a mononic time and reject "older" values than the last one
582 * observed. This is necessary as we do not want to require synchronized
583 * clocks and may not have a bidirectional communication channel.
585 * Even with this, there is no real guarantee against replay achieved here,
586 * unless the latest timestamp is persisted. Persistence should be
587 * provided via PEERSTORE if possible.
589 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
592 * Challenge value used by the initiator to re-identify the path.
594 struct ChallengeNonceP challenge;
599 * Content signed by each peer during DV learning.
601 * This assues the initiator of the DV learning operation that the hop from @e
602 * pred via the signing peer to @e succ actually exists. This makes it
603 * impossible for an adversary to supply the network with bogus routes.
605 * The @e challenge is included to provide replay protection for the
606 * initiator. This way, the initiator knows that the hop existed after the
607 * original @e challenge was first transmitted, providing a freshness metric.
609 * Peers other than the initiator that passively learn paths by observing
610 * these messages do NOT benefit from this. Here, an adversary may indeed
611 * replay old messages. Thus, passively learned paths should always be
612 * immediately marked as "potentially stale".
617 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
619 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
622 * Identity of the previous peer on the path.
624 struct GNUNET_PeerIdentity pred;
627 * Identity of the next peer on the path.
629 struct GNUNET_PeerIdentity succ;
632 * Challenge value used by the initiator to re-identify the path.
634 struct ChallengeNonceP challenge;
639 * An entry describing a peer on a path in a
640 * `struct TransportDVLearnMessage` message.
645 * Identity of a peer on the path.
647 struct GNUNET_PeerIdentity hop;
650 * Signature of this hop over the path, of purpose
651 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
653 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
658 * Internal message used by transport for distance vector learning.
659 * If @e num_hops does not exceed the threshold, peers should append
660 * themselves to the peer list and flood the message (possibly only
661 * to a subset of their neighbours to limit discoverability of the
662 * network topology). To the extend that the @e bidirectional bits
663 * are set, peers may learn the inverse paths even if they did not
666 * Unless received on a bidirectional queue and @e num_hops just
667 * zero, peers that can forward to the initator should always try to
668 * forward to the initiator.
670 struct TransportDVLearnMessage
673 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
675 struct GNUNET_MessageHeader header;
678 * Number of hops this messages has travelled, in NBO. Zero if
681 uint16_t num_hops GNUNET_PACKED;
684 * Bitmask of the last 16 hops indicating whether they are confirmed
685 * available (without DV) in both directions or not, in NBO. Used
686 * to possibly instantly learn a path in both directions. Each peer
687 * should shift this value by one to the left, and then set the
688 * lowest bit IF the current sender can be reached from it (without
691 uint16_t bidirectional GNUNET_PACKED;
694 * Peers receiving this message and delaying forwarding to other
695 * peers for any reason should increment this value by the non-network
696 * delay created by the peer.
698 struct GNUNET_TIME_RelativeNBO non_network_delay;
701 * Time at the initiator when generating the signature.
703 * Note that the receiver MUST IGNORE the absolute time, and only interpret
704 * the value as a mononic time and reject "older" values than the last one
705 * observed. This is necessary as we do not want to require synchronized
706 * clocks and may not have a bidirectional communication channel.
708 * Even with this, there is no real guarantee against replay achieved here,
709 * unless the latest timestamp is persisted. Persistence should be
710 * provided via PEERSTORE if possible.
712 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
715 * Signature of this hop over the path, of purpose
716 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
718 struct GNUNET_CRYPTO_EddsaSignature init_sig;
721 * Identity of the peer that started this learning activity.
723 struct GNUNET_PeerIdentity initiator;
726 * Challenge value used by the initiator to re-identify the path.
728 struct ChallengeNonceP challenge;
730 /* Followed by @e num_hops `struct DVPathEntryP` values,
731 excluding the initiator of the DV trace; the last entry is the
732 current sender; the current peer must not be included. */
737 * Outer layer of an encapsulated message send over multiple hops.
738 * The path given only includes the identities of the subsequent
739 * peers, i.e. it will be empty if we are the receiver. Each
740 * forwarding peer should scan the list from the end, and if it can,
741 * forward to the respective peer. The list should then be shortened
742 * by all the entries up to and including that peer. Each hop should
743 * also increment @e total_hops to allow the receiver to get a precise
744 * estimate on the number of hops the message travelled. Senders must
745 * provide a learned path that thus should work, but intermediaries
746 * know of a shortcut, they are allowed to send the message via that
749 * If a peer finds itself still on the list, it must drop the message.
751 struct TransportDVBoxMessage
754 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
756 struct GNUNET_MessageHeader header;
759 * Number of total hops this messages travelled. In NBO.
760 * @e origin sets this to zero, to be incremented at
763 uint16_t total_hops GNUNET_PACKED;
766 * Number of hops this messages includes. In NBO.
768 uint16_t num_hops GNUNET_PACKED;
771 * Identity of the peer that originated the message.
773 struct GNUNET_PeerIdentity origin;
775 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
776 excluding the @e origin and the current peer, the last must be
777 the ultimate target; if @e num_hops is zero, the receiver of this
778 message is the ultimate target. */
780 /* Followed by the actual message, which itself may be
781 another box, but not a DV_LEARN or DV_BOX message! */
786 * Message send to another peer to validate that it can indeed
787 * receive messages at a particular address.
789 struct TransportValidationChallengeMessage
793 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
795 struct GNUNET_MessageHeader header;
800 uint32_t reserved GNUNET_PACKED;
803 * Challenge to be signed by the receiving peer.
805 struct ChallengeNonceP challenge;
808 * Timestamp of the sender, to be copied into the reply
809 * to allow sender to calculate RTT.
811 struct GNUNET_TIME_AbsoluteNBO sender_time;
816 * Message signed by a peer to confirm that it can indeed
817 * receive messages at a particular address.
819 struct TransportValidationPS
823 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
825 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
828 * How long does the sender believe the address on
829 * which the challenge was received to remain valid?
831 struct GNUNET_TIME_RelativeNBO validity_duration;
834 * Challenge signed by the receiving peer.
836 struct ChallengeNonceP challenge;
841 * Message send to a peer to respond to a
842 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
844 struct TransportValidationResponseMessage
848 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
850 struct GNUNET_MessageHeader header;
855 uint32_t reserved GNUNET_PACKED;
858 * The peer's signature matching the
859 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
861 struct GNUNET_CRYPTO_EddsaSignature signature;
864 * The challenge that was signed by the receiving peer.
866 struct ChallengeNonceP challenge;
869 * Original timestamp of the sender (was @code{sender_time}),
870 * copied into the reply to allow sender to calculate RTT.
872 struct GNUNET_TIME_AbsoluteNBO origin_time;
875 * How long does the sender believe this address to remain
878 struct GNUNET_TIME_RelativeNBO validity_duration;
882 GNUNET_NETWORK_STRUCT_END
886 * What type of client is the `struct TransportClient` about?
891 * We do not know yet (client is fresh).
896 * Is the CORE service, we need to forward traffic to it.
901 * It is a monitor, forward monitor data.
906 * It is a communicator, use for communication.
911 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
918 * Which transmission options are allowable for transmission?
919 * Interpreted bit-wise!
921 enum RouteMessageOptions
924 * Only confirmed, non-DV direct neighbours.
929 * We are allowed to use DV routing for this @a hdr
934 * We are allowed to use unconfirmed queues or DV routes for this message
936 RMO_UNCONFIRMED_ALLOWED = 2,
939 * Reliable and unreliable, DV and non-DV are all acceptable.
941 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
944 * If we have multiple choices, it is OK to send this message
945 * over multiple channels at the same time to improve loss tolerance.
946 * (We do at most 2 transmissions.)
953 * When did we launch this DV learning activity?
955 struct LearnLaunchEntry
959 * Kept (also) in a DLL sorted by launch time.
961 struct LearnLaunchEntry *prev;
964 * Kept (also) in a DLL sorted by launch time.
966 struct LearnLaunchEntry *next;
969 * Challenge that uniquely identifies this activity.
971 struct ChallengeNonceP challenge;
974 * When did we transmit the DV learn message (used to calculate RTT) and
975 * determine freshness of paths learned via this operation.
977 struct GNUNET_TIME_Absolute launch_time;
982 * Entry in our cache of ephemeral keys we currently use. This way, we only
983 * sign an ephemeral once per @e target, and then can re-use it over multiple
984 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
985 * signing is expensive and in some cases we may use backchannel messages a
988 struct EphemeralCacheEntry
992 * Target's peer identity (we don't re-use ephemerals
993 * to limit linkability of messages).
995 struct GNUNET_PeerIdentity target;
998 * Signature affirming @e ephemeral_key of type
999 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1001 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1004 * How long is @e sender_sig valid
1006 struct GNUNET_TIME_Absolute ephemeral_validity;
1009 * What time was @e sender_sig created
1011 struct GNUNET_TIME_Absolute monotime;
1014 * Our ephemeral key.
1016 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1019 * Our private ephemeral key.
1021 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1024 * Node in the ephemeral cache for this entry.
1025 * Used for expiration.
1027 struct GNUNET_CONTAINER_HeapNode *hn;
1032 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1033 * (or current) transmission performance.
1035 struct TransmissionHistoryEntry
1038 * Number of bytes actually sent in the interval.
1040 uint64_t bytes_sent;
1043 * Number of bytes received and acknowledged by the other peer in
1046 uint64_t bytes_received;
1051 * Performance data for a transmission possibility.
1053 struct PerformanceData
1056 * Weighted average for the RTT.
1058 struct GNUNET_TIME_Relative aged_rtt;
1061 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1064 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1067 * What was the last age when we wrote to @e the? Used to clear
1068 * old entries when the age advances.
1070 unsigned int last_age;
1075 * Client connected to the transport service.
1077 struct TransportClient;
1080 * A neighbour that at least one communicator is connected to.
1085 * Entry in our #dv_routes table, representing a (set of) distance
1086 * vector routes to a particular peer.
1088 struct DistanceVector;
1091 * A queue is a message queue provided by a communicator
1092 * via which we can reach a particular neighbour.
1097 * Message awaiting transmission. See detailed comments below.
1099 struct PendingMessage;
1102 * One possible hop towards a DV target.
1104 struct DistanceVectorHop;
1108 * Context from #handle_incoming_msg(). Closure for many
1109 * message handlers below.
1111 struct CommunicatorMessageContext
1115 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1116 * flow control to unchoke.
1118 struct CommunicatorMessageContext *next;
1121 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1122 * flow control to unchoke.
1124 struct CommunicatorMessageContext *prev;
1127 * Which communicator provided us with the message.
1129 struct TransportClient *tc;
1132 * Additional information for flow control and about the sender.
1134 struct GNUNET_TRANSPORT_IncomingMessage im;
1137 * Number of hops the message has travelled (if DV-routed).
1138 * FIXME: make use of this in ACK handling!
1140 uint16_t total_hops;
1145 * A virtual link is another reachable peer that is known to CORE. It
1146 * can be either a `struct Neighbour` with at least one confirmed
1147 * `struct Queue`, or a `struct DistanceVector` with at least one
1148 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1149 * data that is per neighbour that is not specific to how the
1150 * connectivity is established.
1155 * Identity of the peer at the other end of the link.
1157 struct GNUNET_PeerIdentity target;
1160 * Communicators blocked for receiving on @e target as we are waiting
1161 * on the @e core_recv_window to increase.
1163 struct CommunicatorMessageContext *cmc_head;
1166 * Communicators blocked for receiving on @e target as we are waiting
1167 * on the @e core_recv_window to increase.
1169 struct CommunicatorMessageContext *cmc_tail;
1172 * Task scheduled to possibly notfiy core that this peer is no
1173 * longer counting as confirmed. Runs the #core_visibility_check(),
1174 * which checks that some DV-path or a queue exists that is still
1175 * considered confirmed.
1177 struct GNUNET_SCHEDULER_Task *visibility_task;
1180 * Neighbour used by this virtual link, NULL if @e dv is used.
1182 struct Neighbour *n;
1185 * Distance vector used by this virtual link, NULL if @e n is used.
1187 struct DistanceVector *dv;
1190 * How many more messages can we send to core before we exhaust
1191 * the receive window of CORE for this peer? If this hits zero,
1192 * we must tell communicators to stop providing us more messages
1193 * for this peer. In fact, the window can go negative as we
1194 * have multiple communicators, so per communicator we can go
1195 * down by one into the negative range.
1197 int core_recv_window;
1202 * Data structure kept when we are waiting for an acknowledgement.
1204 struct PendingAcknowledgement
1208 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1209 * is kept in relation to its pending message.
1211 struct PendingAcknowledgement *next_pm;
1214 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1215 * is kept in relation to its pending message.
1217 struct PendingAcknowledgement *prev_pm;
1220 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1221 * is kept in relation to the queue that was used to transmit the
1224 struct PendingAcknowledgement *next_queue;
1227 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1228 * is kept in relation to the queue that was used to transmit the
1231 struct PendingAcknowledgement *prev_queue;
1234 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1235 * is kept in relation to the DVH that was used to transmit the
1238 struct PendingAcknowledgement *next_dvh;
1241 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1242 * is kept in relation to the DVH that was used to transmit the
1245 struct PendingAcknowledgement *prev_dvh;
1248 * Pointers for the DLL of all pending acknowledgements.
1249 * This list is sorted by @e transmission time. If the list gets too
1250 * long, the oldest entries are discarded.
1252 struct PendingAcknowledgement *next_pa;
1255 * Pointers for the DLL of all pending acknowledgements.
1256 * This list is sorted by @e transmission time. If the list gets too
1257 * long, the oldest entries are discarded.
1259 struct PendingAcknowledgement *prev_pa;
1262 * Unique identifier for this transmission operation.
1264 struct AcknowledgementUUIDP ack_uuid;
1267 * Message that was transmitted, may be NULL if the message was ACKed
1268 * via another channel.
1270 struct PendingMessage *pm;
1273 * Distance vector path chosen for this transmission, NULL if transmission
1274 * was to a direct neighbour OR if the path was forgotten in the meantime.
1276 struct DistanceVectorHop *dvh;
1279 * Queue used for transmission, NULL if the queue has been destroyed
1280 * (which may happen before we get an acknowledgement).
1282 struct Queue *queue;
1285 * Time of the transmission, for RTT calculation.
1287 struct GNUNET_TIME_Absolute transmission_time;
1290 * Number of bytes of the original message (to calculate bandwidth).
1292 uint16_t message_size;
1297 * One possible hop towards a DV target.
1299 struct DistanceVectorHop
1303 * Kept in a MDLL, sorted by @e timeout.
1305 struct DistanceVectorHop *next_dv;
1308 * Kept in a MDLL, sorted by @e timeout.
1310 struct DistanceVectorHop *prev_dv;
1315 struct DistanceVectorHop *next_neighbour;
1320 struct DistanceVectorHop *prev_neighbour;
1323 * Head of MDLL of messages routed via this path.
1325 struct PendingMessage *pending_msg_head;
1328 * Tail of MDLL of messages routed via this path.
1330 struct PendingMessage *pending_msg_tail;
1333 * Head of DLL of PAs that used our @a path.
1335 struct PendingAcknowledgement *pa_head;
1338 * Tail of DLL of PAs that used our @a path.
1340 struct PendingAcknowledgement *pa_tail;
1343 * What would be the next hop to @e target?
1345 struct Neighbour *next_hop;
1348 * Distance vector entry this hop belongs with.
1350 struct DistanceVector *dv;
1353 * Array of @e distance hops to the target, excluding @e next_hop.
1354 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1355 * at the end of this struct. Excludes the target itself!
1357 const struct GNUNET_PeerIdentity *path;
1360 * At what time do we forget about this path unless we see it again
1363 struct GNUNET_TIME_Absolute timeout;
1366 * For how long is the validation of this path considered
1368 * Set to ZERO if the path is learned by snooping on DV learn messages
1369 * initiated by other peers, and to the time at which we generated the
1370 * challenge for DV learn operations this peer initiated.
1372 struct GNUNET_TIME_Absolute path_valid_until;
1375 * Performance data for this transmission possibility.
1377 struct PerformanceData pd;
1380 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1381 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1384 unsigned int distance;
1389 * Entry in our #dv_routes table, representing a (set of) distance
1390 * vector routes to a particular peer.
1392 struct DistanceVector
1396 * To which peer is this a route?
1398 struct GNUNET_PeerIdentity target;
1401 * Known paths to @e target.
1403 struct DistanceVectorHop *dv_head;
1406 * Known paths to @e target.
1408 struct DistanceVectorHop *dv_tail;
1411 * Task scheduled to purge expired paths from @e dv_head MDLL.
1413 struct GNUNET_SCHEDULER_Task *timeout_task;
1416 * Do we have a confirmed working queue and are thus visible to
1417 * CORE? If so, this is the virtual link, otherwise NULL.
1419 struct VirtualLink *link;
1424 * Entry identifying transmission in one of our `struct
1425 * Queue` which still awaits an ACK. This is used to
1426 * ensure we do not overwhelm a communicator and limit the number of
1427 * messages outstanding per communicator (say in case communicator is
1428 * CPU bound) and per queue (in case bandwidth allocation exceeds
1429 * what the communicator can actually provide towards a particular
1438 struct QueueEntry *next;
1443 struct QueueEntry *prev;
1446 * Queue this entry is queued with.
1448 struct Queue *queue;
1451 * Pending message this entry is for, or NULL for none.
1453 struct PendingMessage *pm;
1456 * Message ID used for this message with the queue used for transmission.
1463 * A queue is a message queue provided by a communicator
1464 * via which we can reach a particular neighbour.
1471 struct Queue *next_neighbour;
1476 struct Queue *prev_neighbour;
1481 struct Queue *prev_client;
1486 struct Queue *next_client;
1489 * Head of DLL of PAs that used this queue.
1491 struct PendingAcknowledgement *pa_head;
1494 * Tail of DLL of PAs that used this queue.
1496 struct PendingAcknowledgement *pa_tail;
1499 * Head of DLL of unacked transmission requests.
1501 struct QueueEntry *queue_head;
1504 * End of DLL of unacked transmission requests.
1506 struct QueueEntry *queue_tail;
1509 * Which neighbour is this queue for?
1511 struct Neighbour *neighbour;
1514 * Which communicator offers this queue?
1516 struct TransportClient *tc;
1519 * Address served by the queue.
1521 const char *address;
1524 * Task scheduled for the time when this queue can (likely) transmit the
1527 struct GNUNET_SCHEDULER_Task *transmit_task;
1530 * How long do *we* consider this @e address to be valid? In the past or
1531 * zero if we have not yet validated it. Can be updated based on
1532 * challenge-response validations (via address validation logic), or when we
1533 * receive ACKs that we can definitively map to transmissions via this
1536 struct GNUNET_TIME_Absolute validated_until;
1539 * Performance data for this queue.
1541 struct PerformanceData pd;
1544 * Message ID generator for transmissions on this queue to the
1550 * Unique identifier of this queue with the communicator.
1555 * Maximum transmission unit supported by this queue.
1562 uint32_t num_msg_pending;
1567 uint32_t num_bytes_pending;
1570 * Length of the DLL starting at @e queue_head.
1572 unsigned int queue_length;
1575 * Network type offered by this queue.
1577 enum GNUNET_NetworkType nt;
1580 * Connection status for this queue.
1582 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1587 * Information we keep for a message that we are reassembling.
1589 struct ReassemblyContext
1593 * Original message ID for of the message that all the fragments
1596 struct MessageUUIDP msg_uuid;
1599 * Which neighbour is this context for?
1601 struct Neighbour *neighbour;
1604 * Entry in the reassembly heap (sorted by expiration).
1606 struct GNUNET_CONTAINER_HeapNode *hn;
1609 * Bitfield with @e msg_size bits representing the positions
1610 * where we have received fragments. When we receive a fragment,
1611 * we check the bits in @e bitfield before incrementing @e msg_missing.
1613 * Allocated after the reassembled message.
1618 * At what time will we give up reassembly of this message?
1620 struct GNUNET_TIME_Absolute reassembly_timeout;
1623 * Time we received the last fragment. @e avg_ack_delay must be
1624 * incremented by now - @e last_frag multiplied by @e num_acks.
1626 struct GNUNET_TIME_Absolute last_frag;
1629 * How big is the message we are reassembling in total?
1634 * How many bytes of the message are still missing? Defragmentation
1635 * is complete when @e msg_missing == 0.
1637 uint16_t msg_missing;
1639 /* Followed by @e msg_size bytes of the (partially) defragmented original
1642 /* Followed by @e bitfield data */
1647 * A neighbour that at least one communicator is connected to.
1653 * Which peer is this about?
1655 struct GNUNET_PeerIdentity pid;
1658 * Map with `struct ReassemblyContext` structs for fragments under
1659 * reassembly. May be NULL if we currently have no fragments from
1660 * this @e pid (lazy initialization).
1662 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1665 * Heap with `struct ReassemblyContext` structs for fragments under
1666 * reassembly. May be NULL if we currently have no fragments from
1667 * this @e pid (lazy initialization).
1669 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1672 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1674 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1677 * Head of list of messages pending for this neighbour.
1679 struct PendingMessage *pending_msg_head;
1682 * Tail of list of messages pending for this neighbour.
1684 struct PendingMessage *pending_msg_tail;
1687 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1688 * purged if this neighbour goes down.
1690 struct DistanceVectorHop *dv_head;
1693 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1694 * purged if this neighbour goes down.
1696 struct DistanceVectorHop *dv_tail;
1699 * Head of DLL of queues to this peer.
1701 struct Queue *queue_head;
1704 * Tail of DLL of queues to this peer.
1706 struct Queue *queue_tail;
1709 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1710 * the PEERSTORE, or NULL.
1712 struct GNUNET_PEERSTORE_IterateContext *get;
1715 * Handle to a PEERSTORE store operation to store this @e pid's @e
1716 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1718 struct GNUNET_PEERSTORE_StoreContext *sc;
1721 * Do we have a confirmed working queue and are thus visible to
1722 * CORE? If so, this is the virtual link, otherwise NULL.
1724 struct VirtualLink *link;
1727 * Latest DVLearn monotonic time seen from this peer. Initialized only
1728 * if @e dl_monotime_available is #GNUNET_YES.
1730 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1733 * Used to generate unique UUIDs for messages that are being
1736 uint64_t message_uuid_ctr;
1739 * Do we have the lastest value for @e last_dv_learn_monotime from
1740 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1742 int dv_monotime_available;
1747 * A peer that an application (client) would like us to talk to directly.
1753 * Which peer is this about?
1755 struct GNUNET_PeerIdentity pid;
1758 * Client responsible for the request.
1760 struct TransportClient *tc;
1763 * Handle for watching the peerstore for HELLOs for this peer.
1765 struct GNUNET_PEERSTORE_WatchContext *wc;
1768 * What kind of performance preference does this @e tc have?
1772 enum GNUNET_MQ_PriorityPreferences pk;
1775 * How much bandwidth would this @e tc like to see?
1777 struct GNUNET_BANDWIDTH_Value32NBO bw;
1782 * Types of different pending messages.
1784 enum PendingMessageType
1788 * Ordinary message received from the CORE service.
1795 PMT_FRAGMENT_BOX = 1,
1800 PMT_RELIABILITY_BOX = 2,
1803 * Any type of acknowledgement.
1805 PMT_ACKNOWLEDGEMENT = 3,
1808 * Control traffic generated by the TRANSPORT service itself.
1816 * Transmission request that is awaiting delivery. The original
1817 * transmission requests from CORE may be too big for some queues.
1818 * In this case, a *tree* of fragments is created. At each
1819 * level of the tree, fragments are kept in a DLL ordered by which
1820 * fragment should be sent next (at the head). The tree is searched
1821 * top-down, with the original message at the root.
1823 * To select a node for transmission, first it is checked if the
1824 * current node's message fits with the MTU. If it does not, we
1825 * either calculate the next fragment (based on @e frag_off) from the
1826 * current node, or, if all fragments have already been created,
1827 * descend to the @e head_frag. Even though the node was already
1828 * fragmented, the fragment may be too big if the fragment was
1829 * generated for a queue with a larger MTU. In this case, the node
1830 * may be fragmented again, thus creating a tree.
1832 * When acknowledgements for fragments are received, the tree
1833 * must be pruned, removing those parts that were already
1834 * acknowledged. When fragments are sent over a reliable
1835 * channel, they can be immediately removed.
1837 * If a message is ever fragmented, then the original "full" message
1838 * is never again transmitted (even if it fits below the MTU), and
1839 * only (remaining) fragments are sent.
1841 struct PendingMessage
1844 * Kept in a MDLL of messages for this @a target.
1846 struct PendingMessage *next_neighbour;
1849 * Kept in a MDLL of messages for this @a target.
1851 struct PendingMessage *prev_neighbour;
1854 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1856 struct PendingMessage *next_client;
1859 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1861 struct PendingMessage *prev_client;
1864 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1865 * #PMT_FRAGMENT_BOx)
1867 struct PendingMessage *next_frag;
1870 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1871 * #PMT_FRAGMENT_BOX)
1873 struct PendingMessage *prev_frag;
1876 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1879 struct PendingMessage *next_dvh;
1882 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1885 struct PendingMessage *prev_dvh;
1888 * Head of DLL of PAs for this pending message.
1890 struct PendingAcknowledgement *pa_head;
1893 * Tail of DLL of PAs for this pending message.
1895 struct PendingAcknowledgement *pa_tail;
1898 * This message, reliability boxed. Only possibly available if @e pmt is
1901 struct PendingMessage *bpm;
1904 * Target of the request (for transmission, may not be ultimate
1907 struct Neighbour *target;
1910 * Distance vector path selected for this message, or
1911 * NULL if transmitted directly.
1913 struct DistanceVectorHop *dvh;
1916 * Set to non-NULL value if this message is currently being given to a
1917 * communicator and we are awaiting that communicator's acknowledgement.
1918 * Note that we must not retransmit a pending message while we're still
1919 * in the process of giving it to a communicator. If a pending message
1920 * is free'd while this entry is non-NULL, the @e qe reference to us
1921 * should simply be set to NULL.
1923 struct QueueEntry *qe;
1926 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1928 struct TransportClient *client;
1931 * Head of a MDLL of fragments created for this core message.
1933 struct PendingMessage *head_frag;
1936 * Tail of a MDLL of fragments created for this core message.
1938 struct PendingMessage *tail_frag;
1941 * Our parent in the fragmentation tree.
1943 struct PendingMessage *frag_parent;
1946 * At what time should we give up on the transmission (and no longer retry)?
1948 struct GNUNET_TIME_Absolute timeout;
1951 * What is the earliest time for us to retry transmission of this message?
1953 struct GNUNET_TIME_Absolute next_attempt;
1956 * UUID to use for this message (used for reassembly of fragments, only
1957 * initialized if @e msg_uuid_set is #GNUNET_YES).
1959 struct MessageUUIDP msg_uuid;
1962 * Type of the pending message.
1964 enum PendingMessageType pmt;
1967 * Preferences for this message.
1968 * TODO: actually use this!
1970 enum GNUNET_MQ_PriorityPreferences prefs;
1973 * Size of the original message.
1978 * Offset at which we should generate the next fragment.
1983 * #GNUNET_YES once @e msg_uuid was initialized
1985 int16_t msg_uuid_set;
1987 /* Followed by @e bytes_msg to transmit */
1992 * Acknowledgement payload.
1994 struct TransportCummulativeAckPayload
1997 * When did we receive the message we are ACKing? Used to calculate
1998 * the delay we introduced by cummulating ACKs.
2000 struct GNUNET_TIME_Absolute receive_time;
2003 * UUID of a message being acknowledged.
2005 struct AcknowledgementUUIDP ack_uuid;
2010 * Data structure in which we track acknowledgements still to
2013 struct AcknowledgementCummulator
2016 * Target peer for which we are accumulating ACKs here.
2018 struct GNUNET_PeerIdentity target;
2021 * ACK data being accumulated. Only @e num_acks slots are valid.
2023 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2026 * Task scheduled either to transmit the cummulative ACK message,
2027 * or to clean up this data structure after extended periods of
2028 * inactivity (if @e num_acks is zero).
2030 struct GNUNET_SCHEDULER_Task *task;
2033 * When is @e task run (only used if @e num_acks is non-zero)?
2035 struct GNUNET_TIME_Absolute min_transmission_time;
2038 * Counter to produce the `ack_counter` in the `struct
2039 * TransportReliabilityAckMessage`. Allows the receiver to detect
2040 * lost ACK messages. Incremented by @e num_acks upon transmission.
2042 uint32_t ack_counter;
2045 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2047 unsigned int num_acks;
2052 * One of the addresses of this peer.
2054 struct AddressListEntry
2060 struct AddressListEntry *next;
2065 struct AddressListEntry *prev;
2068 * Which communicator provides this address?
2070 struct TransportClient *tc;
2073 * The actual address.
2075 const char *address;
2078 * Current context for storing this address in the peerstore.
2080 struct GNUNET_PEERSTORE_StoreContext *sc;
2083 * Task to periodically do @e st operation.
2085 struct GNUNET_SCHEDULER_Task *st;
2088 * What is a typical lifetime the communicator expects this
2089 * address to have? (Always from now.)
2091 struct GNUNET_TIME_Relative expiration;
2094 * Address identifier used by the communicator.
2099 * Network type offered by this address.
2101 enum GNUNET_NetworkType nt;
2106 * Client connected to the transport service.
2108 struct TransportClient
2114 struct TransportClient *next;
2119 struct TransportClient *prev;
2122 * Handle to the client.
2124 struct GNUNET_SERVICE_Client *client;
2127 * Message queue to the client.
2129 struct GNUNET_MQ_Handle *mq;
2132 * What type of client is this?
2134 enum ClientType type;
2140 * Information for @e type #CT_CORE.
2146 * Head of list of messages pending for this client, sorted by
2147 * transmission time ("next_attempt" + possibly internal prioritization).
2149 struct PendingMessage *pending_msg_head;
2152 * Tail of list of messages pending for this client.
2154 struct PendingMessage *pending_msg_tail;
2159 * Information for @e type #CT_MONITOR.
2165 * Peer identity to monitor the addresses of.
2166 * Zero to monitor all neighbours. Valid if
2167 * @e type is #CT_MONITOR.
2169 struct GNUNET_PeerIdentity peer;
2172 * Is this a one-shot monitor?
2180 * Information for @e type #CT_COMMUNICATOR.
2185 * If @e type is #CT_COMMUNICATOR, this communicator
2186 * supports communicating using these addresses.
2188 char *address_prefix;
2191 * Head of DLL of queues offered by this communicator.
2193 struct Queue *queue_head;
2196 * Tail of DLL of queues offered by this communicator.
2198 struct Queue *queue_tail;
2201 * Head of list of the addresses of this peer offered by this
2204 struct AddressListEntry *addr_head;
2207 * Tail of list of the addresses of this peer offered by this
2210 struct AddressListEntry *addr_tail;
2213 * Number of queue entries in all queues to this communicator. Used
2214 * throttle sending to a communicator if we see that the communicator
2215 * is globally unable to keep up.
2217 unsigned int total_queue_length;
2220 * Characteristics of this communicator.
2222 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2227 * Information for @e type #CT_APPLICATION
2233 * Map of requests for peers the given client application would like to
2234 * see connections for. Maps from PIDs to `struct PeerRequest`.
2236 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2245 * State we keep for validation activities. Each of these
2246 * is both in the #validation_heap and the #validation_map.
2248 struct ValidationState
2252 * For which peer is @a address to be validated (or possibly valid)?
2253 * Serves as key in the #validation_map.
2255 struct GNUNET_PeerIdentity pid;
2258 * How long did the peer claim this @e address to be valid? Capped at
2259 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2260 * were told about the address and the value claimed by the other peer at
2261 * that time. May be updated similarly when validation succeeds.
2263 struct GNUNET_TIME_Absolute valid_until;
2266 * How long do *we* consider this @e address to be valid?
2267 * In the past or zero if we have not yet validated it.
2269 struct GNUNET_TIME_Absolute validated_until;
2272 * When did we FIRST use the current @e challenge in a message?
2273 * Used to sanity-check @code{origin_time} in the response when
2274 * calculating the RTT. If the @code{origin_time} is not in
2275 * the expected range, the response is discarded as malicious.
2277 struct GNUNET_TIME_Absolute first_challenge_use;
2280 * When did we LAST use the current @e challenge in a message?
2281 * Used to sanity-check @code{origin_time} in the response when
2282 * calculating the RTT. If the @code{origin_time} is not in
2283 * the expected range, the response is discarded as malicious.
2285 struct GNUNET_TIME_Absolute last_challenge_use;
2288 * Next time we will send the @e challenge to the peer, if this time is past
2289 * @e valid_until, this validation state is released at this time. If the
2290 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2291 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2292 * to re-validate before the validity actually expires.
2294 struct GNUNET_TIME_Absolute next_challenge;
2297 * Current backoff factor we're applying for sending the @a challenge.
2298 * Reset to 0 if the @a challenge is confirmed upon validation.
2299 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2300 * existing value if we receive an unvalidated address again over
2301 * another channel (and thus should consider the information "fresh").
2302 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2304 struct GNUNET_TIME_Relative challenge_backoff;
2307 * Initially set to "forever". Once @e validated_until is set, this value is
2308 * set to the RTT that tells us how long it took to receive the validation.
2310 struct GNUNET_TIME_Relative validation_rtt;
2313 * The challenge we sent to the peer to get it to validate the address. Note
2314 * that we rotate the challenge whenever we update @e validated_until to
2315 * avoid attacks where a peer simply replays an old challenge in the future.
2316 * (We must not rotate more often as otherwise we may discard valid answers
2317 * due to packet losses, latency and reorderings on the network).
2319 struct ChallengeNonceP challenge;
2322 * Claimed address of the peer.
2327 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2328 * heap is used to figure out when the next validation activity should be
2331 struct GNUNET_CONTAINER_HeapNode *hn;
2334 * Handle to a PEERSTORE store operation for this @e address. NULL if
2335 * no PEERSTORE operation is pending.
2337 struct GNUNET_PEERSTORE_StoreContext *sc;
2340 * We are technically ready to send the challenge, but we are waiting for
2341 * the respective queue to become available for transmission.
2348 * A Backtalker is a peer sending us backchannel messages. We use this
2349 * struct to detect monotonic time violations, cache ephemeral key
2350 * material (to avoid repeatedly checking signatures), and to synchronize
2351 * monotonic time with the PEERSTORE.
2356 * Peer this is about.
2358 struct GNUNET_PeerIdentity pid;
2361 * Last (valid) monotonic time received from this sender.
2363 struct GNUNET_TIME_Absolute monotonic_time;
2366 * When will this entry time out?
2368 struct GNUNET_TIME_Absolute timeout;
2371 * Last (valid) ephemeral key received from this sender.
2373 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2376 * Task associated with this backtalker. Can be for timeout,
2377 * or other asynchronous operations.
2379 struct GNUNET_SCHEDULER_Task *task;
2382 * Communicator context waiting on this backchannel's @e get, or NULL.
2384 struct CommunicatorMessageContext *cmc;
2387 * Handle for an operation to fetch @e monotonic_time information from the
2388 * PEERSTORE, or NULL.
2390 struct GNUNET_PEERSTORE_IterateContext *get;
2393 * Handle to a PEERSTORE store operation for this @e pid's @e
2394 * monotonic_time. NULL if no PEERSTORE operation is pending.
2396 struct GNUNET_PEERSTORE_StoreContext *sc;
2399 * Number of bytes of the original message body that follows after this
2407 * Head of linked list of all clients to this service.
2409 static struct TransportClient *clients_head;
2412 * Tail of linked list of all clients to this service.
2414 static struct TransportClient *clients_tail;
2417 * Statistics handle.
2419 static struct GNUNET_STATISTICS_Handle *GST_stats;
2422 * Configuration handle.
2424 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2429 static struct GNUNET_PeerIdentity GST_my_identity;
2434 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2437 * Map from PIDs to `struct Neighbour` entries. A peer is
2438 * a neighbour if we have an MQ to it from some communicator.
2440 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2443 * Map from PIDs to `struct Backtalker` entries. A peer is
2444 * a backtalker if it recently send us backchannel messages.
2446 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2449 * Map from PIDs to `struct AcknowledgementCummulator`s.
2450 * Here we track the cummulative ACKs for transmission.
2452 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2455 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2456 * a `struct PendingAcknowledgement`.
2458 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2461 * Map from PIDs to `struct DistanceVector` entries describing
2462 * known paths to the peer.
2464 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2467 * Map from PIDs to `struct ValidationState` entries describing
2468 * addresses we are aware of and their validity state.
2470 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2473 * Map from PIDs to `struct VirtualLink` entries describing
2474 * links CORE knows to exist.
2476 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2479 * Map from challenges to `struct LearnLaunchEntry` values.
2481 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2484 * Head of a DLL sorted by launch time.
2486 static struct LearnLaunchEntry *lle_head;
2489 * Tail of a DLL sorted by launch time.
2491 static struct LearnLaunchEntry *lle_tail;
2494 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2495 * sorting addresses we are aware of by when we should next try to (re)validate
2498 static struct GNUNET_CONTAINER_Heap *validation_heap;
2501 * Database for peer's HELLOs.
2503 static struct GNUNET_PEERSTORE_Handle *peerstore;
2506 * Heap sorting `struct EphemeralCacheEntry` by their
2507 * key/signature validity.
2509 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2512 * Hash map for looking up `struct EphemeralCacheEntry`s
2513 * by peer identity. (We may have ephemerals in our
2514 * cache for which we do not have a neighbour entry,
2515 * and similar many neighbours may not need ephemerals,
2516 * so we use a second map.)
2518 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2521 * Task to free expired ephemerals.
2523 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2526 * Task run to initiate DV learning.
2528 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2531 * Task to run address validation.
2533 static struct GNUNET_SCHEDULER_Task *validation_task;
2536 * The most recent PA we have created, head of DLL.
2537 * The length of the DLL is kept in #pa_count.
2539 static struct PendingAcknowledgement *pa_head;
2542 * The oldest PA we have created, tail of DLL.
2543 * The length of the DLL is kept in #pa_count.
2545 static struct PendingAcknowledgement *pa_tail;
2548 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2549 * limit the size of the data structure.
2551 static unsigned int pa_count;
2554 * Monotonic time we use for HELLOs generated at this time. TODO: we
2555 * should increase this value from time to time (i.e. whenever a
2556 * `struct AddressListEntry` actually expires), but IF we do this, we
2557 * must also update *all* (remaining) addresses in the PEERSTORE at
2558 * that time! (So for now only increased when the peer is restarted,
2559 * which hopefully roughly matches whenever our addresses change.)
2561 static struct GNUNET_TIME_Absolute hello_mono_time;
2565 * Get an offset into the transmission history buffer for `struct
2566 * PerformanceData`. Note that the caller must perform the required
2567 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2570 * An 'age' lasts 15 minute slots.
2572 * @return current age of the world
2577 struct GNUNET_TIME_Absolute now;
2579 now = GNUNET_TIME_absolute_get ();
2580 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2585 * Release @a pa data structure.
2587 * @param pa data structure to release
2590 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2592 struct Queue *q = pa->queue;
2593 struct PendingMessage *pm = pa->pm;
2594 struct DistanceVectorHop *dvh = pa->dvh;
2596 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2600 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2605 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2610 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2613 GNUNET_assert (GNUNET_YES ==
2614 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2615 &pa->ack_uuid.value,
2622 * Free cached ephemeral key.
2624 * @param ece cached signature to free
2627 free_ephemeral (struct EphemeralCacheEntry *ece)
2629 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2630 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2636 * Free virtual link.
2638 * @param vl link data to free
2641 free_virtual_link (struct VirtualLink *vl)
2643 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2644 if (NULL != vl->visibility_task)
2646 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2647 vl->visibility_task = NULL;
2649 GNUNET_break (NULL == vl->n);
2650 GNUNET_break (NULL == vl->dv);
2656 * Free validation state.
2658 * @param vs validation state to free
2661 free_validation_state (struct ValidationState *vs)
2663 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2664 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2668 GNUNET_PEERSTORE_store_cancel (vs->sc);
2671 GNUNET_free (vs->address);
2677 * Lookup neighbour record for peer @a pid.
2679 * @param pid neighbour to look for
2680 * @return NULL if we do not have this peer as a neighbour
2682 static struct Neighbour *
2683 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2685 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2690 * Details about what to notify monitors about.
2695 * @deprecated To be discussed if we keep these...
2697 struct GNUNET_TIME_Absolute last_validation;
2698 struct GNUNET_TIME_Absolute valid_until;
2699 struct GNUNET_TIME_Absolute next_validation;
2702 * Current round-trip time estimate.
2704 struct GNUNET_TIME_Relative rtt;
2707 * Connection status.
2709 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2714 uint32_t num_msg_pending;
2719 uint32_t num_bytes_pending;
2724 * Free a @dvh. Callers MAY want to check if this was the last path to the
2725 * `target`, and if so call #free_dv_route to also free the associated DV
2726 * entry in #dv_routes (if not, the associated scheduler job should eventually
2729 * @param dvh hop to free
2732 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2734 struct Neighbour *n = dvh->next_hop;
2735 struct DistanceVector *dv = dvh->dv;
2736 struct PendingAcknowledgement *pa;
2737 struct PendingMessage *pm;
2739 while (NULL != (pm = dvh->pending_msg_head))
2741 GNUNET_CONTAINER_MDLL_remove (dvh,
2742 dvh->pending_msg_head,
2743 dvh->pending_msg_tail,
2747 while (NULL != (pa = dvh->pa_head))
2749 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2752 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2753 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2759 * Free entry in #dv_routes. First frees all hops to the target, and
2760 * if there are no entries left, frees @a dv as well.
2762 * @param dv route to free
2765 free_dv_route (struct DistanceVector *dv)
2767 struct DistanceVectorHop *dvh;
2769 while (NULL != (dvh = dv->dv_head))
2770 free_distance_vector_hop (dvh);
2771 if (NULL == dv->dv_head)
2775 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2776 if (NULL != dv->timeout_task)
2777 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2784 * Notify monitor @a tc about an event. That @a tc
2785 * cares about the event has already been checked.
2787 * Send @a tc information in @a me about a @a peer's status with
2788 * respect to some @a address to all monitors that care.
2790 * @param tc monitor to inform
2791 * @param peer peer the information is about
2792 * @param address address the information is about
2793 * @param nt network type associated with @a address
2794 * @param me detailed information to transmit
2797 notify_monitor (struct TransportClient *tc,
2798 const struct GNUNET_PeerIdentity *peer,
2799 const char *address,
2800 enum GNUNET_NetworkType nt,
2801 const struct MonitorEvent *me)
2803 struct GNUNET_MQ_Envelope *env;
2804 struct GNUNET_TRANSPORT_MonitorData *md;
2805 size_t addr_len = strlen (address) + 1;
2807 env = GNUNET_MQ_msg_extra (md,
2809 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2810 md->nt = htonl ((uint32_t) nt);
2812 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2813 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2814 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2815 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2816 md->cs = htonl ((uint32_t) me->cs);
2817 md->num_msg_pending = htonl (me->num_msg_pending);
2818 md->num_bytes_pending = htonl (me->num_bytes_pending);
2819 memcpy (&md[1], address, addr_len);
2820 GNUNET_MQ_send (tc->mq, env);
2825 * Send information in @a me about a @a peer's status with respect
2826 * to some @a address to all monitors that care.
2828 * @param peer peer the information is about
2829 * @param address address the information is about
2830 * @param nt network type associated with @a address
2831 * @param me detailed information to transmit
2834 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2835 const char *address,
2836 enum GNUNET_NetworkType nt,
2837 const struct MonitorEvent *me)
2839 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2841 if (CT_MONITOR != tc->type)
2843 if (tc->details.monitor.one_shot)
2845 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2846 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2848 notify_monitor (tc, peer, address, nt, me);
2854 * Called whenever a client connects. Allocates our
2855 * data structures associated with that client.
2857 * @param cls closure, NULL
2858 * @param client identification of the client
2859 * @param mq message queue for the client
2860 * @return our `struct TransportClient`
2863 client_connect_cb (void *cls,
2864 struct GNUNET_SERVICE_Client *client,
2865 struct GNUNET_MQ_Handle *mq)
2867 struct TransportClient *tc;
2870 tc = GNUNET_new (struct TransportClient);
2871 tc->client = client;
2873 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2882 * @param rc data structure to free
2885 free_reassembly_context (struct ReassemblyContext *rc)
2887 struct Neighbour *n = rc->neighbour;
2889 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2890 GNUNET_assert (GNUNET_OK ==
2891 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2899 * Task run to clean up reassembly context of a neighbour that have expired.
2901 * @param cls a `struct Neighbour`
2904 reassembly_cleanup_task (void *cls)
2906 struct Neighbour *n = cls;
2907 struct ReassemblyContext *rc;
2909 n->reassembly_timeout_task = NULL;
2910 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2912 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2915 free_reassembly_context (rc);
2918 GNUNET_assert (NULL == n->reassembly_timeout_task);
2919 n->reassembly_timeout_task =
2920 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2921 &reassembly_cleanup_task,
2929 * function called to #free_reassembly_context().
2933 * @param value a `struct ReassemblyContext` to free
2934 * @return #GNUNET_OK (continue iteration)
2937 free_reassembly_cb (void *cls, uint32_t key, void *value)
2939 struct ReassemblyContext *rc = value;
2943 free_reassembly_context (rc);
2949 * Release memory used by @a neighbour.
2951 * @param neighbour neighbour entry to free
2954 free_neighbour (struct Neighbour *neighbour)
2956 struct DistanceVectorHop *dvh;
2958 GNUNET_assert (NULL == neighbour->queue_head);
2959 GNUNET_assert (GNUNET_YES ==
2960 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2963 if (NULL != neighbour->reassembly_map)
2965 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2966 &free_reassembly_cb,
2968 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2969 neighbour->reassembly_map = NULL;
2970 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2971 neighbour->reassembly_heap = NULL;
2973 while (NULL != (dvh = neighbour->dv_head))
2975 struct DistanceVector *dv = dvh->dv;
2977 free_distance_vector_hop (dvh);
2978 if (NULL == dv->dv_head)
2981 if (NULL != neighbour->reassembly_timeout_task)
2983 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2984 neighbour->reassembly_timeout_task = NULL;
2986 if (NULL != neighbour->get)
2988 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2989 neighbour->get = NULL;
2991 if (NULL != neighbour->sc)
2993 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2994 neighbour->sc = NULL;
2996 GNUNET_free (neighbour);
3001 * Send message to CORE clients that we lost a connection.
3003 * @param tc client to inform (must be CORE client)
3004 * @param pid peer the connection is for
3007 core_send_connect_info (struct TransportClient *tc,
3008 const struct GNUNET_PeerIdentity *pid)
3010 struct GNUNET_MQ_Envelope *env;
3011 struct ConnectInfoMessage *cim;
3013 GNUNET_assert (CT_CORE == tc->type);
3014 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3016 GNUNET_MQ_send (tc->mq, env);
3021 * Send message to CORE clients that we gained a connection
3023 * @param pid peer the queue was for
3026 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3029 "Informing CORE clients about connection to %s\n",
3031 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3033 if (CT_CORE != tc->type)
3035 core_send_connect_info (tc, pid);
3041 * Send message to CORE clients that we lost a connection.
3043 * @param pid peer the connection was for
3046 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3049 "Informing CORE clients about disconnect from %s\n",
3051 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3053 struct GNUNET_MQ_Envelope *env;
3054 struct DisconnectInfoMessage *dim;
3056 if (CT_CORE != tc->type)
3058 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3060 GNUNET_MQ_send (tc->mq, env);
3066 * We believe we are ready to transmit a message on a queue. Gives the
3067 * message to the communicator for transmission (updating the tracker,
3068 * and re-scheduling itself if applicable).
3070 * @param cls the `struct Queue` to process transmissions for
3073 transmit_on_queue (void *cls);
3077 * Schedule next run of #transmit_on_queue(). Does NOTHING if
3078 * we should run immediately or if the message queue is empty.
3079 * Test for no task being added AND queue not being empty to
3080 * transmit immediately afterwards! This function must only
3081 * be called if the message queue is non-empty!
3083 * @param queue the queue to do scheduling for
3084 * @param inside_job set to #GNUNET_YES if called from
3085 * #transmit_on_queue() itself and NOT setting
3086 * the task means running immediately
3089 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3091 struct Neighbour *n = queue->neighbour;
3092 struct PendingMessage *pm = n->pending_msg_head;
3093 struct GNUNET_TIME_Relative out_delay;
3095 GNUNET_assert (NULL != pm);
3096 if (queue->tc->details.communicator.total_queue_length >=
3097 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3099 GNUNET_STATISTICS_update (
3101 "# Transmission throttled due to communicator queue limit",
3106 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3108 GNUNET_STATISTICS_update (GST_stats,
3109 "# Transmission throttled due to queue queue limit",
3115 out_delay = GNUNET_TIME_absolute_get_remaining (pm->next_attempt);
3116 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3119 GNUNET_ERROR_TYPE_DEBUG,
3120 "Schedule transmission on queue %llu of %s decides to run immediately\n",
3121 (unsigned long long) queue->qid,
3122 GNUNET_i2s (&n->pid));
3123 return; /* we should run immediately! */
3125 /* queue has changed since we were scheduled, reschedule again */
3126 queue->transmit_task =
3127 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3128 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3129 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3130 "Next transmission on queue `%s' in %s (high delay)\n",
3132 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3135 "Next transmission on queue `%s' in %s\n",
3137 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3142 * Task run to check whether the hops of the @a cls still
3143 * are validated, or if we need to core about disconnection.
3145 * @param cls a `struct VirtualLink`
3148 check_link_down (void *cls)
3150 struct VirtualLink *vl = cls;
3151 struct DistanceVector *dv = vl->dv;
3152 struct Neighbour *n = vl->n;
3153 struct GNUNET_TIME_Absolute dvh_timeout;
3154 struct GNUNET_TIME_Absolute q_timeout;
3156 vl->visibility_task = NULL;
3157 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3158 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3160 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3161 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3163 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3164 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3165 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3166 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3168 if ((NULL == vl->n) && (NULL == vl->dv))
3170 cores_send_disconnect_info (&dv->target);
3171 free_virtual_link (vl);
3174 vl->visibility_task =
3175 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3184 * @param queue the queue to free
3187 free_queue (struct Queue *queue)
3189 struct Neighbour *neighbour = queue->neighbour;
3190 struct TransportClient *tc = queue->tc;
3191 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3192 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3193 struct QueueEntry *qe;
3195 struct PendingAcknowledgement *pa;
3196 struct VirtualLink *vl;
3198 if (NULL != queue->transmit_task)
3200 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3201 queue->transmit_task = NULL;
3203 while (NULL != (pa = queue->pa_head))
3205 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3209 GNUNET_CONTAINER_MDLL_remove (neighbour,
3210 neighbour->queue_head,
3211 neighbour->queue_tail,
3213 GNUNET_CONTAINER_MDLL_remove (client,
3214 tc->details.communicator.queue_head,
3215 tc->details.communicator.queue_tail,
3217 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3218 tc->details.communicator.total_queue_length);
3219 while (NULL != (qe = queue->queue_head))
3221 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3222 queue->queue_length--;
3223 tc->details.communicator.total_queue_length--;
3226 GNUNET_assert (qe == qe->pm->qe);
3231 GNUNET_assert (0 == queue->queue_length);
3232 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3233 tc->details.communicator.total_queue_length))
3235 /* Communicator dropped below threshold, resume all queues */
3236 GNUNET_STATISTICS_update (
3238 "# Transmission throttled due to communicator queue limit",
3241 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3243 schedule_transmit_on_queue (s, GNUNET_NO);
3245 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3246 GNUNET_free (queue);
3248 vl = GNUNET_CONTAINER_multipeermap_get (links, &neighbour->pid);
3249 if ((NULL != vl) && (neighbour == vl->n))
3251 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3252 check_link_down (vl);
3254 if (NULL == neighbour->queue_head)
3256 free_neighbour (neighbour);
3264 * @param ale address list entry to free
3267 free_address_list_entry (struct AddressListEntry *ale)
3269 struct TransportClient *tc = ale->tc;
3271 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3272 tc->details.communicator.addr_tail,
3274 if (NULL != ale->sc)
3276 GNUNET_PEERSTORE_store_cancel (ale->sc);
3279 if (NULL != ale->st)
3281 GNUNET_SCHEDULER_cancel (ale->st);
3289 * Stop the peer request in @a value.
3291 * @param cls a `struct TransportClient` that no longer makes the request
3292 * @param pid the peer's identity
3293 * @param value a `struct PeerRequest`
3294 * @return #GNUNET_YES (always)
3297 stop_peer_request (void *cls,
3298 const struct GNUNET_PeerIdentity *pid,
3301 struct TransportClient *tc = cls;
3302 struct PeerRequest *pr = value;
3304 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3307 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3317 * Called whenever a client is disconnected. Frees our
3318 * resources associated with that client.
3320 * @param cls closure, NULL
3321 * @param client identification of the client
3322 * @param app_ctx our `struct TransportClient`
3325 client_disconnect_cb (void *cls,
3326 struct GNUNET_SERVICE_Client *client,
3329 struct TransportClient *tc = app_ctx;
3333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3334 "Client %p disconnected, cleaning up.\n",
3336 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3342 struct PendingMessage *pm;
3344 while (NULL != (pm = tc->details.core.pending_msg_head))
3346 GNUNET_CONTAINER_MDLL_remove (client,
3347 tc->details.core.pending_msg_head,
3348 tc->details.core.pending_msg_tail,
3356 case CT_COMMUNICATOR: {
3358 struct AddressListEntry *ale;
3360 while (NULL != (q = tc->details.communicator.queue_head))
3362 while (NULL != (ale = tc->details.communicator.addr_head))
3363 free_address_list_entry (ale);
3364 GNUNET_free (tc->details.communicator.address_prefix);
3367 case CT_APPLICATION:
3368 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3371 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3379 * Iterator telling new CORE client about all existing
3380 * connections to peers.
3382 * @param cls the new `struct TransportClient`
3383 * @param pid a connected peer
3384 * @param value the `struct Neighbour` with more information
3385 * @return #GNUNET_OK (continue to iterate)
3388 notify_client_connect_info (void *cls,
3389 const struct GNUNET_PeerIdentity *pid,
3392 struct TransportClient *tc = cls;
3395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3396 "Telling new CORE client about existing connection to %s\n",
3398 core_send_connect_info (tc, pid);
3404 * Initialize a "CORE" client. We got a start message from this
3405 * client, so add it to the list of clients for broadcasting of
3408 * @param cls the client
3409 * @param start the start message that was sent
3412 handle_client_start (void *cls, const struct StartMessage *start)
3414 struct TransportClient *tc = cls;
3417 options = ntohl (start->options);
3418 if ((0 != (1 & options)) &&
3419 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3421 /* client thinks this is a different peer, reject */
3423 GNUNET_SERVICE_client_drop (tc->client);
3426 if (CT_NONE != tc->type)
3429 GNUNET_SERVICE_client_drop (tc->client);
3433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3434 "New CORE client with PID %s registered\n",
3435 GNUNET_i2s (&start->self));
3436 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3437 ¬ify_client_connect_info,
3439 GNUNET_SERVICE_client_continue (tc->client);
3444 * Client asked for transmission to a peer. Process the request.
3446 * @param cls the client
3447 * @param obm the send message that was sent
3450 check_client_send (void *cls, const struct OutboundMessage *obm)
3452 struct TransportClient *tc = cls;
3454 const struct GNUNET_MessageHeader *obmm;
3456 if (CT_CORE != tc->type)
3459 return GNUNET_SYSERR;
3461 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3462 if (size < sizeof (struct GNUNET_MessageHeader))
3465 return GNUNET_SYSERR;
3467 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3468 if (size != ntohs (obmm->size))
3471 return GNUNET_SYSERR;
3478 * Free fragment tree below @e root, excluding @e root itself.
3479 * FIXME: this does NOT seem to have the intended semantics
3480 * based on how this is called. Seems we generally DO expect
3481 * @a root to be free'ed itself as well!
3483 * @param root root of the tree to free
3486 free_fragment_tree (struct PendingMessage *root)
3488 struct PendingMessage *frag;
3490 while (NULL != (frag = root->head_frag))
3492 struct PendingAcknowledgement *pa;
3494 free_fragment_tree (frag);
3495 while (NULL != (pa = frag->pa_head))
3497 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3500 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3507 * Release memory associated with @a pm and remove @a pm from associated
3508 * data structures. @a pm must be a top-level pending message and not
3509 * a fragment in the tree. The entire tree is freed (if applicable).
3511 * @param pm the pending message to free
3514 free_pending_message (struct PendingMessage *pm)
3516 struct TransportClient *tc = pm->client;
3517 struct Neighbour *target = pm->target;
3518 struct DistanceVectorHop *dvh = pm->dvh;
3519 struct PendingAcknowledgement *pa;
3523 GNUNET_CONTAINER_MDLL_remove (client,
3524 tc->details.core.pending_msg_head,
3525 tc->details.core.pending_msg_tail,
3530 GNUNET_CONTAINER_MDLL_remove (dvh,
3531 dvh->pending_msg_head,
3532 dvh->pending_msg_tail,
3535 GNUNET_CONTAINER_MDLL_remove (neighbour,
3536 target->pending_msg_head,
3537 target->pending_msg_tail,
3539 while (NULL != (pa = pm->pa_head))
3541 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3545 free_fragment_tree (pm);
3548 GNUNET_assert (pm == pm->qe->pm);
3551 GNUNET_free_non_null (pm->bpm);
3557 * Send a response to the @a pm that we have processed a "send"
3558 * request. Sends a confirmation to the "core" client responsible for
3559 * the original request and free's @a pm.
3561 * @param pm handle to the original pending message
3564 client_send_response (struct PendingMessage *pm)
3566 struct TransportClient *tc = pm->client;
3567 struct Neighbour *target = pm->target;
3568 struct GNUNET_MQ_Envelope *env;
3569 struct SendOkMessage *som;
3573 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3574 som->peer = target->pid;
3575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3576 "Confirming transmission to %s\n",
3577 GNUNET_i2s (&pm->target->pid));
3578 GNUNET_MQ_send (tc->mq, env);
3580 free_pending_message (pm);
3585 * Create a DV Box message.
3587 * @param total_hops how many hops did the message take so far
3588 * @param num_hops length of the @a hops array
3589 * @param origin origin of the message
3590 * @param hops next peer(s) to the destination, including destination
3591 * @param payload encrypted (!) payload of the box
3592 * @param payload_size number of bytes in @a payload
3593 * @return boxed message (caller must #GNUNET_free() it).
3595 static struct TransportDVBoxMessage *
3596 create_dv_box (uint16_t total_hops,
3597 const struct GNUNET_PeerIdentity *origin,
3598 const struct GNUNET_PeerIdentity *target,
3600 const struct GNUNET_PeerIdentity *hops,
3601 const void *payload,
3602 uint16_t payload_size)
3604 struct TransportDVBoxMessage *dvb;
3605 struct GNUNET_PeerIdentity *dhops;
3607 GNUNET_assert (UINT16_MAX <
3608 sizeof (struct TransportDVBoxMessage) +
3609 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3611 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3612 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3615 htons (sizeof (struct TransportDVBoxMessage) +
3616 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3617 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3618 dvb->total_hops = htons (total_hops);
3619 dvb->num_hops = htons (num_hops + 1);
3620 dvb->origin = *origin;
3621 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3622 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3623 dhops[num_hops] = *target;
3624 memcpy (&dhops[num_hops + 1], payload, payload_size);
3626 if (GNUNET_EXTRA_LOGGING > 0)
3630 path = GNUNET_strdup (GNUNET_i2s (&dvb->origin));
3631 for (unsigned int i = 0; i <= num_hops; i++)
3635 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
3639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3640 "Creating DVBox for %u bytes of payload via %s\n",
3641 (unsigned int) payload_size,
3651 * Pick @a hops_array_length random DV paths satisfying @a options
3653 * @param dv data structure to pick paths from
3654 * @param options constraints to satisfy
3655 * @param hops_array[out] set to the result
3656 * @param hops_array_length length of the @a hops_array
3657 * @return number of entries set in @a hops_array
3660 pick_random_dv_hops (const struct DistanceVector *dv,
3661 enum RouteMessageOptions options,
3662 struct DistanceVectorHop **hops_array,
3663 unsigned int hops_array_length)
3665 uint64_t choices[hops_array_length];
3667 unsigned int dv_count;
3669 /* Pick random vectors, but weighted by distance, giving more weight
3670 to shorter vectors */
3673 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3676 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3677 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3678 .rel_value_us == 0))
3679 continue; /* pos unconfirmed and confirmed required */
3680 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3685 if (dv_count <= hops_array_length)
3688 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3690 hops_array[dv_count++] = pos;
3693 for (unsigned int i = 0; i < hops_array_length; i++)
3696 while (GNUNET_NO == ok)
3699 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3701 for (unsigned int j = 0; j < i; j++)
3702 if (choices[i] == choices[j])
3711 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3714 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3716 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3717 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3718 .rel_value_us == 0))
3719 continue; /* pos unconfirmed and confirmed required */
3720 for (unsigned int i = 0; i < hops_array_length; i++)
3721 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3722 hops_array[dv_count++] = pos;
3730 * Client asked for transmission to a peer. Process the request.
3732 * @param cls the client
3733 * @param obm the send message that was sent
3736 handle_client_send (void *cls, const struct OutboundMessage *obm)
3738 struct TransportClient *tc = cls;
3739 struct PendingMessage *pm;
3740 const struct GNUNET_MessageHeader *obmm;
3741 struct Neighbour *target;
3742 struct DistanceVector *dv;
3743 struct DistanceVectorHop *dvh;
3746 const void *payload;
3747 size_t payload_size;
3748 struct TransportDVBoxMessage *dvb;
3749 struct VirtualLink *vl;
3750 enum GNUNET_MQ_PriorityPreferences pp;
3752 GNUNET_assert (CT_CORE == tc->type);
3753 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3754 bytes_msg = ntohs (obmm->size);
3755 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
3756 vl = GNUNET_CONTAINER_multipeermap_get (links, &obm->peer);
3759 /* Failure: don't have this peer as a neighbour (anymore).
3760 Might have gone down asynchronously, so this is NOT
3761 a protocol violation by CORE. Still count the event,
3762 as this should be rare. */
3763 GNUNET_SERVICE_client_continue (tc->client);
3764 GNUNET_STATISTICS_update (GST_stats,
3765 "# messages dropped (neighbour unknown)",
3770 target = lookup_neighbour (&obm->peer);
3772 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3775 GNUNET_assert ((NULL != target) || (NULL != dv));
3776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3777 "Sending %u bytes to %s using %s\n",
3779 GNUNET_i2s (&obm->peer),
3780 (NULL == target) ? "distance vector path" : "direct queue");
3784 struct DistanceVectorHop *dvh;
3786 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3787 GNUNET_assert (1 == res);
3788 target = dvh->next_hop;
3789 /* FIXME: encrypt bytes_msg at &obm[1] to &obm->peer first! */
3790 dvb = create_dv_box (0,
3798 payload_size = ntohs (dvb->header.size);
3805 payload_size = bytes_msg;
3808 was_empty = (NULL == target->pending_msg_head);
3809 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3812 pm->target = target;
3813 pm->bytes_msg = payload_size;
3814 memcpy (&pm[1], payload, payload_size);
3815 GNUNET_free_non_null (dvb);
3820 GNUNET_CONTAINER_MDLL_insert (dvh,
3821 dvh->pending_msg_head,
3822 dvh->pending_msg_tail,
3825 GNUNET_CONTAINER_MDLL_insert (neighbour,
3826 target->pending_msg_head,
3827 target->pending_msg_tail,
3829 GNUNET_CONTAINER_MDLL_insert (client,
3830 tc->details.core.pending_msg_head,
3831 tc->details.core.pending_msg_tail,
3834 return; /* all queues must already be busy */
3835 for (struct Queue *queue = target->queue_head; NULL != queue;
3836 queue = queue->next_neighbour)
3838 /* try transmission on any queue that is idle */
3839 if (NULL == queue->transmit_task)
3841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3842 "Queue %llu to %s is idle, triggering transmission\n",
3843 (unsigned long long) queue->qid,
3844 GNUNET_i2s (&queue->neighbour->pid));
3845 queue->transmit_task =
3846 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3853 * Communicator started. Test message is well-formed.
3855 * @param cls the client
3856 * @param cam the send message that was sent
3859 check_communicator_available (
3861 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3863 struct TransportClient *tc = cls;
3866 if (CT_NONE != tc->type)
3869 return GNUNET_SYSERR;
3871 tc->type = CT_COMMUNICATOR;
3872 size = ntohs (cam->header.size) - sizeof (*cam);
3874 return GNUNET_OK; /* receive-only communicator */
3875 GNUNET_MQ_check_zero_termination (cam);
3881 * Send ACK to communicator (if requested) and free @a cmc.
3883 * @param cmc context for which we are done handling the message
3886 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3888 if (0 != ntohl (cmc->im.fc_on))
3890 /* send ACK when done to communicator for flow control! */
3891 struct GNUNET_MQ_Envelope *env;
3892 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3894 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3895 ack->reserved = htonl (0);
3896 ack->fc_id = cmc->im.fc_id;
3897 ack->sender = cmc->im.sender;
3898 GNUNET_MQ_send (cmc->tc->mq, env);
3900 GNUNET_SERVICE_client_continue (cmc->tc->client);
3906 * Client confirms that it is done handling message(s) to a particular
3907 * peer. We may now provide more messages to CORE for this peer.
3909 * Notifies the respective queues that more messages can now be received.
3911 * @param cls the client
3912 * @param rom the message that was sent
3915 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
3917 struct TransportClient *tc = cls;
3918 struct VirtualLink *vl;
3920 struct CommunicatorMessageContext *cmc;
3922 if (CT_CORE != tc->type)
3925 GNUNET_SERVICE_client_drop (tc->client);
3928 vl = GNUNET_CONTAINER_multipeermap_get (links, &rom->peer);
3931 GNUNET_STATISTICS_update (GST_stats,
3932 "# RECV_OK dropped: virtual link unknown",
3935 GNUNET_SERVICE_client_continue (tc->client);
3938 delta = ntohl (rom->increase_window_delta);
3939 vl->core_recv_window += delta;
3940 if (vl->core_recv_window <= 0)
3942 /* resume communicators */
3943 while (NULL != (cmc = vl->cmc_tail))
3945 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
3946 finish_cmc_handling (cmc);
3952 * Communicator started. Process the request.
3954 * @param cls the client
3955 * @param cam the send message that was sent
3958 handle_communicator_available (
3960 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3962 struct TransportClient *tc = cls;
3965 size = ntohs (cam->header.size) - sizeof (*cam);
3968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3969 "Receive-only communicator connected\n");
3970 return; /* receive-only communicator */
3972 tc->details.communicator.address_prefix =
3973 GNUNET_strdup ((const char *) &cam[1]);
3974 tc->details.communicator.cc =
3975 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3977 "Communicator with prefix `%s' connected\n",
3978 tc->details.communicator.address_prefix);
3979 GNUNET_SERVICE_client_continue (tc->client);
3984 * Communicator requests backchannel transmission. Check the request.
3986 * @param cls the client
3987 * @param cb the send message that was sent
3988 * @return #GNUNET_OK if message is well-formed
3991 check_communicator_backchannel (
3993 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3995 const struct GNUNET_MessageHeader *inbox;
4001 msize = ntohs (cb->header.size) - sizeof (*cb);
4002 if (((size_t) (UINT16_MAX - msize)) >
4003 sizeof (struct TransportBackchannelEncapsulationMessage) +
4004 sizeof (struct TransportBackchannelRequestPayloadP))
4007 return GNUNET_SYSERR;
4009 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4010 isize = ntohs (inbox->size);
4014 return GNUNET_SYSERR;
4016 is = (const char *) inbox;
4019 GNUNET_assert (msize > 0);
4020 if ('\0' != is[msize - 1])
4023 return GNUNET_SYSERR;
4030 * Remove memory used by expired ephemeral keys.
4035 expire_ephemerals (void *cls)
4037 struct EphemeralCacheEntry *ece;
4040 ephemeral_task = NULL;
4041 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
4043 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4046 free_ephemeral (ece);
4049 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4058 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists,
4059 * generate one, cache it and return it.
4061 * @param pid peer to look up ephemeral for
4062 * @param private_key[out] set to the private key
4063 * @param ephemeral_key[out] set to the key
4064 * @param ephemeral_sender_sig[out] set to the signature
4065 * @param monotime[out] set to the monotime used for the signature
4068 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
4069 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
4070 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
4071 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
4072 struct GNUNET_TIME_Absolute *monotime)
4074 struct EphemeralCacheEntry *ece;
4075 struct EphemeralConfirmationPS ec;
4077 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
4078 if ((NULL != ece) &&
4079 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4082 free_ephemeral (ece);
4087 ece = GNUNET_new (struct EphemeralCacheEntry);
4089 ece->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4090 ece->ephemeral_validity =
4091 GNUNET_TIME_absolute_add (ece->monotime, EPHEMERAL_VALIDITY);
4092 GNUNET_assert (GNUNET_OK ==
4093 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
4094 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
4095 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4096 ec.purpose.size = htonl (sizeof (ec));
4098 ec.ephemeral_key = ece->ephemeral_key;
4099 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4103 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
4105 ece->ephemeral_validity.abs_value_us);
4106 GNUNET_assert (GNUNET_OK ==
4107 GNUNET_CONTAINER_multipeermap_put (
4111 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4112 if (NULL == ephemeral_task)
4113 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4117 *private_key = ece->private_key;
4118 *ephemeral_key = ece->ephemeral_key;
4119 *ephemeral_sender_sig = ece->sender_sig;
4120 *monotime = ece->monotime;
4125 * Send the control message @a payload on @a queue.
4127 * @param queue the queue to use for transmission
4128 * @param pm pending message to update once transmission is done, may be NULL!
4129 * @param payload the payload to send (encapsulated in a
4130 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4131 * @param payload_size number of bytes in @a payload
4134 queue_send_msg (struct Queue *queue,
4135 struct PendingMessage *pm,
4136 const void *payload,
4137 size_t payload_size)
4139 struct Neighbour *n = queue->neighbour;
4140 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4141 struct GNUNET_MQ_Envelope *env;
4143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4144 "Queueing %u bytes of payload for transmission on queue %llu to %s\n",
4145 (unsigned int) payload_size,
4146 (unsigned long long) queue->qid,
4147 GNUNET_i2s (&queue->neighbour->pid));
4148 env = GNUNET_MQ_msg_extra (smt,
4150 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4151 smt->qid = queue->qid;
4152 smt->mid = queue->mid_gen;
4153 smt->receiver = n->pid;
4154 memcpy (&smt[1], payload, payload_size);
4156 /* Pass the env to the communicator of queue for transmission. */
4157 struct QueueEntry *qe;
4159 qe = GNUNET_new (struct QueueEntry);
4160 qe->mid = queue->mid_gen++;
4165 GNUNET_assert (NULL == pm->qe);
4168 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4169 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4170 queue->queue_length++;
4171 queue->tc->details.communicator.total_queue_length++;
4172 GNUNET_MQ_send (queue->tc->mq, env);
4178 * Pick a queue of @a n under constraints @a options and schedule
4179 * transmission of @a hdr.
4181 * @param n neighbour to send to
4182 * @param hdr message to send as payload
4183 * @param options whether queues must be confirmed or not,
4184 * and whether we may pick multiple (2) queues
4187 route_via_neighbour (const struct Neighbour *n,
4188 const struct GNUNET_MessageHeader *hdr,
4189 enum RouteMessageOptions options)
4191 struct GNUNET_TIME_Absolute now;
4192 unsigned int candidates;
4196 /* Pick one or two 'random' queues from n (under constraints of options) */
4197 now = GNUNET_TIME_absolute_get ();
4198 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4199 weight in the future; weight could be assigned by observed
4200 bandwidth (note: not sure if we should do this for this type
4201 of control traffic though). */
4203 for (struct Queue *pos = n->queue_head; NULL != pos;
4204 pos = pos->next_neighbour)
4206 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4207 (pos->validated_until.abs_value_us > now.abs_value_us))
4210 if (0 == candidates)
4212 /* This can happen rarely if the last confirmed queue timed
4213 out just as we were beginning to process this message. */
4214 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4215 "Could not route message of type %u to %s: no valid queue\n",
4217 GNUNET_i2s (&n->pid));
4218 GNUNET_STATISTICS_update (GST_stats,
4219 "# route selection failed (all no valid queue)",
4224 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4225 if (0 == (options & RMO_REDUNDANT))
4226 sel2 = candidates; /* picks none! */
4228 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4230 for (struct Queue *pos = n->queue_head; NULL != pos;
4231 pos = pos->next_neighbour)
4233 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4234 (pos->validated_until.abs_value_us > now.abs_value_us))
4236 if ((sel1 == candidates) || (sel2 == candidates))
4238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4239 "Routing message of type %u to %s using %s (#%u)\n",
4241 GNUNET_i2s (&n->pid),
4243 (sel1 == candidates) ? 1 : 2);
4244 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4253 * Given a distance vector path @a dvh route @a payload to
4254 * the ultimate destination respecting @a options.
4255 * Sets up the boxed message and queues it at the next hop.
4257 * @param dvh choice of the path for the message
4258 * @param payload encrypted body to transmit
4259 * @param payload_len number of bytes in @a payload
4260 * @param options options to use for control
4263 forward_via_dvh (const struct DistanceVectorHop *dvh,
4264 const void *payload,
4266 enum RouteMessageOptions options)
4268 struct TransportDVBoxMessage *dvb;
4270 dvb = create_dv_box (0,
4277 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4283 * Pick a path of @a dv under constraints @a options and schedule
4284 * transmission of @a hdr.
4286 * @param n neighbour to send to
4287 * @param hdr message to send as payload
4288 * @param options whether path must be confirmed or not
4289 * and whether we may pick multiple (2) paths
4292 route_via_dv (const struct DistanceVector *dv,
4293 const struct GNUNET_MessageHeader *hdr,
4294 enum RouteMessageOptions options)
4296 struct DistanceVectorHop *hops[2];
4299 res = pick_random_dv_hops (dv,
4302 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4305 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4306 "Failed to route message, could not determine DV path\n");
4309 // FIXME: we should encrypt `hdr` here first!
4310 for (unsigned int i = 0; i < res; i++)
4312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4313 "Routing message of type %u to %s using DV (#%u/%u)\n",
4315 GNUNET_i2s (&dv->target),
4318 forward_via_dvh (hops[i],
4321 hdr->size), /* FIXME: can't do this once encrypted... */
4322 options & (~RMO_REDUNDANT));
4328 * We need to transmit @a hdr to @a target. If necessary, this may
4329 * involve DV routing.
4331 * @param target peer to receive @a hdr
4332 * @param hdr header of the message to route and #GNUNET_free()
4333 * @param options which transmission channels are allowed
4336 route_message (const struct GNUNET_PeerIdentity *target,
4337 struct GNUNET_MessageHeader *hdr,
4338 enum RouteMessageOptions options)
4340 struct VirtualLink *vl;
4341 struct Neighbour *n;
4342 struct DistanceVector *dv;
4344 vl = GNUNET_CONTAINER_multipeermap_get (links, target);
4346 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4347 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4349 /* if confirmed is required, and we do not have anything
4350 confirmed, drop respective options */
4352 n = lookup_neighbour (target);
4353 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4354 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4356 if ((NULL == n) && (NULL == dv))
4358 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4359 "Cannot route message of type %u to %s: no route\n",
4361 GNUNET_i2s (target));
4362 GNUNET_STATISTICS_update (GST_stats,
4363 "# Messages dropped in routing: no acceptable method",
4369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4370 "Routing message of type %u to %s with options %X\n",
4372 GNUNET_i2s (target),
4373 (unsigned int) options);
4374 /* If both dv and n are possible and we must choose:
4375 flip a coin for the choice between the two; for now 50/50 */
4376 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4378 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4383 if ((NULL != n) && (NULL != dv))
4384 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4385 enough for redunancy, so clear the flag. */
4388 route_via_neighbour (n, hdr, options);
4392 route_via_dv (dv, hdr, options);
4399 * Structure of the key material used to encrypt backchannel messages.
4401 struct BackchannelKeyState
4404 * State of our block cipher.
4406 gcry_cipher_hd_t cipher;
4409 * Actual key material.
4415 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4417 struct GNUNET_CRYPTO_AuthKey hmac_key;
4420 * Symmetric key to use for encryption.
4422 char aes_key[256 / 8];
4425 * Counter value to use during setup.
4427 char aes_ctr[128 / 8];
4434 * Given the key material in @a km and the initialization vector
4435 * @a iv, setup the key material for the backchannel in @a key.
4437 * @param km raw master secret
4438 * @param iv initialization vector
4439 * @param key[out] symmetric cipher and HMAC state to generate
4442 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4443 const struct GNUNET_ShortHashCode *iv,
4444 struct BackchannelKeyState *key)
4446 /* must match #dh_key_derive_eph_pub */
4447 GNUNET_assert (GNUNET_YES ==
4448 GNUNET_CRYPTO_kdf (&key->material,
4449 sizeof (key->material),
4450 "transport-backchannel-key",
4451 strlen ("transport-backchannel-key"),
4456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4457 "Deriving backchannel key based on KM %s and IV %s\n",
4460 gcry_cipher_open (&key->cipher,
4461 GCRY_CIPHER_AES256 /* low level: go for speed */,
4462 GCRY_CIPHER_MODE_CTR,
4464 gcry_cipher_setkey (key->cipher,
4465 &key->material.aes_key,
4466 sizeof (key->material.aes_key));
4467 gcry_cipher_setctr (key->cipher,
4468 &key->material.aes_ctr,
4469 sizeof (key->material.aes_ctr));
4474 * Derive backchannel encryption key material from @a priv_ephemeral
4475 * and @a target and @a iv.
4477 * @param priv_ephemeral ephemeral private key to use
4478 * @param target the target peer to encrypt to
4479 * @param iv unique IV to use
4480 * @param key[out] set to the key material
4483 dh_key_derive_eph_pid (
4484 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4485 const struct GNUNET_PeerIdentity *target,
4486 const struct GNUNET_ShortHashCode *iv,
4487 struct BackchannelKeyState *key)
4489 struct GNUNET_HashCode km;
4491 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4492 &target->public_key,
4494 bc_setup_key_state_from_km (&km, iv, key);
4499 * Derive backchannel encryption key material from #GST_my_private_key
4500 * and @a pub_ephemeral and @a iv.
4502 * @param priv_ephemeral ephemeral private key to use
4503 * @param target the target peer to encrypt to
4504 * @param iv unique IV to use
4505 * @param key[out] set to the key material
4508 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4509 const struct GNUNET_ShortHashCode *iv,
4510 struct BackchannelKeyState *key)
4512 struct GNUNET_HashCode km;
4514 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4517 bc_setup_key_state_from_km (&km, iv, key);
4522 * Do HMAC calculation for backchannel messages over @a data using key
4523 * material from @a key.
4525 * @param key key material (from DH)
4526 * @param hmac[out] set to the HMAC
4527 * @param data data to perform HMAC calculation over
4528 * @param data_size number of bytes in @a data
4531 bc_hmac (const struct BackchannelKeyState *key,
4532 struct GNUNET_HashCode *hmac,
4536 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4541 * Perform backchannel encryption using symmetric secret in @a key
4542 * to encrypt data from @a in to @a dst.
4544 * @param key[in,out] key material to use
4545 * @param dst where to write the result
4546 * @param in input data to encrypt (plaintext)
4547 * @param in_size number of bytes of input in @a in and available at @a dst
4550 bc_encrypt (struct BackchannelKeyState *key,
4556 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4561 * Perform backchannel encryption using symmetric secret in @a key
4562 * to encrypt data from @a in to @a dst.
4564 * @param key[in,out] key material to use
4565 * @param ciph cipher text to decrypt
4566 * @param out[out] output data to generate (plaintext)
4567 * @param out_size number of bytes of input in @a ciph and available in @a out
4570 bc_decrypt (struct BackchannelKeyState *key,
4576 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4581 * Clean up key material in @a key.
4583 * @param key key material to clean up (memory must not be free'd!)
4586 bc_key_clean (struct BackchannelKeyState *key)
4588 gcry_cipher_close (key->cipher);
4589 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4594 * Communicator requests backchannel transmission. Process the request.
4596 * @param cls the client
4597 * @param cb the send message that was sent
4600 handle_communicator_backchannel (
4602 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4604 struct TransportClient *tc = cls;
4605 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4606 struct GNUNET_TIME_Absolute monotime;
4607 struct TransportBackchannelEncapsulationMessage *enc;
4608 struct TransportBackchannelRequestPayloadP ppay;
4609 struct BackchannelKeyState key;
4614 const struct GNUNET_MessageHeader *inbox;
4617 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4618 /* 0-termination of 'is' was checked already in
4619 #check_communicator_backchannel() */
4620 is = (const char *) &cb[1];
4621 is += ntohs (inbox->size);
4622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4623 "Preparing backchannel transmission to %s:%s of type %u\n",
4624 GNUNET_i2s (&cb->pid),
4626 ntohs (inbox->size));
4628 /* encapsulate and encrypt message */
4630 /* FIXME: this should be done with the DV logic for all
4631 DV messages, NOT here only for backchannel! */
4632 msize = ntohs (cb->header.size) - sizeof (*cb) +
4633 sizeof (struct TransportBackchannelRequestPayloadP);
4634 enc = GNUNET_malloc (sizeof (*enc) + msize);
4636 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4637 enc->header.size = htons (sizeof (*enc) + msize);
4638 enc->target = cb->pid;
4639 lookup_ephemeral (&cb->pid,
4641 &enc->ephemeral_key,
4644 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4647 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4648 ppay.monotonic_time = GNUNET_TIME_absolute_hton (monotime);
4649 mpos = (char *) &enc[1];
4650 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4653 &mpos[sizeof (ppay)],
4654 ntohs (cb->header.size) - sizeof (*cb));
4658 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4659 bc_key_clean (&key);
4660 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4661 GNUNET_SERVICE_client_continue (tc->client);
4666 * Address of our peer added. Test message is well-formed.
4668 * @param cls the client
4669 * @param aam the send message that was sent
4670 * @return #GNUNET_OK if message is well-formed
4673 check_add_address (void *cls,
4674 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4676 struct TransportClient *tc = cls;
4678 if (CT_COMMUNICATOR != tc->type)
4681 return GNUNET_SYSERR;
4683 GNUNET_MQ_check_zero_termination (aam);
4689 * Ask peerstore to store our address.
4691 * @param cls an `struct AddressListEntry *`
4694 store_pi (void *cls);
4698 * Function called when peerstore is done storing our address.
4700 * @param cls a `struct AddressListEntry`
4701 * @param success #GNUNET_YES if peerstore was successful
4704 peerstore_store_own_cb (void *cls, int success)
4706 struct AddressListEntry *ale = cls;
4709 if (GNUNET_YES != success)
4710 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4711 "Failed to store our own address `%s' in peerstore!\n",
4714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4715 "Successfully stored our own address `%s' in peerstore!\n",
4717 /* refresh period is 1/4 of expiration time, that should be plenty
4718 without being excessive. */
4720 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4728 * Ask peerstore to store our address.
4730 * @param cls an `struct AddressListEntry *`
4733 store_pi (void *cls)
4735 struct AddressListEntry *ale = cls;
4738 struct GNUNET_TIME_Absolute expiration;
4741 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4743 "Storing our address `%s' in peerstore until %s!\n",
4745 GNUNET_STRINGS_absolute_time_to_string (expiration));
4746 GNUNET_HELLO_sign_address (ale->address,
4752 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4755 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4759 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4760 &peerstore_store_own_cb,
4763 if (NULL == ale->sc)
4765 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4766 "Failed to store our address `%s' with peerstore\n",
4769 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4775 * Address of our peer added. Process the request.
4777 * @param cls the client
4778 * @param aam the send message that was sent
4781 handle_add_address (void *cls,
4782 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4784 struct TransportClient *tc = cls;
4785 struct AddressListEntry *ale;
4788 /* 0-termination of &aam[1] was checked in #check_add_address */
4789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4790 "Communicator added address `%s'!\n",
4791 (const char *) &aam[1]);
4792 slen = ntohs (aam->header.size) - sizeof (*aam);
4793 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4795 ale->address = (const char *) &ale[1];
4796 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4797 ale->aid = aam->aid;
4798 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4799 memcpy (&ale[1], &aam[1], slen);
4800 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4801 tc->details.communicator.addr_tail,
4803 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4804 GNUNET_SERVICE_client_continue (tc->client);
4809 * Address of our peer deleted. Process the request.
4811 * @param cls the client
4812 * @param dam the send message that was sent
4815 handle_del_address (void *cls,
4816 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4818 struct TransportClient *tc = cls;
4820 if (CT_COMMUNICATOR != tc->type)
4823 GNUNET_SERVICE_client_drop (tc->client);
4826 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4830 if (dam->aid != ale->aid)
4832 GNUNET_assert (ale->tc == tc);
4833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4834 "Communicator deleted address `%s'!\n",
4836 free_address_list_entry (ale);
4837 GNUNET_SERVICE_client_continue (tc->client);
4840 GNUNET_SERVICE_client_drop (tc->client);
4845 * Given an inbound message @a msg from a communicator @a cmc,
4846 * demultiplex it based on the type calling the right handler.
4848 * @param cmc context for demultiplexing
4849 * @param msg message to demultiplex
4852 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4853 const struct GNUNET_MessageHeader *msg);
4857 * Communicator gave us an unencapsulated message to pass as-is to
4858 * CORE. Process the request.
4860 * @param cls a `struct CommunicatorMessageContext` (must call
4861 * #finish_cmc_handling() when done)
4862 * @param mh the message that was received
4865 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4867 struct CommunicatorMessageContext *cmc = cls;
4868 struct VirtualLink *vl;
4869 uint16_t size = ntohs (mh->size);
4872 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4873 (size < sizeof (struct GNUNET_MessageHeader)))
4875 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4878 finish_cmc_handling (cmc);
4879 GNUNET_SERVICE_client_drop (client);
4882 vl = GNUNET_CONTAINER_multipeermap_get (links, &cmc->im.sender);
4885 /* FIXME: sender is giving us messages for CORE but we don't have
4886 the link up yet! I *suspect* this can happen right now (i.e.
4887 sender has verified us, but we didn't verify sender), but if
4888 we pass this on, CORE would be confused (link down, messages
4889 arrive). We should investigate more if this happens often,
4890 or in a persistent manner, and possibly do "something" about
4891 it. Thus logging as error for now. */
4892 GNUNET_break_op (0);
4893 GNUNET_STATISTICS_update (GST_stats,
4894 "# CORE messages droped (virtual link still down)",
4898 finish_cmc_handling (cmc);
4901 /* Forward to all CORE clients */
4902 have_core = GNUNET_NO;
4903 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4905 struct GNUNET_MQ_Envelope *env;
4906 struct InboundMessage *im;
4908 if (CT_CORE != tc->type)
4910 have_core = GNUNET_YES;
4911 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4912 im->peer = cmc->im.sender;
4913 memcpy (&im[1], mh, size);
4914 GNUNET_MQ_send (tc->mq, env);
4916 vl->core_recv_window--;
4917 if (GNUNET_NO == have_core)
4918 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4919 "Dropped message to CORE: no CORE client connected!\n");
4921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4922 "Delivered message from %s of type %u to CORE\n",
4923 GNUNET_i2s (&cmc->im.sender),
4925 if (vl->core_recv_window > 0)
4927 finish_cmc_handling (cmc);
4930 /* Wait with calling #finish_cmc_handling(cmc) until the message
4931 was processed by CORE MQs (for CORE flow control)! */
4932 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
4937 * Communicator gave us a fragment box. Check the message.
4939 * @param cls a `struct CommunicatorMessageContext`
4940 * @param fb the send message that was sent
4941 * @return #GNUNET_YES if message is well-formed
4944 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4946 uint16_t size = ntohs (fb->header.size);
4947 uint16_t bsize = size - sizeof (*fb);
4952 GNUNET_break_op (0);
4953 return GNUNET_SYSERR;
4955 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4957 GNUNET_break_op (0);
4958 return GNUNET_SYSERR;
4960 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4962 GNUNET_break_op (0);
4963 return GNUNET_SYSERR;
4970 * Clean up an idle cummulative acknowledgement data structure.
4972 * @param cls a `struct AcknowledgementCummulator *`
4975 destroy_ack_cummulator (void *cls)
4977 struct AcknowledgementCummulator *ac = cls;
4980 GNUNET_assert (0 == ac->num_acks);
4983 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4989 * Do the transmission of a cummulative acknowledgement now.
4991 * @param cls a `struct AcknowledgementCummulator *`
4994 transmit_cummulative_ack_cb (void *cls)
4996 struct AcknowledgementCummulator *ac = cls;
4997 struct TransportReliabilityAckMessage *ack;
4998 struct TransportCummulativeAckPayloadP *ap;
5001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5002 "Sending ACK with %u components to %s\n",
5004 GNUNET_i2s (&ac->target));
5005 GNUNET_assert (0 < ac->ack_counter);
5006 ack = GNUNET_malloc (sizeof (*ack) +
5008 sizeof (struct TransportCummulativeAckPayloadP));
5009 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5011 htons (sizeof (*ack) +
5012 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
5013 ack->ack_counter = htonl (ac->ack_counter++);
5014 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5015 for (unsigned int i = 0; i < ac->ack_counter; i++)
5017 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5018 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5019 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5021 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
5023 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5024 &destroy_ack_cummulator,
5030 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5031 * transmission by at most @a ack_delay.
5033 * @param pid target peer
5034 * @param ack_uuid UUID to ack
5035 * @param max_delay how long can the ACK wait
5038 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5039 const struct AcknowledgementUUIDP *ack_uuid,
5040 struct GNUNET_TIME_Absolute max_delay)
5042 struct AcknowledgementCummulator *ac;
5044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5045 "Scheduling ACK %s for transmission to %s\n",
5046 GNUNET_sh2s (&ack_uuid->value),
5048 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5051 ac = GNUNET_new (struct AcknowledgementCummulator);
5053 ac->min_transmission_time = max_delay;
5054 GNUNET_assert (GNUNET_YES ==
5055 GNUNET_CONTAINER_multipeermap_put (
5059 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5063 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5065 /* must run immediately, ack buffer full! */
5066 GNUNET_SCHEDULER_cancel (ac->task);
5067 transmit_cummulative_ack_cb (ac);
5069 GNUNET_SCHEDULER_cancel (ac->task);
5070 ac->min_transmission_time =
5071 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5073 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5074 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5075 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5077 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5078 &transmit_cummulative_ack_cb,
5084 * Closure for #find_by_message_uuid.
5086 struct FindByMessageUuidContext
5091 struct MessageUUIDP message_uuid;
5094 * Set to the reassembly context if found.
5096 struct ReassemblyContext *rc;
5101 * Iterator called to find a reassembly context by the message UUID in the
5104 * @param cls a `struct FindByMessageUuidContext`
5105 * @param key a key (unused)
5106 * @param value a `struct ReassemblyContext`
5107 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5110 find_by_message_uuid (void *cls, uint32_t key, void *value)
5112 struct FindByMessageUuidContext *fc = cls;
5113 struct ReassemblyContext *rc = value;
5116 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5126 * Communicator gave us a fragment. Process the request.
5128 * @param cls a `struct CommunicatorMessageContext` (must call
5129 * #finish_cmc_handling() when done)
5130 * @param fb the message that was received
5133 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5135 struct CommunicatorMessageContext *cmc = cls;
5136 struct Neighbour *n;
5137 struct ReassemblyContext *rc;
5138 const struct GNUNET_MessageHeader *msg;
5143 struct GNUNET_TIME_Relative cdelay;
5144 struct FindByMessageUuidContext fc;
5146 n = lookup_neighbour (&cmc->im.sender);
5149 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5152 finish_cmc_handling (cmc);
5153 GNUNET_SERVICE_client_drop (client);
5156 if (NULL == n->reassembly_map)
5158 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5159 n->reassembly_heap =
5160 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5161 n->reassembly_timeout_task =
5162 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5163 &reassembly_cleanup_task,
5166 msize = ntohs (fb->msg_size);
5167 fc.message_uuid = fb->msg_uuid;
5169 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5171 &find_by_message_uuid,
5173 if (NULL == (rc = fc.rc))
5175 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5176 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5177 rc->msg_uuid = fb->msg_uuid;
5179 rc->msg_size = msize;
5180 rc->reassembly_timeout =
5181 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5182 rc->last_frag = GNUNET_TIME_absolute_get ();
5183 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5185 rc->reassembly_timeout.abs_value_us);
5186 GNUNET_assert (GNUNET_OK ==
5187 GNUNET_CONTAINER_multihashmap32_put (
5191 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5192 target = (char *) &rc[1];
5193 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5194 rc->msg_missing = rc->msg_size;
5195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5196 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5197 ntohs (fb->frag_off),
5199 GNUNET_i2s (&cmc->im.sender),
5200 (unsigned int) fb->msg_uuid.uuid);
5204 target = (char *) &rc[1];
5205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5206 "Received fragment at offset %u/%u from %s for message %u\n",
5207 ntohs (fb->frag_off),
5209 GNUNET_i2s (&cmc->im.sender),
5210 (unsigned int) fb->msg_uuid.uuid);
5212 if (msize != rc->msg_size)
5215 finish_cmc_handling (cmc);
5220 fsize = ntohs (fb->header.size) - sizeof (*fb);
5224 finish_cmc_handling (cmc);
5227 frag_off = ntohs (fb->frag_off);
5228 memcpy (&target[frag_off], &fb[1], fsize);
5229 /* update bitfield and msg_missing */
5230 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5232 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5234 rc->bitfield[i / 8] |= (1 << (i % 8));
5239 /* Compute cummulative ACK */
5240 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5241 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5242 if (0 == rc->msg_missing)
5243 cdelay = GNUNET_TIME_UNIT_ZERO;
5244 cummulative_ack (&cmc->im.sender,
5246 GNUNET_TIME_relative_to_absolute (cdelay));
5247 rc->last_frag = GNUNET_TIME_absolute_get ();
5248 /* is reassembly complete? */
5249 if (0 != rc->msg_missing)
5251 finish_cmc_handling (cmc);
5254 /* reassembly is complete, verify result */
5255 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5256 if (ntohs (msg->size) != rc->msg_size)
5259 free_reassembly_context (rc);
5260 finish_cmc_handling (cmc);
5263 /* successful reassembly */
5264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5265 "Fragment reassembly complete for message %u\n",
5266 (unsigned int) fb->msg_uuid.uuid);
5267 /* FIXME: check that the resulting msg is NOT a
5268 DV Box or Reliability Box, as that is NOT allowed! */
5269 demultiplex_with_cmc (cmc, msg);
5270 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5271 en-route and we forget that we finished this reassembly immediately!
5272 -> keep around until timeout?
5273 -> shorten timeout based on ACK? */
5274 free_reassembly_context (rc);
5279 * Communicator gave us a reliability box. Check the message.
5281 * @param cls a `struct CommunicatorMessageContext`
5282 * @param rb the send message that was sent
5283 * @return #GNUNET_YES if message is well-formed
5286 check_reliability_box (void *cls,
5287 const struct TransportReliabilityBoxMessage *rb)
5290 GNUNET_MQ_check_boxed_message (rb);
5296 * Communicator gave us a reliability box. Process the request.
5298 * @param cls a `struct CommunicatorMessageContext` (must call
5299 * #finish_cmc_handling() when done)
5300 * @param rb the message that was received
5303 handle_reliability_box (void *cls,
5304 const struct TransportReliabilityBoxMessage *rb)
5306 struct CommunicatorMessageContext *cmc = cls;
5307 const struct GNUNET_MessageHeader *inbox =
5308 (const struct GNUNET_MessageHeader *) &rb[1];
5309 struct GNUNET_TIME_Relative rtt;
5311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5312 "Received reliability box from %s with UUID %s of type %u\n",
5313 GNUNET_i2s (&cmc->im.sender),
5314 GNUNET_sh2s (&rb->ack_uuid.value),
5315 (unsigned int) ntohs (inbox->type));
5316 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5317 do not really have an RTT for the
5318 *incoming* queue (should we have
5319 the sender add it to the rb message?) */
5323 (0 == ntohl (rb->ack_countdown))
5324 ? GNUNET_TIME_UNIT_ZERO_ABS
5325 : GNUNET_TIME_relative_to_absolute (
5326 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5327 /* continue with inner message */
5328 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5329 reliability box (not allowed!) */
5330 demultiplex_with_cmc (cmc, inbox);
5335 * Check if we have advanced to another age since the last time. If
5336 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5339 * @param pd[in,out] data to update
5340 * @param age current age
5343 update_pd_age (struct PerformanceData *pd, unsigned int age)
5347 if (age == pd->last_age)
5348 return; /* nothing to do */
5349 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5350 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5352 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5354 the->bytes_sent = 0;
5355 the->bytes_received = 0;
5362 * Update @a pd based on the latest @a rtt and the number of bytes
5363 * that were confirmed to be successfully transmitted.
5365 * @param pd[in,out] data to update
5366 * @param rtt latest round-trip time
5367 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5370 update_performance_data (struct PerformanceData *pd,
5371 struct GNUNET_TIME_Relative rtt,
5372 uint16_t bytes_transmitted_ok)
5374 uint64_t nval = rtt.rel_value_us;
5375 uint64_t oval = pd->aged_rtt.rel_value_us;
5376 unsigned int age = get_age ();
5377 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5379 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5382 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5383 update_pd_age (pd, age);
5384 the->bytes_received += bytes_transmitted_ok;
5389 * We have successfully transmitted data via @a q, update metrics.
5391 * @param q queue to update
5392 * @param rtt round trip time observed
5393 * @param bytes_transmitted_ok number of bytes successfully transmitted
5396 update_queue_performance (struct Queue *q,
5397 struct GNUNET_TIME_Relative rtt,
5398 uint16_t bytes_transmitted_ok)
5400 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5405 * We have successfully transmitted data via @a dvh, update metrics.
5407 * @param dvh distance vector path data to update
5408 * @param rtt round trip time observed
5409 * @param bytes_transmitted_ok number of bytes successfully transmitted
5412 update_dvh_performance (struct DistanceVectorHop *dvh,
5413 struct GNUNET_TIME_Relative rtt,
5414 uint16_t bytes_transmitted_ok)
5416 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5421 * The @a pa was acknowledged, process the acknowledgement.
5423 * @param pa the pending acknowledgement that was satisfied
5424 * @param ack_delay artificial delay from cummulative acks created by the
5428 handle_acknowledged (struct PendingAcknowledgement *pa,
5429 struct GNUNET_TIME_Relative ack_delay)
5431 struct PendingMessage *pm = pa->pm;
5432 struct GNUNET_TIME_Relative delay;
5434 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5435 if (delay.rel_value_us > ack_delay.rel_value_us)
5436 delay = GNUNET_TIME_UNIT_ZERO;
5438 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5439 if (NULL != pa->queue)
5440 update_queue_performance (pa->queue, delay, pa->message_size);
5441 if (NULL != pa->dvh)
5442 update_dvh_performance (pa->dvh, delay, pa->message_size);
5445 if (NULL != pm->frag_parent)
5447 pm = pm->frag_parent;
5448 free_fragment_tree (pa->pm);
5450 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5452 struct PendingMessage *parent = pm->frag_parent;
5454 free_fragment_tree (pm);
5457 if (NULL != pm->head_frag)
5458 pm = NULL; /* we are done, otherwise free 'pm' below */
5461 free_pending_message (pm);
5462 free_pending_acknowledgement (pa);
5467 * Communicator gave us a reliability ack. Check it is well-formed.
5469 * @param cls a `struct CommunicatorMessageContext` (unused)
5470 * @param ra the message that was received
5471 * @return #GNUNET_Ok if @a ra is well-formed
5474 check_reliability_ack (void *cls,
5475 const struct TransportReliabilityAckMessage *ra)
5477 unsigned int n_acks;
5480 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5481 sizeof (struct TransportCummulativeAckPayloadP);
5484 GNUNET_break_op (0);
5485 return GNUNET_SYSERR;
5487 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5488 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5490 GNUNET_break_op (0);
5491 return GNUNET_SYSERR;
5498 * Communicator gave us a reliability ack. Process the request.
5500 * @param cls a `struct CommunicatorMessageContext` (must call
5501 * #finish_cmc_handling() when done)
5502 * @param ra the message that was received
5505 handle_reliability_ack (void *cls,
5506 const struct TransportReliabilityAckMessage *ra)
5508 struct CommunicatorMessageContext *cmc = cls;
5509 const struct TransportCummulativeAckPayloadP *ack;
5510 struct PendingAcknowledgement *pa;
5511 unsigned int n_acks;
5512 uint32_t ack_counter;
5514 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5515 sizeof (struct TransportCummulativeAckPayloadP);
5516 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5517 for (unsigned int i = 0; i < n_acks; i++)
5520 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5523 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5524 "Received ACK from %s with UUID %s which is unknown to us!\n",
5525 GNUNET_i2s (&cmc->im.sender),
5526 GNUNET_sh2s (&ack[i].ack_uuid.value));
5527 GNUNET_STATISTICS_update (
5529 "# FRAGMENT_ACKS dropped, no matching pending message",
5534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5535 "Received ACK from %s with UUID %s\n",
5536 GNUNET_i2s (&cmc->im.sender),
5537 GNUNET_sh2s (&ack[i].ack_uuid.value));
5538 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5541 ack_counter = htonl (ra->ack_counter);
5542 (void) ack_counter; /* silence compiler warning for now */
5543 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5544 // (DV and/or Neighbour?)
5545 finish_cmc_handling (cmc);
5550 * Communicator gave us a backchannel encapsulation. Check the message.
5552 * @param cls a `struct CommunicatorMessageContext`
5553 * @param be the send message that was sent
5554 * @return #GNUNET_YES if message is well-formed
5557 check_backchannel_encapsulation (
5559 const struct TransportBackchannelEncapsulationMessage *be)
5561 uint16_t size = ntohs (be->header.size);
5564 if ((size - sizeof (*be)) <
5565 (sizeof (struct TransportBackchannelRequestPayloadP) +
5566 sizeof (struct GNUNET_MessageHeader)))
5568 GNUNET_break_op (0);
5569 return GNUNET_SYSERR;
5576 * We received the plaintext @a msg from backtalker @a b. Forward
5577 * it to the respective communicator.
5579 * @param b a backtalker
5580 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5581 * followed by the target name of the communicator
5582 * @param msg_size number of bytes in @a msg
5585 forward_backchannel_payload (struct Backtalker *b,
5589 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5590 struct GNUNET_MQ_Envelope *env;
5591 struct TransportClient *tc;
5592 const struct GNUNET_MessageHeader *mh;
5593 const char *target_communicator;
5596 /* Determine target_communicator and check @a msg is well-formed */
5598 mhs = ntohs (mh->size);
5599 if (mhs <= msg_size)
5601 GNUNET_break_op (0);
5604 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5605 if ('\0' != target_communicator[msg_size - mhs - 1])
5607 GNUNET_break_op (0);
5610 /* Find client providing this communicator */
5611 for (tc = clients_head; NULL != tc; tc = tc->next)
5612 if ((CT_COMMUNICATOR == tc->type) &&
5614 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5622 "# Backchannel message dropped: target communicator `%s' unknown",
5623 target_communicator);
5624 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5625 GNUNET_free (stastr);
5628 /* Finally, deliver backchannel message to communicator */
5629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5630 "Delivering backchannel message from %s of type %u to %s\n",
5631 GNUNET_i2s (&b->pid),
5633 target_communicator);
5634 env = GNUNET_MQ_msg_extra (
5637 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5639 memcpy (&cbi[1], msg, msg_size);
5640 GNUNET_MQ_send (tc->mq, env);
5645 * Free data structures associated with @a b.
5647 * @param b data structure to release
5650 free_backtalker (struct Backtalker *b)
5654 GNUNET_PEERSTORE_iterate_cancel (b->get);
5656 GNUNET_assert (NULL != b->cmc);
5657 finish_cmc_handling (b->cmc);
5660 if (NULL != b->task)
5662 GNUNET_SCHEDULER_cancel (b->task);
5667 GNUNET_PEERSTORE_store_cancel (b->sc);
5672 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5678 * Callback to free backtalker records.
5682 * @param value a `struct Backtalker`
5683 * @return #GNUNET_OK (always)
5686 free_backtalker_cb (void *cls,
5687 const struct GNUNET_PeerIdentity *pid,
5690 struct Backtalker *b = value;
5694 free_backtalker (b);
5700 * Function called when it is time to clean up a backtalker.
5702 * @param cls a `struct Backtalker`
5705 backtalker_timeout_cb (void *cls)
5707 struct Backtalker *b = cls;
5710 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5712 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5715 GNUNET_assert (NULL == b->sc);
5716 free_backtalker (b);
5721 * Function called with the monotonic time of a backtalker
5722 * by PEERSTORE. Updates the time and continues processing.
5724 * @param cls a `struct Backtalker`
5725 * @param record the information found, NULL for the last call
5726 * @param emsg error message
5729 backtalker_monotime_cb (void *cls,
5730 const struct GNUNET_PEERSTORE_Record *record,
5733 struct Backtalker *b = cls;
5734 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5735 struct GNUNET_TIME_Absolute mt;
5740 /* we're done with #backtalker_monotime_cb() invocations,
5741 continue normal processing */
5743 GNUNET_assert (NULL != b->cmc);
5744 finish_cmc_handling (b->cmc);
5746 if (0 != b->body_size)
5747 forward_backchannel_payload (b, &b[1], b->body_size);
5750 if (sizeof (*mtbe) != record->value_size)
5755 mtbe = record->value;
5756 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5757 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5760 "Backtalker message from %s dropped, monotime in the past\n",
5761 GNUNET_i2s (&b->pid));
5762 GNUNET_STATISTICS_update (
5764 "# Backchannel messages dropped: monotonic time not increasing",
5767 b->monotonic_time = mt;
5768 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5777 * Function called by PEERSTORE when the store operation of
5778 * a backtalker's monotonic time is complete.
5780 * @param cls the `struct Backtalker`
5781 * @param success #GNUNET_OK on success
5784 backtalker_monotime_store_cb (void *cls, int success)
5786 struct Backtalker *b = cls;
5788 if (GNUNET_OK != success)
5790 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5791 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5794 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5799 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5801 * @param b a backtalker with updated monotonic time
5804 update_backtalker_monotime (struct Backtalker *b)
5806 struct GNUNET_TIME_AbsoluteNBO mtbe;
5810 GNUNET_PEERSTORE_store_cancel (b->sc);
5815 GNUNET_SCHEDULER_cancel (b->task);
5818 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5820 GNUNET_PEERSTORE_store (peerstore,
5823 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5826 GNUNET_TIME_UNIT_FOREVER_ABS,
5827 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5828 &backtalker_monotime_store_cb,
5834 * Communicator gave us a backchannel encapsulation. Process the request.
5835 * (We are not the origin of the backchannel here, the communicator simply
5836 * received a backchannel message and we are expected to forward it.)
5838 * @param cls a `struct CommunicatorMessageContext` (must call
5839 * #finish_cmc_handling() when done)
5840 * @param be the message that was received
5843 handle_backchannel_encapsulation (
5845 const struct TransportBackchannelEncapsulationMessage *be)
5847 struct CommunicatorMessageContext *cmc = cls;
5848 struct BackchannelKeyState key;
5849 struct GNUNET_HashCode hmac;
5853 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5855 /* not for me, try to route to target */
5856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5857 "Forwarding backtalk to %s\n",
5858 GNUNET_i2s (&be->target));
5859 route_message (&be->target,
5860 GNUNET_copy_message (&be->header),
5862 finish_cmc_handling (cmc);
5865 /* FIXME: this should be done when decrypting _any_ DV
5866 message, not only for backchannels! */
5867 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5868 hdr = (const char *) &be[1];
5869 hdr_len = ntohs (be->header.size) - sizeof (*be);
5870 bc_hmac (&key, &hmac, hdr, hdr_len);
5871 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5873 /* HMAC missmatch, disard! */
5874 GNUNET_break_op (0);
5875 finish_cmc_handling (cmc);
5878 /* begin actual decryption */
5880 struct Backtalker *b;
5881 struct GNUNET_TIME_Absolute monotime;
5882 struct TransportBackchannelRequestPayloadP ppay;
5883 char body[hdr_len - sizeof (ppay)];
5885 GNUNET_assert (hdr_len >=
5886 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5887 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5888 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5889 bc_key_clean (&key);
5890 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5892 "Decrypted backtalk from %s\n",
5893 GNUNET_i2s (&ppay.sender));
5894 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5895 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5897 GNUNET_STATISTICS_update (
5899 "# Backchannel messages dropped: monotonic time not increasing",
5902 finish_cmc_handling (cmc);
5906 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5908 /* Check signature */
5909 struct EphemeralConfirmationPS ec;
5911 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5912 ec.purpose.size = htonl (sizeof (ec));
5913 ec.target = GST_my_identity;
5914 ec.ephemeral_key = be->ephemeral_key;
5917 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5920 &ppay.sender.public_key))
5922 /* Signature invalid, disard! */
5923 GNUNET_break_op (0);
5924 finish_cmc_handling (cmc);
5930 /* update key cache and mono time */
5931 b->last_ephemeral = be->ephemeral_key;
5932 b->monotonic_time = monotime;
5933 update_backtalker_monotime (b);
5934 forward_backchannel_payload (b, body, sizeof (body));
5936 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5937 finish_cmc_handling (cmc);
5940 /* setup data structure to cache signature AND check
5941 monotonic time with PEERSTORE before forwarding backchannel payload */
5942 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5943 b->pid = ppay.sender;
5944 b->body_size = sizeof (body);
5945 memcpy (&b[1], body, sizeof (body));
5946 GNUNET_assert (GNUNET_YES ==
5947 GNUNET_CONTAINER_multipeermap_put (
5951 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5952 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5955 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5956 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5958 GNUNET_PEERSTORE_iterate (peerstore,
5961 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5962 &backtalker_monotime_cb,
5969 * Task called when we should check if any of the DV paths
5970 * we have learned to a target are due for garbage collection.
5972 * Collects stale paths, and possibly frees the entire DV
5973 * entry if no paths are left. Otherwise re-schedules itself.
5975 * @param cls a `struct DistanceVector`
5978 path_cleanup_cb (void *cls)
5980 struct DistanceVector *dv = cls;
5981 struct DistanceVectorHop *pos;
5983 dv->timeout_task = NULL;
5984 while (NULL != (pos = dv->dv_head))
5986 GNUNET_assert (dv == pos->dv);
5987 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5989 free_distance_vector_hop (pos);
5997 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6002 * The @a hop is a validated path to the respective target
6003 * peer and we should tell core about it -- and schedule
6004 * a job to revoke the state.
6006 * @param hop a path to some peer that is the reason for activation
6009 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6011 struct DistanceVector *dv = hop->dv;
6012 struct VirtualLink *vl;
6014 vl = GNUNET_CONTAINER_multipeermap_get (links, &dv->target);
6017 /* Link was already up, remember dv is also now available and we are done */
6019 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6020 "Virtual link to %s could now also use DV!\n",
6021 GNUNET_i2s (&dv->target));
6024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6025 "Creating new virtual link to %s using DV!\n",
6026 GNUNET_i2s (&dv->target));
6027 vl = GNUNET_new (struct VirtualLink);
6028 vl->target = dv->target;
6030 vl->core_recv_window = RECV_WINDOW_SIZE;
6031 vl->visibility_task =
6032 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6033 GNUNET_break (GNUNET_YES ==
6034 GNUNET_CONTAINER_multipeermap_put (
6038 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6039 /* We lacked a confirmed connection to the target
6040 before, so tell CORE about it (finally!) */
6041 cores_send_connect_info (&dv->target);
6046 * We have learned a @a path through the network to some other peer, add it to
6047 * our DV data structure (returning #GNUNET_YES on success).
6049 * We do not add paths if we have a sufficient number of shorter
6050 * paths to this target already (returning #GNUNET_NO).
6052 * We also do not add problematic paths, like those where we lack the first
6053 * hop in our neighbour list (i.e. due to a topology change) or where some
6054 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6056 * @param path the path we learned, path[0] should be us,
6057 * and then path contains a valid path from us to
6058 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6059 * @param path_len number of entries on the @a path, at least three!
6060 * @param network_latency how long does the message take from us to
6061 * `path[path_len-1]`? set to "forever" if unknown
6062 * @param path_valid_until how long is this path considered validated? Maybe
6064 * @return #GNUNET_YES on success,
6065 * #GNUNET_NO if we have better path(s) to the target
6066 * #GNUNET_SYSERR if the path is useless and/or invalid
6067 * (i.e. path[1] not a direct neighbour
6068 * or path[i+1] is a direct neighbour for i>0)
6071 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6072 unsigned int path_len,
6073 struct GNUNET_TIME_Relative network_latency,
6074 struct GNUNET_TIME_Absolute path_valid_until)
6076 struct DistanceVectorHop *hop;
6077 struct DistanceVector *dv;
6078 struct Neighbour *next_hop;
6079 unsigned int shorter_distance;
6083 /* what a boring path! not allowed! */
6085 return GNUNET_SYSERR;
6087 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6088 next_hop = lookup_neighbour (&path[1]);
6089 if (NULL == next_hop)
6091 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6093 return GNUNET_SYSERR;
6095 for (unsigned int i = 2; i < path_len; i++)
6096 if (NULL != lookup_neighbour (&path[i]))
6098 /* Useless path: we have a direct connection to some hop
6099 in the middle of the path, so this one is not even
6100 terribly useful for redundancy */
6101 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6102 "Path of %u hops useless: directly link to hop %u (%s)\n",
6105 GNUNET_i2s (&path[i]));
6106 GNUNET_STATISTICS_update (GST_stats,
6107 "# Useless DV path ignored: hop is neighbour",
6110 return GNUNET_SYSERR;
6112 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6115 dv = GNUNET_new (struct DistanceVector);
6116 dv->target = path[path_len - 1];
6117 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6120 GNUNET_assert (GNUNET_OK ==
6121 GNUNET_CONTAINER_multipeermap_put (
6125 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6127 /* Check if we have this path already! */
6128 shorter_distance = 0;
6129 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6132 if (pos->distance < path_len - 2)
6134 /* Note that the distances in 'pos' excludes us (path[0]) and
6135 the next_hop (path[1]), so we need to subtract two
6136 and check next_hop explicitly */
6137 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6139 int match = GNUNET_YES;
6141 for (unsigned int i = 0; i < pos->distance; i++)
6143 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6149 if (GNUNET_YES == match)
6151 struct GNUNET_TIME_Relative last_timeout;
6153 /* Re-discovered known path, update timeout */
6154 GNUNET_STATISTICS_update (GST_stats,
6155 "# Known DV path refreshed",
6158 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6160 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6161 pos->path_valid_until =
6162 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6163 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6164 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6166 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6167 activate_core_visible_dv_path (pos);
6168 if (last_timeout.rel_value_us <
6169 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6170 DV_PATH_DISCOVERY_FREQUENCY)
6173 /* Some peer send DV learn messages too often, we are learning
6174 the same path faster than it would be useful; do not forward! */
6175 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6176 "Rediscovered path too quickly, not forwarding further\n");
6179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6180 "Refreshed known path to %s, forwarding further\n",
6181 GNUNET_i2s (&dv->target));
6186 /* Count how many shorter paths we have (incl. direct
6187 neighbours) before simply giving up on this one! */
6188 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6190 /* We have a shorter path already! */
6191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6192 "Have many shorter DV paths %s, not forwarding further\n",
6193 GNUNET_i2s (&dv->target));
6196 /* create new DV path entry */
6197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6198 "Discovered new DV path to %s\n",
6199 GNUNET_i2s (&dv->target));
6200 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6201 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6202 hop->next_hop = next_hop;
6204 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6207 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6208 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6209 hop->path_valid_until = path_valid_until;
6210 hop->distance = path_len - 2;
6211 hop->pd.aged_rtt = network_latency;
6212 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6213 GNUNET_CONTAINER_MDLL_insert (neighbour,
6217 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6218 activate_core_visible_dv_path (hop);
6224 * Communicator gave us a DV learn message. Check the message.
6226 * @param cls a `struct CommunicatorMessageContext`
6227 * @param dvl the send message that was sent
6228 * @return #GNUNET_YES if message is well-formed
6231 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6233 uint16_t size = ntohs (dvl->header.size);
6234 uint16_t num_hops = ntohs (dvl->num_hops);
6235 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6238 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6240 GNUNET_break_op (0);
6241 return GNUNET_SYSERR;
6243 if (num_hops > MAX_DV_HOPS_ALLOWED)
6245 GNUNET_break_op (0);
6246 return GNUNET_SYSERR;
6248 for (unsigned int i = 0; i < num_hops; i++)
6250 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6252 GNUNET_break_op (0);
6253 return GNUNET_SYSERR;
6255 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6257 GNUNET_break_op (0);
6258 return GNUNET_SYSERR;
6266 * Build and forward a DV learn message to @a next_hop.
6268 * @param next_hop peer to send the message to
6269 * @param msg message received
6270 * @param bi_history bitmask specifying hops on path that were bidirectional
6271 * @param nhops length of the @a hops array
6272 * @param hops path the message traversed so far
6273 * @param in_time when did we receive the message, used to calculate network
6277 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6278 const struct TransportDVLearnMessage *msg,
6279 uint16_t bi_history,
6281 const struct DVPathEntryP *hops,
6282 struct GNUNET_TIME_Absolute in_time)
6284 struct DVPathEntryP *dhops;
6285 struct TransportDVLearnMessage *fwd;
6286 struct GNUNET_TIME_Relative nnd;
6288 /* compute message for forwarding */
6289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6290 "Forwarding DV learn message originating from %s to %s\n",
6291 GNUNET_i2s (&msg->initiator),
6292 GNUNET_i2s2 (next_hop));
6293 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6294 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
6295 (nhops + 1) * sizeof (struct DVPathEntryP));
6296 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6297 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6298 (nhops + 1) * sizeof (struct DVPathEntryP));
6299 fwd->num_hops = htons (nhops + 1);
6300 fwd->bidirectional = htons (bi_history);
6301 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6302 GNUNET_TIME_relative_ntoh (
6303 msg->non_network_delay));
6304 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6305 fwd->init_sig = msg->init_sig;
6306 fwd->initiator = msg->initiator;
6307 fwd->challenge = msg->challenge;
6308 dhops = (struct DVPathEntryP *) &fwd[1];
6309 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6310 dhops[nhops].hop = GST_my_identity;
6312 struct DvHopPS dhp = {.purpose.purpose =
6313 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6314 .purpose.size = htonl (sizeof (dhp)),
6315 .pred = dhops[nhops - 1].hop,
6317 .challenge = msg->challenge};
6319 GNUNET_assert (GNUNET_OK ==
6320 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6322 &dhops[nhops].hop_sig));
6324 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6329 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6331 * @param sender_monotonic_time monotonic time of the initiator
6332 * @param init the signer
6333 * @param challenge the challenge that was signed
6334 * @param init_sig signature presumably by @a init
6335 * @return #GNUNET_OK if the signature is valid
6338 validate_dv_initiator_signature (
6339 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6340 const struct GNUNET_PeerIdentity *init,
6341 const struct ChallengeNonceP *challenge,
6342 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6344 struct DvInitPS ip = {.purpose.purpose = htonl (
6345 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6346 .purpose.size = htonl (sizeof (ip)),
6347 .monotonic_time = sender_monotonic_time,
6348 .challenge = *challenge};
6352 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6357 GNUNET_break_op (0);
6358 return GNUNET_SYSERR;
6365 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6367 struct NeighbourSelectionContext
6370 * Original message we received.
6372 const struct TransportDVLearnMessage *dvl;
6377 const struct DVPathEntryP *hops;
6380 * Time we received the message.
6382 struct GNUNET_TIME_Absolute in_time;
6385 * Offsets of the selected peers.
6387 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6390 * Number of peers eligible for selection.
6392 unsigned int num_eligible;
6395 * Number of peers that were selected for forwarding.
6397 unsigned int num_selections;
6400 * Number of hops in @e hops
6405 * Bitmap of bidirectional connections encountered.
6407 uint16_t bi_history;
6412 * Function called for each neighbour during #handle_dv_learn.
6414 * @param cls a `struct NeighbourSelectionContext *`
6415 * @param pid identity of the peer
6416 * @param value a `struct Neighbour`
6417 * @return #GNUNET_YES (always)
6420 dv_neighbour_selection (void *cls,
6421 const struct GNUNET_PeerIdentity *pid,
6424 struct NeighbourSelectionContext *nsc = cls;
6427 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6428 return GNUNET_YES; /* skip initiator */
6429 for (unsigned int i = 0; i < nsc->nhops; i++)
6430 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6431 return GNUNET_YES; /* skip peers on path */
6432 nsc->num_eligible++;
6438 * Function called for each neighbour during #handle_dv_learn.
6439 * We call #forward_dv_learn() on the neighbour(s) selected
6440 * during #dv_neighbour_selection().
6442 * @param cls a `struct NeighbourSelectionContext *`
6443 * @param pid identity of the peer
6444 * @param value a `struct Neighbour`
6445 * @return #GNUNET_YES (always)
6448 dv_neighbour_transmission (void *cls,
6449 const struct GNUNET_PeerIdentity *pid,
6452 struct NeighbourSelectionContext *nsc = cls;
6455 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6456 return GNUNET_YES; /* skip initiator */
6457 for (unsigned int i = 0; i < nsc->nhops; i++)
6458 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6459 return GNUNET_YES; /* skip peers on path */
6460 for (unsigned int i = 0; i < nsc->num_selections; i++)
6462 if (nsc->selections[i] == nsc->num_eligible)
6464 forward_dv_learn (pid,
6473 nsc->num_eligible++;
6479 * Computes the number of neighbours we should forward a DVInit
6480 * message to given that it has so far taken @a hops_taken hops
6481 * though the network and that the number of neighbours we have
6482 * in total is @a neighbour_count, out of which @a eligible_count
6483 * are not yet on the path.
6485 * NOTE: technically we might want to include NSE in the formula to
6486 * get a better grip on the overall network size. However, for now
6487 * using NSE here would create a dependency issue in the build system.
6488 * => Left for later, hardcoded to 50 for now.
6490 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6491 * peers via DV (`target_total`). We want the reach to be spread out
6492 * over various distances to the origin, with a bias towards shorter
6495 * We make the strong assumption that the network topology looks
6496 * "similar" at other hops, in particular the @a neighbour_count
6497 * should be comparable at other hops.
6499 * If the local neighbourhood is densely connected, we expect that @a
6500 * eligible_count is close to @a neighbour_count minus @a hops_taken
6501 * as a lot of the path is already known. In that case, we should
6502 * forward to few(er) peers to try to find a path out of the
6503 * neighbourhood. OTOH, if @a eligible_count is close to @a
6504 * neighbour_count, we should forward to many peers as we are either
6505 * still close to the origin (i.e. @a hops_taken is small) or because
6506 * we managed to get beyond a local cluster. We express this as
6507 * the `boost_factor` using the square of the fraction of eligible
6508 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6509 * 99% are eligible, the 'boost' will be almost 1).
6511 * Second, the more hops we have taken, the larger the problem of an
6512 * exponential traffic explosion gets. So we take the `target_total`,
6513 * and compute our degree such that at each distance d 2^{-d} peers
6514 * are selected (corrected by the `boost_factor`).
6516 * @param hops_taken number of hops DVInit has travelled so far
6517 * @param neighbour_count number of neighbours we have in total
6518 * @param eligible_count number of neighbours we could in
6522 calculate_fork_degree (unsigned int hops_taken,
6523 unsigned int neighbour_count,
6524 unsigned int eligible_count)
6526 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6527 double eligible_ratio =
6528 ((double) eligible_count) / ((double) neighbour_count);
6529 double boost_factor = eligible_ratio * eligible_ratio;
6533 if (hops_taken >= 64)
6536 return 0; /* precaution given bitshift below */
6538 for (unsigned int i = 1; i < hops_taken; i++)
6540 /* For each hop, subtract the expected number of targets
6541 reached at distance d (so what remains divided by 2^d) */
6542 target_total -= (target_total * boost_factor / (1LLU << i));
6545 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6546 /* round up or down probabilistically depending on how close we were
6547 when floor()ing to rnd */
6548 left = target_total - (double) rnd;
6549 if (UINT32_MAX * left >
6550 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6551 rnd++; /* round up */
6552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6553 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6563 * Function called when peerstore is done storing a DV monotonic time.
6565 * @param cls a `struct Neighbour`
6566 * @param success #GNUNET_YES if peerstore was successful
6569 neighbour_store_dvmono_cb (void *cls, int success)
6571 struct Neighbour *n = cls;
6574 if (GNUNET_YES != success)
6575 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6576 "Failed to store other peer's monotonic time in peerstore!\n");
6581 * Communicator gave us a DV learn message. Process the request.
6583 * @param cls a `struct CommunicatorMessageContext` (must call
6584 * #finish_cmc_handling() when done)
6585 * @param dvl the message that was received
6588 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6590 struct CommunicatorMessageContext *cmc = cls;
6591 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6594 uint16_t bi_history;
6595 const struct DVPathEntryP *hops;
6598 struct GNUNET_TIME_Absolute in_time;
6599 struct Neighbour *n;
6601 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6602 bi_history = ntohs (dvl->bidirectional);
6603 hops = (const struct DVPathEntryP *) &dvl[1];
6607 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6610 finish_cmc_handling (cmc);
6617 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6620 finish_cmc_handling (cmc);
6625 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6626 cc = cmc->tc->details.communicator.cc;
6627 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6628 cc); // FIXME: add bi-directional flag to cc?
6629 in_time = GNUNET_TIME_absolute_get ();
6631 /* continue communicator here, everything else can happen asynchronous! */
6632 finish_cmc_handling (cmc);
6634 n = lookup_neighbour (&dvl->initiator);
6637 if ((n->dv_monotime_available == GNUNET_YES) &&
6638 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6639 n->last_dv_learn_monotime.abs_value_us))
6641 GNUNET_STATISTICS_update (GST_stats,
6642 "# DV learn discarded due to time travel",
6647 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6652 GNUNET_break_op (0);
6655 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6656 if (GNUNET_YES == n->dv_monotime_available)
6659 GNUNET_PEERSTORE_store_cancel (n->sc);
6661 GNUNET_PEERSTORE_store (peerstore,
6664 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6665 &dvl->monotonic_time,
6666 sizeof (dvl->monotonic_time),
6667 GNUNET_TIME_UNIT_FOREVER_ABS,
6668 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6669 &neighbour_store_dvmono_cb,
6673 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6674 If signature verification load too high, implement random drop strategy */
6675 for (unsigned int i = 0; i < nhops; i++)
6677 struct DvHopPS dhp = {.purpose.purpose =
6678 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6679 .purpose.size = htonl (sizeof (dhp)),
6680 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6681 .succ = (nhops - 1 == i) ? GST_my_identity
6683 .challenge = dvl->challenge};
6686 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6689 &hops[i].hop.public_key))
6691 GNUNET_break_op (0);
6696 if (GNUNET_EXTRA_LOGGING > 0)
6700 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6701 for (unsigned int i = 0; i < nhops; i++)
6705 GNUNET_asprintf (&tmp,
6708 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6709 GNUNET_i2s (&hops[i].hop));
6713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6714 "Received DVInit via %s%s%s\n",
6716 bi_hop ? "<->" : "-->",
6717 GNUNET_i2s (&GST_my_identity));
6721 do_fwd = GNUNET_YES;
6722 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6724 struct GNUNET_PeerIdentity path[nhops + 1];
6725 struct GNUNET_TIME_Relative host_latency_sum;
6726 struct GNUNET_TIME_Relative latency;
6727 struct GNUNET_TIME_Relative network_latency;
6729 /* We initiated this, learn the forward path! */
6730 path[0] = GST_my_identity;
6731 path[1] = hops[0].hop;
6732 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6734 // Need also something to lookup initiation time
6735 // to compute RTT! -> add RTT argument here?
6736 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6737 // (based on dvl->challenge, we can identify time of origin!)
6739 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6740 /* assumption: latency on all links is the same */
6741 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6743 for (unsigned int i = 2; i <= nhops; i++)
6745 struct GNUNET_TIME_Relative ilat;
6747 /* assumption: linear latency increase per hop */
6748 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6749 path[i] = hops[i - 1].hop;
6750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6751 "Learned path with %u hops to %s with latency %s\n",
6753 GNUNET_i2s (&path[i]),
6754 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6755 learn_dv_path (path,
6758 GNUNET_TIME_relative_to_absolute (
6759 ADDRESS_VALIDATION_LIFETIME));
6761 /* as we initiated, do not forward again (would be circular!) */
6767 /* last hop was bi-directional, we could learn something here! */
6768 struct GNUNET_PeerIdentity path[nhops + 2];
6770 path[0] = GST_my_identity;
6771 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6772 for (unsigned int i = 0; i < nhops; i++)
6776 if (0 == (bi_history & (1 << i)))
6777 break; /* i-th hop not bi-directional, stop learning! */
6780 path[i + 2] = dvl->initiator;
6784 path[i + 2] = hops[nhops - i - 2].hop;
6787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6788 "Learned inverse path with %u hops to %s\n",
6790 GNUNET_i2s (&path[i + 2]));
6791 iret = learn_dv_path (path,
6793 GNUNET_TIME_UNIT_FOREVER_REL,
6794 GNUNET_TIME_UNIT_ZERO_ABS);
6795 if (GNUNET_SYSERR == iret)
6797 /* path invalid or too long to be interesting for US, thus should also
6798 not be interesting to our neighbours, cut path when forwarding to
6799 'i' hops, except of course for the one that goes back to the
6801 GNUNET_STATISTICS_update (GST_stats,
6802 "# DV learn not forwarded due invalidity of path",
6808 if ((GNUNET_NO == iret) && (nhops == i + 1))
6810 /* we have better paths, and this is the longest target,
6811 so there cannot be anything interesting later */
6812 GNUNET_STATISTICS_update (GST_stats,
6813 "# DV learn not forwarded, got better paths",
6822 if (MAX_DV_HOPS_ALLOWED == nhops)
6824 /* At limit, we're out of here! */
6825 finish_cmc_handling (cmc);
6829 /* Forward to initiator, if path non-trivial and possible */
6830 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6831 did_initiator = GNUNET_NO;
6834 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6836 /* send back to origin! */
6837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6838 "Sending DVL back to initiator %s\n",
6839 GNUNET_i2s (&dvl->initiator));
6840 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6841 did_initiator = GNUNET_YES;
6843 /* We forward under two conditions: either we still learned something
6844 ourselves (do_fwd), or the path was darn short and thus the initiator is
6845 likely to still be very interested in this (and we did NOT already
6846 send it back to the initiator) */
6847 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6848 (GNUNET_NO == did_initiator)))
6850 /* Pick random neighbours that are not yet on the path */
6851 struct NeighbourSelectionContext nsc;
6854 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6857 nsc.bi_history = bi_history;
6859 nsc.in_time = in_time;
6860 nsc.num_eligible = 0;
6861 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6862 &dv_neighbour_selection,
6864 if (0 == nsc.num_eligible)
6865 return; /* done here, cannot forward to anyone else */
6866 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6867 nsc.num_selections =
6868 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6869 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6870 "Forwarding DVL to %u other peers\n",
6871 nsc.num_selections);
6872 for (unsigned int i = 0; i < nsc.num_selections; i++)
6874 (nsc.num_selections == n_cnt)
6875 ? i /* all were selected, avoid collisions by chance */
6876 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6877 nsc.num_eligible = 0;
6878 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6879 &dv_neighbour_transmission,
6886 * Communicator gave us a DV box. Check the message.
6888 * @param cls a `struct CommunicatorMessageContext`
6889 * @param dvb the send message that was sent
6890 * @return #GNUNET_YES if message is well-formed
6893 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6895 uint16_t size = ntohs (dvb->header.size);
6896 uint16_t num_hops = ntohs (dvb->num_hops);
6897 const struct GNUNET_PeerIdentity *hops =
6898 (const struct GNUNET_PeerIdentity *) &dvb[1];
6899 const struct GNUNET_MessageHeader *inbox =
6900 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6905 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6906 sizeof (struct GNUNET_MessageHeader))
6908 GNUNET_break_op (0);
6909 return GNUNET_SYSERR;
6911 isize = ntohs (inbox->size);
6913 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6915 GNUNET_break_op (0);
6916 return GNUNET_SYSERR;
6918 itype = ntohs (inbox->type);
6919 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6920 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6922 GNUNET_break_op (0);
6923 return GNUNET_SYSERR;
6925 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6927 GNUNET_break_op (0);
6928 return GNUNET_SYSERR;
6935 * Create a DV Box message and queue it for transmission to
6938 * @param next_hop peer to receive the message next
6939 * @param total_hops how many hops did the message take so far
6940 * @param num_hops length of the @a hops array
6941 * @param origin origin of the message
6942 * @param hops next peer(s) to the destination, including destination
6943 * @param payload payload of the box
6944 * @param payload_size number of bytes in @a payload
6947 forward_dv_box (struct Neighbour *next_hop,
6948 uint16_t total_hops,
6950 const struct GNUNET_PeerIdentity *origin,
6951 const struct GNUNET_PeerIdentity *hops,
6952 const void *payload,
6953 uint16_t payload_size)
6955 struct TransportDVBoxMessage *dvb;
6957 dvb = create_dv_box (total_hops,
6959 &hops[num_hops - 1] /* == target */,
6960 num_hops - 1 /* do not count target twice */,
6964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6965 "Routing DV Box of %u bytes from %s at %u/%u hops via %s\n",
6967 GNUNET_i2s (origin),
6968 (unsigned int) num_hops,
6969 (unsigned int) total_hops,
6970 GNUNET_i2s2 (&next_hop->pid));
6971 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6977 * Communicator gave us a DV box. Process the request.
6979 * @param cls a `struct CommunicatorMessageContext` (must call
6980 * #finish_cmc_handling() when done)
6981 * @param dvb the message that was received
6984 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6986 struct CommunicatorMessageContext *cmc = cls;
6987 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6988 uint16_t num_hops = ntohs (dvb->num_hops);
6989 const struct GNUNET_PeerIdentity *hops =
6990 (const struct GNUNET_PeerIdentity *) &dvb[1];
6991 const struct GNUNET_MessageHeader *inbox =
6992 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6994 if (GNUNET_EXTRA_LOGGING > 0)
6998 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
6999 for (unsigned int i = 0; i < num_hops; i++)
7003 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7008 "Received DVBox with remainig path %s\n",
7015 /* We're trying from the end of the hops array, as we may be
7016 able to find a shortcut unknown to the origin that way */
7017 for (int i = num_hops - 1; i >= 0; i--)
7019 struct Neighbour *n;
7021 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7023 GNUNET_break_op (0);
7024 finish_cmc_handling (cmc);
7027 n = lookup_neighbour (&hops[i]);
7030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7031 "Skipping %u/%u hops ahead while routing DV Box\n",
7035 ntohs (dvb->total_hops) + 1,
7036 num_hops - i - 1, /* number of hops left */
7038 &hops[i + 1], /* remaining hops */
7039 (const void *) &dvb[1],
7041 GNUNET_STATISTICS_update (GST_stats,
7042 "# DV hops skipped routing boxes",
7045 GNUNET_STATISTICS_update (GST_stats,
7046 "# DV boxes routed (total)",
7049 finish_cmc_handling (cmc);
7052 /* Woopsie, next hop not in neighbours, drop! */
7053 GNUNET_STATISTICS_update (GST_stats,
7054 "# DV Boxes dropped: next hop unknown",
7057 finish_cmc_handling (cmc);
7060 /* We are the target. Unbox and handle message. */
7061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7062 "DVBox received for me from %s\n",
7063 GNUNET_i2s (&dvb->origin));
7064 GNUNET_STATISTICS_update (GST_stats,
7065 "# DV boxes opened (ultimate target)",
7068 cmc->im.sender = dvb->origin;
7069 cmc->total_hops = ntohs (dvb->total_hops);
7070 // FIXME: should *decrypt* inbox here; needs BackchannelEncapsulation!
7071 // FIXME: need to prevent box-in-a-box, so check inbox type!
7072 demultiplex_with_cmc (cmc, inbox);
7077 * Client notified us about transmission from a peer. Process the request.
7079 * @param cls a `struct TransportClient` which sent us the message
7080 * @param obm the send message that was sent
7081 * @return #GNUNET_YES if message is well-formed
7084 check_incoming_msg (void *cls,
7085 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7087 struct TransportClient *tc = cls;
7089 if (CT_COMMUNICATOR != tc->type)
7092 return GNUNET_SYSERR;
7094 GNUNET_MQ_check_boxed_message (im);
7100 * Communicator gave us a transport address validation challenge. Process the
7103 * @param cls a `struct CommunicatorMessageContext` (must call
7104 * #finish_cmc_handling() when done)
7105 * @param tvc the message that was received
7108 handle_validation_challenge (
7110 const struct TransportValidationChallengeMessage *tvc)
7112 struct CommunicatorMessageContext *cmc = cls;
7113 struct TransportValidationResponseMessage *tvr;
7115 if (cmc->total_hops > 0)
7117 /* DV routing is not allowed for validation challenges! */
7118 GNUNET_break_op (0);
7119 finish_cmc_handling (cmc);
7122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7123 "Received address validation challenge %s\n",
7124 GNUNET_sh2s (&tvc->challenge.value));
7125 tvr = GNUNET_new (struct TransportValidationResponseMessage);
7127 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7128 tvr->header.size = htons (sizeof (*tvr));
7129 tvr->challenge = tvc->challenge;
7130 tvr->origin_time = tvc->sender_time;
7131 tvr->validity_duration = cmc->im.expected_address_validity;
7133 /* create signature */
7134 struct TransportValidationPS tvp =
7135 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7136 .purpose.size = htonl (sizeof (tvp)),
7137 .validity_duration = tvr->validity_duration,
7138 .challenge = tvc->challenge};
7140 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7144 route_message (&cmc->im.sender,
7146 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7147 finish_cmc_handling (cmc);
7152 * Closure for #check_known_challenge.
7154 struct CheckKnownChallengeContext
7157 * Set to the challenge we are looking for.
7159 const struct ChallengeNonceP *challenge;
7162 * Set to a matching validation state, if one was found.
7164 struct ValidationState *vs;
7169 * Test if the validation state in @a value matches the
7170 * challenge from @a cls.
7172 * @param cls a `struct CheckKnownChallengeContext`
7173 * @param pid unused (must match though)
7174 * @param value a `struct ValidationState`
7175 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7178 check_known_challenge (void *cls,
7179 const struct GNUNET_PeerIdentity *pid,
7182 struct CheckKnownChallengeContext *ckac = cls;
7183 struct ValidationState *vs = value;
7186 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7194 * Function called when peerstore is done storing a
7195 * validated address.
7197 * @param cls a `struct ValidationState`
7198 * @param success #GNUNET_YES on success
7201 peerstore_store_validation_cb (void *cls, int success)
7203 struct ValidationState *vs = cls;
7206 if (GNUNET_YES == success)
7208 GNUNET_STATISTICS_update (GST_stats,
7209 "# Peerstore failed to store foreign address",
7216 * Task run periodically to validate some address based on #validation_heap.
7221 validation_start_cb (void *cls);
7225 * Set the time for next_challenge of @a vs to @a new_time.
7226 * Updates the heap and if necessary reschedules the job.
7228 * @param vs validation state to update
7229 * @param new_time new time for revalidation
7232 update_next_challenge_time (struct ValidationState *vs,
7233 struct GNUNET_TIME_Absolute new_time)
7235 struct GNUNET_TIME_Relative delta;
7237 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7238 return; /* be lazy */
7239 vs->next_challenge = new_time;
7242 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7244 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7245 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7246 (NULL != validation_task))
7248 if (NULL != validation_task)
7249 GNUNET_SCHEDULER_cancel (validation_task);
7250 /* randomize a bit */
7251 delta.rel_value_us =
7252 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7253 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7254 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7256 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7261 * Find the queue matching @a pid and @a address.
7263 * @param pid peer the queue must go to
7264 * @param address address the queue must use
7265 * @return NULL if no such queue exists
7267 static struct Queue *
7268 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7270 struct Neighbour *n;
7272 n = lookup_neighbour (pid);
7275 for (struct Queue *pos = n->queue_head; NULL != pos;
7276 pos = pos->next_neighbour)
7278 if (0 == strcmp (pos->address, address))
7286 * Communicator gave us a transport address validation response. Process the
7289 * @param cls a `struct CommunicatorMessageContext` (must call
7290 * #finish_cmc_handling() when done)
7291 * @param tvr the message that was received
7294 handle_validation_response (
7296 const struct TransportValidationResponseMessage *tvr)
7298 struct CommunicatorMessageContext *cmc = cls;
7299 struct ValidationState *vs;
7300 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7302 struct GNUNET_TIME_Absolute origin_time;
7304 struct Neighbour *n;
7305 struct VirtualLink *vl;
7307 /* check this is one of our challenges */
7308 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7310 &check_known_challenge,
7312 if (NULL == (vs = ckac.vs))
7314 /* This can happen simply if we 'forgot' the challenge by now,
7315 i.e. because we received the validation response twice */
7316 GNUNET_STATISTICS_update (GST_stats,
7317 "# Validations dropped, challenge unknown",
7320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7321 "Validation response %s dropped, challenge unknown\n",
7322 GNUNET_sh2s (&tvr->challenge.value));
7323 finish_cmc_handling (cmc);
7327 /* sanity check on origin time */
7328 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7329 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7330 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7332 GNUNET_break_op (0);
7333 finish_cmc_handling (cmc);
7338 /* check signature */
7339 struct TransportValidationPS tvp =
7340 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7341 .purpose.size = htonl (sizeof (tvp)),
7342 .validity_duration = tvr->validity_duration,
7343 .challenge = tvr->challenge};
7347 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7350 &cmc->im.sender.public_key))
7352 GNUNET_break_op (0);
7353 finish_cmc_handling (cmc);
7358 /* validity is capped by our willingness to keep track of the
7359 validation entry and the maximum the other peer allows */
7360 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7361 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7362 tvr->validity_duration),
7363 MAX_ADDRESS_VALID_UNTIL));
7364 vs->validated_until =
7365 GNUNET_TIME_absolute_min (vs->valid_until,
7366 GNUNET_TIME_relative_to_absolute (
7367 ADDRESS_VALIDATION_LIFETIME));
7368 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7369 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7370 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7372 sizeof (vs->challenge));
7373 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7374 vs->validated_until,
7375 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7376 VALIDATION_RTT_BUFFER_FACTOR));
7377 vs->last_challenge_use =
7378 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7379 update_next_challenge_time (vs, vs->first_challenge_use);
7380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7381 "Validation response %s accepted, address valid until %s\n",
7382 GNUNET_sh2s (&tvr->challenge.value),
7383 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
7384 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7387 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7389 strlen (vs->address) + 1,
7391 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7392 &peerstore_store_validation_cb,
7394 finish_cmc_handling (cmc);
7396 /* Finally, we now possibly have a confirmed (!) working queue,
7397 update queue status (if queue still is around) */
7398 q = find_queue (&vs->pid, vs->address);
7401 GNUNET_STATISTICS_update (GST_stats,
7402 "# Queues lost at time of successful validation",
7407 q->validated_until = vs->validated_until;
7408 q->pd.aged_rtt = vs->validation_rtt;
7410 vl = GNUNET_CONTAINER_multipeermap_get (links, &vs->pid);
7413 /* Link was already up, remember n is also now available and we are done */
7415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7416 "Virtual link to %s could now also direct neighbour!\n",
7417 GNUNET_i2s (&vs->pid));
7420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7421 "Creating new virtual link to %s using direct neighbour!\n",
7422 GNUNET_i2s (&vs->pid));
7423 vl = GNUNET_new (struct VirtualLink);
7424 vl->target = n->pid;
7426 vl->core_recv_window = RECV_WINDOW_SIZE;
7427 vl->visibility_task =
7428 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7429 GNUNET_break (GNUNET_YES ==
7430 GNUNET_CONTAINER_multipeermap_put (
7434 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7435 /* We lacked a confirmed connection to the target
7436 before, so tell CORE about it (finally!) */
7437 cores_send_connect_info (&n->pid);
7442 * Incoming meessage. Process the request.
7444 * @param im the send message that was received
7447 handle_incoming_msg (void *cls,
7448 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7450 struct TransportClient *tc = cls;
7451 struct CommunicatorMessageContext *cmc =
7452 GNUNET_new (struct CommunicatorMessageContext);
7456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7457 "Received message via communicator from peer %s\n",
7458 GNUNET_i2s (&im->sender));
7459 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7464 * Given an inbound message @a msg from a communicator @a cmc,
7465 * demultiplex it based on the type calling the right handler.
7467 * @param cmc context for demultiplexing
7468 * @param msg message to demultiplex
7471 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7472 const struct GNUNET_MessageHeader *msg)
7474 struct GNUNET_MQ_MessageHandler handlers[] =
7475 {GNUNET_MQ_hd_var_size (fragment_box,
7476 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7477 struct TransportFragmentBoxMessage,
7479 GNUNET_MQ_hd_var_size (reliability_box,
7480 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7481 struct TransportReliabilityBoxMessage,
7483 GNUNET_MQ_hd_var_size (reliability_ack,
7484 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7485 struct TransportReliabilityAckMessage,
7487 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7488 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7489 struct TransportBackchannelEncapsulationMessage,
7491 GNUNET_MQ_hd_var_size (dv_learn,
7492 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7493 struct TransportDVLearnMessage,
7495 GNUNET_MQ_hd_var_size (dv_box,
7496 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7497 struct TransportDVBoxMessage,
7499 GNUNET_MQ_hd_fixed_size (
7500 validation_challenge,
7501 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7502 struct TransportValidationChallengeMessage,
7504 GNUNET_MQ_hd_fixed_size (
7505 validation_response,
7506 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7507 struct TransportValidationResponseMessage,
7509 GNUNET_MQ_handler_end ()};
7512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7513 "Handling message of type %u with %u bytes\n",
7514 (unsigned int) ntohs (msg->type),
7515 (unsigned int) ntohs (msg->size));
7516 ret = GNUNET_MQ_handle_message (handlers, msg);
7517 if (GNUNET_SYSERR == ret)
7520 GNUNET_SERVICE_client_drop (cmc->tc->client);
7524 if (GNUNET_NO == ret)
7526 /* unencapsulated 'raw' message */
7527 handle_raw_message (&cmc, msg);
7533 * New queue became available. Check message.
7535 * @param cls the client
7536 * @param aqm the send message that was sent
7539 check_add_queue_message (void *cls,
7540 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7542 struct TransportClient *tc = cls;
7544 if (CT_COMMUNICATOR != tc->type)
7547 return GNUNET_SYSERR;
7549 GNUNET_MQ_check_zero_termination (aqm);
7555 * If necessary, generates the UUID for a @a pm
7557 * @param pm pending message to generate UUID for.
7560 set_pending_message_uuid (struct PendingMessage *pm)
7562 if (pm->msg_uuid_set)
7564 pm->msg_uuid.uuid = pm->target->message_uuid_ctr++;
7565 pm->msg_uuid_set = GNUNET_YES;
7569 // FIXME: add logging logic from here!
7573 * Setup data structure waiting for acknowledgements.
7575 * @param queue queue the @a pm will be sent over
7576 * @param dvh path the message will take, may be NULL
7577 * @param pm the pending message for transmission
7578 * @return corresponding fresh pending acknowledgement
7580 static struct PendingAcknowledgement *
7581 prepare_pending_acknowledgement (struct Queue *queue,
7582 struct DistanceVectorHop *dvh,
7583 struct PendingMessage *pm)
7585 struct PendingAcknowledgement *pa;
7587 pa = GNUNET_new (struct PendingAcknowledgement);
7593 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7595 sizeof (pa->ack_uuid));
7596 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7598 &pa->ack_uuid.value,
7600 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7601 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7602 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7604 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7605 pa->transmission_time = GNUNET_TIME_absolute_get ();
7606 pa->message_size = pm->bytes_msg;
7612 * Fragment the given @a pm to the given @a mtu. Adds
7613 * additional fragments to the neighbour as well. If the
7614 * @a mtu is too small, generates and error for the @a pm
7617 * @param queue which queue to fragment for
7618 * @param dvh path the message will take, or NULL
7619 * @param pm pending message to fragment for transmission
7620 * @return new message to transmit
7622 static struct PendingMessage *
7623 fragment_message (struct Queue *queue,
7624 struct DistanceVectorHop *dvh,
7625 struct PendingMessage *pm)
7627 struct PendingAcknowledgement *pa;
7628 struct PendingMessage *ff;
7631 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7632 mtu = (0 == queue->mtu)
7633 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7635 set_pending_message_uuid (pm);
7637 /* This invariant is established in #handle_add_queue_message() */
7638 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7640 /* select fragment for transmission, descending the tree if it has
7641 been expanded until we are at a leaf or at a fragment that is small
7645 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7646 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7648 ff = ff->head_frag; /* descent into fragmented fragments */
7651 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7653 /* Did not yet calculate all fragments, calculate next fragment */
7654 struct PendingMessage *frag;
7655 struct TransportFragmentBoxMessage tfb;
7663 orig = (const char *) &ff[1];
7664 msize = ff->bytes_msg;
7667 const struct TransportFragmentBoxMessage *tfbo;
7669 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7670 orig += sizeof (struct TransportFragmentBoxMessage);
7671 msize -= sizeof (struct TransportFragmentBoxMessage);
7672 xoff = ntohs (tfbo->frag_off);
7674 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7675 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7677 GNUNET_malloc (sizeof (struct PendingMessage) +
7678 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7679 frag->target = pm->target;
7680 frag->frag_parent = ff;
7681 frag->timeout = pm->timeout;
7682 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7683 frag->pmt = PMT_FRAGMENT_BOX;
7684 msg = (char *) &frag[1];
7685 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7687 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7688 tfb.ack_uuid = pa->ack_uuid;
7689 tfb.msg_uuid = pm->msg_uuid;
7690 tfb.frag_off = htons (ff->frag_off + xoff);
7691 tfb.msg_size = htons (pm->bytes_msg);
7692 memcpy (msg, &tfb, sizeof (tfb));
7693 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7694 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7695 ff->frag_off += fragsize;
7699 /* Move head to the tail and return it */
7700 GNUNET_CONTAINER_MDLL_remove (frag,
7701 ff->frag_parent->head_frag,
7702 ff->frag_parent->tail_frag,
7704 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7705 ff->frag_parent->head_frag,
7706 ff->frag_parent->tail_frag,
7713 * Reliability-box the given @a pm. On error (can there be any), NULL
7714 * may be returned, otherwise the "replacement" for @a pm (which
7715 * should then be added to the respective neighbour's queue instead of
7716 * @a pm). If the @a pm is already fragmented or reliability boxed,
7717 * or itself an ACK, this function simply returns @a pm.
7719 * @param queue which queue to prepare transmission for
7720 * @param dvh path the message will take, or NULL
7721 * @param pm pending message to box for transmission over unreliabile queue
7722 * @return new message to transmit
7724 static struct PendingMessage *
7725 reliability_box_message (struct Queue *queue,
7726 struct DistanceVectorHop *dvh,
7727 struct PendingMessage *pm)
7729 struct TransportReliabilityBoxMessage rbox;
7730 struct PendingAcknowledgement *pa;
7731 struct PendingMessage *bpm;
7734 if (PMT_CORE != pm->pmt)
7735 return pm; /* already fragmented or reliability boxed, or control message:
7737 if (NULL != pm->bpm)
7738 return pm->bpm; /* already computed earlier: do nothing */
7739 GNUNET_assert (NULL == pm->head_frag);
7740 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7744 client_send_response (pm);
7747 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7749 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7751 bpm->target = pm->target;
7752 bpm->frag_parent = pm;
7753 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7754 bpm->timeout = pm->timeout;
7755 bpm->pmt = PMT_RELIABILITY_BOX;
7756 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7757 set_pending_message_uuid (bpm);
7758 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7759 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7760 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7762 rbox.ack_uuid = pa->ack_uuid;
7763 msg = (char *) &bpm[1];
7764 memcpy (msg, &rbox, sizeof (rbox));
7765 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7772 * Change the value of the `next_attempt` field of @a pm
7773 * to @a next_attempt and re-order @a pm in the transmission
7774 * list as required by the new timestmap.
7776 * @param pm a pending message to update
7777 * @param next_attempt timestamp to use
7780 update_pm_next_attempt (struct PendingMessage *pm,
7781 struct GNUNET_TIME_Absolute next_attempt)
7783 struct Neighbour *neighbour = pm->target;
7785 pm->next_attempt = next_attempt;
7786 if (NULL == pm->frag_parent)
7788 struct PendingMessage *pos;
7790 /* re-insert sort in neighbour list */
7791 GNUNET_CONTAINER_MDLL_remove (neighbour,
7792 neighbour->pending_msg_head,
7793 neighbour->pending_msg_tail,
7795 pos = neighbour->pending_msg_tail;
7796 while ((NULL != pos) &&
7797 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7798 pos = pos->prev_neighbour;
7799 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7800 neighbour->pending_msg_head,
7801 neighbour->pending_msg_tail,
7807 /* re-insert sort in fragment list */
7808 struct PendingMessage *fp = pm->frag_parent;
7809 struct PendingMessage *pos;
7811 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7812 pos = fp->tail_frag;
7813 while ((NULL != pos) &&
7814 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7815 pos = pos->prev_frag;
7816 GNUNET_CONTAINER_MDLL_insert_after (frag,
7826 * We believe we are ready to transmit a message on a queue.
7827 * Gives the message to the
7828 * communicator for transmission (updating the tracker, and re-scheduling
7829 * itself if applicable).
7831 * @param cls the `struct Queue` to process transmissions for
7834 transmit_on_queue (void *cls)
7836 struct Queue *queue = cls;
7837 struct Neighbour *n = queue->neighbour;
7838 struct PendingMessage *pm;
7839 struct PendingMessage *s;
7842 queue->transmit_task = NULL;
7843 if (NULL == (pm = n->pending_msg_head))
7845 /* no message pending, nothing to do here! */
7850 /* message still pending with communciator!
7851 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7854 schedule_transmit_on_queue (queue, GNUNET_YES);
7855 if (NULL != queue->transmit_task)
7856 return; /* do it later */
7858 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7859 overhead += sizeof (struct TransportReliabilityBoxMessage);
7861 if ( ( (0 != queue->mtu) &&
7862 (pm->bytes_msg + overhead > queue->mtu) ) ||
7863 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7864 (NULL != pm->head_frag /* fragments already exist, should
7865 respect that even if MTU is 0 for
7867 s = fragment_message (queue, pm->dvh, s);
7870 /* Fragmentation failed, try next message... */
7871 schedule_transmit_on_queue (queue, GNUNET_NO);
7874 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7875 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7876 s = reliability_box_message (queue, pm->dvh, s);
7879 /* Reliability boxing failed, try next message... */
7880 schedule_transmit_on_queue (queue, GNUNET_NO);
7884 /* Pass 's' for transission to the communicator */
7885 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7886 // FIXME: do something similar to the logic below
7887 // in defragmentation / reliability ACK handling!
7889 /* Check if this transmission somehow conclusively finished handing 'pm'
7890 even without any explicit ACKs */
7891 if ((PMT_CORE == s->pmt) &&
7892 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7894 /* Full message sent, and over reliabile channel */
7895 client_send_response (pm);
7897 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7898 queue->tc->details.communicator.cc) &&
7899 (PMT_FRAGMENT_BOX == s->pmt))
7901 struct PendingMessage *pos;
7903 /* Fragment sent over reliabile channel */
7904 free_fragment_tree (s);
7905 pos = s->frag_parent;
7906 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7908 /* check if subtree is done */
7909 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7913 pos = s->frag_parent;
7914 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7918 /* Was this the last applicable fragmment? */
7919 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7920 client_send_response (pm);
7922 else if (PMT_CORE != pm->pmt)
7924 /* This was an acknowledgement of some type, always free */
7925 free_pending_message (pm);
7929 /* Message not finished, waiting for acknowledgement.
7930 Update time by which we might retransmit 's' based on queue
7931 characteristics (i.e. RTT); it takes one RTT for the message to
7932 arrive and the ACK to come back in the best case; but the other
7933 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7934 retransmitting. Note that in the future this heuristic should
7935 likely be improved further (measure RTT stability, consider
7936 message urgency and size when delaying ACKs, etc.) */
7937 update_pm_next_attempt (s,
7938 GNUNET_TIME_relative_to_absolute (
7939 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7943 /* finally, re-schedule queue transmission task itself */
7944 schedule_transmit_on_queue (queue, GNUNET_NO);
7949 * Queue to a peer went down. Process the request.
7951 * @param cls the client
7952 * @param dqm the send message that was sent
7955 handle_del_queue_message (void *cls,
7956 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7958 struct TransportClient *tc = cls;
7960 if (CT_COMMUNICATOR != tc->type)
7963 GNUNET_SERVICE_client_drop (tc->client);
7966 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7967 queue = queue->next_client)
7969 struct Neighbour *neighbour = queue->neighbour;
7971 if ((dqm->qid != queue->qid) ||
7972 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7975 GNUNET_SERVICE_client_continue (tc->client);
7979 GNUNET_SERVICE_client_drop (tc->client);
7984 * Message was transmitted. Process the request.
7986 * @param cls the client
7987 * @param sma the send message that was sent
7990 handle_send_message_ack (void *cls,
7991 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7993 struct TransportClient *tc = cls;
7994 struct QueueEntry *qe;
7995 struct PendingMessage *pm;
7997 if (CT_COMMUNICATOR != tc->type)
8000 GNUNET_SERVICE_client_drop (tc->client);
8004 /* find our queue entry matching the ACK */
8006 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8007 queue = queue->next_client)
8009 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
8011 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
8014 if (qep->mid != sma->mid)
8023 /* this should never happen */
8025 GNUNET_SERVICE_client_drop (tc->client);
8028 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
8029 qe->queue->queue_tail,
8031 qe->queue->queue_length--;
8032 tc->details.communicator.total_queue_length--;
8033 GNUNET_SERVICE_client_continue (tc->client);
8035 /* if applicable, resume transmissions that waited on ACK */
8036 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
8037 tc->details.communicator.total_queue_length)
8039 /* Communicator dropped below threshold, resume all queues
8040 incident with this client! */
8041 GNUNET_STATISTICS_update (
8043 "# Transmission throttled due to communicator queue limit",
8046 for (struct Queue *queue = tc->details.communicator.queue_head;
8048 queue = queue->next_client)
8049 schedule_transmit_on_queue (queue, GNUNET_NO);
8051 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
8053 /* queue dropped below threshold; only resume this one queue */
8054 GNUNET_STATISTICS_update (GST_stats,
8055 "# Transmission throttled due to queue queue limit",
8058 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
8061 if (NULL != (pm = qe->pm))
8063 struct Neighbour *n;
8065 GNUNET_assert (qe == pm->qe);
8067 /* If waiting for this communicator may have blocked transmission
8068 of pm on other queues for this neighbour, force schedule
8069 transmit on queue for queues of the neighbour */
8071 if (n->pending_msg_head == pm)
8073 for (struct Queue *queue = n->queue_head; NULL != queue;
8074 queue = queue->next_neighbour)
8075 schedule_transmit_on_queue (queue, GNUNET_NO);
8077 if (GNUNET_OK != ntohl (sma->status))
8080 GNUNET_ERROR_TYPE_INFO,
8081 "Queue failed in transmission, will try retransmission immediately\n");
8082 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
8090 * Iterator telling new MONITOR client about all existing
8093 * @param cls the new `struct TransportClient`
8094 * @param pid a connected peer
8095 * @param value the `struct Neighbour` with more information
8096 * @return #GNUNET_OK (continue to iterate)
8099 notify_client_queues (void *cls,
8100 const struct GNUNET_PeerIdentity *pid,
8103 struct TransportClient *tc = cls;
8104 struct Neighbour *neighbour = value;
8106 GNUNET_assert (CT_MONITOR == tc->type);
8107 for (struct Queue *q = neighbour->queue_head; NULL != q;
8108 q = q->next_neighbour)
8110 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
8112 .num_msg_pending = q->num_msg_pending,
8113 .num_bytes_pending = q->num_bytes_pending};
8115 notify_monitor (tc, pid, q->address, q->nt, &me);
8122 * Initialize a monitor client.
8124 * @param cls the client
8125 * @param start the start message that was sent
8128 handle_monitor_start (void *cls,
8129 const struct GNUNET_TRANSPORT_MonitorStart *start)
8131 struct TransportClient *tc = cls;
8133 if (CT_NONE != tc->type)
8136 GNUNET_SERVICE_client_drop (tc->client);
8139 tc->type = CT_MONITOR;
8140 tc->details.monitor.peer = start->peer;
8141 tc->details.monitor.one_shot = ntohl (start->one_shot);
8142 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
8143 GNUNET_SERVICE_client_mark_monitor (tc->client);
8144 GNUNET_SERVICE_client_continue (tc->client);
8149 * Find transport client providing communication service
8150 * for the protocol @a prefix.
8152 * @param prefix communicator name
8153 * @return NULL if no such transport client is available
8155 static struct TransportClient *
8156 lookup_communicator (const char *prefix)
8158 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
8160 if (CT_COMMUNICATOR != tc->type)
8162 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
8166 GNUNET_ERROR_TYPE_WARNING,
8167 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
8174 * Signature of a function called with a communicator @a address of a peer
8175 * @a pid that an application wants us to connect to.
8177 * @param pid target peer
8178 * @param address the address to try
8181 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
8183 static uint32_t idgen;
8184 struct TransportClient *tc;
8186 struct GNUNET_TRANSPORT_CreateQueue *cqm;
8187 struct GNUNET_MQ_Envelope *env;
8190 prefix = GNUNET_HELLO_address_to_prefix (address);
8193 GNUNET_break (0); /* We got an invalid address!? */
8196 tc = lookup_communicator (prefix);
8199 GNUNET_STATISTICS_update (GST_stats,
8200 "# Suggestions ignored due to missing communicator",
8205 /* forward suggestion for queue creation to communicator */
8206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8207 "Request #%u for `%s' communicator to create queue to `%s'\n",
8208 (unsigned int) idgen,
8211 alen = strlen (address) + 1;
8213 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
8214 cqm->request_id = htonl (idgen++);
8215 cqm->receiver = *pid;
8216 memcpy (&cqm[1], address, alen);
8217 GNUNET_MQ_send (tc->mq, env);
8222 * The queue @a q (which matches the peer and address in @a vs) is
8223 * ready for queueing. We should now queue the validation request.
8225 * @param q queue to send on
8226 * @param vs state to derive validation challenge from
8229 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
8231 struct TransportValidationChallengeMessage tvc;
8233 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
8235 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
8236 tvc.header.size = htons (sizeof (tvc));
8237 tvc.reserved = htonl (0);
8238 tvc.challenge = vs->challenge;
8239 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
8240 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
8245 * Task run periodically to validate some address based on #validation_heap.
8250 validation_start_cb (void *cls)
8252 struct ValidationState *vs;
8256 validation_task = NULL;
8257 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
8258 /* drop validations past their expiration */
8261 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
8263 free_validation_state (vs);
8264 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
8267 return; /* woopsie, no more addresses known, should only
8268 happen if we're really a lonely peer */
8269 q = find_queue (&vs->pid, vs->address);
8272 vs->awaiting_queue = GNUNET_YES;
8273 suggest_to_connect (&vs->pid, vs->address);
8276 validation_transmit_on_queue (q, vs);
8277 /* Finally, reschedule next attempt */
8278 vs->challenge_backoff =
8279 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
8280 MAX_VALIDATION_CHALLENGE_FREQ);
8281 update_next_challenge_time (vs,
8282 GNUNET_TIME_relative_to_absolute (
8283 vs->challenge_backoff));
8288 * Closure for #check_connection_quality.
8290 struct QueueQualityContext
8293 * Set to the @e k'th queue encountered.
8298 * Set to the number of quality queues encountered.
8300 unsigned int quality_count;
8303 * Set to the total number of queues encountered.
8305 unsigned int num_queues;
8308 * Decremented for each queue, for selection of the
8309 * k-th queue in @e q.
8316 * Check whether any queue to the given neighbour is
8317 * of a good "quality" and if so, increment the counter.
8318 * Also counts the total number of queues, and returns
8319 * the k-th queue found.
8321 * @param cls a `struct QueueQualityContext *` with counters
8322 * @param pid peer this is about
8323 * @param value a `struct Neighbour`
8324 * @return #GNUNET_OK (continue to iterate)
8327 check_connection_quality (void *cls,
8328 const struct GNUNET_PeerIdentity *pid,
8331 struct QueueQualityContext *ctx = cls;
8332 struct Neighbour *n = value;
8337 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8342 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
8343 statistics and consider those as well here? */
8344 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
8345 do_inc = GNUNET_YES;
8347 if (GNUNET_YES == do_inc)
8348 ctx->quality_count++;
8354 * Task run when we CONSIDER initiating a DV learn
8355 * process. We first check that sending out a message is
8356 * even possible (queues exist), then that it is desirable
8357 * (if not, reschedule the task for later), and finally
8358 * we may then begin the job. If there are too many
8359 * entries in the #dvlearn_map, we purge the oldest entry
8365 start_dv_learn (void *cls)
8367 struct LearnLaunchEntry *lle;
8368 struct QueueQualityContext qqc;
8369 struct TransportDVLearnMessage dvl;
8372 dvlearn_task = NULL;
8373 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8374 return; /* lost all connectivity, cannot do learning */
8375 qqc.quality_count = 0;
8377 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8378 &check_connection_quality,
8380 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8382 struct GNUNET_TIME_Relative delay;
8383 unsigned int factor;
8385 /* scale our retries by how far we are above the threshold */
8386 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8387 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8388 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8391 /* remove old entries in #dvlearn_map if it has grown too big */
8392 while (MAX_DV_LEARN_PENDING >=
8393 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8396 GNUNET_assert (GNUNET_YES ==
8397 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8398 &lle->challenge.value,
8400 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8403 /* setup data structure for learning */
8404 lle = GNUNET_new (struct LearnLaunchEntry);
8405 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8407 sizeof (lle->challenge));
8408 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8409 GNUNET_break (GNUNET_YES ==
8410 GNUNET_CONTAINER_multishortmap_put (
8412 &lle->challenge.value,
8414 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8415 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8416 dvl.header.size = htons (sizeof (dvl));
8417 dvl.num_hops = htons (0);
8418 dvl.bidirectional = htons (0);
8419 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8420 dvl.monotonic_time =
8421 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8423 struct DvInitPS dvip = {.purpose.purpose = htonl (
8424 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8425 .purpose.size = htonl (sizeof (dvip)),
8426 .monotonic_time = dvl.monotonic_time,
8427 .challenge = lle->challenge};
8429 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8433 dvl.initiator = GST_my_identity;
8434 dvl.challenge = lle->challenge;
8436 qqc.quality_count = 0;
8437 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8440 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8441 &check_connection_quality,
8443 GNUNET_assert (NULL != qqc.q);
8445 /* Do this as close to transmission time as possible! */
8446 lle->launch_time = GNUNET_TIME_absolute_get ();
8448 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8449 /* reschedule this job, randomizing the time it runs (but no
8451 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8452 DV_LEARN_BASE_FREQUENCY),
8459 * A new queue has been created, check if any address validation
8460 * requests have been waiting for it.
8462 * @param cls a `struct Queue`
8463 * @param pid peer concerned (unused)
8464 * @param value a `struct ValidationState`
8465 * @return #GNUNET_NO if a match was found and we can stop looking
8468 check_validation_request_pending (void *cls,
8469 const struct GNUNET_PeerIdentity *pid,
8472 struct Queue *q = cls;
8473 struct ValidationState *vs = value;
8476 if ((GNUNET_YES == vs->awaiting_queue) &&
8477 (0 == strcmp (vs->address, q->address)))
8479 vs->awaiting_queue = GNUNET_NO;
8480 validation_transmit_on_queue (q, vs);
8488 * Function called with the monotonic time of a DV initiator
8489 * by PEERSTORE. Updates the time.
8491 * @param cls a `struct Neighbour`
8492 * @param record the information found, NULL for the last call
8493 * @param emsg error message
8496 neighbour_dv_monotime_cb (void *cls,
8497 const struct GNUNET_PEERSTORE_Record *record,
8500 struct Neighbour *n = cls;
8501 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8506 /* we're done with #neighbour_dv_monotime_cb() invocations,
8507 continue normal processing */
8509 n->dv_monotime_available = GNUNET_YES;
8512 if (sizeof (*mtbe) != record->value_size)
8517 mtbe = record->value;
8518 n->last_dv_learn_monotime =
8519 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8520 GNUNET_TIME_absolute_ntoh (*mtbe));
8525 * New queue became available. Process the request.
8527 * @param cls the client
8528 * @param aqm the send message that was sent
8531 handle_add_queue_message (void *cls,
8532 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8534 struct TransportClient *tc = cls;
8535 struct Queue *queue;
8536 struct Neighbour *neighbour;
8540 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8542 /* MTU so small as to be useless for transmissions,
8543 required for #fragment_message()! */
8544 GNUNET_break_op (0);
8545 GNUNET_SERVICE_client_drop (tc->client);
8548 neighbour = lookup_neighbour (&aqm->receiver);
8549 if (NULL == neighbour)
8551 neighbour = GNUNET_new (struct Neighbour);
8552 neighbour->message_uuid_ctr =
8553 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8554 neighbour->pid = aqm->receiver;
8555 GNUNET_assert (GNUNET_OK ==
8556 GNUNET_CONTAINER_multipeermap_put (
8560 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8562 GNUNET_PEERSTORE_iterate (peerstore,
8565 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8566 &neighbour_dv_monotime_cb,
8569 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8570 addr = (const char *) &aqm[1];
8572 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8574 queue->address = (const char *) &queue[1];
8575 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8576 queue->qid = aqm->qid;
8577 queue->mtu = ntohl (aqm->mtu);
8578 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8579 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8580 queue->neighbour = neighbour;
8581 memcpy (&queue[1], addr, addr_len);
8582 /* notify monitors about new queue */
8584 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8586 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8588 GNUNET_CONTAINER_MDLL_insert (neighbour,
8589 neighbour->queue_head,
8590 neighbour->queue_tail,
8592 GNUNET_CONTAINER_MDLL_insert (client,
8593 tc->details.communicator.queue_head,
8594 tc->details.communicator.queue_tail,
8596 /* check if valdiations are waiting for the queue */
8598 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8600 &check_validation_request_pending,
8602 /* might be our first queue, try launching DV learning */
8603 if (NULL == dvlearn_task)
8604 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8605 GNUNET_SERVICE_client_continue (tc->client);
8610 * Communicator tells us that our request to create a queue "worked", that
8611 * is setting up the queue is now in process.
8613 * @param cls the `struct TransportClient`
8614 * @param cqr confirmation message
8617 handle_queue_create_ok (void *cls,
8618 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8620 struct TransportClient *tc = cls;
8622 if (CT_COMMUNICATOR != tc->type)
8625 GNUNET_SERVICE_client_drop (tc->client);
8628 GNUNET_STATISTICS_update (GST_stats,
8629 "# Suggestions succeeded at communicator",
8632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8633 "Request #%u for communicator to create queue succeeded\n",
8634 (unsigned int) ntohs (cqr->request_id));
8635 GNUNET_SERVICE_client_continue (tc->client);
8640 * Communicator tells us that our request to create a queue failed. This
8641 * usually indicates that the provided address is simply invalid or that the
8642 * communicator's resources are exhausted.
8644 * @param cls the `struct TransportClient`
8645 * @param cqr failure message
8648 handle_queue_create_fail (
8650 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8652 struct TransportClient *tc = cls;
8654 if (CT_COMMUNICATOR != tc->type)
8657 GNUNET_SERVICE_client_drop (tc->client);
8660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8661 "Request #%u for communicator to create queue failed\n",
8662 (unsigned int) ntohs (cqr->request_id));
8663 GNUNET_STATISTICS_update (GST_stats,
8664 "# Suggestions failed in queue creation at communicator",
8667 GNUNET_SERVICE_client_continue (tc->client);
8672 * We have received a `struct ExpressPreferenceMessage` from an application
8675 * @param cls handle to the client
8676 * @param msg the start message
8679 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8681 struct TransportClient *tc = cls;
8682 struct PeerRequest *pr;
8684 if (CT_APPLICATION != tc->type)
8687 GNUNET_SERVICE_client_drop (tc->client);
8690 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8695 GNUNET_SERVICE_client_drop (tc->client);
8698 (void) stop_peer_request (tc, &pr->pid, pr);
8699 GNUNET_SERVICE_client_continue (tc->client);
8704 * Closure for #check_known_address.
8706 struct CheckKnownAddressContext
8709 * Set to the address we are looking for.
8711 const char *address;
8714 * Set to a matching validation state, if one was found.
8716 struct ValidationState *vs;
8721 * Test if the validation state in @a value matches the
8722 * address from @a cls.
8724 * @param cls a `struct CheckKnownAddressContext`
8725 * @param pid unused (must match though)
8726 * @param value a `struct ValidationState`
8727 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8730 check_known_address (void *cls,
8731 const struct GNUNET_PeerIdentity *pid,
8734 struct CheckKnownAddressContext *ckac = cls;
8735 struct ValidationState *vs = value;
8738 if (0 != strcmp (vs->address, ckac->address))
8746 * Start address validation.
8748 * @param pid peer the @a address is for
8749 * @param address an address to reach @a pid (presumably)
8752 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8753 const char *address)
8755 struct GNUNET_TIME_Absolute now;
8756 struct ValidationState *vs;
8757 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8759 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8761 &check_known_address,
8763 if (NULL != (vs = ckac.vs))
8765 /* if 'vs' is not currently valid, we need to speed up retrying the
8767 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8769 /* reduce backoff as we got a fresh advertisement */
8770 vs->challenge_backoff =
8771 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8772 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8774 update_next_challenge_time (vs,
8775 GNUNET_TIME_relative_to_absolute (
8776 vs->challenge_backoff));
8780 now = GNUNET_TIME_absolute_get ();
8781 vs = GNUNET_new (struct ValidationState);
8784 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8785 vs->first_challenge_use = now;
8786 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8787 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8789 sizeof (vs->challenge));
8790 vs->address = GNUNET_strdup (address);
8791 GNUNET_assert (GNUNET_YES ==
8792 GNUNET_CONTAINER_multipeermap_put (
8796 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8797 update_next_challenge_time (vs, now);
8802 * Function called by PEERSTORE for each matching record.
8804 * @param cls closure
8805 * @param record peerstore record information
8806 * @param emsg error message, or NULL if no errors
8809 handle_hello (void *cls,
8810 const struct GNUNET_PEERSTORE_Record *record,
8813 struct PeerRequest *pr = cls;
8818 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8819 "Got failure from PEERSTORE: %s\n",
8823 val = record->value;
8824 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8829 start_address_validation (&pr->pid, (const char *) record->value);
8834 * We have received a `struct ExpressPreferenceMessage` from an application
8837 * @param cls handle to the client
8838 * @param msg the start message
8841 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8843 struct TransportClient *tc = cls;
8844 struct PeerRequest *pr;
8846 if (CT_NONE == tc->type)
8848 tc->type = CT_APPLICATION;
8849 tc->details.application.requests =
8850 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8852 if (CT_APPLICATION != tc->type)
8855 GNUNET_SERVICE_client_drop (tc->client);
8858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8859 "Client suggested we talk to %s with preference %d at rate %u\n",
8860 GNUNET_i2s (&msg->peer),
8861 (int) ntohl (msg->pk),
8862 (int) ntohl (msg->bw.value__));
8863 pr = GNUNET_new (struct PeerRequest);
8865 pr->pid = msg->peer;
8867 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
8868 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8869 tc->details.application.requests,
8872 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8876 GNUNET_SERVICE_client_drop (tc->client);
8879 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8882 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8885 GNUNET_SERVICE_client_continue (tc->client);
8890 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8893 * @param cls a `struct TransportClient *`
8894 * @param m message to verify
8895 * @return #GNUNET_OK on success
8898 check_request_hello_validation (void *cls,
8899 const struct RequestHelloValidationMessage *m)
8902 GNUNET_MQ_check_zero_termination (m);
8908 * A client encountered an address of another peer. Consider validating it,
8909 * and if validation succeeds, persist it to PEERSTORE.
8911 * @param cls a `struct TransportClient *`
8912 * @param m message to verify
8915 handle_request_hello_validation (void *cls,
8916 const struct RequestHelloValidationMessage *m)
8918 struct TransportClient *tc = cls;
8920 start_address_validation (&m->peer, (const char *) &m[1]);
8921 GNUNET_SERVICE_client_continue (tc->client);
8926 * Free neighbour entry.
8930 * @param value a `struct Neighbour`
8931 * @return #GNUNET_OK (always)
8934 free_neighbour_cb (void *cls,
8935 const struct GNUNET_PeerIdentity *pid,
8938 struct Neighbour *neighbour = value;
8942 GNUNET_break (0); // should this ever happen?
8943 free_neighbour (neighbour);
8950 * Free DV route entry.
8954 * @param value a `struct DistanceVector`
8955 * @return #GNUNET_OK (always)
8958 free_dv_routes_cb (void *cls,
8959 const struct GNUNET_PeerIdentity *pid,
8962 struct DistanceVector *dv = value;
8973 * Free ephemeral entry.
8977 * @param value a `struct EphemeralCacheEntry`
8978 * @return #GNUNET_OK (always)
8981 free_ephemeral_cb (void *cls,
8982 const struct GNUNET_PeerIdentity *pid,
8985 struct EphemeralCacheEntry *ece = value;
8989 free_ephemeral (ece);
8995 * Free validation state.
8999 * @param value a `struct ValidationState`
9000 * @return #GNUNET_OK (always)
9003 free_validation_state_cb (void *cls,
9004 const struct GNUNET_PeerIdentity *pid,
9007 struct ValidationState *vs = value;
9011 free_validation_state (vs);
9017 * Free pending acknowledgement.
9021 * @param value a `struct PendingAcknowledgement`
9022 * @return #GNUNET_OK (always)
9025 free_pending_ack_cb (void *cls,
9026 const struct GNUNET_ShortHashCode *key,
9029 struct PendingAcknowledgement *pa = value;
9033 free_pending_acknowledgement (pa);
9039 * Free acknowledgement cummulator.
9043 * @param value a `struct AcknowledgementCummulator`
9044 * @return #GNUNET_OK (always)
9047 free_ack_cummulator_cb (void *cls,
9048 const struct GNUNET_PeerIdentity *pid,
9051 struct AcknowledgementCummulator *ac = value;
9061 * Function called when the service shuts down. Unloads our plugins
9062 * and cancels pending validations.
9064 * @param cls closure, unused
9067 do_shutdown (void *cls)
9069 struct LearnLaunchEntry *lle;
9072 if (NULL != ephemeral_task)
9074 GNUNET_SCHEDULER_cancel (ephemeral_task);
9075 ephemeral_task = NULL;
9077 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9078 if (NULL != peerstore)
9080 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9083 if (NULL != GST_stats)
9085 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9088 if (NULL != GST_my_private_key)
9090 GNUNET_free (GST_my_private_key);
9091 GST_my_private_key = NULL;
9093 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9094 &free_ack_cummulator_cb,
9096 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9097 ack_cummulators = NULL;
9098 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
9099 &free_pending_ack_cb,
9101 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
9102 pending_acks = NULL;
9103 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9104 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9106 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9107 GNUNET_CONTAINER_multipeermap_destroy (links);
9109 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9110 &free_backtalker_cb,
9112 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9114 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9115 &free_validation_state_cb,
9117 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9118 validation_map = NULL;
9119 while (NULL != (lle = lle_head))
9121 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9124 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
9126 GNUNET_CONTAINER_heap_destroy (validation_heap);
9127 validation_heap = NULL;
9128 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
9129 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
9131 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
9134 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
9135 ephemeral_map = NULL;
9136 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
9137 ephemeral_heap = NULL;
9142 * Initiate transport service.
9144 * @param cls closure
9145 * @param c configuration to use
9146 * @param service the initialized service
9150 const struct GNUNET_CONFIGURATION_Handle *c,
9151 struct GNUNET_SERVICE_Handle *service)
9156 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
9158 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9159 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
9160 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
9161 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9162 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
9163 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9164 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
9166 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
9167 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
9169 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9171 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
9172 GST_my_private_key =
9173 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
9174 if (NULL == GST_my_private_key)
9177 GNUNET_ERROR_TYPE_ERROR,
9179 "Transport service is lacking key configuration settings. Exiting.\n"));
9180 GNUNET_SCHEDULER_shutdown ();
9183 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
9184 &GST_my_identity.public_key);
9185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9186 "My identity is `%s'\n",
9187 GNUNET_i2s_full (&GST_my_identity));
9188 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
9189 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
9190 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
9191 if (NULL == peerstore)
9194 GNUNET_SCHEDULER_shutdown ();
9201 * Define "main" method using service macro.
9203 GNUNET_SERVICE_MAIN (
9205 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
9208 &client_disconnect_cb,
9210 /* communication with applications */
9211 GNUNET_MQ_hd_fixed_size (suggest,
9212 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
9213 struct ExpressPreferenceMessage,
9215 GNUNET_MQ_hd_fixed_size (suggest_cancel,
9216 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
9217 struct ExpressPreferenceMessage,
9219 GNUNET_MQ_hd_var_size (request_hello_validation,
9220 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
9221 struct RequestHelloValidationMessage,
9223 /* communication with core */
9224 GNUNET_MQ_hd_fixed_size (client_start,
9225 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
9226 struct StartMessage,
9228 GNUNET_MQ_hd_var_size (client_send,
9229 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
9230 struct OutboundMessage,
9232 GNUNET_MQ_hd_fixed_size (client_recv_ok,
9233 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
9234 struct RecvOkMessage,
9236 /* communication with communicators */
9237 GNUNET_MQ_hd_var_size (communicator_available,
9238 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
9239 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
9241 GNUNET_MQ_hd_var_size (communicator_backchannel,
9242 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
9243 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
9245 GNUNET_MQ_hd_var_size (add_address,
9246 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
9247 struct GNUNET_TRANSPORT_AddAddressMessage,
9249 GNUNET_MQ_hd_fixed_size (del_address,
9250 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
9251 struct GNUNET_TRANSPORT_DelAddressMessage,
9253 GNUNET_MQ_hd_var_size (incoming_msg,
9254 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
9255 struct GNUNET_TRANSPORT_IncomingMessage,
9257 GNUNET_MQ_hd_fixed_size (queue_create_ok,
9258 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
9259 struct GNUNET_TRANSPORT_CreateQueueResponse,
9261 GNUNET_MQ_hd_fixed_size (queue_create_fail,
9262 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
9263 struct GNUNET_TRANSPORT_CreateQueueResponse,
9265 GNUNET_MQ_hd_var_size (add_queue_message,
9266 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
9267 struct GNUNET_TRANSPORT_AddQueueMessage,
9269 GNUNET_MQ_hd_fixed_size (del_queue_message,
9270 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
9271 struct GNUNET_TRANSPORT_DelQueueMessage,
9273 GNUNET_MQ_hd_fixed_size (send_message_ack,
9274 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
9275 struct GNUNET_TRANSPORT_SendMessageToAck,
9277 /* communication with monitors */
9278 GNUNET_MQ_hd_fixed_size (monitor_start,
9279 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
9280 struct GNUNET_TRANSPORT_MonitorStart,
9282 GNUNET_MQ_handler_end ());
9285 /* end of file gnunet-service-transport.c */