2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
27 * - add (more) logging
28 * - change transport-core API to specify transmission preferences (latency,
29 * reliability, etc.) per message!
30 * - review retransmission logic, right now there is no smartness there!
31 * => congestion control, flow control, etc [PERFORMANCE-BASICS]
34 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
35 * => Need 128 bit hash map though! [BANDWIDTH, MEMORY]
36 * - queue_send_msg and route_message both by API design have to make copies
37 * of the payload, and route_message on top of that requires a malloc/free.
38 * Change design to approximate "zero" copy better... [CPU]
39 * - could avoid copying body of message into each fragment and keep
40 * fragments as just pointers into the original message and only
41 * fully build fragments just before transmission (optimization, should
42 * reduce CPU and memory use) [CPU, MEMORY]
43 * - if messages are below MTU, consider adding ACKs and other stuff
44 * to the same transmission to avoid tiny messages (requires planning at
45 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
46 * - When we passively learned DV (with unconfirmed freshness), we
47 * right now add the path to our list but with a zero path_valid_until
48 * time and only use it for unconfirmed routes. However, we could consider
49 * triggering an explicit validation mechansim ourselves, specifically routing
50 * a challenge-response message over the path [ROUTING]
51 * - Track ACK losses based on ACK-counter [ROUTING]
53 * Design realizations / discussion:
54 * - communicators do flow control by calling MQ "notify sent"
55 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
56 * or explicitly via backchannel FC ACKs. As long as the
57 * channel is not full, they may 'notify sent' even if the other
58 * peer has not yet confirmed receipt. The other peer confirming
59 * is _only_ for FC, not for more reliable transmission; reliable
60 * transmission (i.e. of fragments) is left to _transport_.
61 * - ACKs sent back in uni-directional communicators are done via
62 * the background channel API; here transport _may_ initially
63 * broadcast (with bounded # hops) if no path is known;
64 * - transport should _integrate_ DV-routing and build a view of
65 * the network; then background channel traffic can be
66 * routed via DV as well as explicit "DV" traffic.
67 * - background channel is also used for ACKs and NAT traversal support
68 * - transport service is responsible for AEAD'ing the background
69 * channel, timestamps and monotonic time are used against replay
70 * of old messages -> peerstore needs to be supplied with
71 * "latest timestamps seen" data
72 * - if transport implements DV, we likely need a 3rd peermap
73 * in addition to ephemerals and (direct) neighbours
74 * ==> check if stuff needs to be moved out of "Neighbour"
75 * - transport should encapsualte core-level messages and do its
76 * own ACKing for RTT/goodput/loss measurements _and_ fragment
80 #include "gnunet_util_lib.h"
81 #include "gnunet_statistics_service.h"
82 #include "gnunet_transport_monitor_service.h"
83 #include "gnunet_peerstore_service.h"
84 #include "gnunet_hello_lib.h"
85 #include "gnunet_signatures.h"
86 #include "transport.h"
89 * Maximum number of messages we acknowledge together in one
90 * cummulative ACK. Larger values may save a bit of bandwidth.
92 #define MAX_CUMMULATIVE_ACKS 64
95 * What is the size we assume for a read operation in the
96 * absence of an MTU for the purpose of flow control?
98 #define IN_PACKET_SIZE_WITHOUT_MTU 128
101 * Number of slots we keep of historic data for computation of
102 * goodput / message loss ratio.
104 #define GOODPUT_AGING_SLOTS 4
107 * Maximum number of peers we select for forwarding DVInit
108 * messages at the same time (excluding initiator).
110 #define MAX_DV_DISCOVERY_SELECTION 16
113 * Window size. How many messages to the same target do we pass
114 * to CORE without a RECV_OK in between? Small values limit
115 * thoughput, large values will increase latency.
117 * FIXME-OPTIMIZE: find out what good values are experimentally,
118 * maybe set adaptively (i.e. to observed available bandwidth).
120 #define RECV_WINDOW_SIZE 4
123 * Minimum number of hops we should forward DV learn messages
124 * even if they are NOT useful for us in hope of looping
125 * back to the initiator?
127 * FIXME: allow initiator some control here instead?
129 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
132 * Maximum DV distance allowed ever.
134 #define MAX_DV_HOPS_ALLOWED 16
137 * Maximum number of DV learning activities we may
138 * have pending at the same time.
140 #define MAX_DV_LEARN_PENDING 64
143 * Maximum number of DV paths we keep simultaneously to the same target.
145 #define MAX_DV_PATHS_TO_TARGET 3
148 * If a queue delays the next message by more than this number
149 * of seconds we log a warning. Note: this is for testing,
150 * the value chosen here might be too aggressively low!
152 #define DELAY_WARN_THRESHOLD \
153 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
156 * We only consider queues as "quality" connections when
157 * suppressing the generation of DV initiation messages if
158 * the latency of the queue is below this threshold.
160 #define DV_QUALITY_RTT_THRESHOLD \
161 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
164 * How long do we consider a DV path valid if we see no
165 * further updates on it? Note: the value chosen here might be too low!
167 #define DV_PATH_VALIDITY_TIMEOUT \
168 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
171 * How long do we cache backchannel (struct Backtalker) information
172 * after a backchannel goes inactive?
174 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
175 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
178 * How long before paths expire would we like to (re)discover DV paths? Should
179 * be below #DV_PATH_VALIDITY_TIMEOUT.
181 #define DV_PATH_DISCOVERY_FREQUENCY \
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
185 * How long are ephemeral keys valid?
187 #define EPHEMERAL_VALIDITY \
188 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
191 * How long do we keep partially reassembled messages around before giving up?
193 #define REASSEMBLY_EXPIRATION \
194 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
197 * What is the fastest rate at which we send challenges *if* we keep learning
198 * an address (gossip, DHT, etc.)?
200 #define FAST_VALIDATION_CHALLENGE_FREQ \
201 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
204 * What is the slowest rate at which we send challenges?
206 #define MAX_VALIDATION_CHALLENGE_FREQ \
207 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
210 * How long until we forget about historic accumulators and thus
211 * reset the ACK counter? Should exceed the maximum time an
212 * active connection experiences without an ACK.
214 #define ACK_CUMMULATOR_TIMEOUT \
215 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
218 * What is the non-randomized base frequency at which we
219 * would initiate DV learn messages?
221 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
224 * How many good connections (confirmed, bi-directional, not DV)
225 * do we need to have to suppress initiating DV learn messages?
227 #define DV_LEARN_QUALITY_THRESHOLD 100
230 * When do we forget an invalid address for sure?
232 #define MAX_ADDRESS_VALID_UNTIL \
233 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
236 * How long do we consider an address valid if we just checked?
238 #define ADDRESS_VALIDATION_LIFETIME \
239 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
242 * What is the maximum frequency at which we do address validation?
243 * A random value between 0 and this value is added when scheduling
244 * the #validation_task (both to ensure we do not validate too often,
245 * and to randomize a bit).
247 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
250 * How many network RTTs before an address validation expires should we begin
251 * trying to revalidate? (Note that the RTT used here is the one that we
252 * experienced during the last validation, not necessarily the latest RTT
255 #define VALIDATION_RTT_BUFFER_FACTOR 3
258 * How many messages can we have pending for a given communicator
259 * process before we start to throttle that communicator?
261 * Used if a communicator might be CPU-bound and cannot handle the traffic.
263 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
266 * How many messages can we have pending for a given queue (queue to
267 * a particular peer via a communicator) process before we start to
268 * throttle that queue?
270 #define QUEUE_LENGTH_LIMIT 32
273 GNUNET_NETWORK_STRUCT_BEGIN
276 * Unique identifier we attach to a message.
281 * Unique value, generated by incrementing the
282 * `message_uuid_ctr` of `struct Neighbour`.
284 uint64_t uuid GNUNET_PACKED;
289 * Unique identifier to map an acknowledgement to a transmission.
291 struct AcknowledgementUUIDP
294 * The UUID value. Not actually a hash, but a random value.
296 struct GNUNET_ShortHashCode value;
301 * Unique identifier we attach to a message.
306 * Unique value identifying a fragment, in NBO.
308 uint32_t uuid GNUNET_PACKED;
313 * Type of a nonce used for challenges.
315 struct ChallengeNonceP
318 * The value of the nonce. Note that this is NOT a hash.
320 struct GNUNET_ShortHashCode value;
325 * Outer layer of an encapsulated backchannel message.
327 struct TransportBackchannelEncapsulationMessage
330 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
332 struct GNUNET_MessageHeader header;
335 * Reserved, always zero.
337 uint32_t reserved GNUNET_PACKED;
340 * Target's peer identity (as backchannels may be transmitted
341 * indirectly, or even be broadcast).
343 struct GNUNET_PeerIdentity target;
346 * Ephemeral key setup by the sender for @e target, used
347 * to encrypt the payload.
349 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
352 * We use an IV here as the @e ephemeral_key is re-used for
353 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
355 struct GNUNET_ShortHashCode iv;
358 * HMAC over the ciphertext of the encrypted, variable-size
359 * body that follows. Verified via DH of @e target and
362 struct GNUNET_HashCode hmac;
364 /* Followed by encrypted, variable-size payload */
369 * Body by which a peer confirms that it is using an ephemeral key.
371 struct EphemeralConfirmationPS
375 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
377 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
380 * How long is this signature over the ephemeral key valid?
382 * Note that the receiver MUST IGNORE the absolute time, and only interpret
383 * the value as a mononic time and reject "older" values than the last one
384 * observed. This is necessary as we do not want to require synchronized
385 * clocks and may not have a bidirectional communication channel.
387 * Even with this, there is no real guarantee against replay achieved here,
388 * unless the latest timestamp is persisted. While persistence should be
389 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
390 * communicators must protect against replay attacks when using backchannel
393 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
396 * Target's peer identity.
398 struct GNUNET_PeerIdentity target;
401 * Ephemeral key setup by the sender for @e target, used
402 * to encrypt the payload.
404 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
409 * Plaintext of the variable-size payload that is encrypted
410 * within a `struct TransportBackchannelEncapsulationMessage`
412 struct TransportBackchannelRequestPayloadP
416 * Sender's peer identity.
418 struct GNUNET_PeerIdentity sender;
421 * Signature of the sender over an
422 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
424 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
427 * Current monotonic time of the sending transport service. Used to
428 * detect replayed messages. Note that the receiver should remember
429 * a list of the recently seen timestamps and only reject messages
430 * if the timestamp is in the list, or the list is "full" and the
431 * timestamp is smaller than the lowest in the list.
433 * Like the @e ephemeral_validity, the list of timestamps per peer should be
434 * persisted to guard against replays after restarts.
436 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
438 /* Followed by a `struct GNUNET_MessageHeader` with a message
439 for a communicator */
441 /* Followed by a 0-termianted string specifying the name of
442 the communicator which is to receive the message */
447 * Outer layer of an encapsulated unfragmented application message sent
448 * over an unreliable channel.
450 struct TransportReliabilityBoxMessage
453 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
455 struct GNUNET_MessageHeader header;
458 * Number of messages still to be sent before a commulative
459 * ACK is requested. Zero if an ACK is requested immediately.
460 * In NBO. Note that the receiver may send the ACK faster
461 * if it believes that is reasonable.
463 uint32_t ack_countdown GNUNET_PACKED;
466 * Unique ID of the message used for signalling receipt of
467 * messages sent over possibly unreliable channels. Should
470 struct AcknowledgementUUIDP ack_uuid;
475 * Acknowledgement payload.
477 struct TransportCummulativeAckPayloadP
480 * How long was the ACK delayed for generating cummulative ACKs?
481 * Used to calculate the correct network RTT by taking the receipt
482 * time of the ack minus the transmission time of the sender minus
485 struct GNUNET_TIME_RelativeNBO ack_delay;
488 * UUID of a message being acknowledged.
490 struct AcknowledgementUUIDP ack_uuid;
495 * Confirmation that the receiver got a
496 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
497 * confirmation may be transmitted over a completely different queue,
498 * so ACKs are identified by a combination of PID of sender and
499 * message UUID, without the queue playing any role!
501 struct TransportReliabilityAckMessage
504 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
506 struct GNUNET_MessageHeader header;
509 * Counter of ACKs transmitted by the sender to us. Incremented
510 * by one for each ACK, used to detect how many ACKs were lost.
512 uint32_t ack_counter GNUNET_PACKED;
514 /* followed by any number of `struct TransportCummulativeAckPayloadP`
515 messages providing ACKs */
520 * Outer layer of an encapsulated fragmented application message.
522 struct TransportFragmentBoxMessage
525 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
527 struct GNUNET_MessageHeader header;
530 * Unique ID of this fragment (and fragment transmission!). Will
531 * change even if a fragement is retransmitted to make each
532 * transmission attempt unique! If a client receives a duplicate
533 * fragment (same @e frag_off for same @a msg_uuid, it must send
534 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
536 struct AcknowledgementUUIDP ack_uuid;
539 * Original message ID for of the message that all the fragments
540 * belong to. Must be the same for all fragments.
542 struct MessageUUIDP msg_uuid;
545 * Offset of this fragment in the overall message.
547 uint16_t frag_off GNUNET_PACKED;
550 * Total size of the message that is being fragmented.
552 uint16_t msg_size GNUNET_PACKED;
557 * Content signed by the initator during DV learning.
559 * The signature is required to prevent DDoS attacks. A peer sending out this
560 * message is potentially generating a lot of traffic that will go back to the
561 * initator, as peers receiving this message will try to let the initiator
562 * know that they got the message.
564 * Without this signature, an attacker could abuse this mechanism for traffic
565 * amplification, sending a lot of traffic to a peer by putting out this type
566 * of message with the victim's peer identity.
568 * Even with just a signature, traffic amplification would be possible via
569 * replay attacks. The @e monotonic_time limits such replay attacks, as every
570 * potential amplificator will check the @e monotonic_time and only respond
571 * (at most) once per message.
576 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
578 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
581 * Time at the initiator when generating the signature.
583 * Note that the receiver MUST IGNORE the absolute time, and only interpret
584 * the value as a mononic time and reject "older" values than the last one
585 * observed. This is necessary as we do not want to require synchronized
586 * clocks and may not have a bidirectional communication channel.
588 * Even with this, there is no real guarantee against replay achieved here,
589 * unless the latest timestamp is persisted. Persistence should be
590 * provided via PEERSTORE if possible.
592 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
595 * Challenge value used by the initiator to re-identify the path.
597 struct ChallengeNonceP challenge;
602 * Content signed by each peer during DV learning.
604 * This assues the initiator of the DV learning operation that the hop from @e
605 * pred via the signing peer to @e succ actually exists. This makes it
606 * impossible for an adversary to supply the network with bogus routes.
608 * The @e challenge is included to provide replay protection for the
609 * initiator. This way, the initiator knows that the hop existed after the
610 * original @e challenge was first transmitted, providing a freshness metric.
612 * Peers other than the initiator that passively learn paths by observing
613 * these messages do NOT benefit from this. Here, an adversary may indeed
614 * replay old messages. Thus, passively learned paths should always be
615 * immediately marked as "potentially stale".
620 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
622 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
625 * Identity of the previous peer on the path.
627 struct GNUNET_PeerIdentity pred;
630 * Identity of the next peer on the path.
632 struct GNUNET_PeerIdentity succ;
635 * Challenge value used by the initiator to re-identify the path.
637 struct ChallengeNonceP challenge;
642 * An entry describing a peer on a path in a
643 * `struct TransportDVLearnMessage` message.
648 * Identity of a peer on the path.
650 struct GNUNET_PeerIdentity hop;
653 * Signature of this hop over the path, of purpose
654 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
656 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
661 * Internal message used by transport for distance vector learning.
662 * If @e num_hops does not exceed the threshold, peers should append
663 * themselves to the peer list and flood the message (possibly only
664 * to a subset of their neighbours to limit discoverability of the
665 * network topology). To the extend that the @e bidirectional bits
666 * are set, peers may learn the inverse paths even if they did not
669 * Unless received on a bidirectional queue and @e num_hops just
670 * zero, peers that can forward to the initator should always try to
671 * forward to the initiator.
673 struct TransportDVLearnMessage
676 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
678 struct GNUNET_MessageHeader header;
681 * Number of hops this messages has travelled, in NBO. Zero if
684 uint16_t num_hops GNUNET_PACKED;
687 * Bitmask of the last 16 hops indicating whether they are confirmed
688 * available (without DV) in both directions or not, in NBO. Used
689 * to possibly instantly learn a path in both directions. Each peer
690 * should shift this value by one to the left, and then set the
691 * lowest bit IF the current sender can be reached from it (without
694 uint16_t bidirectional GNUNET_PACKED;
697 * Peers receiving this message and delaying forwarding to other
698 * peers for any reason should increment this value by the non-network
699 * delay created by the peer.
701 struct GNUNET_TIME_RelativeNBO non_network_delay;
704 * Time at the initiator when generating the signature.
706 * Note that the receiver MUST IGNORE the absolute time, and only interpret
707 * the value as a mononic time and reject "older" values than the last one
708 * observed. This is necessary as we do not want to require synchronized
709 * clocks and may not have a bidirectional communication channel.
711 * Even with this, there is no real guarantee against replay achieved here,
712 * unless the latest timestamp is persisted. Persistence should be
713 * provided via PEERSTORE if possible.
715 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
718 * Signature of this hop over the path, of purpose
719 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
721 struct GNUNET_CRYPTO_EddsaSignature init_sig;
724 * Identity of the peer that started this learning activity.
726 struct GNUNET_PeerIdentity initiator;
729 * Challenge value used by the initiator to re-identify the path.
731 struct ChallengeNonceP challenge;
733 /* Followed by @e num_hops `struct DVPathEntryP` values,
734 excluding the initiator of the DV trace; the last entry is the
735 current sender; the current peer must not be included. */
740 * Outer layer of an encapsulated message send over multiple hops.
741 * The path given only includes the identities of the subsequent
742 * peers, i.e. it will be empty if we are the receiver. Each
743 * forwarding peer should scan the list from the end, and if it can,
744 * forward to the respective peer. The list should then be shortened
745 * by all the entries up to and including that peer. Each hop should
746 * also increment @e total_hops to allow the receiver to get a precise
747 * estimate on the number of hops the message travelled. Senders must
748 * provide a learned path that thus should work, but intermediaries
749 * know of a shortcut, they are allowed to send the message via that
752 * If a peer finds itself still on the list, it must drop the message.
754 struct TransportDVBoxMessage
757 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
759 struct GNUNET_MessageHeader header;
762 * Number of total hops this messages travelled. In NBO.
763 * @e origin sets this to zero, to be incremented at
766 uint16_t total_hops GNUNET_PACKED;
769 * Number of hops this messages includes. In NBO.
771 uint16_t num_hops GNUNET_PACKED;
774 * Identity of the peer that originated the message.
776 struct GNUNET_PeerIdentity origin;
778 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
779 excluding the @e origin and the current peer, the last must be
780 the ultimate target; if @e num_hops is zero, the receiver of this
781 message is the ultimate target. */
783 /* Followed by the actual message, which itself may be
784 another box, but not a DV_LEARN or DV_BOX message! */
789 * Message send to another peer to validate that it can indeed
790 * receive messages at a particular address.
792 struct TransportValidationChallengeMessage
796 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
798 struct GNUNET_MessageHeader header;
803 uint32_t reserved GNUNET_PACKED;
806 * Challenge to be signed by the receiving peer.
808 struct ChallengeNonceP challenge;
811 * Timestamp of the sender, to be copied into the reply
812 * to allow sender to calculate RTT.
814 struct GNUNET_TIME_AbsoluteNBO sender_time;
819 * Message signed by a peer to confirm that it can indeed
820 * receive messages at a particular address.
822 struct TransportValidationPS
826 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
828 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
831 * How long does the sender believe the address on
832 * which the challenge was received to remain valid?
834 struct GNUNET_TIME_RelativeNBO validity_duration;
837 * Challenge signed by the receiving peer.
839 struct ChallengeNonceP challenge;
844 * Message send to a peer to respond to a
845 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
847 struct TransportValidationResponseMessage
851 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
853 struct GNUNET_MessageHeader header;
858 uint32_t reserved GNUNET_PACKED;
861 * The peer's signature matching the
862 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
864 struct GNUNET_CRYPTO_EddsaSignature signature;
867 * The challenge that was signed by the receiving peer.
869 struct ChallengeNonceP challenge;
872 * Original timestamp of the sender (was @code{sender_time}),
873 * copied into the reply to allow sender to calculate RTT.
875 struct GNUNET_TIME_AbsoluteNBO origin_time;
878 * How long does the sender believe this address to remain
881 struct GNUNET_TIME_RelativeNBO validity_duration;
885 GNUNET_NETWORK_STRUCT_END
889 * What type of client is the `struct TransportClient` about?
894 * We do not know yet (client is fresh).
899 * Is the CORE service, we need to forward traffic to it.
904 * It is a monitor, forward monitor data.
909 * It is a communicator, use for communication.
914 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
921 * Which transmission options are allowable for transmission?
922 * Interpreted bit-wise!
924 enum RouteMessageOptions
927 * Only confirmed, non-DV direct neighbours.
932 * We are allowed to use DV routing for this @a hdr
937 * We are allowed to use unconfirmed queues or DV routes for this message
939 RMO_UNCONFIRMED_ALLOWED = 2,
942 * Reliable and unreliable, DV and non-DV are all acceptable.
944 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
947 * If we have multiple choices, it is OK to send this message
948 * over multiple channels at the same time to improve loss tolerance.
949 * (We do at most 2 transmissions.)
956 * When did we launch this DV learning activity?
958 struct LearnLaunchEntry
962 * Kept (also) in a DLL sorted by launch time.
964 struct LearnLaunchEntry *prev;
967 * Kept (also) in a DLL sorted by launch time.
969 struct LearnLaunchEntry *next;
972 * Challenge that uniquely identifies this activity.
974 struct ChallengeNonceP challenge;
977 * When did we transmit the DV learn message (used to calculate RTT) and
978 * determine freshness of paths learned via this operation.
980 struct GNUNET_TIME_Absolute launch_time;
985 * Entry in our cache of ephemeral keys we currently use. This way, we only
986 * sign an ephemeral once per @e target, and then can re-use it over multiple
987 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
988 * signing is expensive and in some cases we may use backchannel messages a
991 struct EphemeralCacheEntry
995 * Target's peer identity (we don't re-use ephemerals
996 * to limit linkability of messages).
998 struct GNUNET_PeerIdentity target;
1001 * Signature affirming @e ephemeral_key of type
1002 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1004 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1007 * How long is @e sender_sig valid
1009 struct GNUNET_TIME_Absolute ephemeral_validity;
1012 * What time was @e sender_sig created
1014 struct GNUNET_TIME_Absolute monotime;
1017 * Our ephemeral key.
1019 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1022 * Our private ephemeral key.
1024 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1027 * Node in the ephemeral cache for this entry.
1028 * Used for expiration.
1030 struct GNUNET_CONTAINER_HeapNode *hn;
1035 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1036 * (or current) transmission performance.
1038 struct TransmissionHistoryEntry
1041 * Number of bytes actually sent in the interval.
1043 uint64_t bytes_sent;
1046 * Number of bytes received and acknowledged by the other peer in
1049 uint64_t bytes_received;
1054 * Performance data for a transmission possibility.
1056 struct PerformanceData
1059 * Weighted average for the RTT.
1061 struct GNUNET_TIME_Relative aged_rtt;
1064 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1067 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1070 * What was the last age when we wrote to @e the? Used to clear
1071 * old entries when the age advances.
1073 unsigned int last_age;
1078 * Client connected to the transport service.
1080 struct TransportClient;
1083 * A neighbour that at least one communicator is connected to.
1088 * Entry in our #dv_routes table, representing a (set of) distance
1089 * vector routes to a particular peer.
1091 struct DistanceVector;
1094 * A queue is a message queue provided by a communicator
1095 * via which we can reach a particular neighbour.
1100 * Message awaiting transmission. See detailed comments below.
1102 struct PendingMessage;
1105 * One possible hop towards a DV target.
1107 struct DistanceVectorHop;
1111 * Context from #handle_incoming_msg(). Closure for many
1112 * message handlers below.
1114 struct CommunicatorMessageContext
1118 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1119 * flow control to unchoke.
1121 struct CommunicatorMessageContext *next;
1124 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1125 * flow control to unchoke.
1127 struct CommunicatorMessageContext *prev;
1130 * Which communicator provided us with the message.
1132 struct TransportClient *tc;
1135 * Additional information for flow control and about the sender.
1137 struct GNUNET_TRANSPORT_IncomingMessage im;
1140 * Number of hops the message has travelled (if DV-routed).
1141 * FIXME: make use of this in ACK handling!
1143 uint16_t total_hops;
1148 * A virtual link is another reachable peer that is known to CORE. It
1149 * can be either a `struct Neighbour` with at least one confirmed
1150 * `struct Queue`, or a `struct DistanceVector` with at least one
1151 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1152 * data that is per neighbour that is not specific to how the
1153 * connectivity is established.
1158 * Identity of the peer at the other end of the link.
1160 struct GNUNET_PeerIdentity target;
1163 * Communicators blocked for receiving on @e target as we are waiting
1164 * on the @e core_recv_window to increase.
1166 struct CommunicatorMessageContext *cmc_head;
1169 * Communicators blocked for receiving on @e target as we are waiting
1170 * on the @e core_recv_window to increase.
1172 struct CommunicatorMessageContext *cmc_tail;
1175 * Task scheduled to possibly notfiy core that this peer is no
1176 * longer counting as confirmed. Runs the #core_visibility_check(),
1177 * which checks that some DV-path or a queue exists that is still
1178 * considered confirmed.
1180 struct GNUNET_SCHEDULER_Task *visibility_task;
1183 * Neighbour used by this virtual link, NULL if @e dv is used.
1185 struct Neighbour *n;
1188 * Distance vector used by this virtual link, NULL if @e n is used.
1190 struct DistanceVector *dv;
1193 * How many more messages can we send to core before we exhaust
1194 * the receive window of CORE for this peer? If this hits zero,
1195 * we must tell communicators to stop providing us more messages
1196 * for this peer. In fact, the window can go negative as we
1197 * have multiple communicators, so per communicator we can go
1198 * down by one into the negative range.
1200 int core_recv_window;
1205 * Data structure kept when we are waiting for an acknowledgement.
1207 struct PendingAcknowledgement
1211 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1212 * is kept in relation to its pending message.
1214 struct PendingAcknowledgement *next_pm;
1217 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1218 * is kept in relation to its pending message.
1220 struct PendingAcknowledgement *prev_pm;
1223 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1224 * is kept in relation to the queue that was used to transmit the
1227 struct PendingAcknowledgement *next_queue;
1230 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1231 * is kept in relation to the queue that was used to transmit the
1234 struct PendingAcknowledgement *prev_queue;
1237 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1238 * is kept in relation to the DVH that was used to transmit the
1241 struct PendingAcknowledgement *next_dvh;
1244 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1245 * is kept in relation to the DVH that was used to transmit the
1248 struct PendingAcknowledgement *prev_dvh;
1251 * Pointers for the DLL of all pending acknowledgements.
1252 * This list is sorted by @e transmission time. If the list gets too
1253 * long, the oldest entries are discarded.
1255 struct PendingAcknowledgement *next_pa;
1258 * Pointers for the DLL of all pending acknowledgements.
1259 * This list is sorted by @e transmission time. If the list gets too
1260 * long, the oldest entries are discarded.
1262 struct PendingAcknowledgement *prev_pa;
1265 * Unique identifier for this transmission operation.
1267 struct AcknowledgementUUIDP ack_uuid;
1270 * Message that was transmitted, may be NULL if the message was ACKed
1271 * via another channel.
1273 struct PendingMessage *pm;
1276 * Distance vector path chosen for this transmission, NULL if transmission
1277 * was to a direct neighbour OR if the path was forgotten in the meantime.
1279 struct DistanceVectorHop *dvh;
1282 * Queue used for transmission, NULL if the queue has been destroyed
1283 * (which may happen before we get an acknowledgement).
1285 struct Queue *queue;
1288 * Time of the transmission, for RTT calculation.
1290 struct GNUNET_TIME_Absolute transmission_time;
1293 * Number of bytes of the original message (to calculate bandwidth).
1295 uint16_t message_size;
1300 * One possible hop towards a DV target.
1302 struct DistanceVectorHop
1306 * Kept in a MDLL, sorted by @e timeout.
1308 struct DistanceVectorHop *next_dv;
1311 * Kept in a MDLL, sorted by @e timeout.
1313 struct DistanceVectorHop *prev_dv;
1318 struct DistanceVectorHop *next_neighbour;
1323 struct DistanceVectorHop *prev_neighbour;
1326 * Head of MDLL of messages routed via this path.
1328 struct PendingMessage *pending_msg_head;
1331 * Tail of MDLL of messages routed via this path.
1333 struct PendingMessage *pending_msg_tail;
1336 * Head of DLL of PAs that used our @a path.
1338 struct PendingAcknowledgement *pa_head;
1341 * Tail of DLL of PAs that used our @a path.
1343 struct PendingAcknowledgement *pa_tail;
1346 * What would be the next hop to @e target?
1348 struct Neighbour *next_hop;
1351 * Distance vector entry this hop belongs with.
1353 struct DistanceVector *dv;
1356 * Array of @e distance hops to the target, excluding @e next_hop.
1357 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1358 * at the end of this struct. Excludes the target itself!
1360 const struct GNUNET_PeerIdentity *path;
1363 * At what time do we forget about this path unless we see it again
1366 struct GNUNET_TIME_Absolute timeout;
1369 * For how long is the validation of this path considered
1371 * Set to ZERO if the path is learned by snooping on DV learn messages
1372 * initiated by other peers, and to the time at which we generated the
1373 * challenge for DV learn operations this peer initiated.
1375 struct GNUNET_TIME_Absolute path_valid_until;
1378 * Performance data for this transmission possibility.
1380 struct PerformanceData pd;
1383 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1384 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1387 unsigned int distance;
1392 * Entry in our #dv_routes table, representing a (set of) distance
1393 * vector routes to a particular peer.
1395 struct DistanceVector
1399 * To which peer is this a route?
1401 struct GNUNET_PeerIdentity target;
1404 * Known paths to @e target.
1406 struct DistanceVectorHop *dv_head;
1409 * Known paths to @e target.
1411 struct DistanceVectorHop *dv_tail;
1414 * Task scheduled to purge expired paths from @e dv_head MDLL.
1416 struct GNUNET_SCHEDULER_Task *timeout_task;
1419 * Do we have a confirmed working queue and are thus visible to
1420 * CORE? If so, this is the virtual link, otherwise NULL.
1422 struct VirtualLink *link;
1427 * Entry identifying transmission in one of our `struct
1428 * Queue` which still awaits an ACK. This is used to
1429 * ensure we do not overwhelm a communicator and limit the number of
1430 * messages outstanding per communicator (say in case communicator is
1431 * CPU bound) and per queue (in case bandwidth allocation exceeds
1432 * what the communicator can actually provide towards a particular
1441 struct QueueEntry *next;
1446 struct QueueEntry *prev;
1449 * Queue this entry is queued with.
1451 struct Queue *queue;
1454 * Pending message this entry is for, or NULL for none.
1456 struct PendingMessage *pm;
1459 * Message ID used for this message with the queue used for transmission.
1466 * A queue is a message queue provided by a communicator
1467 * via which we can reach a particular neighbour.
1474 struct Queue *next_neighbour;
1479 struct Queue *prev_neighbour;
1484 struct Queue *prev_client;
1489 struct Queue *next_client;
1492 * Head of DLL of PAs that used this queue.
1494 struct PendingAcknowledgement *pa_head;
1497 * Tail of DLL of PAs that used this queue.
1499 struct PendingAcknowledgement *pa_tail;
1502 * Head of DLL of unacked transmission requests.
1504 struct QueueEntry *queue_head;
1507 * End of DLL of unacked transmission requests.
1509 struct QueueEntry *queue_tail;
1512 * Which neighbour is this queue for?
1514 struct Neighbour *neighbour;
1517 * Which communicator offers this queue?
1519 struct TransportClient *tc;
1522 * Address served by the queue.
1524 const char *address;
1527 * Task scheduled for the time when this queue can (likely) transmit the
1530 struct GNUNET_SCHEDULER_Task *transmit_task;
1533 * How long do *we* consider this @e address to be valid? In the past or
1534 * zero if we have not yet validated it. Can be updated based on
1535 * challenge-response validations (via address validation logic), or when we
1536 * receive ACKs that we can definitively map to transmissions via this
1539 struct GNUNET_TIME_Absolute validated_until;
1542 * Performance data for this queue.
1544 struct PerformanceData pd;
1547 * Message ID generator for transmissions on this queue to the
1553 * Unique identifier of this queue with the communicator.
1558 * Maximum transmission unit supported by this queue.
1565 uint32_t num_msg_pending;
1570 uint32_t num_bytes_pending;
1573 * Length of the DLL starting at @e queue_head.
1575 unsigned int queue_length;
1578 * Network type offered by this queue.
1580 enum GNUNET_NetworkType nt;
1583 * Connection status for this queue.
1585 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1590 * Information we keep for a message that we are reassembling.
1592 struct ReassemblyContext
1596 * Original message ID for of the message that all the fragments
1599 struct MessageUUIDP msg_uuid;
1602 * Which neighbour is this context for?
1604 struct Neighbour *neighbour;
1607 * Entry in the reassembly heap (sorted by expiration).
1609 struct GNUNET_CONTAINER_HeapNode *hn;
1612 * Bitfield with @e msg_size bits representing the positions
1613 * where we have received fragments. When we receive a fragment,
1614 * we check the bits in @e bitfield before incrementing @e msg_missing.
1616 * Allocated after the reassembled message.
1621 * Task for sending ACK. We may send ACKs either because of hitting
1622 * the @e extra_acks limit, or based on time and @e num_acks. This
1623 * task is for the latter case.
1625 struct GNUNET_SCHEDULER_Task *ack_task;
1628 * At what time will we give up reassembly of this message?
1630 struct GNUNET_TIME_Absolute reassembly_timeout;
1633 * Time we received the last fragment. @e avg_ack_delay must be
1634 * incremented by now - @e last_frag multiplied by @e num_acks.
1636 struct GNUNET_TIME_Absolute last_frag;
1639 * How big is the message we are reassembling in total?
1644 * How many bytes of the message are still missing? Defragmentation
1645 * is complete when @e msg_missing == 0.
1647 uint16_t msg_missing;
1649 /* Followed by @e msg_size bytes of the (partially) defragmented original
1652 /* Followed by @e bitfield data */
1657 * A neighbour that at least one communicator is connected to.
1663 * Which peer is this about?
1665 struct GNUNET_PeerIdentity pid;
1668 * Map with `struct ReassemblyContext` structs for fragments under
1669 * reassembly. May be NULL if we currently have no fragments from
1670 * this @e pid (lazy initialization).
1672 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1675 * Heap with `struct ReassemblyContext` structs for fragments under
1676 * reassembly. May be NULL if we currently have no fragments from
1677 * this @e pid (lazy initialization).
1679 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1682 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1684 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1687 * Head of list of messages pending for this neighbour.
1689 struct PendingMessage *pending_msg_head;
1692 * Tail of list of messages pending for this neighbour.
1694 struct PendingMessage *pending_msg_tail;
1697 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1698 * purged if this neighbour goes down.
1700 struct DistanceVectorHop *dv_head;
1703 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1704 * purged if this neighbour goes down.
1706 struct DistanceVectorHop *dv_tail;
1709 * Head of DLL of queues to this peer.
1711 struct Queue *queue_head;
1714 * Tail of DLL of queues to this peer.
1716 struct Queue *queue_tail;
1719 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1720 * the PEERSTORE, or NULL.
1722 struct GNUNET_PEERSTORE_IterateContext *get;
1725 * Handle to a PEERSTORE store operation to store this @e pid's @e
1726 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1728 struct GNUNET_PEERSTORE_StoreContext *sc;
1731 * Do we have a confirmed working queue and are thus visible to
1732 * CORE? If so, this is the virtual link, otherwise NULL.
1734 struct VirtualLink *link;
1737 * Latest DVLearn monotonic time seen from this peer. Initialized only
1738 * if @e dl_monotime_available is #GNUNET_YES.
1740 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1743 * Do we have the lastest value for @e last_dv_learn_monotime from
1744 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1746 int dv_monotime_available;
1751 * A peer that an application (client) would like us to talk to directly.
1757 * Which peer is this about?
1759 struct GNUNET_PeerIdentity pid;
1762 * Client responsible for the request.
1764 struct TransportClient *tc;
1767 * Handle for watching the peerstore for HELLOs for this peer.
1769 struct GNUNET_PEERSTORE_WatchContext *wc;
1772 * What kind of performance preference does this @e tc have?
1774 enum GNUNET_MQ_PreferenceKind pk;
1777 * How much bandwidth would this @e tc like to see?
1779 struct GNUNET_BANDWIDTH_Value32NBO bw;
1784 * Types of different pending messages.
1786 enum PendingMessageType
1790 * Ordinary message received from the CORE service.
1797 PMT_FRAGMENT_BOX = 1,
1802 PMT_RELIABILITY_BOX = 2,
1805 * Any type of acknowledgement.
1807 PMT_ACKNOWLEDGEMENT = 3,
1810 * Control traffic generated by the TRANSPORT service itself.
1818 * Transmission request that is awaiting delivery. The original
1819 * transmission requests from CORE may be too big for some queues.
1820 * In this case, a *tree* of fragments is created. At each
1821 * level of the tree, fragments are kept in a DLL ordered by which
1822 * fragment should be sent next (at the head). The tree is searched
1823 * top-down, with the original message at the root.
1825 * To select a node for transmission, first it is checked if the
1826 * current node's message fits with the MTU. If it does not, we
1827 * either calculate the next fragment (based on @e frag_off) from the
1828 * current node, or, if all fragments have already been created,
1829 * descend to the @e head_frag. Even though the node was already
1830 * fragmented, the fragment may be too big if the fragment was
1831 * generated for a queue with a larger MTU. In this case, the node
1832 * may be fragmented again, thus creating a tree.
1834 * When acknowledgements for fragments are received, the tree
1835 * must be pruned, removing those parts that were already
1836 * acknowledged. When fragments are sent over a reliable
1837 * channel, they can be immediately removed.
1839 * If a message is ever fragmented, then the original "full" message
1840 * is never again transmitted (even if it fits below the MTU), and
1841 * only (remaining) fragments are sent.
1843 struct PendingMessage
1846 * Kept in a MDLL of messages for this @a target.
1848 struct PendingMessage *next_neighbour;
1851 * Kept in a MDLL of messages for this @a target.
1853 struct PendingMessage *prev_neighbour;
1856 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1858 struct PendingMessage *next_client;
1861 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1863 struct PendingMessage *prev_client;
1866 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1867 * #PMT_FRAGMENT_BOx)
1869 struct PendingMessage *next_frag;
1872 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1873 * #PMT_FRAGMENT_BOX)
1875 struct PendingMessage *prev_frag;
1878 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1881 struct PendingMessage *next_dvh;
1884 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1887 struct PendingMessage *prev_dvh;
1890 * Head of DLL of PAs for this pending message.
1892 struct PendingAcknowledgement *pa_head;
1895 * Tail of DLL of PAs for this pending message.
1897 struct PendingAcknowledgement *pa_tail;
1900 * This message, reliability boxed. Only possibly available if @e pmt is
1903 struct PendingMessage *bpm;
1906 * Target of the request (for transmission, may not be ultimate
1909 struct Neighbour *target;
1912 * Distance vector path selected for this message, or
1913 * NULL if transmitted directly.
1915 struct DistanceVectorHop *dvh;
1918 * Set to non-NULL value if this message is currently being given to a
1919 * communicator and we are awaiting that communicator's acknowledgement.
1920 * Note that we must not retransmit a pending message while we're still
1921 * in the process of giving it to a communicator. If a pending message
1922 * is free'd while this entry is non-NULL, the @e qe reference to us
1923 * should simply be set to NULL.
1925 struct QueueEntry *qe;
1928 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1930 struct TransportClient *client;
1933 * Head of a MDLL of fragments created for this core message.
1935 struct PendingMessage *head_frag;
1938 * Tail of a MDLL of fragments created for this core message.
1940 struct PendingMessage *tail_frag;
1943 * Our parent in the fragmentation tree.
1945 struct PendingMessage *frag_parent;
1948 * At what time should we give up on the transmission (and no longer retry)?
1950 struct GNUNET_TIME_Absolute timeout;
1953 * What is the earliest time for us to retry transmission of this message?
1955 struct GNUNET_TIME_Absolute next_attempt;
1958 * UUID to use for this message (used for reassembly of fragments, only
1959 * initialized if @e msg_uuid_set is #GNUNET_YES).
1961 struct MessageUUIDP msg_uuid;
1964 * Type of the pending message.
1966 enum PendingMessageType pmt;
1969 * Size of the original message.
1974 * Offset at which we should generate the next fragment.
1979 * #GNUNET_YES once @e msg_uuid was initialized
1981 int16_t msg_uuid_set;
1983 /* Followed by @e bytes_msg to transmit */
1988 * Acknowledgement payload.
1990 struct TransportCummulativeAckPayload
1993 * When did we receive the message we are ACKing? Used to calculate
1994 * the delay we introduced by cummulating ACKs.
1996 struct GNUNET_TIME_Absolute receive_time;
1999 * UUID of a message being acknowledged.
2001 struct AcknowledgementUUIDP ack_uuid;
2006 * Data structure in which we track acknowledgements still to
2009 struct AcknowledgementCummulator
2012 * Target peer for which we are accumulating ACKs here.
2014 struct GNUNET_PeerIdentity target;
2017 * ACK data being accumulated. Only @e num_acks slots are valid.
2019 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2022 * Task scheduled either to transmit the cummulative ACK message,
2023 * or to clean up this data structure after extended periods of
2024 * inactivity (if @e num_acks is zero).
2026 struct GNUNET_SCHEDULER_Task *task;
2029 * When is @e task run (only used if @e num_acks is non-zero)?
2031 struct GNUNET_TIME_Absolute min_transmission_time;
2034 * Counter to produce the `ack_counter` in the `struct
2035 * TransportReliabilityAckMessage`. Allows the receiver to detect
2036 * lost ACK messages. Incremented by @e num_acks upon transmission.
2038 uint32_t ack_counter;
2041 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2043 unsigned int num_acks;
2048 * One of the addresses of this peer.
2050 struct AddressListEntry
2056 struct AddressListEntry *next;
2061 struct AddressListEntry *prev;
2064 * Which communicator provides this address?
2066 struct TransportClient *tc;
2069 * The actual address.
2071 const char *address;
2074 * Current context for storing this address in the peerstore.
2076 struct GNUNET_PEERSTORE_StoreContext *sc;
2079 * Task to periodically do @e st operation.
2081 struct GNUNET_SCHEDULER_Task *st;
2084 * What is a typical lifetime the communicator expects this
2085 * address to have? (Always from now.)
2087 struct GNUNET_TIME_Relative expiration;
2090 * Address identifier used by the communicator.
2095 * Network type offered by this address.
2097 enum GNUNET_NetworkType nt;
2102 * Client connected to the transport service.
2104 struct TransportClient
2110 struct TransportClient *next;
2115 struct TransportClient *prev;
2118 * Handle to the client.
2120 struct GNUNET_SERVICE_Client *client;
2123 * Message queue to the client.
2125 struct GNUNET_MQ_Handle *mq;
2128 * What type of client is this?
2130 enum ClientType type;
2136 * Information for @e type #CT_CORE.
2142 * Head of list of messages pending for this client, sorted by
2143 * transmission time ("next_attempt" + possibly internal prioritization).
2145 struct PendingMessage *pending_msg_head;
2148 * Tail of list of messages pending for this client.
2150 struct PendingMessage *pending_msg_tail;
2155 * Information for @e type #CT_MONITOR.
2161 * Peer identity to monitor the addresses of.
2162 * Zero to monitor all neighbours. Valid if
2163 * @e type is #CT_MONITOR.
2165 struct GNUNET_PeerIdentity peer;
2168 * Is this a one-shot monitor?
2176 * Information for @e type #CT_COMMUNICATOR.
2181 * If @e type is #CT_COMMUNICATOR, this communicator
2182 * supports communicating using these addresses.
2184 char *address_prefix;
2187 * Head of DLL of queues offered by this communicator.
2189 struct Queue *queue_head;
2192 * Tail of DLL of queues offered by this communicator.
2194 struct Queue *queue_tail;
2197 * Head of list of the addresses of this peer offered by this
2200 struct AddressListEntry *addr_head;
2203 * Tail of list of the addresses of this peer offered by this
2206 struct AddressListEntry *addr_tail;
2209 * Number of queue entries in all queues to this communicator. Used
2210 * throttle sending to a communicator if we see that the communicator
2211 * is globally unable to keep up.
2213 unsigned int total_queue_length;
2216 * Characteristics of this communicator.
2218 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2223 * Information for @e type #CT_APPLICATION
2229 * Map of requests for peers the given client application would like to
2230 * see connections for. Maps from PIDs to `struct PeerRequest`.
2232 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2241 * State we keep for validation activities. Each of these
2242 * is both in the #validation_heap and the #validation_map.
2244 struct ValidationState
2248 * For which peer is @a address to be validated (or possibly valid)?
2249 * Serves as key in the #validation_map.
2251 struct GNUNET_PeerIdentity pid;
2254 * How long did the peer claim this @e address to be valid? Capped at
2255 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2256 * were told about the address and the value claimed by the other peer at
2257 * that time. May be updated similarly when validation succeeds.
2259 struct GNUNET_TIME_Absolute valid_until;
2262 * How long do *we* consider this @e address to be valid?
2263 * In the past or zero if we have not yet validated it.
2265 struct GNUNET_TIME_Absolute validated_until;
2268 * When did we FIRST use the current @e challenge in a message?
2269 * Used to sanity-check @code{origin_time} in the response when
2270 * calculating the RTT. If the @code{origin_time} is not in
2271 * the expected range, the response is discarded as malicious.
2273 struct GNUNET_TIME_Absolute first_challenge_use;
2276 * When did we LAST use the current @e challenge in a message?
2277 * Used to sanity-check @code{origin_time} in the response when
2278 * calculating the RTT. If the @code{origin_time} is not in
2279 * the expected range, the response is discarded as malicious.
2281 struct GNUNET_TIME_Absolute last_challenge_use;
2284 * Next time we will send the @e challenge to the peer, if this time is past
2285 * @e valid_until, this validation state is released at this time. If the
2286 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2287 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2288 * to re-validate before the validity actually expires.
2290 struct GNUNET_TIME_Absolute next_challenge;
2293 * Current backoff factor we're applying for sending the @a challenge.
2294 * Reset to 0 if the @a challenge is confirmed upon validation.
2295 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2296 * existing value if we receive an unvalidated address again over
2297 * another channel (and thus should consider the information "fresh").
2298 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2300 struct GNUNET_TIME_Relative challenge_backoff;
2303 * Initially set to "forever". Once @e validated_until is set, this value is
2304 * set to the RTT that tells us how long it took to receive the validation.
2306 struct GNUNET_TIME_Relative validation_rtt;
2309 * The challenge we sent to the peer to get it to validate the address. Note
2310 * that we rotate the challenge whenever we update @e validated_until to
2311 * avoid attacks where a peer simply replays an old challenge in the future.
2312 * (We must not rotate more often as otherwise we may discard valid answers
2313 * due to packet losses, latency and reorderings on the network).
2315 struct ChallengeNonceP challenge;
2318 * Claimed address of the peer.
2323 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2324 * heap is used to figure out when the next validation activity should be
2327 struct GNUNET_CONTAINER_HeapNode *hn;
2330 * Handle to a PEERSTORE store operation for this @e address. NULL if
2331 * no PEERSTORE operation is pending.
2333 struct GNUNET_PEERSTORE_StoreContext *sc;
2336 * We are technically ready to send the challenge, but we are waiting for
2337 * the respective queue to become available for transmission.
2344 * A Backtalker is a peer sending us backchannel messages. We use this
2345 * struct to detect monotonic time violations, cache ephemeral key
2346 * material (to avoid repeatedly checking signatures), and to synchronize
2347 * monotonic time with the PEERSTORE.
2352 * Peer this is about.
2354 struct GNUNET_PeerIdentity pid;
2357 * Last (valid) monotonic time received from this sender.
2359 struct GNUNET_TIME_Absolute monotonic_time;
2362 * When will this entry time out?
2364 struct GNUNET_TIME_Absolute timeout;
2367 * Last (valid) ephemeral key received from this sender.
2369 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2372 * Task associated with this backtalker. Can be for timeout,
2373 * or other asynchronous operations.
2375 struct GNUNET_SCHEDULER_Task *task;
2378 * Communicator context waiting on this backchannel's @e get, or NULL.
2380 struct CommunicatorMessageContext *cmc;
2383 * Handle for an operation to fetch @e monotonic_time information from the
2384 * PEERSTORE, or NULL.
2386 struct GNUNET_PEERSTORE_IterateContext *get;
2389 * Handle to a PEERSTORE store operation for this @e pid's @e
2390 * monotonic_time. NULL if no PEERSTORE operation is pending.
2392 struct GNUNET_PEERSTORE_StoreContext *sc;
2395 * Number of bytes of the original message body that follows after this
2403 * Head of linked list of all clients to this service.
2405 static struct TransportClient *clients_head;
2408 * Tail of linked list of all clients to this service.
2410 static struct TransportClient *clients_tail;
2413 * Statistics handle.
2415 static struct GNUNET_STATISTICS_Handle *GST_stats;
2418 * Configuration handle.
2420 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2425 static struct GNUNET_PeerIdentity GST_my_identity;
2430 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2433 * Map from PIDs to `struct Neighbour` entries. A peer is
2434 * a neighbour if we have an MQ to it from some communicator.
2436 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2439 * Map from PIDs to `struct Backtalker` entries. A peer is
2440 * a backtalker if it recently send us backchannel messages.
2442 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2445 * Map from PIDs to `struct AcknowledgementCummulator`s.
2446 * Here we track the cummulative ACKs for transmission.
2448 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2451 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2452 * a `struct PendingAcknowledgement`.
2454 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2457 * Map from PIDs to `struct DistanceVector` entries describing
2458 * known paths to the peer.
2460 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2463 * Map from PIDs to `struct ValidationState` entries describing
2464 * addresses we are aware of and their validity state.
2466 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2469 * Map from PIDs to `struct VirtualLink` entries describing
2470 * links CORE knows to exist.
2472 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2475 * Map from challenges to `struct LearnLaunchEntry` values.
2477 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2480 * Head of a DLL sorted by launch time.
2482 static struct LearnLaunchEntry *lle_head;
2485 * Tail of a DLL sorted by launch time.
2487 static struct LearnLaunchEntry *lle_tail;
2490 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2491 * sorting addresses we are aware of by when we should next try to (re)validate
2494 static struct GNUNET_CONTAINER_Heap *validation_heap;
2497 * Database for peer's HELLOs.
2499 static struct GNUNET_PEERSTORE_Handle *peerstore;
2502 * Heap sorting `struct EphemeralCacheEntry` by their
2503 * key/signature validity.
2505 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2508 * Hash map for looking up `struct EphemeralCacheEntry`s
2509 * by peer identity. (We may have ephemerals in our
2510 * cache for which we do not have a neighbour entry,
2511 * and similar many neighbours may not need ephemerals,
2512 * so we use a second map.)
2514 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2517 * Task to free expired ephemerals.
2519 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2522 * Task run to initiate DV learning.
2524 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2527 * Task to run address validation.
2529 static struct GNUNET_SCHEDULER_Task *validation_task;
2532 * The most recent PA we have created, head of DLL.
2533 * The length of the DLL is kept in #pa_count.
2535 static struct PendingAcknowledgement *pa_head;
2538 * The oldest PA we have created, tail of DLL.
2539 * The length of the DLL is kept in #pa_count.
2541 static struct PendingAcknowledgement *pa_tail;
2544 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2545 * limit the size of the data structure.
2547 static unsigned int pa_count;
2551 * Get an offset into the transmission history buffer for `struct
2552 * PerformanceData`. Note that the caller must perform the required
2553 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2556 * An 'age' lasts 15 minute slots.
2558 * @return current age of the world
2563 struct GNUNET_TIME_Absolute now;
2565 now = GNUNET_TIME_absolute_get ();
2566 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2571 * Release @a pa data structure.
2573 * @param pa data structure to release
2576 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2578 struct Queue *q = pa->queue;
2579 struct PendingMessage *pm = pa->pm;
2580 struct DistanceVectorHop *dvh = pa->dvh;
2582 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2586 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2591 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2596 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2599 GNUNET_assert (GNUNET_YES ==
2600 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2601 &pa->ack_uuid.value,
2608 * Free cached ephemeral key.
2610 * @param ece cached signature to free
2613 free_ephemeral (struct EphemeralCacheEntry *ece)
2615 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2616 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2622 * Free virtual link.
2624 * @param vl link data to free
2627 free_virtual_link (struct VirtualLink *vl)
2629 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2630 if (NULL != vl->visibility_task)
2632 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2633 vl->visibility_task = NULL;
2635 GNUNET_break (NULL == vl->n);
2636 GNUNET_break (NULL == vl->dv);
2642 * Free validation state.
2644 * @param vs validation state to free
2647 free_validation_state (struct ValidationState *vs)
2649 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2650 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2654 GNUNET_PEERSTORE_store_cancel (vs->sc);
2657 GNUNET_free (vs->address);
2663 * Lookup neighbour record for peer @a pid.
2665 * @param pid neighbour to look for
2666 * @return NULL if we do not have this peer as a neighbour
2668 static struct Neighbour *
2669 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2671 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2676 * Details about what to notify monitors about.
2681 * @deprecated To be discussed if we keep these...
2683 struct GNUNET_TIME_Absolute last_validation;
2684 struct GNUNET_TIME_Absolute valid_until;
2685 struct GNUNET_TIME_Absolute next_validation;
2688 * Current round-trip time estimate.
2690 struct GNUNET_TIME_Relative rtt;
2693 * Connection status.
2695 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2700 uint32_t num_msg_pending;
2705 uint32_t num_bytes_pending;
2710 * Free a @dvh. Callers MAY want to check if this was the last path to the
2711 * `target`, and if so call #free_dv_route to also free the associated DV
2712 * entry in #dv_routes (if not, the associated scheduler job should eventually
2715 * @param dvh hop to free
2718 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2720 struct Neighbour *n = dvh->next_hop;
2721 struct DistanceVector *dv = dvh->dv;
2722 struct PendingAcknowledgement *pa;
2723 struct PendingMessage *pm;
2725 while (NULL != (pm = dvh->pending_msg_head))
2727 GNUNET_CONTAINER_MDLL_remove (dvh,
2728 dvh->pending_msg_head,
2729 dvh->pending_msg_tail,
2733 while (NULL != (pa = dvh->pa_head))
2735 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2738 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2739 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2745 * Free entry in #dv_routes. First frees all hops to the target, and
2746 * if there are no entries left, frees @a dv as well.
2748 * @param dv route to free
2751 free_dv_route (struct DistanceVector *dv)
2753 struct DistanceVectorHop *dvh;
2755 while (NULL != (dvh = dv->dv_head))
2756 free_distance_vector_hop (dvh);
2757 if (NULL == dv->dv_head)
2761 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2762 if (NULL != dv->timeout_task)
2763 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2770 * Notify monitor @a tc about an event. That @a tc
2771 * cares about the event has already been checked.
2773 * Send @a tc information in @a me about a @a peer's status with
2774 * respect to some @a address to all monitors that care.
2776 * @param tc monitor to inform
2777 * @param peer peer the information is about
2778 * @param address address the information is about
2779 * @param nt network type associated with @a address
2780 * @param me detailed information to transmit
2783 notify_monitor (struct TransportClient *tc,
2784 const struct GNUNET_PeerIdentity *peer,
2785 const char *address,
2786 enum GNUNET_NetworkType nt,
2787 const struct MonitorEvent *me)
2789 struct GNUNET_MQ_Envelope *env;
2790 struct GNUNET_TRANSPORT_MonitorData *md;
2791 size_t addr_len = strlen (address) + 1;
2793 env = GNUNET_MQ_msg_extra (md,
2795 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2796 md->nt = htonl ((uint32_t) nt);
2798 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2799 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2800 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2801 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2802 md->cs = htonl ((uint32_t) me->cs);
2803 md->num_msg_pending = htonl (me->num_msg_pending);
2804 md->num_bytes_pending = htonl (me->num_bytes_pending);
2805 memcpy (&md[1], address, addr_len);
2806 GNUNET_MQ_send (tc->mq, env);
2811 * Send information in @a me about a @a peer's status with respect
2812 * to some @a address to all monitors that care.
2814 * @param peer peer the information is about
2815 * @param address address the information is about
2816 * @param nt network type associated with @a address
2817 * @param me detailed information to transmit
2820 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2821 const char *address,
2822 enum GNUNET_NetworkType nt,
2823 const struct MonitorEvent *me)
2825 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2827 if (CT_MONITOR != tc->type)
2829 if (tc->details.monitor.one_shot)
2831 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2832 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2834 notify_monitor (tc, peer, address, nt, me);
2840 * Called whenever a client connects. Allocates our
2841 * data structures associated with that client.
2843 * @param cls closure, NULL
2844 * @param client identification of the client
2845 * @param mq message queue for the client
2846 * @return our `struct TransportClient`
2849 client_connect_cb (void *cls,
2850 struct GNUNET_SERVICE_Client *client,
2851 struct GNUNET_MQ_Handle *mq)
2853 struct TransportClient *tc;
2856 tc = GNUNET_new (struct TransportClient);
2857 tc->client = client;
2859 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2868 * @param rc data structure to free
2871 free_reassembly_context (struct ReassemblyContext *rc)
2873 struct Neighbour *n = rc->neighbour;
2875 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2876 GNUNET_assert (GNUNET_OK ==
2877 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2885 * Task run to clean up reassembly context of a neighbour that have expired.
2887 * @param cls a `struct Neighbour`
2890 reassembly_cleanup_task (void *cls)
2892 struct Neighbour *n = cls;
2893 struct ReassemblyContext *rc;
2895 n->reassembly_timeout_task = NULL;
2896 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2898 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2901 free_reassembly_context (rc);
2904 GNUNET_assert (NULL == n->reassembly_timeout_task);
2905 n->reassembly_timeout_task =
2906 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2907 &reassembly_cleanup_task,
2915 * function called to #free_reassembly_context().
2919 * @param value a `struct ReassemblyContext` to free
2920 * @return #GNUNET_OK (continue iteration)
2923 free_reassembly_cb (void *cls, uint32_t key, void *value)
2925 struct ReassemblyContext *rc = value;
2929 free_reassembly_context (rc);
2935 * Release memory used by @a neighbour.
2937 * @param neighbour neighbour entry to free
2940 free_neighbour (struct Neighbour *neighbour)
2942 struct DistanceVectorHop *dvh;
2944 GNUNET_assert (NULL == neighbour->queue_head);
2945 GNUNET_assert (GNUNET_YES ==
2946 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2949 if (NULL != neighbour->reassembly_map)
2951 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2952 &free_reassembly_cb,
2954 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2955 neighbour->reassembly_map = NULL;
2956 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2957 neighbour->reassembly_heap = NULL;
2959 while (NULL != (dvh = neighbour->dv_head))
2961 struct DistanceVector *dv = dvh->dv;
2963 free_distance_vector_hop (dvh);
2964 if (NULL == dv->dv_head)
2967 if (NULL != neighbour->reassembly_timeout_task)
2969 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2970 neighbour->reassembly_timeout_task = NULL;
2972 if (NULL != neighbour->get)
2974 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2975 neighbour->get = NULL;
2977 if (NULL != neighbour->sc)
2979 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2980 neighbour->sc = NULL;
2982 GNUNET_free (neighbour);
2987 * Send message to CORE clients that we lost a connection.
2989 * @param tc client to inform (must be CORE client)
2990 * @param pid peer the connection is for
2993 core_send_connect_info (struct TransportClient *tc,
2994 const struct GNUNET_PeerIdentity *pid)
2996 struct GNUNET_MQ_Envelope *env;
2997 struct ConnectInfoMessage *cim;
2999 GNUNET_assert (CT_CORE == tc->type);
3000 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3002 GNUNET_MQ_send (tc->mq, env);
3007 * Send message to CORE clients that we gained a connection
3009 * @param pid peer the queue was for
3012 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3015 "Informing CORE clients about connection to %s\n",
3017 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3019 if (CT_CORE != tc->type)
3021 core_send_connect_info (tc, pid);
3027 * Send message to CORE clients that we lost a connection.
3029 * @param pid peer the connection was for
3032 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3035 "Informing CORE clients about disconnect from %s\n",
3037 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3039 struct GNUNET_MQ_Envelope *env;
3040 struct DisconnectInfoMessage *dim;
3042 if (CT_CORE != tc->type)
3044 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3046 GNUNET_MQ_send (tc->mq, env);
3052 * We believe we are ready to transmit a message on a queue. Gives the
3053 * message to the communicator for transmission (updating the tracker,
3054 * and re-scheduling itself if applicable).
3056 * @param cls the `struct Queue` to process transmissions for
3059 transmit_on_queue (void *cls);
3063 * Schedule next run of #transmit_on_queue(). Does NOTHING if
3064 * we should run immediately or if the message queue is empty.
3065 * Test for no task being added AND queue not being empty to
3066 * transmit immediately afterwards! This function must only
3067 * be called if the message queue is non-empty!
3069 * @param queue the queue to do scheduling for
3070 * @param inside_job set to #GNUNET_YES if called from
3071 * #transmit_on_queue() itself and NOT setting
3072 * the task means running immediately
3075 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3077 struct Neighbour *n = queue->neighbour;
3078 struct PendingMessage *pm = n->pending_msg_head;
3079 struct GNUNET_TIME_Relative out_delay;
3081 GNUNET_assert (NULL != pm);
3082 if (queue->tc->details.communicator.total_queue_length >=
3083 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3085 GNUNET_STATISTICS_update (
3087 "# Transmission throttled due to communicator queue limit",
3092 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3094 GNUNET_STATISTICS_update (GST_stats,
3095 "# Transmission throttled due to queue queue limit",
3101 out_delay = GNUNET_TIME_absolute_get_remaining (pm->next_attempt);
3102 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3105 GNUNET_ERROR_TYPE_DEBUG,
3106 "Schedule transmission on queue %llu of %s decides to run immediately\n",
3107 (unsigned long long) queue->qid,
3108 GNUNET_i2s (&n->pid));
3109 return; /* we should run immediately! */
3111 /* queue has changed since we were scheduled, reschedule again */
3112 queue->transmit_task =
3113 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3114 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3115 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3116 "Next transmission on queue `%s' in %s (high delay)\n",
3118 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3121 "Next transmission on queue `%s' in %s\n",
3123 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3128 * Task run to check whether the hops of the @a cls still
3129 * are validated, or if we need to core about disconnection.
3131 * @param cls a `struct VirtualLink`
3134 check_link_down (void *cls)
3136 struct VirtualLink *vl = cls;
3137 struct DistanceVector *dv = vl->dv;
3138 struct Neighbour *n = vl->n;
3139 struct GNUNET_TIME_Absolute dvh_timeout;
3140 struct GNUNET_TIME_Absolute q_timeout;
3142 vl->visibility_task = NULL;
3143 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3144 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3146 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3147 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3149 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3150 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3151 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3152 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3154 if ((NULL == vl->n) && (NULL == vl->dv))
3156 cores_send_disconnect_info (&dv->target);
3157 free_virtual_link (vl);
3160 vl->visibility_task =
3161 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3170 * @param queue the queue to free
3173 free_queue (struct Queue *queue)
3175 struct Neighbour *neighbour = queue->neighbour;
3176 struct TransportClient *tc = queue->tc;
3177 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3178 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3179 struct QueueEntry *qe;
3181 struct PendingAcknowledgement *pa;
3182 struct VirtualLink *vl;
3184 if (NULL != queue->transmit_task)
3186 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3187 queue->transmit_task = NULL;
3189 while (NULL != (pa = queue->pa_head))
3191 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3195 GNUNET_CONTAINER_MDLL_remove (neighbour,
3196 neighbour->queue_head,
3197 neighbour->queue_tail,
3199 GNUNET_CONTAINER_MDLL_remove (client,
3200 tc->details.communicator.queue_head,
3201 tc->details.communicator.queue_tail,
3203 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3204 tc->details.communicator.total_queue_length);
3205 while (NULL != (qe = queue->queue_head))
3207 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3208 queue->queue_length--;
3209 tc->details.communicator.total_queue_length--;
3212 GNUNET_assert (qe == qe->pm->qe);
3217 GNUNET_assert (0 == queue->queue_length);
3218 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3219 tc->details.communicator.total_queue_length))
3221 /* Communicator dropped below threshold, resume all queues */
3222 GNUNET_STATISTICS_update (
3224 "# Transmission throttled due to communicator queue limit",
3227 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3229 schedule_transmit_on_queue (s, GNUNET_NO);
3231 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3232 GNUNET_free (queue);
3234 vl = GNUNET_CONTAINER_multipeermap_get (links, &neighbour->pid);
3235 if ((NULL != vl) && (neighbour == vl->n))
3237 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3238 check_link_down (vl);
3240 if (NULL == neighbour->queue_head)
3242 free_neighbour (neighbour);
3250 * @param ale address list entry to free
3253 free_address_list_entry (struct AddressListEntry *ale)
3255 struct TransportClient *tc = ale->tc;
3257 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3258 tc->details.communicator.addr_tail,
3260 if (NULL != ale->sc)
3262 GNUNET_PEERSTORE_store_cancel (ale->sc);
3265 if (NULL != ale->st)
3267 GNUNET_SCHEDULER_cancel (ale->st);
3275 * Stop the peer request in @a value.
3277 * @param cls a `struct TransportClient` that no longer makes the request
3278 * @param pid the peer's identity
3279 * @param value a `struct PeerRequest`
3280 * @return #GNUNET_YES (always)
3283 stop_peer_request (void *cls,
3284 const struct GNUNET_PeerIdentity *pid,
3287 struct TransportClient *tc = cls;
3288 struct PeerRequest *pr = value;
3290 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3293 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3303 * Called whenever a client is disconnected. Frees our
3304 * resources associated with that client.
3306 * @param cls closure, NULL
3307 * @param client identification of the client
3308 * @param app_ctx our `struct TransportClient`
3311 client_disconnect_cb (void *cls,
3312 struct GNUNET_SERVICE_Client *client,
3315 struct TransportClient *tc = app_ctx;
3319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3320 "Client %p disconnected, cleaning up.\n",
3322 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3328 struct PendingMessage *pm;
3330 while (NULL != (pm = tc->details.core.pending_msg_head))
3332 GNUNET_CONTAINER_MDLL_remove (client,
3333 tc->details.core.pending_msg_head,
3334 tc->details.core.pending_msg_tail,
3342 case CT_COMMUNICATOR: {
3344 struct AddressListEntry *ale;
3346 while (NULL != (q = tc->details.communicator.queue_head))
3348 while (NULL != (ale = tc->details.communicator.addr_head))
3349 free_address_list_entry (ale);
3350 GNUNET_free (tc->details.communicator.address_prefix);
3353 case CT_APPLICATION:
3354 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3357 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3365 * Iterator telling new CORE client about all existing
3366 * connections to peers.
3368 * @param cls the new `struct TransportClient`
3369 * @param pid a connected peer
3370 * @param value the `struct Neighbour` with more information
3371 * @return #GNUNET_OK (continue to iterate)
3374 notify_client_connect_info (void *cls,
3375 const struct GNUNET_PeerIdentity *pid,
3378 struct TransportClient *tc = cls;
3381 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3382 "Telling new CORE client about existing connection to %s\n",
3384 core_send_connect_info (tc, pid);
3390 * Initialize a "CORE" client. We got a start message from this
3391 * client, so add it to the list of clients for broadcasting of
3394 * @param cls the client
3395 * @param start the start message that was sent
3398 handle_client_start (void *cls, const struct StartMessage *start)
3400 struct TransportClient *tc = cls;
3403 options = ntohl (start->options);
3404 if ((0 != (1 & options)) &&
3405 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3407 /* client thinks this is a different peer, reject */
3409 GNUNET_SERVICE_client_drop (tc->client);
3412 if (CT_NONE != tc->type)
3415 GNUNET_SERVICE_client_drop (tc->client);
3419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3420 "New CORE client with PID %s registered\n",
3421 GNUNET_i2s (&start->self));
3422 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3423 ¬ify_client_connect_info,
3425 GNUNET_SERVICE_client_continue (tc->client);
3430 * Client asked for transmission to a peer. Process the request.
3432 * @param cls the client
3433 * @param obm the send message that was sent
3436 check_client_send (void *cls, const struct OutboundMessage *obm)
3438 struct TransportClient *tc = cls;
3440 const struct GNUNET_MessageHeader *obmm;
3442 if (CT_CORE != tc->type)
3445 return GNUNET_SYSERR;
3447 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3448 if (size < sizeof (struct GNUNET_MessageHeader))
3451 return GNUNET_SYSERR;
3453 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3454 if (size != ntohs (obmm->size))
3457 return GNUNET_SYSERR;
3464 * Free fragment tree below @e root, excluding @e root itself.
3465 * FIXME: this does NOT seem to have the intended semantics
3466 * based on how this is called. Seems we generally DO expect
3467 * @a root to be free'ed itself as well!
3469 * @param root root of the tree to free
3472 free_fragment_tree (struct PendingMessage *root)
3474 struct PendingMessage *frag;
3476 while (NULL != (frag = root->head_frag))
3478 struct PendingAcknowledgement *pa;
3480 free_fragment_tree (frag);
3481 while (NULL != (pa = frag->pa_head))
3483 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3486 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3493 * Release memory associated with @a pm and remove @a pm from associated
3494 * data structures. @a pm must be a top-level pending message and not
3495 * a fragment in the tree. The entire tree is freed (if applicable).
3497 * @param pm the pending message to free
3500 free_pending_message (struct PendingMessage *pm)
3502 struct TransportClient *tc = pm->client;
3503 struct Neighbour *target = pm->target;
3504 struct DistanceVectorHop *dvh = pm->dvh;
3505 struct PendingAcknowledgement *pa;
3509 GNUNET_CONTAINER_MDLL_remove (client,
3510 tc->details.core.pending_msg_head,
3511 tc->details.core.pending_msg_tail,
3516 GNUNET_CONTAINER_MDLL_remove (dvh,
3517 dvh->pending_msg_head,
3518 dvh->pending_msg_tail,
3521 GNUNET_CONTAINER_MDLL_remove (neighbour,
3522 target->pending_msg_head,
3523 target->pending_msg_tail,
3525 while (NULL != (pa = pm->pa_head))
3527 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3531 free_fragment_tree (pm);
3534 GNUNET_assert (pm == pm->qe->pm);
3537 GNUNET_free_non_null (pm->bpm);
3543 * Send a response to the @a pm that we have processed a "send"
3544 * request. Sends a confirmation to the "core" client responsible for
3545 * the original request and free's @a pm.
3547 * @param pm handle to the original pending message
3550 client_send_response (struct PendingMessage *pm)
3552 struct TransportClient *tc = pm->client;
3553 struct Neighbour *target = pm->target;
3554 struct GNUNET_MQ_Envelope *env;
3555 struct SendOkMessage *som;
3559 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3560 som->peer = target->pid;
3561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3562 "Confirming transmission to %s\n",
3563 GNUNET_i2s (&pm->target->pid));
3564 GNUNET_MQ_send (tc->mq, env);
3566 free_pending_message (pm);
3571 * Create a DV Box message.
3573 * @param total_hops how many hops did the message take so far
3574 * @param num_hops length of the @a hops array
3575 * @param origin origin of the message
3576 * @param hops next peer(s) to the destination, including destination
3577 * @param payload payload of the box
3578 * @param payload_size number of bytes in @a payload
3579 * @return boxed message (caller must #GNUNET_free() it).
3581 static struct TransportDVBoxMessage *
3582 create_dv_box (uint16_t total_hops,
3583 const struct GNUNET_PeerIdentity *origin,
3584 const struct GNUNET_PeerIdentity *target,
3586 const struct GNUNET_PeerIdentity *hops,
3587 const void *payload,
3588 uint16_t payload_size)
3590 struct TransportDVBoxMessage *dvb;
3591 struct GNUNET_PeerIdentity *dhops;
3593 GNUNET_assert (UINT16_MAX <
3594 sizeof (struct TransportDVBoxMessage) +
3595 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3597 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3598 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3601 htons (sizeof (struct TransportDVBoxMessage) +
3602 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3603 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3604 dvb->total_hops = htons (total_hops);
3605 dvb->num_hops = htons (num_hops + 1);
3606 dvb->origin = *origin;
3607 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3608 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3609 dhops[num_hops] = *target;
3610 memcpy (&dhops[num_hops + 1], payload, payload_size);
3612 if (GNUNET_EXTRA_LOGGING > 0)
3616 path = GNUNET_strdup (GNUNET_i2s (&dvb->origin));
3617 for (unsigned int i = 0; i <= num_hops; i++)
3621 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
3625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3626 "Creating DVBox for %u bytes of payload via %s\n",
3627 (unsigned int) payload_size,
3637 * Pick @a hops_array_length random DV paths satisfying @a options
3639 * @param dv data structure to pick paths from
3640 * @param options constraints to satisfy
3641 * @param hops_array[out] set to the result
3642 * @param hops_array_length length of the @a hops_array
3643 * @return number of entries set in @a hops_array
3646 pick_random_dv_hops (const struct DistanceVector *dv,
3647 enum RouteMessageOptions options,
3648 struct DistanceVectorHop **hops_array,
3649 unsigned int hops_array_length)
3651 uint64_t choices[hops_array_length];
3653 unsigned int dv_count;
3655 /* Pick random vectors, but weighted by distance, giving more weight
3656 to shorter vectors */
3659 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3662 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3663 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3664 .rel_value_us == 0))
3665 continue; /* pos unconfirmed and confirmed required */
3666 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3671 if (dv_count <= hops_array_length)
3674 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3676 hops_array[dv_count++] = pos;
3679 for (unsigned int i = 0; i < hops_array_length; i++)
3682 while (GNUNET_NO == ok)
3685 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3687 for (unsigned int j = 0; j < i; j++)
3688 if (choices[i] == choices[j])
3697 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3700 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3702 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3703 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3704 .rel_value_us == 0))
3705 continue; /* pos unconfirmed and confirmed required */
3706 for (unsigned int i = 0; i < hops_array_length; i++)
3707 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3708 hops_array[dv_count++] = pos;
3716 * Client asked for transmission to a peer. Process the request.
3718 * @param cls the client
3719 * @param obm the send message that was sent
3722 handle_client_send (void *cls, const struct OutboundMessage *obm)
3724 struct TransportClient *tc = cls;
3725 struct PendingMessage *pm;
3726 const struct GNUNET_MessageHeader *obmm;
3727 struct Neighbour *target;
3728 struct DistanceVector *dv;
3729 struct DistanceVectorHop *dvh;
3732 const void *payload;
3733 size_t payload_size;
3734 struct TransportDVBoxMessage *dvb;
3735 struct VirtualLink *vl;
3737 GNUNET_assert (CT_CORE == tc->type);
3738 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3739 bytes_msg = ntohs (obmm->size);
3740 vl = GNUNET_CONTAINER_multipeermap_get (links, &obm->peer);
3743 /* Failure: don't have this peer as a neighbour (anymore).
3744 Might have gone down asynchronously, so this is NOT
3745 a protocol violation by CORE. Still count the event,
3746 as this should be rare. */
3747 GNUNET_SERVICE_client_continue (tc->client);
3748 GNUNET_STATISTICS_update (GST_stats,
3749 "# messages dropped (neighbour unknown)",
3754 target = lookup_neighbour (&obm->peer);
3756 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3759 GNUNET_assert ((NULL != target) || (NULL != dv));
3760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3761 "Sending %u bytes to %s using %s\n",
3763 GNUNET_i2s (&obm->peer),
3764 (NULL == target) ? "distance vector path" : "direct queue");
3768 struct DistanceVectorHop *dvh;
3770 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3771 GNUNET_assert (1 == res);
3772 target = dvh->next_hop;
3773 dvb = create_dv_box (0,
3781 payload_size = ntohs (dvb->header.size);
3788 payload_size = bytes_msg;
3791 was_empty = (NULL == target->pending_msg_head);
3792 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3794 pm->target = target;
3795 pm->bytes_msg = payload_size;
3796 memcpy (&pm[1], payload, payload_size);
3797 GNUNET_free_non_null (dvb);
3802 GNUNET_CONTAINER_MDLL_insert (dvh,
3803 dvh->pending_msg_head,
3804 dvh->pending_msg_tail,
3807 GNUNET_CONTAINER_MDLL_insert (neighbour,
3808 target->pending_msg_head,
3809 target->pending_msg_tail,
3811 GNUNET_CONTAINER_MDLL_insert (client,
3812 tc->details.core.pending_msg_head,
3813 tc->details.core.pending_msg_tail,
3816 return; /* all queues must already be busy */
3817 for (struct Queue *queue = target->queue_head; NULL != queue;
3818 queue = queue->next_neighbour)
3820 /* try transmission on any queue that is idle */
3821 if (NULL == queue->transmit_task)
3823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3824 "Queue %llu to %s is idle, triggering transmission\n",
3825 (unsigned long long) queue->qid,
3826 GNUNET_i2s (&queue->neighbour->pid));
3827 queue->transmit_task =
3828 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3835 * Communicator started. Test message is well-formed.
3837 * @param cls the client
3838 * @param cam the send message that was sent
3841 check_communicator_available (
3843 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3845 struct TransportClient *tc = cls;
3848 if (CT_NONE != tc->type)
3851 return GNUNET_SYSERR;
3853 tc->type = CT_COMMUNICATOR;
3854 size = ntohs (cam->header.size) - sizeof (*cam);
3856 return GNUNET_OK; /* receive-only communicator */
3857 GNUNET_MQ_check_zero_termination (cam);
3863 * Send ACK to communicator (if requested) and free @a cmc.
3865 * @param cmc context for which we are done handling the message
3868 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3870 if (0 != ntohl (cmc->im.fc_on))
3872 /* send ACK when done to communicator for flow control! */
3873 struct GNUNET_MQ_Envelope *env;
3874 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3876 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3877 ack->reserved = htonl (0);
3878 ack->fc_id = cmc->im.fc_id;
3879 ack->sender = cmc->im.sender;
3880 GNUNET_MQ_send (cmc->tc->mq, env);
3882 GNUNET_SERVICE_client_continue (cmc->tc->client);
3888 * Client confirms that it is done handling message(s) to a particular
3889 * peer. We may now provide more messages to CORE for this peer.
3891 * Notifies the respective queues that more messages can now be received.
3893 * @param cls the client
3894 * @param rom the message that was sent
3897 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
3899 struct TransportClient *tc = cls;
3900 struct VirtualLink *vl;
3902 struct CommunicatorMessageContext *cmc;
3904 if (CT_CORE != tc->type)
3907 GNUNET_SERVICE_client_drop (tc->client);
3910 vl = GNUNET_CONTAINER_multipeermap_get (links, &rom->peer);
3913 GNUNET_STATISTICS_update (GST_stats,
3914 "# RECV_OK dropped: virtual link unknown",
3917 GNUNET_SERVICE_client_continue (tc->client);
3920 delta = ntohl (rom->increase_window_delta);
3921 vl->core_recv_window += delta;
3922 if (vl->core_recv_window <= 0)
3924 /* resume communicators */
3925 while (NULL != (cmc = vl->cmc_tail))
3927 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
3928 finish_cmc_handling (cmc);
3934 * Communicator started. Process the request.
3936 * @param cls the client
3937 * @param cam the send message that was sent
3940 handle_communicator_available (
3942 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3944 struct TransportClient *tc = cls;
3947 size = ntohs (cam->header.size) - sizeof (*cam);
3950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3951 "Receive-only communicator connected\n");
3952 return; /* receive-only communicator */
3954 tc->details.communicator.address_prefix =
3955 GNUNET_strdup ((const char *) &cam[1]);
3956 tc->details.communicator.cc =
3957 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3959 "Communicator with prefix `%s' connected\n",
3960 tc->details.communicator.address_prefix);
3961 GNUNET_SERVICE_client_continue (tc->client);
3966 * Communicator requests backchannel transmission. Check the request.
3968 * @param cls the client
3969 * @param cb the send message that was sent
3970 * @return #GNUNET_OK if message is well-formed
3973 check_communicator_backchannel (
3975 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3977 const struct GNUNET_MessageHeader *inbox;
3983 msize = ntohs (cb->header.size) - sizeof (*cb);
3984 if (((size_t) (UINT16_MAX - msize)) >
3985 sizeof (struct TransportBackchannelEncapsulationMessage) +
3986 sizeof (struct TransportBackchannelRequestPayloadP))
3989 return GNUNET_SYSERR;
3991 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3992 isize = ntohs (inbox->size);
3996 return GNUNET_SYSERR;
3998 is = (const char *) inbox;
4001 GNUNET_assert (msize > 0);
4002 if ('\0' != is[msize - 1])
4005 return GNUNET_SYSERR;
4012 * Remove memory used by expired ephemeral keys.
4017 expire_ephemerals (void *cls)
4019 struct EphemeralCacheEntry *ece;
4022 ephemeral_task = NULL;
4023 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
4025 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4028 free_ephemeral (ece);
4031 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4040 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists,
4041 * generate one, cache it and return it.
4043 * @param pid peer to look up ephemeral for
4044 * @param private_key[out] set to the private key
4045 * @param ephemeral_key[out] set to the key
4046 * @param ephemeral_sender_sig[out] set to the signature
4047 * @param monotime[out] set to the monotime used for the signature
4050 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
4051 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
4052 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
4053 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
4054 struct GNUNET_TIME_Absolute *monotime)
4056 struct EphemeralCacheEntry *ece;
4057 struct EphemeralConfirmationPS ec;
4059 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
4060 if ((NULL != ece) &&
4061 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4064 free_ephemeral (ece);
4069 ece = GNUNET_new (struct EphemeralCacheEntry);
4071 ece->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4072 ece->ephemeral_validity =
4073 GNUNET_TIME_absolute_add (ece->monotime, EPHEMERAL_VALIDITY);
4074 GNUNET_assert (GNUNET_OK ==
4075 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
4076 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
4077 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4078 ec.purpose.size = htonl (sizeof (ec));
4080 ec.ephemeral_key = ece->ephemeral_key;
4081 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4085 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
4087 ece->ephemeral_validity.abs_value_us);
4088 GNUNET_assert (GNUNET_OK ==
4089 GNUNET_CONTAINER_multipeermap_put (
4093 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4094 if (NULL == ephemeral_task)
4095 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4099 *private_key = ece->private_key;
4100 *ephemeral_key = ece->ephemeral_key;
4101 *ephemeral_sender_sig = ece->sender_sig;
4102 *monotime = ece->monotime;
4107 * Send the control message @a payload on @a queue.
4109 * @param queue the queue to use for transmission
4110 * @param pm pending message to update once transmission is done, may be NULL!
4111 * @param payload the payload to send (encapsulated in a
4112 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4113 * @param payload_size number of bytes in @a payload
4116 queue_send_msg (struct Queue *queue,
4117 struct PendingMessage *pm,
4118 const void *payload,
4119 size_t payload_size)
4121 struct Neighbour *n = queue->neighbour;
4122 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4123 struct GNUNET_MQ_Envelope *env;
4125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4126 "Queueing %u bytes of payload for transmission on queue %llu to %s\n",
4127 (unsigned int) payload_size,
4128 (unsigned long long) queue->qid,
4129 GNUNET_i2s (&queue->neighbour->pid));
4130 env = GNUNET_MQ_msg_extra (smt,
4132 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4133 smt->qid = queue->qid;
4134 smt->mid = queue->mid_gen;
4135 smt->receiver = n->pid;
4136 memcpy (&smt[1], payload, payload_size);
4138 /* Pass the env to the communicator of queue for transmission. */
4139 struct QueueEntry *qe;
4141 qe = GNUNET_new (struct QueueEntry);
4142 qe->mid = queue->mid_gen++;
4147 GNUNET_assert (NULL == pm->qe);
4150 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4151 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4152 queue->queue_length++;
4153 queue->tc->details.communicator.total_queue_length++;
4154 GNUNET_MQ_send (queue->tc->mq, env);
4159 // FIXME: improve logging after this point!
4162 * Pick a queue of @a n under constraints @a options and schedule
4163 * transmission of @a hdr.
4165 * @param n neighbour to send to
4166 * @param hdr message to send as payload
4167 * @param options whether queues must be confirmed or not,
4168 * and whether we may pick multiple (2) queues
4171 route_via_neighbour (const struct Neighbour *n,
4172 const struct GNUNET_MessageHeader *hdr,
4173 enum RouteMessageOptions options)
4175 struct GNUNET_TIME_Absolute now;
4176 unsigned int candidates;
4180 /* Pick one or two 'random' queues from n (under constraints of options) */
4181 now = GNUNET_TIME_absolute_get ();
4182 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4183 weight in the future; weight could be assigned by observed
4184 bandwidth (note: not sure if we should do this for this type
4185 of control traffic though). */
4187 for (struct Queue *pos = n->queue_head; NULL != pos;
4188 pos = pos->next_neighbour)
4190 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4191 (pos->validated_until.abs_value_us > now.abs_value_us))
4194 if (0 == candidates)
4196 /* This can happen rarely if the last confirmed queue timed
4197 out just as we were beginning to process this message. */
4198 GNUNET_STATISTICS_update (GST_stats,
4199 "# route selection failed (all no valid queue)",
4204 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4205 if (0 == (options & RMO_REDUNDANT))
4206 sel2 = candidates; /* picks none! */
4208 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4210 for (struct Queue *pos = n->queue_head; NULL != pos;
4211 pos = pos->next_neighbour)
4213 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4214 (pos->validated_until.abs_value_us > now.abs_value_us))
4216 if ((sel1 == candidates) || (sel2 == candidates))
4217 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4225 * Given a distance vector path @a dvh route @a payload to
4226 * the ultimate destination respecting @a options.
4227 * Sets up the boxed message and queues it at the next hop.
4229 * @param dvh choice of the path for the message
4230 * @param payload body to transmit
4231 * @param options options to use for control
4234 forward_via_dvh (const struct DistanceVectorHop *dvh,
4235 const struct GNUNET_MessageHeader *payload,
4236 enum RouteMessageOptions options)
4238 struct TransportDVBoxMessage *dvb;
4240 dvb = create_dv_box (0,
4246 ntohs (payload->size));
4247 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4253 * Pick a path of @a dv under constraints @a options and schedule
4254 * transmission of @a hdr.
4256 * @param n neighbour to send to
4257 * @param hdr message to send as payload
4258 * @param options whether path must be confirmed or not
4259 * and whether we may pick multiple (2) paths
4262 route_via_dv (const struct DistanceVector *dv,
4263 const struct GNUNET_MessageHeader *hdr,
4264 enum RouteMessageOptions options)
4266 struct DistanceVectorHop *hops[2];
4269 res = pick_random_dv_hops (dv,
4272 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4273 for (unsigned int i = 0; i < res; i++)
4274 forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT));
4279 * We need to transmit @a hdr to @a target. If necessary, this may
4280 * involve DV routing.
4282 * @param target peer to receive @a hdr
4283 * @param hdr header of the message to route and #GNUNET_free()
4284 * @param options which transmission channels are allowed
4287 route_message (const struct GNUNET_PeerIdentity *target,
4288 struct GNUNET_MessageHeader *hdr,
4289 enum RouteMessageOptions options)
4291 struct VirtualLink *vl;
4292 struct Neighbour *n;
4293 struct DistanceVector *dv;
4295 vl = GNUNET_CONTAINER_multipeermap_get (links, target);
4297 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4298 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4300 /* if confirmed is required, and we do not have anything
4301 confirmed, drop respective options */
4303 n = lookup_neighbour (target);
4304 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4305 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4307 if ((NULL == n) && (NULL == dv))
4309 GNUNET_STATISTICS_update (GST_stats,
4310 "# Messages dropped in routing: no acceptable method",
4316 /* If both dv and n are possible and we must choose:
4317 flip a coin for the choice between the two; for now 50/50 */
4318 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4320 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4325 if ((NULL != n) && (NULL != dv))
4326 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4327 enough for redunancy, so clear the flag. */
4330 route_via_neighbour (n, hdr, options);
4334 route_via_dv (dv, hdr, options);
4341 * Structure of the key material used to encrypt backchannel messages.
4343 struct BackchannelKeyState
4346 * State of our block cipher.
4348 gcry_cipher_hd_t cipher;
4351 * Actual key material.
4357 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4359 struct GNUNET_CRYPTO_AuthKey hmac_key;
4362 * Symmetric key to use for encryption.
4364 char aes_key[256 / 8];
4367 * Counter value to use during setup.
4369 char aes_ctr[128 / 8];
4376 * Given the key material in @a km and the initialization vector
4377 * @a iv, setup the key material for the backchannel in @a key.
4379 * @param km raw master secret
4380 * @param iv initialization vector
4381 * @param key[out] symmetric cipher and HMAC state to generate
4384 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4385 const struct GNUNET_ShortHashCode *iv,
4386 struct BackchannelKeyState *key)
4388 /* must match #dh_key_derive_eph_pub */
4389 GNUNET_assert (GNUNET_YES ==
4390 GNUNET_CRYPTO_kdf (&key->material,
4391 sizeof (key->material),
4392 "transport-backchannel-key",
4393 strlen ("transport-backchannel-key"),
4398 gcry_cipher_open (&key->cipher,
4399 GCRY_CIPHER_AES256 /* low level: go for speed */,
4400 GCRY_CIPHER_MODE_CTR,
4402 gcry_cipher_setkey (key->cipher,
4403 &key->material.aes_key,
4404 sizeof (key->material.aes_key));
4405 gcry_cipher_setctr (key->cipher,
4406 &key->material.aes_ctr,
4407 sizeof (key->material.aes_ctr));
4412 * Derive backchannel encryption key material from @a priv_ephemeral
4413 * and @a target and @a iv.
4415 * @param priv_ephemeral ephemeral private key to use
4416 * @param target the target peer to encrypt to
4417 * @param iv unique IV to use
4418 * @param key[out] set to the key material
4421 dh_key_derive_eph_pid (
4422 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4423 const struct GNUNET_PeerIdentity *target,
4424 const struct GNUNET_ShortHashCode *iv,
4425 struct BackchannelKeyState *key)
4427 struct GNUNET_HashCode km;
4429 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4430 &target->public_key,
4432 bc_setup_key_state_from_km (&km, iv, key);
4437 * Derive backchannel encryption key material from #GST_my_private_key
4438 * and @a pub_ephemeral and @a iv.
4440 * @param priv_ephemeral ephemeral private key to use
4441 * @param target the target peer to encrypt to
4442 * @param iv unique IV to use
4443 * @param key[out] set to the key material
4446 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4447 const struct GNUNET_ShortHashCode *iv,
4448 struct BackchannelKeyState *key)
4450 struct GNUNET_HashCode km;
4452 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4455 bc_setup_key_state_from_km (&km, iv, key);
4460 * Do HMAC calculation for backchannel messages over @a data using key
4461 * material from @a key.
4463 * @param key key material (from DH)
4464 * @param hmac[out] set to the HMAC
4465 * @param data data to perform HMAC calculation over
4466 * @param data_size number of bytes in @a data
4469 bc_hmac (const struct BackchannelKeyState *key,
4470 struct GNUNET_HashCode *hmac,
4474 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4479 * Perform backchannel encryption using symmetric secret in @a key
4480 * to encrypt data from @a in to @a dst.
4482 * @param key[in,out] key material to use
4483 * @param dst where to write the result
4484 * @param in input data to encrypt (plaintext)
4485 * @param in_size number of bytes of input in @a in and available at @a dst
4488 bc_encrypt (struct BackchannelKeyState *key,
4494 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4499 * Perform backchannel encryption using symmetric secret in @a key
4500 * to encrypt data from @a in to @a dst.
4502 * @param key[in,out] key material to use
4503 * @param ciph cipher text to decrypt
4504 * @param out[out] output data to generate (plaintext)
4505 * @param out_size number of bytes of input in @a ciph and available in @a out
4508 bc_decrypt (struct BackchannelKeyState *key,
4514 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4519 * Clean up key material in @a key.
4521 * @param key key material to clean up (memory must not be free'd!)
4524 bc_key_clean (struct BackchannelKeyState *key)
4526 gcry_cipher_close (key->cipher);
4527 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4532 * Communicator requests backchannel transmission. Process the request.
4534 * @param cls the client
4535 * @param cb the send message that was sent
4538 handle_communicator_backchannel (
4540 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4542 struct TransportClient *tc = cls;
4543 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4544 struct GNUNET_TIME_Absolute monotime;
4545 struct TransportBackchannelEncapsulationMessage *enc;
4546 struct TransportBackchannelRequestPayloadP ppay;
4547 struct BackchannelKeyState key;
4551 /* encapsulate and encrypt message */
4552 msize = ntohs (cb->header.size) - sizeof (*cb) +
4553 sizeof (struct TransportBackchannelRequestPayloadP);
4554 enc = GNUNET_malloc (sizeof (*enc) + msize);
4556 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4557 enc->header.size = htons (sizeof (*enc) + msize);
4558 enc->target = cb->pid;
4559 lookup_ephemeral (&cb->pid,
4561 &enc->ephemeral_key,
4564 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4567 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4568 ppay.monotonic_time = GNUNET_TIME_absolute_hton (monotime);
4569 mpos = (char *) &enc[1];
4570 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4573 &mpos[sizeof (ppay)],
4574 ntohs (cb->header.size) - sizeof (*cb));
4578 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4579 bc_key_clean (&key);
4580 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4581 GNUNET_SERVICE_client_continue (tc->client);
4586 * Address of our peer added. Test message is well-formed.
4588 * @param cls the client
4589 * @param aam the send message that was sent
4590 * @return #GNUNET_OK if message is well-formed
4593 check_add_address (void *cls,
4594 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4596 struct TransportClient *tc = cls;
4598 if (CT_COMMUNICATOR != tc->type)
4601 return GNUNET_SYSERR;
4603 GNUNET_MQ_check_zero_termination (aam);
4609 * Ask peerstore to store our address.
4611 * @param cls an `struct AddressListEntry *`
4614 store_pi (void *cls);
4618 * Function called when peerstore is done storing our address.
4620 * @param cls a `struct AddressListEntry`
4621 * @param success #GNUNET_YES if peerstore was successful
4624 peerstore_store_own_cb (void *cls, int success)
4626 struct AddressListEntry *ale = cls;
4629 if (GNUNET_YES != success)
4630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4631 "Failed to store our own address `%s' in peerstore!\n",
4633 /* refresh period is 1/4 of expiration time, that should be plenty
4634 without being excessive. */
4636 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4644 * Ask peerstore to store our address.
4646 * @param cls an `struct AddressListEntry *`
4649 store_pi (void *cls)
4651 struct AddressListEntry *ale = cls;
4654 struct GNUNET_TIME_Absolute expiration;
4657 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4658 GNUNET_HELLO_sign_address (ale->address,
4664 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4667 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4671 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4672 &peerstore_store_own_cb,
4675 if (NULL == ale->sc)
4677 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4678 "Failed to store our address `%s' with peerstore\n",
4681 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4687 * Address of our peer added. Process the request.
4689 * @param cls the client
4690 * @param aam the send message that was sent
4693 handle_add_address (void *cls,
4694 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4696 struct TransportClient *tc = cls;
4697 struct AddressListEntry *ale;
4700 slen = ntohs (aam->header.size) - sizeof (*aam);
4701 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4703 ale->address = (const char *) &ale[1];
4704 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4705 ale->aid = aam->aid;
4706 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4707 memcpy (&ale[1], &aam[1], slen);
4708 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4709 tc->details.communicator.addr_tail,
4711 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4712 GNUNET_SERVICE_client_continue (tc->client);
4717 * Address of our peer deleted. Process the request.
4719 * @param cls the client
4720 * @param dam the send message that was sent
4723 handle_del_address (void *cls,
4724 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4726 struct TransportClient *tc = cls;
4728 if (CT_COMMUNICATOR != tc->type)
4731 GNUNET_SERVICE_client_drop (tc->client);
4734 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4738 if (dam->aid != ale->aid)
4740 GNUNET_assert (ale->tc == tc);
4741 free_address_list_entry (ale);
4742 GNUNET_SERVICE_client_continue (tc->client);
4745 GNUNET_SERVICE_client_drop (tc->client);
4750 * Given an inbound message @a msg from a communicator @a cmc,
4751 * demultiplex it based on the type calling the right handler.
4753 * @param cmc context for demultiplexing
4754 * @param msg message to demultiplex
4757 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4758 const struct GNUNET_MessageHeader *msg);
4762 * Communicator gave us an unencapsulated message to pass as-is to
4763 * CORE. Process the request.
4765 * @param cls a `struct CommunicatorMessageContext` (must call
4766 * #finish_cmc_handling() when done)
4767 * @param mh the message that was received
4770 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4772 struct CommunicatorMessageContext *cmc = cls;
4773 struct VirtualLink *vl;
4774 uint16_t size = ntohs (mh->size);
4776 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4777 (size < sizeof (struct GNUNET_MessageHeader)))
4779 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4782 finish_cmc_handling (cmc);
4783 GNUNET_SERVICE_client_drop (client);
4786 vl = GNUNET_CONTAINER_multipeermap_get (links, &cmc->im.sender);
4789 /* FIXME: sender is giving us messages for CORE but we don't have
4790 the link up yet! I *suspect* this can happen right now (i.e.
4791 sender has verified us, but we didn't verify sender), but if
4792 we pass this on, CORE would be confused (link down, messages
4793 arrive). We should investigate more if this happens often,
4794 or in a persistent manner, and possibly do "something" about
4795 it. Thus logging as error for now. */
4796 GNUNET_break_op (0);
4797 GNUNET_STATISTICS_update (GST_stats,
4798 "# CORE messages droped (virtual link still down)",
4802 finish_cmc_handling (cmc);
4805 /* Forward to all CORE clients */
4806 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4808 struct GNUNET_MQ_Envelope *env;
4809 struct InboundMessage *im;
4811 if (CT_CORE != tc->type)
4813 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4814 im->peer = cmc->im.sender;
4815 memcpy (&im[1], mh, size);
4816 GNUNET_MQ_send (tc->mq, env);
4818 vl->core_recv_window--;
4819 if (vl->core_recv_window > 0)
4821 finish_cmc_handling (cmc);
4824 /* Wait with calling #finish_cmc_handling(cmc) until the message
4825 was processed by CORE MQs (for CORE flow control)! */
4826 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
4831 * Communicator gave us a fragment box. Check the message.
4833 * @param cls a `struct CommunicatorMessageContext`
4834 * @param fb the send message that was sent
4835 * @return #GNUNET_YES if message is well-formed
4838 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4840 uint16_t size = ntohs (fb->header.size);
4841 uint16_t bsize = size - sizeof (*fb);
4846 GNUNET_break_op (0);
4847 return GNUNET_SYSERR;
4849 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4851 GNUNET_break_op (0);
4852 return GNUNET_SYSERR;
4854 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4856 GNUNET_break_op (0);
4857 return GNUNET_SYSERR;
4864 * Clean up an idle cummulative acknowledgement data structure.
4866 * @param cls a `struct AcknowledgementCummulator *`
4869 destroy_ack_cummulator (void *cls)
4871 struct AcknowledgementCummulator *ac = cls;
4874 GNUNET_assert (0 == ac->num_acks);
4877 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4883 * Do the transmission of a cummulative acknowledgement now.
4885 * @param cls a `struct AcknowledgementCummulator *`
4888 transmit_cummulative_ack_cb (void *cls)
4890 struct AcknowledgementCummulator *ac = cls;
4891 struct TransportReliabilityAckMessage *ack;
4892 struct TransportCummulativeAckPayloadP *ap;
4895 GNUNET_assert (0 < ac->ack_counter);
4896 ack = GNUNET_malloc (sizeof (*ack) +
4898 sizeof (struct TransportCummulativeAckPayloadP));
4899 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4901 htons (sizeof (*ack) +
4902 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4903 ack->ack_counter = htonl (ac->ack_counter++);
4904 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4905 for (unsigned int i = 0; i < ac->ack_counter; i++)
4907 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4908 ap[i].ack_delay = GNUNET_TIME_relative_hton (
4909 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
4911 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
4913 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
4914 &destroy_ack_cummulator,
4920 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
4921 * transmission by at most @a ack_delay.
4923 * @param pid target peer
4924 * @param ack_uuid UUID to ack
4925 * @param max_delay how long can the ACK wait
4928 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
4929 const struct AcknowledgementUUIDP *ack_uuid,
4930 struct GNUNET_TIME_Absolute max_delay)
4932 struct AcknowledgementCummulator *ac;
4934 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
4937 ac = GNUNET_new (struct AcknowledgementCummulator);
4939 ac->min_transmission_time = max_delay;
4940 GNUNET_assert (GNUNET_YES ==
4941 GNUNET_CONTAINER_multipeermap_put (
4945 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4949 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
4951 /* must run immediately, ack buffer full! */
4952 GNUNET_SCHEDULER_cancel (ac->task);
4953 transmit_cummulative_ack_cb (ac);
4955 GNUNET_SCHEDULER_cancel (ac->task);
4956 ac->min_transmission_time =
4957 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
4959 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
4960 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
4961 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
4963 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
4964 &transmit_cummulative_ack_cb,
4970 * Closure for #find_by_message_uuid.
4972 struct FindByMessageUuidContext
4977 struct MessageUUIDP message_uuid;
4980 * Set to the reassembly context if found.
4982 struct ReassemblyContext *rc;
4987 * Iterator called to find a reassembly context by the message UUID in the
4990 * @param cls a `struct FindByMessageUuidContext`
4991 * @param key a key (unused)
4992 * @param value a `struct ReassemblyContext`
4993 * @return #GNUNET_YES if not found, #GNUNET_NO if found
4996 find_by_message_uuid (void *cls, uint32_t key, void *value)
4998 struct FindByMessageUuidContext *fc = cls;
4999 struct ReassemblyContext *rc = value;
5002 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5012 * Communicator gave us a fragment. Process the request.
5014 * @param cls a `struct CommunicatorMessageContext` (must call
5015 * #finish_cmc_handling() when done)
5016 * @param fb the message that was received
5019 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5021 struct CommunicatorMessageContext *cmc = cls;
5022 struct Neighbour *n;
5023 struct ReassemblyContext *rc;
5024 const struct GNUNET_MessageHeader *msg;
5029 struct GNUNET_TIME_Relative cdelay;
5030 struct FindByMessageUuidContext fc;
5032 n = lookup_neighbour (&cmc->im.sender);
5035 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5038 finish_cmc_handling (cmc);
5039 GNUNET_SERVICE_client_drop (client);
5042 if (NULL == n->reassembly_map)
5044 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5045 n->reassembly_heap =
5046 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5047 n->reassembly_timeout_task =
5048 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5049 &reassembly_cleanup_task,
5052 msize = ntohs (fb->msg_size);
5053 fc.message_uuid = fb->msg_uuid;
5055 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5057 &find_by_message_uuid,
5059 if (NULL == (rc = fc.rc))
5061 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5062 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5063 rc->msg_uuid = fb->msg_uuid;
5065 rc->msg_size = msize;
5066 rc->reassembly_timeout =
5067 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5068 rc->last_frag = GNUNET_TIME_absolute_get ();
5069 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5071 rc->reassembly_timeout.abs_value_us);
5072 GNUNET_assert (GNUNET_OK ==
5073 GNUNET_CONTAINER_multihashmap32_put (
5077 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5078 target = (char *) &rc[1];
5079 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5080 rc->msg_missing = rc->msg_size;
5084 target = (char *) &rc[1];
5086 if (msize != rc->msg_size)
5089 finish_cmc_handling (cmc);
5094 fsize = ntohs (fb->header.size) - sizeof (*fb);
5098 finish_cmc_handling (cmc);
5101 frag_off = ntohs (fb->frag_off);
5102 memcpy (&target[frag_off], &fb[1], fsize);
5103 /* update bitfield and msg_missing */
5104 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5106 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5108 rc->bitfield[i / 8] |= (1 << (i % 8));
5113 /* Compute cummulative ACK */
5114 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5115 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5116 if (0 == rc->msg_missing)
5117 cdelay = GNUNET_TIME_UNIT_ZERO;
5118 cummulative_ack (&cmc->im.sender,
5120 GNUNET_TIME_relative_to_absolute (cdelay));
5121 rc->last_frag = GNUNET_TIME_absolute_get ();
5122 /* is reassembly complete? */
5123 if (0 != rc->msg_missing)
5125 finish_cmc_handling (cmc);
5128 /* reassembly is complete, verify result */
5129 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5130 if (ntohs (msg->size) != rc->msg_size)
5133 free_reassembly_context (rc);
5134 finish_cmc_handling (cmc);
5137 /* successful reassembly */
5138 demultiplex_with_cmc (cmc, msg);
5139 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5140 en-route and we forget that we finished this reassembly immediately!
5141 -> keep around until timeout?
5142 -> shorten timeout based on ACK? */
5143 free_reassembly_context (rc);
5148 * Communicator gave us a reliability box. Check the message.
5150 * @param cls a `struct CommunicatorMessageContext`
5151 * @param rb the send message that was sent
5152 * @return #GNUNET_YES if message is well-formed
5155 check_reliability_box (void *cls,
5156 const struct TransportReliabilityBoxMessage *rb)
5159 GNUNET_MQ_check_boxed_message (rb);
5165 * Communicator gave us a reliability box. Process the request.
5167 * @param cls a `struct CommunicatorMessageContext` (must call
5168 * #finish_cmc_handling() when done)
5169 * @param rb the message that was received
5172 handle_reliability_box (void *cls,
5173 const struct TransportReliabilityBoxMessage *rb)
5175 struct CommunicatorMessageContext *cmc = cls;
5176 const struct GNUNET_MessageHeader *inbox =
5177 (const struct GNUNET_MessageHeader *) &rb[1];
5179 // FIXME: call cummulative_ack(), have ack_countdown influence max_delay!
5180 (void) (0 == ntohl (rb->ack_countdown));
5181 /* continue with inner message */
5182 demultiplex_with_cmc (cmc, inbox);
5187 * Check if we have advanced to another age since the last time. If
5188 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5191 * @param pd[in,out] data to update
5192 * @param age current age
5195 update_pd_age (struct PerformanceData *pd, unsigned int age)
5199 if (age == pd->last_age)
5200 return; /* nothing to do */
5201 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5202 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5204 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5206 the->bytes_sent = 0;
5207 the->bytes_received = 0;
5214 * Update @a pd based on the latest @a rtt and the number of bytes
5215 * that were confirmed to be successfully transmitted.
5217 * @param pd[in,out] data to update
5218 * @param rtt latest round-trip time
5219 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5222 update_performance_data (struct PerformanceData *pd,
5223 struct GNUNET_TIME_Relative rtt,
5224 uint16_t bytes_transmitted_ok)
5226 uint64_t nval = rtt.rel_value_us;
5227 uint64_t oval = pd->aged_rtt.rel_value_us;
5228 unsigned int age = get_age ();
5229 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5231 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5234 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5235 update_pd_age (pd, age);
5236 the->bytes_received += bytes_transmitted_ok;
5241 * We have successfully transmitted data via @a q, update metrics.
5243 * @param q queue to update
5244 * @param rtt round trip time observed
5245 * @param bytes_transmitted_ok number of bytes successfully transmitted
5248 update_queue_performance (struct Queue *q,
5249 struct GNUNET_TIME_Relative rtt,
5250 uint16_t bytes_transmitted_ok)
5252 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5257 * We have successfully transmitted data via @a dvh, update metrics.
5259 * @param dvh distance vector path data to update
5260 * @param rtt round trip time observed
5261 * @param bytes_transmitted_ok number of bytes successfully transmitted
5264 update_dvh_performance (struct DistanceVectorHop *dvh,
5265 struct GNUNET_TIME_Relative rtt,
5266 uint16_t bytes_transmitted_ok)
5268 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5273 * The @a pa was acknowledged, process the acknowledgement.
5275 * @param pa the pending acknowledgement that was satisfied
5276 * @param ack_delay artificial delay from cummulative acks created by the
5280 handle_acknowledged (struct PendingAcknowledgement *pa,
5281 struct GNUNET_TIME_Relative ack_delay)
5283 struct PendingMessage *pm = pa->pm;
5284 struct GNUNET_TIME_Relative delay;
5286 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5287 if (delay.rel_value_us > ack_delay.rel_value_us)
5288 delay = GNUNET_TIME_UNIT_ZERO;
5290 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5291 if (NULL != pa->queue)
5292 update_queue_performance (pa->queue, delay, pa->message_size);
5293 if (NULL != pa->dvh)
5294 update_dvh_performance (pa->dvh, delay, pa->message_size);
5297 if (NULL != pm->frag_parent)
5299 pm = pm->frag_parent;
5300 free_fragment_tree (pa->pm);
5302 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5304 struct PendingMessage *parent = pm->frag_parent;
5306 free_fragment_tree (pm);
5309 if (NULL != pm->head_frag)
5310 pm = NULL; /* we are done, otherwise free 'pm' below */
5313 free_pending_message (pm);
5314 free_pending_acknowledgement (pa);
5319 * Communicator gave us a reliability ack. Check it is well-formed.
5321 * @param cls a `struct CommunicatorMessageContext` (unused)
5322 * @param ra the message that was received
5323 * @return #GNUNET_Ok if @a ra is well-formed
5326 check_reliability_ack (void *cls,
5327 const struct TransportReliabilityAckMessage *ra)
5329 unsigned int n_acks;
5332 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5333 sizeof (struct TransportCummulativeAckPayloadP);
5336 GNUNET_break_op (0);
5337 return GNUNET_SYSERR;
5339 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5340 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5342 GNUNET_break_op (0);
5343 return GNUNET_SYSERR;
5350 * Communicator gave us a reliability ack. Process the request.
5352 * @param cls a `struct CommunicatorMessageContext` (must call
5353 * #finish_cmc_handling() when done)
5354 * @param ra the message that was received
5357 handle_reliability_ack (void *cls,
5358 const struct TransportReliabilityAckMessage *ra)
5360 struct CommunicatorMessageContext *cmc = cls;
5361 const struct TransportCummulativeAckPayloadP *ack;
5362 struct PendingAcknowledgement *pa;
5363 unsigned int n_acks;
5364 uint32_t ack_counter;
5366 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5367 sizeof (struct TransportCummulativeAckPayloadP);
5368 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5369 for (unsigned int i = 0; i < n_acks; i++)
5372 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5375 GNUNET_STATISTICS_update (
5377 "# FRAGMENT_ACKS dropped, no matching pending message",
5382 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5385 ack_counter = htonl (ra->ack_counter);
5386 (void) ack_counter; /* silence compiler warning for now */
5387 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5388 // (DV and/or Neighbour?)
5389 finish_cmc_handling (cmc);
5394 * Communicator gave us a backchannel encapsulation. Check the message.
5396 * @param cls a `struct CommunicatorMessageContext`
5397 * @param be the send message that was sent
5398 * @return #GNUNET_YES if message is well-formed
5401 check_backchannel_encapsulation (
5403 const struct TransportBackchannelEncapsulationMessage *be)
5405 uint16_t size = ntohs (be->header.size);
5408 if ((size - sizeof (*be)) <
5409 (sizeof (struct TransportBackchannelRequestPayloadP) +
5410 sizeof (struct GNUNET_MessageHeader)))
5412 GNUNET_break_op (0);
5413 return GNUNET_SYSERR;
5420 * We received the plaintext @a msg from backtalker @a b. Forward
5421 * it to the respective communicator.
5423 * @param b a backtalker
5424 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5425 * followed by the target name of the communicator
5426 * @param msg_size number of bytes in @a msg
5429 forward_backchannel_payload (struct Backtalker *b,
5433 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5434 struct GNUNET_MQ_Envelope *env;
5435 struct TransportClient *tc;
5436 const struct GNUNET_MessageHeader *mh;
5437 const char *target_communicator;
5440 /* Determine target_communicator and check @a msg is well-formed */
5442 mhs = ntohs (mh->size);
5443 if (mhs <= msg_size)
5445 GNUNET_break_op (0);
5448 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5449 if ('\0' != target_communicator[msg_size - mhs - 1])
5451 GNUNET_break_op (0);
5454 /* Find client providing this communicator */
5455 for (tc = clients_head; NULL != tc; tc = tc->next)
5456 if ((CT_COMMUNICATOR == tc->type) &&
5458 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5466 "# Backchannel message dropped: target communicator `%s' unknown",
5467 target_communicator);
5468 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5469 GNUNET_free (stastr);
5472 /* Finally, deliver backchannel message to communicator */
5473 env = GNUNET_MQ_msg_extra (
5476 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5478 memcpy (&cbi[1], msg, msg_size);
5479 GNUNET_MQ_send (tc->mq, env);
5484 * Free data structures associated with @a b.
5486 * @param b data structure to release
5489 free_backtalker (struct Backtalker *b)
5493 GNUNET_PEERSTORE_iterate_cancel (b->get);
5495 GNUNET_assert (NULL != b->cmc);
5496 finish_cmc_handling (b->cmc);
5499 if (NULL != b->task)
5501 GNUNET_SCHEDULER_cancel (b->task);
5506 GNUNET_PEERSTORE_store_cancel (b->sc);
5511 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5517 * Callback to free backtalker records.
5521 * @param value a `struct Backtalker`
5522 * @return #GNUNET_OK (always)
5525 free_backtalker_cb (void *cls,
5526 const struct GNUNET_PeerIdentity *pid,
5529 struct Backtalker *b = value;
5533 free_backtalker (b);
5539 * Function called when it is time to clean up a backtalker.
5541 * @param cls a `struct Backtalker`
5544 backtalker_timeout_cb (void *cls)
5546 struct Backtalker *b = cls;
5549 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5551 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5554 GNUNET_assert (NULL == b->sc);
5555 free_backtalker (b);
5560 * Function called with the monotonic time of a backtalker
5561 * by PEERSTORE. Updates the time and continues processing.
5563 * @param cls a `struct Backtalker`
5564 * @param record the information found, NULL for the last call
5565 * @param emsg error message
5568 backtalker_monotime_cb (void *cls,
5569 const struct GNUNET_PEERSTORE_Record *record,
5572 struct Backtalker *b = cls;
5573 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5574 struct GNUNET_TIME_Absolute mt;
5579 /* we're done with #backtalker_monotime_cb() invocations,
5580 continue normal processing */
5582 GNUNET_assert (NULL != b->cmc);
5583 finish_cmc_handling (b->cmc);
5585 if (0 != b->body_size)
5586 forward_backchannel_payload (b, &b[1], b->body_size);
5589 if (sizeof (*mtbe) != record->value_size)
5594 mtbe = record->value;
5595 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5596 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5598 GNUNET_STATISTICS_update (
5600 "# Backchannel messages dropped: monotonic time not increasing",
5603 b->monotonic_time = mt;
5604 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5613 * Function called by PEERSTORE when the store operation of
5614 * a backtalker's monotonic time is complete.
5616 * @param cls the `struct Backtalker`
5617 * @param success #GNUNET_OK on success
5620 backtalker_monotime_store_cb (void *cls, int success)
5622 struct Backtalker *b = cls;
5624 if (GNUNET_OK != success)
5626 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5627 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5630 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5635 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5637 * @param b a backtalker with updated monotonic time
5640 update_backtalker_monotime (struct Backtalker *b)
5642 struct GNUNET_TIME_AbsoluteNBO mtbe;
5646 GNUNET_PEERSTORE_store_cancel (b->sc);
5651 GNUNET_SCHEDULER_cancel (b->task);
5654 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5656 GNUNET_PEERSTORE_store (peerstore,
5659 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5662 GNUNET_TIME_UNIT_FOREVER_ABS,
5663 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5664 &backtalker_monotime_store_cb,
5670 * Communicator gave us a backchannel encapsulation. Process the request.
5671 * (We are not the origin of the backchannel here, the communicator simply
5672 * received a backchannel message and we are expected to forward it.)
5674 * @param cls a `struct CommunicatorMessageContext` (must call
5675 * #finish_cmc_handling() when done)
5676 * @param be the message that was received
5679 handle_backchannel_encapsulation (
5681 const struct TransportBackchannelEncapsulationMessage *be)
5683 struct CommunicatorMessageContext *cmc = cls;
5684 struct BackchannelKeyState key;
5685 struct GNUNET_HashCode hmac;
5689 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5691 /* not for me, try to route to target */
5692 route_message (&be->target,
5693 GNUNET_copy_message (&be->header),
5695 finish_cmc_handling (cmc);
5698 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5699 hdr = (const char *) &be[1];
5700 hdr_len = ntohs (be->header.size) - sizeof (*be);
5701 bc_hmac (&key, &hmac, hdr, hdr_len);
5702 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5704 /* HMAC missmatch, disard! */
5705 GNUNET_break_op (0);
5706 finish_cmc_handling (cmc);
5709 /* begin actual decryption */
5711 struct Backtalker *b;
5712 struct GNUNET_TIME_Absolute monotime;
5713 struct TransportBackchannelRequestPayloadP ppay;
5714 char body[hdr_len - sizeof (ppay)];
5716 GNUNET_assert (hdr_len >=
5717 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5718 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5719 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5720 bc_key_clean (&key);
5721 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5722 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5723 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5725 GNUNET_STATISTICS_update (
5727 "# Backchannel messages dropped: monotonic time not increasing",
5730 finish_cmc_handling (cmc);
5734 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5736 /* Check signature */
5737 struct EphemeralConfirmationPS ec;
5739 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5740 ec.purpose.size = htonl (sizeof (ec));
5741 ec.target = GST_my_identity;
5742 ec.ephemeral_key = be->ephemeral_key;
5745 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5748 &ppay.sender.public_key))
5750 /* Signature invalid, disard! */
5751 GNUNET_break_op (0);
5752 finish_cmc_handling (cmc);
5758 /* update key cache and mono time */
5759 b->last_ephemeral = be->ephemeral_key;
5760 b->monotonic_time = monotime;
5761 update_backtalker_monotime (b);
5762 forward_backchannel_payload (b, body, sizeof (body));
5764 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5765 finish_cmc_handling (cmc);
5768 /* setup data structure to cache signature AND check
5769 monotonic time with PEERSTORE before forwarding backchannel payload */
5770 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5771 b->pid = ppay.sender;
5772 b->body_size = sizeof (body);
5773 memcpy (&b[1], body, sizeof (body));
5774 GNUNET_assert (GNUNET_YES ==
5775 GNUNET_CONTAINER_multipeermap_put (
5779 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5780 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5783 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5784 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5786 GNUNET_PEERSTORE_iterate (peerstore,
5789 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5790 &backtalker_monotime_cb,
5797 * Task called when we should check if any of the DV paths
5798 * we have learned to a target are due for garbage collection.
5800 * Collects stale paths, and possibly frees the entire DV
5801 * entry if no paths are left. Otherwise re-schedules itself.
5803 * @param cls a `struct DistanceVector`
5806 path_cleanup_cb (void *cls)
5808 struct DistanceVector *dv = cls;
5809 struct DistanceVectorHop *pos;
5811 dv->timeout_task = NULL;
5812 while (NULL != (pos = dv->dv_head))
5814 GNUNET_assert (dv == pos->dv);
5815 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5817 free_distance_vector_hop (pos);
5825 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5830 * The @a hop is a validated path to the respective target
5831 * peer and we should tell core about it -- and schedule
5832 * a job to revoke the state.
5834 * @param hop a path to some peer that is the reason for activation
5837 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5839 struct DistanceVector *dv = hop->dv;
5840 struct VirtualLink *vl;
5842 vl = GNUNET_CONTAINER_multipeermap_get (links, &dv->target);
5845 /* Link was already up, remember dv is also now available and we are done */
5849 vl = GNUNET_new (struct VirtualLink);
5850 vl->target = dv->target;
5852 vl->core_recv_window = RECV_WINDOW_SIZE;
5853 vl->visibility_task =
5854 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
5855 GNUNET_break (GNUNET_YES ==
5856 GNUNET_CONTAINER_multipeermap_put (
5860 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5861 /* We lacked a confirmed connection to the target
5862 before, so tell CORE about it (finally!) */
5863 cores_send_connect_info (&dv->target);
5868 * We have learned a @a path through the network to some other peer, add it to
5869 * our DV data structure (returning #GNUNET_YES on success).
5871 * We do not add paths if we have a sufficient number of shorter
5872 * paths to this target already (returning #GNUNET_NO).
5874 * We also do not add problematic paths, like those where we lack the first
5875 * hop in our neighbour list (i.e. due to a topology change) or where some
5876 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5878 * @param path the path we learned, path[0] should be us,
5879 * and then path contains a valid path from us to
5880 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
5881 * @param path_len number of entries on the @a path, at least three!
5882 * @param network_latency how long does the message take from us to
5883 * `path[path_len-1]`? set to "forever" if unknown
5884 * @param path_valid_until how long is this path considered validated? Maybe
5886 * @return #GNUNET_YES on success,
5887 * #GNUNET_NO if we have better path(s) to the target
5888 * #GNUNET_SYSERR if the path is useless and/or invalid
5889 * (i.e. path[1] not a direct neighbour
5890 * or path[i+1] is a direct neighbour for i>0)
5893 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5894 unsigned int path_len,
5895 struct GNUNET_TIME_Relative network_latency,
5896 struct GNUNET_TIME_Absolute path_valid_until)
5898 struct DistanceVectorHop *hop;
5899 struct DistanceVector *dv;
5900 struct Neighbour *next_hop;
5901 unsigned int shorter_distance;
5905 /* what a boring path! not allowed! */
5907 return GNUNET_SYSERR;
5909 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5910 next_hop = lookup_neighbour (&path[1]);
5911 if (NULL == next_hop)
5913 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5915 return GNUNET_SYSERR;
5917 for (unsigned int i = 2; i < path_len; i++)
5918 if (NULL != lookup_neighbour (&path[i]))
5920 /* Useless path, we have a direct connection to some hop
5921 in the middle of the path, so this one doesn't even
5922 seem terribly useful for redundancy */
5923 return GNUNET_SYSERR;
5925 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5928 dv = GNUNET_new (struct DistanceVector);
5929 dv->target = path[path_len - 1];
5930 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5933 GNUNET_assert (GNUNET_OK ==
5934 GNUNET_CONTAINER_multipeermap_put (
5938 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5940 /* Check if we have this path already! */
5941 shorter_distance = 0;
5942 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5945 if (pos->distance < path_len - 2)
5947 /* Note that the distances in 'pos' excludes us (path[0]) and
5948 the next_hop (path[1]), so we need to subtract two
5949 and check next_hop explicitly */
5950 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5952 int match = GNUNET_YES;
5954 for (unsigned int i = 0; i < pos->distance; i++)
5956 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5962 if (GNUNET_YES == match)
5964 struct GNUNET_TIME_Relative last_timeout;
5966 /* Re-discovered known path, update timeout */
5967 GNUNET_STATISTICS_update (GST_stats,
5968 "# Known DV path refreshed",
5971 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5973 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5974 pos->path_valid_until =
5975 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5976 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5977 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5979 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
5980 activate_core_visible_dv_path (pos);
5981 if (last_timeout.rel_value_us <
5982 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5983 DV_PATH_DISCOVERY_FREQUENCY)
5986 /* Some peer send DV learn messages too often, we are learning
5987 the same path faster than it would be useful; do not forward! */
5994 /* Count how many shorter paths we have (incl. direct
5995 neighbours) before simply giving up on this one! */
5996 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
5998 /* We have a shorter path already! */
6001 /* create new DV path entry */
6002 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6003 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6004 hop->next_hop = next_hop;
6006 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6009 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6010 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6011 hop->path_valid_until = path_valid_until;
6012 hop->distance = path_len - 2;
6013 hop->pd.aged_rtt = network_latency;
6014 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6015 GNUNET_CONTAINER_MDLL_insert (neighbour,
6019 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6020 activate_core_visible_dv_path (hop);
6026 * Communicator gave us a DV learn message. Check the message.
6028 * @param cls a `struct CommunicatorMessageContext`
6029 * @param dvl the send message that was sent
6030 * @return #GNUNET_YES if message is well-formed
6033 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6035 uint16_t size = ntohs (dvl->header.size);
6036 uint16_t num_hops = ntohs (dvl->num_hops);
6037 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6040 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6042 GNUNET_break_op (0);
6043 return GNUNET_SYSERR;
6045 if (num_hops > MAX_DV_HOPS_ALLOWED)
6047 GNUNET_break_op (0);
6048 return GNUNET_SYSERR;
6050 for (unsigned int i = 0; i < num_hops; i++)
6052 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6054 GNUNET_break_op (0);
6055 return GNUNET_SYSERR;
6057 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6059 GNUNET_break_op (0);
6060 return GNUNET_SYSERR;
6068 * Build and forward a DV learn message to @a next_hop.
6070 * @param next_hop peer to send the message to
6071 * @param msg message received
6072 * @param bi_history bitmask specifying hops on path that were bidirectional
6073 * @param nhops length of the @a hops array
6074 * @param hops path the message traversed so far
6075 * @param in_time when did we receive the message, used to calculate network
6079 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6080 const struct TransportDVLearnMessage *msg,
6081 uint16_t bi_history,
6083 const struct DVPathEntryP *hops,
6084 struct GNUNET_TIME_Absolute in_time)
6086 struct DVPathEntryP *dhops;
6087 struct TransportDVLearnMessage *fwd;
6088 struct GNUNET_TIME_Relative nnd;
6090 /* compute message for forwarding */
6091 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6092 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
6093 (nhops + 1) * sizeof (struct DVPathEntryP));
6094 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6095 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6096 (nhops + 1) * sizeof (struct DVPathEntryP));
6097 fwd->num_hops = htons (nhops + 1);
6098 fwd->bidirectional = htons (bi_history);
6099 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6100 GNUNET_TIME_relative_ntoh (
6101 msg->non_network_delay));
6102 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6103 fwd->init_sig = msg->init_sig;
6104 fwd->initiator = msg->initiator;
6105 fwd->challenge = msg->challenge;
6106 dhops = (struct DVPathEntryP *) &fwd[1];
6107 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6108 dhops[nhops].hop = GST_my_identity;
6110 struct DvHopPS dhp = {.purpose.purpose =
6111 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6112 .purpose.size = htonl (sizeof (dhp)),
6113 .pred = dhops[nhops - 1].hop,
6115 .challenge = msg->challenge};
6117 GNUNET_assert (GNUNET_OK ==
6118 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6120 &dhops[nhops].hop_sig));
6122 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6127 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6129 * @param sender_monotonic_time monotonic time of the initiator
6130 * @param init the signer
6131 * @param challenge the challenge that was signed
6132 * @param init_sig signature presumably by @a init
6133 * @return #GNUNET_OK if the signature is valid
6136 validate_dv_initiator_signature (
6137 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6138 const struct GNUNET_PeerIdentity *init,
6139 const struct ChallengeNonceP *challenge,
6140 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6142 struct DvInitPS ip = {.purpose.purpose = htonl (
6143 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6144 .purpose.size = htonl (sizeof (ip)),
6145 .monotonic_time = sender_monotonic_time,
6146 .challenge = *challenge};
6150 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6155 GNUNET_break_op (0);
6156 return GNUNET_SYSERR;
6163 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6165 struct NeighbourSelectionContext
6168 * Original message we received.
6170 const struct TransportDVLearnMessage *dvl;
6175 const struct DVPathEntryP *hops;
6178 * Time we received the message.
6180 struct GNUNET_TIME_Absolute in_time;
6183 * Offsets of the selected peers.
6185 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6188 * Number of peers eligible for selection.
6190 unsigned int num_eligible;
6193 * Number of peers that were selected for forwarding.
6195 unsigned int num_selections;
6198 * Number of hops in @e hops
6203 * Bitmap of bidirectional connections encountered.
6205 uint16_t bi_history;
6210 * Function called for each neighbour during #handle_dv_learn.
6212 * @param cls a `struct NeighbourSelectionContext *`
6213 * @param pid identity of the peer
6214 * @param value a `struct Neighbour`
6215 * @return #GNUNET_YES (always)
6218 dv_neighbour_selection (void *cls,
6219 const struct GNUNET_PeerIdentity *pid,
6222 struct NeighbourSelectionContext *nsc = cls;
6225 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6226 return GNUNET_YES; /* skip initiator */
6227 for (unsigned int i = 0; i < nsc->nhops; i++)
6228 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6229 return GNUNET_YES; /* skip peers on path */
6230 nsc->num_eligible++;
6236 * Function called for each neighbour during #handle_dv_learn.
6237 * We call #forward_dv_learn() on the neighbour(s) selected
6238 * during #dv_neighbour_selection().
6240 * @param cls a `struct NeighbourSelectionContext *`
6241 * @param pid identity of the peer
6242 * @param value a `struct Neighbour`
6243 * @return #GNUNET_YES (always)
6246 dv_neighbour_transmission (void *cls,
6247 const struct GNUNET_PeerIdentity *pid,
6250 struct NeighbourSelectionContext *nsc = cls;
6253 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6254 return GNUNET_YES; /* skip initiator */
6255 for (unsigned int i = 0; i < nsc->nhops; i++)
6256 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6257 return GNUNET_YES; /* skip peers on path */
6258 for (unsigned int i = 0; i < nsc->num_selections; i++)
6260 if (nsc->selections[i] == nsc->num_eligible)
6262 forward_dv_learn (pid,
6271 nsc->num_eligible++;
6277 * Computes the number of neighbours we should forward a DVInit
6278 * message to given that it has so far taken @a hops_taken hops
6279 * though the network and that the number of neighbours we have
6280 * in total is @a neighbour_count, out of which @a eligible_count
6281 * are not yet on the path.
6283 * NOTE: technically we might want to include NSE in the formula to
6284 * get a better grip on the overall network size. However, for now
6285 * using NSE here would create a dependency issue in the build system.
6286 * => Left for later, hardcoded to 50 for now.
6288 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6289 * peers via DV (`target_total`). We want the reach to be spread out
6290 * over various distances to the origin, with a bias towards shorter
6293 * We make the strong assumption that the network topology looks
6294 * "similar" at other hops, in particular the @a neighbour_count
6295 * should be comparable at other hops.
6297 * If the local neighbourhood is densely connected, we expect that @a
6298 * eligible_count is close to @a neighbour_count minus @a hops_taken
6299 * as a lot of the path is already known. In that case, we should
6300 * forward to few(er) peers to try to find a path out of the
6301 * neighbourhood. OTOH, if @a eligible_count is close to @a
6302 * neighbour_count, we should forward to many peers as we are either
6303 * still close to the origin (i.e. @a hops_taken is small) or because
6304 * we managed to get beyond a local cluster. We express this as
6305 * the `boost_factor` using the square of the fraction of eligible
6306 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6307 * 99% are eligible, the 'boost' will be almost 1).
6309 * Second, the more hops we have taken, the larger the problem of an
6310 * exponential traffic explosion gets. So we take the `target_total`,
6311 * and compute our degree such that at each distance d 2^{-d} peers
6312 * are selected (corrected by the `boost_factor`).
6314 * @param hops_taken number of hops DVInit has travelled so far
6315 * @param neighbour_count number of neighbours we have in total
6316 * @param eligible_count number of neighbours we could in
6320 calculate_fork_degree (unsigned int hops_taken,
6321 unsigned int neighbour_count,
6322 unsigned int eligible_count)
6324 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6325 double eligible_ratio =
6326 ((double) eligible_count) / ((double) neighbour_count);
6327 double boost_factor = eligible_ratio * eligible_ratio;
6331 if (hops_taken >= 64)
6332 return 0; /* precaution given bitshift below */
6333 for (unsigned int i = 1; i < hops_taken; i++)
6335 /* For each hop, subtract the expected number of targets
6336 reached at distance d (so what remains divided by 2^d) */
6337 target_total -= (target_total * boost_factor / (1LLU << i));
6340 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6341 /* round up or down probabilistically depending on how close we were
6342 when floor()ing to rnd */
6343 left = target_total - (double) rnd;
6344 if (UINT32_MAX * left >
6345 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6346 rnd++; /* round up */
6352 * Function called when peerstore is done storing a DV monotonic time.
6354 * @param cls a `struct Neighbour`
6355 * @param success #GNUNET_YES if peerstore was successful
6358 neighbour_store_dvmono_cb (void *cls, int success)
6360 struct Neighbour *n = cls;
6363 if (GNUNET_YES != success)
6364 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6365 "Failed to store other peer's monotonic time in peerstore!\n");
6370 * Communicator gave us a DV learn message. Process the request.
6372 * @param cls a `struct CommunicatorMessageContext` (must call
6373 * #finish_cmc_handling() when done)
6374 * @param dvl the message that was received
6377 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6379 struct CommunicatorMessageContext *cmc = cls;
6380 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6383 uint16_t bi_history;
6384 const struct DVPathEntryP *hops;
6387 struct GNUNET_TIME_Absolute in_time;
6388 struct Neighbour *n;
6390 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6391 bi_history = ntohs (dvl->bidirectional);
6392 hops = (const struct DVPathEntryP *) &dvl[1];
6396 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6399 finish_cmc_handling (cmc);
6406 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6409 finish_cmc_handling (cmc);
6414 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6415 cc = cmc->tc->details.communicator.cc;
6416 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6417 cc); // FIXME: add bi-directional flag to cc?
6418 in_time = GNUNET_TIME_absolute_get ();
6420 /* continue communicator here, everything else can happen asynchronous! */
6421 finish_cmc_handling (cmc);
6423 n = lookup_neighbour (&dvl->initiator);
6426 if ((n->dv_monotime_available == GNUNET_YES) &&
6427 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6428 n->last_dv_learn_monotime.abs_value_us))
6430 GNUNET_STATISTICS_update (GST_stats,
6431 "# DV learn discarded due to time travel",
6436 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6441 GNUNET_break_op (0);
6444 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6445 if (GNUNET_YES == n->dv_monotime_available)
6448 GNUNET_PEERSTORE_store_cancel (n->sc);
6450 GNUNET_PEERSTORE_store (peerstore,
6453 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6454 &dvl->monotonic_time,
6455 sizeof (dvl->monotonic_time),
6456 GNUNET_TIME_UNIT_FOREVER_ABS,
6457 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6458 &neighbour_store_dvmono_cb,
6462 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6463 If signature verification load too high, implement random drop strategy */
6464 for (unsigned int i = 0; i < nhops; i++)
6466 struct DvHopPS dhp = {.purpose.purpose =
6467 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6468 .purpose.size = htonl (sizeof (dhp)),
6469 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6470 .succ = (nhops - 1 == i) ? GST_my_identity
6472 .challenge = dvl->challenge};
6475 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6478 &hops[i].hop.public_key))
6480 GNUNET_break_op (0);
6485 do_fwd = GNUNET_YES;
6486 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6488 struct GNUNET_PeerIdentity path[nhops + 1];
6489 struct GNUNET_TIME_Relative host_latency_sum;
6490 struct GNUNET_TIME_Relative latency;
6491 struct GNUNET_TIME_Relative network_latency;
6493 /* We initiated this, learn the forward path! */
6494 path[0] = GST_my_identity;
6495 path[1] = hops[0].hop;
6496 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6498 // Need also something to lookup initiation time
6499 // to compute RTT! -> add RTT argument here?
6500 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6501 // (based on dvl->challenge, we can identify time of origin!)
6503 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6504 /* assumption: latency on all links is the same */
6505 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6507 for (unsigned int i = 2; i <= nhops; i++)
6509 struct GNUNET_TIME_Relative ilat;
6511 /* assumption: linear latency increase per hop */
6512 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6513 path[i] = hops[i - 1].hop;
6514 learn_dv_path (path,
6517 GNUNET_TIME_relative_to_absolute (
6518 ADDRESS_VALIDATION_LIFETIME));
6520 /* as we initiated, do not forward again (would be circular!) */
6526 /* last hop was bi-directional, we could learn something here! */
6527 struct GNUNET_PeerIdentity path[nhops + 2];
6529 path[0] = GST_my_identity;
6530 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6531 for (unsigned int i = 0; i < nhops; i++)
6535 if (0 == (bi_history & (1 << i)))
6536 break; /* i-th hop not bi-directional, stop learning! */
6539 path[i + 2] = dvl->initiator;
6543 path[i + 2] = hops[nhops - i - 2].hop;
6546 iret = learn_dv_path (path,
6548 GNUNET_TIME_UNIT_FOREVER_REL,
6549 GNUNET_TIME_UNIT_ZERO_ABS);
6550 if (GNUNET_SYSERR == iret)
6552 /* path invalid or too long to be interesting for US, thus should also
6553 not be interesting to our neighbours, cut path when forwarding to
6554 'i' hops, except of course for the one that goes back to the
6556 GNUNET_STATISTICS_update (GST_stats,
6557 "# DV learn not forwarded due invalidity of path",
6563 if ((GNUNET_NO == iret) && (nhops == i + 1))
6565 /* we have better paths, and this is the longest target,
6566 so there cannot be anything interesting later */
6567 GNUNET_STATISTICS_update (GST_stats,
6568 "# DV learn not forwarded, got better paths",
6577 if (MAX_DV_HOPS_ALLOWED == nhops)
6579 /* At limit, we're out of here! */
6580 finish_cmc_handling (cmc);
6584 /* Forward to initiator, if path non-trivial and possible */
6585 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6586 did_initiator = GNUNET_NO;
6589 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6591 /* send back to origin! */
6592 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6593 did_initiator = GNUNET_YES;
6595 /* We forward under two conditions: either we still learned something
6596 ourselves (do_fwd), or the path was darn short and thus the initiator is
6597 likely to still be very interested in this (and we did NOT already
6598 send it back to the initiator) */
6599 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6600 (GNUNET_NO == did_initiator)))
6602 /* Pick random neighbours that are not yet on the path */
6603 struct NeighbourSelectionContext nsc;
6606 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6609 nsc.bi_history = bi_history;
6611 nsc.in_time = in_time;
6612 nsc.num_eligible = 0;
6613 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6614 &dv_neighbour_selection,
6616 if (0 == nsc.num_eligible)
6617 return; /* done here, cannot forward to anyone else */
6618 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6619 nsc.num_selections =
6620 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6621 for (unsigned int i = 0; i < nsc.num_selections; i++)
6623 (nsc.num_selections == n_cnt)
6624 ? i /* all were selected, avoid collisions by chance */
6625 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6626 nsc.num_eligible = 0;
6627 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6628 &dv_neighbour_transmission,
6635 * Communicator gave us a DV box. Check the message.
6637 * @param cls a `struct CommunicatorMessageContext`
6638 * @param dvb the send message that was sent
6639 * @return #GNUNET_YES if message is well-formed
6642 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6644 uint16_t size = ntohs (dvb->header.size);
6645 uint16_t num_hops = ntohs (dvb->num_hops);
6646 const struct GNUNET_PeerIdentity *hops =
6647 (const struct GNUNET_PeerIdentity *) &dvb[1];
6648 const struct GNUNET_MessageHeader *inbox =
6649 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6654 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6655 sizeof (struct GNUNET_MessageHeader))
6657 GNUNET_break_op (0);
6658 return GNUNET_SYSERR;
6660 isize = ntohs (inbox->size);
6662 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6664 GNUNET_break_op (0);
6665 return GNUNET_SYSERR;
6667 itype = ntohs (inbox->type);
6668 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6669 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6671 GNUNET_break_op (0);
6672 return GNUNET_SYSERR;
6674 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6676 GNUNET_break_op (0);
6677 return GNUNET_SYSERR;
6684 * Create a DV Box message and queue it for transmission to
6687 * @param next_hop peer to receive the message next
6688 * @param total_hops how many hops did the message take so far
6689 * @param num_hops length of the @a hops array
6690 * @param origin origin of the message
6691 * @param hops next peer(s) to the destination, including destination
6692 * @param payload payload of the box
6693 * @param payload_size number of bytes in @a payload
6696 forward_dv_box (struct Neighbour *next_hop,
6697 uint16_t total_hops,
6699 const struct GNUNET_PeerIdentity *origin,
6700 const struct GNUNET_PeerIdentity *hops,
6701 const void *payload,
6702 uint16_t payload_size)
6704 struct TransportDVBoxMessage *dvb;
6706 dvb = create_dv_box (total_hops,
6708 &hops[num_hops - 1] /* == target */,
6709 num_hops - 1 /* do not count target twice */,
6713 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6719 * Communicator gave us a DV box. Process the request.
6721 * @param cls a `struct CommunicatorMessageContext` (must call
6722 * #finish_cmc_handling() when done)
6723 * @param dvb the message that was received
6726 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6728 struct CommunicatorMessageContext *cmc = cls;
6729 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6730 uint16_t num_hops = ntohs (dvb->num_hops);
6731 const struct GNUNET_PeerIdentity *hops =
6732 (const struct GNUNET_PeerIdentity *) &dvb[1];
6733 const struct GNUNET_MessageHeader *inbox =
6734 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6738 /* We're trying from the end of the hops array, as we may be
6739 able to find a shortcut unknown to the origin that way */
6740 for (int i = num_hops - 1; i >= 0; i--)
6742 struct Neighbour *n;
6744 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6746 GNUNET_break_op (0);
6747 finish_cmc_handling (cmc);
6750 n = lookup_neighbour (&hops[i]);
6754 ntohs (dvb->total_hops) + 1,
6755 num_hops - i - 1, /* number of hops left */
6757 &hops[i + 1], /* remaining hops */
6758 (const void *) &dvb[1],
6760 finish_cmc_handling (cmc);
6763 /* Woopsie, next hop not in neighbours, drop! */
6764 GNUNET_STATISTICS_update (GST_stats,
6765 "# DV Boxes dropped: next hop unknown",
6768 finish_cmc_handling (cmc);
6771 /* We are the target. Unbox and handle message. */
6772 cmc->im.sender = dvb->origin;
6773 cmc->total_hops = ntohs (dvb->total_hops);
6774 demultiplex_with_cmc (cmc, inbox);
6779 * Client notified us about transmission from a peer. Process the request.
6781 * @param cls a `struct TransportClient` which sent us the message
6782 * @param obm the send message that was sent
6783 * @return #GNUNET_YES if message is well-formed
6786 check_incoming_msg (void *cls,
6787 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6789 struct TransportClient *tc = cls;
6791 if (CT_COMMUNICATOR != tc->type)
6794 return GNUNET_SYSERR;
6796 GNUNET_MQ_check_boxed_message (im);
6802 * Communicator gave us a transport address validation challenge. Process the
6805 * @param cls a `struct CommunicatorMessageContext` (must call
6806 * #finish_cmc_handling() when done)
6807 * @param tvc the message that was received
6810 handle_validation_challenge (
6812 const struct TransportValidationChallengeMessage *tvc)
6814 struct CommunicatorMessageContext *cmc = cls;
6815 struct TransportValidationResponseMessage *tvr;
6817 if (cmc->total_hops > 0)
6819 /* DV routing is not allowed for validation challenges! */
6820 GNUNET_break_op (0);
6821 finish_cmc_handling (cmc);
6824 tvr = GNUNET_new (struct TransportValidationResponseMessage);
6826 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
6827 tvr->header.size = htons (sizeof (*tvr));
6828 tvr->challenge = tvc->challenge;
6829 tvr->origin_time = tvc->sender_time;
6830 tvr->validity_duration = cmc->im.expected_address_validity;
6832 /* create signature */
6833 struct TransportValidationPS tvp =
6834 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6835 .purpose.size = htonl (sizeof (tvp)),
6836 .validity_duration = tvr->validity_duration,
6837 .challenge = tvc->challenge};
6839 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6843 route_message (&cmc->im.sender,
6845 RMO_ANYTHING_GOES | RMO_REDUNDANT);
6846 finish_cmc_handling (cmc);
6851 * Closure for #check_known_challenge.
6853 struct CheckKnownChallengeContext
6856 * Set to the challenge we are looking for.
6858 const struct ChallengeNonceP *challenge;
6861 * Set to a matching validation state, if one was found.
6863 struct ValidationState *vs;
6868 * Test if the validation state in @a value matches the
6869 * challenge from @a cls.
6871 * @param cls a `struct CheckKnownChallengeContext`
6872 * @param pid unused (must match though)
6873 * @param value a `struct ValidationState`
6874 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6877 check_known_challenge (void *cls,
6878 const struct GNUNET_PeerIdentity *pid,
6881 struct CheckKnownChallengeContext *ckac = cls;
6882 struct ValidationState *vs = value;
6885 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
6893 * Function called when peerstore is done storing a
6894 * validated address.
6896 * @param cls a `struct ValidationState`
6897 * @param success #GNUNET_YES on success
6900 peerstore_store_validation_cb (void *cls, int success)
6902 struct ValidationState *vs = cls;
6905 if (GNUNET_YES == success)
6907 GNUNET_STATISTICS_update (GST_stats,
6908 "# Peerstore failed to store foreign address",
6915 * Task run periodically to validate some address based on #validation_heap.
6920 validation_start_cb (void *cls);
6924 * Set the time for next_challenge of @a vs to @a new_time.
6925 * Updates the heap and if necessary reschedules the job.
6927 * @param vs validation state to update
6928 * @param new_time new time for revalidation
6931 update_next_challenge_time (struct ValidationState *vs,
6932 struct GNUNET_TIME_Absolute new_time)
6934 struct GNUNET_TIME_Relative delta;
6936 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
6937 return; /* be lazy */
6938 vs->next_challenge = new_time;
6941 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
6943 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
6944 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
6945 (NULL != validation_task))
6947 if (NULL != validation_task)
6948 GNUNET_SCHEDULER_cancel (validation_task);
6949 /* randomize a bit */
6950 delta.rel_value_us =
6951 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6952 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
6953 new_time = GNUNET_TIME_absolute_add (new_time, delta);
6955 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
6960 * Find the queue matching @a pid and @a address.
6962 * @param pid peer the queue must go to
6963 * @param address address the queue must use
6964 * @return NULL if no such queue exists
6966 static struct Queue *
6967 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
6969 struct Neighbour *n;
6971 n = lookup_neighbour (pid);
6974 for (struct Queue *pos = n->queue_head; NULL != pos;
6975 pos = pos->next_neighbour)
6977 if (0 == strcmp (pos->address, address))
6985 * Communicator gave us a transport address validation response. Process the
6988 * @param cls a `struct CommunicatorMessageContext` (must call
6989 * #finish_cmc_handling() when done)
6990 * @param tvr the message that was received
6993 handle_validation_response (
6995 const struct TransportValidationResponseMessage *tvr)
6997 struct CommunicatorMessageContext *cmc = cls;
6998 struct ValidationState *vs;
6999 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7001 struct GNUNET_TIME_Absolute origin_time;
7003 struct Neighbour *n;
7004 struct VirtualLink *vl;
7006 /* check this is one of our challenges */
7007 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7009 &check_known_challenge,
7011 if (NULL == (vs = ckac.vs))
7013 /* This can happen simply if we 'forgot' the challenge by now,
7014 i.e. because we received the validation response twice */
7015 GNUNET_STATISTICS_update (GST_stats,
7016 "# Validations dropped, challenge unknown",
7019 finish_cmc_handling (cmc);
7023 /* sanity check on origin time */
7024 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7025 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7026 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7028 GNUNET_break_op (0);
7029 finish_cmc_handling (cmc);
7034 /* check signature */
7035 struct TransportValidationPS tvp =
7036 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7037 .purpose.size = htonl (sizeof (tvp)),
7038 .validity_duration = tvr->validity_duration,
7039 .challenge = tvr->challenge};
7043 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7046 &cmc->im.sender.public_key))
7048 GNUNET_break_op (0);
7049 finish_cmc_handling (cmc);
7054 /* validity is capped by our willingness to keep track of the
7055 validation entry and the maximum the other peer allows */
7056 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7057 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7058 tvr->validity_duration),
7059 MAX_ADDRESS_VALID_UNTIL));
7060 vs->validated_until =
7061 GNUNET_TIME_absolute_min (vs->valid_until,
7062 GNUNET_TIME_relative_to_absolute (
7063 ADDRESS_VALIDATION_LIFETIME));
7064 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7065 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7066 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7068 sizeof (vs->challenge));
7069 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7070 vs->validated_until,
7071 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7072 VALIDATION_RTT_BUFFER_FACTOR));
7073 vs->last_challenge_use =
7074 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7075 update_next_challenge_time (vs, vs->first_challenge_use);
7076 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7079 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7081 strlen (vs->address) + 1,
7083 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7084 &peerstore_store_validation_cb,
7086 finish_cmc_handling (cmc);
7088 /* Finally, we now possibly have a confirmed (!) working queue,
7089 update queue status (if queue still is around) */
7090 q = find_queue (&vs->pid, vs->address);
7093 GNUNET_STATISTICS_update (GST_stats,
7094 "# Queues lost at time of successful validation",
7099 q->validated_until = vs->validated_until;
7100 q->pd.aged_rtt = vs->validation_rtt;
7102 vl = GNUNET_CONTAINER_multipeermap_get (links, &vs->pid);
7105 /* Link was already up, remember n is also now available and we are done */
7109 vl = GNUNET_new (struct VirtualLink);
7110 vl->target = n->pid;
7112 vl->core_recv_window = RECV_WINDOW_SIZE;
7113 vl->visibility_task =
7114 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7115 GNUNET_break (GNUNET_YES ==
7116 GNUNET_CONTAINER_multipeermap_put (
7120 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7121 /* We lacked a confirmed connection to the target
7122 before, so tell CORE about it (finally!) */
7123 cores_send_connect_info (&n->pid);
7128 * Incoming meessage. Process the request.
7130 * @param im the send message that was received
7133 handle_incoming_msg (void *cls,
7134 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7136 struct TransportClient *tc = cls;
7137 struct CommunicatorMessageContext *cmc =
7138 GNUNET_new (struct CommunicatorMessageContext);
7142 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7147 * Given an inbound message @a msg from a communicator @a cmc,
7148 * demultiplex it based on the type calling the right handler.
7150 * @param cmc context for demultiplexing
7151 * @param msg message to demultiplex
7154 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7155 const struct GNUNET_MessageHeader *msg)
7157 struct GNUNET_MQ_MessageHandler handlers[] =
7158 {GNUNET_MQ_hd_var_size (fragment_box,
7159 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7160 struct TransportFragmentBoxMessage,
7162 GNUNET_MQ_hd_var_size (reliability_box,
7163 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7164 struct TransportReliabilityBoxMessage,
7166 GNUNET_MQ_hd_var_size (reliability_ack,
7167 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7168 struct TransportReliabilityAckMessage,
7170 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7171 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7172 struct TransportBackchannelEncapsulationMessage,
7174 GNUNET_MQ_hd_var_size (dv_learn,
7175 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7176 struct TransportDVLearnMessage,
7178 GNUNET_MQ_hd_var_size (dv_box,
7179 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7180 struct TransportDVBoxMessage,
7182 GNUNET_MQ_hd_fixed_size (
7183 validation_challenge,
7184 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7185 struct TransportValidationChallengeMessage,
7187 GNUNET_MQ_hd_fixed_size (
7188 validation_response,
7189 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7190 struct TransportValidationResponseMessage,
7192 GNUNET_MQ_handler_end ()};
7195 ret = GNUNET_MQ_handle_message (handlers, msg);
7196 if (GNUNET_SYSERR == ret)
7199 GNUNET_SERVICE_client_drop (cmc->tc->client);
7203 if (GNUNET_NO == ret)
7205 /* unencapsulated 'raw' message */
7206 handle_raw_message (&cmc, msg);
7212 * New queue became available. Check message.
7214 * @param cls the client
7215 * @param aqm the send message that was sent
7218 check_add_queue_message (void *cls,
7219 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7221 struct TransportClient *tc = cls;
7223 if (CT_COMMUNICATOR != tc->type)
7226 return GNUNET_SYSERR;
7228 GNUNET_MQ_check_zero_termination (aqm);
7234 * If necessary, generates the UUID for a @a pm
7236 * @param pm pending message to generate UUID for.
7239 set_pending_message_uuid (struct PendingMessage *pm)
7241 if (pm->msg_uuid_set)
7243 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7245 sizeof (pm->msg_uuid));
7246 pm->msg_uuid_set = GNUNET_YES;
7251 * Setup data structure waiting for acknowledgements.
7253 * @param queue queue the @a pm will be sent over
7254 * @param dvh path the message will take, may be NULL
7255 * @param pm the pending message for transmission
7256 * @return corresponding fresh pending acknowledgement
7258 static struct PendingAcknowledgement *
7259 prepare_pending_acknowledgement (struct Queue *queue,
7260 struct DistanceVectorHop *dvh,
7261 struct PendingMessage *pm)
7263 struct PendingAcknowledgement *pa;
7265 pa = GNUNET_new (struct PendingAcknowledgement);
7271 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7273 sizeof (pa->ack_uuid));
7274 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7276 &pa->ack_uuid.value,
7278 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7279 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7280 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7282 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7283 pa->transmission_time = GNUNET_TIME_absolute_get ();
7284 pa->message_size = pm->bytes_msg;
7290 * Fragment the given @a pm to the given @a mtu. Adds
7291 * additional fragments to the neighbour as well. If the
7292 * @a mtu is too small, generates and error for the @a pm
7295 * @param queue which queue to fragment for
7296 * @param dvh path the message will take, or NULL
7297 * @param pm pending message to fragment for transmission
7298 * @return new message to transmit
7300 static struct PendingMessage *
7301 fragment_message (struct Queue *queue,
7302 struct DistanceVectorHop *dvh,
7303 struct PendingMessage *pm)
7305 struct PendingAcknowledgement *pa;
7306 struct PendingMessage *ff;
7309 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7310 mtu = (0 == queue->mtu)
7311 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7313 set_pending_message_uuid (pm);
7315 /* This invariant is established in #handle_add_queue_message() */
7316 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7318 /* select fragment for transmission, descending the tree if it has
7319 been expanded until we are at a leaf or at a fragment that is small
7323 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7324 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7326 ff = ff->head_frag; /* descent into fragmented fragments */
7329 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7331 /* Did not yet calculate all fragments, calculate next fragment */
7332 struct PendingMessage *frag;
7333 struct TransportFragmentBoxMessage tfb;
7341 orig = (const char *) &ff[1];
7342 msize = ff->bytes_msg;
7345 const struct TransportFragmentBoxMessage *tfbo;
7347 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7348 orig += sizeof (struct TransportFragmentBoxMessage);
7349 msize -= sizeof (struct TransportFragmentBoxMessage);
7350 xoff = ntohs (tfbo->frag_off);
7352 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7353 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7355 GNUNET_malloc (sizeof (struct PendingMessage) +
7356 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7357 frag->target = pm->target;
7358 frag->frag_parent = ff;
7359 frag->timeout = pm->timeout;
7360 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7361 frag->pmt = PMT_FRAGMENT_BOX;
7362 msg = (char *) &frag[1];
7363 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7365 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7366 tfb.ack_uuid = pa->ack_uuid;
7367 tfb.msg_uuid = pm->msg_uuid;
7368 tfb.frag_off = htons (ff->frag_off + xoff);
7369 tfb.msg_size = htons (pm->bytes_msg);
7370 memcpy (msg, &tfb, sizeof (tfb));
7371 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7372 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7373 ff->frag_off += fragsize;
7377 /* Move head to the tail and return it */
7378 GNUNET_CONTAINER_MDLL_remove (frag,
7379 ff->frag_parent->head_frag,
7380 ff->frag_parent->tail_frag,
7382 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7383 ff->frag_parent->head_frag,
7384 ff->frag_parent->tail_frag,
7391 * Reliability-box the given @a pm. On error (can there be any), NULL
7392 * may be returned, otherwise the "replacement" for @a pm (which
7393 * should then be added to the respective neighbour's queue instead of
7394 * @a pm). If the @a pm is already fragmented or reliability boxed,
7395 * or itself an ACK, this function simply returns @a pm.
7397 * @param queue which queue to prepare transmission for
7398 * @param dvh path the message will take, or NULL
7399 * @param pm pending message to box for transmission over unreliabile queue
7400 * @return new message to transmit
7402 static struct PendingMessage *
7403 reliability_box_message (struct Queue *queue,
7404 struct DistanceVectorHop *dvh,
7405 struct PendingMessage *pm)
7407 struct TransportReliabilityBoxMessage rbox;
7408 struct PendingAcknowledgement *pa;
7409 struct PendingMessage *bpm;
7412 if (PMT_CORE != pm->pmt)
7413 return pm; /* already fragmented or reliability boxed, or control message:
7415 if (NULL != pm->bpm)
7416 return pm->bpm; /* already computed earlier: do nothing */
7417 GNUNET_assert (NULL == pm->head_frag);
7418 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7422 client_send_response (pm);
7425 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7427 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7429 bpm->target = pm->target;
7430 bpm->frag_parent = pm;
7431 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7432 bpm->timeout = pm->timeout;
7433 bpm->pmt = PMT_RELIABILITY_BOX;
7434 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7435 set_pending_message_uuid (bpm);
7436 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7437 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7438 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7440 rbox.ack_uuid = pa->ack_uuid;
7441 msg = (char *) &bpm[1];
7442 memcpy (msg, &rbox, sizeof (rbox));
7443 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7450 * Change the value of the `next_attempt` field of @a pm
7451 * to @a next_attempt and re-order @a pm in the transmission
7452 * list as required by the new timestmap.
7454 * @param pm a pending message to update
7455 * @param next_attempt timestamp to use
7458 update_pm_next_attempt (struct PendingMessage *pm,
7459 struct GNUNET_TIME_Absolute next_attempt)
7461 struct Neighbour *neighbour = pm->target;
7463 pm->next_attempt = next_attempt;
7464 if (NULL == pm->frag_parent)
7466 struct PendingMessage *pos;
7468 /* re-insert sort in neighbour list */
7469 GNUNET_CONTAINER_MDLL_remove (neighbour,
7470 neighbour->pending_msg_head,
7471 neighbour->pending_msg_tail,
7473 pos = neighbour->pending_msg_tail;
7474 while ((NULL != pos) &&
7475 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7476 pos = pos->prev_neighbour;
7477 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7478 neighbour->pending_msg_head,
7479 neighbour->pending_msg_tail,
7485 /* re-insert sort in fragment list */
7486 struct PendingMessage *fp = pm->frag_parent;
7487 struct PendingMessage *pos;
7489 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7490 pos = fp->tail_frag;
7491 while ((NULL != pos) &&
7492 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7493 pos = pos->prev_frag;
7494 GNUNET_CONTAINER_MDLL_insert_after (frag,
7504 * We believe we are ready to transmit a message on a queue.
7505 * Gives the message to the
7506 * communicator for transmission (updating the tracker, and re-scheduling
7507 * itself if applicable).
7509 * @param cls the `struct Queue` to process transmissions for
7512 transmit_on_queue (void *cls)
7514 struct Queue *queue = cls;
7515 struct Neighbour *n = queue->neighbour;
7516 struct PendingMessage *pm;
7517 struct PendingMessage *s;
7520 queue->transmit_task = NULL;
7521 if (NULL == (pm = n->pending_msg_head))
7523 /* no message pending, nothing to do here! */
7528 /* message still pending with communciator!
7529 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7532 schedule_transmit_on_queue (queue, GNUNET_YES);
7533 if (NULL != queue->transmit_task)
7534 return; /* do it later */
7536 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7537 overhead += sizeof (struct TransportReliabilityBoxMessage);
7539 if ( ( (0 != queue->mtu) &&
7540 (pm->bytes_msg + overhead > queue->mtu) ) ||
7541 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7542 (NULL != pm->head_frag /* fragments already exist, should
7543 respect that even if MTU is 0 for
7545 s = fragment_message (queue, pm->dvh, s);
7548 /* Fragmentation failed, try next message... */
7549 schedule_transmit_on_queue (queue, GNUNET_NO);
7552 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7553 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7554 s = reliability_box_message (queue, pm->dvh, s);
7557 /* Reliability boxing failed, try next message... */
7558 schedule_transmit_on_queue (queue, GNUNET_NO);
7562 /* Pass 's' for transission to the communicator */
7563 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7564 // FIXME: do something similar to the logic below
7565 // in defragmentation / reliability ACK handling!
7567 /* Check if this transmission somehow conclusively finished handing 'pm'
7568 even without any explicit ACKs */
7569 if ((PMT_CORE == s->pmt) &&
7570 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7572 /* Full message sent, and over reliabile channel */
7573 client_send_response (pm);
7575 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7576 queue->tc->details.communicator.cc) &&
7577 (PMT_FRAGMENT_BOX == s->pmt))
7579 struct PendingMessage *pos;
7581 /* Fragment sent over reliabile channel */
7582 free_fragment_tree (s);
7583 pos = s->frag_parent;
7584 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7586 /* check if subtree is done */
7587 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7591 pos = s->frag_parent;
7592 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7596 /* Was this the last applicable fragmment? */
7597 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7598 client_send_response (pm);
7600 else if (PMT_CORE != pm->pmt)
7602 /* This was an acknowledgement of some type, always free */
7603 free_pending_message (pm);
7607 /* Message not finished, waiting for acknowledgement.
7608 Update time by which we might retransmit 's' based on queue
7609 characteristics (i.e. RTT); it takes one RTT for the message to
7610 arrive and the ACK to come back in the best case; but the other
7611 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7612 retransmitting. Note that in the future this heuristic should
7613 likely be improved further (measure RTT stability, consider
7614 message urgency and size when delaying ACKs, etc.) */
7615 update_pm_next_attempt (s,
7616 GNUNET_TIME_relative_to_absolute (
7617 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7621 /* finally, re-schedule queue transmission task itself */
7622 schedule_transmit_on_queue (queue, GNUNET_NO);
7627 * Queue to a peer went down. Process the request.
7629 * @param cls the client
7630 * @param dqm the send message that was sent
7633 handle_del_queue_message (void *cls,
7634 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7636 struct TransportClient *tc = cls;
7638 if (CT_COMMUNICATOR != tc->type)
7641 GNUNET_SERVICE_client_drop (tc->client);
7644 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7645 queue = queue->next_client)
7647 struct Neighbour *neighbour = queue->neighbour;
7649 if ((dqm->qid != queue->qid) ||
7650 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7653 GNUNET_SERVICE_client_continue (tc->client);
7657 GNUNET_SERVICE_client_drop (tc->client);
7662 * Message was transmitted. Process the request.
7664 * @param cls the client
7665 * @param sma the send message that was sent
7668 handle_send_message_ack (void *cls,
7669 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7671 struct TransportClient *tc = cls;
7672 struct QueueEntry *qe;
7673 struct PendingMessage *pm;
7675 if (CT_COMMUNICATOR != tc->type)
7678 GNUNET_SERVICE_client_drop (tc->client);
7682 /* find our queue entry matching the ACK */
7684 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7685 queue = queue->next_client)
7687 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7689 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7692 if (qep->mid != sma->mid)
7701 /* this should never happen */
7703 GNUNET_SERVICE_client_drop (tc->client);
7706 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7707 qe->queue->queue_tail,
7709 qe->queue->queue_length--;
7710 tc->details.communicator.total_queue_length--;
7711 GNUNET_SERVICE_client_continue (tc->client);
7713 /* if applicable, resume transmissions that waited on ACK */
7714 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7715 tc->details.communicator.total_queue_length)
7717 /* Communicator dropped below threshold, resume all queues
7718 incident with this client! */
7719 GNUNET_STATISTICS_update (
7721 "# Transmission throttled due to communicator queue limit",
7724 for (struct Queue *queue = tc->details.communicator.queue_head;
7726 queue = queue->next_client)
7727 schedule_transmit_on_queue (queue, GNUNET_NO);
7729 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7731 /* queue dropped below threshold; only resume this one queue */
7732 GNUNET_STATISTICS_update (GST_stats,
7733 "# Transmission throttled due to queue queue limit",
7736 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7739 if (NULL != (pm = qe->pm))
7741 struct Neighbour *n;
7743 GNUNET_assert (qe == pm->qe);
7745 /* If waiting for this communicator may have blocked transmission
7746 of pm on other queues for this neighbour, force schedule
7747 transmit on queue for queues of the neighbour */
7749 if (n->pending_msg_head == pm)
7751 for (struct Queue *queue = n->queue_head; NULL != queue;
7752 queue = queue->next_neighbour)
7753 schedule_transmit_on_queue (queue, GNUNET_NO);
7755 if (GNUNET_OK != ntohl (sma->status))
7758 GNUNET_ERROR_TYPE_INFO,
7759 "Queue failed in transmission, will try retransmission immediately\n");
7760 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7768 * Iterator telling new MONITOR client about all existing
7771 * @param cls the new `struct TransportClient`
7772 * @param pid a connected peer
7773 * @param value the `struct Neighbour` with more information
7774 * @return #GNUNET_OK (continue to iterate)
7777 notify_client_queues (void *cls,
7778 const struct GNUNET_PeerIdentity *pid,
7781 struct TransportClient *tc = cls;
7782 struct Neighbour *neighbour = value;
7784 GNUNET_assert (CT_MONITOR == tc->type);
7785 for (struct Queue *q = neighbour->queue_head; NULL != q;
7786 q = q->next_neighbour)
7788 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7790 .num_msg_pending = q->num_msg_pending,
7791 .num_bytes_pending = q->num_bytes_pending};
7793 notify_monitor (tc, pid, q->address, q->nt, &me);
7800 * Initialize a monitor client.
7802 * @param cls the client
7803 * @param start the start message that was sent
7806 handle_monitor_start (void *cls,
7807 const struct GNUNET_TRANSPORT_MonitorStart *start)
7809 struct TransportClient *tc = cls;
7811 if (CT_NONE != tc->type)
7814 GNUNET_SERVICE_client_drop (tc->client);
7817 tc->type = CT_MONITOR;
7818 tc->details.monitor.peer = start->peer;
7819 tc->details.monitor.one_shot = ntohl (start->one_shot);
7820 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
7821 GNUNET_SERVICE_client_mark_monitor (tc->client);
7822 GNUNET_SERVICE_client_continue (tc->client);
7827 * Find transport client providing communication service
7828 * for the protocol @a prefix.
7830 * @param prefix communicator name
7831 * @return NULL if no such transport client is available
7833 static struct TransportClient *
7834 lookup_communicator (const char *prefix)
7836 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7838 if (CT_COMMUNICATOR != tc->type)
7840 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
7844 GNUNET_ERROR_TYPE_WARNING,
7845 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
7852 * Signature of a function called with a communicator @a address of a peer
7853 * @a pid that an application wants us to connect to.
7855 * @param pid target peer
7856 * @param address the address to try
7859 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
7861 static uint32_t idgen;
7862 struct TransportClient *tc;
7864 struct GNUNET_TRANSPORT_CreateQueue *cqm;
7865 struct GNUNET_MQ_Envelope *env;
7868 prefix = GNUNET_HELLO_address_to_prefix (address);
7871 GNUNET_break (0); /* We got an invalid address!? */
7874 tc = lookup_communicator (prefix);
7877 GNUNET_STATISTICS_update (GST_stats,
7878 "# Suggestions ignored due to missing communicator",
7883 /* forward suggestion for queue creation to communicator */
7884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7885 "Request #%u for `%s' communicator to create queue to `%s'\n",
7886 (unsigned int) idgen,
7889 alen = strlen (address) + 1;
7891 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
7892 cqm->request_id = htonl (idgen++);
7893 cqm->receiver = *pid;
7894 memcpy (&cqm[1], address, alen);
7895 GNUNET_MQ_send (tc->mq, env);
7900 * The queue @a q (which matches the peer and address in @a vs) is
7901 * ready for queueing. We should now queue the validation request.
7903 * @param q queue to send on
7904 * @param vs state to derive validation challenge from
7907 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
7909 struct TransportValidationChallengeMessage tvc;
7911 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
7913 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
7914 tvc.header.size = htons (sizeof (tvc));
7915 tvc.reserved = htonl (0);
7916 tvc.challenge = vs->challenge;
7917 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
7918 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7923 * Task run periodically to validate some address based on #validation_heap.
7928 validation_start_cb (void *cls)
7930 struct ValidationState *vs;
7934 validation_task = NULL;
7935 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7936 /* drop validations past their expiration */
7939 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7941 free_validation_state (vs);
7942 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7945 return; /* woopsie, no more addresses known, should only
7946 happen if we're really a lonely peer */
7947 q = find_queue (&vs->pid, vs->address);
7950 vs->awaiting_queue = GNUNET_YES;
7951 suggest_to_connect (&vs->pid, vs->address);
7954 validation_transmit_on_queue (q, vs);
7955 /* Finally, reschedule next attempt */
7956 vs->challenge_backoff =
7957 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
7958 MAX_VALIDATION_CHALLENGE_FREQ);
7959 update_next_challenge_time (vs,
7960 GNUNET_TIME_relative_to_absolute (
7961 vs->challenge_backoff));
7966 * Closure for #check_connection_quality.
7968 struct QueueQualityContext
7971 * Set to the @e k'th queue encountered.
7976 * Set to the number of quality queues encountered.
7978 unsigned int quality_count;
7981 * Set to the total number of queues encountered.
7983 unsigned int num_queues;
7986 * Decremented for each queue, for selection of the
7987 * k-th queue in @e q.
7994 * Check whether any queue to the given neighbour is
7995 * of a good "quality" and if so, increment the counter.
7996 * Also counts the total number of queues, and returns
7997 * the k-th queue found.
7999 * @param cls a `struct QueueQualityContext *` with counters
8000 * @param pid peer this is about
8001 * @param value a `struct Neighbour`
8002 * @return #GNUNET_OK (continue to iterate)
8005 check_connection_quality (void *cls,
8006 const struct GNUNET_PeerIdentity *pid,
8009 struct QueueQualityContext *ctx = cls;
8010 struct Neighbour *n = value;
8015 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8020 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
8021 statistics and consider those as well here? */
8022 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
8023 do_inc = GNUNET_YES;
8025 if (GNUNET_YES == do_inc)
8026 ctx->quality_count++;
8032 * Task run when we CONSIDER initiating a DV learn
8033 * process. We first check that sending out a message is
8034 * even possible (queues exist), then that it is desirable
8035 * (if not, reschedule the task for later), and finally
8036 * we may then begin the job. If there are too many
8037 * entries in the #dvlearn_map, we purge the oldest entry
8043 start_dv_learn (void *cls)
8045 struct LearnLaunchEntry *lle;
8046 struct QueueQualityContext qqc;
8047 struct TransportDVLearnMessage dvl;
8050 dvlearn_task = NULL;
8051 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8052 return; /* lost all connectivity, cannot do learning */
8053 qqc.quality_count = 0;
8055 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8056 &check_connection_quality,
8058 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8060 struct GNUNET_TIME_Relative delay;
8061 unsigned int factor;
8063 /* scale our retries by how far we are above the threshold */
8064 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8065 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8066 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8069 /* remove old entries in #dvlearn_map if it has grown too big */
8070 while (MAX_DV_LEARN_PENDING >=
8071 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8074 GNUNET_assert (GNUNET_YES ==
8075 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8076 &lle->challenge.value,
8078 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8081 /* setup data structure for learning */
8082 lle = GNUNET_new (struct LearnLaunchEntry);
8083 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8085 sizeof (lle->challenge));
8086 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8087 GNUNET_break (GNUNET_YES ==
8088 GNUNET_CONTAINER_multishortmap_put (
8090 &lle->challenge.value,
8092 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8093 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8094 dvl.header.size = htons (sizeof (dvl));
8095 dvl.num_hops = htons (0);
8096 dvl.bidirectional = htons (0);
8097 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8098 dvl.monotonic_time =
8099 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8101 struct DvInitPS dvip = {.purpose.purpose = htonl (
8102 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8103 .purpose.size = htonl (sizeof (dvip)),
8104 .monotonic_time = dvl.monotonic_time,
8105 .challenge = lle->challenge};
8107 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8111 dvl.initiator = GST_my_identity;
8112 dvl.challenge = lle->challenge;
8114 qqc.quality_count = 0;
8115 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8118 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8119 &check_connection_quality,
8121 GNUNET_assert (NULL != qqc.q);
8123 /* Do this as close to transmission time as possible! */
8124 lle->launch_time = GNUNET_TIME_absolute_get ();
8126 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8127 /* reschedule this job, randomizing the time it runs (but no
8129 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8130 DV_LEARN_BASE_FREQUENCY),
8137 * A new queue has been created, check if any address validation
8138 * requests have been waiting for it.
8140 * @param cls a `struct Queue`
8141 * @param pid peer concerned (unused)
8142 * @param value a `struct ValidationState`
8143 * @return #GNUNET_NO if a match was found and we can stop looking
8146 check_validation_request_pending (void *cls,
8147 const struct GNUNET_PeerIdentity *pid,
8150 struct Queue *q = cls;
8151 struct ValidationState *vs = value;
8154 if ((GNUNET_YES == vs->awaiting_queue) &&
8155 (0 == strcmp (vs->address, q->address)))
8157 vs->awaiting_queue = GNUNET_NO;
8158 validation_transmit_on_queue (q, vs);
8166 * Function called with the monotonic time of a DV initiator
8167 * by PEERSTORE. Updates the time.
8169 * @param cls a `struct Neighbour`
8170 * @param record the information found, NULL for the last call
8171 * @param emsg error message
8174 neighbour_dv_monotime_cb (void *cls,
8175 const struct GNUNET_PEERSTORE_Record *record,
8178 struct Neighbour *n = cls;
8179 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8184 /* we're done with #neighbour_dv_monotime_cb() invocations,
8185 continue normal processing */
8187 n->dv_monotime_available = GNUNET_YES;
8190 if (sizeof (*mtbe) != record->value_size)
8195 mtbe = record->value;
8196 n->last_dv_learn_monotime =
8197 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8198 GNUNET_TIME_absolute_ntoh (*mtbe));
8203 * New queue became available. Process the request.
8205 * @param cls the client
8206 * @param aqm the send message that was sent
8209 handle_add_queue_message (void *cls,
8210 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8212 struct TransportClient *tc = cls;
8213 struct Queue *queue;
8214 struct Neighbour *neighbour;
8218 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8220 /* MTU so small as to be useless for transmissions,
8221 required for #fragment_message()! */
8222 GNUNET_break_op (0);
8223 GNUNET_SERVICE_client_drop (tc->client);
8226 neighbour = lookup_neighbour (&aqm->receiver);
8227 if (NULL == neighbour)
8229 neighbour = GNUNET_new (struct Neighbour);
8230 neighbour->pid = aqm->receiver;
8231 GNUNET_assert (GNUNET_OK ==
8232 GNUNET_CONTAINER_multipeermap_put (
8236 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8238 GNUNET_PEERSTORE_iterate (peerstore,
8241 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8242 &neighbour_dv_monotime_cb,
8245 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8246 addr = (const char *) &aqm[1];
8248 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8250 queue->address = (const char *) &queue[1];
8251 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8252 queue->qid = aqm->qid;
8253 queue->mtu = ntohl (aqm->mtu);
8254 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8255 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8256 queue->neighbour = neighbour;
8257 memcpy (&queue[1], addr, addr_len);
8258 /* notify monitors about new queue */
8260 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8262 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8264 GNUNET_CONTAINER_MDLL_insert (neighbour,
8265 neighbour->queue_head,
8266 neighbour->queue_tail,
8268 GNUNET_CONTAINER_MDLL_insert (client,
8269 tc->details.communicator.queue_head,
8270 tc->details.communicator.queue_tail,
8272 /* check if valdiations are waiting for the queue */
8274 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8276 &check_validation_request_pending,
8278 /* might be our first queue, try launching DV learning */
8279 if (NULL == dvlearn_task)
8280 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8281 GNUNET_SERVICE_client_continue (tc->client);
8286 * Communicator tells us that our request to create a queue "worked", that
8287 * is setting up the queue is now in process.
8289 * @param cls the `struct TransportClient`
8290 * @param cqr confirmation message
8293 handle_queue_create_ok (void *cls,
8294 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8296 struct TransportClient *tc = cls;
8298 if (CT_COMMUNICATOR != tc->type)
8301 GNUNET_SERVICE_client_drop (tc->client);
8304 GNUNET_STATISTICS_update (GST_stats,
8305 "# Suggestions succeeded at communicator",
8308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8309 "Request #%u for communicator to create queue succeeded\n",
8310 (unsigned int) ntohs (cqr->request_id));
8311 GNUNET_SERVICE_client_continue (tc->client);
8316 * Communicator tells us that our request to create a queue failed. This
8317 * usually indicates that the provided address is simply invalid or that the
8318 * communicator's resources are exhausted.
8320 * @param cls the `struct TransportClient`
8321 * @param cqr failure message
8324 handle_queue_create_fail (
8326 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8328 struct TransportClient *tc = cls;
8330 if (CT_COMMUNICATOR != tc->type)
8333 GNUNET_SERVICE_client_drop (tc->client);
8336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8337 "Request #%u for communicator to create queue failed\n",
8338 (unsigned int) ntohs (cqr->request_id));
8339 GNUNET_STATISTICS_update (GST_stats,
8340 "# Suggestions failed in queue creation at communicator",
8343 GNUNET_SERVICE_client_continue (tc->client);
8348 * We have received a `struct ExpressPreferenceMessage` from an application
8351 * @param cls handle to the client
8352 * @param msg the start message
8355 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8357 struct TransportClient *tc = cls;
8358 struct PeerRequest *pr;
8360 if (CT_APPLICATION != tc->type)
8363 GNUNET_SERVICE_client_drop (tc->client);
8366 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8371 GNUNET_SERVICE_client_drop (tc->client);
8374 (void) stop_peer_request (tc, &pr->pid, pr);
8375 GNUNET_SERVICE_client_continue (tc->client);
8380 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8381 * messages. We do nothing here, real verification is done later.
8383 * @param cls a `struct TransportClient *`
8384 * @param msg message to verify
8385 * @return #GNUNET_OK
8388 check_address_consider_verify (
8390 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8399 * Closure for #check_known_address.
8401 struct CheckKnownAddressContext
8404 * Set to the address we are looking for.
8406 const char *address;
8409 * Set to a matching validation state, if one was found.
8411 struct ValidationState *vs;
8416 * Test if the validation state in @a value matches the
8417 * address from @a cls.
8419 * @param cls a `struct CheckKnownAddressContext`
8420 * @param pid unused (must match though)
8421 * @param value a `struct ValidationState`
8422 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8425 check_known_address (void *cls,
8426 const struct GNUNET_PeerIdentity *pid,
8429 struct CheckKnownAddressContext *ckac = cls;
8430 struct ValidationState *vs = value;
8433 if (0 != strcmp (vs->address, ckac->address))
8441 * Start address validation.
8443 * @param pid peer the @a address is for
8444 * @param address an address to reach @a pid (presumably)
8445 * @param expiration when did @a pid claim @a address will become invalid
8448 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8449 const char *address,
8450 struct GNUNET_TIME_Absolute expiration)
8452 struct GNUNET_TIME_Absolute now;
8453 struct ValidationState *vs;
8454 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8456 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
8457 return; /* expired */
8458 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8460 &check_known_address,
8462 if (NULL != (vs = ckac.vs))
8464 /* if 'vs' is not currently valid, we need to speed up retrying the
8466 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8468 /* reduce backoff as we got a fresh advertisement */
8469 vs->challenge_backoff =
8470 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8471 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8473 update_next_challenge_time (vs,
8474 GNUNET_TIME_relative_to_absolute (
8475 vs->challenge_backoff));
8479 now = GNUNET_TIME_absolute_get ();
8480 vs = GNUNET_new (struct ValidationState);
8482 vs->valid_until = expiration;
8483 vs->first_challenge_use = now;
8484 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8485 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8487 sizeof (vs->challenge));
8488 vs->address = GNUNET_strdup (address);
8489 GNUNET_assert (GNUNET_YES ==
8490 GNUNET_CONTAINER_multipeermap_put (
8494 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8495 update_next_challenge_time (vs, now);
8500 * Function called by PEERSTORE for each matching record.
8502 * @param cls closure
8503 * @param record peerstore record information
8504 * @param emsg error message, or NULL if no errors
8507 handle_hello (void *cls,
8508 const struct GNUNET_PEERSTORE_Record *record,
8511 struct PeerRequest *pr = cls;
8516 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8517 "Got failure from PEERSTORE: %s\n",
8521 val = record->value;
8522 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8527 start_address_validation (&pr->pid,
8528 (const char *) record->value,
8534 * We have received a `struct ExpressPreferenceMessage` from an application
8537 * @param cls handle to the client
8538 * @param msg the start message
8541 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8543 struct TransportClient *tc = cls;
8544 struct PeerRequest *pr;
8546 if (CT_NONE == tc->type)
8548 tc->type = CT_APPLICATION;
8549 tc->details.application.requests =
8550 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8552 if (CT_APPLICATION != tc->type)
8555 GNUNET_SERVICE_client_drop (tc->client);
8558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8559 "Client suggested we talk to %s with preference %d at rate %u\n",
8560 GNUNET_i2s (&msg->peer),
8561 (int) ntohl (msg->pk),
8562 (int) ntohl (msg->bw.value__));
8563 pr = GNUNET_new (struct PeerRequest);
8565 pr->pid = msg->peer;
8567 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
8568 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8569 tc->details.application.requests,
8572 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8576 GNUNET_SERVICE_client_drop (tc->client);
8579 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8582 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8585 GNUNET_SERVICE_client_continue (tc->client);
8590 * Given another peers address, consider checking it for validity
8591 * and then adding it to the Peerstore.
8593 * @param cls a `struct TransportClient`
8594 * @param hdr message containing the raw address data and
8595 * signature in the body, see #GNUNET_HELLO_extract_address()
8598 handle_address_consider_verify (
8600 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8602 struct TransportClient *tc = cls;
8604 enum GNUNET_NetworkType nt;
8605 struct GNUNET_TIME_Absolute expiration;
8608 // OPTIMIZE-FIXME: checking that we know this address already should
8609 // be done BEFORE checking the signature => HELLO API change!
8610 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8613 GNUNET_HELLO_extract_address (&hdr[1],
8614 ntohs (hdr->header.size) - sizeof (*hdr),
8618 if (NULL == address)
8620 GNUNET_break_op (0);
8623 start_address_validation (&hdr->peer, address, expiration);
8624 GNUNET_free (address);
8625 GNUNET_SERVICE_client_continue (tc->client);
8630 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8633 * @param cls a `struct TransportClient *`
8634 * @param m message to verify
8635 * @return #GNUNET_OK on success
8638 check_request_hello_validation (void *cls,
8639 const struct RequestHelloValidationMessage *m)
8642 GNUNET_MQ_check_zero_termination (m);
8648 * A client encountered an address of another peer. Consider validating it,
8649 * and if validation succeeds, persist it to PEERSTORE.
8651 * @param cls a `struct TransportClient *`
8652 * @param m message to verify
8655 handle_request_hello_validation (void *cls,
8656 const struct RequestHelloValidationMessage *m)
8658 struct TransportClient *tc = cls;
8660 start_address_validation (&m->peer,
8661 (const char *) &m[1],
8662 GNUNET_TIME_absolute_ntoh (m->expiration));
8663 GNUNET_SERVICE_client_continue (tc->client);
8668 * Free neighbour entry.
8672 * @param value a `struct Neighbour`
8673 * @return #GNUNET_OK (always)
8676 free_neighbour_cb (void *cls,
8677 const struct GNUNET_PeerIdentity *pid,
8680 struct Neighbour *neighbour = value;
8684 GNUNET_break (0); // should this ever happen?
8685 free_neighbour (neighbour);
8692 * Free DV route entry.
8696 * @param value a `struct DistanceVector`
8697 * @return #GNUNET_OK (always)
8700 free_dv_routes_cb (void *cls,
8701 const struct GNUNET_PeerIdentity *pid,
8704 struct DistanceVector *dv = value;
8715 * Free ephemeral entry.
8719 * @param value a `struct EphemeralCacheEntry`
8720 * @return #GNUNET_OK (always)
8723 free_ephemeral_cb (void *cls,
8724 const struct GNUNET_PeerIdentity *pid,
8727 struct EphemeralCacheEntry *ece = value;
8731 free_ephemeral (ece);
8737 * Free validation state.
8741 * @param value a `struct ValidationState`
8742 * @return #GNUNET_OK (always)
8745 free_validation_state_cb (void *cls,
8746 const struct GNUNET_PeerIdentity *pid,
8749 struct ValidationState *vs = value;
8753 free_validation_state (vs);
8759 * Free pending acknowledgement.
8763 * @param value a `struct PendingAcknowledgement`
8764 * @return #GNUNET_OK (always)
8767 free_pending_ack_cb (void *cls,
8768 const struct GNUNET_ShortHashCode *key,
8771 struct PendingAcknowledgement *pa = value;
8775 free_pending_acknowledgement (pa);
8781 * Free acknowledgement cummulator.
8785 * @param value a `struct AcknowledgementCummulator`
8786 * @return #GNUNET_OK (always)
8789 free_ack_cummulator_cb (void *cls,
8790 const struct GNUNET_PeerIdentity *pid,
8793 struct AcknowledgementCummulator *ac = value;
8803 * Function called when the service shuts down. Unloads our plugins
8804 * and cancels pending validations.
8806 * @param cls closure, unused
8809 do_shutdown (void *cls)
8811 struct LearnLaunchEntry *lle;
8814 if (NULL != ephemeral_task)
8816 GNUNET_SCHEDULER_cancel (ephemeral_task);
8817 ephemeral_task = NULL;
8819 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
8820 if (NULL != peerstore)
8822 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
8825 if (NULL != GST_stats)
8827 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
8830 if (NULL != GST_my_private_key)
8832 GNUNET_free (GST_my_private_key);
8833 GST_my_private_key = NULL;
8835 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
8836 &free_ack_cummulator_cb,
8838 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
8839 ack_cummulators = NULL;
8840 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
8841 &free_pending_ack_cb,
8843 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
8844 pending_acks = NULL;
8845 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
8846 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
8848 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
8849 GNUNET_CONTAINER_multipeermap_destroy (links);
8851 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
8852 &free_backtalker_cb,
8854 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
8856 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
8857 &free_validation_state_cb,
8859 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
8860 validation_map = NULL;
8861 while (NULL != (lle = lle_head))
8863 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8866 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
8868 GNUNET_CONTAINER_heap_destroy (validation_heap);
8869 validation_heap = NULL;
8870 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
8871 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
8873 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
8876 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
8877 ephemeral_map = NULL;
8878 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
8879 ephemeral_heap = NULL;
8884 * Initiate transport service.
8886 * @param cls closure
8887 * @param c configuration to use
8888 * @param service the initialized service
8892 const struct GNUNET_CONFIGURATION_Handle *c,
8893 struct GNUNET_SERVICE_Handle *service)
8899 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8900 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
8901 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
8902 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8903 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
8904 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8905 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
8907 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8908 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
8910 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
8912 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
8913 GST_my_private_key =
8914 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
8915 if (NULL == GST_my_private_key)
8918 GNUNET_ERROR_TYPE_ERROR,
8920 "Transport service is lacking key configuration settings. Exiting.\n"));
8921 GNUNET_SCHEDULER_shutdown ();
8924 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
8925 &GST_my_identity.public_key);
8926 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
8927 "My identity is `%s'\n",
8928 GNUNET_i2s_full (&GST_my_identity));
8929 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
8930 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
8931 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
8932 if (NULL == peerstore)
8935 GNUNET_SCHEDULER_shutdown ();
8942 * Define "main" method using service macro.
8944 GNUNET_SERVICE_MAIN (
8946 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
8949 &client_disconnect_cb,
8951 /* communication with applications */
8952 GNUNET_MQ_hd_fixed_size (suggest,
8953 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
8954 struct ExpressPreferenceMessage,
8956 GNUNET_MQ_hd_fixed_size (suggest_cancel,
8957 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
8958 struct ExpressPreferenceMessage,
8960 GNUNET_MQ_hd_var_size (request_hello_validation,
8961 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
8962 struct RequestHelloValidationMessage,
8964 /* communication with core */
8965 GNUNET_MQ_hd_fixed_size (client_start,
8966 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
8967 struct StartMessage,
8969 GNUNET_MQ_hd_var_size (client_send,
8970 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
8971 struct OutboundMessage,
8973 GNUNET_MQ_hd_fixed_size (client_recv_ok,
8974 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
8975 struct RecvOkMessage,
8977 /* communication with communicators */
8978 GNUNET_MQ_hd_var_size (communicator_available,
8979 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
8980 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
8982 GNUNET_MQ_hd_var_size (communicator_backchannel,
8983 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
8984 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
8986 GNUNET_MQ_hd_var_size (add_address,
8987 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
8988 struct GNUNET_TRANSPORT_AddAddressMessage,
8990 GNUNET_MQ_hd_fixed_size (del_address,
8991 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
8992 struct GNUNET_TRANSPORT_DelAddressMessage,
8994 GNUNET_MQ_hd_var_size (incoming_msg,
8995 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
8996 struct GNUNET_TRANSPORT_IncomingMessage,
8998 GNUNET_MQ_hd_fixed_size (queue_create_ok,
8999 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
9000 struct GNUNET_TRANSPORT_CreateQueueResponse,
9002 GNUNET_MQ_hd_fixed_size (queue_create_fail,
9003 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
9004 struct GNUNET_TRANSPORT_CreateQueueResponse,
9006 GNUNET_MQ_hd_var_size (add_queue_message,
9007 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
9008 struct GNUNET_TRANSPORT_AddQueueMessage,
9010 GNUNET_MQ_hd_var_size (address_consider_verify,
9011 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
9012 struct GNUNET_TRANSPORT_AddressToVerify,
9014 GNUNET_MQ_hd_fixed_size (del_queue_message,
9015 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
9016 struct GNUNET_TRANSPORT_DelQueueMessage,
9018 GNUNET_MQ_hd_fixed_size (send_message_ack,
9019 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
9020 struct GNUNET_TRANSPORT_SendMessageToAck,
9022 /* communication with monitors */
9023 GNUNET_MQ_hd_fixed_size (monitor_start,
9024 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
9025 struct GNUNET_TRANSPORT_MonitorStart,
9027 GNUNET_MQ_handler_end ());
9030 /* end of file gnunet-service-transport.c */