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 * - complete flow control push back from CORE via TRANSPORT to communicators:
28 * + resume communicators in handle_client_recv_ok (see FIXME)
29 * + count transmissions to CORE and suspend communicators if window is full
30 * - check flow control push back from TRANSPROT to CORE:
31 * + check when to send ACKs
32 * - change transport-core API to provide proper flow control in both
33 * directions, allow multiple messages per peer simultaneously (tag
34 * confirmations with unique message ID), and replace quota-out with
35 * proper flow control; specify transmission preferences (latency,
36 * reliability, etc.) per message!
40 * - review retransmission logic, right now there is no smartness there!
41 * => congestion control, flow control, etc
44 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
45 * => Need 128 bit hash map though!
46 * - queue_send_msg and route_message both by API design have to make copies
47 * of the payload, and route_message on top of that requires a malloc/free.
48 * Change design to approximate "zero" copy better...
49 * - could avoid copying body of message into each fragment and keep
50 * fragments as just pointers into the original message and only
51 * fully build fragments just before transmission (optimization, should
52 * reduce CPU and memory use)
53 * - if messages are below MTU, consider adding ACKs and other stuff
54 * (requires planning at receiver, and additional MST-style demultiplex
56 * - When we passively learned DV (with unconfirmed freshness), we
57 * right now add the path to our list but with a zero path_valid_until
58 * time and only use it for unconfirmed routes. However, we could consider
59 * triggering an explicit validation mechansim ourselves, specifically routing
60 * a challenge-response message over the path (OPTIMIZATION-FIXME).
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 * Unique identifier we attach to a message.
315 * Unique value identifying a fragment, in NBO.
317 uint32_t uuid GNUNET_PACKED;
322 * Type of a nonce used for challenges.
324 struct ChallengeNonceP
327 * The value of the nonce. Note that this is NOT a hash.
329 struct GNUNET_ShortHashCode value;
334 * Outer layer of an encapsulated backchannel message.
336 struct TransportBackchannelEncapsulationMessage
339 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
341 struct GNUNET_MessageHeader header;
344 * Reserved, always zero.
346 uint32_t reserved GNUNET_PACKED;
349 * Target's peer identity (as backchannels may be transmitted
350 * indirectly, or even be broadcast).
352 struct GNUNET_PeerIdentity target;
355 * Ephemeral key setup by the sender for @e target, used
356 * to encrypt the payload.
358 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
361 * We use an IV here as the @e ephemeral_key is re-used for
362 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
364 struct GNUNET_ShortHashCode iv;
367 * HMAC over the ciphertext of the encrypted, variable-size
368 * body that follows. Verified via DH of @e target and
371 struct GNUNET_HashCode hmac;
373 /* Followed by encrypted, variable-size payload */
378 * Body by which a peer confirms that it is using an ephemeral key.
380 struct EphemeralConfirmationPS
384 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
386 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
389 * How long is this signature over the ephemeral key valid?
391 * Note that the receiver MUST IGNORE the absolute time, and only interpret
392 * the value as a mononic time and reject "older" values than the last one
393 * observed. This is necessary as we do not want to require synchronized
394 * clocks and may not have a bidirectional communication channel.
396 * Even with this, there is no real guarantee against replay achieved here,
397 * unless the latest timestamp is persisted. While persistence should be
398 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
399 * communicators must protect against replay attacks when using backchannel
402 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
405 * Target's peer identity.
407 struct GNUNET_PeerIdentity target;
410 * Ephemeral key setup by the sender for @e target, used
411 * to encrypt the payload.
413 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
418 * Plaintext of the variable-size payload that is encrypted
419 * within a `struct TransportBackchannelEncapsulationMessage`
421 struct TransportBackchannelRequestPayloadP
425 * Sender's peer identity.
427 struct GNUNET_PeerIdentity sender;
430 * Signature of the sender over an
431 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
433 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
436 * Current monotonic time of the sending transport service. Used to
437 * detect replayed messages. Note that the receiver should remember
438 * a list of the recently seen timestamps and only reject messages
439 * if the timestamp is in the list, or the list is "full" and the
440 * timestamp is smaller than the lowest in the list.
442 * Like the @e ephemeral_validity, the list of timestamps per peer should be
443 * persisted to guard against replays after restarts.
445 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
447 /* Followed by a `struct GNUNET_MessageHeader` with a message
448 for a communicator */
450 /* Followed by a 0-termianted string specifying the name of
451 the communicator which is to receive the message */
456 * Outer layer of an encapsulated unfragmented application message sent
457 * over an unreliable channel.
459 struct TransportReliabilityBoxMessage
462 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
464 struct GNUNET_MessageHeader header;
467 * Number of messages still to be sent before a commulative
468 * ACK is requested. Zero if an ACK is requested immediately.
469 * In NBO. Note that the receiver may send the ACK faster
470 * if it believes that is reasonable.
472 uint32_t ack_countdown GNUNET_PACKED;
475 * Unique ID of the message used for signalling receipt of
476 * messages sent over possibly unreliable channels. Should
479 struct AcknowledgementUUIDP ack_uuid;
484 * Acknowledgement payload.
486 struct TransportCummulativeAckPayloadP
489 * How long was the ACK delayed for generating cummulative ACKs?
490 * Used to calculate the correct network RTT by taking the receipt
491 * time of the ack minus the transmission time of the sender minus
494 struct GNUNET_TIME_RelativeNBO ack_delay;
497 * UUID of a message being acknowledged.
499 struct AcknowledgementUUIDP ack_uuid;
504 * Confirmation that the receiver got a
505 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
506 * confirmation may be transmitted over a completely different queue,
507 * so ACKs are identified by a combination of PID of sender and
508 * message UUID, without the queue playing any role!
510 struct TransportReliabilityAckMessage
513 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
515 struct GNUNET_MessageHeader header;
518 * Counter of ACKs transmitted by the sender to us. Incremented
519 * by one for each ACK, used to detect how many ACKs were lost.
521 uint32_t ack_counter GNUNET_PACKED;
523 /* followed by any number of `struct TransportCummulativeAckPayloadP`
524 messages providing ACKs */
529 * Outer layer of an encapsulated fragmented application message.
531 struct TransportFragmentBoxMessage
534 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
536 struct GNUNET_MessageHeader header;
539 * Unique ID of this fragment (and fragment transmission!). Will
540 * change even if a fragement is retransmitted to make each
541 * transmission attempt unique! If a client receives a duplicate
542 * fragment (same @e frag_off for same @a msg_uuid, it must send
543 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
545 struct AcknowledgementUUIDP ack_uuid;
548 * Original message ID for of the message that all the fragments
549 * belong to. Must be the same for all fragments.
551 struct MessageUUIDP msg_uuid;
554 * Offset of this fragment in the overall message.
556 uint16_t frag_off GNUNET_PACKED;
559 * Total size of the message that is being fragmented.
561 uint16_t msg_size GNUNET_PACKED;
566 * Content signed by the initator during DV learning.
568 * The signature is required to prevent DDoS attacks. A peer sending out this
569 * message is potentially generating a lot of traffic that will go back to the
570 * initator, as peers receiving this message will try to let the initiator
571 * know that they got the message.
573 * Without this signature, an attacker could abuse this mechanism for traffic
574 * amplification, sending a lot of traffic to a peer by putting out this type
575 * of message with the victim's peer identity.
577 * Even with just a signature, traffic amplification would be possible via
578 * replay attacks. The @e monotonic_time limits such replay attacks, as every
579 * potential amplificator will check the @e monotonic_time and only respond
580 * (at most) once per message.
585 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
587 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
590 * Time at the initiator when generating the signature.
592 * Note that the receiver MUST IGNORE the absolute time, and only interpret
593 * the value as a mononic time and reject "older" values than the last one
594 * observed. This is necessary as we do not want to require synchronized
595 * clocks and may not have a bidirectional communication channel.
597 * Even with this, there is no real guarantee against replay achieved here,
598 * unless the latest timestamp is persisted. Persistence should be
599 * provided via PEERSTORE if possible.
601 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
604 * Challenge value used by the initiator to re-identify the path.
606 struct ChallengeNonceP challenge;
611 * Content signed by each peer during DV learning.
613 * This assues the initiator of the DV learning operation that the hop from @e
614 * pred via the signing peer to @e succ actually exists. This makes it
615 * impossible for an adversary to supply the network with bogus routes.
617 * The @e challenge is included to provide replay protection for the
618 * initiator. This way, the initiator knows that the hop existed after the
619 * original @e challenge was first transmitted, providing a freshness metric.
621 * Peers other than the initiator that passively learn paths by observing
622 * these messages do NOT benefit from this. Here, an adversary may indeed
623 * replay old messages. Thus, passively learned paths should always be
624 * immediately marked as "potentially stale".
629 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
631 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
634 * Identity of the previous peer on the path.
636 struct GNUNET_PeerIdentity pred;
639 * Identity of the next peer on the path.
641 struct GNUNET_PeerIdentity succ;
644 * Challenge value used by the initiator to re-identify the path.
646 struct ChallengeNonceP challenge;
651 * An entry describing a peer on a path in a
652 * `struct TransportDVLearnMessage` message.
657 * Identity of a peer on the path.
659 struct GNUNET_PeerIdentity hop;
662 * Signature of this hop over the path, of purpose
663 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
665 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
670 * Internal message used by transport for distance vector learning.
671 * If @e num_hops does not exceed the threshold, peers should append
672 * themselves to the peer list and flood the message (possibly only
673 * to a subset of their neighbours to limit discoverability of the
674 * network topology). To the extend that the @e bidirectional bits
675 * are set, peers may learn the inverse paths even if they did not
678 * Unless received on a bidirectional queue and @e num_hops just
679 * zero, peers that can forward to the initator should always try to
680 * forward to the initiator.
682 struct TransportDVLearnMessage
685 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
687 struct GNUNET_MessageHeader header;
690 * Number of hops this messages has travelled, in NBO. Zero if
693 uint16_t num_hops GNUNET_PACKED;
696 * Bitmask of the last 16 hops indicating whether they are confirmed
697 * available (without DV) in both directions or not, in NBO. Used
698 * to possibly instantly learn a path in both directions. Each peer
699 * should shift this value by one to the left, and then set the
700 * lowest bit IF the current sender can be reached from it (without
703 uint16_t bidirectional GNUNET_PACKED;
706 * Peers receiving this message and delaying forwarding to other
707 * peers for any reason should increment this value by the non-network
708 * delay created by the peer.
710 struct GNUNET_TIME_RelativeNBO non_network_delay;
713 * Time at the initiator when generating the signature.
715 * Note that the receiver MUST IGNORE the absolute time, and only interpret
716 * the value as a mononic time and reject "older" values than the last one
717 * observed. This is necessary as we do not want to require synchronized
718 * clocks and may not have a bidirectional communication channel.
720 * Even with this, there is no real guarantee against replay achieved here,
721 * unless the latest timestamp is persisted. Persistence should be
722 * provided via PEERSTORE if possible.
724 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
727 * Signature of this hop over the path, of purpose
728 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
730 struct GNUNET_CRYPTO_EddsaSignature init_sig;
733 * Identity of the peer that started this learning activity.
735 struct GNUNET_PeerIdentity initiator;
738 * Challenge value used by the initiator to re-identify the path.
740 struct ChallengeNonceP challenge;
742 /* Followed by @e num_hops `struct DVPathEntryP` values,
743 excluding the initiator of the DV trace; the last entry is the
744 current sender; the current peer must not be included. */
749 * Outer layer of an encapsulated message send over multiple hops.
750 * The path given only includes the identities of the subsequent
751 * peers, i.e. it will be empty if we are the receiver. Each
752 * forwarding peer should scan the list from the end, and if it can,
753 * forward to the respective peer. The list should then be shortened
754 * by all the entries up to and including that peer. Each hop should
755 * also increment @e total_hops to allow the receiver to get a precise
756 * estimate on the number of hops the message travelled. Senders must
757 * provide a learned path that thus should work, but intermediaries
758 * know of a shortcut, they are allowed to send the message via that
761 * If a peer finds itself still on the list, it must drop the message.
763 struct TransportDVBoxMessage
766 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
768 struct GNUNET_MessageHeader header;
771 * Number of total hops this messages travelled. In NBO.
772 * @e origin sets this to zero, to be incremented at
775 uint16_t total_hops GNUNET_PACKED;
778 * Number of hops this messages includes. In NBO.
780 uint16_t num_hops GNUNET_PACKED;
783 * Identity of the peer that originated the message.
785 struct GNUNET_PeerIdentity origin;
787 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
788 excluding the @e origin and the current peer, the last must be
789 the ultimate target; if @e num_hops is zero, the receiver of this
790 message is the ultimate target. */
792 /* Followed by the actual message, which itself may be
793 another box, but not a DV_LEARN or DV_BOX message! */
798 * Message send to another peer to validate that it can indeed
799 * receive messages at a particular address.
801 struct TransportValidationChallengeMessage
805 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
807 struct GNUNET_MessageHeader header;
812 uint32_t reserved GNUNET_PACKED;
815 * Challenge to be signed by the receiving peer.
817 struct ChallengeNonceP challenge;
820 * Timestamp of the sender, to be copied into the reply
821 * to allow sender to calculate RTT.
823 struct GNUNET_TIME_AbsoluteNBO sender_time;
828 * Message signed by a peer to confirm that it can indeed
829 * receive messages at a particular address.
831 struct TransportValidationPS
835 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
837 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
840 * How long does the sender believe the address on
841 * which the challenge was received to remain valid?
843 struct GNUNET_TIME_RelativeNBO validity_duration;
846 * Challenge signed by the receiving peer.
848 struct ChallengeNonceP challenge;
853 * Message send to a peer to respond to a
854 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
856 struct TransportValidationResponseMessage
860 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
862 struct GNUNET_MessageHeader header;
867 uint32_t reserved GNUNET_PACKED;
870 * The peer's signature matching the
871 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
873 struct GNUNET_CRYPTO_EddsaSignature signature;
876 * The challenge that was signed by the receiving peer.
878 struct ChallengeNonceP challenge;
881 * Original timestamp of the sender (was @code{sender_time}),
882 * copied into the reply to allow sender to calculate RTT.
884 struct GNUNET_TIME_AbsoluteNBO origin_time;
887 * How long does the sender believe this address to remain
890 struct GNUNET_TIME_RelativeNBO validity_duration;
894 GNUNET_NETWORK_STRUCT_END
898 * What type of client is the `struct TransportClient` about?
903 * We do not know yet (client is fresh).
908 * Is the CORE service, we need to forward traffic to it.
913 * It is a monitor, forward monitor data.
918 * It is a communicator, use for communication.
923 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
930 * Which transmission options are allowable for transmission?
931 * Interpreted bit-wise!
933 enum RouteMessageOptions
936 * Only confirmed, non-DV direct neighbours.
941 * We are allowed to use DV routing for this @a hdr
946 * We are allowed to use unconfirmed queues or DV routes for this message
948 RMO_UNCONFIRMED_ALLOWED = 2,
951 * Reliable and unreliable, DV and non-DV are all acceptable.
953 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
956 * If we have multiple choices, it is OK to send this message
957 * over multiple channels at the same time to improve loss tolerance.
958 * (We do at most 2 transmissions.)
965 * When did we launch this DV learning activity?
967 struct LearnLaunchEntry
971 * Kept (also) in a DLL sorted by launch time.
973 struct LearnLaunchEntry *prev;
976 * Kept (also) in a DLL sorted by launch time.
978 struct LearnLaunchEntry *next;
981 * Challenge that uniquely identifies this activity.
983 struct ChallengeNonceP challenge;
986 * When did we transmit the DV learn message (used to calculate RTT) and
987 * determine freshness of paths learned via this operation.
989 struct GNUNET_TIME_Absolute launch_time;
994 * Entry in our cache of ephemeral keys we currently use. This way, we only
995 * sign an ephemeral once per @e target, and then can re-use it over multiple
996 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
997 * signing is expensive and in some cases we may use backchannel messages a
1000 struct EphemeralCacheEntry
1004 * Target's peer identity (we don't re-use ephemerals
1005 * to limit linkability of messages).
1007 struct GNUNET_PeerIdentity target;
1010 * Signature affirming @e ephemeral_key of type
1011 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1013 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1016 * How long is @e sender_sig valid
1018 struct GNUNET_TIME_Absolute ephemeral_validity;
1021 * What time was @e sender_sig created
1023 struct GNUNET_TIME_Absolute monotime;
1026 * Our ephemeral key.
1028 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1031 * Our private ephemeral key.
1033 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1036 * Node in the ephemeral cache for this entry.
1037 * Used for expiration.
1039 struct GNUNET_CONTAINER_HeapNode *hn;
1044 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1045 * (or current) transmission performance.
1047 struct TransmissionHistoryEntry
1050 * Number of bytes actually sent in the interval.
1052 uint64_t bytes_sent;
1055 * Number of bytes received and acknowledged by the other peer in
1058 uint64_t bytes_received;
1063 * Performance data for a transmission possibility.
1065 struct PerformanceData
1068 * Weighted average for the RTT.
1070 struct GNUNET_TIME_Relative aged_rtt;
1073 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1076 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1079 * What was the last age when we wrote to @e the? Used to clear
1080 * old entries when the age advances.
1082 unsigned int last_age;
1087 * Client connected to the transport service.
1089 struct TransportClient;
1092 * A neighbour that at least one communicator is connected to.
1097 * Entry in our #dv_routes table, representing a (set of) distance
1098 * vector routes to a particular peer.
1100 struct DistanceVector;
1103 * A queue is a message queue provided by a communicator
1104 * via which we can reach a particular neighbour.
1109 * Message awaiting transmission. See detailed comments below.
1111 struct PendingMessage;
1114 * One possible hop towards a DV target.
1116 struct DistanceVectorHop;
1119 * A virtual link is another reachable peer that is known to CORE. It
1120 * can be either a `struct Neighbour` with at least one confirmed
1121 * `struct Queue`, or a `struct DistanceVector` with at least one
1122 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1123 * data that is per neighbour that is not specific to how the
1124 * connectivity is established.
1129 * Identity of the peer at the other end of the link.
1131 struct GNUNET_PeerIdentity target;
1134 * Task scheduled to possibly notfiy core that this peer is no
1135 * longer counting as confirmed. Runs the #core_visibility_check(),
1136 * which checks that some DV-path or a queue exists that is still
1137 * considered confirmed.
1139 struct GNUNET_SCHEDULER_Task *visibility_task;
1142 * Neighbour used by this virtual link, NULL if @e dv is used.
1144 struct Neighbour *n;
1147 * Distance vector used by this virtual link, NULL if @e n is used.
1149 struct DistanceVector *dv;
1152 * How many more messages can we send to core before we exhaust
1153 * the receive window of CORE for this peer? If this hits zero,
1154 * we must tell communicators to stop providing us more messages
1157 unsigned int core_recv_window;
1162 * Data structure kept when we are waiting for an acknowledgement.
1164 struct PendingAcknowledgement
1168 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1169 * is kept in relation to its pending message.
1171 struct PendingAcknowledgement *next_pm;
1174 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1175 * is kept in relation to its pending message.
1177 struct PendingAcknowledgement *prev_pm;
1180 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1181 * is kept in relation to the queue that was used to transmit the
1184 struct PendingAcknowledgement *next_queue;
1187 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1188 * is kept in relation to the queue that was used to transmit the
1191 struct PendingAcknowledgement *prev_queue;
1194 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1195 * is kept in relation to the DVH that was used to transmit the
1198 struct PendingAcknowledgement *next_dvh;
1201 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1202 * is kept in relation to the DVH that was used to transmit the
1205 struct PendingAcknowledgement *prev_dvh;
1208 * Pointers for the DLL of all pending acknowledgements.
1209 * This list is sorted by @e transmission time. If the list gets too
1210 * long, the oldest entries are discarded.
1212 struct PendingAcknowledgement *next_pa;
1215 * Pointers for the DLL of all pending acknowledgements.
1216 * This list is sorted by @e transmission time. If the list gets too
1217 * long, the oldest entries are discarded.
1219 struct PendingAcknowledgement *prev_pa;
1222 * Unique identifier for this transmission operation.
1224 struct AcknowledgementUUIDP ack_uuid;
1227 * Message that was transmitted, may be NULL if the message was ACKed
1228 * via another channel.
1230 struct PendingMessage *pm;
1233 * Distance vector path chosen for this transmission, NULL if transmission
1234 * was to a direct neighbour OR if the path was forgotten in the meantime.
1236 struct DistanceVectorHop *dvh;
1239 * Queue used for transmission, NULL if the queue has been destroyed
1240 * (which may happen before we get an acknowledgement).
1242 struct Queue *queue;
1245 * Time of the transmission, for RTT calculation.
1247 struct GNUNET_TIME_Absolute transmission_time;
1250 * Number of bytes of the original message (to calculate bandwidth).
1252 uint16_t message_size;
1257 * One possible hop towards a DV target.
1259 struct DistanceVectorHop
1263 * Kept in a MDLL, sorted by @e timeout.
1265 struct DistanceVectorHop *next_dv;
1268 * Kept in a MDLL, sorted by @e timeout.
1270 struct DistanceVectorHop *prev_dv;
1275 struct DistanceVectorHop *next_neighbour;
1280 struct DistanceVectorHop *prev_neighbour;
1283 * Head of MDLL of messages routed via this path.
1285 struct PendingMessage *pending_msg_head;
1288 * Tail of MDLL of messages routed via this path.
1290 struct PendingMessage *pending_msg_tail;
1293 * Head of DLL of PAs that used our @a path.
1295 struct PendingAcknowledgement *pa_head;
1298 * Tail of DLL of PAs that used our @a path.
1300 struct PendingAcknowledgement *pa_tail;
1303 * What would be the next hop to @e target?
1305 struct Neighbour *next_hop;
1308 * Distance vector entry this hop belongs with.
1310 struct DistanceVector *dv;
1313 * Array of @e distance hops to the target, excluding @e next_hop.
1314 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1315 * at the end of this struct. Excludes the target itself!
1317 const struct GNUNET_PeerIdentity *path;
1320 * At what time do we forget about this path unless we see it again
1323 struct GNUNET_TIME_Absolute timeout;
1326 * For how long is the validation of this path considered
1328 * Set to ZERO if the path is learned by snooping on DV learn messages
1329 * initiated by other peers, and to the time at which we generated the
1330 * challenge for DV learn operations this peer initiated.
1332 struct GNUNET_TIME_Absolute path_valid_until;
1335 * Performance data for this transmission possibility.
1337 struct PerformanceData pd;
1340 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1341 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1344 unsigned int distance;
1349 * Entry in our #dv_routes table, representing a (set of) distance
1350 * vector routes to a particular peer.
1352 struct DistanceVector
1356 * To which peer is this a route?
1358 struct GNUNET_PeerIdentity target;
1361 * Known paths to @e target.
1363 struct DistanceVectorHop *dv_head;
1366 * Known paths to @e target.
1368 struct DistanceVectorHop *dv_tail;
1371 * Task scheduled to purge expired paths from @e dv_head MDLL.
1373 struct GNUNET_SCHEDULER_Task *timeout_task;
1376 * Do we have a confirmed working queue and are thus visible to
1377 * CORE? If so, this is the virtual link, otherwise NULL.
1379 struct VirtualLink *link;
1384 * Entry identifying transmission in one of our `struct
1385 * Queue` which still awaits an ACK. This is used to
1386 * ensure we do not overwhelm a communicator and limit the number of
1387 * messages outstanding per communicator (say in case communicator is
1388 * CPU bound) and per queue (in case bandwidth allocation exceeds
1389 * what the communicator can actually provide towards a particular
1398 struct QueueEntry *next;
1403 struct QueueEntry *prev;
1406 * Queue this entry is queued with.
1408 struct Queue *queue;
1411 * Pending message this entry is for, or NULL for none.
1413 struct PendingMessage *pm;
1416 * Message ID used for this message with the queue used for transmission.
1423 * A queue is a message queue provided by a communicator
1424 * via which we can reach a particular neighbour.
1431 struct Queue *next_neighbour;
1436 struct Queue *prev_neighbour;
1441 struct Queue *prev_client;
1446 struct Queue *next_client;
1449 * Head of DLL of PAs that used this queue.
1451 struct PendingAcknowledgement *pa_head;
1454 * Tail of DLL of PAs that used this queue.
1456 struct PendingAcknowledgement *pa_tail;
1459 * Head of DLL of unacked transmission requests.
1461 struct QueueEntry *queue_head;
1464 * End of DLL of unacked transmission requests.
1466 struct QueueEntry *queue_tail;
1469 * Which neighbour is this queue for?
1471 struct Neighbour *neighbour;
1474 * Which communicator offers this queue?
1476 struct TransportClient *tc;
1479 * Address served by the queue.
1481 const char *address;
1484 * Task scheduled for the time when this queue can (likely) transmit the
1487 struct GNUNET_SCHEDULER_Task *transmit_task;
1490 * How long do *we* consider this @e address to be valid? In the past or
1491 * zero if we have not yet validated it. Can be updated based on
1492 * challenge-response validations (via address validation logic), or when we
1493 * receive ACKs that we can definitively map to transmissions via this
1496 struct GNUNET_TIME_Absolute validated_until;
1499 * Performance data for this queue.
1501 struct PerformanceData pd;
1504 * Message ID generator for transmissions on this queue to the
1510 * Unique identifier of this queue with the communicator.
1515 * Maximum transmission unit supported by this queue.
1522 uint32_t num_msg_pending;
1527 uint32_t num_bytes_pending;
1530 * Length of the DLL starting at @e queue_head.
1532 unsigned int queue_length;
1535 * Network type offered by this queue.
1537 enum GNUNET_NetworkType nt;
1540 * Connection status for this queue.
1542 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1547 * Information we keep for a message that we are reassembling.
1549 struct ReassemblyContext
1553 * Original message ID for of the message that all the fragments
1556 struct MessageUUIDP msg_uuid;
1559 * Which neighbour is this context for?
1561 struct Neighbour *neighbour;
1564 * Entry in the reassembly heap (sorted by expiration).
1566 struct GNUNET_CONTAINER_HeapNode *hn;
1569 * Bitfield with @e msg_size bits representing the positions
1570 * where we have received fragments. When we receive a fragment,
1571 * we check the bits in @e bitfield before incrementing @e msg_missing.
1573 * Allocated after the reassembled message.
1578 * Task for sending ACK. We may send ACKs either because of hitting
1579 * the @e extra_acks limit, or based on time and @e num_acks. This
1580 * task is for the latter case.
1582 struct GNUNET_SCHEDULER_Task *ack_task;
1585 * At what time will we give up reassembly of this message?
1587 struct GNUNET_TIME_Absolute reassembly_timeout;
1590 * Time we received the last fragment. @e avg_ack_delay must be
1591 * incremented by now - @e last_frag multiplied by @e num_acks.
1593 struct GNUNET_TIME_Absolute last_frag;
1596 * How big is the message we are reassembling in total?
1601 * How many bytes of the message are still missing? Defragmentation
1602 * is complete when @e msg_missing == 0.
1604 uint16_t msg_missing;
1606 /* Followed by @e msg_size bytes of the (partially) defragmented original
1609 /* Followed by @e bitfield data */
1614 * A neighbour that at least one communicator is connected to.
1620 * Which peer is this about?
1622 struct GNUNET_PeerIdentity pid;
1625 * Map with `struct ReassemblyContext` structs for fragments under
1626 * reassembly. May be NULL if we currently have no fragments from
1627 * this @e pid (lazy initialization).
1629 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1632 * Heap with `struct ReassemblyContext` structs for fragments under
1633 * reassembly. May be NULL if we currently have no fragments from
1634 * this @e pid (lazy initialization).
1636 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1639 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1641 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1644 * Head of list of messages pending for this neighbour.
1646 struct PendingMessage *pending_msg_head;
1649 * Tail of list of messages pending for this neighbour.
1651 struct PendingMessage *pending_msg_tail;
1654 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1655 * purged if this neighbour goes down.
1657 struct DistanceVectorHop *dv_head;
1660 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1661 * purged if this neighbour goes down.
1663 struct DistanceVectorHop *dv_tail;
1666 * Head of DLL of queues to this peer.
1668 struct Queue *queue_head;
1671 * Tail of DLL of queues to this peer.
1673 struct Queue *queue_tail;
1676 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1677 * the PEERSTORE, or NULL.
1679 struct GNUNET_PEERSTORE_IterateContext *get;
1682 * Handle to a PEERSTORE store operation to store this @e pid's @e
1683 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1685 struct GNUNET_PEERSTORE_StoreContext *sc;
1688 * Do we have a confirmed working queue and are thus visible to
1689 * CORE? If so, this is the virtual link, otherwise NULL.
1691 struct VirtualLink *link;
1694 * Latest DVLearn monotonic time seen from this peer. Initialized only
1695 * if @e dl_monotime_available is #GNUNET_YES.
1697 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1700 * Do we have the lastest value for @e last_dv_learn_monotime from
1701 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1703 int dv_monotime_available;
1708 * A peer that an application (client) would like us to talk to directly.
1714 * Which peer is this about?
1716 struct GNUNET_PeerIdentity pid;
1719 * Client responsible for the request.
1721 struct TransportClient *tc;
1724 * Handle for watching the peerstore for HELLOs for this peer.
1726 struct GNUNET_PEERSTORE_WatchContext *wc;
1729 * What kind of performance preference does this @e tc have?
1731 enum GNUNET_MQ_PreferenceKind pk;
1734 * How much bandwidth would this @e tc like to see?
1736 struct GNUNET_BANDWIDTH_Value32NBO bw;
1741 * Types of different pending messages.
1743 enum PendingMessageType
1747 * Ordinary message received from the CORE service.
1754 PMT_FRAGMENT_BOX = 1,
1759 PMT_RELIABILITY_BOX = 2,
1762 * Any type of acknowledgement.
1764 PMT_ACKNOWLEDGEMENT = 3,
1767 * Control traffic generated by the TRANSPORT service itself.
1775 * Transmission request that is awaiting delivery. The original
1776 * transmission requests from CORE may be too big for some queues.
1777 * In this case, a *tree* of fragments is created. At each
1778 * level of the tree, fragments are kept in a DLL ordered by which
1779 * fragment should be sent next (at the head). The tree is searched
1780 * top-down, with the original message at the root.
1782 * To select a node for transmission, first it is checked if the
1783 * current node's message fits with the MTU. If it does not, we
1784 * either calculate the next fragment (based on @e frag_off) from the
1785 * current node, or, if all fragments have already been created,
1786 * descend to the @e head_frag. Even though the node was already
1787 * fragmented, the fragment may be too big if the fragment was
1788 * generated for a queue with a larger MTU. In this case, the node
1789 * may be fragmented again, thus creating a tree.
1791 * When acknowledgements for fragments are received, the tree
1792 * must be pruned, removing those parts that were already
1793 * acknowledged. When fragments are sent over a reliable
1794 * channel, they can be immediately removed.
1796 * If a message is ever fragmented, then the original "full" message
1797 * is never again transmitted (even if it fits below the MTU), and
1798 * only (remaining) fragments are sent.
1800 struct PendingMessage
1803 * Kept in a MDLL of messages for this @a target.
1805 struct PendingMessage *next_neighbour;
1808 * Kept in a MDLL of messages for this @a target.
1810 struct PendingMessage *prev_neighbour;
1813 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1815 struct PendingMessage *next_client;
1818 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1820 struct PendingMessage *prev_client;
1823 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1824 * #PMT_FRAGMENT_BOx)
1826 struct PendingMessage *next_frag;
1829 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1830 * #PMT_FRAGMENT_BOX)
1832 struct PendingMessage *prev_frag;
1835 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1838 struct PendingMessage *next_dvh;
1841 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1844 struct PendingMessage *prev_dvh;
1847 * Head of DLL of PAs for this pending message.
1849 struct PendingAcknowledgement *pa_head;
1852 * Tail of DLL of PAs for this pending message.
1854 struct PendingAcknowledgement *pa_tail;
1857 * This message, reliability boxed. Only possibly available if @e pmt is
1860 struct PendingMessage *bpm;
1863 * Target of the request (for transmission, may not be ultimate
1866 struct Neighbour *target;
1869 * Distance vector path selected for this message, or
1870 * NULL if transmitted directly.
1872 struct DistanceVectorHop *dvh;
1875 * Set to non-NULL value if this message is currently being given to a
1876 * communicator and we are awaiting that communicator's acknowledgement.
1877 * Note that we must not retransmit a pending message while we're still
1878 * in the process of giving it to a communicator. If a pending message
1879 * is free'd while this entry is non-NULL, the @e qe reference to us
1880 * should simply be set to NULL.
1882 struct QueueEntry *qe;
1885 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1887 struct TransportClient *client;
1890 * Head of a MDLL of fragments created for this core message.
1892 struct PendingMessage *head_frag;
1895 * Tail of a MDLL of fragments created for this core message.
1897 struct PendingMessage *tail_frag;
1900 * Our parent in the fragmentation tree.
1902 struct PendingMessage *frag_parent;
1905 * At what time should we give up on the transmission (and no longer retry)?
1907 struct GNUNET_TIME_Absolute timeout;
1910 * What is the earliest time for us to retry transmission of this message?
1912 struct GNUNET_TIME_Absolute next_attempt;
1915 * UUID to use for this message (used for reassembly of fragments, only
1916 * initialized if @e msg_uuid_set is #GNUNET_YES).
1918 struct MessageUUIDP msg_uuid;
1921 * Type of the pending message.
1923 enum PendingMessageType pmt;
1926 * Size of the original message.
1931 * Offset at which we should generate the next fragment.
1936 * #GNUNET_YES once @e msg_uuid was initialized
1938 int16_t msg_uuid_set;
1940 /* Followed by @e bytes_msg to transmit */
1945 * Acknowledgement payload.
1947 struct TransportCummulativeAckPayload
1950 * When did we receive the message we are ACKing? Used to calculate
1951 * the delay we introduced by cummulating ACKs.
1953 struct GNUNET_TIME_Absolute receive_time;
1956 * UUID of a message being acknowledged.
1958 struct AcknowledgementUUIDP ack_uuid;
1963 * Data structure in which we track acknowledgements still to
1966 struct AcknowledgementCummulator
1969 * Target peer for which we are accumulating ACKs here.
1971 struct GNUNET_PeerIdentity target;
1974 * ACK data being accumulated. Only @e num_acks slots are valid.
1976 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
1979 * Task scheduled either to transmit the cummulative ACK message,
1980 * or to clean up this data structure after extended periods of
1981 * inactivity (if @e num_acks is zero).
1983 struct GNUNET_SCHEDULER_Task *task;
1986 * When is @e task run (only used if @e num_acks is non-zero)?
1988 struct GNUNET_TIME_Absolute min_transmission_time;
1991 * Counter to produce the `ack_counter` in the `struct
1992 * TransportReliabilityAckMessage`. Allows the receiver to detect
1993 * lost ACK messages. Incremented by @e num_acks upon transmission.
1995 uint32_t ack_counter;
1998 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2000 unsigned int num_acks;
2005 * One of the addresses of this peer.
2007 struct AddressListEntry
2013 struct AddressListEntry *next;
2018 struct AddressListEntry *prev;
2021 * Which communicator provides this address?
2023 struct TransportClient *tc;
2026 * The actual address.
2028 const char *address;
2031 * Current context for storing this address in the peerstore.
2033 struct GNUNET_PEERSTORE_StoreContext *sc;
2036 * Task to periodically do @e st operation.
2038 struct GNUNET_SCHEDULER_Task *st;
2041 * What is a typical lifetime the communicator expects this
2042 * address to have? (Always from now.)
2044 struct GNUNET_TIME_Relative expiration;
2047 * Address identifier used by the communicator.
2052 * Network type offered by this address.
2054 enum GNUNET_NetworkType nt;
2059 * Client connected to the transport service.
2061 struct TransportClient
2067 struct TransportClient *next;
2072 struct TransportClient *prev;
2075 * Handle to the client.
2077 struct GNUNET_SERVICE_Client *client;
2080 * Message queue to the client.
2082 struct GNUNET_MQ_Handle *mq;
2085 * What type of client is this?
2087 enum ClientType type;
2093 * Information for @e type #CT_CORE.
2099 * Head of list of messages pending for this client, sorted by
2100 * transmission time ("next_attempt" + possibly internal prioritization).
2102 struct PendingMessage *pending_msg_head;
2105 * Tail of list of messages pending for this client.
2107 struct PendingMessage *pending_msg_tail;
2112 * Information for @e type #CT_MONITOR.
2118 * Peer identity to monitor the addresses of.
2119 * Zero to monitor all neighbours. Valid if
2120 * @e type is #CT_MONITOR.
2122 struct GNUNET_PeerIdentity peer;
2125 * Is this a one-shot monitor?
2133 * Information for @e type #CT_COMMUNICATOR.
2138 * If @e type is #CT_COMMUNICATOR, this communicator
2139 * supports communicating using these addresses.
2141 char *address_prefix;
2144 * Head of DLL of queues offered by this communicator.
2146 struct Queue *queue_head;
2149 * Tail of DLL of queues offered by this communicator.
2151 struct Queue *queue_tail;
2154 * Head of list of the addresses of this peer offered by this
2157 struct AddressListEntry *addr_head;
2160 * Tail of list of the addresses of this peer offered by this
2163 struct AddressListEntry *addr_tail;
2166 * Number of queue entries in all queues to this communicator. Used
2167 * throttle sending to a communicator if we see that the communicator
2168 * is globally unable to keep up.
2170 unsigned int total_queue_length;
2173 * Characteristics of this communicator.
2175 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2180 * Information for @e type #CT_APPLICATION
2186 * Map of requests for peers the given client application would like to
2187 * see connections for. Maps from PIDs to `struct PeerRequest`.
2189 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2198 * State we keep for validation activities. Each of these
2199 * is both in the #validation_heap and the #validation_map.
2201 struct ValidationState
2205 * For which peer is @a address to be validated (or possibly valid)?
2206 * Serves as key in the #validation_map.
2208 struct GNUNET_PeerIdentity pid;
2211 * How long did the peer claim this @e address to be valid? Capped at
2212 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2213 * were told about the address and the value claimed by the other peer at
2214 * that time. May be updated similarly when validation succeeds.
2216 struct GNUNET_TIME_Absolute valid_until;
2219 * How long do *we* consider this @e address to be valid?
2220 * In the past or zero if we have not yet validated it.
2222 struct GNUNET_TIME_Absolute validated_until;
2225 * When did we FIRST use the current @e challenge in a message?
2226 * Used to sanity-check @code{origin_time} in the response when
2227 * calculating the RTT. If the @code{origin_time} is not in
2228 * the expected range, the response is discarded as malicious.
2230 struct GNUNET_TIME_Absolute first_challenge_use;
2233 * When did we LAST use the current @e challenge in a message?
2234 * Used to sanity-check @code{origin_time} in the response when
2235 * calculating the RTT. If the @code{origin_time} is not in
2236 * the expected range, the response is discarded as malicious.
2238 struct GNUNET_TIME_Absolute last_challenge_use;
2241 * Next time we will send the @e challenge to the peer, if this time is past
2242 * @e valid_until, this validation state is released at this time. If the
2243 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2244 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2245 * to re-validate before the validity actually expires.
2247 struct GNUNET_TIME_Absolute next_challenge;
2250 * Current backoff factor we're applying for sending the @a challenge.
2251 * Reset to 0 if the @a challenge is confirmed upon validation.
2252 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2253 * existing value if we receive an unvalidated address again over
2254 * another channel (and thus should consider the information "fresh").
2255 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2257 struct GNUNET_TIME_Relative challenge_backoff;
2260 * Initially set to "forever". Once @e validated_until is set, this value is
2261 * set to the RTT that tells us how long it took to receive the validation.
2263 struct GNUNET_TIME_Relative validation_rtt;
2266 * The challenge we sent to the peer to get it to validate the address. Note
2267 * that we rotate the challenge whenever we update @e validated_until to
2268 * avoid attacks where a peer simply replays an old challenge in the future.
2269 * (We must not rotate more often as otherwise we may discard valid answers
2270 * due to packet losses, latency and reorderings on the network).
2272 struct ChallengeNonceP challenge;
2275 * Claimed address of the peer.
2280 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2281 * heap is used to figure out when the next validation activity should be
2284 struct GNUNET_CONTAINER_HeapNode *hn;
2287 * Handle to a PEERSTORE store operation for this @e address. NULL if
2288 * no PEERSTORE operation is pending.
2290 struct GNUNET_PEERSTORE_StoreContext *sc;
2293 * We are technically ready to send the challenge, but we are waiting for
2294 * the respective queue to become available for transmission.
2301 * A Backtalker is a peer sending us backchannel messages. We use this
2302 * struct to detect monotonic time violations, cache ephemeral key
2303 * material (to avoid repeatedly checking signatures), and to synchronize
2304 * monotonic time with the PEERSTORE.
2309 * Peer this is about.
2311 struct GNUNET_PeerIdentity pid;
2314 * Last (valid) monotonic time received from this sender.
2316 struct GNUNET_TIME_Absolute monotonic_time;
2319 * When will this entry time out?
2321 struct GNUNET_TIME_Absolute timeout;
2324 * Last (valid) ephemeral key received from this sender.
2326 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2329 * Task associated with this backtalker. Can be for timeout,
2330 * or other asynchronous operations.
2332 struct GNUNET_SCHEDULER_Task *task;
2335 * Communicator context waiting on this backchannel's @e get, or NULL.
2337 struct CommunicatorMessageContext *cmc;
2340 * Handle for an operation to fetch @e monotonic_time information from the
2341 * PEERSTORE, or NULL.
2343 struct GNUNET_PEERSTORE_IterateContext *get;
2346 * Handle to a PEERSTORE store operation for this @e pid's @e
2347 * monotonic_time. NULL if no PEERSTORE operation is pending.
2349 struct GNUNET_PEERSTORE_StoreContext *sc;
2352 * Number of bytes of the original message body that follows after this
2360 * Head of linked list of all clients to this service.
2362 static struct TransportClient *clients_head;
2365 * Tail of linked list of all clients to this service.
2367 static struct TransportClient *clients_tail;
2370 * Statistics handle.
2372 static struct GNUNET_STATISTICS_Handle *GST_stats;
2375 * Configuration handle.
2377 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2382 static struct GNUNET_PeerIdentity GST_my_identity;
2387 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2390 * Map from PIDs to `struct Neighbour` entries. A peer is
2391 * a neighbour if we have an MQ to it from some communicator.
2393 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2396 * Map from PIDs to `struct Backtalker` entries. A peer is
2397 * a backtalker if it recently send us backchannel messages.
2399 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2402 * Map from PIDs to `struct AcknowledgementCummulator`s.
2403 * Here we track the cummulative ACKs for transmission.
2405 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2408 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2409 * a `struct PendingAcknowledgement`.
2411 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2414 * Map from PIDs to `struct DistanceVector` entries describing
2415 * known paths to the peer.
2417 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2420 * Map from PIDs to `struct ValidationState` entries describing
2421 * addresses we are aware of and their validity state.
2423 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2426 * Map from PIDs to `struct VirtualLink` entries describing
2427 * links CORE knows to exist.
2429 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2432 * Map from challenges to `struct LearnLaunchEntry` values.
2434 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2437 * Head of a DLL sorted by launch time.
2439 static struct LearnLaunchEntry *lle_head;
2442 * Tail of a DLL sorted by launch time.
2444 static struct LearnLaunchEntry *lle_tail;
2447 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2448 * sorting addresses we are aware of by when we should next try to (re)validate
2451 static struct GNUNET_CONTAINER_Heap *validation_heap;
2454 * Database for peer's HELLOs.
2456 static struct GNUNET_PEERSTORE_Handle *peerstore;
2459 * Heap sorting `struct EphemeralCacheEntry` by their
2460 * key/signature validity.
2462 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2465 * Hash map for looking up `struct EphemeralCacheEntry`s
2466 * by peer identity. (We may have ephemerals in our
2467 * cache for which we do not have a neighbour entry,
2468 * and similar many neighbours may not need ephemerals,
2469 * so we use a second map.)
2471 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2474 * Task to free expired ephemerals.
2476 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2479 * Task run to initiate DV learning.
2481 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2484 * Task to run address validation.
2486 static struct GNUNET_SCHEDULER_Task *validation_task;
2489 * The most recent PA we have created, head of DLL.
2490 * The length of the DLL is kept in #pa_count.
2492 static struct PendingAcknowledgement *pa_head;
2495 * The oldest PA we have created, tail of DLL.
2496 * The length of the DLL is kept in #pa_count.
2498 static struct PendingAcknowledgement *pa_tail;
2501 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2502 * limit the size of the data structure.
2504 static unsigned int pa_count;
2508 * Get an offset into the transmission history buffer for `struct
2509 * PerformanceData`. Note that the caller must perform the required
2510 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2513 * An 'age' lasts 15 minute slots.
2515 * @return current age of the world
2520 struct GNUNET_TIME_Absolute now;
2522 now = GNUNET_TIME_absolute_get ();
2523 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2528 * Release @a pa data structure.
2530 * @param pa data structure to release
2533 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2535 struct Queue *q = pa->queue;
2536 struct PendingMessage *pm = pa->pm;
2537 struct DistanceVectorHop *dvh = pa->dvh;
2539 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2543 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2548 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2553 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2556 GNUNET_assert (GNUNET_YES ==
2557 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2558 &pa->ack_uuid.value,
2565 * Free cached ephemeral key.
2567 * @param ece cached signature to free
2570 free_ephemeral (struct EphemeralCacheEntry *ece)
2572 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2573 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2579 * Free virtual link.
2581 * @param vl link data to free
2584 free_virtual_link (struct VirtualLink *vl)
2586 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2587 if (NULL != vl->visibility_task)
2589 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2590 vl->visibility_task = NULL;
2592 GNUNET_break (NULL == vl->n);
2593 GNUNET_break (NULL == vl->dv);
2599 * Free validation state.
2601 * @param vs validation state to free
2604 free_validation_state (struct ValidationState *vs)
2606 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2607 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2611 GNUNET_PEERSTORE_store_cancel (vs->sc);
2614 GNUNET_free (vs->address);
2620 * Lookup neighbour record for peer @a pid.
2622 * @param pid neighbour to look for
2623 * @return NULL if we do not have this peer as a neighbour
2625 static struct Neighbour *
2626 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2628 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2633 * Details about what to notify monitors about.
2638 * @deprecated To be discussed if we keep these...
2640 struct GNUNET_TIME_Absolute last_validation;
2641 struct GNUNET_TIME_Absolute valid_until;
2642 struct GNUNET_TIME_Absolute next_validation;
2645 * Current round-trip time estimate.
2647 struct GNUNET_TIME_Relative rtt;
2650 * Connection status.
2652 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2657 uint32_t num_msg_pending;
2662 uint32_t num_bytes_pending;
2667 * Free a @dvh. Callers MAY want to check if this was the last path to the
2668 * `target`, and if so call #free_dv_route to also free the associated DV
2669 * entry in #dv_routes (if not, the associated scheduler job should eventually
2672 * @param dvh hop to free
2675 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2677 struct Neighbour *n = dvh->next_hop;
2678 struct DistanceVector *dv = dvh->dv;
2679 struct PendingAcknowledgement *pa;
2680 struct PendingMessage *pm;
2682 while (NULL != (pm = dvh->pending_msg_head))
2684 GNUNET_CONTAINER_MDLL_remove (dvh,
2685 dvh->pending_msg_head,
2686 dvh->pending_msg_tail,
2690 while (NULL != (pa = dvh->pa_head))
2692 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2695 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2696 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2702 * Free entry in #dv_routes. First frees all hops to the target, and
2703 * if there are no entries left, frees @a dv as well.
2705 * @param dv route to free
2708 free_dv_route (struct DistanceVector *dv)
2710 struct DistanceVectorHop *dvh;
2712 while (NULL != (dvh = dv->dv_head))
2713 free_distance_vector_hop (dvh);
2714 if (NULL == dv->dv_head)
2718 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2719 if (NULL != dv->timeout_task)
2720 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2727 * Notify monitor @a tc about an event. That @a tc
2728 * cares about the event has already been checked.
2730 * Send @a tc information in @a me about a @a peer's status with
2731 * respect to some @a address to all monitors that care.
2733 * @param tc monitor to inform
2734 * @param peer peer the information is about
2735 * @param address address the information is about
2736 * @param nt network type associated with @a address
2737 * @param me detailed information to transmit
2740 notify_monitor (struct TransportClient *tc,
2741 const struct GNUNET_PeerIdentity *peer,
2742 const char *address,
2743 enum GNUNET_NetworkType nt,
2744 const struct MonitorEvent *me)
2746 struct GNUNET_MQ_Envelope *env;
2747 struct GNUNET_TRANSPORT_MonitorData *md;
2748 size_t addr_len = strlen (address) + 1;
2750 env = GNUNET_MQ_msg_extra (md,
2752 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2753 md->nt = htonl ((uint32_t) nt);
2755 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2756 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2757 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2758 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2759 md->cs = htonl ((uint32_t) me->cs);
2760 md->num_msg_pending = htonl (me->num_msg_pending);
2761 md->num_bytes_pending = htonl (me->num_bytes_pending);
2762 memcpy (&md[1], address, addr_len);
2763 GNUNET_MQ_send (tc->mq, env);
2768 * Send information in @a me about a @a peer's status with respect
2769 * to some @a address to all monitors that care.
2771 * @param peer peer the information is about
2772 * @param address address the information is about
2773 * @param nt network type associated with @a address
2774 * @param me detailed information to transmit
2777 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2778 const char *address,
2779 enum GNUNET_NetworkType nt,
2780 const struct MonitorEvent *me)
2782 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2784 if (CT_MONITOR != tc->type)
2786 if (tc->details.monitor.one_shot)
2788 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2789 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2791 notify_monitor (tc, peer, address, nt, me);
2797 * Called whenever a client connects. Allocates our
2798 * data structures associated with that client.
2800 * @param cls closure, NULL
2801 * @param client identification of the client
2802 * @param mq message queue for the client
2803 * @return our `struct TransportClient`
2806 client_connect_cb (void *cls,
2807 struct GNUNET_SERVICE_Client *client,
2808 struct GNUNET_MQ_Handle *mq)
2810 struct TransportClient *tc;
2813 tc = GNUNET_new (struct TransportClient);
2814 tc->client = client;
2816 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2825 * @param rc data structure to free
2828 free_reassembly_context (struct ReassemblyContext *rc)
2830 struct Neighbour *n = rc->neighbour;
2832 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2833 GNUNET_assert (GNUNET_OK ==
2834 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2842 * Task run to clean up reassembly context of a neighbour that have expired.
2844 * @param cls a `struct Neighbour`
2847 reassembly_cleanup_task (void *cls)
2849 struct Neighbour *n = cls;
2850 struct ReassemblyContext *rc;
2852 n->reassembly_timeout_task = NULL;
2853 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2855 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2858 free_reassembly_context (rc);
2861 GNUNET_assert (NULL == n->reassembly_timeout_task);
2862 n->reassembly_timeout_task =
2863 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2864 &reassembly_cleanup_task,
2872 * function called to #free_reassembly_context().
2876 * @param value a `struct ReassemblyContext` to free
2877 * @return #GNUNET_OK (continue iteration)
2880 free_reassembly_cb (void *cls, uint32_t key, void *value)
2882 struct ReassemblyContext *rc = value;
2886 free_reassembly_context (rc);
2892 * Release memory used by @a neighbour.
2894 * @param neighbour neighbour entry to free
2897 free_neighbour (struct Neighbour *neighbour)
2899 struct DistanceVectorHop *dvh;
2901 GNUNET_assert (NULL == neighbour->queue_head);
2902 GNUNET_assert (GNUNET_YES ==
2903 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2906 if (NULL != neighbour->reassembly_map)
2908 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2909 &free_reassembly_cb,
2911 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2912 neighbour->reassembly_map = NULL;
2913 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2914 neighbour->reassembly_heap = NULL;
2916 while (NULL != (dvh = neighbour->dv_head))
2918 struct DistanceVector *dv = dvh->dv;
2920 free_distance_vector_hop (dvh);
2921 if (NULL == dv->dv_head)
2924 if (NULL != neighbour->reassembly_timeout_task)
2926 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2927 neighbour->reassembly_timeout_task = NULL;
2929 if (NULL != neighbour->get)
2931 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2932 neighbour->get = NULL;
2934 if (NULL != neighbour->sc)
2936 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2937 neighbour->sc = NULL;
2939 GNUNET_free (neighbour);
2944 * Send message to CORE clients that we lost a connection.
2946 * @param tc client to inform (must be CORE client)
2947 * @param pid peer the connection is for
2950 core_send_connect_info (struct TransportClient *tc,
2951 const struct GNUNET_PeerIdentity *pid)
2953 struct GNUNET_MQ_Envelope *env;
2954 struct ConnectInfoMessage *cim;
2956 GNUNET_assert (CT_CORE == tc->type);
2957 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2959 GNUNET_MQ_send (tc->mq, env);
2964 * Send message to CORE clients that we gained a connection
2966 * @param pid peer the queue was for
2969 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
2971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2972 "Informing CORE clients about connection to %s\n",
2974 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2976 if (CT_CORE != tc->type)
2978 core_send_connect_info (tc, pid);
2984 * Send message to CORE clients that we lost a connection.
2986 * @param pid peer the connection was for
2989 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2992 "Informing CORE clients about disconnect from %s\n",
2994 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2996 struct GNUNET_MQ_Envelope *env;
2997 struct DisconnectInfoMessage *dim;
2999 if (CT_CORE != tc->type)
3001 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3003 GNUNET_MQ_send (tc->mq, env);
3009 * We believe we are ready to transmit a message on a queue. Gives the
3010 * message to the communicator for transmission (updating the tracker,
3011 * and re-scheduling itself if applicable).
3013 * @param cls the `struct Queue` to process transmissions for
3016 transmit_on_queue (void *cls);
3020 * Schedule next run of #transmit_on_queue(). Does NOTHING if
3021 * we should run immediately or if the message queue is empty.
3022 * Test for no task being added AND queue not being empty to
3023 * transmit immediately afterwards! This function must only
3024 * be called if the message queue is non-empty!
3026 * @param queue the queue to do scheduling for
3027 * @param inside_job set to #GNUNET_YES if called from
3028 * #transmit_on_queue() itself and NOT setting
3029 * the task means running immediately
3032 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3034 struct Neighbour *n = queue->neighbour;
3035 struct PendingMessage *pm = n->pending_msg_head;
3036 struct GNUNET_TIME_Relative out_delay;
3038 GNUNET_assert (NULL != pm);
3039 if (queue->tc->details.communicator.total_queue_length >=
3040 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3042 GNUNET_STATISTICS_update (
3044 "# Transmission throttled due to communicator queue limit",
3049 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3051 GNUNET_STATISTICS_update (GST_stats,
3052 "# Transmission throttled due to queue queue limit",
3058 out_delay = GNUNET_TIME_absolute_get_remaining (pm->next_attempt);
3059 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3062 GNUNET_ERROR_TYPE_DEBUG,
3063 "Schedule transmission on queue %llu of %s decides to run immediately\n",
3064 (unsigned long long) queue->qid,
3065 GNUNET_i2s (&n->pid));
3066 return; /* we should run immediately! */
3068 /* queue has changed since we were scheduled, reschedule again */
3069 queue->transmit_task =
3070 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3071 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3072 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3073 "Next transmission on queue `%s' in %s (high delay)\n",
3075 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3078 "Next transmission on queue `%s' in %s\n",
3080 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3085 * Task run to check whether the hops of the @a cls still
3086 * are validated, or if we need to core about disconnection.
3088 * @param cls a `struct VirtualLink`
3091 check_link_down (void *cls)
3093 struct VirtualLink *vl = cls;
3094 struct DistanceVector *dv = vl->dv;
3095 struct Neighbour *n = vl->n;
3096 struct GNUNET_TIME_Absolute dvh_timeout;
3097 struct GNUNET_TIME_Absolute q_timeout;
3099 vl->visibility_task = NULL;
3100 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3101 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3103 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3104 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3106 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3107 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3108 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3109 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3111 if ((NULL == vl->n) && (NULL == vl->dv))
3113 cores_send_disconnect_info (&dv->target);
3114 free_virtual_link (vl);
3117 vl->visibility_task =
3118 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3127 * @param queue the queue to free
3130 free_queue (struct Queue *queue)
3132 struct Neighbour *neighbour = queue->neighbour;
3133 struct TransportClient *tc = queue->tc;
3134 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3135 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3136 struct QueueEntry *qe;
3138 struct PendingAcknowledgement *pa;
3139 struct VirtualLink *vl;
3141 if (NULL != queue->transmit_task)
3143 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3144 queue->transmit_task = NULL;
3146 while (NULL != (pa = queue->pa_head))
3148 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3152 GNUNET_CONTAINER_MDLL_remove (neighbour,
3153 neighbour->queue_head,
3154 neighbour->queue_tail,
3156 GNUNET_CONTAINER_MDLL_remove (client,
3157 tc->details.communicator.queue_head,
3158 tc->details.communicator.queue_tail,
3160 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3161 tc->details.communicator.total_queue_length);
3162 while (NULL != (qe = queue->queue_head))
3164 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3165 queue->queue_length--;
3166 tc->details.communicator.total_queue_length--;
3169 GNUNET_assert (qe == qe->pm->qe);
3174 GNUNET_assert (0 == queue->queue_length);
3175 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3176 tc->details.communicator.total_queue_length))
3178 /* Communicator dropped below threshold, resume all queues */
3179 GNUNET_STATISTICS_update (
3181 "# Transmission throttled due to communicator queue limit",
3184 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3186 schedule_transmit_on_queue (s, GNUNET_NO);
3188 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3189 GNUNET_free (queue);
3191 vl = GNUNET_CONTAINER_multipeermap_get (links, &neighbour->pid);
3192 if ((NULL != vl) && (neighbour == vl->n))
3194 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3195 check_link_down (vl);
3197 if (NULL == neighbour->queue_head)
3199 free_neighbour (neighbour);
3207 * @param ale address list entry to free
3210 free_address_list_entry (struct AddressListEntry *ale)
3212 struct TransportClient *tc = ale->tc;
3214 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3215 tc->details.communicator.addr_tail,
3217 if (NULL != ale->sc)
3219 GNUNET_PEERSTORE_store_cancel (ale->sc);
3222 if (NULL != ale->st)
3224 GNUNET_SCHEDULER_cancel (ale->st);
3232 * Stop the peer request in @a value.
3234 * @param cls a `struct TransportClient` that no longer makes the request
3235 * @param pid the peer's identity
3236 * @param value a `struct PeerRequest`
3237 * @return #GNUNET_YES (always)
3240 stop_peer_request (void *cls,
3241 const struct GNUNET_PeerIdentity *pid,
3244 struct TransportClient *tc = cls;
3245 struct PeerRequest *pr = value;
3247 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3250 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3260 * Called whenever a client is disconnected. Frees our
3261 * resources associated with that client.
3263 * @param cls closure, NULL
3264 * @param client identification of the client
3265 * @param app_ctx our `struct TransportClient`
3268 client_disconnect_cb (void *cls,
3269 struct GNUNET_SERVICE_Client *client,
3272 struct TransportClient *tc = app_ctx;
3276 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3277 "Client %p disconnected, cleaning up.\n",
3279 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3285 struct PendingMessage *pm;
3287 while (NULL != (pm = tc->details.core.pending_msg_head))
3289 GNUNET_CONTAINER_MDLL_remove (client,
3290 tc->details.core.pending_msg_head,
3291 tc->details.core.pending_msg_tail,
3299 case CT_COMMUNICATOR: {
3301 struct AddressListEntry *ale;
3303 while (NULL != (q = tc->details.communicator.queue_head))
3305 while (NULL != (ale = tc->details.communicator.addr_head))
3306 free_address_list_entry (ale);
3307 GNUNET_free (tc->details.communicator.address_prefix);
3310 case CT_APPLICATION:
3311 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3314 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3322 * Iterator telling new CORE client about all existing
3323 * connections to peers.
3325 * @param cls the new `struct TransportClient`
3326 * @param pid a connected peer
3327 * @param value the `struct Neighbour` with more information
3328 * @return #GNUNET_OK (continue to iterate)
3331 notify_client_connect_info (void *cls,
3332 const struct GNUNET_PeerIdentity *pid,
3335 struct TransportClient *tc = cls;
3338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3339 "Telling new CORE client about existing connection to %s\n",
3341 core_send_connect_info (tc, pid);
3347 * Initialize a "CORE" client. We got a start message from this
3348 * client, so add it to the list of clients for broadcasting of
3351 * @param cls the client
3352 * @param start the start message that was sent
3355 handle_client_start (void *cls, const struct StartMessage *start)
3357 struct TransportClient *tc = cls;
3360 options = ntohl (start->options);
3361 if ((0 != (1 & options)) &&
3362 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3364 /* client thinks this is a different peer, reject */
3366 GNUNET_SERVICE_client_drop (tc->client);
3369 if (CT_NONE != tc->type)
3372 GNUNET_SERVICE_client_drop (tc->client);
3376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3377 "New CORE client with PID %s registered\n",
3378 GNUNET_i2s (&start->self));
3379 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3380 ¬ify_client_connect_info,
3382 GNUNET_SERVICE_client_continue (tc->client);
3387 * Client asked for transmission to a peer. Process the request.
3389 * @param cls the client
3390 * @param obm the send message that was sent
3393 check_client_send (void *cls, const struct OutboundMessage *obm)
3395 struct TransportClient *tc = cls;
3397 const struct GNUNET_MessageHeader *obmm;
3399 if (CT_CORE != tc->type)
3402 return GNUNET_SYSERR;
3404 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3405 if (size < sizeof (struct GNUNET_MessageHeader))
3408 return GNUNET_SYSERR;
3410 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3411 if (size != ntohs (obmm->size))
3414 return GNUNET_SYSERR;
3421 * Free fragment tree below @e root, excluding @e root itself.
3422 * FIXME: this does NOT seem to have the intended semantics
3423 * based on how this is called. Seems we generally DO expect
3424 * @a root to be free'ed itself as well!
3426 * @param root root of the tree to free
3429 free_fragment_tree (struct PendingMessage *root)
3431 struct PendingMessage *frag;
3433 while (NULL != (frag = root->head_frag))
3435 struct PendingAcknowledgement *pa;
3437 free_fragment_tree (frag);
3438 while (NULL != (pa = frag->pa_head))
3440 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3443 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3450 * Release memory associated with @a pm and remove @a pm from associated
3451 * data structures. @a pm must be a top-level pending message and not
3452 * a fragment in the tree. The entire tree is freed (if applicable).
3454 * @param pm the pending message to free
3457 free_pending_message (struct PendingMessage *pm)
3459 struct TransportClient *tc = pm->client;
3460 struct Neighbour *target = pm->target;
3461 struct DistanceVectorHop *dvh = pm->dvh;
3462 struct PendingAcknowledgement *pa;
3466 GNUNET_CONTAINER_MDLL_remove (client,
3467 tc->details.core.pending_msg_head,
3468 tc->details.core.pending_msg_tail,
3473 GNUNET_CONTAINER_MDLL_remove (dvh,
3474 dvh->pending_msg_head,
3475 dvh->pending_msg_tail,
3478 GNUNET_CONTAINER_MDLL_remove (neighbour,
3479 target->pending_msg_head,
3480 target->pending_msg_tail,
3482 while (NULL != (pa = pm->pa_head))
3484 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3488 free_fragment_tree (pm);
3491 GNUNET_assert (pm == pm->qe->pm);
3494 GNUNET_free_non_null (pm->bpm);
3500 * Send a response to the @a pm that we have processed a
3501 * "send" request with status @a success. We
3502 * transmitted @a bytes_physical on the actual wire.
3503 * Sends a confirmation to the "core" client responsible
3504 * for the original request and free's @a pm.
3506 * @param pm handle to the original pending message
3507 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
3508 * for transmission failure
3509 * @param bytes_physical amount of bandwidth consumed
3512 client_send_response (struct PendingMessage *pm,
3514 uint32_t bytes_physical)
3516 struct TransportClient *tc = pm->client;
3517 struct Neighbour *target = pm->target;
3518 struct GNUNET_MQ_Envelope *env;
3519 struct SendOkMessage *som;
3523 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3524 som->peer = target->pid;
3525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3526 "Confirming %s transmission of %u/%u bytes to %s\n",
3527 (GNUNET_OK == success) ? "successful" : "failed",
3528 (unsigned int) pm->bytes_msg,
3529 (unsigned int) bytes_physical,
3530 GNUNET_i2s (&pm->target->pid));
3531 GNUNET_MQ_send (tc->mq, env);
3533 free_pending_message (pm);
3538 * Create a DV Box message.
3540 * @param total_hops how many hops did the message take so far
3541 * @param num_hops length of the @a hops array
3542 * @param origin origin of the message
3543 * @param hops next peer(s) to the destination, including destination
3544 * @param payload payload of the box
3545 * @param payload_size number of bytes in @a payload
3546 * @return boxed message (caller must #GNUNET_free() it).
3548 static struct TransportDVBoxMessage *
3549 create_dv_box (uint16_t total_hops,
3550 const struct GNUNET_PeerIdentity *origin,
3551 const struct GNUNET_PeerIdentity *target,
3553 const struct GNUNET_PeerIdentity *hops,
3554 const void *payload,
3555 uint16_t payload_size)
3557 struct TransportDVBoxMessage *dvb;
3558 struct GNUNET_PeerIdentity *dhops;
3560 GNUNET_assert (UINT16_MAX <
3561 sizeof (struct TransportDVBoxMessage) +
3562 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3564 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3565 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3568 htons (sizeof (struct TransportDVBoxMessage) +
3569 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3570 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3571 dvb->total_hops = htons (total_hops);
3572 dvb->num_hops = htons (num_hops + 1);
3573 dvb->origin = *origin;
3574 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3575 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3576 dhops[num_hops] = *target;
3577 memcpy (&dhops[num_hops + 1], payload, payload_size);
3579 if (GNUNET_EXTRA_LOGGING > 0)
3583 path = GNUNET_strdup (GNUNET_i2s (&dvb->origin));
3584 for (unsigned int i = 0; i <= num_hops; i++)
3588 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
3592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3593 "Creating DVBox for %u bytes of payload via %s\n",
3594 (unsigned int) payload_size,
3604 * Pick @a hops_array_length random DV paths satisfying @a options
3606 * @param dv data structure to pick paths from
3607 * @param options constraints to satisfy
3608 * @param hops_array[out] set to the result
3609 * @param hops_array_length length of the @a hops_array
3610 * @return number of entries set in @a hops_array
3613 pick_random_dv_hops (const struct DistanceVector *dv,
3614 enum RouteMessageOptions options,
3615 struct DistanceVectorHop **hops_array,
3616 unsigned int hops_array_length)
3618 uint64_t choices[hops_array_length];
3620 unsigned int dv_count;
3622 /* Pick random vectors, but weighted by distance, giving more weight
3623 to shorter vectors */
3626 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3629 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3630 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3631 .rel_value_us == 0))
3632 continue; /* pos unconfirmed and confirmed required */
3633 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3638 if (dv_count <= hops_array_length)
3641 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3643 hops_array[dv_count++] = pos;
3646 for (unsigned int i = 0; i < hops_array_length; i++)
3649 while (GNUNET_NO == ok)
3652 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3654 for (unsigned int j = 0; j < i; j++)
3655 if (choices[i] == choices[j])
3664 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3667 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3669 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3670 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3671 .rel_value_us == 0))
3672 continue; /* pos unconfirmed and confirmed required */
3673 for (unsigned int i = 0; i < hops_array_length; i++)
3674 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3675 hops_array[dv_count++] = pos;
3683 * Client asked for transmission to a peer. Process the request.
3685 * @param cls the client
3686 * @param obm the send message that was sent
3689 handle_client_send (void *cls, const struct OutboundMessage *obm)
3691 struct TransportClient *tc = cls;
3692 struct PendingMessage *pm;
3693 const struct GNUNET_MessageHeader *obmm;
3694 struct Neighbour *target;
3695 struct DistanceVector *dv;
3696 struct DistanceVectorHop *dvh;
3699 const void *payload;
3700 size_t payload_size;
3701 struct TransportDVBoxMessage *dvb;
3702 struct VirtualLink *vl;
3704 GNUNET_assert (CT_CORE == tc->type);
3705 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3706 bytes_msg = ntohs (obmm->size);
3707 vl = GNUNET_CONTAINER_multipeermap_get (links, &obm->peer);
3710 /* Failure: don't have this peer as a neighbour (anymore).
3711 Might have gone down asynchronously, so this is NOT
3712 a protocol violation by CORE. Still count the event,
3713 as this should be rare. */
3714 GNUNET_SERVICE_client_continue (tc->client);
3715 GNUNET_STATISTICS_update (GST_stats,
3716 "# messages dropped (neighbour unknown)",
3721 target = lookup_neighbour (&obm->peer);
3723 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3726 GNUNET_assert ((NULL != target) || (NULL != dv));
3727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3728 "Sending %u bytes to %s using %s\n",
3730 GNUNET_i2s (&obm->peer),
3731 (NULL == target) ? "distance vector path" : "direct queue");
3735 struct DistanceVectorHop *dvh;
3737 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3738 GNUNET_assert (1 == res);
3739 target = dvh->next_hop;
3740 dvb = create_dv_box (0,
3748 payload_size = ntohs (dvb->header.size);
3755 payload_size = bytes_msg;
3758 was_empty = (NULL == target->pending_msg_head);
3759 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3761 pm->target = target;
3762 pm->bytes_msg = payload_size;
3763 memcpy (&pm[1], payload, payload_size);
3764 GNUNET_free_non_null (dvb);
3769 GNUNET_CONTAINER_MDLL_insert (dvh,
3770 dvh->pending_msg_head,
3771 dvh->pending_msg_tail,
3774 GNUNET_CONTAINER_MDLL_insert (neighbour,
3775 target->pending_msg_head,
3776 target->pending_msg_tail,
3778 GNUNET_CONTAINER_MDLL_insert (client,
3779 tc->details.core.pending_msg_head,
3780 tc->details.core.pending_msg_tail,
3783 return; /* all queues must already be busy */
3784 for (struct Queue *queue = target->queue_head; NULL != queue;
3785 queue = queue->next_neighbour)
3787 /* try transmission on any queue that is idle */
3788 if (NULL == queue->transmit_task)
3790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3791 "Queue %llu to %s is idle, triggering transmission\n",
3792 (unsigned long long) queue->qid,
3793 GNUNET_i2s (&queue->neighbour->pid));
3794 queue->transmit_task =
3795 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3802 * Communicator started. Test message is well-formed.
3804 * @param cls the client
3805 * @param cam the send message that was sent
3808 check_communicator_available (
3810 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3812 struct TransportClient *tc = cls;
3815 if (CT_NONE != tc->type)
3818 return GNUNET_SYSERR;
3820 tc->type = CT_COMMUNICATOR;
3821 size = ntohs (cam->header.size) - sizeof (*cam);
3823 return GNUNET_OK; /* receive-only communicator */
3824 GNUNET_MQ_check_zero_termination (cam);
3830 * Client confirms that it is done handling message(s) to a particular
3831 * peer. We may now provide more messages to CORE for this peer.
3833 * Notifies the respective queues that more messages can now be received.
3835 * @param cls the client
3836 * @param rom the message that was sent
3839 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
3841 struct TransportClient *tc = cls;
3842 struct VirtualLink *vl;
3845 if (CT_CORE != tc->type)
3848 GNUNET_SERVICE_client_drop (tc->client);
3851 vl = GNUNET_CONTAINER_multipeermap_get (links, &rom->peer);
3854 GNUNET_STATISTICS_update (GST_stats,
3855 "# RECV_OK dropped: virtual link unknown",
3858 GNUNET_SERVICE_client_continue (tc->client);
3861 delta = ntohl (rom->increase_window_delta);
3862 vl->core_recv_window += delta;
3863 if (delta == vl->core_recv_window)
3865 // FIXME: resume communicators!
3871 * Communicator started. Process the request.
3873 * @param cls the client
3874 * @param cam the send message that was sent
3877 handle_communicator_available (
3879 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3881 struct TransportClient *tc = cls;
3884 size = ntohs (cam->header.size) - sizeof (*cam);
3887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3888 "Receive-only communicator connected\n");
3889 return; /* receive-only communicator */
3891 tc->details.communicator.address_prefix =
3892 GNUNET_strdup ((const char *) &cam[1]);
3893 tc->details.communicator.cc =
3894 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3896 "Communicator with prefix `%s' connected\n",
3897 tc->details.communicator.address_prefix);
3898 GNUNET_SERVICE_client_continue (tc->client);
3903 * Communicator requests backchannel transmission. Check the request.
3905 * @param cls the client
3906 * @param cb the send message that was sent
3907 * @return #GNUNET_OK if message is well-formed
3910 check_communicator_backchannel (
3912 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3914 const struct GNUNET_MessageHeader *inbox;
3920 msize = ntohs (cb->header.size) - sizeof (*cb);
3921 if (((size_t) (UINT16_MAX - msize)) >
3922 sizeof (struct TransportBackchannelEncapsulationMessage) +
3923 sizeof (struct TransportBackchannelRequestPayloadP))
3926 return GNUNET_SYSERR;
3928 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3929 isize = ntohs (inbox->size);
3933 return GNUNET_SYSERR;
3935 is = (const char *) inbox;
3938 GNUNET_assert (msize > 0);
3939 if ('\0' != is[msize - 1])
3942 return GNUNET_SYSERR;
3949 * Remove memory used by expired ephemeral keys.
3954 expire_ephemerals (void *cls)
3956 struct EphemeralCacheEntry *ece;
3959 ephemeral_task = NULL;
3960 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3962 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3965 free_ephemeral (ece);
3968 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3977 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists,
3978 * generate one, cache it and return it.
3980 * @param pid peer to look up ephemeral for
3981 * @param private_key[out] set to the private key
3982 * @param ephemeral_key[out] set to the key
3983 * @param ephemeral_sender_sig[out] set to the signature
3984 * @param monotime[out] set to the monotime used for the signature
3987 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3988 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3989 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3990 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3991 struct GNUNET_TIME_Absolute *monotime)
3993 struct EphemeralCacheEntry *ece;
3994 struct EphemeralConfirmationPS ec;
3996 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3997 if ((NULL != ece) &&
3998 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4001 free_ephemeral (ece);
4006 ece = GNUNET_new (struct EphemeralCacheEntry);
4008 ece->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4009 ece->ephemeral_validity =
4010 GNUNET_TIME_absolute_add (ece->monotime, EPHEMERAL_VALIDITY);
4011 GNUNET_assert (GNUNET_OK ==
4012 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
4013 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
4014 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4015 ec.purpose.size = htonl (sizeof (ec));
4017 ec.ephemeral_key = ece->ephemeral_key;
4018 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4022 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
4024 ece->ephemeral_validity.abs_value_us);
4025 GNUNET_assert (GNUNET_OK ==
4026 GNUNET_CONTAINER_multipeermap_put (
4030 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4031 if (NULL == ephemeral_task)
4032 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4036 *private_key = ece->private_key;
4037 *ephemeral_key = ece->ephemeral_key;
4038 *ephemeral_sender_sig = ece->sender_sig;
4039 *monotime = ece->monotime;
4044 * Send the control message @a payload on @a queue.
4046 * @param queue the queue to use for transmission
4047 * @param pm pending message to update once transmission is done, may be NULL!
4048 * @param payload the payload to send (encapsulated in a
4049 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4050 * @param payload_size number of bytes in @a payload
4053 queue_send_msg (struct Queue *queue,
4054 struct PendingMessage *pm,
4055 const void *payload,
4056 size_t payload_size)
4058 struct Neighbour *n = queue->neighbour;
4059 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4060 struct GNUNET_MQ_Envelope *env;
4062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4063 "Queueing %u bytes of payload for transmission on queue %llu to %s\n",
4064 (unsigned int) payload_size,
4065 (unsigned long long) queue->qid,
4066 GNUNET_i2s (&queue->neighbour->pid));
4067 env = GNUNET_MQ_msg_extra (smt,
4069 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4070 smt->qid = queue->qid;
4071 smt->mid = queue->mid_gen;
4072 smt->receiver = n->pid;
4073 memcpy (&smt[1], payload, payload_size);
4075 /* Pass the env to the communicator of queue for transmission. */
4076 struct QueueEntry *qe;
4078 qe = GNUNET_new (struct QueueEntry);
4079 qe->mid = queue->mid_gen++;
4084 GNUNET_assert (NULL == pm->qe);
4087 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4088 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4089 queue->queue_length++;
4090 queue->tc->details.communicator.total_queue_length++;
4091 GNUNET_MQ_send (queue->tc->mq, env);
4096 // FIXME: improve logging after this point!
4099 * Pick a queue of @a n under constraints @a options and schedule
4100 * transmission of @a hdr.
4102 * @param n neighbour to send to
4103 * @param hdr message to send as payload
4104 * @param options whether queues must be confirmed or not,
4105 * and whether we may pick multiple (2) queues
4108 route_via_neighbour (const struct Neighbour *n,
4109 const struct GNUNET_MessageHeader *hdr,
4110 enum RouteMessageOptions options)
4112 struct GNUNET_TIME_Absolute now;
4113 unsigned int candidates;
4117 /* Pick one or two 'random' queues from n (under constraints of options) */
4118 now = GNUNET_TIME_absolute_get ();
4119 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4120 weight in the future; weight could be assigned by observed
4121 bandwidth (note: not sure if we should do this for this type
4122 of control traffic though). */
4124 for (struct Queue *pos = n->queue_head; NULL != pos;
4125 pos = pos->next_neighbour)
4127 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4128 (pos->validated_until.abs_value_us > now.abs_value_us))
4131 if (0 == candidates)
4133 /* This can happen rarely if the last confirmed queue timed
4134 out just as we were beginning to process this message. */
4135 GNUNET_STATISTICS_update (GST_stats,
4136 "# route selection failed (all no valid queue)",
4141 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4142 if (0 == (options & RMO_REDUNDANT))
4143 sel2 = candidates; /* picks none! */
4145 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4147 for (struct Queue *pos = n->queue_head; NULL != pos;
4148 pos = pos->next_neighbour)
4150 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4151 (pos->validated_until.abs_value_us > now.abs_value_us))
4153 if ((sel1 == candidates) || (sel2 == candidates))
4154 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4162 * Given a distance vector path @a dvh route @a payload to
4163 * the ultimate destination respecting @a options.
4164 * Sets up the boxed message and queues it at the next hop.
4166 * @param dvh choice of the path for the message
4167 * @param payload body to transmit
4168 * @param options options to use for control
4171 forward_via_dvh (const struct DistanceVectorHop *dvh,
4172 const struct GNUNET_MessageHeader *payload,
4173 enum RouteMessageOptions options)
4175 struct TransportDVBoxMessage *dvb;
4177 dvb = create_dv_box (0,
4183 ntohs (payload->size));
4184 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4190 * Pick a path of @a dv under constraints @a options and schedule
4191 * transmission of @a hdr.
4193 * @param n neighbour to send to
4194 * @param hdr message to send as payload
4195 * @param options whether path must be confirmed or not
4196 * and whether we may pick multiple (2) paths
4199 route_via_dv (const struct DistanceVector *dv,
4200 const struct GNUNET_MessageHeader *hdr,
4201 enum RouteMessageOptions options)
4203 struct DistanceVectorHop *hops[2];
4206 res = pick_random_dv_hops (dv,
4209 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4210 for (unsigned int i = 0; i < res; i++)
4211 forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT));
4216 * We need to transmit @a hdr to @a target. If necessary, this may
4217 * involve DV routing.
4219 * @param target peer to receive @a hdr
4220 * @param hdr header of the message to route and #GNUNET_free()
4221 * @param options which transmission channels are allowed
4224 route_message (const struct GNUNET_PeerIdentity *target,
4225 struct GNUNET_MessageHeader *hdr,
4226 enum RouteMessageOptions options)
4228 struct VirtualLink *vl;
4229 struct Neighbour *n;
4230 struct DistanceVector *dv;
4232 vl = GNUNET_CONTAINER_multipeermap_get (links, target);
4234 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4235 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4237 /* if confirmed is required, and we do not have anything
4238 confirmed, drop respective options */
4240 n = lookup_neighbour (target);
4241 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4242 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4244 if ((NULL == n) && (NULL == dv))
4246 GNUNET_STATISTICS_update (GST_stats,
4247 "# Messages dropped in routing: no acceptable method",
4253 /* If both dv and n are possible and we must choose:
4254 flip a coin for the choice between the two; for now 50/50 */
4255 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4257 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4262 if ((NULL != n) && (NULL != dv))
4263 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4264 enough for redunancy, so clear the flag. */
4267 route_via_neighbour (n, hdr, options);
4271 route_via_dv (dv, hdr, options);
4278 * Structure of the key material used to encrypt backchannel messages.
4280 struct BackchannelKeyState
4283 * State of our block cipher.
4285 gcry_cipher_hd_t cipher;
4288 * Actual key material.
4294 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4296 struct GNUNET_CRYPTO_AuthKey hmac_key;
4299 * Symmetric key to use for encryption.
4301 char aes_key[256 / 8];
4304 * Counter value to use during setup.
4306 char aes_ctr[128 / 8];
4313 * Given the key material in @a km and the initialization vector
4314 * @a iv, setup the key material for the backchannel in @a key.
4316 * @param km raw master secret
4317 * @param iv initialization vector
4318 * @param key[out] symmetric cipher and HMAC state to generate
4321 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4322 const struct GNUNET_ShortHashCode *iv,
4323 struct BackchannelKeyState *key)
4325 /* must match #dh_key_derive_eph_pub */
4326 GNUNET_assert (GNUNET_YES ==
4327 GNUNET_CRYPTO_kdf (&key->material,
4328 sizeof (key->material),
4329 "transport-backchannel-key",
4330 strlen ("transport-backchannel-key"),
4335 gcry_cipher_open (&key->cipher,
4336 GCRY_CIPHER_AES256 /* low level: go for speed */,
4337 GCRY_CIPHER_MODE_CTR,
4339 gcry_cipher_setkey (key->cipher,
4340 &key->material.aes_key,
4341 sizeof (key->material.aes_key));
4342 gcry_cipher_setctr (key->cipher,
4343 &key->material.aes_ctr,
4344 sizeof (key->material.aes_ctr));
4349 * Derive backchannel encryption key material from @a priv_ephemeral
4350 * and @a target and @a iv.
4352 * @param priv_ephemeral ephemeral private key to use
4353 * @param target the target peer to encrypt to
4354 * @param iv unique IV to use
4355 * @param key[out] set to the key material
4358 dh_key_derive_eph_pid (
4359 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4360 const struct GNUNET_PeerIdentity *target,
4361 const struct GNUNET_ShortHashCode *iv,
4362 struct BackchannelKeyState *key)
4364 struct GNUNET_HashCode km;
4366 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4367 &target->public_key,
4369 bc_setup_key_state_from_km (&km, iv, key);
4374 * Derive backchannel encryption key material from #GST_my_private_key
4375 * and @a pub_ephemeral and @a iv.
4377 * @param priv_ephemeral ephemeral private key to use
4378 * @param target the target peer to encrypt to
4379 * @param iv unique IV to use
4380 * @param key[out] set to the key material
4383 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4384 const struct GNUNET_ShortHashCode *iv,
4385 struct BackchannelKeyState *key)
4387 struct GNUNET_HashCode km;
4389 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4392 bc_setup_key_state_from_km (&km, iv, key);
4397 * Do HMAC calculation for backchannel messages over @a data using key
4398 * material from @a key.
4400 * @param key key material (from DH)
4401 * @param hmac[out] set to the HMAC
4402 * @param data data to perform HMAC calculation over
4403 * @param data_size number of bytes in @a data
4406 bc_hmac (const struct BackchannelKeyState *key,
4407 struct GNUNET_HashCode *hmac,
4411 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4416 * Perform backchannel encryption using symmetric secret in @a key
4417 * to encrypt data from @a in to @a dst.
4419 * @param key[in,out] key material to use
4420 * @param dst where to write the result
4421 * @param in input data to encrypt (plaintext)
4422 * @param in_size number of bytes of input in @a in and available at @a dst
4425 bc_encrypt (struct BackchannelKeyState *key,
4431 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4436 * Perform backchannel encryption using symmetric secret in @a key
4437 * to encrypt data from @a in to @a dst.
4439 * @param key[in,out] key material to use
4440 * @param ciph cipher text to decrypt
4441 * @param out[out] output data to generate (plaintext)
4442 * @param out_size number of bytes of input in @a ciph and available in @a out
4445 bc_decrypt (struct BackchannelKeyState *key,
4451 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4456 * Clean up key material in @a key.
4458 * @param key key material to clean up (memory must not be free'd!)
4461 bc_key_clean (struct BackchannelKeyState *key)
4463 gcry_cipher_close (key->cipher);
4464 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4469 * Communicator requests backchannel transmission. Process the request.
4471 * @param cls the client
4472 * @param cb the send message that was sent
4475 handle_communicator_backchannel (
4477 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4479 struct TransportClient *tc = cls;
4480 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4481 struct GNUNET_TIME_Absolute monotime;
4482 struct TransportBackchannelEncapsulationMessage *enc;
4483 struct TransportBackchannelRequestPayloadP ppay;
4484 struct BackchannelKeyState key;
4488 /* encapsulate and encrypt message */
4489 msize = ntohs (cb->header.size) - sizeof (*cb) +
4490 sizeof (struct TransportBackchannelRequestPayloadP);
4491 enc = GNUNET_malloc (sizeof (*enc) + msize);
4493 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4494 enc->header.size = htons (sizeof (*enc) + msize);
4495 enc->target = cb->pid;
4496 lookup_ephemeral (&cb->pid,
4498 &enc->ephemeral_key,
4501 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4504 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4505 ppay.monotonic_time = GNUNET_TIME_absolute_hton (monotime);
4506 mpos = (char *) &enc[1];
4507 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4510 &mpos[sizeof (ppay)],
4511 ntohs (cb->header.size) - sizeof (*cb));
4515 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4516 bc_key_clean (&key);
4517 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4518 GNUNET_SERVICE_client_continue (tc->client);
4523 * Address of our peer added. Test message is well-formed.
4525 * @param cls the client
4526 * @param aam the send message that was sent
4527 * @return #GNUNET_OK if message is well-formed
4530 check_add_address (void *cls,
4531 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4533 struct TransportClient *tc = cls;
4535 if (CT_COMMUNICATOR != tc->type)
4538 return GNUNET_SYSERR;
4540 GNUNET_MQ_check_zero_termination (aam);
4546 * Ask peerstore to store our address.
4548 * @param cls an `struct AddressListEntry *`
4551 store_pi (void *cls);
4555 * Function called when peerstore is done storing our address.
4557 * @param cls a `struct AddressListEntry`
4558 * @param success #GNUNET_YES if peerstore was successful
4561 peerstore_store_own_cb (void *cls, int success)
4563 struct AddressListEntry *ale = cls;
4566 if (GNUNET_YES != success)
4567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4568 "Failed to store our own address `%s' in peerstore!\n",
4570 /* refresh period is 1/4 of expiration time, that should be plenty
4571 without being excessive. */
4573 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4581 * Ask peerstore to store our address.
4583 * @param cls an `struct AddressListEntry *`
4586 store_pi (void *cls)
4588 struct AddressListEntry *ale = cls;
4591 struct GNUNET_TIME_Absolute expiration;
4594 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4595 GNUNET_HELLO_sign_address (ale->address,
4601 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4604 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4608 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4609 &peerstore_store_own_cb,
4612 if (NULL == ale->sc)
4614 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4615 "Failed to store our address `%s' with peerstore\n",
4618 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4624 * Address of our peer added. Process the request.
4626 * @param cls the client
4627 * @param aam the send message that was sent
4630 handle_add_address (void *cls,
4631 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4633 struct TransportClient *tc = cls;
4634 struct AddressListEntry *ale;
4637 slen = ntohs (aam->header.size) - sizeof (*aam);
4638 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4640 ale->address = (const char *) &ale[1];
4641 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4642 ale->aid = aam->aid;
4643 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4644 memcpy (&ale[1], &aam[1], slen);
4645 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4646 tc->details.communicator.addr_tail,
4648 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4649 GNUNET_SERVICE_client_continue (tc->client);
4654 * Address of our peer deleted. Process the request.
4656 * @param cls the client
4657 * @param dam the send message that was sent
4660 handle_del_address (void *cls,
4661 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4663 struct TransportClient *tc = cls;
4665 if (CT_COMMUNICATOR != tc->type)
4668 GNUNET_SERVICE_client_drop (tc->client);
4671 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4675 if (dam->aid != ale->aid)
4677 GNUNET_assert (ale->tc == tc);
4678 free_address_list_entry (ale);
4679 GNUNET_SERVICE_client_continue (tc->client);
4682 GNUNET_SERVICE_client_drop (tc->client);
4687 * Context from #handle_incoming_msg(). Closure for many
4688 * message handlers below.
4690 struct CommunicatorMessageContext
4693 * Which communicator provided us with the message.
4695 struct TransportClient *tc;
4698 * Additional information for flow control and about the sender.
4700 struct GNUNET_TRANSPORT_IncomingMessage im;
4703 * Number of hops the message has travelled (if DV-routed).
4704 * FIXME: make use of this in ACK handling!
4706 uint16_t total_hops;
4711 * Given an inbound message @a msg from a communicator @a cmc,
4712 * demultiplex it based on the type calling the right handler.
4714 * @param cmc context for demultiplexing
4715 * @param msg message to demultiplex
4718 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4719 const struct GNUNET_MessageHeader *msg);
4723 * Send ACK to communicator (if requested) and free @a cmc.
4725 * @param cmc context for which we are done handling the message
4728 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4730 if (0 != ntohl (cmc->im.fc_on))
4732 /* send ACK when done to communicator for flow control! */
4733 struct GNUNET_MQ_Envelope *env;
4734 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4736 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4737 ack->reserved = htonl (0);
4738 ack->fc_id = cmc->im.fc_id;
4739 ack->sender = cmc->im.sender;
4740 GNUNET_MQ_send (cmc->tc->mq, env);
4742 GNUNET_SERVICE_client_continue (cmc->tc->client);
4748 * Communicator gave us an unencapsulated message to pass as-is to
4749 * CORE. Process the request.
4751 * @param cls a `struct CommunicatorMessageContext` (must call
4752 * #finish_cmc_handling() when done)
4753 * @param mh the message that was received
4756 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4758 struct CommunicatorMessageContext *cmc = cls;
4759 uint16_t size = ntohs (mh->size);
4761 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4762 (size < sizeof (struct GNUNET_MessageHeader)))
4764 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4767 finish_cmc_handling (cmc);
4768 GNUNET_SERVICE_client_drop (client);
4771 /* Forward to all CORE clients */
4772 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4774 struct GNUNET_MQ_Envelope *env;
4775 struct InboundMessage *im;
4777 if (CT_CORE != tc->type)
4779 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4780 im->peer = cmc->im.sender;
4781 memcpy (&im[1], mh, size);
4782 GNUNET_MQ_send (tc->mq, env);
4784 /* FIXME: consider doing this _only_ once the message
4785 was drained from the CORE MQs to extend flow control to CORE!
4786 (basically, increment counter in cmc, decrement on MQ send continuation!
4788 finish_cmc_handling (cmc);
4793 * Communicator gave us a fragment box. Check the message.
4795 * @param cls a `struct CommunicatorMessageContext`
4796 * @param fb the send message that was sent
4797 * @return #GNUNET_YES if message is well-formed
4800 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4802 uint16_t size = ntohs (fb->header.size);
4803 uint16_t bsize = size - sizeof (*fb);
4808 GNUNET_break_op (0);
4809 return GNUNET_SYSERR;
4811 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4813 GNUNET_break_op (0);
4814 return GNUNET_SYSERR;
4816 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4818 GNUNET_break_op (0);
4819 return GNUNET_SYSERR;
4826 * Clean up an idle cummulative acknowledgement data structure.
4828 * @param cls a `struct AcknowledgementCummulator *`
4831 destroy_ack_cummulator (void *cls)
4833 struct AcknowledgementCummulator *ac = cls;
4836 GNUNET_assert (0 == ac->num_acks);
4839 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4845 * Do the transmission of a cummulative acknowledgement now.
4847 * @param cls a `struct AcknowledgementCummulator *`
4850 transmit_cummulative_ack_cb (void *cls)
4852 struct AcknowledgementCummulator *ac = cls;
4853 struct TransportReliabilityAckMessage *ack;
4854 struct TransportCummulativeAckPayloadP *ap;
4857 GNUNET_assert (0 < ac->ack_counter);
4858 ack = GNUNET_malloc (sizeof (*ack) +
4860 sizeof (struct TransportCummulativeAckPayloadP));
4861 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4863 htons (sizeof (*ack) +
4864 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4865 ack->ack_counter = htonl (ac->ack_counter++);
4866 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4867 for (unsigned int i = 0; i < ac->ack_counter; i++)
4869 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4870 ap[i].ack_delay = GNUNET_TIME_relative_hton (
4871 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
4873 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
4875 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
4876 &destroy_ack_cummulator,
4882 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
4883 * transmission by at most @a ack_delay.
4885 * @param pid target peer
4886 * @param ack_uuid UUID to ack
4887 * @param max_delay how long can the ACK wait
4890 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
4891 const struct AcknowledgementUUIDP *ack_uuid,
4892 struct GNUNET_TIME_Absolute max_delay)
4894 struct AcknowledgementCummulator *ac;
4896 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
4899 ac = GNUNET_new (struct AcknowledgementCummulator);
4901 ac->min_transmission_time = max_delay;
4902 GNUNET_assert (GNUNET_YES ==
4903 GNUNET_CONTAINER_multipeermap_put (
4907 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4911 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
4913 /* must run immediately, ack buffer full! */
4914 GNUNET_SCHEDULER_cancel (ac->task);
4915 transmit_cummulative_ack_cb (ac);
4917 GNUNET_SCHEDULER_cancel (ac->task);
4918 ac->min_transmission_time =
4919 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
4921 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
4922 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
4923 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
4925 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
4926 &transmit_cummulative_ack_cb,
4932 * Closure for #find_by_message_uuid.
4934 struct FindByMessageUuidContext
4939 struct MessageUUIDP message_uuid;
4942 * Set to the reassembly context if found.
4944 struct ReassemblyContext *rc;
4949 * Iterator called to find a reassembly context by the message UUID in the
4952 * @param cls a `struct FindByMessageUuidContext`
4953 * @param key a key (unused)
4954 * @param value a `struct ReassemblyContext`
4955 * @return #GNUNET_YES if not found, #GNUNET_NO if found
4958 find_by_message_uuid (void *cls, uint32_t key, void *value)
4960 struct FindByMessageUuidContext *fc = cls;
4961 struct ReassemblyContext *rc = value;
4964 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
4974 * Communicator gave us a fragment. Process the request.
4976 * @param cls a `struct CommunicatorMessageContext` (must call
4977 * #finish_cmc_handling() when done)
4978 * @param fb the message that was received
4981 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4983 struct CommunicatorMessageContext *cmc = cls;
4984 struct Neighbour *n;
4985 struct ReassemblyContext *rc;
4986 const struct GNUNET_MessageHeader *msg;
4991 struct GNUNET_TIME_Relative cdelay;
4992 struct FindByMessageUuidContext fc;
4994 n = lookup_neighbour (&cmc->im.sender);
4997 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5000 finish_cmc_handling (cmc);
5001 GNUNET_SERVICE_client_drop (client);
5004 if (NULL == n->reassembly_map)
5006 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5007 n->reassembly_heap =
5008 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5009 n->reassembly_timeout_task =
5010 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5011 &reassembly_cleanup_task,
5014 msize = ntohs (fb->msg_size);
5015 fc.message_uuid = fb->msg_uuid;
5017 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5019 &find_by_message_uuid,
5021 if (NULL == (rc = fc.rc))
5023 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5024 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5025 rc->msg_uuid = fb->msg_uuid;
5027 rc->msg_size = msize;
5028 rc->reassembly_timeout =
5029 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5030 rc->last_frag = GNUNET_TIME_absolute_get ();
5031 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5033 rc->reassembly_timeout.abs_value_us);
5034 GNUNET_assert (GNUNET_OK ==
5035 GNUNET_CONTAINER_multihashmap32_put (
5039 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5040 target = (char *) &rc[1];
5041 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5042 rc->msg_missing = rc->msg_size;
5046 target = (char *) &rc[1];
5048 if (msize != rc->msg_size)
5051 finish_cmc_handling (cmc);
5056 fsize = ntohs (fb->header.size) - sizeof (*fb);
5060 finish_cmc_handling (cmc);
5063 frag_off = ntohs (fb->frag_off);
5064 memcpy (&target[frag_off], &fb[1], fsize);
5065 /* update bitfield and msg_missing */
5066 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5068 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5070 rc->bitfield[i / 8] |= (1 << (i % 8));
5075 /* Compute cummulative ACK */
5076 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5077 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5078 if (0 == rc->msg_missing)
5079 cdelay = GNUNET_TIME_UNIT_ZERO;
5080 cummulative_ack (&cmc->im.sender,
5082 GNUNET_TIME_relative_to_absolute (cdelay));
5083 rc->last_frag = GNUNET_TIME_absolute_get ();
5084 /* is reassembly complete? */
5085 if (0 != rc->msg_missing)
5087 finish_cmc_handling (cmc);
5090 /* reassembly is complete, verify result */
5091 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5092 if (ntohs (msg->size) != rc->msg_size)
5095 free_reassembly_context (rc);
5096 finish_cmc_handling (cmc);
5099 /* successful reassembly */
5100 demultiplex_with_cmc (cmc, msg);
5101 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5102 en-route and we forget that we finished this reassembly immediately!
5103 -> keep around until timeout?
5104 -> shorten timeout based on ACK? */
5105 free_reassembly_context (rc);
5110 * Communicator gave us a reliability box. Check the message.
5112 * @param cls a `struct CommunicatorMessageContext`
5113 * @param rb the send message that was sent
5114 * @return #GNUNET_YES if message is well-formed
5117 check_reliability_box (void *cls,
5118 const struct TransportReliabilityBoxMessage *rb)
5121 GNUNET_MQ_check_boxed_message (rb);
5127 * Communicator gave us a reliability box. Process the request.
5129 * @param cls a `struct CommunicatorMessageContext` (must call
5130 * #finish_cmc_handling() when done)
5131 * @param rb the message that was received
5134 handle_reliability_box (void *cls,
5135 const struct TransportReliabilityBoxMessage *rb)
5137 struct CommunicatorMessageContext *cmc = cls;
5138 const struct GNUNET_MessageHeader *inbox =
5139 (const struct GNUNET_MessageHeader *) &rb[1];
5141 // FIXME: call cummulative_ack(), have ack_countdown influence max_delay!
5142 (void) (0 == ntohl (rb->ack_countdown));
5143 /* continue with inner message */
5144 demultiplex_with_cmc (cmc, inbox);
5149 * Check if we have advanced to another age since the last time. If
5150 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5153 * @param pd[in,out] data to update
5154 * @param age current age
5157 update_pd_age (struct PerformanceData *pd, unsigned int age)
5161 if (age == pd->last_age)
5162 return; /* nothing to do */
5163 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5164 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5166 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5168 the->bytes_sent = 0;
5169 the->bytes_received = 0;
5176 * Update @a pd based on the latest @a rtt and the number of bytes
5177 * that were confirmed to be successfully transmitted.
5179 * @param pd[in,out] data to update
5180 * @param rtt latest round-trip time
5181 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5184 update_performance_data (struct PerformanceData *pd,
5185 struct GNUNET_TIME_Relative rtt,
5186 uint16_t bytes_transmitted_ok)
5188 uint64_t nval = rtt.rel_value_us;
5189 uint64_t oval = pd->aged_rtt.rel_value_us;
5190 unsigned int age = get_age ();
5191 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5193 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5196 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5197 update_pd_age (pd, age);
5198 the->bytes_received += bytes_transmitted_ok;
5203 * We have successfully transmitted data via @a q, update metrics.
5205 * @param q queue to update
5206 * @param rtt round trip time observed
5207 * @param bytes_transmitted_ok number of bytes successfully transmitted
5210 update_queue_performance (struct Queue *q,
5211 struct GNUNET_TIME_Relative rtt,
5212 uint16_t bytes_transmitted_ok)
5214 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5219 * We have successfully transmitted data via @a dvh, update metrics.
5221 * @param dvh distance vector path data to update
5222 * @param rtt round trip time observed
5223 * @param bytes_transmitted_ok number of bytes successfully transmitted
5226 update_dvh_performance (struct DistanceVectorHop *dvh,
5227 struct GNUNET_TIME_Relative rtt,
5228 uint16_t bytes_transmitted_ok)
5230 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5235 * The @a pa was acknowledged, process the acknowledgement.
5237 * @param pa the pending acknowledgement that was satisfied
5238 * @param ack_delay artificial delay from cummulative acks created by the
5242 handle_acknowledged (struct PendingAcknowledgement *pa,
5243 struct GNUNET_TIME_Relative ack_delay)
5245 struct PendingMessage *pm = pa->pm;
5246 struct GNUNET_TIME_Relative delay;
5248 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5249 if (delay.rel_value_us > ack_delay.rel_value_us)
5250 delay = GNUNET_TIME_UNIT_ZERO;
5252 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5253 if (NULL != pa->queue)
5254 update_queue_performance (pa->queue, delay, pa->message_size);
5255 if (NULL != pa->dvh)
5256 update_dvh_performance (pa->dvh, delay, pa->message_size);
5259 if (NULL != pm->frag_parent)
5261 pm = pm->frag_parent;
5262 free_fragment_tree (pa->pm);
5264 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5266 struct PendingMessage *parent = pm->frag_parent;
5268 free_fragment_tree (pm);
5271 if (NULL != pm->head_frag)
5272 pm = NULL; /* we are done, otherwise free 'pm' below */
5275 free_pending_message (pm);
5276 free_pending_acknowledgement (pa);
5281 * Communicator gave us a reliability ack. Check it is well-formed.
5283 * @param cls a `struct CommunicatorMessageContext` (unused)
5284 * @param ra the message that was received
5285 * @return #GNUNET_Ok if @a ra is well-formed
5288 check_reliability_ack (void *cls,
5289 const struct TransportReliabilityAckMessage *ra)
5291 unsigned int n_acks;
5294 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5295 sizeof (struct TransportCummulativeAckPayloadP);
5298 GNUNET_break_op (0);
5299 return GNUNET_SYSERR;
5301 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5302 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5304 GNUNET_break_op (0);
5305 return GNUNET_SYSERR;
5312 * Communicator gave us a reliability ack. Process the request.
5314 * @param cls a `struct CommunicatorMessageContext` (must call
5315 * #finish_cmc_handling() when done)
5316 * @param ra the message that was received
5319 handle_reliability_ack (void *cls,
5320 const struct TransportReliabilityAckMessage *ra)
5322 struct CommunicatorMessageContext *cmc = cls;
5323 const struct TransportCummulativeAckPayloadP *ack;
5324 struct PendingAcknowledgement *pa;
5325 unsigned int n_acks;
5326 uint32_t ack_counter;
5328 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5329 sizeof (struct TransportCummulativeAckPayloadP);
5330 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5331 for (unsigned int i = 0; i < n_acks; i++)
5334 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5337 GNUNET_STATISTICS_update (
5339 "# FRAGMENT_ACKS dropped, no matching pending message",
5344 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5347 ack_counter = htonl (ra->ack_counter);
5348 // FIXME: track ACK losses based on ack_counter somewhere!
5349 // (DV and/or Neighbour?)
5350 finish_cmc_handling (cmc);
5355 * Communicator gave us a backchannel encapsulation. Check the message.
5357 * @param cls a `struct CommunicatorMessageContext`
5358 * @param be the send message that was sent
5359 * @return #GNUNET_YES if message is well-formed
5362 check_backchannel_encapsulation (
5364 const struct TransportBackchannelEncapsulationMessage *be)
5366 uint16_t size = ntohs (be->header.size);
5369 if ((size - sizeof (*be)) <
5370 (sizeof (struct TransportBackchannelRequestPayloadP) +
5371 sizeof (struct GNUNET_MessageHeader)))
5373 GNUNET_break_op (0);
5374 return GNUNET_SYSERR;
5381 * We received the plaintext @a msg from backtalker @a b. Forward
5382 * it to the respective communicator.
5384 * @param b a backtalker
5385 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5386 * followed by the target name of the communicator
5387 * @param msg_size number of bytes in @a msg
5390 forward_backchannel_payload (struct Backtalker *b,
5394 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5395 struct GNUNET_MQ_Envelope *env;
5396 struct TransportClient *tc;
5397 const struct GNUNET_MessageHeader *mh;
5398 const char *target_communicator;
5401 /* Determine target_communicator and check @a msg is well-formed */
5403 mhs = ntohs (mh->size);
5404 if (mhs <= msg_size)
5406 GNUNET_break_op (0);
5409 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5410 if ('\0' != target_communicator[msg_size - mhs - 1])
5412 GNUNET_break_op (0);
5415 /* Find client providing this communicator */
5416 for (tc = clients_head; NULL != tc; tc = tc->next)
5417 if ((CT_COMMUNICATOR == tc->type) &&
5419 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5427 "# Backchannel message dropped: target communicator `%s' unknown",
5428 target_communicator);
5429 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5430 GNUNET_free (stastr);
5433 /* Finally, deliver backchannel message to communicator */
5434 env = GNUNET_MQ_msg_extra (
5437 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5439 memcpy (&cbi[1], msg, msg_size);
5440 GNUNET_MQ_send (tc->mq, env);
5445 * Free data structures associated with @a b.
5447 * @param b data structure to release
5450 free_backtalker (struct Backtalker *b)
5454 GNUNET_PEERSTORE_iterate_cancel (b->get);
5456 GNUNET_assert (NULL != b->cmc);
5457 finish_cmc_handling (b->cmc);
5460 if (NULL != b->task)
5462 GNUNET_SCHEDULER_cancel (b->task);
5467 GNUNET_PEERSTORE_store_cancel (b->sc);
5472 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5478 * Callback to free backtalker records.
5482 * @param value a `struct Backtalker`
5483 * @return #GNUNET_OK (always)
5486 free_backtalker_cb (void *cls,
5487 const struct GNUNET_PeerIdentity *pid,
5490 struct Backtalker *b = value;
5494 free_backtalker (b);
5500 * Function called when it is time to clean up a backtalker.
5502 * @param cls a `struct Backtalker`
5505 backtalker_timeout_cb (void *cls)
5507 struct Backtalker *b = cls;
5510 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5512 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5515 GNUNET_assert (NULL == b->sc);
5516 free_backtalker (b);
5521 * Function called with the monotonic time of a backtalker
5522 * by PEERSTORE. Updates the time and continues processing.
5524 * @param cls a `struct Backtalker`
5525 * @param record the information found, NULL for the last call
5526 * @param emsg error message
5529 backtalker_monotime_cb (void *cls,
5530 const struct GNUNET_PEERSTORE_Record *record,
5533 struct Backtalker *b = cls;
5534 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5535 struct GNUNET_TIME_Absolute mt;
5540 /* we're done with #backtalker_monotime_cb() invocations,
5541 continue normal processing */
5543 GNUNET_assert (NULL != b->cmc);
5544 finish_cmc_handling (b->cmc);
5546 if (0 != b->body_size)
5547 forward_backchannel_payload (b, &b[1], b->body_size);
5550 if (sizeof (*mtbe) != record->value_size)
5555 mtbe = record->value;
5556 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5557 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5559 GNUNET_STATISTICS_update (
5561 "# Backchannel messages dropped: monotonic time not increasing",
5564 b->monotonic_time = mt;
5565 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5574 * Function called by PEERSTORE when the store operation of
5575 * a backtalker's monotonic time is complete.
5577 * @param cls the `struct Backtalker`
5578 * @param success #GNUNET_OK on success
5581 backtalker_monotime_store_cb (void *cls, int success)
5583 struct Backtalker *b = cls;
5585 if (GNUNET_OK != success)
5587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5588 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5591 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5596 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5598 * @param b a backtalker with updated monotonic time
5601 update_backtalker_monotime (struct Backtalker *b)
5603 struct GNUNET_TIME_AbsoluteNBO mtbe;
5607 GNUNET_PEERSTORE_store_cancel (b->sc);
5612 GNUNET_SCHEDULER_cancel (b->task);
5615 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5617 GNUNET_PEERSTORE_store (peerstore,
5620 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5623 GNUNET_TIME_UNIT_FOREVER_ABS,
5624 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5625 &backtalker_monotime_store_cb,
5631 * Communicator gave us a backchannel encapsulation. Process the request.
5632 * (We are not the origin of the backchannel here, the communicator simply
5633 * received a backchannel message and we are expected to forward it.)
5635 * @param cls a `struct CommunicatorMessageContext` (must call
5636 * #finish_cmc_handling() when done)
5637 * @param be the message that was received
5640 handle_backchannel_encapsulation (
5642 const struct TransportBackchannelEncapsulationMessage *be)
5644 struct CommunicatorMessageContext *cmc = cls;
5645 struct BackchannelKeyState key;
5646 struct GNUNET_HashCode hmac;
5650 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5652 /* not for me, try to route to target */
5653 route_message (&be->target,
5654 GNUNET_copy_message (&be->header),
5656 finish_cmc_handling (cmc);
5659 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5660 hdr = (const char *) &be[1];
5661 hdr_len = ntohs (be->header.size) - sizeof (*be);
5662 bc_hmac (&key, &hmac, hdr, hdr_len);
5663 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5665 /* HMAC missmatch, disard! */
5666 GNUNET_break_op (0);
5667 finish_cmc_handling (cmc);
5670 /* begin actual decryption */
5672 struct Backtalker *b;
5673 struct GNUNET_TIME_Absolute monotime;
5674 struct TransportBackchannelRequestPayloadP ppay;
5675 char body[hdr_len - sizeof (ppay)];
5677 GNUNET_assert (hdr_len >=
5678 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5679 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5680 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5681 bc_key_clean (&key);
5682 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5683 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5684 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5686 GNUNET_STATISTICS_update (
5688 "# Backchannel messages dropped: monotonic time not increasing",
5691 finish_cmc_handling (cmc);
5695 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5697 /* Check signature */
5698 struct EphemeralConfirmationPS ec;
5700 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5701 ec.purpose.size = htonl (sizeof (ec));
5702 ec.target = GST_my_identity;
5703 ec.ephemeral_key = be->ephemeral_key;
5706 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5709 &ppay.sender.public_key))
5711 /* Signature invalid, disard! */
5712 GNUNET_break_op (0);
5713 finish_cmc_handling (cmc);
5719 /* update key cache and mono time */
5720 b->last_ephemeral = be->ephemeral_key;
5721 b->monotonic_time = monotime;
5722 update_backtalker_monotime (b);
5723 forward_backchannel_payload (b, body, sizeof (body));
5725 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5726 finish_cmc_handling (cmc);
5729 /* setup data structure to cache signature AND check
5730 monotonic time with PEERSTORE before forwarding backchannel payload */
5731 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5732 b->pid = ppay.sender;
5733 b->body_size = sizeof (body);
5734 memcpy (&b[1], body, sizeof (body));
5735 GNUNET_assert (GNUNET_YES ==
5736 GNUNET_CONTAINER_multipeermap_put (
5740 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5741 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5744 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5745 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5747 GNUNET_PEERSTORE_iterate (peerstore,
5750 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5751 &backtalker_monotime_cb,
5758 * Task called when we should check if any of the DV paths
5759 * we have learned to a target are due for garbage collection.
5761 * Collects stale paths, and possibly frees the entire DV
5762 * entry if no paths are left. Otherwise re-schedules itself.
5764 * @param cls a `struct DistanceVector`
5767 path_cleanup_cb (void *cls)
5769 struct DistanceVector *dv = cls;
5770 struct DistanceVectorHop *pos;
5772 dv->timeout_task = NULL;
5773 while (NULL != (pos = dv->dv_head))
5775 GNUNET_assert (dv == pos->dv);
5776 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5778 free_distance_vector_hop (pos);
5786 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5791 * The @a hop is a validated path to the respective target
5792 * peer and we should tell core about it -- and schedule
5793 * a job to revoke the state.
5795 * @param hop a path to some peer that is the reason for activation
5798 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5800 struct DistanceVector *dv = hop->dv;
5801 struct VirtualLink *vl;
5803 vl = GNUNET_CONTAINER_multipeermap_get (links, &dv->target);
5806 /* Link was already up, remember dv is also now available and we are done */
5810 vl = GNUNET_new (struct VirtualLink);
5811 vl->target = dv->target;
5813 vl->core_recv_window = RECV_WINDOW_SIZE;
5814 vl->visibility_task =
5815 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
5816 GNUNET_break (GNUNET_YES ==
5817 GNUNET_CONTAINER_multipeermap_put (
5821 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5822 /* We lacked a confirmed connection to the target
5823 before, so tell CORE about it (finally!) */
5824 cores_send_connect_info (&dv->target);
5829 * We have learned a @a path through the network to some other peer, add it to
5830 * our DV data structure (returning #GNUNET_YES on success).
5832 * We do not add paths if we have a sufficient number of shorter
5833 * paths to this target already (returning #GNUNET_NO).
5835 * We also do not add problematic paths, like those where we lack the first
5836 * hop in our neighbour list (i.e. due to a topology change) or where some
5837 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5839 * @param path the path we learned, path[0] should be us,
5840 * and then path contains a valid path from us to
5841 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
5842 * @param path_len number of entries on the @a path, at least three!
5843 * @param network_latency how long does the message take from us to
5844 * `path[path_len-1]`? set to "forever" if unknown
5845 * @param path_valid_until how long is this path considered validated? Maybe
5847 * @return #GNUNET_YES on success,
5848 * #GNUNET_NO if we have better path(s) to the target
5849 * #GNUNET_SYSERR if the path is useless and/or invalid
5850 * (i.e. path[1] not a direct neighbour
5851 * or path[i+1] is a direct neighbour for i>0)
5854 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5855 unsigned int path_len,
5856 struct GNUNET_TIME_Relative network_latency,
5857 struct GNUNET_TIME_Absolute path_valid_until)
5859 struct DistanceVectorHop *hop;
5860 struct DistanceVector *dv;
5861 struct Neighbour *next_hop;
5862 unsigned int shorter_distance;
5866 /* what a boring path! not allowed! */
5868 return GNUNET_SYSERR;
5870 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5871 next_hop = lookup_neighbour (&path[1]);
5872 if (NULL == next_hop)
5874 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5876 return GNUNET_SYSERR;
5878 for (unsigned int i = 2; i < path_len; i++)
5879 if (NULL != lookup_neighbour (&path[i]))
5881 /* Useless path, we have a direct connection to some hop
5882 in the middle of the path, so this one doesn't even
5883 seem terribly useful for redundancy */
5884 return GNUNET_SYSERR;
5886 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5889 dv = GNUNET_new (struct DistanceVector);
5890 dv->target = path[path_len - 1];
5891 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5894 GNUNET_assert (GNUNET_OK ==
5895 GNUNET_CONTAINER_multipeermap_put (
5899 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5901 /* Check if we have this path already! */
5902 shorter_distance = 0;
5903 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5906 if (pos->distance < path_len - 2)
5908 /* Note that the distances in 'pos' excludes us (path[0]) and
5909 the next_hop (path[1]), so we need to subtract two
5910 and check next_hop explicitly */
5911 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5913 int match = GNUNET_YES;
5915 for (unsigned int i = 0; i < pos->distance; i++)
5917 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5923 if (GNUNET_YES == match)
5925 struct GNUNET_TIME_Relative last_timeout;
5927 /* Re-discovered known path, update timeout */
5928 GNUNET_STATISTICS_update (GST_stats,
5929 "# Known DV path refreshed",
5932 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5934 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5935 pos->path_valid_until =
5936 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5937 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5938 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5940 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
5941 activate_core_visible_dv_path (pos);
5942 if (last_timeout.rel_value_us <
5943 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5944 DV_PATH_DISCOVERY_FREQUENCY)
5947 /* Some peer send DV learn messages too often, we are learning
5948 the same path faster than it would be useful; do not forward! */
5955 /* Count how many shorter paths we have (incl. direct
5956 neighbours) before simply giving up on this one! */
5957 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
5959 /* We have a shorter path already! */
5962 /* create new DV path entry */
5963 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
5964 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5965 hop->next_hop = next_hop;
5967 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
5970 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5971 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5972 hop->path_valid_until = path_valid_until;
5973 hop->distance = path_len - 2;
5974 hop->pd.aged_rtt = network_latency;
5975 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
5976 GNUNET_CONTAINER_MDLL_insert (neighbour,
5980 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
5981 activate_core_visible_dv_path (hop);
5987 * Communicator gave us a DV learn message. Check the message.
5989 * @param cls a `struct CommunicatorMessageContext`
5990 * @param dvl the send message that was sent
5991 * @return #GNUNET_YES if message is well-formed
5994 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
5996 uint16_t size = ntohs (dvl->header.size);
5997 uint16_t num_hops = ntohs (dvl->num_hops);
5998 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6001 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6003 GNUNET_break_op (0);
6004 return GNUNET_SYSERR;
6006 if (num_hops > MAX_DV_HOPS_ALLOWED)
6008 GNUNET_break_op (0);
6009 return GNUNET_SYSERR;
6011 for (unsigned int i = 0; i < num_hops; i++)
6013 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6015 GNUNET_break_op (0);
6016 return GNUNET_SYSERR;
6018 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6020 GNUNET_break_op (0);
6021 return GNUNET_SYSERR;
6029 * Build and forward a DV learn message to @a next_hop.
6031 * @param next_hop peer to send the message to
6032 * @param msg message received
6033 * @param bi_history bitmask specifying hops on path that were bidirectional
6034 * @param nhops length of the @a hops array
6035 * @param hops path the message traversed so far
6036 * @param in_time when did we receive the message, used to calculate network
6040 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6041 const struct TransportDVLearnMessage *msg,
6042 uint16_t bi_history,
6044 const struct DVPathEntryP *hops,
6045 struct GNUNET_TIME_Absolute in_time)
6047 struct DVPathEntryP *dhops;
6048 struct TransportDVLearnMessage *fwd;
6049 struct GNUNET_TIME_Relative nnd;
6051 /* compute message for forwarding */
6052 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6053 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
6054 (nhops + 1) * sizeof (struct DVPathEntryP));
6055 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6056 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6057 (nhops + 1) * sizeof (struct DVPathEntryP));
6058 fwd->num_hops = htons (nhops + 1);
6059 fwd->bidirectional = htons (bi_history);
6060 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6061 GNUNET_TIME_relative_ntoh (
6062 msg->non_network_delay));
6063 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6064 fwd->init_sig = msg->init_sig;
6065 fwd->initiator = msg->initiator;
6066 fwd->challenge = msg->challenge;
6067 dhops = (struct DVPathEntryP *) &fwd[1];
6068 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6069 dhops[nhops].hop = GST_my_identity;
6071 struct DvHopPS dhp = {.purpose.purpose =
6072 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6073 .purpose.size = htonl (sizeof (dhp)),
6074 .pred = dhops[nhops - 1].hop,
6076 .challenge = msg->challenge};
6078 GNUNET_assert (GNUNET_OK ==
6079 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6081 &dhops[nhops].hop_sig));
6083 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6088 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6090 * @param sender_monotonic_time monotonic time of the initiator
6091 * @param init the signer
6092 * @param challenge the challenge that was signed
6093 * @param init_sig signature presumably by @a init
6094 * @return #GNUNET_OK if the signature is valid
6097 validate_dv_initiator_signature (
6098 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6099 const struct GNUNET_PeerIdentity *init,
6100 const struct ChallengeNonceP *challenge,
6101 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6103 struct DvInitPS ip = {.purpose.purpose = htonl (
6104 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6105 .purpose.size = htonl (sizeof (ip)),
6106 .monotonic_time = sender_monotonic_time,
6107 .challenge = *challenge};
6111 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6116 GNUNET_break_op (0);
6117 return GNUNET_SYSERR;
6124 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6126 struct NeighbourSelectionContext
6129 * Original message we received.
6131 const struct TransportDVLearnMessage *dvl;
6136 const struct DVPathEntryP *hops;
6139 * Time we received the message.
6141 struct GNUNET_TIME_Absolute in_time;
6144 * Offsets of the selected peers.
6146 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6149 * Number of peers eligible for selection.
6151 unsigned int num_eligible;
6154 * Number of peers that were selected for forwarding.
6156 unsigned int num_selections;
6159 * Number of hops in @e hops
6164 * Bitmap of bidirectional connections encountered.
6166 uint16_t bi_history;
6171 * Function called for each neighbour during #handle_dv_learn.
6173 * @param cls a `struct NeighbourSelectionContext *`
6174 * @param pid identity of the peer
6175 * @param value a `struct Neighbour`
6176 * @return #GNUNET_YES (always)
6179 dv_neighbour_selection (void *cls,
6180 const struct GNUNET_PeerIdentity *pid,
6183 struct NeighbourSelectionContext *nsc = cls;
6186 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6187 return GNUNET_YES; /* skip initiator */
6188 for (unsigned int i = 0; i < nsc->nhops; i++)
6189 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6190 return GNUNET_YES; /* skip peers on path */
6191 nsc->num_eligible++;
6197 * Function called for each neighbour during #handle_dv_learn.
6198 * We call #forward_dv_learn() on the neighbour(s) selected
6199 * during #dv_neighbour_selection().
6201 * @param cls a `struct NeighbourSelectionContext *`
6202 * @param pid identity of the peer
6203 * @param value a `struct Neighbour`
6204 * @return #GNUNET_YES (always)
6207 dv_neighbour_transmission (void *cls,
6208 const struct GNUNET_PeerIdentity *pid,
6211 struct NeighbourSelectionContext *nsc = cls;
6214 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6215 return GNUNET_YES; /* skip initiator */
6216 for (unsigned int i = 0; i < nsc->nhops; i++)
6217 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6218 return GNUNET_YES; /* skip peers on path */
6219 for (unsigned int i = 0; i < nsc->num_selections; i++)
6221 if (nsc->selections[i] == nsc->num_eligible)
6223 forward_dv_learn (pid,
6232 nsc->num_eligible++;
6238 * Computes the number of neighbours we should forward a DVInit
6239 * message to given that it has so far taken @a hops_taken hops
6240 * though the network and that the number of neighbours we have
6241 * in total is @a neighbour_count, out of which @a eligible_count
6242 * are not yet on the path.
6244 * NOTE: technically we might want to include NSE in the formula to
6245 * get a better grip on the overall network size. However, for now
6246 * using NSE here would create a dependency issue in the build system.
6247 * => Left for later, hardcoded to 50 for now.
6249 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6250 * peers via DV (`target_total`). We want the reach to be spread out
6251 * over various distances to the origin, with a bias towards shorter
6254 * We make the strong assumption that the network topology looks
6255 * "similar" at other hops, in particular the @a neighbour_count
6256 * should be comparable at other hops.
6258 * If the local neighbourhood is densely connected, we expect that @a
6259 * eligible_count is close to @a neighbour_count minus @a hops_taken
6260 * as a lot of the path is already known. In that case, we should
6261 * forward to few(er) peers to try to find a path out of the
6262 * neighbourhood. OTOH, if @a eligible_count is close to @a
6263 * neighbour_count, we should forward to many peers as we are either
6264 * still close to the origin (i.e. @a hops_taken is small) or because
6265 * we managed to get beyond a local cluster. We express this as
6266 * the `boost_factor` using the square of the fraction of eligible
6267 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6268 * 99% are eligible, the 'boost' will be almost 1).
6270 * Second, the more hops we have taken, the larger the problem of an
6271 * exponential traffic explosion gets. So we take the `target_total`,
6272 * and compute our degree such that at each distance d 2^{-d} peers
6273 * are selected (corrected by the `boost_factor`).
6275 * @param hops_taken number of hops DVInit has travelled so far
6276 * @param neighbour_count number of neighbours we have in total
6277 * @param eligible_count number of neighbours we could in
6281 calculate_fork_degree (unsigned int hops_taken,
6282 unsigned int neighbour_count,
6283 unsigned int eligible_count)
6285 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6286 double eligible_ratio =
6287 ((double) eligible_count) / ((double) neighbour_count);
6288 double boost_factor = eligible_ratio * eligible_ratio;
6292 if (hops_taken >= 64)
6293 return 0; /* precaution given bitshift below */
6294 for (unsigned int i = 1; i < hops_taken; i++)
6296 /* For each hop, subtract the expected number of targets
6297 reached at distance d (so what remains divided by 2^d) */
6298 target_total -= (target_total * boost_factor / (1LLU << i));
6301 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6302 /* round up or down probabilistically depending on how close we were
6303 when floor()ing to rnd */
6304 left = target_total - (double) rnd;
6305 if (UINT32_MAX * left >
6306 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6307 rnd++; /* round up */
6313 * Function called when peerstore is done storing a DV monotonic time.
6315 * @param cls a `struct Neighbour`
6316 * @param success #GNUNET_YES if peerstore was successful
6319 neighbour_store_dvmono_cb (void *cls, int success)
6321 struct Neighbour *n = cls;
6324 if (GNUNET_YES != success)
6325 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6326 "Failed to store other peer's monotonic time in peerstore!\n");
6331 * Communicator gave us a DV learn message. Process the request.
6333 * @param cls a `struct CommunicatorMessageContext` (must call
6334 * #finish_cmc_handling() when done)
6335 * @param dvl the message that was received
6338 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6340 struct CommunicatorMessageContext *cmc = cls;
6341 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6344 uint16_t bi_history;
6345 const struct DVPathEntryP *hops;
6348 struct GNUNET_TIME_Absolute in_time;
6349 struct Neighbour *n;
6351 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6352 bi_history = ntohs (dvl->bidirectional);
6353 hops = (const struct DVPathEntryP *) &dvl[1];
6357 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6360 finish_cmc_handling (cmc);
6367 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6370 finish_cmc_handling (cmc);
6375 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6376 cc = cmc->tc->details.communicator.cc;
6377 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6378 cc); // FIXME: add bi-directional flag to cc?
6379 in_time = GNUNET_TIME_absolute_get ();
6381 /* continue communicator here, everything else can happen asynchronous! */
6382 finish_cmc_handling (cmc);
6384 n = lookup_neighbour (&dvl->initiator);
6387 if ((n->dv_monotime_available == GNUNET_YES) &&
6388 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6389 n->last_dv_learn_monotime.abs_value_us))
6391 GNUNET_STATISTICS_update (GST_stats,
6392 "# DV learn discarded due to time travel",
6397 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6402 GNUNET_break_op (0);
6405 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6406 if (GNUNET_YES == n->dv_monotime_available)
6409 GNUNET_PEERSTORE_store_cancel (n->sc);
6411 GNUNET_PEERSTORE_store (peerstore,
6414 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6415 &dvl->monotonic_time,
6416 sizeof (dvl->monotonic_time),
6417 GNUNET_TIME_UNIT_FOREVER_ABS,
6418 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6419 &neighbour_store_dvmono_cb,
6423 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6424 If signature verification load too high, implement random drop strategy */
6425 for (unsigned int i = 0; i < nhops; i++)
6427 struct DvHopPS dhp = {.purpose.purpose =
6428 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6429 .purpose.size = htonl (sizeof (dhp)),
6430 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6431 .succ = (nhops - 1 == i) ? GST_my_identity
6433 .challenge = dvl->challenge};
6436 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6439 &hops[i].hop.public_key))
6441 GNUNET_break_op (0);
6446 do_fwd = GNUNET_YES;
6447 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6449 struct GNUNET_PeerIdentity path[nhops + 1];
6450 struct GNUNET_TIME_Relative host_latency_sum;
6451 struct GNUNET_TIME_Relative latency;
6452 struct GNUNET_TIME_Relative network_latency;
6454 /* We initiated this, learn the forward path! */
6455 path[0] = GST_my_identity;
6456 path[1] = hops[0].hop;
6457 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6459 // Need also something to lookup initiation time
6460 // to compute RTT! -> add RTT argument here?
6461 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6462 // (based on dvl->challenge, we can identify time of origin!)
6464 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6465 /* assumption: latency on all links is the same */
6466 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6468 for (unsigned int i = 2; i <= nhops; i++)
6470 struct GNUNET_TIME_Relative ilat;
6472 /* assumption: linear latency increase per hop */
6473 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6474 path[i] = hops[i - 1].hop;
6475 learn_dv_path (path,
6478 GNUNET_TIME_relative_to_absolute (
6479 ADDRESS_VALIDATION_LIFETIME));
6481 /* as we initiated, do not forward again (would be circular!) */
6487 /* last hop was bi-directional, we could learn something here! */
6488 struct GNUNET_PeerIdentity path[nhops + 2];
6490 path[0] = GST_my_identity;
6491 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6492 for (unsigned int i = 0; i < nhops; i++)
6496 if (0 == (bi_history & (1 << i)))
6497 break; /* i-th hop not bi-directional, stop learning! */
6500 path[i + 2] = dvl->initiator;
6504 path[i + 2] = hops[nhops - i - 2].hop;
6507 iret = learn_dv_path (path,
6509 GNUNET_TIME_UNIT_FOREVER_REL,
6510 GNUNET_TIME_UNIT_ZERO_ABS);
6511 if (GNUNET_SYSERR == iret)
6513 /* path invalid or too long to be interesting for US, thus should also
6514 not be interesting to our neighbours, cut path when forwarding to
6515 'i' hops, except of course for the one that goes back to the
6517 GNUNET_STATISTICS_update (GST_stats,
6518 "# DV learn not forwarded due invalidity of path",
6524 if ((GNUNET_NO == iret) && (nhops == i + 1))
6526 /* we have better paths, and this is the longest target,
6527 so there cannot be anything interesting later */
6528 GNUNET_STATISTICS_update (GST_stats,
6529 "# DV learn not forwarded, got better paths",
6538 if (MAX_DV_HOPS_ALLOWED == nhops)
6540 /* At limit, we're out of here! */
6541 finish_cmc_handling (cmc);
6545 /* Forward to initiator, if path non-trivial and possible */
6546 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6547 did_initiator = GNUNET_NO;
6550 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6552 /* send back to origin! */
6553 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6554 did_initiator = GNUNET_YES;
6556 /* We forward under two conditions: either we still learned something
6557 ourselves (do_fwd), or the path was darn short and thus the initiator is
6558 likely to still be very interested in this (and we did NOT already
6559 send it back to the initiator) */
6560 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6561 (GNUNET_NO == did_initiator)))
6563 /* Pick random neighbours that are not yet on the path */
6564 struct NeighbourSelectionContext nsc;
6567 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6570 nsc.bi_history = bi_history;
6572 nsc.in_time = in_time;
6573 nsc.num_eligible = 0;
6574 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6575 &dv_neighbour_selection,
6577 if (0 == nsc.num_eligible)
6578 return; /* done here, cannot forward to anyone else */
6579 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6580 nsc.num_selections =
6581 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6582 for (unsigned int i = 0; i < nsc.num_selections; i++)
6584 (nsc.num_selections == n_cnt)
6585 ? i /* all were selected, avoid collisions by chance */
6586 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6587 nsc.num_eligible = 0;
6588 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6589 &dv_neighbour_transmission,
6596 * Communicator gave us a DV box. Check the message.
6598 * @param cls a `struct CommunicatorMessageContext`
6599 * @param dvb the send message that was sent
6600 * @return #GNUNET_YES if message is well-formed
6603 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6605 uint16_t size = ntohs (dvb->header.size);
6606 uint16_t num_hops = ntohs (dvb->num_hops);
6607 const struct GNUNET_PeerIdentity *hops =
6608 (const struct GNUNET_PeerIdentity *) &dvb[1];
6609 const struct GNUNET_MessageHeader *inbox =
6610 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6615 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6616 sizeof (struct GNUNET_MessageHeader))
6618 GNUNET_break_op (0);
6619 return GNUNET_SYSERR;
6621 isize = ntohs (inbox->size);
6623 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6625 GNUNET_break_op (0);
6626 return GNUNET_SYSERR;
6628 itype = ntohs (inbox->type);
6629 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6630 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6632 GNUNET_break_op (0);
6633 return GNUNET_SYSERR;
6635 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6637 GNUNET_break_op (0);
6638 return GNUNET_SYSERR;
6645 * Create a DV Box message and queue it for transmission to
6648 * @param next_hop peer to receive the message next
6649 * @param total_hops how many hops did the message take so far
6650 * @param num_hops length of the @a hops array
6651 * @param origin origin of the message
6652 * @param hops next peer(s) to the destination, including destination
6653 * @param payload payload of the box
6654 * @param payload_size number of bytes in @a payload
6657 forward_dv_box (struct Neighbour *next_hop,
6658 uint16_t total_hops,
6660 const struct GNUNET_PeerIdentity *origin,
6661 const struct GNUNET_PeerIdentity *hops,
6662 const void *payload,
6663 uint16_t payload_size)
6665 struct TransportDVBoxMessage *dvb;
6667 dvb = create_dv_box (total_hops,
6669 &hops[num_hops - 1] /* == target */,
6670 num_hops - 1 /* do not count target twice */,
6674 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6680 * Communicator gave us a DV box. Process the request.
6682 * @param cls a `struct CommunicatorMessageContext` (must call
6683 * #finish_cmc_handling() when done)
6684 * @param dvb the message that was received
6687 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6689 struct CommunicatorMessageContext *cmc = cls;
6690 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6691 uint16_t num_hops = ntohs (dvb->num_hops);
6692 const struct GNUNET_PeerIdentity *hops =
6693 (const struct GNUNET_PeerIdentity *) &dvb[1];
6694 const struct GNUNET_MessageHeader *inbox =
6695 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6699 /* We're trying from the end of the hops array, as we may be
6700 able to find a shortcut unknown to the origin that way */
6701 for (int i = num_hops - 1; i >= 0; i--)
6703 struct Neighbour *n;
6705 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6707 GNUNET_break_op (0);
6708 finish_cmc_handling (cmc);
6711 n = lookup_neighbour (&hops[i]);
6715 ntohs (dvb->total_hops) + 1,
6716 num_hops - i - 1, /* number of hops left */
6718 &hops[i + 1], /* remaining hops */
6719 (const void *) &dvb[1],
6721 finish_cmc_handling (cmc);
6724 /* Woopsie, next hop not in neighbours, drop! */
6725 GNUNET_STATISTICS_update (GST_stats,
6726 "# DV Boxes dropped: next hop unknown",
6729 finish_cmc_handling (cmc);
6732 /* We are the target. Unbox and handle message. */
6733 cmc->im.sender = dvb->origin;
6734 cmc->total_hops = ntohs (dvb->total_hops);
6735 demultiplex_with_cmc (cmc, inbox);
6740 * Client notified us about transmission from a peer. Process the request.
6742 * @param cls a `struct TransportClient` which sent us the message
6743 * @param obm the send message that was sent
6744 * @return #GNUNET_YES if message is well-formed
6747 check_incoming_msg (void *cls,
6748 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6750 struct TransportClient *tc = cls;
6752 if (CT_COMMUNICATOR != tc->type)
6755 return GNUNET_SYSERR;
6757 GNUNET_MQ_check_boxed_message (im);
6763 * Communicator gave us a transport address validation challenge. Process the
6766 * @param cls a `struct CommunicatorMessageContext` (must call
6767 * #finish_cmc_handling() when done)
6768 * @param tvc the message that was received
6771 handle_validation_challenge (
6773 const struct TransportValidationChallengeMessage *tvc)
6775 struct CommunicatorMessageContext *cmc = cls;
6776 struct TransportValidationResponseMessage *tvr;
6778 if (cmc->total_hops > 0)
6780 /* DV routing is not allowed for validation challenges! */
6781 GNUNET_break_op (0);
6782 finish_cmc_handling (cmc);
6785 tvr = GNUNET_new (struct TransportValidationResponseMessage);
6787 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
6788 tvr->header.size = htons (sizeof (*tvr));
6789 tvr->challenge = tvc->challenge;
6790 tvr->origin_time = tvc->sender_time;
6791 tvr->validity_duration = cmc->im.expected_address_validity;
6793 /* create signature */
6794 struct TransportValidationPS tvp =
6795 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6796 .purpose.size = htonl (sizeof (tvp)),
6797 .validity_duration = tvr->validity_duration,
6798 .challenge = tvc->challenge};
6800 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6804 route_message (&cmc->im.sender,
6806 RMO_ANYTHING_GOES | RMO_REDUNDANT);
6807 finish_cmc_handling (cmc);
6812 * Closure for #check_known_challenge.
6814 struct CheckKnownChallengeContext
6817 * Set to the challenge we are looking for.
6819 const struct ChallengeNonceP *challenge;
6822 * Set to a matching validation state, if one was found.
6824 struct ValidationState *vs;
6829 * Test if the validation state in @a value matches the
6830 * challenge from @a cls.
6832 * @param cls a `struct CheckKnownChallengeContext`
6833 * @param pid unused (must match though)
6834 * @param value a `struct ValidationState`
6835 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6838 check_known_challenge (void *cls,
6839 const struct GNUNET_PeerIdentity *pid,
6842 struct CheckKnownChallengeContext *ckac = cls;
6843 struct ValidationState *vs = value;
6846 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
6854 * Function called when peerstore is done storing a
6855 * validated address.
6857 * @param cls a `struct ValidationState`
6858 * @param success #GNUNET_YES on success
6861 peerstore_store_validation_cb (void *cls, int success)
6863 struct ValidationState *vs = cls;
6866 if (GNUNET_YES == success)
6868 GNUNET_STATISTICS_update (GST_stats,
6869 "# Peerstore failed to store foreign address",
6876 * Task run periodically to validate some address based on #validation_heap.
6881 validation_start_cb (void *cls);
6885 * Set the time for next_challenge of @a vs to @a new_time.
6886 * Updates the heap and if necessary reschedules the job.
6888 * @param vs validation state to update
6889 * @param new_time new time for revalidation
6892 update_next_challenge_time (struct ValidationState *vs,
6893 struct GNUNET_TIME_Absolute new_time)
6895 struct GNUNET_TIME_Relative delta;
6897 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
6898 return; /* be lazy */
6899 vs->next_challenge = new_time;
6902 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
6904 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
6905 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
6906 (NULL != validation_task))
6908 if (NULL != validation_task)
6909 GNUNET_SCHEDULER_cancel (validation_task);
6910 /* randomize a bit */
6911 delta.rel_value_us =
6912 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6913 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
6914 new_time = GNUNET_TIME_absolute_add (new_time, delta);
6916 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
6921 * Find the queue matching @a pid and @a address.
6923 * @param pid peer the queue must go to
6924 * @param address address the queue must use
6925 * @return NULL if no such queue exists
6927 static struct Queue *
6928 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
6930 struct Neighbour *n;
6932 n = lookup_neighbour (pid);
6935 for (struct Queue *pos = n->queue_head; NULL != pos;
6936 pos = pos->next_neighbour)
6938 if (0 == strcmp (pos->address, address))
6946 * Communicator gave us a transport address validation response. Process the
6949 * @param cls a `struct CommunicatorMessageContext` (must call
6950 * #finish_cmc_handling() when done)
6951 * @param tvr the message that was received
6954 handle_validation_response (
6956 const struct TransportValidationResponseMessage *tvr)
6958 struct CommunicatorMessageContext *cmc = cls;
6959 struct ValidationState *vs;
6960 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
6962 struct GNUNET_TIME_Absolute origin_time;
6964 struct Neighbour *n;
6965 struct VirtualLink *vl;
6967 /* check this is one of our challenges */
6968 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6970 &check_known_challenge,
6972 if (NULL == (vs = ckac.vs))
6974 /* This can happen simply if we 'forgot' the challenge by now,
6975 i.e. because we received the validation response twice */
6976 GNUNET_STATISTICS_update (GST_stats,
6977 "# Validations dropped, challenge unknown",
6980 finish_cmc_handling (cmc);
6984 /* sanity check on origin time */
6985 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
6986 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
6987 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
6989 GNUNET_break_op (0);
6990 finish_cmc_handling (cmc);
6995 /* check signature */
6996 struct TransportValidationPS tvp =
6997 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6998 .purpose.size = htonl (sizeof (tvp)),
6999 .validity_duration = tvr->validity_duration,
7000 .challenge = tvr->challenge};
7004 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7007 &cmc->im.sender.public_key))
7009 GNUNET_break_op (0);
7010 finish_cmc_handling (cmc);
7015 /* validity is capped by our willingness to keep track of the
7016 validation entry and the maximum the other peer allows */
7017 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7018 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7019 tvr->validity_duration),
7020 MAX_ADDRESS_VALID_UNTIL));
7021 vs->validated_until =
7022 GNUNET_TIME_absolute_min (vs->valid_until,
7023 GNUNET_TIME_relative_to_absolute (
7024 ADDRESS_VALIDATION_LIFETIME));
7025 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7026 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7027 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7029 sizeof (vs->challenge));
7030 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7031 vs->validated_until,
7032 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7033 VALIDATION_RTT_BUFFER_FACTOR));
7034 vs->last_challenge_use =
7035 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7036 update_next_challenge_time (vs, vs->first_challenge_use);
7037 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7040 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7042 strlen (vs->address) + 1,
7044 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7045 &peerstore_store_validation_cb,
7047 finish_cmc_handling (cmc);
7049 /* Finally, we now possibly have a confirmed (!) working queue,
7050 update queue status (if queue still is around) */
7051 q = find_queue (&vs->pid, vs->address);
7054 GNUNET_STATISTICS_update (GST_stats,
7055 "# Queues lost at time of successful validation",
7060 q->validated_until = vs->validated_until;
7061 q->pd.aged_rtt = vs->validation_rtt;
7063 vl = GNUNET_CONTAINER_multipeermap_get (links, &vs->pid);
7066 /* Link was already up, remember n is also now available and we are done */
7070 vl = GNUNET_new (struct VirtualLink);
7071 vl->target = n->pid;
7073 vl->core_recv_window = RECV_WINDOW_SIZE;
7074 vl->visibility_task =
7075 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7076 GNUNET_break (GNUNET_YES ==
7077 GNUNET_CONTAINER_multipeermap_put (
7081 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7082 /* We lacked a confirmed connection to the target
7083 before, so tell CORE about it (finally!) */
7084 cores_send_connect_info (&n->pid);
7089 * Incoming meessage. Process the request.
7091 * @param im the send message that was received
7094 handle_incoming_msg (void *cls,
7095 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7097 struct TransportClient *tc = cls;
7098 struct CommunicatorMessageContext *cmc =
7099 GNUNET_new (struct CommunicatorMessageContext);
7103 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7108 * Given an inbound message @a msg from a communicator @a cmc,
7109 * demultiplex it based on the type calling the right handler.
7111 * @param cmc context for demultiplexing
7112 * @param msg message to demultiplex
7115 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7116 const struct GNUNET_MessageHeader *msg)
7118 struct GNUNET_MQ_MessageHandler handlers[] =
7119 {GNUNET_MQ_hd_var_size (fragment_box,
7120 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7121 struct TransportFragmentBoxMessage,
7123 GNUNET_MQ_hd_var_size (reliability_box,
7124 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7125 struct TransportReliabilityBoxMessage,
7127 GNUNET_MQ_hd_var_size (reliability_ack,
7128 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7129 struct TransportReliabilityAckMessage,
7131 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7132 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7133 struct TransportBackchannelEncapsulationMessage,
7135 GNUNET_MQ_hd_var_size (dv_learn,
7136 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7137 struct TransportDVLearnMessage,
7139 GNUNET_MQ_hd_var_size (dv_box,
7140 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7141 struct TransportDVBoxMessage,
7143 GNUNET_MQ_hd_fixed_size (
7144 validation_challenge,
7145 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7146 struct TransportValidationChallengeMessage,
7148 GNUNET_MQ_hd_fixed_size (
7149 validation_response,
7150 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7151 struct TransportValidationResponseMessage,
7153 GNUNET_MQ_handler_end ()};
7156 ret = GNUNET_MQ_handle_message (handlers, msg);
7157 if (GNUNET_SYSERR == ret)
7160 GNUNET_SERVICE_client_drop (cmc->tc->client);
7164 if (GNUNET_NO == ret)
7166 /* unencapsulated 'raw' message */
7167 handle_raw_message (&cmc, msg);
7173 * New queue became available. Check message.
7175 * @param cls the client
7176 * @param aqm the send message that was sent
7179 check_add_queue_message (void *cls,
7180 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7182 struct TransportClient *tc = cls;
7184 if (CT_COMMUNICATOR != tc->type)
7187 return GNUNET_SYSERR;
7189 GNUNET_MQ_check_zero_termination (aqm);
7195 * If necessary, generates the UUID for a @a pm
7197 * @param pm pending message to generate UUID for.
7200 set_pending_message_uuid (struct PendingMessage *pm)
7202 if (pm->msg_uuid_set)
7204 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7206 sizeof (pm->msg_uuid));
7207 pm->msg_uuid_set = GNUNET_YES;
7212 * Setup data structure waiting for acknowledgements.
7214 * @param queue queue the @a pm will be sent over
7215 * @param dvh path the message will take, may be NULL
7216 * @param pm the pending message for transmission
7217 * @return corresponding fresh pending acknowledgement
7219 static struct PendingAcknowledgement *
7220 prepare_pending_acknowledgement (struct Queue *queue,
7221 struct DistanceVectorHop *dvh,
7222 struct PendingMessage *pm)
7224 struct PendingAcknowledgement *pa;
7226 pa = GNUNET_new (struct PendingAcknowledgement);
7232 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7234 sizeof (pa->ack_uuid));
7235 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7237 &pa->ack_uuid.value,
7239 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7240 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7241 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7243 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7244 pa->transmission_time = GNUNET_TIME_absolute_get ();
7245 pa->message_size = pm->bytes_msg;
7251 * Fragment the given @a pm to the given @a mtu. Adds
7252 * additional fragments to the neighbour as well. If the
7253 * @a mtu is too small, generates and error for the @a pm
7256 * @param queue which queue to fragment for
7257 * @param dvh path the message will take, or NULL
7258 * @param pm pending message to fragment for transmission
7259 * @return new message to transmit
7261 static struct PendingMessage *
7262 fragment_message (struct Queue *queue,
7263 struct DistanceVectorHop *dvh,
7264 struct PendingMessage *pm)
7266 struct PendingAcknowledgement *pa;
7267 struct PendingMessage *ff;
7270 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7271 mtu = (0 == queue->mtu)
7272 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7274 set_pending_message_uuid (pm);
7276 /* This invariant is established in #handle_add_queue_message() */
7277 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7279 /* select fragment for transmission, descending the tree if it has
7280 been expanded until we are at a leaf or at a fragment that is small
7284 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7285 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7287 ff = ff->head_frag; /* descent into fragmented fragments */
7290 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7292 /* Did not yet calculate all fragments, calculate next fragment */
7293 struct PendingMessage *frag;
7294 struct TransportFragmentBoxMessage tfb;
7302 orig = (const char *) &ff[1];
7303 msize = ff->bytes_msg;
7306 const struct TransportFragmentBoxMessage *tfbo;
7308 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7309 orig += sizeof (struct TransportFragmentBoxMessage);
7310 msize -= sizeof (struct TransportFragmentBoxMessage);
7311 xoff = ntohs (tfbo->frag_off);
7313 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7314 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7316 GNUNET_malloc (sizeof (struct PendingMessage) +
7317 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7318 frag->target = pm->target;
7319 frag->frag_parent = ff;
7320 frag->timeout = pm->timeout;
7321 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7322 frag->pmt = PMT_FRAGMENT_BOX;
7323 msg = (char *) &frag[1];
7324 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7326 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7327 tfb.ack_uuid = pa->ack_uuid;
7328 tfb.msg_uuid = pm->msg_uuid;
7329 tfb.frag_off = htons (ff->frag_off + xoff);
7330 tfb.msg_size = htons (pm->bytes_msg);
7331 memcpy (msg, &tfb, sizeof (tfb));
7332 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7333 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7334 ff->frag_off += fragsize;
7338 /* Move head to the tail and return it */
7339 GNUNET_CONTAINER_MDLL_remove (frag,
7340 ff->frag_parent->head_frag,
7341 ff->frag_parent->tail_frag,
7343 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7344 ff->frag_parent->head_frag,
7345 ff->frag_parent->tail_frag,
7352 * Reliability-box the given @a pm. On error (can there be any), NULL
7353 * may be returned, otherwise the "replacement" for @a pm (which
7354 * should then be added to the respective neighbour's queue instead of
7355 * @a pm). If the @a pm is already fragmented or reliability boxed,
7356 * or itself an ACK, this function simply returns @a pm.
7358 * @param queue which queue to prepare transmission for
7359 * @param dvh path the message will take, or NULL
7360 * @param pm pending message to box for transmission over unreliabile queue
7361 * @return new message to transmit
7363 static struct PendingMessage *
7364 reliability_box_message (struct Queue *queue,
7365 struct DistanceVectorHop *dvh,
7366 struct PendingMessage *pm)
7368 struct TransportReliabilityBoxMessage rbox;
7369 struct PendingAcknowledgement *pa;
7370 struct PendingMessage *bpm;
7373 if (PMT_CORE != pm->pmt)
7374 return pm; /* already fragmented or reliability boxed, or control message:
7376 if (NULL != pm->bpm)
7377 return pm->bpm; /* already computed earlier: do nothing */
7378 GNUNET_assert (NULL == pm->head_frag);
7379 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7383 client_send_response (pm, GNUNET_NO, 0);
7386 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7388 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7390 bpm->target = pm->target;
7391 bpm->frag_parent = pm;
7392 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7393 bpm->timeout = pm->timeout;
7394 bpm->pmt = PMT_RELIABILITY_BOX;
7395 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7396 set_pending_message_uuid (bpm);
7397 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7398 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7399 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7401 rbox.ack_uuid = pa->ack_uuid;
7402 msg = (char *) &bpm[1];
7403 memcpy (msg, &rbox, sizeof (rbox));
7404 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7411 * Change the value of the `next_attempt` field of @a pm
7412 * to @a next_attempt and re-order @a pm in the transmission
7413 * list as required by the new timestmap.
7415 * @param pm a pending message to update
7416 * @param next_attempt timestamp to use
7419 update_pm_next_attempt (struct PendingMessage *pm,
7420 struct GNUNET_TIME_Absolute next_attempt)
7422 struct Neighbour *neighbour = pm->target;
7424 pm->next_attempt = next_attempt;
7425 if (NULL == pm->frag_parent)
7427 struct PendingMessage *pos;
7429 /* re-insert sort in neighbour list */
7430 GNUNET_CONTAINER_MDLL_remove (neighbour,
7431 neighbour->pending_msg_head,
7432 neighbour->pending_msg_tail,
7434 pos = neighbour->pending_msg_tail;
7435 while ((NULL != pos) &&
7436 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7437 pos = pos->prev_neighbour;
7438 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7439 neighbour->pending_msg_head,
7440 neighbour->pending_msg_tail,
7446 /* re-insert sort in fragment list */
7447 struct PendingMessage *fp = pm->frag_parent;
7448 struct PendingMessage *pos;
7450 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7451 pos = fp->tail_frag;
7452 while ((NULL != pos) &&
7453 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7454 pos = pos->prev_frag;
7455 GNUNET_CONTAINER_MDLL_insert_after (frag,
7465 * We believe we are ready to transmit a message on a queue.
7466 * Gives the message to the
7467 * communicator for transmission (updating the tracker, and re-scheduling
7468 * itself if applicable).
7470 * @param cls the `struct Queue` to process transmissions for
7473 transmit_on_queue (void *cls)
7475 struct Queue *queue = cls;
7476 struct Neighbour *n = queue->neighbour;
7477 struct PendingMessage *pm;
7478 struct PendingMessage *s;
7481 queue->transmit_task = NULL;
7482 if (NULL == (pm = n->pending_msg_head))
7484 /* no message pending, nothing to do here! */
7489 /* message still pending with communciator!
7490 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7493 schedule_transmit_on_queue (queue, GNUNET_YES);
7494 if (NULL != queue->transmit_task)
7495 return; /* do it later */
7497 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7498 overhead += sizeof (struct TransportReliabilityBoxMessage);
7500 if ( ( (0 != queue->mtu) &&
7501 (pm->bytes_msg + overhead > queue->mtu) ) ||
7502 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7503 (NULL != pm->head_frag /* fragments already exist, should
7504 respect that even if MTU is 0 for
7506 s = fragment_message (queue, pm->dvh, s);
7509 /* Fragmentation failed, try next message... */
7510 schedule_transmit_on_queue (queue, GNUNET_NO);
7513 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7514 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7515 s = reliability_box_message (queue, pm->dvh, s);
7518 /* Reliability boxing failed, try next message... */
7519 schedule_transmit_on_queue (queue, GNUNET_NO);
7523 /* Pass 's' for transission to the communicator */
7524 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7525 // FIXME: do something similar to the logic below
7526 // in defragmentation / reliability ACK handling!
7528 /* Check if this transmission somehow conclusively finished handing 'pm'
7529 even without any explicit ACKs */
7530 if ((PMT_CORE == s->pmt) &&
7531 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7533 /* Full message sent, and over reliabile channel */
7534 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
7536 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7537 queue->tc->details.communicator.cc) &&
7538 (PMT_FRAGMENT_BOX == s->pmt))
7540 struct PendingMessage *pos;
7542 /* Fragment sent over reliabile channel */
7543 free_fragment_tree (s);
7544 pos = s->frag_parent;
7545 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7547 /* check if subtree is done */
7548 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7552 pos = s->frag_parent;
7553 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7557 /* Was this the last applicable fragmment? */
7558 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7559 client_send_response (
7562 pm->bytes_msg /* FIXME: calculate and add overheads! */);
7564 else if (PMT_CORE != pm->pmt)
7566 /* This was an acknowledgement of some type, always free */
7567 free_pending_message (pm);
7571 /* Message not finished, waiting for acknowledgement.
7572 Update time by which we might retransmit 's' based on queue
7573 characteristics (i.e. RTT); it takes one RTT for the message to
7574 arrive and the ACK to come back in the best case; but the other
7575 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7576 retransmitting. Note that in the future this heuristic should
7577 likely be improved further (measure RTT stability, consider
7578 message urgency and size when delaying ACKs, etc.) */
7579 update_pm_next_attempt (s,
7580 GNUNET_TIME_relative_to_absolute (
7581 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7585 /* finally, re-schedule queue transmission task itself */
7586 schedule_transmit_on_queue (queue, GNUNET_NO);
7591 * Queue to a peer went down. Process the request.
7593 * @param cls the client
7594 * @param dqm the send message that was sent
7597 handle_del_queue_message (void *cls,
7598 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7600 struct TransportClient *tc = cls;
7602 if (CT_COMMUNICATOR != tc->type)
7605 GNUNET_SERVICE_client_drop (tc->client);
7608 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7609 queue = queue->next_client)
7611 struct Neighbour *neighbour = queue->neighbour;
7613 if ((dqm->qid != queue->qid) ||
7614 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7617 GNUNET_SERVICE_client_continue (tc->client);
7621 GNUNET_SERVICE_client_drop (tc->client);
7626 * Message was transmitted. Process the request.
7628 * @param cls the client
7629 * @param sma the send message that was sent
7632 handle_send_message_ack (void *cls,
7633 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7635 struct TransportClient *tc = cls;
7636 struct QueueEntry *qe;
7637 struct PendingMessage *pm;
7639 if (CT_COMMUNICATOR != tc->type)
7642 GNUNET_SERVICE_client_drop (tc->client);
7646 /* find our queue entry matching the ACK */
7648 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7649 queue = queue->next_client)
7651 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7653 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7656 if (qep->mid != sma->mid)
7665 /* this should never happen */
7667 GNUNET_SERVICE_client_drop (tc->client);
7670 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7671 qe->queue->queue_tail,
7673 qe->queue->queue_length--;
7674 tc->details.communicator.total_queue_length--;
7675 GNUNET_SERVICE_client_continue (tc->client);
7677 /* if applicable, resume transmissions that waited on ACK */
7678 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7679 tc->details.communicator.total_queue_length)
7681 /* Communicator dropped below threshold, resume all queues
7682 incident with this client! */
7683 GNUNET_STATISTICS_update (
7685 "# Transmission throttled due to communicator queue limit",
7688 for (struct Queue *queue = tc->details.communicator.queue_head;
7690 queue = queue->next_client)
7691 schedule_transmit_on_queue (queue, GNUNET_NO);
7693 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7695 /* queue dropped below threshold; only resume this one queue */
7696 GNUNET_STATISTICS_update (GST_stats,
7697 "# Transmission throttled due to queue queue limit",
7700 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7703 if (NULL != (pm = qe->pm))
7705 struct Neighbour *n;
7707 GNUNET_assert (qe == pm->qe);
7709 /* If waiting for this communicator may have blocked transmission
7710 of pm on other queues for this neighbour, force schedule
7711 transmit on queue for queues of the neighbour */
7713 if (n->pending_msg_head == pm)
7715 for (struct Queue *queue = n->queue_head; NULL != queue;
7716 queue = queue->next_neighbour)
7717 schedule_transmit_on_queue (queue, GNUNET_NO);
7719 if (GNUNET_OK != ntohl (sma->status))
7722 GNUNET_ERROR_TYPE_INFO,
7723 "Queue failed in transmission, will try retransmission immediately\n");
7724 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7732 * Iterator telling new MONITOR client about all existing
7735 * @param cls the new `struct TransportClient`
7736 * @param pid a connected peer
7737 * @param value the `struct Neighbour` with more information
7738 * @return #GNUNET_OK (continue to iterate)
7741 notify_client_queues (void *cls,
7742 const struct GNUNET_PeerIdentity *pid,
7745 struct TransportClient *tc = cls;
7746 struct Neighbour *neighbour = value;
7748 GNUNET_assert (CT_MONITOR == tc->type);
7749 for (struct Queue *q = neighbour->queue_head; NULL != q;
7750 q = q->next_neighbour)
7752 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7754 .num_msg_pending = q->num_msg_pending,
7755 .num_bytes_pending = q->num_bytes_pending};
7757 notify_monitor (tc, pid, q->address, q->nt, &me);
7764 * Initialize a monitor client.
7766 * @param cls the client
7767 * @param start the start message that was sent
7770 handle_monitor_start (void *cls,
7771 const struct GNUNET_TRANSPORT_MonitorStart *start)
7773 struct TransportClient *tc = cls;
7775 if (CT_NONE != tc->type)
7778 GNUNET_SERVICE_client_drop (tc->client);
7781 tc->type = CT_MONITOR;
7782 tc->details.monitor.peer = start->peer;
7783 tc->details.monitor.one_shot = ntohl (start->one_shot);
7784 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
7785 GNUNET_SERVICE_client_mark_monitor (tc->client);
7786 GNUNET_SERVICE_client_continue (tc->client);
7791 * Find transport client providing communication service
7792 * for the protocol @a prefix.
7794 * @param prefix communicator name
7795 * @return NULL if no such transport client is available
7797 static struct TransportClient *
7798 lookup_communicator (const char *prefix)
7800 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7802 if (CT_COMMUNICATOR != tc->type)
7804 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
7808 GNUNET_ERROR_TYPE_WARNING,
7809 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
7816 * Signature of a function called with a communicator @a address of a peer
7817 * @a pid that an application wants us to connect to.
7819 * @param pid target peer
7820 * @param address the address to try
7823 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
7825 static uint32_t idgen;
7826 struct TransportClient *tc;
7828 struct GNUNET_TRANSPORT_CreateQueue *cqm;
7829 struct GNUNET_MQ_Envelope *env;
7832 prefix = GNUNET_HELLO_address_to_prefix (address);
7835 GNUNET_break (0); /* We got an invalid address!? */
7838 tc = lookup_communicator (prefix);
7841 GNUNET_STATISTICS_update (GST_stats,
7842 "# Suggestions ignored due to missing communicator",
7847 /* forward suggestion for queue creation to communicator */
7848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7849 "Request #%u for `%s' communicator to create queue to `%s'\n",
7850 (unsigned int) idgen,
7853 alen = strlen (address) + 1;
7855 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
7856 cqm->request_id = htonl (idgen++);
7857 cqm->receiver = *pid;
7858 memcpy (&cqm[1], address, alen);
7859 GNUNET_MQ_send (tc->mq, env);
7864 * The queue @a q (which matches the peer and address in @a vs) is
7865 * ready for queueing. We should now queue the validation request.
7867 * @param q queue to send on
7868 * @param vs state to derive validation challenge from
7871 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
7873 struct TransportValidationChallengeMessage tvc;
7875 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
7877 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
7878 tvc.header.size = htons (sizeof (tvc));
7879 tvc.reserved = htonl (0);
7880 tvc.challenge = vs->challenge;
7881 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
7882 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7887 * Task run periodically to validate some address based on #validation_heap.
7892 validation_start_cb (void *cls)
7894 struct ValidationState *vs;
7898 validation_task = NULL;
7899 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7900 /* drop validations past their expiration */
7903 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7905 free_validation_state (vs);
7906 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7909 return; /* woopsie, no more addresses known, should only
7910 happen if we're really a lonely peer */
7911 q = find_queue (&vs->pid, vs->address);
7914 vs->awaiting_queue = GNUNET_YES;
7915 suggest_to_connect (&vs->pid, vs->address);
7918 validation_transmit_on_queue (q, vs);
7919 /* Finally, reschedule next attempt */
7920 vs->challenge_backoff =
7921 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
7922 MAX_VALIDATION_CHALLENGE_FREQ);
7923 update_next_challenge_time (vs,
7924 GNUNET_TIME_relative_to_absolute (
7925 vs->challenge_backoff));
7930 * Closure for #check_connection_quality.
7932 struct QueueQualityContext
7935 * Set to the @e k'th queue encountered.
7940 * Set to the number of quality queues encountered.
7942 unsigned int quality_count;
7945 * Set to the total number of queues encountered.
7947 unsigned int num_queues;
7950 * Decremented for each queue, for selection of the
7951 * k-th queue in @e q.
7958 * Check whether any queue to the given neighbour is
7959 * of a good "quality" and if so, increment the counter.
7960 * Also counts the total number of queues, and returns
7961 * the k-th queue found.
7963 * @param cls a `struct QueueQualityContext *` with counters
7964 * @param pid peer this is about
7965 * @param value a `struct Neighbour`
7966 * @return #GNUNET_OK (continue to iterate)
7969 check_connection_quality (void *cls,
7970 const struct GNUNET_PeerIdentity *pid,
7973 struct QueueQualityContext *ctx = cls;
7974 struct Neighbour *n = value;
7979 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7984 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
7985 statistics and consider those as well here? */
7986 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
7987 do_inc = GNUNET_YES;
7989 if (GNUNET_YES == do_inc)
7990 ctx->quality_count++;
7996 * Task run when we CONSIDER initiating a DV learn
7997 * process. We first check that sending out a message is
7998 * even possible (queues exist), then that it is desirable
7999 * (if not, reschedule the task for later), and finally
8000 * we may then begin the job. If there are too many
8001 * entries in the #dvlearn_map, we purge the oldest entry
8007 start_dv_learn (void *cls)
8009 struct LearnLaunchEntry *lle;
8010 struct QueueQualityContext qqc;
8011 struct TransportDVLearnMessage dvl;
8014 dvlearn_task = NULL;
8015 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8016 return; /* lost all connectivity, cannot do learning */
8017 qqc.quality_count = 0;
8019 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8020 &check_connection_quality,
8022 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8024 struct GNUNET_TIME_Relative delay;
8025 unsigned int factor;
8027 /* scale our retries by how far we are above the threshold */
8028 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8029 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8030 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8033 /* remove old entries in #dvlearn_map if it has grown too big */
8034 while (MAX_DV_LEARN_PENDING >=
8035 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8038 GNUNET_assert (GNUNET_YES ==
8039 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8040 &lle->challenge.value,
8042 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8045 /* setup data structure for learning */
8046 lle = GNUNET_new (struct LearnLaunchEntry);
8047 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8049 sizeof (lle->challenge));
8050 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8051 GNUNET_break (GNUNET_YES ==
8052 GNUNET_CONTAINER_multishortmap_put (
8054 &lle->challenge.value,
8056 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8057 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8058 dvl.header.size = htons (sizeof (dvl));
8059 dvl.num_hops = htons (0);
8060 dvl.bidirectional = htons (0);
8061 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8062 dvl.monotonic_time =
8063 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8065 struct DvInitPS dvip = {.purpose.purpose = htonl (
8066 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8067 .purpose.size = htonl (sizeof (dvip)),
8068 .monotonic_time = dvl.monotonic_time,
8069 .challenge = lle->challenge};
8071 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8075 dvl.initiator = GST_my_identity;
8076 dvl.challenge = lle->challenge;
8078 qqc.quality_count = 0;
8079 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8082 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8083 &check_connection_quality,
8085 GNUNET_assert (NULL != qqc.q);
8087 /* Do this as close to transmission time as possible! */
8088 lle->launch_time = GNUNET_TIME_absolute_get ();
8090 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8091 /* reschedule this job, randomizing the time it runs (but no
8093 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8094 DV_LEARN_BASE_FREQUENCY),
8101 * A new queue has been created, check if any address validation
8102 * requests have been waiting for it.
8104 * @param cls a `struct Queue`
8105 * @param pid peer concerned (unused)
8106 * @param value a `struct ValidationState`
8107 * @return #GNUNET_NO if a match was found and we can stop looking
8110 check_validation_request_pending (void *cls,
8111 const struct GNUNET_PeerIdentity *pid,
8114 struct Queue *q = cls;
8115 struct ValidationState *vs = value;
8118 if ((GNUNET_YES == vs->awaiting_queue) &&
8119 (0 == strcmp (vs->address, q->address)))
8121 vs->awaiting_queue = GNUNET_NO;
8122 validation_transmit_on_queue (q, vs);
8130 * Function called with the monotonic time of a DV initiator
8131 * by PEERSTORE. Updates the time.
8133 * @param cls a `struct Neighbour`
8134 * @param record the information found, NULL for the last call
8135 * @param emsg error message
8138 neighbour_dv_monotime_cb (void *cls,
8139 const struct GNUNET_PEERSTORE_Record *record,
8142 struct Neighbour *n = cls;
8143 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8148 /* we're done with #neighbour_dv_monotime_cb() invocations,
8149 continue normal processing */
8151 n->dv_monotime_available = GNUNET_YES;
8154 if (sizeof (*mtbe) != record->value_size)
8159 mtbe = record->value;
8160 n->last_dv_learn_monotime =
8161 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8162 GNUNET_TIME_absolute_ntoh (*mtbe));
8167 * New queue became available. Process the request.
8169 * @param cls the client
8170 * @param aqm the send message that was sent
8173 handle_add_queue_message (void *cls,
8174 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8176 struct TransportClient *tc = cls;
8177 struct Queue *queue;
8178 struct Neighbour *neighbour;
8182 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8184 /* MTU so small as to be useless for transmissions,
8185 required for #fragment_message()! */
8186 GNUNET_break_op (0);
8187 GNUNET_SERVICE_client_drop (tc->client);
8190 neighbour = lookup_neighbour (&aqm->receiver);
8191 if (NULL == neighbour)
8193 neighbour = GNUNET_new (struct Neighbour);
8194 neighbour->pid = aqm->receiver;
8195 GNUNET_assert (GNUNET_OK ==
8196 GNUNET_CONTAINER_multipeermap_put (
8200 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8202 GNUNET_PEERSTORE_iterate (peerstore,
8205 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8206 &neighbour_dv_monotime_cb,
8209 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8210 addr = (const char *) &aqm[1];
8212 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8214 queue->address = (const char *) &queue[1];
8215 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8216 queue->qid = aqm->qid;
8217 queue->mtu = ntohl (aqm->mtu);
8218 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8219 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8220 queue->neighbour = neighbour;
8221 memcpy (&queue[1], addr, addr_len);
8222 /* notify monitors about new queue */
8224 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8226 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8228 GNUNET_CONTAINER_MDLL_insert (neighbour,
8229 neighbour->queue_head,
8230 neighbour->queue_tail,
8232 GNUNET_CONTAINER_MDLL_insert (client,
8233 tc->details.communicator.queue_head,
8234 tc->details.communicator.queue_tail,
8236 /* check if valdiations are waiting for the queue */
8238 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8240 &check_validation_request_pending,
8242 /* might be our first queue, try launching DV learning */
8243 if (NULL == dvlearn_task)
8244 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8245 GNUNET_SERVICE_client_continue (tc->client);
8250 * Communicator tells us that our request to create a queue "worked", that
8251 * is setting up the queue is now in process.
8253 * @param cls the `struct TransportClient`
8254 * @param cqr confirmation message
8257 handle_queue_create_ok (void *cls,
8258 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8260 struct TransportClient *tc = cls;
8262 if (CT_COMMUNICATOR != tc->type)
8265 GNUNET_SERVICE_client_drop (tc->client);
8268 GNUNET_STATISTICS_update (GST_stats,
8269 "# Suggestions succeeded at communicator",
8272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8273 "Request #%u for communicator to create queue succeeded\n",
8274 (unsigned int) ntohs (cqr->request_id));
8275 GNUNET_SERVICE_client_continue (tc->client);
8280 * Communicator tells us that our request to create a queue failed. This
8281 * usually indicates that the provided address is simply invalid or that the
8282 * communicator's resources are exhausted.
8284 * @param cls the `struct TransportClient`
8285 * @param cqr failure message
8288 handle_queue_create_fail (
8290 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8292 struct TransportClient *tc = cls;
8294 if (CT_COMMUNICATOR != tc->type)
8297 GNUNET_SERVICE_client_drop (tc->client);
8300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8301 "Request #%u for communicator to create queue failed\n",
8302 (unsigned int) ntohs (cqr->request_id));
8303 GNUNET_STATISTICS_update (GST_stats,
8304 "# Suggestions failed in queue creation at communicator",
8307 GNUNET_SERVICE_client_continue (tc->client);
8312 * We have received a `struct ExpressPreferenceMessage` from an application
8315 * @param cls handle to the client
8316 * @param msg the start message
8319 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8321 struct TransportClient *tc = cls;
8322 struct PeerRequest *pr;
8324 if (CT_APPLICATION != tc->type)
8327 GNUNET_SERVICE_client_drop (tc->client);
8330 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8335 GNUNET_SERVICE_client_drop (tc->client);
8338 (void) stop_peer_request (tc, &pr->pid, pr);
8339 GNUNET_SERVICE_client_continue (tc->client);
8344 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8345 * messages. We do nothing here, real verification is done later.
8347 * @param cls a `struct TransportClient *`
8348 * @param msg message to verify
8349 * @return #GNUNET_OK
8352 check_address_consider_verify (
8354 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8363 * Closure for #check_known_address.
8365 struct CheckKnownAddressContext
8368 * Set to the address we are looking for.
8370 const char *address;
8373 * Set to a matching validation state, if one was found.
8375 struct ValidationState *vs;
8380 * Test if the validation state in @a value matches the
8381 * address from @a cls.
8383 * @param cls a `struct CheckKnownAddressContext`
8384 * @param pid unused (must match though)
8385 * @param value a `struct ValidationState`
8386 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8389 check_known_address (void *cls,
8390 const struct GNUNET_PeerIdentity *pid,
8393 struct CheckKnownAddressContext *ckac = cls;
8394 struct ValidationState *vs = value;
8397 if (0 != strcmp (vs->address, ckac->address))
8405 * Start address validation.
8407 * @param pid peer the @a address is for
8408 * @param address an address to reach @a pid (presumably)
8409 * @param expiration when did @a pid claim @a address will become invalid
8412 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8413 const char *address,
8414 struct GNUNET_TIME_Absolute expiration)
8416 struct GNUNET_TIME_Absolute now;
8417 struct ValidationState *vs;
8418 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8420 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
8421 return; /* expired */
8422 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8424 &check_known_address,
8426 if (NULL != (vs = ckac.vs))
8428 /* if 'vs' is not currently valid, we need to speed up retrying the
8430 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8432 /* reduce backoff as we got a fresh advertisement */
8433 vs->challenge_backoff =
8434 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8435 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8437 update_next_challenge_time (vs,
8438 GNUNET_TIME_relative_to_absolute (
8439 vs->challenge_backoff));
8443 now = GNUNET_TIME_absolute_get ();
8444 vs = GNUNET_new (struct ValidationState);
8446 vs->valid_until = expiration;
8447 vs->first_challenge_use = now;
8448 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8449 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8451 sizeof (vs->challenge));
8452 vs->address = GNUNET_strdup (address);
8453 GNUNET_assert (GNUNET_YES ==
8454 GNUNET_CONTAINER_multipeermap_put (
8458 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8459 update_next_challenge_time (vs, now);
8464 * Function called by PEERSTORE for each matching record.
8466 * @param cls closure
8467 * @param record peerstore record information
8468 * @param emsg error message, or NULL if no errors
8471 handle_hello (void *cls,
8472 const struct GNUNET_PEERSTORE_Record *record,
8475 struct PeerRequest *pr = cls;
8480 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8481 "Got failure from PEERSTORE: %s\n",
8485 val = record->value;
8486 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8491 start_address_validation (&pr->pid,
8492 (const char *) record->value,
8498 * We have received a `struct ExpressPreferenceMessage` from an application
8501 * @param cls handle to the client
8502 * @param msg the start message
8505 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8507 struct TransportClient *tc = cls;
8508 struct PeerRequest *pr;
8510 if (CT_NONE == tc->type)
8512 tc->type = CT_APPLICATION;
8513 tc->details.application.requests =
8514 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8516 if (CT_APPLICATION != tc->type)
8519 GNUNET_SERVICE_client_drop (tc->client);
8522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8523 "Client suggested we talk to %s with preference %d at rate %u\n",
8524 GNUNET_i2s (&msg->peer),
8525 (int) ntohl (msg->pk),
8526 (int) ntohl (msg->bw.value__));
8527 pr = GNUNET_new (struct PeerRequest);
8529 pr->pid = msg->peer;
8531 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
8532 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8533 tc->details.application.requests,
8536 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8540 GNUNET_SERVICE_client_drop (tc->client);
8543 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8546 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8549 GNUNET_SERVICE_client_continue (tc->client);
8554 * Given another peers address, consider checking it for validity
8555 * and then adding it to the Peerstore.
8557 * @param cls a `struct TransportClient`
8558 * @param hdr message containing the raw address data and
8559 * signature in the body, see #GNUNET_HELLO_extract_address()
8562 handle_address_consider_verify (
8564 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8566 struct TransportClient *tc = cls;
8568 enum GNUNET_NetworkType nt;
8569 struct GNUNET_TIME_Absolute expiration;
8572 // OPTIMIZE-FIXME: checking that we know this address already should
8573 // be done BEFORE checking the signature => HELLO API change!
8574 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8577 GNUNET_HELLO_extract_address (&hdr[1],
8578 ntohs (hdr->header.size) - sizeof (*hdr),
8582 if (NULL == address)
8584 GNUNET_break_op (0);
8587 start_address_validation (&hdr->peer, address, expiration);
8588 GNUNET_free (address);
8589 GNUNET_SERVICE_client_continue (tc->client);
8594 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8597 * @param cls a `struct TransportClient *`
8598 * @param m message to verify
8599 * @return #GNUNET_OK on success
8602 check_request_hello_validation (void *cls,
8603 const struct RequestHelloValidationMessage *m)
8606 GNUNET_MQ_check_zero_termination (m);
8612 * A client encountered an address of another peer. Consider validating it,
8613 * and if validation succeeds, persist it to PEERSTORE.
8615 * @param cls a `struct TransportClient *`
8616 * @param m message to verify
8619 handle_request_hello_validation (void *cls,
8620 const struct RequestHelloValidationMessage *m)
8622 struct TransportClient *tc = cls;
8624 start_address_validation (&m->peer,
8625 (const char *) &m[1],
8626 GNUNET_TIME_absolute_ntoh (m->expiration));
8627 GNUNET_SERVICE_client_continue (tc->client);
8632 * Free neighbour entry.
8636 * @param value a `struct Neighbour`
8637 * @return #GNUNET_OK (always)
8640 free_neighbour_cb (void *cls,
8641 const struct GNUNET_PeerIdentity *pid,
8644 struct Neighbour *neighbour = value;
8648 GNUNET_break (0); // should this ever happen?
8649 free_neighbour (neighbour);
8656 * Free DV route entry.
8660 * @param value a `struct DistanceVector`
8661 * @return #GNUNET_OK (always)
8664 free_dv_routes_cb (void *cls,
8665 const struct GNUNET_PeerIdentity *pid,
8668 struct DistanceVector *dv = value;
8679 * Free ephemeral entry.
8683 * @param value a `struct EphemeralCacheEntry`
8684 * @return #GNUNET_OK (always)
8687 free_ephemeral_cb (void *cls,
8688 const struct GNUNET_PeerIdentity *pid,
8691 struct EphemeralCacheEntry *ece = value;
8695 free_ephemeral (ece);
8701 * Free validation state.
8705 * @param value a `struct ValidationState`
8706 * @return #GNUNET_OK (always)
8709 free_validation_state_cb (void *cls,
8710 const struct GNUNET_PeerIdentity *pid,
8713 struct ValidationState *vs = value;
8717 free_validation_state (vs);
8723 * Free pending acknowledgement.
8727 * @param value a `struct PendingAcknowledgement`
8728 * @return #GNUNET_OK (always)
8731 free_pending_ack_cb (void *cls,
8732 const struct GNUNET_ShortHashCode *key,
8735 struct PendingAcknowledgement *pa = value;
8739 free_pending_acknowledgement (pa);
8745 * Free acknowledgement cummulator.
8749 * @param value a `struct AcknowledgementCummulator`
8750 * @return #GNUNET_OK (always)
8753 free_ack_cummulator_cb (void *cls,
8754 const struct GNUNET_PeerIdentity *pid,
8757 struct AcknowledgementCummulator *ac = value;
8767 * Function called when the service shuts down. Unloads our plugins
8768 * and cancels pending validations.
8770 * @param cls closure, unused
8773 do_shutdown (void *cls)
8775 struct LearnLaunchEntry *lle;
8778 if (NULL != ephemeral_task)
8780 GNUNET_SCHEDULER_cancel (ephemeral_task);
8781 ephemeral_task = NULL;
8783 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
8784 if (NULL != peerstore)
8786 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
8789 if (NULL != GST_stats)
8791 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
8794 if (NULL != GST_my_private_key)
8796 GNUNET_free (GST_my_private_key);
8797 GST_my_private_key = NULL;
8799 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
8800 &free_ack_cummulator_cb,
8802 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
8803 ack_cummulators = NULL;
8804 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
8805 &free_pending_ack_cb,
8807 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
8808 pending_acks = NULL;
8809 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
8810 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
8812 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
8813 GNUNET_CONTAINER_multipeermap_destroy (links);
8815 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
8816 &free_backtalker_cb,
8818 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
8820 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
8821 &free_validation_state_cb,
8823 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
8824 validation_map = NULL;
8825 while (NULL != (lle = lle_head))
8827 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8830 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
8832 GNUNET_CONTAINER_heap_destroy (validation_heap);
8833 validation_heap = NULL;
8834 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
8835 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
8837 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
8840 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
8841 ephemeral_map = NULL;
8842 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
8843 ephemeral_heap = NULL;
8848 * Initiate transport service.
8850 * @param cls closure
8851 * @param c configuration to use
8852 * @param service the initialized service
8856 const struct GNUNET_CONFIGURATION_Handle *c,
8857 struct GNUNET_SERVICE_Handle *service)
8863 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8864 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
8865 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
8866 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8867 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
8868 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8869 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
8871 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8872 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
8874 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8876 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8877 GST_my_private_key =
8878 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
8879 if (NULL == GST_my_private_key)
8882 GNUNET_ERROR_TYPE_ERROR,
8884 "Transport service is lacking key configuration settings. Exiting.\n"));
8885 GNUNET_SCHEDULER_shutdown ();
8888 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
8889 &GST_my_identity.public_key);
8890 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8891 "My identity is `%s'\n",
8892 GNUNET_i2s_full (&GST_my_identity));
8893 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
8894 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
8895 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
8896 if (NULL == peerstore)
8899 GNUNET_SCHEDULER_shutdown ();
8906 * Define "main" method using service macro.
8908 GNUNET_SERVICE_MAIN (
8910 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
8913 &client_disconnect_cb,
8915 /* communication with applications */
8916 GNUNET_MQ_hd_fixed_size (suggest,
8917 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
8918 struct ExpressPreferenceMessage,
8920 GNUNET_MQ_hd_fixed_size (suggest_cancel,
8921 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
8922 struct ExpressPreferenceMessage,
8924 GNUNET_MQ_hd_var_size (request_hello_validation,
8925 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
8926 struct RequestHelloValidationMessage,
8928 /* communication with core */
8929 GNUNET_MQ_hd_fixed_size (client_start,
8930 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
8931 struct StartMessage,
8933 GNUNET_MQ_hd_var_size (client_send,
8934 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
8935 struct OutboundMessage,
8937 GNUNET_MQ_hd_fixed_size (client_recv_ok,
8938 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
8939 struct RecvOkMessage,
8941 /* communication with communicators */
8942 GNUNET_MQ_hd_var_size (communicator_available,
8943 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
8944 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
8946 GNUNET_MQ_hd_var_size (communicator_backchannel,
8947 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
8948 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
8950 GNUNET_MQ_hd_var_size (add_address,
8951 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
8952 struct GNUNET_TRANSPORT_AddAddressMessage,
8954 GNUNET_MQ_hd_fixed_size (del_address,
8955 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
8956 struct GNUNET_TRANSPORT_DelAddressMessage,
8958 GNUNET_MQ_hd_var_size (incoming_msg,
8959 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
8960 struct GNUNET_TRANSPORT_IncomingMessage,
8962 GNUNET_MQ_hd_fixed_size (queue_create_ok,
8963 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
8964 struct GNUNET_TRANSPORT_CreateQueueResponse,
8966 GNUNET_MQ_hd_fixed_size (queue_create_fail,
8967 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
8968 struct GNUNET_TRANSPORT_CreateQueueResponse,
8970 GNUNET_MQ_hd_var_size (add_queue_message,
8971 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
8972 struct GNUNET_TRANSPORT_AddQueueMessage,
8974 GNUNET_MQ_hd_var_size (address_consider_verify,
8975 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
8976 struct GNUNET_TRANSPORT_AddressToVerify,
8978 GNUNET_MQ_hd_fixed_size (del_queue_message,
8979 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
8980 struct GNUNET_TRANSPORT_DelQueueMessage,
8982 GNUNET_MQ_hd_fixed_size (send_message_ack,
8983 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
8984 struct GNUNET_TRANSPORT_SendMessageToAck,
8986 /* communication with monitors */
8987 GNUNET_MQ_hd_fixed_size (monitor_start,
8988 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
8989 struct GNUNET_TRANSPORT_MonitorStart,
8991 GNUNET_MQ_handler_end ());
8994 /* end of file gnunet-service-transport.c */