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 * - track RTT, distance, loss, etc. => requires extra data structures!
28 * - proper use/initialization of timestamps in messages exchanged
30 * - persistence of monotonic time obtained from other peers
31 * in PEERSTORE (by message type)
32 * - change transport-core API to provide proper flow control in both
33 * directions, allow multiple messages per peer simultaneously (tag
34 * confirmations with unique message ID), and replace quota-out with
35 * proper flow control; specify transmission preferences (latency,
36 * reliability, etc.) per message!
40 * - review retransmission logic, right now there is no smartness there!
41 * => congestion control, flow control, etc (requires RTT, loss, etc.)
44 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
45 * against our pending message queue (requires additional per neighbour
46 * hash map to be maintained, avoids possible linear scan on pending msgs)
47 * - queue_send_msg and route_message both by API design have to make copies
48 * of the payload, and route_message on top of that requires a malloc/free.
49 * Change design to approximate "zero" copy better...
50 * - could avoid copying body of message into each fragment and keep
51 * fragments as just pointers into the original message and only
52 * fully build fragments just before transmission (optimization, should
53 * reduce CPU and memory use)
54 * - if messages are below MTU, consider adding ACKs and other stuff
55 * (requires planning at receiver, and additional MST-style demultiplex
57 * - When we passively learned DV (with unconfirmed freshness), we
58 * right now add the path to our list but with a zero path_valid_until
59 * time and only use it for unconfirmed routes. However, we could consider
60 * triggering an explicit validation mechansim ourselves, specifically routing
61 * a challenge-response message over the path (OPTIMIZATION-FIXME).
63 * Design realizations / discussion:
64 * - communicators do flow control by calling MQ "notify sent"
65 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
66 * or explicitly via backchannel FC ACKs. As long as the
67 * channel is not full, they may 'notify sent' even if the other
68 * peer has not yet confirmed receipt. The other peer confirming
69 * is _only_ for FC, not for more reliable transmission; reliable
70 * transmission (i.e. of fragments) is left to _transport_.
71 * - ACKs sent back in uni-directional communicators are done via
72 * the background channel API; here transport _may_ initially
73 * broadcast (with bounded # hops) if no path is known;
74 * - transport should _integrate_ DV-routing and build a view of
75 * the network; then background channel traffic can be
76 * routed via DV as well as explicit "DV" traffic.
77 * - background channel is also used for ACKs and NAT traversal support
78 * - transport service is responsible for AEAD'ing the background
79 * channel, timestamps and monotonic time are used against replay
80 * of old messages -> peerstore needs to be supplied with
81 * "latest timestamps seen" data
82 * - if transport implements DV, we likely need a 3rd peermap
83 * in addition to ephemerals and (direct) neighbours
84 * ==> check if stuff needs to be moved out of "Neighbour"
85 * - transport should encapsualte core-level messages and do its
86 * own ACKing for RTT/goodput/loss measurements _and_ fragment
90 #include "gnunet_util_lib.h"
91 #include "gnunet_statistics_service.h"
92 #include "gnunet_transport_monitor_service.h"
93 #include "gnunet_peerstore_service.h"
94 #include "gnunet_hello_lib.h"
95 #include "gnunet_signatures.h"
96 #include "transport.h"
100 * What is the size we assume for a read operation in the
101 * absence of an MTU for the purpose of flow control?
103 #define IN_PACKET_SIZE_WITHOUT_MTU 128
106 * Minimum number of hops we should forward DV learn messages
107 * even if they are NOT useful for us in hope of looping
108 * back to the initiator?
110 * FIXME: allow initiator some control here instead?
112 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
115 * Maximum DV distance allowed ever.
117 #define MAX_DV_HOPS_ALLOWED 16
120 * Maximum number of DV learning activities we may
121 * have pending at the same time.
123 #define MAX_DV_LEARN_PENDING 64
126 * Maximum number of DV paths we keep simultaneously to the same target.
128 #define MAX_DV_PATHS_TO_TARGET 3
131 * If a queue delays the next message by more than this number
132 * of seconds we log a warning. Note: this is for testing,
133 * the value chosen here might be too aggressively low!
135 #define DELAY_WARN_THRESHOLD \
136 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
139 * We only consider queues as "quality" connections when
140 * suppressing the generation of DV initiation messages if
141 * the latency of the queue is below this threshold.
143 #define DV_QUALITY_RTT_THRESHOLD \
144 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
147 * How long do we consider a DV path valid if we see no
148 * further updates on it? Note: the value chosen here might be too low!
150 #define DV_PATH_VALIDITY_TIMEOUT \
151 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
154 * How long do we cache backchannel (struct Backtalker) information
155 * after a backchannel goes inactive?
157 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
158 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
161 * How long before paths expire would we like to (re)discover DV paths? Should
162 * be below #DV_PATH_VALIDITY_TIMEOUT.
164 #define DV_PATH_DISCOVERY_FREQUENCY \
165 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
168 * How long are ephemeral keys valid?
170 #define EPHEMERAL_VALIDITY \
171 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
174 * How long do we keep partially reassembled messages around before giving up?
176 #define REASSEMBLY_EXPIRATION \
177 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
180 * What is the fastest rate at which we send challenges *if* we keep learning
181 * an address (gossip, DHT, etc.)?
183 #define FAST_VALIDATION_CHALLENGE_FREQ \
184 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
187 * What is the slowest rate at which we send challenges?
189 #define MAX_VALIDATION_CHALLENGE_FREQ \
190 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
193 * What is the non-randomized base frequency at which we
194 * would initiate DV learn messages?
196 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
199 * How many good connections (confirmed, bi-directional, not DV)
200 * do we need to have to suppress initiating DV learn messages?
202 #define DV_LEARN_QUALITY_THRESHOLD 100
205 * When do we forget an invalid address for sure?
207 #define MAX_ADDRESS_VALID_UNTIL \
208 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
211 * How long do we consider an address valid if we just checked?
213 #define ADDRESS_VALIDATION_LIFETIME \
214 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
217 * What is the maximum frequency at which we do address validation?
218 * A random value between 0 and this value is added when scheduling
219 * the #validation_task (both to ensure we do not validate too often,
220 * and to randomize a bit).
222 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
225 * How many network RTTs before an address validation expires should we begin
226 * trying to revalidate? (Note that the RTT used here is the one that we
227 * experienced during the last validation, not necessarily the latest RTT
230 #define VALIDATION_RTT_BUFFER_FACTOR 3
233 * How many messages can we have pending for a given communicator
234 * process before we start to throttle that communicator?
236 * Used if a communicator might be CPU-bound and cannot handle the traffic.
238 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
241 * How many messages can we have pending for a given queue (queue to
242 * a particular peer via a communicator) process before we start to
243 * throttle that queue?
245 #define QUEUE_LENGTH_LIMIT 32
248 GNUNET_NETWORK_STRUCT_BEGIN
251 * Outer layer of an encapsulated backchannel message.
253 struct TransportBackchannelEncapsulationMessage
256 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
258 struct GNUNET_MessageHeader header;
261 * Reserved, always zero.
263 uint32_t reserved GNUNET_PACKED;
266 * Target's peer identity (as backchannels may be transmitted
267 * indirectly, or even be broadcast).
269 struct GNUNET_PeerIdentity target;
272 * Ephemeral key setup by the sender for @e target, used
273 * to encrypt the payload.
275 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
278 * We use an IV here as the @e ephemeral_key is re-used for
279 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
281 struct GNUNET_ShortHashCode iv;
284 * HMAC over the ciphertext of the encrypted, variable-size
285 * body that follows. Verified via DH of @e target and
288 struct GNUNET_HashCode hmac;
290 /* Followed by encrypted, variable-size payload */
295 * Body by which a peer confirms that it is using an ephemeral key.
297 struct EphemeralConfirmationPS
301 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
303 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
306 * How long is this signature over the ephemeral key valid?
308 * Note that the receiver MUST IGNORE the absolute time, and only interpret
309 * the value as a mononic time and reject "older" values than the last one
310 * observed. This is necessary as we do not want to require synchronized
311 * clocks and may not have a bidirectional communication channel.
313 * Even with this, there is no real guarantee against replay achieved here,
314 * unless the latest timestamp is persisted. While persistence should be
315 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
316 * communicators must protect against replay attacks when using backchannel
319 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
322 * Target's peer identity.
324 struct GNUNET_PeerIdentity target;
327 * Ephemeral key setup by the sender for @e target, used
328 * to encrypt the payload.
330 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
335 * Plaintext of the variable-size payload that is encrypted
336 * within a `struct TransportBackchannelEncapsulationMessage`
338 struct TransportBackchannelRequestPayload
342 * Sender's peer identity.
344 struct GNUNET_PeerIdentity sender;
347 * Signature of the sender over an
348 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
350 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
353 * How long is this signature over the ephemeral key valid?
355 * Note that the receiver MUST IGNORE the absolute time, and only interpret
356 * the value as a mononic time and reject "older" values than the last one
357 * observed. This is necessary as we do not want to require synchronized
358 * clocks and may not have a bidirectional communication channel.
360 * Even with this, there is no real guarantee against replay achieved here,
361 * unless the latest timestamp is persisted. While persistence should be
362 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
363 * communicators must protect against replay attacks when using backchannel
366 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
369 * Current monotonic time of the sending transport service. Used to
370 * detect replayed messages. Note that the receiver should remember
371 * a list of the recently seen timestamps and only reject messages
372 * if the timestamp is in the list, or the list is "full" and the
373 * timestamp is smaller than the lowest in the list.
375 * Like the @e ephemeral_validity, the list of timestamps per peer should be
376 * persisted to guard against replays after restarts.
378 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
380 /* Followed by a `struct GNUNET_MessageHeader` with a message
381 for a communicator */
383 /* Followed by a 0-termianted string specifying the name of
384 the communicator which is to receive the message */
389 * Outer layer of an encapsulated unfragmented application message sent
390 * over an unreliable channel.
392 struct TransportReliabilityBox
395 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
397 struct GNUNET_MessageHeader header;
400 * Number of messages still to be sent before a commulative
401 * ACK is requested. Zero if an ACK is requested immediately.
402 * In NBO. Note that the receiver may send the ACK faster
403 * if it believes that is reasonable.
405 uint32_t ack_countdown GNUNET_PACKED;
408 * Unique ID of the message used for signalling receipt of
409 * messages sent over possibly unreliable channels. Should
412 struct GNUNET_ShortHashCode msg_uuid;
417 * Confirmation that the receiver got a
418 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
419 * confirmation may be transmitted over a completely different queue,
420 * so ACKs are identified by a combination of PID of sender and
421 * message UUID, without the queue playing any role!
423 struct TransportReliabilityAckMessage
426 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
428 struct GNUNET_MessageHeader header;
433 uint32_t reserved GNUNET_PACKED;
436 * How long was the ACK delayed relative to the average time of
437 * receipt of the messages being acknowledged? Used to calculate
438 * the average RTT by taking the receipt time of the ack minus the
439 * average transmission time of the sender minus this value.
441 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
443 /* followed by any number of `struct GNUNET_ShortHashCode`
444 messages providing ACKs */
449 * Outer layer of an encapsulated fragmented application message.
451 struct TransportFragmentBox
454 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
456 struct GNUNET_MessageHeader header;
459 * Unique ID of this fragment (and fragment transmission!). Will
460 * change even if a fragement is retransmitted to make each
461 * transmission attempt unique! Should be incremented by one for
462 * each fragment transmission. If a client receives a duplicate
463 * fragment (same @e frag_off), it must send
464 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
466 uint32_t frag_uuid GNUNET_PACKED;
469 * Original message ID for of the message that all the1
470 * fragments belong to. Must be the same for all fragments.
472 struct GNUNET_ShortHashCode msg_uuid;
475 * Offset of this fragment in the overall message.
477 uint16_t frag_off GNUNET_PACKED;
480 * Total size of the message that is being fragmented.
482 uint16_t msg_size GNUNET_PACKED;
487 * Outer layer of an fragmented application message sent over a queue
488 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
489 * received, the receiver has two RTTs or 64 further fragments with
490 * the same basic message time to send an acknowledgement, possibly
491 * acknowledging up to 65 fragments in one ACK. ACKs must also be
492 * sent immediately once all fragments were sent.
494 struct TransportFragmentAckMessage
497 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
499 struct GNUNET_MessageHeader header;
502 * Unique ID of the lowest fragment UUID being acknowledged.
504 uint32_t frag_uuid GNUNET_PACKED;
507 * Bitfield of up to 64 additional fragments following the
508 * @e msg_uuid being acknowledged by this message.
510 uint64_t extra_acks GNUNET_PACKED;
513 * Original message ID for of the message that all the
514 * fragments belong to.
516 struct GNUNET_ShortHashCode msg_uuid;
519 * How long was the ACK delayed relative to the average time of
520 * receipt of the fragments being acknowledged? Used to calculate
521 * the average RTT by taking the receipt time of the ack minus the
522 * average transmission time of the sender minus this value.
524 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
527 * How long until the receiver will stop trying reassembly
530 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
535 * Content signed by the initator during DV learning.
537 * The signature is required to prevent DDoS attacks. A peer sending out this
538 * message is potentially generating a lot of traffic that will go back to the
539 * initator, as peers receiving this message will try to let the initiator
540 * know that they got the message.
542 * Without this signature, an attacker could abuse this mechanism for traffic
543 * amplification, sending a lot of traffic to a peer by putting out this type
544 * of message with the victim's peer identity.
546 * Even with just a signature, traffic amplification would be possible via
547 * replay attacks. The @e monotonic_time limits such replay attacks, as every
548 * potential amplificator will check the @e monotonic_time and only respond
549 * (at most) once per message.
554 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
556 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
559 * Time at the initiator when generating the signature.
561 * Note that the receiver MUST IGNORE the absolute time, and only interpret
562 * the value as a mononic time and reject "older" values than the last one
563 * observed. This is necessary as we do not want to require synchronized
564 * clocks and may not have a bidirectional communication channel.
566 * Even with this, there is no real guarantee against replay achieved here,
567 * unless the latest timestamp is persisted. Persistence should be
568 * provided via PEERSTORE if possible.
570 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
573 * Challenge value used by the initiator to re-identify the path.
575 struct GNUNET_ShortHashCode challenge;
580 * Content signed by each peer during DV learning.
582 * This assues the initiator of the DV learning operation that the hop from @e
583 * pred via the signing peer to @e succ actually exists. This makes it
584 * impossible for an adversary to supply the network with bogus routes.
586 * The @e challenge is included to provide replay protection for the
587 * initiator. This way, the initiator knows that the hop existed after the
588 * original @e challenge was first transmitted, providing a freshness metric.
590 * Peers other than the initiator that passively learn paths by observing
591 * these messages do NOT benefit from this. Here, an adversary may indeed
592 * replay old messages. Thus, passively learned paths should always be
593 * immediately marked as "potentially stale".
598 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
600 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
603 * Identity of the previous peer on the path.
605 struct GNUNET_PeerIdentity pred;
608 * Identity of the next peer on the path.
610 struct GNUNET_PeerIdentity succ;
613 * Challenge value used by the initiator to re-identify the path.
615 struct GNUNET_ShortHashCode challenge;
620 * An entry describing a peer on a path in a
621 * `struct TransportDVLearn` message.
626 * Identity of a peer on the path.
628 struct GNUNET_PeerIdentity hop;
631 * Signature of this hop over the path, of purpose
632 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
634 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
639 * Internal message used by transport for distance vector learning.
640 * If @e num_hops does not exceed the threshold, peers should append
641 * themselves to the peer list and flood the message (possibly only
642 * to a subset of their neighbours to limit discoverability of the
643 * network topology). To the extend that the @e bidirectional bits
644 * are set, peers may learn the inverse paths even if they did not
647 * Unless received on a bidirectional queue and @e num_hops just
648 * zero, peers that can forward to the initator should always try to
649 * forward to the initiator.
651 struct TransportDVLearn
654 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
656 struct GNUNET_MessageHeader header;
659 * Number of hops this messages has travelled, in NBO. Zero if
662 uint16_t num_hops GNUNET_PACKED;
665 * Bitmask of the last 16 hops indicating whether they are confirmed
666 * available (without DV) in both directions or not, in NBO. Used
667 * to possibly instantly learn a path in both directions. Each peer
668 * should shift this value by one to the left, and then set the
669 * lowest bit IF the current sender can be reached from it (without
672 uint16_t bidirectional GNUNET_PACKED;
675 * Peers receiving this message and delaying forwarding to other
676 * peers for any reason should increment this value by the non-network
677 * delay created by the peer.
679 struct GNUNET_TIME_RelativeNBO non_network_delay;
682 * Signature of this hop over the path, of purpose
683 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
685 struct GNUNET_CRYPTO_EddsaSignature init_sig;
688 * Identity of the peer that started this learning activity.
690 struct GNUNET_PeerIdentity initiator;
693 * Challenge value used by the initiator to re-identify the path.
695 struct GNUNET_ShortHashCode challenge;
697 /* Followed by @e num_hops `struct DVPathEntryP` values,
698 excluding the initiator of the DV trace; the last entry is the
699 current sender; the current peer must not be included. */
704 * Outer layer of an encapsulated message send over multiple hops.
705 * The path given only includes the identities of the subsequent
706 * peers, i.e. it will be empty if we are the receiver. Each
707 * forwarding peer should scan the list from the end, and if it can,
708 * forward to the respective peer. The list should then be shortened
709 * by all the entries up to and including that peer. Each hop should
710 * also increment @e total_hops to allow the receiver to get a precise
711 * estimate on the number of hops the message travelled. Senders must
712 * provide a learned path that thus should work, but intermediaries
713 * know of a shortcut, they are allowed to send the message via that
716 * If a peer finds itself still on the list, it must drop the message.
718 struct TransportDVBox
721 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
723 struct GNUNET_MessageHeader header;
726 * Number of total hops this messages travelled. In NBO.
727 * @e origin sets this to zero, to be incremented at
730 uint16_t total_hops GNUNET_PACKED;
733 * Number of hops this messages includes. In NBO.
735 uint16_t num_hops GNUNET_PACKED;
738 * Identity of the peer that originated the message.
740 struct GNUNET_PeerIdentity origin;
742 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
743 excluding the @e origin and the current peer, the last must be
744 the ultimate target; if @e num_hops is zero, the receiver of this
745 message is the ultimate target. */
747 /* Followed by the actual message, which itself may be
748 another box, but not a DV_LEARN or DV_BOX message! */
753 * Message send to another peer to validate that it can indeed
754 * receive messages at a particular address.
756 struct TransportValidationChallenge
760 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
762 struct GNUNET_MessageHeader header;
767 uint32_t reserved GNUNET_PACKED;
770 * Challenge to be signed by the receiving peer.
772 struct GNUNET_ShortHashCode challenge;
775 * Timestamp of the sender, to be copied into the reply
776 * to allow sender to calculate RTT.
778 struct GNUNET_TIME_AbsoluteNBO sender_time;
783 * Message signed by a peer to confirm that it can indeed
784 * receive messages at a particular address.
786 struct TransportValidationPS
790 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
792 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
795 * How long does the sender believe the address on
796 * which the challenge was received to remain valid?
798 struct GNUNET_TIME_RelativeNBO validity_duration;
801 * Challenge signed by the receiving peer.
803 struct GNUNET_ShortHashCode challenge;
808 * Message send to a peer to respond to a
809 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
811 struct TransportValidationResponse
815 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
817 struct GNUNET_MessageHeader header;
822 uint32_t reserved GNUNET_PACKED;
825 * The peer's signature matching the
826 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
828 struct GNUNET_CRYPTO_EddsaSignature signature;
831 * The challenge that was signed by the receiving peer.
833 struct GNUNET_ShortHashCode challenge;
836 * Original timestamp of the sender (was @code{sender_time}),
837 * copied into the reply to allow sender to calculate RTT.
839 struct GNUNET_TIME_AbsoluteNBO origin_time;
842 * How long does the sender believe this address to remain
845 struct GNUNET_TIME_RelativeNBO validity_duration;
849 GNUNET_NETWORK_STRUCT_END
853 * What type of client is the `struct TransportClient` about?
858 * We do not know yet (client is fresh).
863 * Is the CORE service, we need to forward traffic to it.
868 * It is a monitor, forward monitor data.
873 * It is a communicator, use for communication.
878 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
885 * When did we launch this DV learning activity?
887 struct LearnLaunchEntry
891 * Kept (also) in a DLL sorted by launch time.
893 struct LearnLaunchEntry *prev;
896 * Kept (also) in a DLL sorted by launch time.
898 struct LearnLaunchEntry *next;
901 * Challenge that uniquely identifies this activity.
903 struct GNUNET_ShortHashCode challenge;
906 * When did we transmit the DV learn message (used to calculate RTT) and
907 * determine freshness of paths learned via this operation.
909 struct GNUNET_TIME_Absolute launch_time;
914 * Entry in our cache of ephemeral keys we currently use. This way, we only
915 * sign an ephemeral once per @e target, and then can re-use it over multiple
916 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
917 * signing is expensive and in some cases we may use backchannel messages a
920 struct EphemeralCacheEntry
924 * Target's peer identity (we don't re-use ephemerals
925 * to limit linkability of messages).
927 struct GNUNET_PeerIdentity target;
930 * Signature affirming @e ephemeral_key of type
931 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
933 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
936 * How long is @e sender_sig valid
938 struct GNUNET_TIME_Absolute ephemeral_validity;
943 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
946 * Our private ephemeral key.
948 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
951 * Node in the ephemeral cache for this entry.
952 * Used for expiration.
954 struct GNUNET_CONTAINER_HeapNode *hn;
959 * Client connected to the transport service.
961 struct TransportClient;
965 * A neighbour that at least one communicator is connected to.
971 * Entry in our #dv_routes table, representing a (set of) distance
972 * vector routes to a particular peer.
974 struct DistanceVector;
977 * One possible hop towards a DV target.
979 struct DistanceVectorHop
983 * Kept in a MDLL, sorted by @e timeout.
985 struct DistanceVectorHop *next_dv;
988 * Kept in a MDLL, sorted by @e timeout.
990 struct DistanceVectorHop *prev_dv;
995 struct DistanceVectorHop *next_neighbour;
1000 struct DistanceVectorHop *prev_neighbour;
1003 * What would be the next hop to @e target?
1005 struct Neighbour *next_hop;
1008 * Distance vector entry this hop belongs with.
1010 struct DistanceVector *dv;
1013 * Array of @e distance hops to the target, excluding @e next_hop.
1014 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1015 * at the end of this struct. Excludes the target itself!
1017 const struct GNUNET_PeerIdentity *path;
1020 * At what time do we forget about this path unless we see it again
1023 struct GNUNET_TIME_Absolute timeout;
1026 * For how long is the validation of this path considered
1028 * Set to ZERO if the path is learned by snooping on DV learn messages
1029 * initiated by other peers, and to the time at which we generated the
1030 * challenge for DV learn operations this peer initiated.
1032 struct GNUNET_TIME_Absolute path_valid_until;
1035 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1036 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1039 unsigned int distance;
1044 * Entry in our #dv_routes table, representing a (set of) distance
1045 * vector routes to a particular peer.
1047 struct DistanceVector
1051 * To which peer is this a route?
1053 struct GNUNET_PeerIdentity target;
1056 * Known paths to @e target.
1058 struct DistanceVectorHop *dv_head;
1061 * Known paths to @e target.
1063 struct DistanceVectorHop *dv_tail;
1066 * Task scheduled to purge expired paths from @e dv_head MDLL.
1068 struct GNUNET_SCHEDULER_Task *timeout_task;
1071 * Task scheduled to possibly notfiy core that this queue is no longer
1072 * counting as confirmed. Runs the #core_queue_visibility_check().
1074 struct GNUNET_SCHEDULER_Task *visibility_task;
1077 * Quota at which CORE is allowed to transmit to this peer
1078 * (note that the value CORE should actually be told is this
1079 * value plus the respective value in `struct Neighbour`).
1080 * Should match the sum of the quotas of all of the paths.
1082 * FIXME: not yet set, tricky to get right given multiple paths,
1083 * many of which may be inactive! (=> Idea: measure???)
1084 * FIXME: how do we set this value initially when we tell CORE?
1085 * Options: start at a minimum value or at literally zero?
1086 * (=> Current thought: clean would be zero!)
1088 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1091 * Is one of the DV paths in this struct 'confirmed' and thus
1092 * the cause for CORE to see this peer as connected? (Note that
1093 * the same may apply to a `struct Neighbour` at the same time.)
1100 * A queue is a message queue provided by a communicator
1101 * via which we can reach a particular neighbour.
1106 * Message awaiting transmission. See detailed comments below.
1108 struct PendingMessage;
1111 * Entry identifying transmission in one of our `struct
1112 * Queue` which still awaits an ACK. This is used to
1113 * ensure we do not overwhelm a communicator and limit the number of
1114 * messages outstanding per communicator (say in case communicator is
1115 * CPU bound) and per queue (in case bandwidth allocation exceeds
1116 * what the communicator can actually provide towards a particular
1125 struct QueueEntry *next;
1130 struct QueueEntry *prev;
1133 * Queue this entry is queued with.
1135 struct Queue *queue;
1138 * Pending message this entry is for, or NULL for none.
1140 struct PendingMessage *pm;
1143 * Message ID used for this message with the queue used for transmission.
1150 * A queue is a message queue provided by a communicator
1151 * via which we can reach a particular neighbour.
1158 struct Queue *next_neighbour;
1163 struct Queue *prev_neighbour;
1168 struct Queue *prev_client;
1173 struct Queue *next_client;
1176 * Head of DLL of unacked transmission requests.
1178 struct QueueEntry *queue_head;
1181 * End of DLL of unacked transmission requests.
1183 struct QueueEntry *queue_tail;
1186 * Which neighbour is this queue for?
1188 struct Neighbour *neighbour;
1191 * Which communicator offers this queue?
1193 struct TransportClient *tc;
1196 * Address served by the queue.
1198 const char *address;
1201 * Task scheduled for the time when this queue can (likely) transmit the
1202 * next message. Still needs to check with the @e tracker_out to be sure.
1204 struct GNUNET_SCHEDULER_Task *transmit_task;
1207 * Task scheduled to possibly notfiy core that this queue is no longer
1208 * counting as confirmed. Runs the #core_queue_visibility_check().
1210 struct GNUNET_SCHEDULER_Task *visibility_task;
1213 * Our current RTT estimate for this queue.
1215 struct GNUNET_TIME_Relative rtt;
1218 * How long do *we* consider this @e address to be valid? In the past or
1219 * zero if we have not yet validated it. Can be updated based on
1220 * challenge-response validations (via address validation logic), or when we
1221 * receive ACKs that we can definitively map to transmissions via this
1224 struct GNUNET_TIME_Absolute validated_until;
1227 * Message ID generator for transmissions on this queue.
1232 * Unique identifier of this queue with the communicator.
1237 * Maximum transmission unit supported by this queue.
1244 uint32_t num_msg_pending;
1249 uint32_t num_bytes_pending;
1252 * Length of the DLL starting at @e queue_head.
1254 unsigned int queue_length;
1257 * Network type offered by this queue.
1259 enum GNUNET_NetworkType nt;
1262 * Connection status for this queue.
1264 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1267 * How much outbound bandwidth do we have available for this queue?
1269 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1272 * How much inbound bandwidth do we have available for this queue?
1274 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1279 * Information we keep for a message that we are reassembling.
1281 struct ReassemblyContext
1285 * Original message ID for of the message that all the
1286 * fragments belong to.
1288 struct GNUNET_ShortHashCode msg_uuid;
1291 * Which neighbour is this context for?
1293 struct Neighbour *neighbour;
1296 * Entry in the reassembly heap (sorted by expiration).
1298 struct GNUNET_CONTAINER_HeapNode *hn;
1301 * Bitfield with @e msg_size bits representing the positions
1302 * where we have received fragments. When we receive a fragment,
1303 * we check the bits in @e bitfield before incrementing @e msg_missing.
1305 * Allocated after the reassembled message.
1310 * Task for sending ACK. We may send ACKs either because of hitting
1311 * the @e extra_acks limit, or based on time and @e num_acks. This
1312 * task is for the latter case.
1314 struct GNUNET_SCHEDULER_Task *ack_task;
1317 * At what time will we give up reassembly of this message?
1319 struct GNUNET_TIME_Absolute reassembly_timeout;
1322 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1323 * Should be reset to zero when @e num_acks is set to 0.
1325 struct GNUNET_TIME_Relative avg_ack_delay;
1328 * Time we received the last fragment. @e avg_ack_delay must be
1329 * incremented by now - @e last_frag multiplied by @e num_acks.
1331 struct GNUNET_TIME_Absolute last_frag;
1334 * Bitfield of up to 64 additional fragments following @e frag_uuid
1335 * to be acknowledged in the next cummulative ACK.
1337 uint64_t extra_acks;
1340 * Unique ID of the lowest fragment UUID to be acknowledged in the
1341 * next cummulative ACK. Only valid if @e num_acks > 0.
1346 * Number of ACKs we have accumulated so far. Reset to 0
1347 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1349 unsigned int num_acks;
1352 * How big is the message we are reassembling in total?
1357 * How many bytes of the message are still missing? Defragmentation
1358 * is complete when @e msg_missing == 0.
1360 uint16_t msg_missing;
1362 /* Followed by @e msg_size bytes of the (partially) defragmented original
1365 /* Followed by @e bitfield data */
1370 * A neighbour that at least one communicator is connected to.
1376 * Which peer is this about?
1378 struct GNUNET_PeerIdentity pid;
1381 * Map with `struct ReassemblyContext` structs for fragments under
1382 * reassembly. May be NULL if we currently have no fragments from
1383 * this @e pid (lazy initialization).
1385 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1388 * Heap with `struct ReassemblyContext` structs for fragments under
1389 * reassembly. May be NULL if we currently have no fragments from
1390 * this @e pid (lazy initialization).
1392 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1395 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1397 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1400 * Head of list of messages pending for this neighbour.
1402 struct PendingMessage *pending_msg_head;
1405 * Tail of list of messages pending for this neighbour.
1407 struct PendingMessage *pending_msg_tail;
1410 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1411 * purged if this neighbour goes down.
1413 struct DistanceVectorHop *dv_head;
1416 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1417 * purged if this neighbour goes down.
1419 struct DistanceVectorHop *dv_tail;
1422 * Head of DLL of queues to this peer.
1424 struct Queue *queue_head;
1427 * Tail of DLL of queues to this peer.
1429 struct Queue *queue_tail;
1432 * Task run to cleanup pending messages that have exceeded their timeout.
1434 struct GNUNET_SCHEDULER_Task *timeout_task;
1437 * Quota at which CORE is allowed to transmit to this peer
1438 * (note that the value CORE should actually be told is this
1439 * value plus the respective value in `struct DistanceVector`).
1440 * Should match the sum of the quotas of all of the queues.
1442 * FIXME: not yet set, tricky to get right given multiple queues!
1443 * (=> Idea: measure???)
1444 * FIXME: how do we set this value initially when we tell CORE?
1445 * Options: start at a minimum value or at literally zero?
1446 * (=> Current thought: clean would be zero!)
1448 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1451 * What is the earliest timeout of any message in @e pending_msg_tail?
1453 struct GNUNET_TIME_Absolute earliest_timeout;
1456 * Do we have a confirmed working queue and are thus visible to
1464 * A peer that an application (client) would like us to talk to directly.
1470 * Which peer is this about?
1472 struct GNUNET_PeerIdentity pid;
1475 * Client responsible for the request.
1477 struct TransportClient *tc;
1480 * Handle for watching the peerstore for HELLOs for this peer.
1482 struct GNUNET_PEERSTORE_WatchContext *wc;
1485 * What kind of performance preference does this @e tc have?
1487 enum GNUNET_MQ_PreferenceKind pk;
1490 * How much bandwidth would this @e tc like to see?
1492 struct GNUNET_BANDWIDTH_Value32NBO bw;
1497 * Types of different pending messages.
1499 enum PendingMessageType
1503 * Ordinary message received from the CORE service.
1510 PMT_FRAGMENT_BOX = 1,
1515 PMT_RELIABILITY_BOX = 2,
1518 * Any type of acknowledgement.
1520 PMT_ACKNOWLEDGEMENT = 3,
1523 * Control traffic generated by the TRANSPORT service itself.
1531 * Transmission request that is awaiting delivery. The original
1532 * transmission requests from CORE may be too big for some queues.
1533 * In this case, a *tree* of fragments is created. At each
1534 * level of the tree, fragments are kept in a DLL ordered by which
1535 * fragment should be sent next (at the head). The tree is searched
1536 * top-down, with the original message at the root.
1538 * To select a node for transmission, first it is checked if the
1539 * current node's message fits with the MTU. If it does not, we
1540 * either calculate the next fragment (based on @e frag_off) from the
1541 * current node, or, if all fragments have already been created,
1542 * descend to the @e head_frag. Even though the node was already
1543 * fragmented, the fragment may be too big if the fragment was
1544 * generated for a queue with a larger MTU. In this case, the node
1545 * may be fragmented again, thus creating a tree.
1547 * When acknowledgements for fragments are received, the tree
1548 * must be pruned, removing those parts that were already
1549 * acknowledged. When fragments are sent over a reliable
1550 * channel, they can be immediately removed.
1552 * If a message is ever fragmented, then the original "full" message
1553 * is never again transmitted (even if it fits below the MTU), and
1554 * only (remaining) fragments are sent.
1556 struct PendingMessage
1559 * Kept in a MDLL of messages for this @a target.
1561 struct PendingMessage *next_neighbour;
1564 * Kept in a MDLL of messages for this @a target.
1566 struct PendingMessage *prev_neighbour;
1569 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1571 struct PendingMessage *next_client;
1574 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1576 struct PendingMessage *prev_client;
1579 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1580 * #PMT_FRAGMENT_BOx)
1582 struct PendingMessage *next_frag;
1585 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1586 * #PMT_FRAGMENT_BOX)
1588 struct PendingMessage *prev_frag;
1591 * This message, reliability boxed. Only possibly available if @e pmt is
1594 struct PendingMessage *bpm;
1597 * Target of the request.
1599 struct Neighbour *target;
1602 * Set to non-NULL value if this message is currently being given to a
1603 * communicator and we are awaiting that communicator's acknowledgement.
1604 * Note that we must not retransmit a pending message while we're still
1605 * in the process of giving it to a communicator. If a pending message
1606 * is free'd while this entry is non-NULL, the @e qe reference to us
1607 * should simply be set to NULL.
1609 struct QueueEntry *qe;
1612 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1614 struct TransportClient *client;
1617 * Head of a MDLL of fragments created for this core message.
1619 struct PendingMessage *head_frag;
1622 * Tail of a MDLL of fragments created for this core message.
1624 struct PendingMessage *tail_frag;
1627 * Our parent in the fragmentation tree.
1629 struct PendingMessage *frag_parent;
1632 * At what time should we give up on the transmission (and no longer retry)?
1634 struct GNUNET_TIME_Absolute timeout;
1637 * What is the earliest time for us to retry transmission of this message?
1639 struct GNUNET_TIME_Absolute next_attempt;
1642 * UUID to use for this message (used for reassembly of fragments, only
1643 * initialized if @e msg_uuid_set is #GNUNET_YES).
1645 struct GNUNET_ShortHashCode msg_uuid;
1648 * Counter incremented per generated fragment.
1650 uint32_t frag_uuidgen;
1653 * Type of the pending message.
1655 enum PendingMessageType pmt;
1658 * Size of the original message.
1663 * Offset at which we should generate the next fragment.
1668 * #GNUNET_YES once @e msg_uuid was initialized
1670 int16_t msg_uuid_set;
1672 /* Followed by @e bytes_msg to transmit */
1677 * One of the addresses of this peer.
1679 struct AddressListEntry
1685 struct AddressListEntry *next;
1690 struct AddressListEntry *prev;
1693 * Which communicator provides this address?
1695 struct TransportClient *tc;
1698 * The actual address.
1700 const char *address;
1703 * Current context for storing this address in the peerstore.
1705 struct GNUNET_PEERSTORE_StoreContext *sc;
1708 * Task to periodically do @e st operation.
1710 struct GNUNET_SCHEDULER_Task *st;
1713 * What is a typical lifetime the communicator expects this
1714 * address to have? (Always from now.)
1716 struct GNUNET_TIME_Relative expiration;
1719 * Address identifier used by the communicator.
1724 * Network type offered by this address.
1726 enum GNUNET_NetworkType nt;
1731 * Client connected to the transport service.
1733 struct TransportClient
1739 struct TransportClient *next;
1744 struct TransportClient *prev;
1747 * Handle to the client.
1749 struct GNUNET_SERVICE_Client *client;
1752 * Message queue to the client.
1754 struct GNUNET_MQ_Handle *mq;
1757 * What type of client is this?
1759 enum ClientType type;
1765 * Information for @e type #CT_CORE.
1771 * Head of list of messages pending for this client, sorted by
1772 * transmission time ("next_attempt" + possibly internal prioritization).
1774 struct PendingMessage *pending_msg_head;
1777 * Tail of list of messages pending for this client.
1779 struct PendingMessage *pending_msg_tail;
1784 * Information for @e type #CT_MONITOR.
1790 * Peer identity to monitor the addresses of.
1791 * Zero to monitor all neighbours. Valid if
1792 * @e type is #CT_MONITOR.
1794 struct GNUNET_PeerIdentity peer;
1797 * Is this a one-shot monitor?
1805 * Information for @e type #CT_COMMUNICATOR.
1810 * If @e type is #CT_COMMUNICATOR, this communicator
1811 * supports communicating using these addresses.
1813 char *address_prefix;
1816 * Head of DLL of queues offered by this communicator.
1818 struct Queue *queue_head;
1821 * Tail of DLL of queues offered by this communicator.
1823 struct Queue *queue_tail;
1826 * Head of list of the addresses of this peer offered by this
1829 struct AddressListEntry *addr_head;
1832 * Tail of list of the addresses of this peer offered by this
1835 struct AddressListEntry *addr_tail;
1838 * Number of queue entries in all queues to this communicator. Used
1839 * throttle sending to a communicator if we see that the communicator
1840 * is globally unable to keep up.
1842 unsigned int total_queue_length;
1845 * Characteristics of this communicator.
1847 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1852 * Information for @e type #CT_APPLICATION
1858 * Map of requests for peers the given client application would like to
1859 * see connections for. Maps from PIDs to `struct PeerRequest`.
1861 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1870 * State we keep for validation activities. Each of these
1871 * is both in the #validation_heap and the #validation_map.
1873 struct ValidationState
1877 * For which peer is @a address to be validated (or possibly valid)?
1878 * Serves as key in the #validation_map.
1880 struct GNUNET_PeerIdentity pid;
1883 * How long did the peer claim this @e address to be valid? Capped at
1884 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1885 * were told about the address and the value claimed by the other peer at
1886 * that time. May be updated similarly when validation succeeds.
1888 struct GNUNET_TIME_Absolute valid_until;
1891 * How long do *we* consider this @e address to be valid?
1892 * In the past or zero if we have not yet validated it.
1894 struct GNUNET_TIME_Absolute validated_until;
1897 * When did we FIRST use the current @e challenge in a message?
1898 * Used to sanity-check @code{origin_time} in the response when
1899 * calculating the RTT. If the @code{origin_time} is not in
1900 * the expected range, the response is discarded as malicious.
1902 struct GNUNET_TIME_Absolute first_challenge_use;
1905 * When did we LAST use the current @e challenge in a message?
1906 * Used to sanity-check @code{origin_time} in the response when
1907 * calculating the RTT. If the @code{origin_time} is not in
1908 * the expected range, the response is discarded as malicious.
1910 struct GNUNET_TIME_Absolute last_challenge_use;
1913 * Next time we will send the @e challenge to the peer, if this time is past
1914 * @e valid_until, this validation state is released at this time. If the
1915 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1916 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1917 * to re-validate before the validity actually expires.
1919 struct GNUNET_TIME_Absolute next_challenge;
1922 * Current backoff factor we're applying for sending the @a challenge.
1923 * Reset to 0 if the @a challenge is confirmed upon validation.
1924 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1925 * existing value if we receive an unvalidated address again over
1926 * another channel (and thus should consider the information "fresh").
1927 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1929 struct GNUNET_TIME_Relative challenge_backoff;
1932 * Initially set to "forever". Once @e validated_until is set, this value is
1933 * set to the RTT that tells us how long it took to receive the validation.
1935 struct GNUNET_TIME_Relative validation_rtt;
1938 * The challenge we sent to the peer to get it to validate the address. Note
1939 * that we rotate the challenge whenever we update @e validated_until to
1940 * avoid attacks where a peer simply replays an old challenge in the future.
1941 * (We must not rotate more often as otherwise we may discard valid answers
1942 * due to packet losses, latency and reorderings on the network).
1944 struct GNUNET_ShortHashCode challenge;
1947 * Claimed address of the peer.
1952 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1953 * heap is used to figure out when the next validation activity should be
1956 struct GNUNET_CONTAINER_HeapNode *hn;
1959 * Handle to a PEERSTORE store operation for this @e address. NULL if
1960 * no PEERSTORE operation is pending.
1962 struct GNUNET_PEERSTORE_StoreContext *sc;
1965 * We are technically ready to send the challenge, but we are waiting for
1966 * the respective queue to become available for transmission.
1973 * A Backtalker is a peer sending us backchannel messages. We use this
1974 * struct to detect monotonic time violations, cache ephemeral key
1975 * material (to avoid repeatedly checking signatures), and to synchronize
1976 * monotonic time with the PEERSTORE.
1981 * Peer this is about.
1983 struct GNUNET_PeerIdentity pid;
1986 * Last (valid) monotonic time received from this sender.
1988 struct GNUNET_TIME_Absolute monotonic_time;
1991 * When will this entry time out?
1993 struct GNUNET_TIME_Absolute timeout;
1996 * Last (valid) ephemeral key received from this sender.
1998 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2001 * Task associated with this backtalker. Can be for timeout,
2002 * or other asynchronous operations.
2004 struct GNUNET_SCHEDULER_Task *task;
2007 * Communicator context waiting on this backchannel's @e get, or NULL.
2009 struct CommunicatorMessageContext *cmc;
2012 * Handle for an operation to fetch @e monotonic_time information from the
2013 * PEERSTORE, or NULL.
2015 struct GNUNET_PEERSTORE_IterateContext *get;
2018 * Handle to a PEERSTORE store operation for this @e pid's @e
2019 * monotonic_time. NULL if no PEERSTORE operation is pending.
2021 struct GNUNET_PEERSTORE_StoreContext *sc;
2024 * Number of bytes of the original message body that follows after this
2032 * Head of linked list of all clients to this service.
2034 static struct TransportClient *clients_head;
2037 * Tail of linked list of all clients to this service.
2039 static struct TransportClient *clients_tail;
2042 * Statistics handle.
2044 static struct GNUNET_STATISTICS_Handle *GST_stats;
2047 * Configuration handle.
2049 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2054 static struct GNUNET_PeerIdentity GST_my_identity;
2059 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2062 * Map from PIDs to `struct Neighbour` entries. A peer is
2063 * a neighbour if we have an MQ to it from some communicator.
2065 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2068 * Map from PIDs to `struct Backtalker` entries. A peer is
2069 * a backtalker if it recently send us backchannel messages.
2071 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2074 * Map from PIDs to `struct DistanceVector` entries describing
2075 * known paths to the peer.
2077 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2080 * Map from PIDs to `struct ValidationState` entries describing
2081 * addresses we are aware of and their validity state.
2083 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2086 * Map from challenges to `struct LearnLaunchEntry` values.
2088 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2091 * Head of a DLL sorted by launch time.
2093 static struct LearnLaunchEntry *lle_head;
2096 * Tail of a DLL sorted by launch time.
2098 static struct LearnLaunchEntry *lle_tail;
2101 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2102 * sorting addresses we are aware of by when we should next try to (re)validate
2105 static struct GNUNET_CONTAINER_Heap *validation_heap;
2108 * Database for peer's HELLOs.
2110 static struct GNUNET_PEERSTORE_Handle *peerstore;
2113 * Heap sorting `struct EphemeralCacheEntry` by their
2114 * key/signature validity.
2116 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2119 * Hash map for looking up `struct EphemeralCacheEntry`s
2120 * by peer identity. (We may have ephemerals in our
2121 * cache for which we do not have a neighbour entry,
2122 * and similar many neighbours may not need ephemerals,
2123 * so we use a second map.)
2125 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2128 * Task to free expired ephemerals.
2130 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2133 * Task run to initiate DV learning.
2135 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2138 * Task to run address validation.
2140 static struct GNUNET_SCHEDULER_Task *validation_task;
2144 * Free cached ephemeral key.
2146 * @param ece cached signature to free
2149 free_ephemeral (struct EphemeralCacheEntry *ece)
2151 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2152 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2158 * Free validation state.
2160 * @param vs validation state to free
2163 free_validation_state (struct ValidationState *vs)
2165 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2166 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2170 GNUNET_PEERSTORE_store_cancel (vs->sc);
2173 GNUNET_free (vs->address);
2179 * Lookup neighbour record for peer @a pid.
2181 * @param pid neighbour to look for
2182 * @return NULL if we do not have this peer as a neighbour
2184 static struct Neighbour *
2185 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2187 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2192 * Details about what to notify monitors about.
2197 * @deprecated To be discussed if we keep these...
2199 struct GNUNET_TIME_Absolute last_validation;
2200 struct GNUNET_TIME_Absolute valid_until;
2201 struct GNUNET_TIME_Absolute next_validation;
2204 * Current round-trip time estimate.
2206 struct GNUNET_TIME_Relative rtt;
2209 * Connection status.
2211 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2216 uint32_t num_msg_pending;
2221 uint32_t num_bytes_pending;
2226 * Free a @dvh. Callers MAY want to check if this was the last path to the
2227 * `target`, and if so call #free_dv_route to also free the associated DV
2228 * entry in #dv_routes (if not, the associated scheduler job should eventually
2231 * @param dvh hop to free
2234 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2236 struct Neighbour *n = dvh->next_hop;
2237 struct DistanceVector *dv = dvh->dv;
2239 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2240 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2246 * Free entry in #dv_routes. First frees all hops to the target, and
2247 * if there are no entries left, frees @a dv as well.
2249 * @param dv route to free
2252 free_dv_route (struct DistanceVector *dv)
2254 struct DistanceVectorHop *dvh;
2256 while (NULL != (dvh = dv->dv_head))
2257 free_distance_vector_hop (dvh);
2258 if (NULL == dv->dv_head)
2262 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2263 if (NULL != dv->visibility_task)
2264 GNUNET_SCHEDULER_cancel (dv->visibility_task);
2265 if (NULL != dv->timeout_task)
2266 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2273 * Notify monitor @a tc about an event. That @a tc
2274 * cares about the event has already been checked.
2276 * Send @a tc information in @a me about a @a peer's status with
2277 * respect to some @a address to all monitors that care.
2279 * @param tc monitor to inform
2280 * @param peer peer the information is about
2281 * @param address address the information is about
2282 * @param nt network type associated with @a address
2283 * @param me detailed information to transmit
2286 notify_monitor (struct TransportClient *tc,
2287 const struct GNUNET_PeerIdentity *peer,
2288 const char *address,
2289 enum GNUNET_NetworkType nt,
2290 const struct MonitorEvent *me)
2292 struct GNUNET_MQ_Envelope *env;
2293 struct GNUNET_TRANSPORT_MonitorData *md;
2294 size_t addr_len = strlen (address) + 1;
2296 env = GNUNET_MQ_msg_extra (md,
2298 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2299 md->nt = htonl ((uint32_t) nt);
2301 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2302 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2303 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2304 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2305 md->cs = htonl ((uint32_t) me->cs);
2306 md->num_msg_pending = htonl (me->num_msg_pending);
2307 md->num_bytes_pending = htonl (me->num_bytes_pending);
2308 memcpy (&md[1], address, addr_len);
2309 GNUNET_MQ_send (tc->mq, env);
2314 * Send information in @a me about a @a peer's status with respect
2315 * to some @a address to all monitors that care.
2317 * @param peer peer the information is about
2318 * @param address address the information is about
2319 * @param nt network type associated with @a address
2320 * @param me detailed information to transmit
2323 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2324 const char *address,
2325 enum GNUNET_NetworkType nt,
2326 const struct MonitorEvent *me)
2328 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2330 if (CT_MONITOR != tc->type)
2332 if (tc->details.monitor.one_shot)
2334 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2335 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2337 notify_monitor (tc, peer, address, nt, me);
2343 * Called whenever a client connects. Allocates our
2344 * data structures associated with that client.
2346 * @param cls closure, NULL
2347 * @param client identification of the client
2348 * @param mq message queue for the client
2349 * @return our `struct TransportClient`
2352 client_connect_cb (void *cls,
2353 struct GNUNET_SERVICE_Client *client,
2354 struct GNUNET_MQ_Handle *mq)
2356 struct TransportClient *tc;
2359 tc = GNUNET_new (struct TransportClient);
2360 tc->client = client;
2362 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2371 * @param rc data structure to free
2374 free_reassembly_context (struct ReassemblyContext *rc)
2376 struct Neighbour *n = rc->neighbour;
2378 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2379 GNUNET_assert (GNUNET_OK ==
2380 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2388 * Task run to clean up reassembly context of a neighbour that have expired.
2390 * @param cls a `struct Neighbour`
2393 reassembly_cleanup_task (void *cls)
2395 struct Neighbour *n = cls;
2396 struct ReassemblyContext *rc;
2398 n->reassembly_timeout_task = NULL;
2399 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2401 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2404 free_reassembly_context (rc);
2407 GNUNET_assert (NULL == n->reassembly_timeout_task);
2408 n->reassembly_timeout_task =
2409 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2410 &reassembly_cleanup_task,
2418 * function called to #free_reassembly_context().
2422 * @param value a `struct ReassemblyContext` to free
2423 * @return #GNUNET_OK (continue iteration)
2426 free_reassembly_cb (void *cls,
2427 const struct GNUNET_ShortHashCode *key,
2430 struct ReassemblyContext *rc = value;
2434 free_reassembly_context (rc);
2440 * Release memory used by @a neighbour.
2442 * @param neighbour neighbour entry to free
2445 free_neighbour (struct Neighbour *neighbour)
2447 struct DistanceVectorHop *dvh;
2449 GNUNET_assert (NULL == neighbour->queue_head);
2450 GNUNET_assert (GNUNET_YES ==
2451 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2454 if (NULL != neighbour->timeout_task)
2455 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2456 if (NULL != neighbour->reassembly_map)
2458 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2459 &free_reassembly_cb,
2461 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2462 neighbour->reassembly_map = NULL;
2463 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2464 neighbour->reassembly_heap = NULL;
2466 while (NULL != (dvh = neighbour->dv_head))
2468 struct DistanceVector *dv = dvh->dv;
2470 free_distance_vector_hop (dvh);
2471 if (NULL == dv->dv_head)
2474 if (NULL != neighbour->reassembly_timeout_task)
2475 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2476 GNUNET_free (neighbour);
2481 * Send message to CORE clients that we lost a connection.
2483 * @param tc client to inform (must be CORE client)
2484 * @param pid peer the connection is for
2485 * @param quota_out current quota for the peer
2488 core_send_connect_info (struct TransportClient *tc,
2489 const struct GNUNET_PeerIdentity *pid,
2490 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2492 struct GNUNET_MQ_Envelope *env;
2493 struct ConnectInfoMessage *cim;
2495 GNUNET_assert (CT_CORE == tc->type);
2496 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2497 cim->quota_out = quota_out;
2499 GNUNET_MQ_send (tc->mq, env);
2504 * Send message to CORE clients that we gained a connection
2506 * @param pid peer the queue was for
2507 * @param quota_out current quota for the peer
2510 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2511 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2513 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2515 if (CT_CORE != tc->type)
2517 core_send_connect_info (tc, pid, quota_out);
2523 * Send message to CORE clients that we lost a connection.
2525 * @param pid peer the connection was for
2528 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2530 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2532 struct GNUNET_MQ_Envelope *env;
2533 struct DisconnectInfoMessage *dim;
2535 if (CT_CORE != tc->type)
2537 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2539 GNUNET_MQ_send (tc->mq, env);
2545 * We believe we are ready to transmit a message on a queue. Double-checks
2546 * with the queue's "tracker_out" and then gives the message to the
2547 * communicator for transmission (updating the tracker, and re-scheduling
2548 * itself if applicable).
2550 * @param cls the `struct Queue` to process transmissions for
2553 transmit_on_queue (void *cls);
2557 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2558 * we should run immediately or if the message queue is empty.
2559 * Test for no task being added AND queue not being empty to
2560 * transmit immediately afterwards! This function must only
2561 * be called if the message queue is non-empty!
2563 * @param queue the queue to do scheduling for
2564 * @param inside_job set to #GNUNET_YES if called from
2565 * #transmit_on_queue() itself and NOT setting
2566 * the task means running immediately
2569 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
2571 struct Neighbour *n = queue->neighbour;
2572 struct PendingMessage *pm = n->pending_msg_head;
2573 struct GNUNET_TIME_Relative out_delay;
2576 GNUNET_assert (NULL != pm);
2577 if (queue->tc->details.communicator.total_queue_length >=
2578 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2580 GNUNET_STATISTICS_update (
2582 "# Transmission throttled due to communicator queue limit",
2587 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2589 GNUNET_STATISTICS_update (GST_stats,
2590 "# Transmission throttled due to queue queue limit",
2596 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
2598 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
2599 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
2602 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
2603 return; /* we should run immediately! */
2604 /* queue has changed since we were scheduled, reschedule again */
2605 queue->transmit_task =
2606 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
2607 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2608 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2609 "Next transmission on queue `%s' in %s (high delay)\n",
2611 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2614 "Next transmission on queue `%s' in %s\n",
2616 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2621 * Check whether the CORE visibility of @a n changed. If so,
2622 * check whether we need to notify CORE.
2624 * @param n neighbour to perform the check for
2627 update_neighbour_core_visibility (struct Neighbour *n);
2633 * @param queue the queue to free
2636 free_queue (struct Queue *queue)
2638 struct Neighbour *neighbour = queue->neighbour;
2639 struct TransportClient *tc = queue->tc;
2640 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
2641 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
2642 struct QueueEntry *qe;
2645 if (NULL != queue->transmit_task)
2647 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2648 queue->transmit_task = NULL;
2650 if (NULL != queue->visibility_task)
2652 GNUNET_SCHEDULER_cancel (queue->visibility_task);
2653 queue->visibility_task = NULL;
2655 GNUNET_CONTAINER_MDLL_remove (neighbour,
2656 neighbour->queue_head,
2657 neighbour->queue_tail,
2659 GNUNET_CONTAINER_MDLL_remove (client,
2660 tc->details.communicator.queue_head,
2661 tc->details.communicator.queue_tail,
2663 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
2664 tc->details.communicator.total_queue_length);
2665 while (NULL != (qe = queue->queue_head))
2667 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
2668 queue->queue_length--;
2669 tc->details.communicator.total_queue_length--;
2672 GNUNET_assert (qe == qe->pm->qe);
2677 GNUNET_assert (0 == queue->queue_length);
2678 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
2679 tc->details.communicator.total_queue_length))
2681 /* Communicator dropped below threshold, resume all queues */
2682 GNUNET_STATISTICS_update (
2684 "# Transmission throttled due to communicator queue limit",
2687 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
2689 schedule_transmit_on_queue (s, GNUNET_NO);
2691 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
2692 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2693 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2694 GNUNET_free (queue);
2696 update_neighbour_core_visibility (neighbour);
2697 cores_send_disconnect_info (&neighbour->pid);
2699 if (NULL == neighbour->queue_head)
2701 free_neighbour (neighbour);
2709 * @param ale address list entry to free
2712 free_address_list_entry (struct AddressListEntry *ale)
2714 struct TransportClient *tc = ale->tc;
2716 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2717 tc->details.communicator.addr_tail,
2719 if (NULL != ale->sc)
2721 GNUNET_PEERSTORE_store_cancel (ale->sc);
2724 if (NULL != ale->st)
2726 GNUNET_SCHEDULER_cancel (ale->st);
2734 * Stop the peer request in @a value.
2736 * @param cls a `struct TransportClient` that no longer makes the request
2737 * @param pid the peer's identity
2738 * @param value a `struct PeerRequest`
2739 * @return #GNUNET_YES (always)
2742 stop_peer_request (void *cls,
2743 const struct GNUNET_PeerIdentity *pid,
2746 struct TransportClient *tc = cls;
2747 struct PeerRequest *pr = value;
2749 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2752 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2762 * Called whenever a client is disconnected. Frees our
2763 * resources associated with that client.
2765 * @param cls closure, NULL
2766 * @param client identification of the client
2767 * @param app_ctx our `struct TransportClient`
2770 client_disconnect_cb (void *cls,
2771 struct GNUNET_SERVICE_Client *client,
2774 struct TransportClient *tc = app_ctx;
2777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2778 "Client %p disconnected, cleaning up.\n",
2780 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
2786 struct PendingMessage *pm;
2788 while (NULL != (pm = tc->details.core.pending_msg_head))
2790 GNUNET_CONTAINER_MDLL_remove (client,
2791 tc->details.core.pending_msg_head,
2792 tc->details.core.pending_msg_tail,
2800 case CT_COMMUNICATOR: {
2802 struct AddressListEntry *ale;
2804 while (NULL != (q = tc->details.communicator.queue_head))
2806 while (NULL != (ale = tc->details.communicator.addr_head))
2807 free_address_list_entry (ale);
2808 GNUNET_free (tc->details.communicator.address_prefix);
2811 case CT_APPLICATION:
2812 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2815 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2823 * Iterator telling new CORE client about all existing
2824 * connections to peers.
2826 * @param cls the new `struct TransportClient`
2827 * @param pid a connected peer
2828 * @param value the `struct Neighbour` with more information
2829 * @return #GNUNET_OK (continue to iterate)
2832 notify_client_connect_info (void *cls,
2833 const struct GNUNET_PeerIdentity *pid,
2836 struct TransportClient *tc = cls;
2837 struct Neighbour *neighbour = value;
2839 core_send_connect_info (tc, pid, neighbour->quota_out);
2845 * Initialize a "CORE" client. We got a start message from this
2846 * client, so add it to the list of clients for broadcasting of
2849 * @param cls the client
2850 * @param start the start message that was sent
2853 handle_client_start (void *cls, const struct StartMessage *start)
2855 struct TransportClient *tc = cls;
2858 options = ntohl (start->options);
2859 if ((0 != (1 & options)) &&
2860 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
2862 /* client thinks this is a different peer, reject */
2864 GNUNET_SERVICE_client_drop (tc->client);
2867 if (CT_NONE != tc->type)
2870 GNUNET_SERVICE_client_drop (tc->client);
2874 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2875 ¬ify_client_connect_info,
2877 GNUNET_SERVICE_client_continue (tc->client);
2882 * Client asked for transmission to a peer. Process the request.
2884 * @param cls the client
2885 * @param obm the send message that was sent
2888 check_client_send (void *cls, const struct OutboundMessage *obm)
2890 struct TransportClient *tc = cls;
2892 const struct GNUNET_MessageHeader *obmm;
2894 if (CT_CORE != tc->type)
2897 return GNUNET_SYSERR;
2899 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2900 if (size < sizeof (struct GNUNET_MessageHeader))
2903 return GNUNET_SYSERR;
2905 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2906 if (size != ntohs (obmm->size))
2909 return GNUNET_SYSERR;
2916 * Free fragment tree below @e root, excluding @e root itself.
2918 * @param root root of the tree to free
2921 free_fragment_tree (struct PendingMessage *root)
2923 struct PendingMessage *frag;
2925 while (NULL != (frag = root->head_frag))
2927 free_fragment_tree (frag);
2928 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2935 * Release memory associated with @a pm and remove @a pm from associated
2936 * data structures. @a pm must be a top-level pending message and not
2937 * a fragment in the tree. The entire tree is freed (if applicable).
2939 * @param pm the pending message to free
2942 free_pending_message (struct PendingMessage *pm)
2944 struct TransportClient *tc = pm->client;
2945 struct Neighbour *target = pm->target;
2949 GNUNET_CONTAINER_MDLL_remove (client,
2950 tc->details.core.pending_msg_head,
2951 tc->details.core.pending_msg_tail,
2954 GNUNET_CONTAINER_MDLL_remove (neighbour,
2955 target->pending_msg_head,
2956 target->pending_msg_tail,
2958 free_fragment_tree (pm);
2961 GNUNET_assert (pm == pm->qe->pm);
2964 GNUNET_free_non_null (pm->bpm);
2970 * Send a response to the @a pm that we have processed a
2971 * "send" request with status @a success. We
2972 * transmitted @a bytes_physical on the actual wire.
2973 * Sends a confirmation to the "core" client responsible
2974 * for the original request and free's @a pm.
2976 * @param pm handle to the original pending message
2977 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2978 * for transmission failure
2979 * @param bytes_physical amount of bandwidth consumed
2982 client_send_response (struct PendingMessage *pm,
2984 uint32_t bytes_physical)
2986 struct TransportClient *tc = pm->client;
2987 struct Neighbour *target = pm->target;
2988 struct GNUNET_MQ_Envelope *env;
2989 struct SendOkMessage *som;
2993 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2994 som->success = htonl ((uint32_t) success);
2995 som->bytes_msg = htons (pm->bytes_msg);
2996 som->bytes_physical = htonl (bytes_physical);
2997 som->peer = target->pid;
2998 GNUNET_MQ_send (tc->mq, env);
3000 free_pending_message (pm);
3005 * Checks the message queue for a neighbour for messages that have timed
3006 * out and purges them.
3008 * @param cls a `struct Neighbour`
3011 check_queue_timeouts (void *cls)
3013 struct Neighbour *n = cls;
3014 struct PendingMessage *pm;
3015 struct GNUNET_TIME_Absolute now;
3016 struct GNUNET_TIME_Absolute earliest_timeout;
3018 n->timeout_task = NULL;
3019 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
3020 now = GNUNET_TIME_absolute_get ();
3021 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
3023 pm = pos->next_neighbour;
3024 if (pos->timeout.abs_value_us <= now.abs_value_us)
3026 GNUNET_STATISTICS_update (GST_stats,
3027 "# messages dropped (timeout before confirmation)",
3030 client_send_response (pm, GNUNET_NO, 0);
3034 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
3036 n->earliest_timeout = earliest_timeout;
3037 if (NULL != n->pending_msg_head)
3039 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
3044 * Client asked for transmission to a peer. Process the request.
3046 * @param cls the client
3047 * @param obm the send message that was sent
3050 handle_client_send (void *cls, const struct OutboundMessage *obm)
3052 struct TransportClient *tc = cls;
3053 struct PendingMessage *pm;
3054 const struct GNUNET_MessageHeader *obmm;
3055 struct Neighbour *target;
3059 GNUNET_assert (CT_CORE == tc->type);
3060 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3061 bytes_msg = ntohs (obmm->size);
3062 target = lookup_neighbour (&obm->peer);
3065 /* Failure: don't have this peer as a neighbour (anymore).
3066 Might have gone down asynchronously, so this is NOT
3067 a protocol violation by CORE. Still count the event,
3068 as this should be rare. */
3069 struct GNUNET_MQ_Envelope *env;
3070 struct SendOkMessage *som;
3072 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3073 som->success = htonl (GNUNET_SYSERR);
3074 som->bytes_msg = htonl (bytes_msg);
3075 som->bytes_physical = htonl (0);
3076 som->peer = obm->peer;
3077 GNUNET_MQ_send (tc->mq, env);
3078 GNUNET_SERVICE_client_continue (tc->client);
3079 GNUNET_STATISTICS_update (GST_stats,
3080 "# messages dropped (neighbour unknown)",
3085 was_empty = (NULL == target->pending_msg_head);
3086 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
3088 pm->target = target;
3089 pm->bytes_msg = bytes_msg;
3091 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
3092 memcpy (&pm[1], &obm[1], bytes_msg);
3093 GNUNET_CONTAINER_MDLL_insert (neighbour,
3094 target->pending_msg_head,
3095 target->pending_msg_tail,
3097 GNUNET_CONTAINER_MDLL_insert (client,
3098 tc->details.core.pending_msg_head,
3099 tc->details.core.pending_msg_tail,
3101 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3103 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3104 if (NULL != target->timeout_task)
3105 GNUNET_SCHEDULER_cancel (target->timeout_task);
3106 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3107 &check_queue_timeouts,
3111 return; /* all queues must already be busy */
3112 for (struct Queue *queue = target->queue_head; NULL != queue;
3113 queue = queue->next_neighbour)
3115 /* try transmission on any queue that is idle */
3116 if (NULL == queue->transmit_task)
3117 queue->transmit_task =
3118 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3124 * Communicator started. Test message is well-formed.
3126 * @param cls the client
3127 * @param cam the send message that was sent
3130 check_communicator_available (
3132 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3134 struct TransportClient *tc = cls;
3137 if (CT_NONE != tc->type)
3140 return GNUNET_SYSERR;
3142 tc->type = CT_COMMUNICATOR;
3143 size = ntohs (cam->header.size) - sizeof (*cam);
3145 return GNUNET_OK; /* receive-only communicator */
3146 GNUNET_MQ_check_zero_termination (cam);
3152 * Communicator started. Process the request.
3154 * @param cls the client
3155 * @param cam the send message that was sent
3158 handle_communicator_available (
3160 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3162 struct TransportClient *tc = cls;
3165 size = ntohs (cam->header.size) - sizeof (*cam);
3167 return; /* receive-only communicator */
3168 tc->details.communicator.address_prefix =
3169 GNUNET_strdup ((const char *) &cam[1]);
3170 tc->details.communicator.cc =
3171 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3172 GNUNET_SERVICE_client_continue (tc->client);
3177 * Communicator requests backchannel transmission. Check the request.
3179 * @param cls the client
3180 * @param cb the send message that was sent
3181 * @return #GNUNET_OK if message is well-formed
3184 check_communicator_backchannel (
3186 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3188 const struct GNUNET_MessageHeader *inbox;
3194 msize = ntohs (cb->header.size) - sizeof (*cb);
3195 if (UINT16_MAX - msize >
3196 sizeof (struct TransportBackchannelEncapsulationMessage) +
3197 sizeof (struct TransportBackchannelRequestPayload))
3200 return GNUNET_SYSERR;
3202 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3203 isize = ntohs (inbox->size);
3207 return GNUNET_SYSERR;
3209 is = (const char *) inbox;
3212 GNUNET_assert (msize > 0);
3213 if ('\0' != is[msize - 1])
3216 return GNUNET_SYSERR;
3223 * Remove memory used by expired ephemeral keys.
3228 expire_ephemerals (void *cls)
3230 struct EphemeralCacheEntry *ece;
3233 ephemeral_task = NULL;
3234 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3236 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3239 free_ephemeral (ece);
3242 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3251 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3252 * one, cache it and return it.
3254 * @param pid peer to look up ephemeral for
3255 * @param private_key[out] set to the private key
3256 * @param ephemeral_key[out] set to the key
3257 * @param ephemeral_sender_sig[out] set to the signature
3258 * @param ephemeral_validity[out] set to the validity expiration time
3261 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3262 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3263 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3264 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3265 struct GNUNET_TIME_Absolute *ephemeral_validity)
3267 struct EphemeralCacheEntry *ece;
3268 struct EphemeralConfirmationPS ec;
3270 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3271 if ((NULL != ece) &&
3272 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3275 free_ephemeral (ece);
3280 ece = GNUNET_new (struct EphemeralCacheEntry);
3282 ece->ephemeral_validity =
3283 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3284 EPHEMERAL_VALIDITY);
3285 GNUNET_assert (GNUNET_OK ==
3286 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3287 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3288 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3289 ec.purpose.size = htonl (sizeof (ec));
3291 ec.ephemeral_key = ece->ephemeral_key;
3292 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3296 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3298 ece->ephemeral_validity.abs_value_us);
3299 GNUNET_assert (GNUNET_OK ==
3300 GNUNET_CONTAINER_multipeermap_put (
3304 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3305 if (NULL == ephemeral_task)
3306 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3310 *private_key = ece->private_key;
3311 *ephemeral_key = ece->ephemeral_key;
3312 *ephemeral_sender_sig = ece->sender_sig;
3313 *ephemeral_validity = ece->ephemeral_validity;
3318 * Send the control message @a payload on @a queue.
3320 * @param queue the queue to use for transmission
3321 * @param pm pending message to update once transmission is done, may be NULL!
3322 * @param payload the payload to send (encapsulated in a
3323 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3324 * @param payload_size number of bytes in @a payload
3327 queue_send_msg (struct Queue *queue,
3328 struct PendingMessage *pm,
3329 const void *payload,
3330 size_t payload_size)
3332 struct Neighbour *n = queue->neighbour;
3333 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3334 struct GNUNET_MQ_Envelope *env;
3336 env = GNUNET_MQ_msg_extra (smt,
3338 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3339 smt->qid = queue->qid;
3340 smt->mid = queue->mid_gen;
3341 smt->receiver = n->pid;
3342 memcpy (&smt[1], payload, payload_size);
3344 /* Pass the env to the communicator of queue for transmission. */
3345 struct QueueEntry *qe;
3347 qe = GNUNET_new (struct QueueEntry);
3348 qe->mid = queue->mid_gen++;
3353 GNUNET_assert (NULL == pm->qe);
3356 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3357 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3358 queue->queue_length++;
3359 queue->tc->details.communicator.total_queue_length++;
3360 GNUNET_MQ_send (queue->tc->mq, env);
3366 * Which transmission options are allowable for transmission?
3367 * Interpreted bit-wise!
3369 enum RouteMessageOptions
3372 * Only confirmed, non-DV direct neighbours.
3377 * We are allowed to use DV routing for this @a hdr
3382 * We are allowed to use unconfirmed queues or DV routes for this message
3384 RMO_UNCONFIRMED_ALLOWED = 2,
3387 * Reliable and unreliable, DV and non-DV are all acceptable.
3389 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
3392 * If we have multiple choices, it is OK to send this message
3393 * over multiple channels at the same time to improve loss tolerance.
3394 * (We do at most 2 transmissions.)
3401 * Pick a queue of @a n under constraints @a options and schedule
3402 * transmission of @a hdr.
3404 * @param n neighbour to send to
3405 * @param hdr message to send as payload
3406 * @param options whether queues must be confirmed or not,
3407 * and whether we may pick multiple (2) queues
3410 route_via_neighbour (const struct Neighbour *n,
3411 const struct GNUNET_MessageHeader *hdr,
3412 enum RouteMessageOptions options)
3414 struct GNUNET_TIME_Absolute now;
3415 unsigned int candidates;
3419 /* Pick one or two 'random' queues from n (under constraints of options) */
3420 now = GNUNET_TIME_absolute_get ();
3421 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
3422 weight in the future; weight could be assigned by observed
3423 bandwidth (note: not sure if we should do this for this type
3424 of control traffic though). */
3426 for (struct Queue *pos = n->queue_head; NULL != pos;
3427 pos = pos->next_neighbour)
3429 /* Count the queue with the visibility task in all cases, as
3430 otherwise we may end up with no queues just because the
3431 time for the visibility task just expired but the scheduler
3432 just ran this task first */
3433 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
3434 (pos->validated_until.abs_value_us > now.abs_value_us) ||
3435 (NULL != pos->visibility_task))
3438 if (0 == candidates)
3440 /* Given that we above check for pos->visibility task,
3441 this should be strictly impossible. */
3445 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3446 if (0 == (options & RMO_REDUNDANT))
3447 sel2 = candidates; /* picks none! */
3449 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3451 for (struct Queue *pos = n->queue_head; NULL != pos;
3452 pos = pos->next_neighbour)
3454 /* Count the queue with the visibility task in all cases, as
3455 otherwise we may end up with no queues just because the
3456 time for the visibility task just expired but the scheduler
3457 just ran this task first */
3458 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
3459 (NULL != pos->visibility_task))
3461 if ((sel1 == candidates) || (sel2 == candidates))
3462 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
3470 * Given a distance vector path @a dvh route @a payload to
3471 * the ultimate destination respecting @a options.
3472 * Sets up the boxed message and queues it at the next hop.
3474 * @param dvh choice of the path for the message
3475 * @param payload body to transmit
3476 * @param options options to use for control
3479 forward_via_dvh (const struct DistanceVectorHop *dvh,
3480 const struct GNUNET_MessageHeader *payload,
3481 enum RouteMessageOptions options)
3483 uint16_t mlen = ntohs (payload->size);
3484 char boxram[sizeof (struct TransportDVBox) +
3485 (dvh->distance + 1) * sizeof (struct GNUNET_PeerIdentity) +
3487 struct TransportDVBox *box = (struct TransportDVBox *) boxram;
3488 struct GNUNET_PeerIdentity *path = (struct GNUNET_PeerIdentity *) &box[1];
3490 box->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3491 box->header.size = htons (sizeof (boxram));
3492 box->total_hops = htons (0);
3493 box->num_hops = htons (dvh->distance + 1);
3494 box->origin = GST_my_identity;
3495 memcpy (path, dvh->path, dvh->distance * sizeof (struct GNUNET_PeerIdentity));
3496 path[dvh->distance] = dvh->dv->target;
3497 memcpy (&path[dvh->distance + 1], payload, mlen);
3498 route_via_neighbour (dvh->next_hop, &box->header, options);
3503 * Pick a path of @a dv under constraints @a options and schedule
3504 * transmission of @a hdr.
3506 * @param n neighbour to send to
3507 * @param hdr message to send as payload
3508 * @param options whether path must be confirmed or not
3509 * and whether we may pick multiple (2) paths
3512 route_via_dv (const struct DistanceVector *dv,
3513 const struct GNUNET_MessageHeader *hdr,
3514 enum RouteMessageOptions options)
3516 struct DistanceVectorHop *h1;
3517 struct DistanceVectorHop *h2;
3522 /* Pick random vectors, but weighted by distance, giving more weight
3523 to shorter vectors */
3525 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3528 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3529 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3530 .rel_value_us == 0))
3531 continue; /* pos unconfirmed and confirmed required */
3532 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3539 choice1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3540 choice2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3544 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3547 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3549 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3550 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3551 .rel_value_us == 0))
3552 continue; /* pos unconfirmed and confirmed required */
3553 if ((num_dv <= choice1) && (num_dv + delta > choice1))
3555 if ((num_dv <= choice2) && (num_dv + delta > choice2))
3559 forward_via_dvh (h1, hdr, options & (~RMO_REDUNDANT));
3560 if (0 == (options & RMO_REDUNDANT))
3561 forward_via_dvh (h2, hdr, options & (~RMO_REDUNDANT));
3566 * We need to transmit @a hdr to @a target. If necessary, this may
3567 * involve DV routing.
3569 * @param target peer to receive @a hdr
3570 * @param hdr header of the message to route and #GNUNET_free()
3571 * @param options which transmission channels are allowed
3574 route_message (const struct GNUNET_PeerIdentity *target,
3575 struct GNUNET_MessageHeader *hdr,
3576 enum RouteMessageOptions options)
3578 struct Neighbour *n;
3579 struct DistanceVector *dv;
3581 n = GNUNET_CONTAINER_multipeermap_get (neighbours, target);
3582 dv = (0 != (options & RMO_DV_ALLOWED))
3583 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
3585 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
3587 /* if confirmed is required, and we do not have anything
3588 confirmed, drop respective options */
3589 if ((NULL != n) && (GNUNET_NO == n->core_visible))
3591 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
3594 if ((NULL == n) && (NULL == dv))
3596 GNUNET_STATISTICS_update (GST_stats,
3597 "# Messages dropped in routing: no acceptable method",
3603 /* If both dv and n are possible and we must choose:
3604 flip a coin for the choice between the two; for now 50/50 */
3605 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
3607 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
3612 if ((NULL != n) && (NULL != dv))
3613 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
3614 enough for redunancy, so clear the flag. */
3617 route_via_neighbour (n, hdr, options);
3621 route_via_dv (dv, hdr, options);
3628 * Structure of the key material used to encrypt backchannel messages.
3630 struct BackchannelKeyState
3633 * State of our block cipher.
3635 gcry_cipher_hd_t cipher;
3638 * Actual key material.
3644 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3646 struct GNUNET_CRYPTO_AuthKey hmac_key;
3649 * Symmetric key to use for encryption.
3651 char aes_key[256 / 8];
3654 * Counter value to use during setup.
3656 char aes_ctr[128 / 8];
3663 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3664 const struct GNUNET_ShortHashCode *iv,
3665 struct BackchannelKeyState *key)
3667 /* must match #dh_key_derive_eph_pub */
3668 GNUNET_assert (GNUNET_YES ==
3669 GNUNET_CRYPTO_kdf (&key->material,
3670 sizeof (key->material),
3671 "transport-backchannel-key",
3672 strlen ("transport-backchannel-key"),
3677 gcry_cipher_open (&key->cipher,
3678 GCRY_CIPHER_AES256 /* low level: go for speed */,
3679 GCRY_CIPHER_MODE_CTR,
3681 gcry_cipher_setkey (key->cipher,
3682 &key->material.aes_key,
3683 sizeof (key->material.aes_key));
3684 gcry_cipher_setctr (key->cipher,
3685 &key->material.aes_ctr,
3686 sizeof (key->material.aes_ctr));
3691 * Derive backchannel encryption key material from @a priv_ephemeral
3692 * and @a target and @a iv.
3694 * @param priv_ephemeral ephemeral private key to use
3695 * @param target the target peer to encrypt to
3696 * @param iv unique IV to use
3697 * @param key[out] set to the key material
3700 dh_key_derive_eph_pid (
3701 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3702 const struct GNUNET_PeerIdentity *target,
3703 const struct GNUNET_ShortHashCode *iv,
3704 struct BackchannelKeyState *key)
3706 struct GNUNET_HashCode km;
3708 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3709 &target->public_key,
3711 bc_setup_key_state_from_km (&km, iv, key);
3716 * Derive backchannel encryption key material from #GST_my_private_key
3717 * and @a pub_ephemeral and @a iv.
3719 * @param priv_ephemeral ephemeral private key to use
3720 * @param target the target peer to encrypt to
3721 * @param iv unique IV to use
3722 * @param key[out] set to the key material
3725 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3726 const struct GNUNET_ShortHashCode *iv,
3727 struct BackchannelKeyState *key)
3729 struct GNUNET_HashCode km;
3731 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3734 bc_setup_key_state_from_km (&km, iv, key);
3739 * Do HMAC calculation for backchannel messages over @a data using key
3740 * material from @a key.
3742 * @param key key material (from DH)
3743 * @param hmac[out] set to the HMAC
3744 * @param data data to perform HMAC calculation over
3745 * @param data_size number of bytes in @a data
3748 bc_hmac (const struct BackchannelKeyState *key,
3749 struct GNUNET_HashCode *hmac,
3753 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
3758 * Perform backchannel encryption using symmetric secret in @a key
3759 * to encrypt data from @a in to @a dst.
3761 * @param key[in,out] key material to use
3762 * @param dst where to write the result
3763 * @param in input data to encrypt (plaintext)
3764 * @param in_size number of bytes of input in @a in and available at @a dst
3767 bc_encrypt (struct BackchannelKeyState *key,
3773 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
3778 * Perform backchannel encryption using symmetric secret in @a key
3779 * to encrypt data from @a in to @a dst.
3781 * @param key[in,out] key material to use
3782 * @param ciph cipher text to decrypt
3783 * @param out[out] output data to generate (plaintext)
3784 * @param out_size number of bytes of input in @a ciph and available in @a out
3787 bc_decrypt (struct BackchannelKeyState *key,
3793 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
3798 * Clean up key material in @a key.
3800 * @param key key material to clean up (memory must not be free'd!)
3803 bc_key_clean (struct BackchannelKeyState *key)
3805 gcry_cipher_close (key->cipher);
3806 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
3811 * Communicator requests backchannel transmission. Process the request.
3813 * @param cls the client
3814 * @param cb the send message that was sent
3817 handle_communicator_backchannel (
3819 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3821 struct TransportClient *tc = cls;
3822 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3823 struct GNUNET_TIME_Absolute ephemeral_validity;
3824 struct TransportBackchannelEncapsulationMessage *enc;
3825 struct TransportBackchannelRequestPayload ppay;
3826 struct BackchannelKeyState key;
3830 /* encapsulate and encrypt message */
3831 msize = ntohs (cb->header.size) - sizeof (*cb) +
3832 sizeof (struct TransportBackchannelRequestPayload);
3833 enc = GNUNET_malloc (sizeof (*enc) + msize);
3835 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3836 enc->header.size = htons (sizeof (*enc) + msize);
3837 enc->target = cb->pid;
3838 lookup_ephemeral (&cb->pid,
3840 &enc->ephemeral_key,
3842 &ephemeral_validity);
3843 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3846 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
3847 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3848 ppay.monotonic_time =
3849 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3850 mpos = (char *) &enc[1];
3851 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
3854 &mpos[sizeof (ppay)],
3855 ntohs (cb->header.size) - sizeof (*cb));
3859 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3860 bc_key_clean (&key);
3861 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
3862 GNUNET_SERVICE_client_continue (tc->client);
3867 * Address of our peer added. Test message is well-formed.
3869 * @param cls the client
3870 * @param aam the send message that was sent
3871 * @return #GNUNET_OK if message is well-formed
3874 check_add_address (void *cls,
3875 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3877 struct TransportClient *tc = cls;
3879 if (CT_COMMUNICATOR != tc->type)
3882 return GNUNET_SYSERR;
3884 GNUNET_MQ_check_zero_termination (aam);
3890 * Ask peerstore to store our address.
3892 * @param cls an `struct AddressListEntry *`
3895 store_pi (void *cls);
3899 * Function called when peerstore is done storing our address.
3901 * @param cls a `struct AddressListEntry`
3902 * @param success #GNUNET_YES if peerstore was successful
3905 peerstore_store_own_cb (void *cls, int success)
3907 struct AddressListEntry *ale = cls;
3910 if (GNUNET_YES != success)
3911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3912 "Failed to store our own address `%s' in peerstore!\n",
3914 /* refresh period is 1/4 of expiration time, that should be plenty
3915 without being excessive. */
3917 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3925 * Ask peerstore to store our address.
3927 * @param cls an `struct AddressListEntry *`
3930 store_pi (void *cls)
3932 struct AddressListEntry *ale = cls;
3935 struct GNUNET_TIME_Absolute expiration;
3938 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3939 GNUNET_HELLO_sign_address (ale->address,
3945 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3948 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3952 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3953 &peerstore_store_own_cb,
3956 if (NULL == ale->sc)
3958 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3959 "Failed to store our address `%s' with peerstore\n",
3962 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
3968 * Address of our peer added. Process the request.
3970 * @param cls the client
3971 * @param aam the send message that was sent
3974 handle_add_address (void *cls,
3975 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3977 struct TransportClient *tc = cls;
3978 struct AddressListEntry *ale;
3981 slen = ntohs (aam->header.size) - sizeof (*aam);
3982 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3984 ale->address = (const char *) &ale[1];
3985 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3986 ale->aid = aam->aid;
3987 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3988 memcpy (&ale[1], &aam[1], slen);
3989 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3990 tc->details.communicator.addr_tail,
3992 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
3993 GNUNET_SERVICE_client_continue (tc->client);
3998 * Address of our peer deleted. Process the request.
4000 * @param cls the client
4001 * @param dam the send message that was sent
4004 handle_del_address (void *cls,
4005 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4007 struct TransportClient *tc = cls;
4009 if (CT_COMMUNICATOR != tc->type)
4012 GNUNET_SERVICE_client_drop (tc->client);
4015 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4019 if (dam->aid != ale->aid)
4021 GNUNET_assert (ale->tc == tc);
4022 free_address_list_entry (ale);
4023 GNUNET_SERVICE_client_continue (tc->client);
4026 GNUNET_SERVICE_client_drop (tc->client);
4031 * Context from #handle_incoming_msg(). Closure for many
4032 * message handlers below.
4034 struct CommunicatorMessageContext
4037 * Which communicator provided us with the message.
4039 struct TransportClient *tc;
4042 * Additional information for flow control and about the sender.
4044 struct GNUNET_TRANSPORT_IncomingMessage im;
4047 * Number of hops the message has travelled (if DV-routed).
4048 * FIXME: make use of this in ACK handling!
4050 uint16_t total_hops;
4055 * Given an inbound message @a msg from a communicator @a cmc,
4056 * demultiplex it based on the type calling the right handler.
4058 * @param cmc context for demultiplexing
4059 * @param msg message to demultiplex
4062 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4063 const struct GNUNET_MessageHeader *msg);
4067 * Send ACK to communicator (if requested) and free @a cmc.
4069 * @param cmc context for which we are done handling the message
4072 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4074 if (0 != ntohl (cmc->im.fc_on))
4076 /* send ACK when done to communicator for flow control! */
4077 struct GNUNET_MQ_Envelope *env;
4078 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4080 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4081 ack->reserved = htonl (0);
4082 ack->fc_id = cmc->im.fc_id;
4083 ack->sender = cmc->im.sender;
4084 GNUNET_MQ_send (cmc->tc->mq, env);
4086 GNUNET_SERVICE_client_continue (cmc->tc->client);
4092 * Communicator gave us an unencapsulated message to pass as-is to
4093 * CORE. Process the request.
4095 * @param cls a `struct CommunicatorMessageContext` (must call
4096 * #finish_cmc_handling() when done)
4097 * @param mh the message that was received
4100 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4102 struct CommunicatorMessageContext *cmc = cls;
4103 uint16_t size = ntohs (mh->size);
4105 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4106 (size < sizeof (struct GNUNET_MessageHeader)))
4108 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4111 finish_cmc_handling (cmc);
4112 GNUNET_SERVICE_client_drop (client);
4115 /* Forward to all CORE clients */
4116 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4118 struct GNUNET_MQ_Envelope *env;
4119 struct InboundMessage *im;
4121 if (CT_CORE != tc->type)
4123 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4124 im->peer = cmc->im.sender;
4125 memcpy (&im[1], mh, size);
4126 GNUNET_MQ_send (tc->mq, env);
4128 /* FIXME: consider doing this _only_ once the message
4129 was drained from the CORE MQs to extend flow control to CORE!
4130 (basically, increment counter in cmc, decrement on MQ send continuation! */
4131 finish_cmc_handling (cmc);
4136 * Communicator gave us a fragment box. Check the message.
4138 * @param cls a `struct CommunicatorMessageContext`
4139 * @param fb the send message that was sent
4140 * @return #GNUNET_YES if message is well-formed
4143 check_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4145 uint16_t size = ntohs (fb->header.size);
4146 uint16_t bsize = size - sizeof (*fb);
4150 GNUNET_break_op (0);
4151 return GNUNET_SYSERR;
4153 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4155 GNUNET_break_op (0);
4156 return GNUNET_SYSERR;
4158 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4160 GNUNET_break_op (0);
4161 return GNUNET_SYSERR;
4168 * Generate a fragment acknowledgement for an @a rc.
4170 * @param rc context to generate ACK for, @a rc ACK state is reset
4173 send_fragment_ack (struct ReassemblyContext *rc)
4175 struct TransportFragmentAckMessage *ack;
4177 ack = GNUNET_new (struct TransportFragmentAckMessage);
4178 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
4179 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
4180 ack->frag_uuid = htonl (rc->frag_uuid);
4181 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
4182 ack->msg_uuid = rc->msg_uuid;
4183 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
4184 if (0 == rc->msg_missing)
4185 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4186 GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
4188 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4189 GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
4190 route_message (&rc->neighbour->pid, &ack->header, RMO_DV_ALLOWED);
4191 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
4193 rc->extra_acks = 0LLU;
4198 * Communicator gave us a fragment. Process the request.
4200 * @param cls a `struct CommunicatorMessageContext` (must call
4201 * #finish_cmc_handling() when done)
4202 * @param fb the message that was received
4205 handle_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4207 struct CommunicatorMessageContext *cmc = cls;
4208 struct Neighbour *n;
4209 struct ReassemblyContext *rc;
4210 const struct GNUNET_MessageHeader *msg;
4216 struct GNUNET_TIME_Relative cdelay;
4219 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4222 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4225 finish_cmc_handling (cmc);
4226 GNUNET_SERVICE_client_drop (client);
4229 if (NULL == n->reassembly_map)
4231 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_YES);
4232 n->reassembly_heap =
4233 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4234 n->reassembly_timeout_task =
4235 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4236 &reassembly_cleanup_task,
4239 msize = ntohs (fb->msg_size);
4240 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map, &fb->msg_uuid);
4243 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4244 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4245 rc->msg_uuid = fb->msg_uuid;
4247 rc->msg_size = msize;
4248 rc->reassembly_timeout =
4249 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4250 rc->last_frag = GNUNET_TIME_absolute_get ();
4251 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4253 rc->reassembly_timeout.abs_value_us);
4254 GNUNET_assert (GNUNET_OK ==
4255 GNUNET_CONTAINER_multishortmap_put (
4259 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4260 target = (char *) &rc[1];
4261 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4262 rc->msg_missing = rc->msg_size;
4266 target = (char *) &rc[1];
4268 if (msize != rc->msg_size)
4271 finish_cmc_handling (cmc);
4276 fsize = ntohs (fb->header.size) - sizeof (*fb);
4277 frag_off = ntohs (fb->frag_off);
4278 memcpy (&target[frag_off], &fb[1], fsize);
4279 /* update bitfield and msg_missing */
4280 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4282 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4284 rc->bitfield[i / 8] |= (1 << (i % 8));
4289 /* Compute cummulative ACK */
4290 frag_uuid = ntohl (fb->frag_uuid);
4291 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4292 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->num_acks);
4293 rc->last_frag = GNUNET_TIME_absolute_get ();
4294 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay, cdelay);
4295 ack_now = GNUNET_NO;
4296 if (0 == rc->num_acks)
4298 /* case one: first ack */
4299 rc->frag_uuid = frag_uuid;
4300 rc->extra_acks = 0LLU;
4303 else if ((frag_uuid >= rc->frag_uuid) && (frag_uuid <= rc->frag_uuid + 64))
4305 /* case two: ack fits after existing min UUID */
4306 if ((frag_uuid == rc->frag_uuid) ||
4307 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))))
4309 /* duplicate fragment, ack now! */
4310 ack_now = GNUNET_YES;
4314 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
4318 else if ((rc->frag_uuid > frag_uuid) &&
4319 (((rc->frag_uuid == frag_uuid + 64) && (0 == rc->extra_acks)) ||
4320 ((rc->frag_uuid < frag_uuid + 64) &&
4323 ~((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))))))
4325 /* can fit ack by shifting extra acks and starting at
4326 frag_uid, test above esured that the bits we will
4327 shift 'extra_acks' by are all zero. */
4328 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
4329 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
4330 rc->frag_uuid = frag_uuid;
4333 if (65 == rc->num_acks) /* OPTIMIZE-FIXME: maybe use smaller threshold? This
4334 is very aggressive. */
4335 ack_now = GNUNET_YES; /* maximum acks received */
4336 // FIXME: possibly also ACK based on RTT (but for that we'd need to
4337 // determine the queue used for the ACK first!)
4339 /* is reassembly complete? */
4340 if (0 != rc->msg_missing)
4343 send_fragment_ack (rc);
4344 finish_cmc_handling (cmc);
4347 /* reassembly is complete, verify result */
4348 msg = (const struct GNUNET_MessageHeader *) &rc[1];
4349 if (ntohs (msg->size) != rc->msg_size)
4352 free_reassembly_context (rc);
4353 finish_cmc_handling (cmc);
4356 /* successful reassembly */
4357 send_fragment_ack (rc);
4358 demultiplex_with_cmc (cmc, msg);
4359 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
4360 en-route and we forget that we finished this reassembly immediately!
4361 -> keep around until timeout?
4362 -> shorten timeout based on ACK? */
4363 free_reassembly_context (rc);
4368 * Check the @a fa against the fragments associated with @a pm.
4369 * If it matches, remove the matching fragments from the transmission
4372 * @param pm pending message to check against the ack
4373 * @param fa the ack that was received
4374 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4377 check_ack_against_pm (struct PendingMessage *pm,
4378 const struct TransportFragmentAckMessage *fa)
4381 struct PendingMessage *nxt;
4382 uint32_t fs = ntohl (fa->frag_uuid);
4383 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4386 for (struct PendingMessage *frag = pm->head_frag; NULL != frag; frag = nxt)
4388 const struct TransportFragmentBox *tfb =
4389 (const struct TransportFragmentBox *) &pm[1];
4390 uint32_t fu = ntohl (tfb->frag_uuid);
4392 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4393 nxt = frag->next_frag;
4394 /* Check for exact match or match in the 'xtra' bitmask */
4396 ((fu > fs) && (fu <= fs + 64) && (0 != (1LLU << (fu - fs - 1) & xtra))))
4399 free_fragment_tree (frag);
4407 * Communicator gave us a fragment acknowledgement. Process the request.
4409 * @param cls a `struct CommunicatorMessageContext` (must call
4410 * #finish_cmc_handling() when done)
4411 * @param fa the message that was received
4414 handle_fragment_ack (void *cls, const struct TransportFragmentAckMessage *fa)
4416 struct CommunicatorMessageContext *cmc = cls;
4417 struct Neighbour *n;
4420 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4423 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4426 finish_cmc_handling (cmc);
4427 GNUNET_SERVICE_client_drop (client);
4430 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4431 matched = GNUNET_NO;
4432 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm;
4433 pm = pm->prev_neighbour)
4435 if (0 != GNUNET_memcmp (&fa->msg_uuid, &pm->msg_uuid))
4437 matched = GNUNET_YES;
4438 if (GNUNET_YES == check_ack_against_pm (pm, fa))
4440 struct GNUNET_TIME_Relative avg_ack_delay =
4441 GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4442 // FIXME: update RTT and other reliability data!
4443 // ISSUE: we don't know which of n's queues the message(s)
4444 // took (and in fact the different messages might have gone
4445 // over different queues and possibly over multiple).
4446 // => track queues with PendingMessages, and update RTT only if
4447 // the queue used is unique?
4448 // -> how can we get loss rates?
4449 // -> or, add extra state to Box and ACK to identify queue?
4450 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4451 // the queue with the fragment! (-> this logic must
4452 // be moved into check_ack_against_pm!)
4453 (void) avg_ack_delay;
4457 GNUNET_STATISTICS_update (GST_stats,
4458 "# FRAGMENT_ACKS dropped, no matching fragment",
4462 if (NULL == pm->head_frag)
4464 // if entire message is ACKed, handle that as well.
4465 // => clean up PM, any post actions?
4466 free_pending_message (pm);
4470 struct GNUNET_TIME_Relative reassembly_timeout =
4471 GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4472 // OPTIMIZE-FIXME: adjust retransmission strategy based on
4473 // reassembly_timeout!
4474 (void) reassembly_timeout;
4478 if (GNUNET_NO == matched)
4480 GNUNET_STATISTICS_update (GST_stats,
4481 "# FRAGMENT_ACKS dropped, no matching pending message",
4485 finish_cmc_handling (cmc);
4490 * Communicator gave us a reliability box. Check the message.
4492 * @param cls a `struct CommunicatorMessageContext`
4493 * @param rb the send message that was sent
4494 * @return #GNUNET_YES if message is well-formed
4497 check_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4499 GNUNET_MQ_check_boxed_message (rb);
4505 * Communicator gave us a reliability box. Process the request.
4507 * @param cls a `struct CommunicatorMessageContext` (must call
4508 * #finish_cmc_handling() when done)
4509 * @param rb the message that was received
4512 handle_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4514 struct CommunicatorMessageContext *cmc = cls;
4515 const struct GNUNET_MessageHeader *inbox =
4516 (const struct GNUNET_MessageHeader *) &rb[1];
4518 if (0 == ntohl (rb->ack_countdown))
4520 struct TransportReliabilityAckMessage *ack;
4522 /* FIXME-OPTIMIZE: implement cummulative ACKs and ack_countdown,
4523 then setting the avg_ack_delay field below: */
4524 ack = GNUNET_malloc (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4525 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4527 htons (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4528 memcpy (&ack[1], &rb->msg_uuid, sizeof (struct GNUNET_ShortHashCode));
4529 route_message (&cmc->im.sender, &ack->header, RMO_DV_ALLOWED);
4531 /* continue with inner message */
4532 demultiplex_with_cmc (cmc, inbox);
4537 * Communicator gave us a reliability ack. Process the request.
4539 * @param cls a `struct CommunicatorMessageContext` (must call
4540 * #finish_cmc_handling() when done)
4541 * @param ra the message that was received
4544 handle_reliability_ack (void *cls,
4545 const struct TransportReliabilityAckMessage *ra)
4547 struct CommunicatorMessageContext *cmc = cls;
4548 struct Neighbour *n;
4549 unsigned int n_acks;
4550 const struct GNUNET_ShortHashCode *msg_uuids;
4551 struct PendingMessage *nxt;
4554 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4557 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4560 finish_cmc_handling (cmc);
4561 GNUNET_SERVICE_client_drop (client);
4564 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
4565 sizeof (struct GNUNET_ShortHashCode);
4566 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4568 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4569 matched = GNUNET_NO;
4570 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm; pm = nxt)
4574 nxt = pm->next_neighbour;
4575 in_list = GNUNET_NO;
4576 for (unsigned int i = 0; i < n_acks; i++)
4578 if (0 != GNUNET_memcmp (&msg_uuids[i], &pm->msg_uuid))
4580 in_list = GNUNET_YES;
4583 if (GNUNET_NO == in_list)
4586 /* this pm was acked! */
4587 matched = GNUNET_YES;
4588 free_pending_message (pm);
4591 struct GNUNET_TIME_Relative avg_ack_delay =
4592 GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4593 // FIXME: update RTT and other reliability data!
4594 // ISSUE: we don't know which of n's queues the message(s)
4595 // took (and in fact the different messages might have gone
4596 // over different queues and possibly over multiple).
4597 // => track queues with PendingMessages, and update RTT only if
4598 // the queue used is unique?
4599 // -> how can we get loss rates?
4600 // -> or, add extra state to MSG and ACKs to identify queue?
4601 // -> if we do this, might just do the same for the avg_ack_delay!
4602 (void) avg_ack_delay;
4605 if (GNUNET_NO == matched)
4607 GNUNET_STATISTICS_update (GST_stats,
4608 "# FRAGMENT_ACKS dropped, no matching pending message",
4612 finish_cmc_handling (cmc);
4617 * Communicator gave us a backchannel encapsulation. Check the message.
4619 * @param cls a `struct CommunicatorMessageContext`
4620 * @param be the send message that was sent
4621 * @return #GNUNET_YES if message is well-formed
4624 check_backchannel_encapsulation (
4626 const struct TransportBackchannelEncapsulationMessage *be)
4628 uint16_t size = ntohs (be->header.size);
4631 if ((size - sizeof (*be)) <
4632 (sizeof (struct TransportBackchannelRequestPayload) +
4633 sizeof (struct GNUNET_MessageHeader)))
4635 GNUNET_break_op (0);
4636 return GNUNET_SYSERR;
4643 * We received the plaintext @a msg from backtalker @a b. Forward
4644 * it to the respective communicator.
4646 * @param b a backtalker
4647 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
4648 * followed by the target name of the communicator
4649 * @param msg_size number of bytes in @a msg
4652 forward_backchannel_payload (struct Backtalker *b,
4656 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
4657 struct GNUNET_MQ_Envelope *env;
4658 struct TransportClient *tc;
4659 const struct GNUNET_MessageHeader *mh;
4660 const char *target_communicator;
4663 /* Determine target_communicator and check @a msg is well-formed */
4665 mhs = ntohs (mh->size);
4666 if (mhs <= msg_size)
4668 GNUNET_break_op (0);
4671 target_communicator = &((const char *) msg)[ntohs (mh->size)];
4672 if ('\0' != target_communicator[msg_size - mhs - 1])
4674 GNUNET_break_op (0);
4677 /* Find client providing this communicator */
4678 for (tc = clients_head; NULL != tc; tc = tc->next)
4679 if ((CT_COMMUNICATOR == tc->type) &&
4681 strcmp (tc->details.communicator.address_prefix, target_communicator)))
4689 "# Backchannel message dropped: target communicator `%s' unknown",
4690 target_communicator);
4691 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
4692 GNUNET_free (stastr);
4695 /* Finally, deliver backchannel message to communicator */
4696 env = GNUNET_MQ_msg_extra (
4699 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
4701 memcpy (&cbi[1], msg, msg_size);
4702 GNUNET_MQ_send (tc->mq, env);
4707 * Free data structures associated with @a b.
4709 * @param b data structure to release
4712 free_backtalker (struct Backtalker *b)
4716 GNUNET_PEERSTORE_iterate_cancel (b->get);
4718 GNUNET_assert (NULL != b->cmc);
4719 finish_cmc_handling (b->cmc);
4722 if (NULL != b->task)
4724 GNUNET_SCHEDULER_cancel (b->task);
4729 GNUNET_PEERSTORE_store_cancel (b->sc);
4734 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
4740 * Callback to free backtalker records.
4744 * @param value a `struct Backtalker`
4745 * @return #GNUNET_OK (always)
4748 free_backtalker_cb (void *cls,
4749 const struct GNUNET_PeerIdentity *pid,
4752 struct Backtalker *b = value;
4756 free_backtalker (b);
4762 * Function called when it is time to clean up a backtalker.
4764 * @param cls a `struct Backtalker`
4767 backtalker_timeout_cb (void *cls)
4769 struct Backtalker *b = cls;
4772 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
4774 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
4777 GNUNET_assert (NULL == b->sc);
4778 free_backtalker (b);
4783 * Function called with the monotonic time of a backtalker
4784 * by PEERSTORE. Updates the time and continues processing.
4786 * @param cls a `struct Backtalker`
4787 * @param record the information found, NULL for the last call
4788 * @param emsg error message
4791 backtalker_monotime_cb (void *cls,
4792 const struct GNUNET_PEERSTORE_Record *record,
4795 struct Backtalker *b = cls;
4796 struct GNUNET_TIME_AbsoluteNBO *mtbe;
4797 struct GNUNET_TIME_Absolute mt;
4802 /* we're done with #backtalker_monotime_cb() invocations,
4803 continue normal processing */
4805 GNUNET_assert (NULL != b->cmc);
4806 finish_cmc_handling (b->cmc);
4808 if (0 != b->body_size)
4809 forward_backchannel_payload (b, &b[1], b->body_size);
4812 if (sizeof (*mtbe) != record->value_size)
4817 mtbe = record->value;
4818 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
4819 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
4821 GNUNET_STATISTICS_update (
4823 "# Backchannel messages dropped: monotonic time not increasing",
4826 b->monotonic_time = mt;
4827 /* Setting body_size to 0 prevents call to #forward_backchannel_payload() */
4835 * Function called by PEERSTORE when the store operation of
4836 * a backtalker's monotonic time is complete.
4838 * @param cls the `struct Backtalker`
4839 * @param success #GNUNET_OK on success
4842 backtalker_monotime_store_cb (void *cls, int success)
4844 struct Backtalker *b = cls;
4846 if (GNUNET_OK != success)
4848 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4849 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
4852 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
4857 * The backtalker @a b monotonic time changed. Update PEERSTORE.
4859 * @param b a backtalker with updated monotonic time
4862 update_backtalker_monotime (struct Backtalker *b)
4864 struct GNUNET_TIME_AbsoluteNBO mtbe;
4868 GNUNET_PEERSTORE_store_cancel (b->sc);
4873 GNUNET_SCHEDULER_cancel (b->task);
4876 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
4877 b->sc = GNUNET_PEERSTORE_store (peerstore,
4880 "transport-backchannel-monotonic-time",
4883 GNUNET_TIME_UNIT_FOREVER_ABS,
4884 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
4885 &backtalker_monotime_store_cb,
4891 * Communicator gave us a backchannel encapsulation. Process the request.
4892 * (We are not the origin of the backchannel here, the communicator simply
4893 * received a backchannel message and we are expected to forward it.)
4895 * @param cls a `struct CommunicatorMessageContext` (must call
4896 * #finish_cmc_handling() when done)
4897 * @param be the message that was received
4900 handle_backchannel_encapsulation (
4902 const struct TransportBackchannelEncapsulationMessage *be)
4904 struct CommunicatorMessageContext *cmc = cls;
4905 struct BackchannelKeyState key;
4906 struct GNUNET_HashCode hmac;
4910 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
4912 /* not for me, try to route to target */
4913 route_message (&be->target,
4914 GNUNET_copy_message (&be->header),
4916 finish_cmc_handling (cmc);
4919 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
4920 hdr = (const char *) &be[1];
4921 hdr_len = ntohs (be->header.size) - sizeof (*be);
4922 bc_hmac (&key, &hmac, hdr, hdr_len);
4923 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
4925 /* HMAC missmatch, disard! */
4926 GNUNET_break_op (0);
4927 finish_cmc_handling (cmc);
4930 /* begin actual decryption */
4932 struct Backtalker *b;
4933 struct GNUNET_TIME_Absolute monotime;
4934 struct TransportBackchannelRequestPayload ppay;
4935 char body[hdr_len - sizeof (ppay)];
4937 GNUNET_assert (hdr_len >=
4938 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4939 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
4940 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
4941 bc_key_clean (&key);
4942 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
4943 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
4944 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
4946 GNUNET_STATISTICS_update (
4948 "# Backchannel messages dropped: monotonic time not increasing",
4951 finish_cmc_handling (cmc);
4955 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
4957 /* Check signature */
4958 struct EphemeralConfirmationPS ec;
4960 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4961 ec.purpose.size = htonl (sizeof (ec));
4962 ec.target = GST_my_identity;
4963 ec.ephemeral_key = be->ephemeral_key;
4966 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
4969 &ppay.sender.public_key))
4971 /* Signature invalid, disard! */
4972 GNUNET_break_op (0);
4973 finish_cmc_handling (cmc);
4979 /* update key cache and mono time */
4980 b->last_ephemeral = be->ephemeral_key;
4981 b->monotonic_time = monotime;
4982 update_backtalker_monotime (b);
4983 forward_backchannel_payload (b, body, sizeof (body));
4985 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
4986 finish_cmc_handling (cmc);
4989 /* setup data structure to cache signature AND check
4990 monotonic time with PEERSTORE before forwarding backchannel payload */
4991 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
4992 b->pid = ppay.sender;
4993 b->body_size = sizeof (body);
4994 memcpy (&b[1], body, sizeof (body));
4995 GNUNET_assert (GNUNET_YES ==
4996 GNUNET_CONTAINER_multipeermap_put (
5000 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5001 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5004 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5005 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5006 b->get = GNUNET_PEERSTORE_iterate (peerstore,
5009 "transport-backchannel-monotonic-time",
5010 &backtalker_monotime_cb,
5017 * Task called when we should check if any of the DV paths
5018 * we have learned to a target are due for garbage collection.
5020 * Collects stale paths, and possibly frees the entire DV
5021 * entry if no paths are left. Otherwise re-schedules itself.
5023 * @param cls a `struct DistanceVector`
5026 path_cleanup_cb (void *cls)
5028 struct DistanceVector *dv = cls;
5029 struct DistanceVectorHop *pos;
5031 dv->timeout_task = NULL;
5032 while (NULL != (pos = dv->dv_head))
5034 GNUNET_assert (dv == pos->dv);
5035 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5037 free_distance_vector_hop (pos);
5045 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5049 * Task run to check whether the hops of the @a cls still
5050 * are validated, or if we need to core about disconnection.
5052 * @param cls a `struct DistanceVector` (with core_visible set!)
5055 check_dv_path_down (void *cls)
5057 struct DistanceVector *dv = cls;
5058 struct Neighbour *n;
5060 dv->visibility_task = NULL;
5061 GNUNET_assert (GNUNET_YES == dv->core_visible);
5062 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5066 GNUNET_TIME_absolute_get_remaining (pos->path_valid_until).rel_value_us)
5068 dv->visibility_task = GNUNET_SCHEDULER_add_at (pos->path_valid_until,
5069 &check_dv_path_down,
5074 /* all paths invalid, make dv core-invisible */
5075 dv->core_visible = GNUNET_NO;
5076 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
5077 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5078 return; /* no need to tell core, connection still up! */
5079 cores_send_disconnect_info (&dv->target);
5084 * The @a hop is a validated path to the respective target
5085 * peer and we should tell core about it -- and schedule
5086 * a job to revoke the state.
5088 * @param hop a path to some peer that is the reason for activation
5091 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5093 struct DistanceVector *dv = hop->dv;
5094 struct Neighbour *n;
5096 GNUNET_assert (GNUNET_NO == dv->core_visible);
5097 GNUNET_assert (NULL == dv->visibility_task);
5099 dv->core_visible = GNUNET_YES;
5100 dv->visibility_task =
5101 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_dv_path_down, dv);
5102 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
5103 if ((NULL != n) && (GNUNET_YES == n->core_visible))
5104 return; /* no need to tell core, connection already up! */
5105 cores_send_connect_info (&dv->target,
5107 ? GNUNET_BANDWIDTH_value_sum (n->quota_out,
5114 * We have learned a @a path through the network to some other peer, add it to
5115 * our DV data structure (returning #GNUNET_YES on success).
5117 * We do not add paths if we have a sufficient number of shorter
5118 * paths to this target already (returning #GNUNET_NO).
5120 * We also do not add problematic paths, like those where we lack the first
5121 * hop in our neighbour list (i.e. due to a topology change) or where some
5122 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
5124 * @param path the path we learned, path[0] should be us,
5125 * and then path contains a valid path from us to `path[path_len-1]`
5126 * path[1] should be a direct neighbour (we should check!)
5127 * @param path_len number of entries on the @a path, at least three!
5128 * @param network_latency how long does the message take from us to
5129 * `path[path_len-1]`? set to "forever" if unknown
5130 * @param path_valid_until how long is this path considered validated? Maybe be
5132 * @return #GNUNET_YES on success,
5133 * #GNUNET_NO if we have better path(s) to the target
5134 * #GNUNET_SYSERR if the path is useless and/or invalid
5135 * (i.e. path[1] not a direct neighbour
5136 * or path[i+1] is a direct neighbour for i>0)
5139 learn_dv_path (const struct GNUNET_PeerIdentity *path,
5140 unsigned int path_len,
5141 struct GNUNET_TIME_Relative network_latency,
5142 struct GNUNET_TIME_Absolute path_valid_until)
5144 struct DistanceVectorHop *hop;
5145 struct DistanceVector *dv;
5146 struct Neighbour *next_hop;
5147 unsigned int shorter_distance;
5151 /* what a boring path! not allowed! */
5153 return GNUNET_SYSERR;
5155 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
5156 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours, &path[1]);
5157 if (NULL == next_hop)
5159 /* next hop must be a neighbour, otherwise this whole thing is useless! */
5161 return GNUNET_SYSERR;
5163 for (unsigned int i = 2; i < path_len; i++)
5164 if (NULL != GNUNET_CONTAINER_multipeermap_get (neighbours, &path[i]))
5166 /* Useless path, we have a direct connection to some hop
5167 in the middle of the path, so this one doesn't even
5168 seem terribly useful for redundancy */
5169 return GNUNET_SYSERR;
5171 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
5174 dv = GNUNET_new (struct DistanceVector);
5175 dv->target = path[path_len - 1];
5176 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
5179 GNUNET_assert (GNUNET_OK ==
5180 GNUNET_CONTAINER_multipeermap_put (
5184 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5186 /* Check if we have this path already! */
5187 shorter_distance = 0;
5188 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5191 if (pos->distance < path_len - 2)
5193 /* Note that the distances in 'pos' excludes us (path[0]) and
5194 the next_hop (path[1]), so we need to subtract two
5195 and check next_hop explicitly */
5196 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
5198 int match = GNUNET_YES;
5200 for (unsigned int i = 0; i < pos->distance; i++)
5202 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
5208 if (GNUNET_YES == match)
5210 struct GNUNET_TIME_Relative last_timeout;
5212 /* Re-discovered known path, update timeout */
5213 GNUNET_STATISTICS_update (GST_stats,
5214 "# Known DV path refreshed",
5217 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
5219 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5220 pos->path_valid_until =
5221 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
5222 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
5223 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
5224 if ((GNUNET_NO == dv->core_visible) &&
5225 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until)
5227 activate_core_visible_dv_path (pos);
5228 if (last_timeout.rel_value_us <
5229 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
5230 DV_PATH_DISCOVERY_FREQUENCY)
5233 /* Some peer send DV learn messages too often, we are learning
5234 the same path faster than it would be useful; do not forward! */
5241 /* Count how many shorter paths we have (incl. direct
5242 neighbours) before simply giving up on this one! */
5243 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
5245 /* We have a shorter path already! */
5248 /* create new DV path entry */
5249 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
5250 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5251 hop->next_hop = next_hop;
5253 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
5256 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
5257 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
5258 hop->path_valid_until = path_valid_until;
5259 hop->distance = path_len - 2;
5260 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
5261 GNUNET_CONTAINER_MDLL_insert (neighbour,
5265 if ((GNUNET_NO == dv->core_visible) &&
5266 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us))
5267 activate_core_visible_dv_path (hop);
5273 * Communicator gave us a DV learn message. Check the message.
5275 * @param cls a `struct CommunicatorMessageContext`
5276 * @param dvl the send message that was sent
5277 * @return #GNUNET_YES if message is well-formed
5280 check_dv_learn (void *cls, const struct TransportDVLearn *dvl)
5282 uint16_t size = ntohs (dvl->header.size);
5283 uint16_t num_hops = ntohs (dvl->num_hops);
5284 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
5287 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
5289 GNUNET_break_op (0);
5290 return GNUNET_SYSERR;
5292 if (num_hops > MAX_DV_HOPS_ALLOWED)
5294 GNUNET_break_op (0);
5295 return GNUNET_SYSERR;
5297 for (unsigned int i = 0; i < num_hops; i++)
5299 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
5301 GNUNET_break_op (0);
5302 return GNUNET_SYSERR;
5304 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
5306 GNUNET_break_op (0);
5307 return GNUNET_SYSERR;
5315 * Build and forward a DV learn message to @a next_hop.
5317 * @param next_hop peer to send the message to
5318 * @param msg message received
5319 * @param bi_history bitmask specifying hops on path that were bidirectional
5320 * @param nhops length of the @a hops array
5321 * @param hops path the message traversed so far
5322 * @param in_time when did we receive the message, used to calculate network
5326 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
5327 const struct TransportDVLearn *msg,
5328 uint16_t bi_history,
5330 const struct DVPathEntryP *hops,
5331 struct GNUNET_TIME_Absolute in_time)
5333 struct DVPathEntryP *dhops;
5334 struct TransportDVLearn *fwd;
5335 struct GNUNET_TIME_Relative nnd;
5337 /* compute message for forwarding */
5338 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
5339 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
5340 (nhops + 1) * sizeof (struct DVPathEntryP));
5341 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
5342 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
5343 (nhops + 1) * sizeof (struct DVPathEntryP));
5344 fwd->num_hops = htons (nhops + 1);
5345 fwd->bidirectional = htons (bi_history);
5346 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
5347 GNUNET_TIME_relative_ntoh (
5348 msg->non_network_delay));
5349 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
5350 fwd->init_sig = msg->init_sig;
5351 fwd->initiator = msg->initiator;
5352 fwd->challenge = msg->challenge;
5353 dhops = (struct DVPathEntryP *) &fwd[1];
5354 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
5355 dhops[nhops].hop = GST_my_identity;
5357 struct DvHopPS dhp = {.purpose.purpose =
5358 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
5359 .purpose.size = htonl (sizeof (dhp)),
5360 .pred = dhops[nhops - 1].hop,
5362 .challenge = msg->challenge};
5364 GNUNET_assert (GNUNET_OK ==
5365 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5367 &dhops[nhops].hop_sig));
5369 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
5374 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
5376 * @param init the signer
5377 * @param challenge the challenge that was signed
5378 * @param init_sig signature presumably by @a init
5379 * @return #GNUNET_OK if the signature is valid
5382 validate_dv_initiator_signature (
5383 const struct GNUNET_PeerIdentity *init,
5384 const struct GNUNET_ShortHashCode *challenge,
5385 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
5387 struct DvInitPS ip = {.purpose.purpose = htonl (
5388 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
5389 .purpose.size = htonl (sizeof (ip)),
5390 .challenge = *challenge};
5394 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
5399 GNUNET_break_op (0);
5400 return GNUNET_SYSERR;
5407 * Communicator gave us a DV learn message. Process the request.
5409 * @param cls a `struct CommunicatorMessageContext` (must call
5410 * #finish_cmc_handling() when done)
5411 * @param dvl the message that was received
5414 handle_dv_learn (void *cls, const struct TransportDVLearn *dvl)
5416 struct CommunicatorMessageContext *cmc = cls;
5417 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
5420 uint16_t bi_history;
5421 const struct DVPathEntryP *hops;
5424 struct GNUNET_TIME_Absolute in_time;
5426 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
5427 bi_history = ntohs (dvl->bidirectional);
5428 hops = (const struct DVPathEntryP *) &dvl[1];
5432 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
5435 finish_cmc_handling (cmc);
5442 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
5445 finish_cmc_handling (cmc);
5450 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
5451 cc = cmc->tc->details.communicator.cc;
5452 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
5453 cc); // FIXME: add bi-directional flag to cc?
5454 in_time = GNUNET_TIME_absolute_get ();
5456 /* continue communicator here, everything else can happen asynchronous! */
5457 finish_cmc_handling (cmc);
5459 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
5460 the initiator signature if we send the message back to the initiator... */
5461 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
5465 GNUNET_break_op (0);
5468 // FIXME: asynchronously (!) verify hop-by-hop signatures!
5469 // => if signature verification load too high, implement random drop
5472 do_fwd = GNUNET_YES;
5473 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
5475 struct GNUNET_PeerIdentity path[nhops + 1];
5476 struct GNUNET_TIME_Relative host_latency_sum;
5477 struct GNUNET_TIME_Relative latency;
5478 struct GNUNET_TIME_Relative network_latency;
5480 /* We initiated this, learn the forward path! */
5481 path[0] = GST_my_identity;
5482 path[1] = hops[0].hop;
5483 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
5485 // Need also something to lookup initiation time
5486 // to compute RTT! -> add RTT argument here?
5487 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
5488 // (based on dvl->challenge, we can identify time of origin!)
5490 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
5491 /* assumption: latency on all links is the same */
5492 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
5494 for (unsigned int i = 2; i <= nhops; i++)
5496 struct GNUNET_TIME_Relative ilat;
5498 /* assumption: linear latency increase per hop */
5499 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
5500 path[i] = hops[i - 1].hop;
5501 learn_dv_path (path,
5504 GNUNET_TIME_relative_to_absolute (
5505 ADDRESS_VALIDATION_LIFETIME));
5507 /* as we initiated, do not forward again (would be circular!) */
5513 /* last hop was bi-directional, we could learn something here! */
5514 struct GNUNET_PeerIdentity path[nhops + 2];
5516 path[0] = GST_my_identity;
5517 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
5518 for (unsigned int i = 0; i < nhops; i++)
5522 if (0 == (bi_history & (1 << i)))
5523 break; /* i-th hop not bi-directional, stop learning! */
5526 path[i + 2] = dvl->initiator;
5530 path[i + 2] = hops[nhops - i - 2].hop;
5533 iret = learn_dv_path (path,
5535 GNUNET_TIME_UNIT_FOREVER_REL,
5536 GNUNET_TIME_UNIT_ZERO_ABS);
5537 if (GNUNET_SYSERR == iret)
5539 /* path invalid or too long to be interesting for US, thus should also
5540 not be interesting to our neighbours, cut path when forwarding to
5541 'i' hops, except of course for the one that goes back to the
5543 GNUNET_STATISTICS_update (GST_stats,
5544 "# DV learn not forwarded due invalidity of path",
5550 if ((GNUNET_NO == iret) && (nhops == i + 1))
5552 /* we have better paths, and this is the longest target,
5553 so there cannot be anything interesting later */
5554 GNUNET_STATISTICS_update (GST_stats,
5555 "# DV learn not forwarded, got better paths",
5564 if (MAX_DV_HOPS_ALLOWED == nhops)
5566 /* At limit, we're out of here! */
5567 finish_cmc_handling (cmc);
5571 /* Forward to initiator, if path non-trivial and possible */
5572 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
5573 did_initiator = GNUNET_NO;
5576 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
5578 /* send back to origin! */
5579 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
5580 did_initiator = GNUNET_YES;
5582 /* We forward under two conditions: either we still learned something
5583 ourselves (do_fwd), or the path was darn short and thus the initiator is
5584 likely to still be very interested in this (and we did NOT already
5585 send it back to the initiator) */
5586 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
5587 (GNUNET_NO == did_initiator)))
5589 /* FIXME: loop over all neighbours, pick those with low
5590 queues AND that are not yet on the path; possibly
5591 adapt threshold to nhops! */
5593 forward_dv_learn (NULL, // fill in peer from iterator here!
5605 * Communicator gave us a DV box. Check the message.
5607 * @param cls a `struct CommunicatorMessageContext`
5608 * @param dvb the send message that was sent
5609 * @return #GNUNET_YES if message is well-formed
5612 check_dv_box (void *cls, const struct TransportDVBox *dvb)
5614 uint16_t size = ntohs (dvb->header.size);
5615 uint16_t num_hops = ntohs (dvb->num_hops);
5616 const struct GNUNET_PeerIdentity *hops =
5617 (const struct GNUNET_PeerIdentity *) &dvb[1];
5618 const struct GNUNET_MessageHeader *inbox =
5619 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5624 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
5625 sizeof (struct GNUNET_MessageHeader))
5627 GNUNET_break_op (0);
5628 return GNUNET_SYSERR;
5630 isize = ntohs (inbox->size);
5632 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
5634 GNUNET_break_op (0);
5635 return GNUNET_SYSERR;
5637 itype = ntohs (inbox->type);
5638 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
5639 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
5641 GNUNET_break_op (0);
5642 return GNUNET_SYSERR;
5644 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
5646 GNUNET_break_op (0);
5647 return GNUNET_SYSERR;
5654 * Create a DV Box message and queue it for transmission to
5657 * @param next_hop peer to receive the message next
5658 * @param total_hops how many hops did the message take so far
5659 * @param num_hops length of the @a hops array
5660 * @param origin origin of the message
5661 * @param hops next peer(s) to the destination, including destination
5662 * @param payload payload of the box
5663 * @param payload_size number of bytes in @a payload
5666 forward_dv_box (struct Neighbour *next_hop,
5667 uint16_t total_hops,
5669 const struct GNUNET_PeerIdentity *origin,
5670 const struct GNUNET_PeerIdentity *hops,
5671 const void *payload,
5672 uint16_t payload_size)
5674 struct TransportDVBox *dvb;
5675 struct GNUNET_PeerIdentity *dhops;
5677 GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBox) +
5678 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5680 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
5681 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5684 htons (sizeof (struct TransportDVBox) +
5685 sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size);
5686 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5687 dvb->total_hops = htons (total_hops);
5688 dvb->num_hops = htons (num_hops);
5689 dvb->origin = *origin;
5690 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5691 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
5692 memcpy (&dhops[num_hops], payload, payload_size);
5693 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
5698 * Communicator gave us a DV box. Process the request.
5700 * @param cls a `struct CommunicatorMessageContext` (must call
5701 * #finish_cmc_handling() when done)
5702 * @param dvb the message that was received
5705 handle_dv_box (void *cls, const struct TransportDVBox *dvb)
5707 struct CommunicatorMessageContext *cmc = cls;
5708 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5709 uint16_t num_hops = ntohs (dvb->num_hops);
5710 const struct GNUNET_PeerIdentity *hops =
5711 (const struct GNUNET_PeerIdentity *) &dvb[1];
5712 const struct GNUNET_MessageHeader *inbox =
5713 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5717 /* We're trying from the end of the hops array, as we may be
5718 able to find a shortcut unknown to the origin that way */
5719 for (int i = num_hops - 1; i >= 0; i--)
5721 struct Neighbour *n;
5723 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
5725 GNUNET_break_op (0);
5726 finish_cmc_handling (cmc);
5729 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &hops[i]);
5733 ntohs (dvb->total_hops) + 1,
5734 num_hops - i - 1, /* number of hops left */
5736 &hops[i + 1], /* remaining hops */
5737 (const void *) &dvb[1],
5739 finish_cmc_handling (cmc);
5742 /* Woopsie, next hop not in neighbours, drop! */
5743 GNUNET_STATISTICS_update (GST_stats,
5744 "# DV Boxes dropped: next hop unknown",
5747 finish_cmc_handling (cmc);
5750 /* We are the target. Unbox and handle message. */
5751 cmc->im.sender = dvb->origin;
5752 cmc->total_hops = ntohs (dvb->total_hops);
5753 demultiplex_with_cmc (cmc, inbox);
5758 * Client notified us about transmission from a peer. Process the request.
5760 * @param cls a `struct TransportClient` which sent us the message
5761 * @param obm the send message that was sent
5762 * @return #GNUNET_YES if message is well-formed
5765 check_incoming_msg (void *cls,
5766 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5768 struct TransportClient *tc = cls;
5770 if (CT_COMMUNICATOR != tc->type)
5773 return GNUNET_SYSERR;
5775 GNUNET_MQ_check_boxed_message (im);
5781 * Communicator gave us a transport address validation challenge. Process the
5784 * @param cls a `struct CommunicatorMessageContext` (must call
5785 * #finish_cmc_handling() when done)
5786 * @param tvc the message that was received
5789 handle_validation_challenge (void *cls,
5790 const struct TransportValidationChallenge *tvc)
5792 struct CommunicatorMessageContext *cmc = cls;
5793 struct TransportValidationResponse *tvr;
5795 if (cmc->total_hops > 0)
5797 /* DV routing is not allowed for validation challenges! */
5798 GNUNET_break_op (0);
5799 finish_cmc_handling (cmc);
5802 tvr = GNUNET_new (struct TransportValidationResponse);
5804 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5805 tvr->header.size = htons (sizeof (*tvr));
5806 tvr->challenge = tvc->challenge;
5807 tvr->origin_time = tvc->sender_time;
5808 tvr->validity_duration = cmc->im.expected_address_validity;
5810 /* create signature */
5811 struct TransportValidationPS tvp =
5812 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5813 .purpose.size = htonl (sizeof (tvp)),
5814 .validity_duration = tvr->validity_duration,
5815 .challenge = tvc->challenge};
5817 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5821 route_message (&cmc->im.sender,
5823 RMO_ANYTHING_GOES | RMO_REDUNDANT);
5824 finish_cmc_handling (cmc);
5829 * Closure for #check_known_challenge.
5831 struct CheckKnownChallengeContext
5834 * Set to the challenge we are looking for.
5836 const struct GNUNET_ShortHashCode *challenge;
5839 * Set to a matching validation state, if one was found.
5841 struct ValidationState *vs;
5846 * Test if the validation state in @a value matches the
5847 * challenge from @a cls.
5849 * @param cls a `struct CheckKnownChallengeContext`
5850 * @param pid unused (must match though)
5851 * @param value a `struct ValidationState`
5852 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5855 check_known_challenge (void *cls,
5856 const struct GNUNET_PeerIdentity *pid,
5859 struct CheckKnownChallengeContext *ckac = cls;
5860 struct ValidationState *vs = value;
5863 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
5871 * Function called when peerstore is done storing a
5872 * validated address.
5874 * @param cls a `struct ValidationState`
5875 * @param success #GNUNET_YES on success
5878 peerstore_store_validation_cb (void *cls, int success)
5880 struct ValidationState *vs = cls;
5883 if (GNUNET_YES == success)
5885 GNUNET_STATISTICS_update (GST_stats,
5886 "# Peerstore failed to store foreign address",
5893 * Task run periodically to validate some address based on #validation_heap.
5898 validation_start_cb (void *cls);
5902 * Set the time for next_challenge of @a vs to @a new_time.
5903 * Updates the heap and if necessary reschedules the job.
5905 * @param vs validation state to update
5906 * @param new_time new time for revalidation
5909 update_next_challenge_time (struct ValidationState *vs,
5910 struct GNUNET_TIME_Absolute new_time)
5912 struct GNUNET_TIME_Relative delta;
5914 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5915 return; /* be lazy */
5916 vs->next_challenge = new_time;
5919 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
5921 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
5922 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5923 (NULL != validation_task))
5925 if (NULL != validation_task)
5926 GNUNET_SCHEDULER_cancel (validation_task);
5927 /* randomize a bit */
5928 delta.rel_value_us =
5929 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5930 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5931 new_time = GNUNET_TIME_absolute_add (new_time, delta);
5933 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
5938 * Find the queue matching @a pid and @a address.
5940 * @param pid peer the queue must go to
5941 * @param address address the queue must use
5942 * @return NULL if no such queue exists
5944 static struct Queue *
5945 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
5947 struct Neighbour *n;
5949 n = GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
5952 for (struct Queue *pos = n->queue_head; NULL != pos;
5953 pos = pos->next_neighbour)
5955 if (0 == strcmp (pos->address, address))
5963 * Task run periodically to check whether the validity of the given queue has
5964 * run its course. If so, finds either another queue to take over, or clears
5965 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
5966 * chance to take over, and if that fails, notifies CORE about the disconnect.
5968 * @param cls a `struct Queue`
5971 core_queue_visibility_check (void *cls)
5973 struct Queue *q = cls;
5975 q->visibility_task = NULL;
5976 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5978 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5979 &core_queue_visibility_check,
5983 update_neighbour_core_visibility (q->neighbour);
5988 * Check whether the CORE visibility of @a n should change. Finds either a
5989 * queue to preserve the visibility, or clears the neighbour's `core_visible`
5990 * flag. In the latter case, gives DV routes a chance to take over, and if
5991 * that fails, notifies CORE about the disconnect. If so, check whether we
5992 * need to notify CORE.
5994 * @param n neighbour to perform the check for
5997 update_neighbour_core_visibility (struct Neighbour *n)
5999 struct DistanceVector *dv;
6001 GNUNET_assert (GNUNET_YES == n->core_visible);
6002 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
6003 the #core_queue_visibility_check() task for that queue */
6004 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6007 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
6009 /* found a valid queue, use this one */
6010 q->visibility_task =
6011 GNUNET_SCHEDULER_add_at (q->validated_until,
6012 &core_queue_visibility_check,
6017 n->core_visible = GNUNET_NO;
6019 /* Check if _any_ DV route to this neighbour is currently
6020 valid, if so, do NOT tell core about the loss of direct
6021 connectivity (DV still counts!) */
6022 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
6023 if (GNUNET_YES == dv->core_visible)
6025 /* Nothing works anymore, need to tell CORE about the loss of
6027 cores_send_disconnect_info (&n->pid);
6032 * Communicator gave us a transport address validation response. Process the
6035 * @param cls a `struct CommunicatorMessageContext` (must call
6036 * #finish_cmc_handling() when done)
6037 * @param tvr the message that was received
6040 handle_validation_response (void *cls,
6041 const struct TransportValidationResponse *tvr)
6043 struct CommunicatorMessageContext *cmc = cls;
6044 struct ValidationState *vs;
6045 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
6047 struct GNUNET_TIME_Absolute origin_time;
6049 struct DistanceVector *dv;
6050 struct Neighbour *n;
6052 /* check this is one of our challenges */
6053 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6055 &check_known_challenge,
6057 if (NULL == (vs = ckac.vs))
6059 /* This can happen simply if we 'forgot' the challenge by now,
6060 i.e. because we received the validation response twice */
6061 GNUNET_STATISTICS_update (GST_stats,
6062 "# Validations dropped, challenge unknown",
6065 finish_cmc_handling (cmc);
6069 /* sanity check on origin time */
6070 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
6071 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
6072 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
6074 GNUNET_break_op (0);
6075 finish_cmc_handling (cmc);
6080 /* check signature */
6081 struct TransportValidationPS tvp =
6082 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
6083 .purpose.size = htonl (sizeof (tvp)),
6084 .validity_duration = tvr->validity_duration,
6085 .challenge = tvr->challenge};
6089 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
6092 &cmc->im.sender.public_key))
6094 GNUNET_break_op (0);
6095 finish_cmc_handling (cmc);
6100 /* validity is capped by our willingness to keep track of the
6101 validation entry and the maximum the other peer allows */
6102 vs->valid_until = GNUNET_TIME_relative_to_absolute (
6103 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
6104 tvr->validity_duration),
6105 MAX_ADDRESS_VALID_UNTIL));
6106 vs->validated_until =
6107 GNUNET_TIME_absolute_min (vs->valid_until,
6108 GNUNET_TIME_relative_to_absolute (
6109 ADDRESS_VALIDATION_LIFETIME));
6110 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
6111 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
6112 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6114 sizeof (vs->challenge));
6115 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
6116 vs->validated_until,
6117 GNUNET_TIME_relative_multiply (vs->validation_rtt,
6118 VALIDATION_RTT_BUFFER_FACTOR));
6119 vs->last_challenge_use =
6120 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
6121 update_next_challenge_time (vs, vs->first_challenge_use);
6122 vs->sc = GNUNET_PEERSTORE_store (peerstore,
6125 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
6127 strlen (vs->address) + 1,
6129 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
6130 &peerstore_store_validation_cb,
6132 finish_cmc_handling (cmc);
6134 /* Finally, we now possibly have a confirmed (!) working queue,
6135 update queue status (if queue still is around) */
6136 q = find_queue (&vs->pid, vs->address);
6139 GNUNET_STATISTICS_update (GST_stats,
6140 "# Queues lost at time of successful validation",
6145 q->validated_until = vs->validated_until;
6146 q->rtt = vs->validation_rtt;
6148 if (GNUNET_NO != n->core_visible)
6149 return; /* nothing changed, we are done here */
6150 n->core_visible = GNUNET_YES;
6151 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
6152 &core_queue_visibility_check,
6154 /* Check if _any_ DV route to this neighbour is
6155 currently valid, if so, do NOT tell core anything! */
6156 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
6157 if ((NULL != dv) && (GNUNET_YES == dv->core_visible))
6158 return; /* nothing changed, done */
6159 /* We lacked a confirmed connection to the neighbour
6160 before, so tell CORE about it (finally!) */
6161 cores_send_connect_info (&n->pid,
6163 ? GNUNET_BANDWIDTH_value_sum (dv->quota_out,
6170 * Incoming meessage. Process the request.
6172 * @param im the send message that was received
6175 handle_incoming_msg (void *cls,
6176 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6178 struct TransportClient *tc = cls;
6179 struct CommunicatorMessageContext *cmc =
6180 GNUNET_new (struct CommunicatorMessageContext);
6184 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
6189 * Given an inbound message @a msg from a communicator @a cmc,
6190 * demultiplex it based on the type calling the right handler.
6192 * @param cmc context for demultiplexing
6193 * @param msg message to demultiplex
6196 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
6197 const struct GNUNET_MessageHeader *msg)
6199 struct GNUNET_MQ_MessageHandler handlers[] =
6200 {GNUNET_MQ_hd_var_size (fragment_box,
6201 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
6202 struct TransportFragmentBox,
6204 GNUNET_MQ_hd_fixed_size (fragment_ack,
6205 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
6206 struct TransportFragmentAckMessage,
6208 GNUNET_MQ_hd_var_size (reliability_box,
6209 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
6210 struct TransportReliabilityBox,
6212 GNUNET_MQ_hd_fixed_size (reliability_ack,
6213 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
6214 struct TransportReliabilityAckMessage,
6216 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
6217 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
6218 struct TransportBackchannelEncapsulationMessage,
6220 GNUNET_MQ_hd_var_size (dv_learn,
6221 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
6222 struct TransportDVLearn,
6224 GNUNET_MQ_hd_var_size (dv_box,
6225 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
6226 struct TransportDVBox,
6228 GNUNET_MQ_hd_fixed_size (
6229 validation_challenge,
6230 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
6231 struct TransportValidationChallenge,
6233 GNUNET_MQ_hd_fixed_size (
6234 validation_response,
6235 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
6236 struct TransportValidationResponse,
6238 GNUNET_MQ_handler_end ()};
6241 ret = GNUNET_MQ_handle_message (handlers, msg);
6242 if (GNUNET_SYSERR == ret)
6245 GNUNET_SERVICE_client_drop (cmc->tc->client);
6249 if (GNUNET_NO == ret)
6251 /* unencapsulated 'raw' message */
6252 handle_raw_message (&cmc, msg);
6258 * New queue became available. Check message.
6260 * @param cls the client
6261 * @param aqm the send message that was sent
6264 check_add_queue_message (void *cls,
6265 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6267 struct TransportClient *tc = cls;
6269 if (CT_COMMUNICATOR != tc->type)
6272 return GNUNET_SYSERR;
6274 GNUNET_MQ_check_zero_termination (aqm);
6280 * Bandwidth tracker informs us that the delay until we should receive
6283 * @param cls a `struct Queue` for which the delay changed
6286 tracker_update_in_cb (void *cls)
6288 struct Queue *queue = cls;
6289 struct GNUNET_TIME_Relative in_delay;
6292 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
6293 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
6294 // FIXME: how exactly do we do inbound flow control?
6299 * If necessary, generates the UUID for a @a pm
6301 * @param pm pending message to generate UUID for.
6304 set_pending_message_uuid (struct PendingMessage *pm)
6306 if (pm->msg_uuid_set)
6308 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6310 sizeof (pm->msg_uuid));
6311 pm->msg_uuid_set = GNUNET_YES;
6316 * Fragment the given @a pm to the given @a mtu. Adds
6317 * additional fragments to the neighbour as well. If the
6318 * @a mtu is too small, generates and error for the @a pm
6321 * @param pm pending message to fragment for transmission
6322 * @param mtu MTU to apply
6323 * @return new message to transmit
6325 static struct PendingMessage *
6326 fragment_message (struct PendingMessage *pm, uint16_t mtu)
6328 struct PendingMessage *ff;
6330 set_pending_message_uuid (pm);
6332 /* This invariant is established in #handle_add_queue_message() */
6333 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
6335 /* select fragment for transmission, descending the tree if it has
6336 been expanded until we are at a leaf or at a fragment that is small enough
6339 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
6340 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
6342 ff = ff->head_frag; /* descent into fragmented fragments */
6345 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
6347 /* Did not yet calculate all fragments, calculate next fragment */
6348 struct PendingMessage *frag;
6349 struct TransportFragmentBox tfb;
6357 orig = (const char *) &ff[1];
6358 msize = ff->bytes_msg;
6361 const struct TransportFragmentBox *tfbo;
6363 tfbo = (const struct TransportFragmentBox *) orig;
6364 orig += sizeof (struct TransportFragmentBox);
6365 msize -= sizeof (struct TransportFragmentBox);
6366 xoff = ntohs (tfbo->frag_off);
6368 fragmax = mtu - sizeof (struct TransportFragmentBox);
6369 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
6370 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
6371 sizeof (struct TransportFragmentBox) + fragsize);
6372 frag->target = pm->target;
6373 frag->frag_parent = ff;
6374 frag->timeout = pm->timeout;
6375 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
6376 frag->pmt = PMT_FRAGMENT_BOX;
6377 msg = (char *) &frag[1];
6378 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
6379 tfb.header.size = htons (sizeof (struct TransportFragmentBox) + fragsize);
6380 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
6381 tfb.msg_uuid = pm->msg_uuid;
6382 tfb.frag_off = htons (ff->frag_off + xoff);
6383 tfb.msg_size = htons (pm->bytes_msg);
6384 memcpy (msg, &tfb, sizeof (tfb));
6385 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
6386 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
6387 ff->frag_off += fragsize;
6391 /* Move head to the tail and return it */
6392 GNUNET_CONTAINER_MDLL_remove (frag,
6393 ff->frag_parent->head_frag,
6394 ff->frag_parent->tail_frag,
6396 GNUNET_CONTAINER_MDLL_insert_tail (frag,
6397 ff->frag_parent->head_frag,
6398 ff->frag_parent->tail_frag,
6405 * Reliability-box the given @a pm. On error (can there be any), NULL
6406 * may be returned, otherwise the "replacement" for @a pm (which
6407 * should then be added to the respective neighbour's queue instead of
6408 * @a pm). If the @a pm is already fragmented or reliability boxed,
6409 * or itself an ACK, this function simply returns @a pm.
6411 * @param pm pending message to box for transmission over unreliabile queue
6412 * @return new message to transmit
6414 static struct PendingMessage *
6415 reliability_box_message (struct PendingMessage *pm)
6417 struct TransportReliabilityBox rbox;
6418 struct PendingMessage *bpm;
6421 if (PMT_CORE != pm->pmt)
6422 return pm; /* already fragmented or reliability boxed, or control message:
6424 if (NULL != pm->bpm)
6425 return pm->bpm; /* already computed earlier: do nothing */
6426 GNUNET_assert (NULL == pm->head_frag);
6427 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
6431 client_send_response (pm, GNUNET_NO, 0);
6434 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
6436 bpm->target = pm->target;
6437 bpm->frag_parent = pm;
6438 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
6439 bpm->timeout = pm->timeout;
6440 bpm->pmt = PMT_RELIABILITY_BOX;
6441 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
6442 set_pending_message_uuid (bpm);
6443 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
6444 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
6445 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
6446 rbox.msg_uuid = pm->msg_uuid;
6447 msg = (char *) &bpm[1];
6448 memcpy (msg, &rbox, sizeof (rbox));
6449 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
6456 * Change the value of the `next_attempt` field of @a pm
6457 * to @a next_attempt and re-order @a pm in the transmission
6458 * list as required by the new timestmap.
6460 * @param pm a pending message to update
6461 * @param next_attempt timestamp to use
6464 update_pm_next_attempt (struct PendingMessage *pm,
6465 struct GNUNET_TIME_Absolute next_attempt)
6467 struct Neighbour *neighbour = pm->target;
6469 pm->next_attempt = next_attempt;
6470 if (NULL == pm->frag_parent)
6472 struct PendingMessage *pos;
6474 /* re-insert sort in neighbour list */
6475 GNUNET_CONTAINER_MDLL_remove (neighbour,
6476 neighbour->pending_msg_head,
6477 neighbour->pending_msg_tail,
6479 pos = neighbour->pending_msg_tail;
6480 while ((NULL != pos) &&
6481 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6482 pos = pos->prev_neighbour;
6483 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
6484 neighbour->pending_msg_head,
6485 neighbour->pending_msg_tail,
6491 /* re-insert sort in fragment list */
6492 struct PendingMessage *fp = pm->frag_parent;
6493 struct PendingMessage *pos;
6495 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
6496 pos = fp->tail_frag;
6497 while ((NULL != pos) &&
6498 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6499 pos = pos->prev_frag;
6500 GNUNET_CONTAINER_MDLL_insert_after (frag,
6510 * We believe we are ready to transmit a message on a queue. Double-checks
6511 * with the queue's "tracker_out" and then gives the message to the
6512 * communicator for transmission (updating the tracker, and re-scheduling
6513 * itself if applicable).
6515 * @param cls the `struct Queue` to process transmissions for
6518 transmit_on_queue (void *cls)
6520 struct Queue *queue = cls;
6521 struct Neighbour *n = queue->neighbour;
6522 struct PendingMessage *pm;
6523 struct PendingMessage *s;
6526 queue->transmit_task = NULL;
6527 if (NULL == (pm = n->pending_msg_head))
6529 /* no message pending, nothing to do here! */
6534 /* message still pending with communciator!
6535 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
6538 schedule_transmit_on_queue (queue, GNUNET_YES);
6539 if (NULL != queue->transmit_task)
6540 return; /* do it later */
6542 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6543 overhead += sizeof (struct TransportReliabilityBox);
6545 if ( ( (0 != queue->mtu) &&
6546 (pm->bytes_msg + overhead > queue->mtu) ) ||
6547 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
6548 (NULL != pm->head_frag /* fragments already exist, should
6549 respect that even if MTU is 0 for
6551 s = fragment_message (s,
6554 sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
6558 /* Fragmentation failed, try next message... */
6559 schedule_transmit_on_queue (queue, GNUNET_NO);
6562 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6563 s = reliability_box_message (s);
6566 /* Reliability boxing failed, try next message... */
6567 schedule_transmit_on_queue (queue, GNUNET_NO);
6571 /* Pass 's' for transission to the communicator */
6572 queue_send_msg (queue, s, &s[1], s->bytes_msg);
6573 // FIXME: do something similar to the logic below
6574 // in defragmentation / reliability ACK handling!
6576 /* Check if this transmission somehow conclusively finished handing 'pm'
6577 even without any explicit ACKs */
6578 if ((PMT_CORE == s->pmt) &&
6579 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
6581 /* Full message sent, and over reliabile channel */
6582 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
6584 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
6585 queue->tc->details.communicator.cc) &&
6586 (PMT_FRAGMENT_BOX == s->pmt))
6588 struct PendingMessage *pos;
6590 /* Fragment sent over reliabile channel */
6591 free_fragment_tree (s);
6592 pos = s->frag_parent;
6593 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6595 /* check if subtree is done */
6596 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6600 pos = s->frag_parent;
6601 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6605 /* Was this the last applicable fragmment? */
6606 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
6607 client_send_response (
6610 pm->bytes_msg /* FIXME: calculate and add overheads! */);
6612 else if (PMT_CORE != pm->pmt)
6614 /* This was an acknowledgement of some type, always free */
6615 free_pending_message (pm);
6619 /* Message not finished, waiting for acknowledgement.
6620 Update time by which we might retransmit 's' based on queue
6621 characteristics (i.e. RTT); it takes one RTT for the message to
6622 arrive and the ACK to come back in the best case; but the other
6623 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
6624 retransmitting. Note that in the future this heuristic should
6625 likely be improved further (measure RTT stability, consider
6626 message urgency and size when delaying ACKs, etc.) */
6627 update_pm_next_attempt (s,
6628 GNUNET_TIME_relative_to_absolute (
6629 GNUNET_TIME_relative_multiply (queue->rtt, 4)));
6632 /* finally, re-schedule queue transmission task itself */
6633 schedule_transmit_on_queue (queue, GNUNET_NO);
6638 * Bandwidth tracker informs us that the delay until we
6639 * can transmit again changed.
6641 * @param cls a `struct Queue` for which the delay changed
6644 tracker_update_out_cb (void *cls)
6646 struct Queue *queue = cls;
6647 struct Neighbour *n = queue->neighbour;
6649 if (NULL == n->pending_msg_head)
6651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6652 "Bandwidth allocation updated for empty transmission queue `%s'\n",
6654 return; /* no message pending, nothing to do here! */
6656 GNUNET_SCHEDULER_cancel (queue->transmit_task);
6657 queue->transmit_task = NULL;
6658 schedule_transmit_on_queue (queue, GNUNET_NO);
6663 * Bandwidth tracker informs us that excessive outbound bandwidth was
6664 * allocated which is not being used.
6666 * @param cls a `struct Queue` for which the excess was noted
6669 tracker_excess_out_cb (void *cls)
6673 /* FIXME: trigger excess bandwidth report to core? Right now,
6674 this is done internally within transport_api2_core already,
6675 but we probably want to change the logic and trigger it
6676 from here via a message instead! */
6677 /* TODO: maybe inform someone at this point? */
6678 GNUNET_STATISTICS_update (GST_stats,
6679 "# Excess outbound bandwidth reported",
6686 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
6687 * which is not being used.
6689 * @param cls a `struct Queue` for which the excess was noted
6692 tracker_excess_in_cb (void *cls)
6696 /* TODO: maybe inform somone at this point? */
6697 GNUNET_STATISTICS_update (GST_stats,
6698 "# Excess inbound bandwidth reported",
6705 * Queue to a peer went down. Process the request.
6707 * @param cls the client
6708 * @param dqm the send message that was sent
6711 handle_del_queue_message (void *cls,
6712 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
6714 struct TransportClient *tc = cls;
6716 if (CT_COMMUNICATOR != tc->type)
6719 GNUNET_SERVICE_client_drop (tc->client);
6722 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6723 queue = queue->next_client)
6725 struct Neighbour *neighbour = queue->neighbour;
6727 if ((dqm->qid != queue->qid) ||
6728 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
6731 GNUNET_SERVICE_client_continue (tc->client);
6735 GNUNET_SERVICE_client_drop (tc->client);
6740 * Message was transmitted. Process the request.
6742 * @param cls the client
6743 * @param sma the send message that was sent
6746 handle_send_message_ack (void *cls,
6747 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
6749 struct TransportClient *tc = cls;
6750 struct QueueEntry *qe;
6751 struct PendingMessage *pm;
6753 if (CT_COMMUNICATOR != tc->type)
6756 GNUNET_SERVICE_client_drop (tc->client);
6760 /* find our queue entry matching the ACK */
6762 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6763 queue = queue->next_client)
6765 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
6767 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
6770 if (qep->mid != sma->mid)
6779 /* this should never happen */
6781 GNUNET_SERVICE_client_drop (tc->client);
6784 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6785 qe->queue->queue_tail,
6787 qe->queue->queue_length--;
6788 tc->details.communicator.total_queue_length--;
6789 GNUNET_SERVICE_client_continue (tc->client);
6791 /* if applicable, resume transmissions that waited on ACK */
6792 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
6793 tc->details.communicator.total_queue_length)
6795 /* Communicator dropped below threshold, resume all queues
6796 incident with this client! */
6797 GNUNET_STATISTICS_update (
6799 "# Transmission throttled due to communicator queue limit",
6802 for (struct Queue *queue = tc->details.communicator.queue_head;
6804 queue = queue->next_client)
6805 schedule_transmit_on_queue (queue, GNUNET_NO);
6807 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6809 /* queue dropped below threshold; only resume this one queue */
6810 GNUNET_STATISTICS_update (GST_stats,
6811 "# Transmission throttled due to queue queue limit",
6814 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
6817 if (NULL != (pm = qe->pm))
6819 struct Neighbour *n;
6821 GNUNET_assert (qe == pm->qe);
6823 /* If waiting for this communicator may have blocked transmission
6824 of pm on other queues for this neighbour, force schedule
6825 transmit on queue for queues of the neighbour */
6827 if (n->pending_msg_head == pm)
6829 for (struct Queue *queue = n->queue_head; NULL != queue;
6830 queue = queue->next_neighbour)
6831 schedule_transmit_on_queue (queue, GNUNET_NO);
6833 if (GNUNET_OK != ntohl (sma->status))
6836 GNUNET_ERROR_TYPE_INFO,
6837 "Queue failed in transmission, will try retransmission immediately\n");
6838 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
6846 * Iterator telling new MONITOR client about all existing
6849 * @param cls the new `struct TransportClient`
6850 * @param pid a connected peer
6851 * @param value the `struct Neighbour` with more information
6852 * @return #GNUNET_OK (continue to iterate)
6855 notify_client_queues (void *cls,
6856 const struct GNUNET_PeerIdentity *pid,
6859 struct TransportClient *tc = cls;
6860 struct Neighbour *neighbour = value;
6862 GNUNET_assert (CT_MONITOR == tc->type);
6863 for (struct Queue *q = neighbour->queue_head; NULL != q;
6864 q = q->next_neighbour)
6866 struct MonitorEvent me = {.rtt = q->rtt,
6868 .num_msg_pending = q->num_msg_pending,
6869 .num_bytes_pending = q->num_bytes_pending};
6871 notify_monitor (tc, pid, q->address, q->nt, &me);
6878 * Initialize a monitor client.
6880 * @param cls the client
6881 * @param start the start message that was sent
6884 handle_monitor_start (void *cls,
6885 const struct GNUNET_TRANSPORT_MonitorStart *start)
6887 struct TransportClient *tc = cls;
6889 if (CT_NONE != tc->type)
6892 GNUNET_SERVICE_client_drop (tc->client);
6895 tc->type = CT_MONITOR;
6896 tc->details.monitor.peer = start->peer;
6897 tc->details.monitor.one_shot = ntohl (start->one_shot);
6898 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
6899 GNUNET_SERVICE_client_mark_monitor (tc->client);
6900 GNUNET_SERVICE_client_continue (tc->client);
6905 * Find transport client providing communication service
6906 * for the protocol @a prefix.
6908 * @param prefix communicator name
6909 * @return NULL if no such transport client is available
6911 static struct TransportClient *
6912 lookup_communicator (const char *prefix)
6914 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6916 if (CT_COMMUNICATOR != tc->type)
6918 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
6922 GNUNET_ERROR_TYPE_WARNING,
6923 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6930 * Signature of a function called with a communicator @a address of a peer
6931 * @a pid that an application wants us to connect to.
6933 * @param pid target peer
6934 * @param address the address to try
6937 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
6939 static uint32_t idgen;
6940 struct TransportClient *tc;
6942 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6943 struct GNUNET_MQ_Envelope *env;
6946 prefix = GNUNET_HELLO_address_to_prefix (address);
6949 GNUNET_break (0); /* We got an invalid address!? */
6952 tc = lookup_communicator (prefix);
6955 GNUNET_STATISTICS_update (GST_stats,
6956 "# Suggestions ignored due to missing communicator",
6961 /* forward suggestion for queue creation to communicator */
6962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6963 "Request #%u for `%s' communicator to create queue to `%s'\n",
6964 (unsigned int) idgen,
6967 alen = strlen (address) + 1;
6969 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6970 cqm->request_id = htonl (idgen++);
6971 cqm->receiver = *pid;
6972 memcpy (&cqm[1], address, alen);
6973 GNUNET_MQ_send (tc->mq, env);
6978 * The queue @a q (which matches the peer and address in @a vs) is
6979 * ready for queueing. We should now queue the validation request.
6981 * @param q queue to send on
6982 * @param vs state to derive validation challenge from
6985 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
6987 struct TransportValidationChallenge tvc;
6989 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6991 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6992 tvc.header.size = htons (sizeof (tvc));
6993 tvc.reserved = htonl (0);
6994 tvc.challenge = vs->challenge;
6995 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6996 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
7001 * Task run periodically to validate some address based on #validation_heap.
7006 validation_start_cb (void *cls)
7008 struct ValidationState *vs;
7012 validation_task = NULL;
7013 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7014 /* drop validations past their expiration */
7017 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
7019 free_validation_state (vs);
7020 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
7023 return; /* woopsie, no more addresses known, should only
7024 happen if we're really a lonely peer */
7025 q = find_queue (&vs->pid, vs->address);
7028 vs->awaiting_queue = GNUNET_YES;
7029 suggest_to_connect (&vs->pid, vs->address);
7032 validation_transmit_on_queue (q, vs);
7033 /* Finally, reschedule next attempt */
7034 vs->challenge_backoff =
7035 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
7036 MAX_VALIDATION_CHALLENGE_FREQ);
7037 update_next_challenge_time (vs,
7038 GNUNET_TIME_relative_to_absolute (
7039 vs->challenge_backoff));
7044 * Closure for #check_connection_quality.
7046 struct QueueQualityContext
7049 * Set to the @e k'th queue encountered.
7054 * Set to the number of quality queues encountered.
7056 unsigned int quality_count;
7059 * Set to the total number of queues encountered.
7061 unsigned int num_queues;
7064 * Decremented for each queue, for selection of the
7065 * k-th queue in @e q.
7072 * Check whether any queue to the given neighbour is
7073 * of a good "quality" and if so, increment the counter.
7074 * Also counts the total number of queues, and returns
7075 * the k-th queue found.
7077 * @param cls a `struct QueueQualityContext *` with counters
7078 * @param pid peer this is about
7079 * @param value a `struct Neighbour`
7080 * @return #GNUNET_OK (continue to iterate)
7083 check_connection_quality (void *cls,
7084 const struct GNUNET_PeerIdentity *pid,
7087 struct QueueQualityContext *ctx = cls;
7088 struct Neighbour *n = value;
7093 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7098 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
7099 statistics and consider those as well here? */
7100 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
7101 do_inc = GNUNET_YES;
7103 if (GNUNET_YES == do_inc)
7104 ctx->quality_count++;
7110 * Task run when we CONSIDER initiating a DV learn
7111 * process. We first check that sending out a message is
7112 * even possible (queues exist), then that it is desirable
7113 * (if not, reschedule the task for later), and finally
7114 * we may then begin the job. If there are too many
7115 * entries in the #dvlearn_map, we purge the oldest entry
7121 start_dv_learn (void *cls)
7123 struct LearnLaunchEntry *lle;
7124 struct QueueQualityContext qqc;
7125 struct TransportDVLearn dvl;
7128 dvlearn_task = NULL;
7129 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
7130 return; /* lost all connectivity, cannot do learning */
7131 qqc.quality_count = 0;
7133 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7134 &check_connection_quality,
7136 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
7138 struct GNUNET_TIME_Relative delay;
7139 unsigned int factor;
7141 /* scale our retries by how far we are above the threshold */
7142 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
7143 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
7144 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
7147 /* remove old entries in #dvlearn_map if it has grown too big */
7148 while (MAX_DV_LEARN_PENDING >=
7149 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
7152 GNUNET_assert (GNUNET_YES ==
7153 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
7156 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7159 /* setup data structure for learning */
7160 lle = GNUNET_new (struct LearnLaunchEntry);
7161 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7163 sizeof (lle->challenge));
7164 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
7165 GNUNET_break (GNUNET_YES ==
7166 GNUNET_CONTAINER_multishortmap_put (
7170 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7171 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
7172 dvl.header.size = htons (sizeof (dvl));
7173 dvl.num_hops = htons (0);
7174 dvl.bidirectional = htons (0);
7175 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
7177 struct DvInitPS dvip = {.purpose.purpose = htonl (
7178 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
7179 .purpose.size = htonl (sizeof (dvip)),
7180 .challenge = lle->challenge};
7182 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7186 dvl.initiator = GST_my_identity;
7187 dvl.challenge = lle->challenge;
7189 qqc.quality_count = 0;
7190 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
7193 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7194 &check_connection_quality,
7196 GNUNET_assert (NULL != qqc.q);
7198 /* Do this as close to transmission time as possible! */
7199 lle->launch_time = GNUNET_TIME_absolute_get ();
7201 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
7202 /* reschedule this job, randomizing the time it runs (but no
7204 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
7205 DV_LEARN_BASE_FREQUENCY),
7212 * A new queue has been created, check if any address validation
7213 * requests have been waiting for it.
7215 * @param cls a `struct Queue`
7216 * @param pid peer concerned (unused)
7217 * @param value a `struct ValidationState`
7218 * @return #GNUNET_NO if a match was found and we can stop looking
7221 check_validation_request_pending (void *cls,
7222 const struct GNUNET_PeerIdentity *pid,
7225 struct Queue *q = cls;
7226 struct ValidationState *vs = value;
7229 if ((GNUNET_YES == vs->awaiting_queue) &&
7230 (0 == strcmp (vs->address, q->address)))
7232 vs->awaiting_queue = GNUNET_NO;
7233 validation_transmit_on_queue (q, vs);
7241 * New queue became available. Process the request.
7243 * @param cls the client
7244 * @param aqm the send message that was sent
7247 handle_add_queue_message (void *cls,
7248 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7250 struct TransportClient *tc = cls;
7251 struct Queue *queue;
7252 struct Neighbour *neighbour;
7256 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
7258 /* MTU so small as to be useless for transmissions,
7259 required for #fragment_message()! */
7260 GNUNET_break_op (0);
7261 GNUNET_SERVICE_client_drop (tc->client);
7264 neighbour = lookup_neighbour (&aqm->receiver);
7265 if (NULL == neighbour)
7267 neighbour = GNUNET_new (struct Neighbour);
7268 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
7269 neighbour->pid = aqm->receiver;
7270 GNUNET_assert (GNUNET_OK ==
7271 GNUNET_CONTAINER_multipeermap_put (
7275 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7277 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
7278 addr = (const char *) &aqm[1];
7280 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
7282 queue->address = (const char *) &queue[1];
7283 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7284 queue->qid = aqm->qid;
7285 queue->mtu = ntohl (aqm->mtu);
7286 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
7287 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
7288 queue->neighbour = neighbour;
7289 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
7290 &tracker_update_in_cb,
7292 GNUNET_BANDWIDTH_ZERO,
7293 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
7294 &tracker_excess_in_cb,
7296 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
7297 &tracker_update_out_cb,
7299 GNUNET_BANDWIDTH_ZERO,
7300 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
7301 &tracker_excess_out_cb,
7303 memcpy (&queue[1], addr, addr_len);
7304 /* notify monitors about new queue */
7306 struct MonitorEvent me = {.rtt = queue->rtt, .cs = queue->cs};
7308 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
7310 GNUNET_CONTAINER_MDLL_insert (neighbour,
7311 neighbour->queue_head,
7312 neighbour->queue_tail,
7314 GNUNET_CONTAINER_MDLL_insert (client,
7315 tc->details.communicator.queue_head,
7316 tc->details.communicator.queue_tail,
7318 /* check if valdiations are waiting for the queue */
7320 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7322 &check_validation_request_pending,
7324 /* might be our first queue, try launching DV learning */
7325 if (NULL == dvlearn_task)
7326 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
7327 GNUNET_SERVICE_client_continue (tc->client);
7332 * Communicator tells us that our request to create a queue "worked", that
7333 * is setting up the queue is now in process.
7335 * @param cls the `struct TransportClient`
7336 * @param cqr confirmation message
7339 handle_queue_create_ok (void *cls,
7340 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
7342 struct TransportClient *tc = cls;
7344 if (CT_COMMUNICATOR != tc->type)
7347 GNUNET_SERVICE_client_drop (tc->client);
7350 GNUNET_STATISTICS_update (GST_stats,
7351 "# Suggestions succeeded at communicator",
7354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7355 "Request #%u for communicator to create queue succeeded\n",
7356 (unsigned int) ntohs (cqr->request_id));
7357 GNUNET_SERVICE_client_continue (tc->client);
7362 * Communicator tells us that our request to create a queue failed. This usually
7363 * indicates that the provided address is simply invalid or that the
7364 * communicator's resources are exhausted.
7366 * @param cls the `struct TransportClient`
7367 * @param cqr failure message
7370 handle_queue_create_fail (
7372 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
7374 struct TransportClient *tc = cls;
7376 if (CT_COMMUNICATOR != tc->type)
7379 GNUNET_SERVICE_client_drop (tc->client);
7382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7383 "Request #%u for communicator to create queue failed\n",
7384 (unsigned int) ntohs (cqr->request_id));
7385 GNUNET_STATISTICS_update (GST_stats,
7386 "# Suggestions failed in queue creation at communicator",
7389 GNUNET_SERVICE_client_continue (tc->client);
7394 * We have received a `struct ExpressPreferenceMessage` from an application
7397 * @param cls handle to the client
7398 * @param msg the start message
7401 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
7403 struct TransportClient *tc = cls;
7404 struct PeerRequest *pr;
7406 if (CT_APPLICATION != tc->type)
7409 GNUNET_SERVICE_client_drop (tc->client);
7412 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
7417 GNUNET_SERVICE_client_drop (tc->client);
7420 (void) stop_peer_request (tc, &pr->pid, pr);
7421 GNUNET_SERVICE_client_continue (tc->client);
7426 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
7427 * messages. We do nothing here, real verification is done later.
7429 * @param cls a `struct TransportClient *`
7430 * @param msg message to verify
7431 * @return #GNUNET_OK
7434 check_address_consider_verify (
7436 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7445 * Closure for #check_known_address.
7447 struct CheckKnownAddressContext
7450 * Set to the address we are looking for.
7452 const char *address;
7455 * Set to a matching validation state, if one was found.
7457 struct ValidationState *vs;
7462 * Test if the validation state in @a value matches the
7463 * address from @a cls.
7465 * @param cls a `struct CheckKnownAddressContext`
7466 * @param pid unused (must match though)
7467 * @param value a `struct ValidationState`
7468 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7471 check_known_address (void *cls,
7472 const struct GNUNET_PeerIdentity *pid,
7475 struct CheckKnownAddressContext *ckac = cls;
7476 struct ValidationState *vs = value;
7479 if (0 != strcmp (vs->address, ckac->address))
7487 * Start address validation.
7489 * @param pid peer the @a address is for
7490 * @param address an address to reach @a pid (presumably)
7491 * @param expiration when did @a pid claim @a address will become invalid
7494 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7495 const char *address,
7496 struct GNUNET_TIME_Absolute expiration)
7498 struct GNUNET_TIME_Absolute now;
7499 struct ValidationState *vs;
7500 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7502 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
7503 return; /* expired */
7504 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7506 &check_known_address,
7508 if (NULL != (vs = ckac.vs))
7510 /* if 'vs' is not currently valid, we need to speed up retrying the
7512 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7514 /* reduce backoff as we got a fresh advertisement */
7515 vs->challenge_backoff =
7516 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7517 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7519 update_next_challenge_time (vs,
7520 GNUNET_TIME_relative_to_absolute (
7521 vs->challenge_backoff));
7525 now = GNUNET_TIME_absolute_get ();
7526 vs = GNUNET_new (struct ValidationState);
7528 vs->valid_until = expiration;
7529 vs->first_challenge_use = now;
7530 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7531 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7533 sizeof (vs->challenge));
7534 vs->address = GNUNET_strdup (address);
7535 GNUNET_assert (GNUNET_YES ==
7536 GNUNET_CONTAINER_multipeermap_put (
7540 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7541 update_next_challenge_time (vs, now);
7546 * Function called by PEERSTORE for each matching record.
7548 * @param cls closure
7549 * @param record peerstore record information
7550 * @param emsg error message, or NULL if no errors
7553 handle_hello (void *cls,
7554 const struct GNUNET_PEERSTORE_Record *record,
7557 struct PeerRequest *pr = cls;
7562 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7563 "Got failure from PEERSTORE: %s\n",
7567 val = record->value;
7568 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7573 start_address_validation (&pr->pid,
7574 (const char *) record->value,
7580 * We have received a `struct ExpressPreferenceMessage` from an application
7583 * @param cls handle to the client
7584 * @param msg the start message
7587 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
7589 struct TransportClient *tc = cls;
7590 struct PeerRequest *pr;
7592 if (CT_NONE == tc->type)
7594 tc->type = CT_APPLICATION;
7595 tc->details.application.requests =
7596 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
7598 if (CT_APPLICATION != tc->type)
7601 GNUNET_SERVICE_client_drop (tc->client);
7604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7605 "Client suggested we talk to %s with preference %d at rate %u\n",
7606 GNUNET_i2s (&msg->peer),
7607 (int) ntohl (msg->pk),
7608 (int) ntohl (msg->bw.value__));
7609 pr = GNUNET_new (struct PeerRequest);
7611 pr->pid = msg->peer;
7613 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
7614 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
7615 tc->details.application.requests,
7618 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
7622 GNUNET_SERVICE_client_drop (tc->client);
7625 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
7628 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7631 GNUNET_SERVICE_client_continue (tc->client);
7636 * Given another peers address, consider checking it for validity
7637 * and then adding it to the Peerstore.
7639 * @param cls a `struct TransportClient`
7640 * @param hdr message containing the raw address data and
7641 * signature in the body, see #GNUNET_HELLO_extract_address()
7644 handle_address_consider_verify (
7646 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7648 struct TransportClient *tc = cls;
7650 enum GNUNET_NetworkType nt;
7651 struct GNUNET_TIME_Absolute expiration;
7654 // OPTIMIZE-FIXME: checking that we know this address already should
7655 // be done BEFORE checking the signature => HELLO API change!
7656 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
7658 GNUNET_HELLO_extract_address (&hdr[1],
7659 ntohs (hdr->header.size) - sizeof (*hdr),
7663 if (NULL == address)
7665 GNUNET_break_op (0);
7668 start_address_validation (&hdr->peer, address, expiration);
7669 GNUNET_free (address);
7670 GNUNET_SERVICE_client_continue (tc->client);
7675 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
7678 * @param cls a `struct TransportClient *`
7679 * @param m message to verify
7680 * @return #GNUNET_OK on success
7683 check_request_hello_validation (void *cls,
7684 const struct RequestHelloValidationMessage *m)
7687 GNUNET_MQ_check_zero_termination (m);
7693 * A client encountered an address of another peer. Consider validating it,
7694 * and if validation succeeds, persist it to PEERSTORE.
7696 * @param cls a `struct TransportClient *`
7697 * @param m message to verify
7700 handle_request_hello_validation (void *cls,
7701 const struct RequestHelloValidationMessage *m)
7703 struct TransportClient *tc = cls;
7705 start_address_validation (&m->peer,
7706 (const char *) &m[1],
7707 GNUNET_TIME_absolute_ntoh (m->expiration));
7708 GNUNET_SERVICE_client_continue (tc->client);
7713 * Free neighbour entry.
7717 * @param value a `struct Neighbour`
7718 * @return #GNUNET_OK (always)
7721 free_neighbour_cb (void *cls,
7722 const struct GNUNET_PeerIdentity *pid,
7725 struct Neighbour *neighbour = value;
7729 GNUNET_break (0); // should this ever happen?
7730 free_neighbour (neighbour);
7737 * Free DV route entry.
7741 * @param value a `struct DistanceVector`
7742 * @return #GNUNET_OK (always)
7745 free_dv_routes_cb (void *cls,
7746 const struct GNUNET_PeerIdentity *pid,
7749 struct DistanceVector *dv = value;
7760 * Free ephemeral entry.
7764 * @param value a `struct EphemeralCacheEntry`
7765 * @return #GNUNET_OK (always)
7768 free_ephemeral_cb (void *cls,
7769 const struct GNUNET_PeerIdentity *pid,
7772 struct EphemeralCacheEntry *ece = value;
7776 free_ephemeral (ece);
7782 * Free validation state.
7786 * @param value a `struct ValidationState`
7787 * @return #GNUNET_OK (always)
7790 free_validation_state_cb (void *cls,
7791 const struct GNUNET_PeerIdentity *pid,
7794 struct ValidationState *vs = value;
7798 free_validation_state (vs);
7804 * Function called when the service shuts down. Unloads our plugins
7805 * and cancels pending validations.
7807 * @param cls closure, unused
7810 do_shutdown (void *cls)
7812 struct LearnLaunchEntry *lle;
7815 if (NULL != ephemeral_task)
7817 GNUNET_SCHEDULER_cancel (ephemeral_task);
7818 ephemeral_task = NULL;
7820 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
7821 if (NULL != peerstore)
7823 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
7826 if (NULL != GST_stats)
7828 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
7831 if (NULL != GST_my_private_key)
7833 GNUNET_free (GST_my_private_key);
7834 GST_my_private_key = NULL;
7836 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7838 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
7839 &free_backtalker_cb,
7841 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
7843 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7844 &free_validation_state_cb,
7846 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7847 validation_map = NULL;
7848 while (NULL != (lle = lle_head))
7850 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7853 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7855 GNUNET_CONTAINER_heap_destroy (validation_heap);
7856 validation_heap = NULL;
7857 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
7858 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7860 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7863 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7864 ephemeral_map = NULL;
7865 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7866 ephemeral_heap = NULL;
7871 * Initiate transport service.
7873 * @param cls closure
7874 * @param c configuration to use
7875 * @param service the initialized service
7879 const struct GNUNET_CONFIGURATION_Handle *c,
7880 struct GNUNET_SERVICE_Handle *service)
7886 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
7887 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7888 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7889 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
7891 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7892 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7894 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7896 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7897 GST_my_private_key =
7898 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7899 if (NULL == GST_my_private_key)
7902 GNUNET_ERROR_TYPE_ERROR,
7904 "Transport service is lacking key configuration settings. Exiting.\n"));
7905 GNUNET_SCHEDULER_shutdown ();
7908 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7909 &GST_my_identity.public_key);
7910 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7911 "My identity is `%s'\n",
7912 GNUNET_i2s_full (&GST_my_identity));
7913 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
7914 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
7915 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7916 if (NULL == peerstore)
7919 GNUNET_SCHEDULER_shutdown ();
7926 * Define "main" method using service macro.
7928 GNUNET_SERVICE_MAIN (
7930 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7933 &client_disconnect_cb,
7935 /* communication with applications */
7936 GNUNET_MQ_hd_fixed_size (suggest,
7937 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7938 struct ExpressPreferenceMessage,
7940 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7941 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7942 struct ExpressPreferenceMessage,
7944 GNUNET_MQ_hd_var_size (request_hello_validation,
7945 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7946 struct RequestHelloValidationMessage,
7948 /* communication with core */
7949 GNUNET_MQ_hd_fixed_size (client_start,
7950 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7951 struct StartMessage,
7953 GNUNET_MQ_hd_var_size (client_send,
7954 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7955 struct OutboundMessage,
7957 /* communication with communicators */
7958 GNUNET_MQ_hd_var_size (communicator_available,
7959 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7960 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7962 GNUNET_MQ_hd_var_size (communicator_backchannel,
7963 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7964 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7966 GNUNET_MQ_hd_var_size (add_address,
7967 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7968 struct GNUNET_TRANSPORT_AddAddressMessage,
7970 GNUNET_MQ_hd_fixed_size (del_address,
7971 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7972 struct GNUNET_TRANSPORT_DelAddressMessage,
7974 GNUNET_MQ_hd_var_size (incoming_msg,
7975 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7976 struct GNUNET_TRANSPORT_IncomingMessage,
7978 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7979 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7980 struct GNUNET_TRANSPORT_CreateQueueResponse,
7982 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7983 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7984 struct GNUNET_TRANSPORT_CreateQueueResponse,
7986 GNUNET_MQ_hd_var_size (add_queue_message,
7987 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7988 struct GNUNET_TRANSPORT_AddQueueMessage,
7990 GNUNET_MQ_hd_var_size (address_consider_verify,
7991 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7992 struct GNUNET_TRANSPORT_AddressToVerify,
7994 GNUNET_MQ_hd_fixed_size (del_queue_message,
7995 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7996 struct GNUNET_TRANSPORT_DelQueueMessage,
7998 GNUNET_MQ_hd_fixed_size (send_message_ack,
7999 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
8000 struct GNUNET_TRANSPORT_SendMessageToAck,
8002 /* communication with monitors */
8003 GNUNET_MQ_hd_fixed_size (monitor_start,
8004 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
8005 struct GNUNET_TRANSPORT_MonitorStart,
8007 GNUNET_MQ_handler_end ());
8010 /* end of file gnunet-service-transport.c */