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 * - retransmission logic
28 * - track RTT, distance, loss, etc. => requires extra data structures!
31 * - change transport-core API to provide proper flow control in both
32 * directions, allow multiple messages per peer simultaneously (tag
33 * confirmations with unique message ID), and replace quota-out with
34 * proper flow control;
35 * - if messages are below MTU, consider adding ACKs and other stuff
36 * (requires planning at receiver, and additional MST-style demultiplex
38 * - could avoid copying body of message into each fragment and keep
39 * fragments as just pointers into the original message and only
40 * fully build fragments just before transmission (optimization, should
41 * reduce CPU and memory use)
42 * - When we passively learned DV (with unconfirmed freshness), we
43 * right now add the path to our list but with a zero path_valid_until
44 * time and only use it for unconfirmed routes. However, we could consider
45 * triggering an explicit validation mechansim ourselves, specifically routing
46 * a challenge-response message over the path (OPTIMIZATION-FIXME).
48 * FIXME (without marks in the code!):
49 * - proper use/initialization of timestamps in messages exchanged
51 * - persistence of monotonic time obtained from other peers
52 * in PEERSTORE (by message type)
55 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
56 * against our pending message queue (requires additional per neighbour
57 * hash map to be maintained, avoids possible linear scan on pending msgs)
58 * - queue_send_msg and route_message both by API design have to make copies
59 * of the payload, and route_message on top of that requires a malloc/free.
60 * Change design to approximate "zero" copy better...
62 * Design realizations / discussion:
63 * - communicators do flow control by calling MQ "notify sent"
64 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
65 * or explicitly via backchannel FC ACKs. As long as the
66 * channel is not full, they may 'notify sent' even if the other
67 * peer has not yet confirmed receipt. The other peer confirming
68 * is _only_ for FC, not for more reliable transmission; reliable
69 * transmission (i.e. of fragments) is left to _transport_.
70 * - ACKs sent back in uni-directional communicators are done via
71 * the background channel API; here transport _may_ initially
72 * broadcast (with bounded # hops) if no path is known;
73 * - transport should _integrate_ DV-routing and build a view of
74 * the network; then background channel traffic can be
75 * routed via DV as well as explicit "DV" traffic.
76 * - background channel is also used for ACKs and NAT traversal support
77 * - transport service is responsible for AEAD'ing the background
78 * channel, timestamps and monotonic time are used against replay
79 * of old messages -> peerstore needs to be supplied with
80 * "latest timestamps seen" data
81 * - if transport implements DV, we likely need a 3rd peermap
82 * in addition to ephemerals and (direct) neighbours
83 * ==> check if stuff needs to be moved out of "Neighbour"
84 * - transport should encapsualte core-level messages and do its
85 * own ACKing for RTT/goodput/loss measurements _and_ fragment
89 #include "gnunet_util_lib.h"
90 #include "gnunet_statistics_service.h"
91 #include "gnunet_transport_monitor_service.h"
92 #include "gnunet_peerstore_service.h"
93 #include "gnunet_hello_lib.h"
94 #include "gnunet_signatures.h"
95 #include "transport.h"
99 * What is the size we assume for a read operation in the
100 * absence of an MTU for the purpose of flow control?
102 #define IN_PACKET_SIZE_WITHOUT_MTU 128
105 * Minimum number of hops we should forward DV learn messages
106 * even if they are NOT useful for us in hope of looping
107 * back to the initiator?
109 * FIXME: allow initiator some control here instead?
111 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
114 * Maximum DV distance allowed ever.
116 #define MAX_DV_HOPS_ALLOWED 16
119 * Maximum number of DV learning activities we may
120 * have pending at the same time.
122 #define MAX_DV_LEARN_PENDING 64
125 * Maximum number of DV paths we keep simultaneously to the same target.
127 #define MAX_DV_PATHS_TO_TARGET 3
130 * If a queue delays the next message by more than this number
131 * of seconds we log a warning. Note: this is for testing,
132 * the value chosen here might be too aggressively low!
134 #define DELAY_WARN_THRESHOLD \
135 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
138 * We only consider queues as "quality" connections when
139 * suppressing the generation of DV initiation messages if
140 * the latency of the queue is below this threshold.
142 #define DV_QUALITY_RTT_THRESHOLD \
143 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
146 * How long do we consider a DV path valid if we see no
147 * further updates on it? Note: the value chosen here might be too low!
149 #define DV_PATH_VALIDITY_TIMEOUT \
150 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
153 * How long before paths expire would we like to (re)discover DV paths? Should
154 * be below #DV_PATH_VALIDITY_TIMEOUT.
156 #define DV_PATH_DISCOVERY_FREQUENCY \
157 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
160 * How long are ephemeral keys valid?
162 #define EPHEMERAL_VALIDITY \
163 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
166 * How long do we keep partially reassembled messages around before giving up?
168 #define REASSEMBLY_EXPIRATION \
169 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
172 * What is the fastest rate at which we send challenges *if* we keep learning
173 * an address (gossip, DHT, etc.)?
175 #define FAST_VALIDATION_CHALLENGE_FREQ \
176 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
179 * What is the slowest rate at which we send challenges?
181 #define MAX_VALIDATION_CHALLENGE_FREQ \
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
185 * What is the non-randomized base frequency at which we
186 * would initiate DV learn messages?
188 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
191 * How many good connections (confirmed, bi-directional, not DV)
192 * do we need to have to suppress initiating DV learn messages?
194 #define DV_LEARN_QUALITY_THRESHOLD 100
197 * When do we forget an invalid address for sure?
199 #define MAX_ADDRESS_VALID_UNTIL \
200 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
203 * How long do we consider an address valid if we just checked?
205 #define ADDRESS_VALIDATION_LIFETIME \
206 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
209 * What is the maximum frequency at which we do address validation?
210 * A random value between 0 and this value is added when scheduling
211 * the #validation_task (both to ensure we do not validate too often,
212 * and to randomize a bit).
214 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
217 * How many network RTTs before an address validation expires should we begin
218 * trying to revalidate? (Note that the RTT used here is the one that we
219 * experienced during the last validation, not necessarily the latest RTT
222 #define VALIDATION_RTT_BUFFER_FACTOR 3
225 * How many messages can we have pending for a given communicator
226 * process before we start to throttle that communicator?
228 * Used if a communicator might be CPU-bound and cannot handle the traffic.
230 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
233 * How many messages can we have pending for a given queue (queue to
234 * a particular peer via a communicator) process before we start to
235 * throttle that queue?
237 #define QUEUE_LENGTH_LIMIT 32
240 GNUNET_NETWORK_STRUCT_BEGIN
243 * Outer layer of an encapsulated backchannel message.
245 struct TransportBackchannelEncapsulationMessage
248 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
250 struct GNUNET_MessageHeader header;
253 * Distance the backchannel message has traveled, to be updated at
254 * each hop. Used to bound the number of hops in case a backchannel
255 * message is broadcast and thus travels without routing
256 * information (during initial backchannel discovery).
261 * Target's peer identity (as backchannels may be transmitted
262 * indirectly, or even be broadcast).
264 struct GNUNET_PeerIdentity target;
267 * Ephemeral key setup by the sender for @e target, used
268 * to encrypt the payload.
270 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
273 * We use an IV here as the @e ephemeral_key is re-used for
274 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
276 struct GNUNET_ShortHashCode iv;
279 * HMAC over the ciphertext of the encrypted, variable-size
280 * body that follows. Verified via DH of @e target and
283 struct GNUNET_HashCode hmac;
285 /* Followed by encrypted, variable-size payload */
290 * Body by which a peer confirms that it is using an ephemeral key.
292 struct EphemeralConfirmation
296 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
298 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
301 * How long is this signature over the ephemeral key valid?
303 * Note that the receiver MUST IGNORE the absolute time, and only interpret
304 * the value as a mononic time and reject "older" values than the last one
305 * observed. This is necessary as we do not want to require synchronized
306 * clocks and may not have a bidirectional communication channel.
308 * Even with this, there is no real guarantee against replay achieved here,
309 * unless the latest timestamp is persisted. While persistence should be
310 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
311 * communicators must protect against replay attacks when using backchannel
314 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
317 * Target's peer identity.
319 struct GNUNET_PeerIdentity target;
322 * Ephemeral key setup by the sender for @e target, used
323 * to encrypt the payload.
325 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
330 * Plaintext of the variable-size payload that is encrypted
331 * within a `struct TransportBackchannelEncapsulationMessage`
333 struct TransportBackchannelRequestPayload
337 * Sender's peer identity.
339 struct GNUNET_PeerIdentity sender;
342 * Signature of the sender over an
343 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
345 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
348 * How long is this signature over the ephemeral key valid?
350 * Note that the receiver MUST IGNORE the absolute time, and only interpret
351 * the value as a mononic time and reject "older" values than the last one
352 * observed. This is necessary as we do not want to require synchronized
353 * clocks and may not have a bidirectional communication channel.
355 * Even with this, there is no real guarantee against replay achieved here,
356 * unless the latest timestamp is persisted. While persistence should be
357 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
358 * communicators must protect against replay attacks when using backchannel
361 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
364 * Current monotonic time of the sending transport service. Used to
365 * detect replayed messages. Note that the receiver should remember
366 * a list of the recently seen timestamps and only reject messages
367 * if the timestamp is in the list, or the list is "full" and the
368 * timestamp is smaller than the lowest in the list.
370 * Like the @e ephemeral_validity, the list of timestamps per peer should be
371 * persisted to guard against replays after restarts.
373 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
375 /* Followed by a `struct GNUNET_MessageHeader` with a message
376 for a communicator */
378 /* Followed by a 0-termianted string specifying the name of
379 the communicator which is to receive the message */
384 * Outer layer of an encapsulated unfragmented application message sent
385 * over an unreliable channel.
387 struct TransportReliabilityBox
390 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
392 struct GNUNET_MessageHeader header;
395 * Number of messages still to be sent before a commulative
396 * ACK is requested. Zero if an ACK is requested immediately.
397 * In NBO. Note that the receiver may send the ACK faster
398 * if it believes that is reasonable.
400 uint32_t ack_countdown GNUNET_PACKED;
403 * Unique ID of the message used for signalling receipt of
404 * messages sent over possibly unreliable channels. Should
407 struct GNUNET_ShortHashCode msg_uuid;
412 * Confirmation that the receiver got a
413 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
414 * confirmation may be transmitted over a completely different queue,
415 * so ACKs are identified by a combination of PID of sender and
416 * message UUID, without the queue playing any role!
418 struct TransportReliabilityAckMessage
421 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
423 struct GNUNET_MessageHeader header;
428 uint32_t reserved GNUNET_PACKED;
431 * How long was the ACK delayed relative to the average time of
432 * receipt of the messages being acknowledged? Used to calculate
433 * the average RTT by taking the receipt time of the ack minus the
434 * average transmission time of the sender minus this value.
436 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
438 /* followed by any number of `struct GNUNET_ShortHashCode`
439 messages providing ACKs */
444 * Outer layer of an encapsulated fragmented application message.
446 struct TransportFragmentBox
449 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
451 struct GNUNET_MessageHeader header;
454 * Unique ID of this fragment (and fragment transmission!). Will
455 * change even if a fragement is retransmitted to make each
456 * transmission attempt unique! Should be incremented by one for
457 * each fragment transmission. If a client receives a duplicate
458 * fragment (same @e frag_off), it must send
459 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
461 uint32_t frag_uuid GNUNET_PACKED;
464 * Original message ID for of the message that all the1
465 * fragments belong to. Must be the same for all fragments.
467 struct GNUNET_ShortHashCode msg_uuid;
470 * Offset of this fragment in the overall message.
472 uint16_t frag_off GNUNET_PACKED;
475 * Total size of the message that is being fragmented.
477 uint16_t msg_size GNUNET_PACKED;
482 * Outer layer of an fragmented application message sent over a queue
483 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
484 * received, the receiver has two RTTs or 64 further fragments with
485 * the same basic message time to send an acknowledgement, possibly
486 * acknowledging up to 65 fragments in one ACK. ACKs must also be
487 * sent immediately once all fragments were sent.
489 struct TransportFragmentAckMessage
492 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
494 struct GNUNET_MessageHeader header;
497 * Unique ID of the lowest fragment UUID being acknowledged.
499 uint32_t frag_uuid GNUNET_PACKED;
502 * Bitfield of up to 64 additional fragments following the
503 * @e msg_uuid being acknowledged by this message.
505 uint64_t extra_acks GNUNET_PACKED;
508 * Original message ID for of the message that all the
509 * fragments belong to.
511 struct GNUNET_ShortHashCode msg_uuid;
514 * How long was the ACK delayed relative to the average time of
515 * receipt of the fragments being acknowledged? Used to calculate
516 * the average RTT by taking the receipt time of the ack minus the
517 * average transmission time of the sender minus this value.
519 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
522 * How long until the receiver will stop trying reassembly
525 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
530 * Content signed by the initator during DV learning.
532 * The signature is required to prevent DDoS attacks. A peer sending out this
533 * message is potentially generating a lot of traffic that will go back to the
534 * initator, as peers receiving this message will try to let the initiator
535 * know that they got the message.
537 * Without this signature, an attacker could abuse this mechanism for traffic
538 * amplification, sending a lot of traffic to a peer by putting out this type
539 * of message with the victim's peer identity.
541 * Even with just a signature, traffic amplification would be possible via
542 * replay attacks. The @e monotonic_time limits such replay attacks, as every
543 * potential amplificator will check the @e monotonic_time and only respond
544 * (at most) once per message.
549 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
551 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
554 * Time at the initiator when generating the signature.
556 * Note that the receiver MUST IGNORE the absolute time, and only interpret
557 * the value as a mononic time and reject "older" values than the last one
558 * observed. This is necessary as we do not want to require synchronized
559 * clocks and may not have a bidirectional communication channel.
561 * Even with this, there is no real guarantee against replay achieved here,
562 * unless the latest timestamp is persisted. Persistence should be
563 * provided via PEERSTORE if possible.
565 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
568 * Challenge value used by the initiator to re-identify the path.
570 struct GNUNET_ShortHashCode challenge;
575 * Content signed by each peer during DV learning.
577 * This assues the initiator of the DV learning operation that the hop from @e
578 * pred via the signing peer to @e succ actually exists. This makes it
579 * impossible for an adversary to supply the network with bogus routes.
581 * The @e challenge is included to provide replay protection for the
582 * initiator. This way, the initiator knows that the hop existed after the
583 * original @e challenge was first transmitted, providing a freshness metric.
585 * Peers other than the initiator that passively learn paths by observing
586 * these messages do NOT benefit from this. Here, an adversary may indeed
587 * replay old messages. Thus, passively learned paths should always be
588 * immediately marked as "potentially stale".
593 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
595 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
598 * Identity of the previous peer on the path.
600 struct GNUNET_PeerIdentity pred;
603 * Identity of the next peer on the path.
605 struct GNUNET_PeerIdentity succ;
608 * Challenge value used by the initiator to re-identify the path.
610 struct GNUNET_ShortHashCode challenge;
615 * An entry describing a peer on a path in a
616 * `struct TransportDVLearn` message.
621 * Identity of a peer on the path.
623 struct GNUNET_PeerIdentity hop;
626 * Signature of this hop over the path, of purpose
627 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
629 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
634 * Internal message used by transport for distance vector learning.
635 * If @e num_hops does not exceed the threshold, peers should append
636 * themselves to the peer list and flood the message (possibly only
637 * to a subset of their neighbours to limit discoverability of the
638 * network topology). To the extend that the @e bidirectional bits
639 * are set, peers may learn the inverse paths even if they did not
642 * Unless received on a bidirectional queue and @e num_hops just
643 * zero, peers that can forward to the initator should always try to
644 * forward to the initiator.
646 struct TransportDVLearn
649 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
651 struct GNUNET_MessageHeader header;
654 * Number of hops this messages has travelled, in NBO. Zero if
657 uint16_t num_hops GNUNET_PACKED;
660 * Bitmask of the last 16 hops indicating whether they are confirmed
661 * available (without DV) in both directions or not, in NBO. Used
662 * to possibly instantly learn a path in both directions. Each peer
663 * should shift this value by one to the left, and then set the
664 * lowest bit IF the current sender can be reached from it (without
667 uint16_t bidirectional GNUNET_PACKED;
670 * Peers receiving this message and delaying forwarding to other
671 * peers for any reason should increment this value by the non-network
672 * delay created by the peer.
674 struct GNUNET_TIME_RelativeNBO non_network_delay;
677 * Signature of this hop over the path, of purpose
678 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
680 struct GNUNET_CRYPTO_EddsaSignature init_sig;
683 * Identity of the peer that started this learning activity.
685 struct GNUNET_PeerIdentity initiator;
688 * Challenge value used by the initiator to re-identify the path.
690 struct GNUNET_ShortHashCode challenge;
692 /* Followed by @e num_hops `struct DVPathEntryP` values,
693 excluding the initiator of the DV trace; the last entry is the
694 current sender; the current peer must not be included. */
699 * Outer layer of an encapsulated message send over multiple hops.
700 * The path given only includes the identities of the subsequent
701 * peers, i.e. it will be empty if we are the receiver. Each
702 * forwarding peer should scan the list from the end, and if it can,
703 * forward to the respective peer. The list should then be shortened
704 * by all the entries up to and including that peer. Each hop should
705 * also increment @e total_hops to allow the receiver to get a precise
706 * estimate on the number of hops the message travelled. Senders must
707 * provide a learned path that thus should work, but intermediaries
708 * know of a shortcut, they are allowed to send the message via that
711 * If a peer finds itself still on the list, it must drop the message.
713 struct TransportDVBox
716 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
718 struct GNUNET_MessageHeader header;
721 * Number of total hops this messages travelled. In NBO.
722 * @e origin sets this to zero, to be incremented at
725 uint16_t total_hops GNUNET_PACKED;
728 * Number of hops this messages includes. In NBO.
730 uint16_t num_hops GNUNET_PACKED;
733 * Identity of the peer that originated the message.
735 struct GNUNET_PeerIdentity origin;
737 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
738 excluding the @e origin and the current peer, the last must be
739 the ultimate target; if @e num_hops is zero, the receiver of this
740 message is the ultimate target. */
742 /* Followed by the actual message, which itself may be
743 another box, but not a DV_LEARN or DV_BOX message! */
748 * Message send to another peer to validate that it can indeed
749 * receive messages at a particular address.
751 struct TransportValidationChallenge
755 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
757 struct GNUNET_MessageHeader header;
762 uint32_t reserved GNUNET_PACKED;
765 * Challenge to be signed by the receiving peer.
767 struct GNUNET_ShortHashCode challenge;
770 * Timestamp of the sender, to be copied into the reply
771 * to allow sender to calculate RTT.
773 struct GNUNET_TIME_AbsoluteNBO sender_time;
778 * Message signed by a peer to confirm that it can indeed
779 * receive messages at a particular address.
781 struct TransportValidationPS
785 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
787 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
790 * How long does the sender believe the address on
791 * which the challenge was received to remain valid?
793 struct GNUNET_TIME_RelativeNBO validity_duration;
796 * Challenge signed by the receiving peer.
798 struct GNUNET_ShortHashCode challenge;
803 * Message send to a peer to respond to a
804 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
806 struct TransportValidationResponse
810 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
812 struct GNUNET_MessageHeader header;
817 uint32_t reserved GNUNET_PACKED;
820 * The peer's signature matching the
821 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
823 struct GNUNET_CRYPTO_EddsaSignature signature;
826 * The challenge that was signed by the receiving peer.
828 struct GNUNET_ShortHashCode challenge;
831 * Original timestamp of the sender (was @code{sender_time}),
832 * copied into the reply to allow sender to calculate RTT.
834 struct GNUNET_TIME_AbsoluteNBO origin_time;
837 * How long does the sender believe this address to remain
840 struct GNUNET_TIME_RelativeNBO validity_duration;
844 GNUNET_NETWORK_STRUCT_END
848 * What type of client is the `struct TransportClient` about?
853 * We do not know yet (client is fresh).
858 * Is the CORE service, we need to forward traffic to it.
863 * It is a monitor, forward monitor data.
868 * It is a communicator, use for communication.
873 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
880 * When did we launch this DV learning activity?
882 struct LearnLaunchEntry
886 * Kept (also) in a DLL sorted by launch time.
888 struct LearnLaunchEntry *prev;
891 * Kept (also) in a DLL sorted by launch time.
893 struct LearnLaunchEntry *next;
896 * Challenge that uniquely identifies this activity.
898 struct GNUNET_ShortHashCode challenge;
901 * When did we transmit the DV learn message (used to calculate RTT) and
902 * determine freshness of paths learned via this operation.
904 struct GNUNET_TIME_Absolute launch_time;
909 * Entry in our cache of ephemeral keys we currently use. This way, we only
910 * sign an ephemeral once per @e target, and then can re-use it over multiple
911 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
912 * signing is expensive and in some cases we may use backchannel messages a
915 struct EphemeralCacheEntry
919 * Target's peer identity (we don't re-use ephemerals
920 * to limit linkability of messages).
922 struct GNUNET_PeerIdentity target;
925 * Signature affirming @e ephemeral_key of type
926 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
928 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
931 * How long is @e sender_sig valid
933 struct GNUNET_TIME_Absolute ephemeral_validity;
938 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
941 * Our private ephemeral key.
943 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
946 * Node in the ephemeral cache for this entry.
947 * Used for expiration.
949 struct GNUNET_CONTAINER_HeapNode *hn;
954 * Client connected to the transport service.
956 struct TransportClient;
960 * A neighbour that at least one communicator is connected to.
966 * Entry in our #dv_routes table, representing a (set of) distance
967 * vector routes to a particular peer.
969 struct DistanceVector;
972 * One possible hop towards a DV target.
974 struct DistanceVectorHop
978 * Kept in a MDLL, sorted by @e timeout.
980 struct DistanceVectorHop *next_dv;
983 * Kept in a MDLL, sorted by @e timeout.
985 struct DistanceVectorHop *prev_dv;
990 struct DistanceVectorHop *next_neighbour;
995 struct DistanceVectorHop *prev_neighbour;
998 * What would be the next hop to @e target?
1000 struct Neighbour *next_hop;
1003 * Distance vector entry this hop belongs with.
1005 struct DistanceVector *dv;
1008 * Array of @e distance hops to the target, excluding @e next_hop.
1009 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1010 * at the end of this struct. Excludes the target itself!
1012 const struct GNUNET_PeerIdentity *path;
1015 * At what time do we forget about this path unless we see it again
1018 struct GNUNET_TIME_Absolute timeout;
1021 * For how long is the validation of this path considered
1023 * Set to ZERO if the path is learned by snooping on DV learn messages
1024 * initiated by other peers, and to the time at which we generated the
1025 * challenge for DV learn operations this peer initiated.
1027 struct GNUNET_TIME_Absolute path_valid_until;
1030 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1031 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1034 unsigned int distance;
1039 * Entry in our #dv_routes table, representing a (set of) distance
1040 * vector routes to a particular peer.
1042 struct DistanceVector
1046 * To which peer is this a route?
1048 struct GNUNET_PeerIdentity target;
1051 * Known paths to @e target.
1053 struct DistanceVectorHop *dv_head;
1056 * Known paths to @e target.
1058 struct DistanceVectorHop *dv_tail;
1061 * Task scheduled to purge expired paths from @e dv_head MDLL.
1063 struct GNUNET_SCHEDULER_Task *timeout_task;
1066 * Task scheduled to possibly notfiy core that this queue is no longer
1067 * counting as confirmed. Runs the #core_queue_visibility_check().
1069 struct GNUNET_SCHEDULER_Task *visibility_task;
1072 * Quota at which CORE is allowed to transmit to this peer
1073 * (note that the value CORE should actually be told is this
1074 * value plus the respective value in `struct Neighbour`).
1075 * Should match the sum of the quotas of all of the paths.
1077 * FIXME: not yet set, tricky to get right given multiple paths,
1078 * many of which may be inactive! (=> Idea: measure???)
1079 * FIXME: how do we set this value initially when we tell CORE?
1080 * Options: start at a minimum value or at literally zero?
1081 * (=> Current thought: clean would be zero!)
1083 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1086 * Is one of the DV paths in this struct 'confirmed' and thus
1087 * the cause for CORE to see this peer as connected? (Note that
1088 * the same may apply to a `struct Neighbour` at the same time.)
1095 * A queue is a message queue provided by a communicator
1096 * via which we can reach a particular neighbour.
1102 * Entry identifying transmission in one of our `struct
1103 * Queue` which still awaits an ACK. This is used to
1104 * ensure we do not overwhelm a communicator and limit the number of
1105 * messages outstanding per communicator (say in case communicator is
1106 * CPU bound) and per queue (in case bandwidth allocation exceeds
1107 * what the communicator can actually provide towards a particular
1116 struct QueueEntry *next;
1121 struct QueueEntry *prev;
1124 * Queue this entry is queued with.
1126 struct Queue *queue;
1129 * Message ID used for this message with the queue used for transmission.
1136 * A queue is a message queue provided by a communicator
1137 * via which we can reach a particular neighbour.
1144 struct Queue *next_neighbour;
1149 struct Queue *prev_neighbour;
1154 struct Queue *prev_client;
1159 struct Queue *next_client;
1162 * Head of DLL of unacked transmission requests.
1164 struct QueueEntry *queue_head;
1167 * End of DLL of unacked transmission requests.
1169 struct QueueEntry *queue_tail;
1172 * Which neighbour is this queue for?
1174 struct Neighbour *neighbour;
1177 * Which communicator offers this queue?
1179 struct TransportClient *tc;
1182 * Address served by the queue.
1184 const char *address;
1187 * Task scheduled for the time when this queue can (likely) transmit the
1188 * next message. Still needs to check with the @e tracker_out to be sure.
1190 struct GNUNET_SCHEDULER_Task *transmit_task;
1193 * Task scheduled to possibly notfiy core that this queue is no longer
1194 * counting as confirmed. Runs the #core_queue_visibility_check().
1196 struct GNUNET_SCHEDULER_Task *visibility_task;
1199 * Our current RTT estimate for this queue.
1201 struct GNUNET_TIME_Relative rtt;
1204 * How long do *we* consider this @e address to be valid? In the past or
1205 * zero if we have not yet validated it. Can be updated based on
1206 * challenge-response validations (via address validation logic), or when we
1207 * receive ACKs that we can definitively map to transmissions via this
1210 struct GNUNET_TIME_Absolute validated_until;
1213 * Message ID generator for transmissions on this queue.
1218 * Unique identifier of this queue with the communicator.
1223 * Maximum transmission unit supported by this queue.
1228 * Distance to the target of this queue.
1229 * FIXME: needed? DV is done differently these days...
1236 uint32_t num_msg_pending;
1241 uint32_t num_bytes_pending;
1244 * Length of the DLL starting at @e queue_head.
1246 unsigned int queue_length;
1249 * Network type offered by this queue.
1251 enum GNUNET_NetworkType nt;
1254 * Connection status for this queue.
1256 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1259 * How much outbound bandwidth do we have available for this queue?
1261 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1264 * How much inbound bandwidth do we have available for this queue?
1266 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1271 * Information we keep for a message that we are reassembling.
1273 struct ReassemblyContext
1277 * Original message ID for of the message that all the
1278 * fragments belong to.
1280 struct GNUNET_ShortHashCode msg_uuid;
1283 * Which neighbour is this context for?
1285 struct Neighbour *neighbour;
1288 * Entry in the reassembly heap (sorted by expiration).
1290 struct GNUNET_CONTAINER_HeapNode *hn;
1293 * Bitfield with @e msg_size bits representing the positions
1294 * where we have received fragments. When we receive a fragment,
1295 * we check the bits in @e bitfield before incrementing @e msg_missing.
1297 * Allocated after the reassembled message.
1302 * Task for sending ACK. We may send ACKs either because of hitting
1303 * the @e extra_acks limit, or based on time and @e num_acks. This
1304 * task is for the latter case.
1306 struct GNUNET_SCHEDULER_Task *ack_task;
1309 * At what time will we give up reassembly of this message?
1311 struct GNUNET_TIME_Absolute reassembly_timeout;
1314 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1315 * Should be reset to zero when @e num_acks is set to 0.
1317 struct GNUNET_TIME_Relative avg_ack_delay;
1320 * Time we received the last fragment. @e avg_ack_delay must be
1321 * incremented by now - @e last_frag multiplied by @e num_acks.
1323 struct GNUNET_TIME_Absolute last_frag;
1326 * Bitfield of up to 64 additional fragments following @e frag_uuid
1327 * to be acknowledged in the next cummulative ACK.
1329 uint64_t extra_acks;
1332 * Unique ID of the lowest fragment UUID to be acknowledged in the
1333 * next cummulative ACK. Only valid if @e num_acks > 0.
1338 * Number of ACKs we have accumulated so far. Reset to 0
1339 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1341 unsigned int num_acks;
1344 * How big is the message we are reassembling in total?
1349 * How many bytes of the message are still missing? Defragmentation
1350 * is complete when @e msg_missing == 0.
1352 uint16_t msg_missing;
1354 /* Followed by @e msg_size bytes of the (partially) defragmented original
1357 /* Followed by @e bitfield data */
1362 * A neighbour that at least one communicator is connected to.
1368 * Which peer is this about?
1370 struct GNUNET_PeerIdentity pid;
1373 * Map with `struct ReassemblyContext` structs for fragments under
1374 * reassembly. May be NULL if we currently have no fragments from
1375 * this @e pid (lazy initialization).
1377 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1380 * Heap with `struct ReassemblyContext` structs for fragments under
1381 * reassembly. May be NULL if we currently have no fragments from
1382 * this @e pid (lazy initialization).
1384 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1387 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1389 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1392 * Head of list of messages pending for this neighbour.
1394 struct PendingMessage *pending_msg_head;
1397 * Tail of list of messages pending for this neighbour.
1399 struct PendingMessage *pending_msg_tail;
1402 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1403 * purged if this neighbour goes down.
1405 struct DistanceVectorHop *dv_head;
1408 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1409 * purged if this neighbour goes down.
1411 struct DistanceVectorHop *dv_tail;
1414 * Head of DLL of queues to this peer.
1416 struct Queue *queue_head;
1419 * Tail of DLL of queues to this peer.
1421 struct Queue *queue_tail;
1424 * Task run to cleanup pending messages that have exceeded their timeout.
1426 struct GNUNET_SCHEDULER_Task *timeout_task;
1429 * Quota at which CORE is allowed to transmit to this peer
1430 * (note that the value CORE should actually be told is this
1431 * value plus the respective value in `struct DistanceVector`).
1432 * Should match the sum of the quotas of all of the queues.
1434 * FIXME: not yet set, tricky to get right given multiple queues!
1435 * (=> Idea: measure???)
1436 * FIXME: how do we set this value initially when we tell CORE?
1437 * Options: start at a minimum value or at literally zero?
1438 * (=> Current thought: clean would be zero!)
1440 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1443 * What is the earliest timeout of any message in @e pending_msg_tail?
1445 struct GNUNET_TIME_Absolute earliest_timeout;
1448 * Do we have a confirmed working queue and are thus visible to
1456 * A peer that an application (client) would like us to talk to directly.
1462 * Which peer is this about?
1464 struct GNUNET_PeerIdentity pid;
1467 * Client responsible for the request.
1469 struct TransportClient *tc;
1472 * Handle for watching the peerstore for HELLOs for this peer.
1474 struct GNUNET_PEERSTORE_WatchContext *wc;
1477 * What kind of performance preference does this @e tc have?
1479 enum GNUNET_MQ_PreferenceKind pk;
1482 * How much bandwidth would this @e tc like to see?
1484 struct GNUNET_BANDWIDTH_Value32NBO bw;
1489 * Types of different pending messages.
1491 enum PendingMessageType
1495 * Ordinary message received from the CORE service.
1502 PMT_FRAGMENT_BOX = 1,
1507 PMT_RELIABILITY_BOX = 2,
1510 * Any type of acknowledgement.
1512 PMT_ACKNOWLEDGEMENT = 3,
1515 * Control traffic generated by the TRANSPORT service itself.
1523 * Transmission request that is awaiting delivery. The original
1524 * transmission requests from CORE may be too big for some queues.
1525 * In this case, a *tree* of fragments is created. At each
1526 * level of the tree, fragments are kept in a DLL ordered by which
1527 * fragment should be sent next (at the head). The tree is searched
1528 * top-down, with the original message at the root.
1530 * To select a node for transmission, first it is checked if the
1531 * current node's message fits with the MTU. If it does not, we
1532 * either calculate the next fragment (based on @e frag_off) from the
1533 * current node, or, if all fragments have already been created,
1534 * descend to the @e head_frag. Even though the node was already
1535 * fragmented, the fragment may be too big if the fragment was
1536 * generated for a queue with a larger MTU. In this case, the node
1537 * may be fragmented again, thus creating a tree.
1539 * When acknowledgements for fragments are received, the tree
1540 * must be pruned, removing those parts that were already
1541 * acknowledged. When fragments are sent over a reliable
1542 * channel, they can be immediately removed.
1544 * If a message is ever fragmented, then the original "full" message
1545 * is never again transmitted (even if it fits below the MTU), and
1546 * only (remaining) fragments are sent.
1548 struct PendingMessage
1551 * Kept in a MDLL of messages for this @a target.
1553 struct PendingMessage *next_neighbour;
1556 * Kept in a MDLL of messages for this @a target.
1558 struct PendingMessage *prev_neighbour;
1561 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1563 struct PendingMessage *next_client;
1566 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1568 struct PendingMessage *prev_client;
1571 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1572 * #PMT_FRAGMENT_BOx)
1574 struct PendingMessage *next_frag;
1577 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1578 * #PMT_FRAGMENT_BOX)
1580 struct PendingMessage *prev_frag;
1583 * This message, reliability boxed. Only possibly available if @e pmt is
1586 struct PendingMessage *bpm;
1589 * Target of the request.
1591 struct Neighbour *target;
1594 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1596 struct TransportClient *client;
1599 * Head of a MDLL of fragments created for this core message.
1601 struct PendingMessage *head_frag;
1604 * Tail of a MDLL of fragments created for this core message.
1606 struct PendingMessage *tail_frag;
1609 * Our parent in the fragmentation tree.
1611 struct PendingMessage *frag_parent;
1614 * At what time should we give up on the transmission (and no longer retry)?
1616 struct GNUNET_TIME_Absolute timeout;
1619 * What is the earliest time for us to retry transmission of this message?
1621 struct GNUNET_TIME_Absolute next_attempt;
1624 * UUID to use for this message (used for reassembly of fragments, only
1625 * initialized if @e msg_uuid_set is #GNUNET_YES).
1627 struct GNUNET_ShortHashCode msg_uuid;
1630 * Counter incremented per generated fragment.
1632 uint32_t frag_uuidgen;
1635 * Type of the pending message.
1637 enum PendingMessageType pmt;
1640 * Size of the original message.
1645 * Offset at which we should generate the next fragment.
1650 * #GNUNET_YES once @e msg_uuid was initialized
1652 int16_t msg_uuid_set;
1654 /* Followed by @e bytes_msg to transmit */
1659 * One of the addresses of this peer.
1661 struct AddressListEntry
1667 struct AddressListEntry *next;
1672 struct AddressListEntry *prev;
1675 * Which communicator provides this address?
1677 struct TransportClient *tc;
1680 * The actual address.
1682 const char *address;
1685 * Current context for storing this address in the peerstore.
1687 struct GNUNET_PEERSTORE_StoreContext *sc;
1690 * Task to periodically do @e st operation.
1692 struct GNUNET_SCHEDULER_Task *st;
1695 * What is a typical lifetime the communicator expects this
1696 * address to have? (Always from now.)
1698 struct GNUNET_TIME_Relative expiration;
1701 * Address identifier used by the communicator.
1706 * Network type offered by this address.
1708 enum GNUNET_NetworkType nt;
1713 * Client connected to the transport service.
1715 struct TransportClient
1721 struct TransportClient *next;
1726 struct TransportClient *prev;
1729 * Handle to the client.
1731 struct GNUNET_SERVICE_Client *client;
1734 * Message queue to the client.
1736 struct GNUNET_MQ_Handle *mq;
1739 * What type of client is this?
1741 enum ClientType type;
1747 * Information for @e type #CT_CORE.
1753 * Head of list of messages pending for this client, sorted by
1754 * transmission time ("next_attempt" + possibly internal prioritization).
1756 struct PendingMessage *pending_msg_head;
1759 * Tail of list of messages pending for this client.
1761 struct PendingMessage *pending_msg_tail;
1766 * Information for @e type #CT_MONITOR.
1772 * Peer identity to monitor the addresses of.
1773 * Zero to monitor all neighbours. Valid if
1774 * @e type is #CT_MONITOR.
1776 struct GNUNET_PeerIdentity peer;
1779 * Is this a one-shot monitor?
1787 * Information for @e type #CT_COMMUNICATOR.
1792 * If @e type is #CT_COMMUNICATOR, this communicator
1793 * supports communicating using these addresses.
1795 char *address_prefix;
1798 * Head of DLL of queues offered by this communicator.
1800 struct Queue *queue_head;
1803 * Tail of DLL of queues offered by this communicator.
1805 struct Queue *queue_tail;
1808 * Head of list of the addresses of this peer offered by this
1811 struct AddressListEntry *addr_head;
1814 * Tail of list of the addresses of this peer offered by this
1817 struct AddressListEntry *addr_tail;
1820 * Number of queue entries in all queues to this communicator. Used
1821 * throttle sending to a communicator if we see that the communicator
1822 * is globally unable to keep up.
1824 unsigned int total_queue_length;
1827 * Characteristics of this communicator.
1829 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1834 * Information for @e type #CT_APPLICATION
1840 * Map of requests for peers the given client application would like to
1841 * see connections for. Maps from PIDs to `struct PeerRequest`.
1843 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1852 * State we keep for validation activities. Each of these
1853 * is both in the #validation_heap and the #validation_map.
1855 struct ValidationState
1859 * For which peer is @a address to be validated (or possibly valid)?
1860 * Serves as key in the #validation_map.
1862 struct GNUNET_PeerIdentity pid;
1865 * How long did the peer claim this @e address to be valid? Capped at
1866 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1867 * were told about the address and the value claimed by the other peer at
1868 * that time. May be updated similarly when validation succeeds.
1870 struct GNUNET_TIME_Absolute valid_until;
1873 * How long do *we* consider this @e address to be valid?
1874 * In the past or zero if we have not yet validated it.
1876 struct GNUNET_TIME_Absolute validated_until;
1879 * When did we FIRST use the current @e challenge in a message?
1880 * Used to sanity-check @code{origin_time} in the response when
1881 * calculating the RTT. If the @code{origin_time} is not in
1882 * the expected range, the response is discarded as malicious.
1884 struct GNUNET_TIME_Absolute first_challenge_use;
1887 * When did we LAST use the current @e challenge in a message?
1888 * Used to sanity-check @code{origin_time} in the response when
1889 * calculating the RTT. If the @code{origin_time} is not in
1890 * the expected range, the response is discarded as malicious.
1892 struct GNUNET_TIME_Absolute last_challenge_use;
1895 * Next time we will send the @e challenge to the peer, if this time is past
1896 * @e valid_until, this validation state is released at this time. If the
1897 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1898 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1899 * to re-validate before the validity actually expires.
1901 struct GNUNET_TIME_Absolute next_challenge;
1904 * Current backoff factor we're applying for sending the @a challenge.
1905 * Reset to 0 if the @a challenge is confirmed upon validation.
1906 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1907 * existing value if we receive an unvalidated address again over
1908 * another channel (and thus should consider the information "fresh").
1909 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1911 struct GNUNET_TIME_Relative challenge_backoff;
1914 * Initially set to "forever". Once @e validated_until is set, this value is
1915 * set to the RTT that tells us how long it took to receive the validation.
1917 struct GNUNET_TIME_Relative validation_rtt;
1920 * The challenge we sent to the peer to get it to validate the address. Note
1921 * that we rotate the challenge whenever we update @e validated_until to
1922 * avoid attacks where a peer simply replays an old challenge in the future.
1923 * (We must not rotate more often as otherwise we may discard valid answers
1924 * due to packet losses, latency and reorderings on the network).
1926 struct GNUNET_ShortHashCode challenge;
1929 * Claimed address of the peer.
1934 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1935 * heap is used to figure out when the next validation activity should be
1938 struct GNUNET_CONTAINER_HeapNode *hn;
1941 * Handle to a PEERSTORE store operation for this @e address. NULL if
1942 * no PEERSTORE operation is pending.
1944 struct GNUNET_PEERSTORE_StoreContext *sc;
1947 * We are technically ready to send the challenge, but we are waiting for
1948 * the respective queue to become available for transmission.
1955 * Head of linked list of all clients to this service.
1957 static struct TransportClient *clients_head;
1960 * Tail of linked list of all clients to this service.
1962 static struct TransportClient *clients_tail;
1965 * Statistics handle.
1967 static struct GNUNET_STATISTICS_Handle *GST_stats;
1970 * Configuration handle.
1972 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1977 static struct GNUNET_PeerIdentity GST_my_identity;
1982 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1985 * Map from PIDs to `struct Neighbour` entries. A peer is
1986 * a neighbour if we have an MQ to it from some communicator.
1988 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1991 * Map from PIDs to `struct DistanceVector` entries describing
1992 * known paths to the peer.
1994 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
1997 * Map from PIDs to `struct ValidationState` entries describing
1998 * addresses we are aware of and their validity state.
2000 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2003 * Map from challenges to `struct LearnLaunchEntry` values.
2005 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2008 * Head of a DLL sorted by launch time.
2010 static struct LearnLaunchEntry *lle_head;
2013 * Tail of a DLL sorted by launch time.
2015 static struct LearnLaunchEntry *lle_tail;
2018 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2019 * sorting addresses we are aware of by when we should next try to (re)validate
2022 static struct GNUNET_CONTAINER_Heap *validation_heap;
2025 * Database for peer's HELLOs.
2027 static struct GNUNET_PEERSTORE_Handle *peerstore;
2030 * Heap sorting `struct EphemeralCacheEntry` by their
2031 * key/signature validity.
2033 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2036 * Hash map for looking up `struct EphemeralCacheEntry`s
2037 * by peer identity. (We may have ephemerals in our
2038 * cache for which we do not have a neighbour entry,
2039 * and similar many neighbours may not need ephemerals,
2040 * so we use a second map.)
2042 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2045 * Task to free expired ephemerals.
2047 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2050 * Task run to initiate DV learning.
2052 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2055 * Task to run address validation.
2057 static struct GNUNET_SCHEDULER_Task *validation_task;
2061 * Free cached ephemeral key.
2063 * @param ece cached signature to free
2066 free_ephemeral (struct EphemeralCacheEntry *ece)
2068 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2069 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2075 * Free validation state.
2077 * @param vs validation state to free
2080 free_validation_state (struct ValidationState *vs)
2082 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2083 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2087 GNUNET_PEERSTORE_store_cancel (vs->sc);
2090 GNUNET_free (vs->address);
2096 * Lookup neighbour record for peer @a pid.
2098 * @param pid neighbour to look for
2099 * @return NULL if we do not have this peer as a neighbour
2101 static struct Neighbour *
2102 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2104 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2109 * Details about what to notify monitors about.
2114 * @deprecated To be discussed if we keep these...
2116 struct GNUNET_TIME_Absolute last_validation;
2117 struct GNUNET_TIME_Absolute valid_until;
2118 struct GNUNET_TIME_Absolute next_validation;
2121 * Current round-trip time estimate.
2123 struct GNUNET_TIME_Relative rtt;
2126 * Connection status.
2128 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2133 uint32_t num_msg_pending;
2138 uint32_t num_bytes_pending;
2143 * Free a @dvh. Callers MAY want to check if this was the last path to the
2144 * `target`, and if so call #free_dv_route to also free the associated DV
2145 * entry in #dv_routes (if not, the associated scheduler job should eventually
2148 * @param dvh hop to free
2151 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2153 struct Neighbour *n = dvh->next_hop;
2154 struct DistanceVector *dv = dvh->dv;
2156 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2157 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2163 * Free entry in #dv_routes. First frees all hops to the target, and
2164 * if there are no entries left, frees @a dv as well.
2166 * @param dv route to free
2169 free_dv_route (struct DistanceVector *dv)
2171 struct DistanceVectorHop *dvh;
2173 while (NULL != (dvh = dv->dv_head))
2174 free_distance_vector_hop (dvh);
2175 if (NULL == dv->dv_head)
2179 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2180 if (NULL != dv->visibility_task)
2181 GNUNET_SCHEDULER_cancel (dv->visibility_task);
2182 if (NULL != dv->timeout_task)
2183 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2190 * Notify monitor @a tc about an event. That @a tc
2191 * cares about the event has already been checked.
2193 * Send @a tc information in @a me about a @a peer's status with
2194 * respect to some @a address to all monitors that care.
2196 * @param tc monitor to inform
2197 * @param peer peer the information is about
2198 * @param address address the information is about
2199 * @param nt network type associated with @a address
2200 * @param me detailed information to transmit
2203 notify_monitor (struct TransportClient *tc,
2204 const struct GNUNET_PeerIdentity *peer,
2205 const char *address,
2206 enum GNUNET_NetworkType nt,
2207 const struct MonitorEvent *me)
2209 struct GNUNET_MQ_Envelope *env;
2210 struct GNUNET_TRANSPORT_MonitorData *md;
2211 size_t addr_len = strlen (address) + 1;
2213 env = GNUNET_MQ_msg_extra (md,
2215 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2216 md->nt = htonl ((uint32_t) nt);
2218 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2219 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2220 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2221 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2222 md->cs = htonl ((uint32_t) me->cs);
2223 md->num_msg_pending = htonl (me->num_msg_pending);
2224 md->num_bytes_pending = htonl (me->num_bytes_pending);
2225 memcpy (&md[1], address, addr_len);
2226 GNUNET_MQ_send (tc->mq, env);
2231 * Send information in @a me about a @a peer's status with respect
2232 * to some @a address to all monitors that care.
2234 * @param peer peer the information is about
2235 * @param address address the information is about
2236 * @param nt network type associated with @a address
2237 * @param me detailed information to transmit
2240 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2241 const char *address,
2242 enum GNUNET_NetworkType nt,
2243 const struct MonitorEvent *me)
2245 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2247 if (CT_MONITOR != tc->type)
2249 if (tc->details.monitor.one_shot)
2251 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2252 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2254 notify_monitor (tc, peer, address, nt, me);
2260 * Called whenever a client connects. Allocates our
2261 * data structures associated with that client.
2263 * @param cls closure, NULL
2264 * @param client identification of the client
2265 * @param mq message queue for the client
2266 * @return our `struct TransportClient`
2269 client_connect_cb (void *cls,
2270 struct GNUNET_SERVICE_Client *client,
2271 struct GNUNET_MQ_Handle *mq)
2273 struct TransportClient *tc;
2276 tc = GNUNET_new (struct TransportClient);
2277 tc->client = client;
2279 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2288 * @param rc data structure to free
2291 free_reassembly_context (struct ReassemblyContext *rc)
2293 struct Neighbour *n = rc->neighbour;
2295 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2296 GNUNET_assert (GNUNET_OK ==
2297 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2305 * Task run to clean up reassembly context of a neighbour that have expired.
2307 * @param cls a `struct Neighbour`
2310 reassembly_cleanup_task (void *cls)
2312 struct Neighbour *n = cls;
2313 struct ReassemblyContext *rc;
2315 n->reassembly_timeout_task = NULL;
2316 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2318 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2321 free_reassembly_context (rc);
2324 GNUNET_assert (NULL == n->reassembly_timeout_task);
2325 n->reassembly_timeout_task =
2326 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2327 &reassembly_cleanup_task,
2335 * function called to #free_reassembly_context().
2339 * @param value a `struct ReassemblyContext` to free
2340 * @return #GNUNET_OK (continue iteration)
2343 free_reassembly_cb (void *cls,
2344 const struct GNUNET_ShortHashCode *key,
2347 struct ReassemblyContext *rc = value;
2351 free_reassembly_context (rc);
2357 * Release memory used by @a neighbour.
2359 * @param neighbour neighbour entry to free
2362 free_neighbour (struct Neighbour *neighbour)
2364 struct DistanceVectorHop *dvh;
2366 GNUNET_assert (NULL == neighbour->queue_head);
2367 GNUNET_assert (GNUNET_YES ==
2368 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2371 if (NULL != neighbour->timeout_task)
2372 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2373 if (NULL != neighbour->reassembly_map)
2375 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2376 &free_reassembly_cb,
2378 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2379 neighbour->reassembly_map = NULL;
2380 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2381 neighbour->reassembly_heap = NULL;
2383 while (NULL != (dvh = neighbour->dv_head))
2385 struct DistanceVector *dv = dvh->dv;
2387 free_distance_vector_hop (dvh);
2388 if (NULL == dv->dv_head)
2391 if (NULL != neighbour->reassembly_timeout_task)
2392 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2393 GNUNET_free (neighbour);
2398 * Send message to CORE clients that we lost a connection.
2400 * @param tc client to inform (must be CORE client)
2401 * @param pid peer the connection is for
2402 * @param quota_out current quota for the peer
2405 core_send_connect_info (struct TransportClient *tc,
2406 const struct GNUNET_PeerIdentity *pid,
2407 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2409 struct GNUNET_MQ_Envelope *env;
2410 struct ConnectInfoMessage *cim;
2412 GNUNET_assert (CT_CORE == tc->type);
2413 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2414 cim->quota_out = quota_out;
2416 GNUNET_MQ_send (tc->mq, env);
2421 * Send message to CORE clients that we gained a connection
2423 * @param pid peer the queue was for
2424 * @param quota_out current quota for the peer
2427 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2428 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2430 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2432 if (CT_CORE != tc->type)
2434 core_send_connect_info (tc, pid, quota_out);
2440 * Send message to CORE clients that we lost a connection.
2442 * @param pid peer the connection was for
2445 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2447 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2449 struct GNUNET_MQ_Envelope *env;
2450 struct DisconnectInfoMessage *dim;
2452 if (CT_CORE != tc->type)
2454 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2456 GNUNET_MQ_send (tc->mq, env);
2462 * We believe we are ready to transmit a message on a queue. Double-checks
2463 * with the queue's "tracker_out" and then gives the message to the
2464 * communicator for transmission (updating the tracker, and re-scheduling
2465 * itself if applicable).
2467 * @param cls the `struct Queue` to process transmissions for
2470 transmit_on_queue (void *cls);
2474 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2475 * we should run immediately or if the message queue is empty.
2476 * Test for no task being added AND queue not being empty to
2477 * transmit immediately afterwards! This function must only
2478 * be called if the message queue is non-empty!
2480 * @param queue the queue to do scheduling for
2483 schedule_transmit_on_queue (struct Queue *queue)
2485 struct Neighbour *n = queue->neighbour;
2486 struct PendingMessage *pm = n->pending_msg_head;
2487 struct GNUNET_TIME_Relative out_delay;
2490 GNUNET_assert (NULL != pm);
2491 if (queue->tc->details.communicator.total_queue_length >=
2492 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2494 GNUNET_STATISTICS_update (
2496 "# Transmission throttled due to communicator queue limit",
2501 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2503 GNUNET_STATISTICS_update (GST_stats,
2504 "# Transmission throttled due to queue queue limit",
2510 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
2512 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
2513 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
2516 if (0 == out_delay.rel_value_us)
2517 return; /* we should run immediately! */
2518 /* queue has changed since we were scheduled, reschedule again */
2519 queue->transmit_task =
2520 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
2521 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2522 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2523 "Next transmission on queue `%s' in %s (high delay)\n",
2525 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2528 "Next transmission on queue `%s' in %s\n",
2530 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2535 * Check whether the CORE visibility of @a n changed. If so,
2536 * check whether we need to notify CORE.
2538 * @param n neighbour to perform the check for
2541 update_neighbour_core_visibility (struct Neighbour *n);
2547 * @param queue the queue to free
2550 free_queue (struct Queue *queue)
2552 struct Neighbour *neighbour = queue->neighbour;
2553 struct TransportClient *tc = queue->tc;
2554 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
2555 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
2556 struct QueueEntry *qe;
2559 if (NULL != queue->transmit_task)
2561 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2562 queue->transmit_task = NULL;
2564 if (NULL != queue->visibility_task)
2566 GNUNET_SCHEDULER_cancel (queue->visibility_task);
2567 queue->visibility_task = NULL;
2569 GNUNET_CONTAINER_MDLL_remove (neighbour,
2570 neighbour->queue_head,
2571 neighbour->queue_tail,
2573 GNUNET_CONTAINER_MDLL_remove (client,
2574 tc->details.communicator.queue_head,
2575 tc->details.communicator.queue_tail,
2577 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
2578 tc->details.communicator.total_queue_length);
2579 while (NULL != (qe = queue->queue_head))
2581 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
2582 queue->queue_length--;
2583 tc->details.communicator.total_queue_length--;
2586 GNUNET_assert (0 == queue->queue_length);
2587 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
2588 tc->details.communicator.total_queue_length))
2590 /* Communicator dropped below threshold, resume all queues */
2591 GNUNET_STATISTICS_update (
2593 "# Transmission throttled due to communicator queue limit",
2596 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
2598 schedule_transmit_on_queue (s);
2600 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
2601 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2602 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2603 GNUNET_free (queue);
2605 update_neighbour_core_visibility (neighbour);
2606 cores_send_disconnect_info (&neighbour->pid);
2608 if (NULL == neighbour->queue_head)
2610 free_neighbour (neighbour);
2618 * @param ale address list entry to free
2621 free_address_list_entry (struct AddressListEntry *ale)
2623 struct TransportClient *tc = ale->tc;
2625 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2626 tc->details.communicator.addr_tail,
2628 if (NULL != ale->sc)
2630 GNUNET_PEERSTORE_store_cancel (ale->sc);
2633 if (NULL != ale->st)
2635 GNUNET_SCHEDULER_cancel (ale->st);
2643 * Stop the peer request in @a value.
2645 * @param cls a `struct TransportClient` that no longer makes the request
2646 * @param pid the peer's identity
2647 * @param value a `struct PeerRequest`
2648 * @return #GNUNET_YES (always)
2651 stop_peer_request (void *cls,
2652 const struct GNUNET_PeerIdentity *pid,
2655 struct TransportClient *tc = cls;
2656 struct PeerRequest *pr = value;
2658 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2661 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2671 * Called whenever a client is disconnected. Frees our
2672 * resources associated with that client.
2674 * @param cls closure, NULL
2675 * @param client identification of the client
2676 * @param app_ctx our `struct TransportClient`
2679 client_disconnect_cb (void *cls,
2680 struct GNUNET_SERVICE_Client *client,
2683 struct TransportClient *tc = app_ctx;
2686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2687 "Client %p disconnected, cleaning up.\n",
2689 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
2695 struct PendingMessage *pm;
2697 while (NULL != (pm = tc->details.core.pending_msg_head))
2699 GNUNET_CONTAINER_MDLL_remove (client,
2700 tc->details.core.pending_msg_head,
2701 tc->details.core.pending_msg_tail,
2709 case CT_COMMUNICATOR: {
2711 struct AddressListEntry *ale;
2713 while (NULL != (q = tc->details.communicator.queue_head))
2715 while (NULL != (ale = tc->details.communicator.addr_head))
2716 free_address_list_entry (ale);
2717 GNUNET_free (tc->details.communicator.address_prefix);
2720 case CT_APPLICATION:
2721 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2724 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2732 * Iterator telling new CORE client about all existing
2733 * connections to peers.
2735 * @param cls the new `struct TransportClient`
2736 * @param pid a connected peer
2737 * @param value the `struct Neighbour` with more information
2738 * @return #GNUNET_OK (continue to iterate)
2741 notify_client_connect_info (void *cls,
2742 const struct GNUNET_PeerIdentity *pid,
2745 struct TransportClient *tc = cls;
2746 struct Neighbour *neighbour = value;
2748 core_send_connect_info (tc, pid, neighbour->quota_out);
2754 * Initialize a "CORE" client. We got a start message from this
2755 * client, so add it to the list of clients for broadcasting of
2758 * @param cls the client
2759 * @param start the start message that was sent
2762 handle_client_start (void *cls, const struct StartMessage *start)
2764 struct TransportClient *tc = cls;
2767 options = ntohl (start->options);
2768 if ((0 != (1 & options)) &&
2769 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
2771 /* client thinks this is a different peer, reject */
2773 GNUNET_SERVICE_client_drop (tc->client);
2776 if (CT_NONE != tc->type)
2779 GNUNET_SERVICE_client_drop (tc->client);
2783 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2784 ¬ify_client_connect_info,
2786 GNUNET_SERVICE_client_continue (tc->client);
2791 * Client asked for transmission to a peer. Process the request.
2793 * @param cls the client
2794 * @param obm the send message that was sent
2797 check_client_send (void *cls, const struct OutboundMessage *obm)
2799 struct TransportClient *tc = cls;
2801 const struct GNUNET_MessageHeader *obmm;
2803 if (CT_CORE != tc->type)
2806 return GNUNET_SYSERR;
2808 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2809 if (size < sizeof (struct GNUNET_MessageHeader))
2812 return GNUNET_SYSERR;
2814 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2815 if (size != ntohs (obmm->size))
2818 return GNUNET_SYSERR;
2825 * Free fragment tree below @e root, excluding @e root itself.
2827 * @param root root of the tree to free
2830 free_fragment_tree (struct PendingMessage *root)
2832 struct PendingMessage *frag;
2834 while (NULL != (frag = root->head_frag))
2836 free_fragment_tree (frag);
2837 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2844 * Release memory associated with @a pm and remove @a pm from associated
2845 * data structures. @a pm must be a top-level pending message and not
2846 * a fragment in the tree. The entire tree is freed (if applicable).
2848 * @param pm the pending message to free
2851 free_pending_message (struct PendingMessage *pm)
2853 struct TransportClient *tc = pm->client;
2854 struct Neighbour *target = pm->target;
2858 GNUNET_CONTAINER_MDLL_remove (client,
2859 tc->details.core.pending_msg_head,
2860 tc->details.core.pending_msg_tail,
2863 GNUNET_CONTAINER_MDLL_remove (neighbour,
2864 target->pending_msg_head,
2865 target->pending_msg_tail,
2867 free_fragment_tree (pm);
2868 GNUNET_free_non_null (pm->bpm);
2874 * Send a response to the @a pm that we have processed a
2875 * "send" request with status @a success. We
2876 * transmitted @a bytes_physical on the actual wire.
2877 * Sends a confirmation to the "core" client responsible
2878 * for the original request and free's @a pm.
2880 * @param pm handle to the original pending message
2881 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2882 * for transmission failure
2883 * @param bytes_physical amount of bandwidth consumed
2886 client_send_response (struct PendingMessage *pm,
2888 uint32_t bytes_physical)
2890 struct TransportClient *tc = pm->client;
2891 struct Neighbour *target = pm->target;
2892 struct GNUNET_MQ_Envelope *env;
2893 struct SendOkMessage *som;
2897 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2898 som->success = htonl ((uint32_t) success);
2899 som->bytes_msg = htons (pm->bytes_msg);
2900 som->bytes_physical = htonl (bytes_physical);
2901 som->peer = target->pid;
2902 GNUNET_MQ_send (tc->mq, env);
2904 free_pending_message (pm);
2909 * Checks the message queue for a neighbour for messages that have timed
2910 * out and purges them.
2912 * @param cls a `struct Neighbour`
2915 check_queue_timeouts (void *cls)
2917 struct Neighbour *n = cls;
2918 struct PendingMessage *pm;
2919 struct GNUNET_TIME_Absolute now;
2920 struct GNUNET_TIME_Absolute earliest_timeout;
2922 n->timeout_task = NULL;
2923 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2924 now = GNUNET_TIME_absolute_get ();
2925 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
2927 pm = pos->next_neighbour;
2928 if (pos->timeout.abs_value_us <= now.abs_value_us)
2930 GNUNET_STATISTICS_update (GST_stats,
2931 "# messages dropped (timeout before confirmation)",
2934 client_send_response (pm, GNUNET_NO, 0);
2938 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
2940 n->earliest_timeout = earliest_timeout;
2941 if (NULL != n->pending_msg_head)
2943 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
2948 * Client asked for transmission to a peer. Process the request.
2950 * @param cls the client
2951 * @param obm the send message that was sent
2954 handle_client_send (void *cls, const struct OutboundMessage *obm)
2956 struct TransportClient *tc = cls;
2957 struct PendingMessage *pm;
2958 const struct GNUNET_MessageHeader *obmm;
2959 struct Neighbour *target;
2963 GNUNET_assert (CT_CORE == tc->type);
2964 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2965 bytes_msg = ntohs (obmm->size);
2966 target = lookup_neighbour (&obm->peer);
2969 /* Failure: don't have this peer as a neighbour (anymore).
2970 Might have gone down asynchronously, so this is NOT
2971 a protocol violation by CORE. Still count the event,
2972 as this should be rare. */
2973 struct GNUNET_MQ_Envelope *env;
2974 struct SendOkMessage *som;
2976 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2977 som->success = htonl (GNUNET_SYSERR);
2978 som->bytes_msg = htonl (bytes_msg);
2979 som->bytes_physical = htonl (0);
2980 som->peer = obm->peer;
2981 GNUNET_MQ_send (tc->mq, env);
2982 GNUNET_SERVICE_client_continue (tc->client);
2983 GNUNET_STATISTICS_update (GST_stats,
2984 "# messages dropped (neighbour unknown)",
2989 was_empty = (NULL == target->pending_msg_head);
2990 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2992 pm->target = target;
2993 pm->bytes_msg = bytes_msg;
2995 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2996 memcpy (&pm[1], &obm[1], bytes_msg);
2997 GNUNET_CONTAINER_MDLL_insert (neighbour,
2998 target->pending_msg_head,
2999 target->pending_msg_tail,
3001 GNUNET_CONTAINER_MDLL_insert (client,
3002 tc->details.core.pending_msg_head,
3003 tc->details.core.pending_msg_tail,
3005 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3007 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3008 if (NULL != target->timeout_task)
3009 GNUNET_SCHEDULER_cancel (target->timeout_task);
3010 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3011 &check_queue_timeouts,
3015 return; /* all queues must already be busy */
3016 for (struct Queue *queue = target->queue_head; NULL != queue;
3017 queue = queue->next_neighbour)
3019 /* try transmission on any queue that is idle */
3020 if (NULL == queue->transmit_task)
3021 queue->transmit_task =
3022 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3028 * Communicator started. Test message is well-formed.
3030 * @param cls the client
3031 * @param cam the send message that was sent
3034 check_communicator_available (
3036 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3038 struct TransportClient *tc = cls;
3041 if (CT_NONE != tc->type)
3044 return GNUNET_SYSERR;
3046 tc->type = CT_COMMUNICATOR;
3047 size = ntohs (cam->header.size) - sizeof (*cam);
3049 return GNUNET_OK; /* receive-only communicator */
3050 GNUNET_MQ_check_zero_termination (cam);
3056 * Communicator started. Process the request.
3058 * @param cls the client
3059 * @param cam the send message that was sent
3062 handle_communicator_available (
3064 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3066 struct TransportClient *tc = cls;
3069 size = ntohs (cam->header.size) - sizeof (*cam);
3071 return; /* receive-only communicator */
3072 tc->details.communicator.address_prefix =
3073 GNUNET_strdup ((const char *) &cam[1]);
3074 tc->details.communicator.cc =
3075 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3076 GNUNET_SERVICE_client_continue (tc->client);
3081 * Communicator requests backchannel transmission. Check the request.
3083 * @param cls the client
3084 * @param cb the send message that was sent
3085 * @return #GNUNET_OK if message is well-formed
3088 check_communicator_backchannel (
3090 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3092 const struct GNUNET_MessageHeader *inbox;
3098 msize = ntohs (cb->header.size) - sizeof (*cb);
3099 if (UINT16_MAX - msize >
3100 sizeof (struct TransportBackchannelEncapsulationMessage) +
3101 sizeof (struct TransportBackchannelRequestPayload))
3104 return GNUNET_SYSERR;
3106 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3107 isize = ntohs (inbox->size);
3111 return GNUNET_SYSERR;
3113 is = (const char *) inbox;
3116 GNUNET_assert (msize > 0);
3117 if ('\0' != is[msize - 1])
3120 return GNUNET_SYSERR;
3127 * Remove memory used by expired ephemeral keys.
3132 expire_ephemerals (void *cls)
3134 struct EphemeralCacheEntry *ece;
3137 ephemeral_task = NULL;
3138 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3140 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3143 free_ephemeral (ece);
3146 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3155 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3156 * one, cache it and return it.
3158 * @param pid peer to look up ephemeral for
3159 * @param private_key[out] set to the private key
3160 * @param ephemeral_key[out] set to the key
3161 * @param ephemeral_sender_sig[out] set to the signature
3162 * @param ephemeral_validity[out] set to the validity expiration time
3165 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3166 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3167 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3168 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3169 struct GNUNET_TIME_Absolute *ephemeral_validity)
3171 struct EphemeralCacheEntry *ece;
3172 struct EphemeralConfirmation ec;
3174 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3175 if ((NULL != ece) &&
3176 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3179 free_ephemeral (ece);
3184 ece = GNUNET_new (struct EphemeralCacheEntry);
3186 ece->ephemeral_validity =
3187 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3188 EPHEMERAL_VALIDITY);
3189 GNUNET_assert (GNUNET_OK ==
3190 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3191 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3192 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3193 ec.purpose.size = htonl (sizeof (ec));
3195 ec.ephemeral_key = ece->ephemeral_key;
3196 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3200 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3202 ece->ephemeral_validity.abs_value_us);
3203 GNUNET_assert (GNUNET_OK ==
3204 GNUNET_CONTAINER_multipeermap_put (
3208 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3209 if (NULL == ephemeral_task)
3210 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3214 *private_key = ece->private_key;
3215 *ephemeral_key = ece->ephemeral_key;
3216 *ephemeral_sender_sig = ece->sender_sig;
3217 *ephemeral_validity = ece->ephemeral_validity;
3222 * Send the control message @a payload on @a queue.
3224 * @param queue the queue to use for transmission
3225 * @param pm pending message to update once transmission is done, may be NULL!
3226 * @param payload the payload to send (encapsulated in a
3227 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3228 * @param payload_size number of bytes in @a payload
3231 queue_send_msg (struct Queue *queue,
3232 struct PendingMessage *pm,
3233 const void *payload,
3234 size_t payload_size)
3236 struct Neighbour *n = queue->neighbour;
3237 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3238 struct GNUNET_MQ_Envelope *env;
3240 env = GNUNET_MQ_msg_extra (smt,
3242 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3243 smt->qid = queue->qid;
3244 smt->mid = queue->mid_gen;
3245 smt->receiver = n->pid;
3246 memcpy (&smt[1], payload, payload_size);
3248 /* Pass the env to the communicator of queue for transmission. */
3249 struct QueueEntry *qe;
3251 qe = GNUNET_new (struct QueueEntry);
3252 qe->mid = queue->mid_gen++;
3254 // qe->pm = pm; // FIXME: not so easy, reference management on 'free(s)'!
3255 // (also, note that pm may be NULL!)
3256 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3257 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3258 queue->queue_length++;
3259 queue->tc->details.communicator.total_queue_length++;
3260 GNUNET_MQ_send (queue->tc->mq, env);
3266 * Which transmission options are allowable for transmission?
3267 * Interpreted bit-wise!
3269 enum RouteMessageOptions
3272 * Only confirmed, non-DV direct neighbours.
3277 * We are allowed to use DV routing for this @a hdr
3282 * We are allowed to use unconfirmed queues or DV routes for this message
3284 RMO_UNCONFIRMED_ALLOWED = 2,
3287 * Reliable and unreliable, DV and non-DV are all acceptable.
3289 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
3292 * If we have multiple choices, it is OK to send this message
3293 * over multiple channels at the same time to improve loss tolerance.
3294 * (We do at most 2 transmissions.)
3301 * Pick a queue of @a n under constraints @a options and schedule
3302 * transmission of @a hdr.
3304 * @param n neighbour to send to
3305 * @param hdr message to send as payload
3306 * @param options whether queues must be confirmed or not,
3307 * and whether we may pick multiple (2) queues
3310 route_via_neighbour (const struct Neighbour *n,
3311 const struct GNUNET_MessageHeader *hdr,
3312 enum RouteMessageOptions options)
3314 struct GNUNET_TIME_Absolute now;
3315 unsigned int candidates;
3319 /* Pick one or two 'random' queues from n (under constraints of options) */
3320 now = GNUNET_TIME_absolute_get ();
3321 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
3322 weight in the future; weight could be assigned by observed
3323 bandwidth (note: not sure if we should do this for this type
3324 of control traffic though). */
3326 for (struct Queue *pos = n->queue_head; NULL != pos;
3327 pos = pos->next_neighbour)
3329 /* Count the queue with the visibility task in all cases, as
3330 otherwise we may end up with no queues just because the
3331 time for the visibility task just expired but the scheduler
3332 just ran this task first */
3333 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
3334 (pos->validated_until.abs_value_us > now.abs_value_us) ||
3335 (NULL != pos->visibility_task))
3338 if (0 == candidates)
3340 /* Given that we above check for pos->visibility task,
3341 this should be strictly impossible. */
3345 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3346 if (0 == (options & RMO_REDUNDANT))
3347 sel2 = candidates; /* picks none! */
3349 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3351 for (struct Queue *pos = n->queue_head; NULL != pos;
3352 pos = pos->next_neighbour)
3354 /* Count the queue with the visibility task in all cases, as
3355 otherwise we may end up with no queues just because the
3356 time for the visibility task just expired but the scheduler
3357 just ran this task first */
3358 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
3359 (NULL != pos->visibility_task))
3361 if ((sel1 == candidates) || (sel2 == candidates))
3362 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
3370 * Given a distance vector path @a dvh route @a payload to
3371 * the ultimate destination respecting @a options.
3372 * Sets up the boxed message and queues it at the next hop.
3374 * @param dvh choice of the path for the message
3375 * @param payload body to transmit
3376 * @param options options to use for control
3379 forward_via_dvh (const struct DistanceVectorHop *dvh,
3380 const struct GNUNET_MessageHeader *payload,
3381 enum RouteMessageOptions options)
3383 uint16_t mlen = ntohs (payload->size);
3384 char boxram[sizeof (struct TransportDVBox) +
3385 (dvh->distance + 1) * sizeof (struct GNUNET_PeerIdentity) +
3387 struct TransportDVBox *box = (struct TransportDVBox *) boxram;
3388 struct GNUNET_PeerIdentity *path = (struct GNUNET_PeerIdentity *) &box[1];
3390 box->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3391 box->header.size = htons (sizeof (boxram));
3392 box->total_hops = htons (0);
3393 box->num_hops = htons (dvh->distance + 1);
3394 box->origin = GST_my_identity;
3395 memcpy (path, dvh->path, dvh->distance * sizeof (struct GNUNET_PeerIdentity));
3396 path[dvh->distance] = dvh->dv->target;
3397 memcpy (&path[dvh->distance + 1], payload, mlen);
3398 route_via_neighbour (dvh->next_hop, &box->header, options);
3403 * Pick a path of @a dv under constraints @a options and schedule
3404 * transmission of @a hdr.
3406 * @param n neighbour to send to
3407 * @param hdr message to send as payload
3408 * @param options whether path must be confirmed or not
3409 * and whether we may pick multiple (2) paths
3412 route_via_dv (const struct DistanceVector *dv,
3413 const struct GNUNET_MessageHeader *hdr,
3414 enum RouteMessageOptions options)
3416 struct DistanceVectorHop *h1;
3417 struct DistanceVectorHop *h2;
3422 /* Pick random vectors, but weighted by distance, giving more weight
3423 to shorter vectors */
3425 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3428 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3429 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3430 .rel_value_us == 0))
3431 continue; /* pos unconfirmed and confirmed required */
3432 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3439 choice1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3440 choice2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3444 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3447 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3449 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3450 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3451 .rel_value_us == 0))
3452 continue; /* pos unconfirmed and confirmed required */
3453 if ((num_dv <= choice1) && (num_dv + delta > choice1))
3455 if ((num_dv <= choice2) && (num_dv + delta > choice2))
3459 forward_via_dvh (h1, hdr, options & (~RMO_REDUNDANT));
3460 if (0 == (options & RMO_REDUNDANT))
3461 forward_via_dvh (h2, hdr, options & (~RMO_REDUNDANT));
3466 * We need to transmit @a hdr to @a target. If necessary, this may
3467 * involve DV routing.
3469 * @param target peer to receive @a hdr
3470 * @param hdr header of the message to route and #GNUNET_free()
3471 * @param options which transmission channels are allowed
3474 route_message (const struct GNUNET_PeerIdentity *target,
3475 struct GNUNET_MessageHeader *hdr,
3476 enum RouteMessageOptions options)
3478 struct Neighbour *n;
3479 struct DistanceVector *dv;
3481 n = GNUNET_CONTAINER_multipeermap_get (neighbours, target);
3482 dv = (0 != (options & RMO_DV_ALLOWED))
3483 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
3485 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
3487 /* if confirmed is required, and we do not have anything
3488 confirmed, drop respective options */
3489 if ((NULL != n) && (GNUNET_NO == n->core_visible))
3491 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
3494 if ((NULL == n) && (NULL == dv))
3496 GNUNET_STATISTICS_update (GST_stats,
3497 "# Messages dropped in routing: no acceptable method",
3503 /* If both dv and n are possible and we must choose:
3504 flip a coin for the choice between the two; for now 50/50 */
3505 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
3507 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
3512 if ((NULL != n) && (NULL != dv))
3513 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
3514 enough for redunancy, so clear the flag. */
3517 route_via_neighbour (n, hdr, options);
3521 route_via_dv (dv, hdr, options);
3528 * Structure of the key material used to encrypt backchannel messages.
3530 struct BackchannelKeyState
3533 * State of our block cipher.
3535 gcry_cipher_hd_t cipher;
3538 * Actual key material.
3544 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3546 struct GNUNET_CRYPTO_AuthKey hmac_key;
3549 * Symmetric key to use for encryption.
3551 char aes_key[256 / 8];
3554 * Counter value to use during setup.
3556 char aes_ctr[128 / 8];
3563 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3564 const struct GNUNET_ShortHashCode *iv,
3565 struct BackchannelKeyState *key)
3567 /* must match #dh_key_derive_eph_pub */
3568 GNUNET_assert (GNUNET_YES ==
3569 GNUNET_CRYPTO_kdf (&key->material,
3570 sizeof (key->material),
3571 "transport-backchannel-key",
3572 strlen ("transport-backchannel-key"),
3577 gcry_cipher_open (&key->cipher,
3578 GCRY_CIPHER_AES256 /* low level: go for speed */,
3579 GCRY_CIPHER_MODE_CTR,
3581 gcry_cipher_setkey (key->cipher,
3582 &key->material.aes_key,
3583 sizeof (key->material.aes_key));
3584 gcry_cipher_setctr (key->cipher,
3585 &key->material.aes_ctr,
3586 sizeof (key->material.aes_ctr));
3591 * Derive backchannel encryption key material from @a priv_ephemeral
3592 * and @a target and @a iv.
3594 * @param priv_ephemeral ephemeral private key to use
3595 * @param target the target peer to encrypt to
3596 * @param iv unique IV to use
3597 * @param key[out] set to the key material
3600 dh_key_derive_eph_pid (
3601 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3602 const struct GNUNET_PeerIdentity *target,
3603 const struct GNUNET_ShortHashCode *iv,
3604 struct BackchannelKeyState *key)
3606 struct GNUNET_HashCode km;
3608 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3609 &target->public_key,
3611 bc_setup_key_state_from_km (&km, iv, key);
3616 * Derive backchannel encryption key material from #GST_my_private_key
3617 * and @a pub_ephemeral and @a iv.
3619 * @param priv_ephemeral ephemeral private key to use
3620 * @param target the target peer to encrypt to
3621 * @param iv unique IV to use
3622 * @param key[out] set to the key material
3625 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3626 const struct GNUNET_ShortHashCode *iv,
3627 struct BackchannelKeyState *key)
3629 struct GNUNET_HashCode km;
3631 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3634 bc_setup_key_state_from_km (&km, iv, key);
3639 * Do HMAC calculation for backchannel messages over @a data using key
3640 * material from @a key.
3642 * @param key key material (from DH)
3643 * @param hmac[out] set to the HMAC
3644 * @param data data to perform HMAC calculation over
3645 * @param data_size number of bytes in @a data
3648 bc_hmac (const struct BackchannelKeyState *key,
3649 struct GNUNET_HashCode *hmac,
3653 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
3658 * Perform backchannel encryption using symmetric secret in @a key
3659 * to encrypt data from @a in to @a dst.
3661 * @param key[in,out] key material to use
3662 * @param dst where to write the result
3663 * @param in input data to encrypt (plaintext)
3664 * @param in_size number of bytes of input in @a in and available at @a dst
3667 bc_encrypt (struct BackchannelKeyState *key,
3673 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
3678 * Perform backchannel encryption using symmetric secret in @a key
3679 * to encrypt data from @a in to @a dst.
3681 * @param key[in,out] key material to use
3682 * @param ciph cipher text to decrypt
3683 * @param out[out] output data to generate (plaintext)
3684 * @param out_size number of bytes of input in @a ciph and available in @a out
3687 bc_decrypt (struct BackchannelKeyState *key,
3693 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
3698 * Clean up key material in @a key.
3700 * @param key key material to clean up (memory must not be free'd!)
3703 bc_key_clean (struct BackchannelKeyState *key)
3705 gcry_cipher_close (key->cipher);
3706 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
3711 * Communicator requests backchannel transmission. Process the request.
3713 * @param cls the client
3714 * @param cb the send message that was sent
3717 handle_communicator_backchannel (
3719 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3721 struct TransportClient *tc = cls;
3722 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3723 struct GNUNET_TIME_Absolute ephemeral_validity;
3724 struct TransportBackchannelEncapsulationMessage *enc;
3725 struct TransportBackchannelRequestPayload ppay;
3726 struct BackchannelKeyState key;
3730 /* encapsulate and encrypt message */
3731 msize = ntohs (cb->header.size) - sizeof (*cb) +
3732 sizeof (struct TransportBackchannelRequestPayload);
3733 enc = GNUNET_malloc (sizeof (*enc) + msize);
3735 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3736 enc->header.size = htons (sizeof (*enc) + msize);
3737 enc->target = cb->pid;
3738 lookup_ephemeral (&cb->pid,
3740 &enc->ephemeral_key,
3742 &ephemeral_validity);
3743 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3746 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
3747 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3748 ppay.monotonic_time =
3749 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3750 mpos = (char *) &enc[1];
3751 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
3754 &mpos[sizeof (ppay)],
3755 ntohs (cb->header.size) - sizeof (*cb));
3759 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3760 bc_key_clean (&key);
3761 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
3762 GNUNET_SERVICE_client_continue (tc->client);
3767 * Address of our peer added. Test message is well-formed.
3769 * @param cls the client
3770 * @param aam the send message that was sent
3771 * @return #GNUNET_OK if message is well-formed
3774 check_add_address (void *cls,
3775 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3777 struct TransportClient *tc = cls;
3779 if (CT_COMMUNICATOR != tc->type)
3782 return GNUNET_SYSERR;
3784 GNUNET_MQ_check_zero_termination (aam);
3790 * Ask peerstore to store our address.
3792 * @param cls an `struct AddressListEntry *`
3795 store_pi (void *cls);
3799 * Function called when peerstore is done storing our address.
3801 * @param cls a `struct AddressListEntry`
3802 * @param success #GNUNET_YES if peerstore was successful
3805 peerstore_store_own_cb (void *cls, int success)
3807 struct AddressListEntry *ale = cls;
3810 if (GNUNET_YES != success)
3811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3812 "Failed to store our own address `%s' in peerstore!\n",
3814 /* refresh period is 1/4 of expiration time, that should be plenty
3815 without being excessive. */
3817 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3825 * Ask peerstore to store our address.
3827 * @param cls an `struct AddressListEntry *`
3830 store_pi (void *cls)
3832 struct AddressListEntry *ale = cls;
3835 struct GNUNET_TIME_Absolute expiration;
3838 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3839 GNUNET_HELLO_sign_address (ale->address,
3845 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3848 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3852 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3853 &peerstore_store_own_cb,
3856 if (NULL == ale->sc)
3858 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3859 "Failed to store our address `%s' with peerstore\n",
3862 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
3868 * Address of our peer added. Process the request.
3870 * @param cls the client
3871 * @param aam the send message that was sent
3874 handle_add_address (void *cls,
3875 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3877 struct TransportClient *tc = cls;
3878 struct AddressListEntry *ale;
3881 slen = ntohs (aam->header.size) - sizeof (*aam);
3882 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3884 ale->address = (const char *) &ale[1];
3885 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3886 ale->aid = aam->aid;
3887 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3888 memcpy (&ale[1], &aam[1], slen);
3889 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3890 tc->details.communicator.addr_tail,
3892 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
3893 GNUNET_SERVICE_client_continue (tc->client);
3898 * Address of our peer deleted. Process the request.
3900 * @param cls the client
3901 * @param dam the send message that was sent
3904 handle_del_address (void *cls,
3905 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3907 struct TransportClient *tc = cls;
3909 if (CT_COMMUNICATOR != tc->type)
3912 GNUNET_SERVICE_client_drop (tc->client);
3915 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3919 if (dam->aid != ale->aid)
3921 GNUNET_assert (ale->tc == tc);
3922 free_address_list_entry (ale);
3923 GNUNET_SERVICE_client_continue (tc->client);
3926 GNUNET_SERVICE_client_drop (tc->client);
3931 * Context from #handle_incoming_msg(). Closure for many
3932 * message handlers below.
3934 struct CommunicatorMessageContext
3937 * Which communicator provided us with the message.
3939 struct TransportClient *tc;
3942 * Additional information for flow control and about the sender.
3944 struct GNUNET_TRANSPORT_IncomingMessage im;
3947 * Number of hops the message has travelled (if DV-routed).
3948 * FIXME: make use of this in ACK handling!
3950 uint16_t total_hops;
3955 * Given an inbound message @a msg from a communicator @a cmc,
3956 * demultiplex it based on the type calling the right handler.
3958 * @param cmc context for demultiplexing
3959 * @param msg message to demultiplex
3962 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3963 const struct GNUNET_MessageHeader *msg);
3967 * Send ACK to communicator (if requested) and free @a cmc.
3969 * @param cmc context for which we are done handling the message
3972 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3974 if (0 != ntohl (cmc->im.fc_on))
3976 /* send ACK when done to communicator for flow control! */
3977 struct GNUNET_MQ_Envelope *env;
3978 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3980 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3981 ack->reserved = htonl (0);
3982 ack->fc_id = cmc->im.fc_id;
3983 ack->sender = cmc->im.sender;
3984 GNUNET_MQ_send (cmc->tc->mq, env);
3986 GNUNET_SERVICE_client_continue (cmc->tc->client);
3992 * Communicator gave us an unencapsulated message to pass as-is to
3993 * CORE. Process the request.
3995 * @param cls a `struct CommunicatorMessageContext` (must call
3996 * #finish_cmc_handling() when done)
3997 * @param mh the message that was received
4000 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4002 struct CommunicatorMessageContext *cmc = cls;
4003 uint16_t size = ntohs (mh->size);
4005 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4006 (size < sizeof (struct GNUNET_MessageHeader)))
4008 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4011 finish_cmc_handling (cmc);
4012 GNUNET_SERVICE_client_drop (client);
4015 /* Forward to all CORE clients */
4016 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4018 struct GNUNET_MQ_Envelope *env;
4019 struct InboundMessage *im;
4021 if (CT_CORE != tc->type)
4023 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4024 im->peer = cmc->im.sender;
4025 memcpy (&im[1], mh, size);
4026 GNUNET_MQ_send (tc->mq, env);
4028 /* FIXME: consider doing this _only_ once the message
4029 was drained from the CORE MQs to extend flow control to CORE!
4030 (basically, increment counter in cmc, decrement on MQ send continuation! */
4031 finish_cmc_handling (cmc);
4036 * Communicator gave us a fragment box. Check the message.
4038 * @param cls a `struct CommunicatorMessageContext`
4039 * @param fb the send message that was sent
4040 * @return #GNUNET_YES if message is well-formed
4043 check_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4045 uint16_t size = ntohs (fb->header.size);
4046 uint16_t bsize = size - sizeof (*fb);
4050 GNUNET_break_op (0);
4051 return GNUNET_SYSERR;
4053 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4055 GNUNET_break_op (0);
4056 return GNUNET_SYSERR;
4058 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4060 GNUNET_break_op (0);
4061 return GNUNET_SYSERR;
4068 * Generate a fragment acknowledgement for an @a rc.
4070 * @param rc context to generate ACK for, @a rc ACK state is reset
4073 send_fragment_ack (struct ReassemblyContext *rc)
4075 struct TransportFragmentAckMessage *ack;
4077 ack = GNUNET_new (struct TransportFragmentAckMessage);
4078 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
4079 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
4080 ack->frag_uuid = htonl (rc->frag_uuid);
4081 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
4082 ack->msg_uuid = rc->msg_uuid;
4083 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
4084 if (0 == rc->msg_missing)
4085 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4086 GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
4088 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4089 GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
4090 route_message (&rc->neighbour->pid, &ack->header, RMO_DV_ALLOWED);
4091 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
4093 rc->extra_acks = 0LLU;
4098 * Communicator gave us a fragment. Process the request.
4100 * @param cls a `struct CommunicatorMessageContext` (must call
4101 * #finish_cmc_handling() when done)
4102 * @param fb the message that was received
4105 handle_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4107 struct CommunicatorMessageContext *cmc = cls;
4108 struct Neighbour *n;
4109 struct ReassemblyContext *rc;
4110 const struct GNUNET_MessageHeader *msg;
4116 struct GNUNET_TIME_Relative cdelay;
4119 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4122 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4125 finish_cmc_handling (cmc);
4126 GNUNET_SERVICE_client_drop (client);
4129 if (NULL == n->reassembly_map)
4131 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_YES);
4132 n->reassembly_heap =
4133 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4134 n->reassembly_timeout_task =
4135 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4136 &reassembly_cleanup_task,
4139 msize = ntohs (fb->msg_size);
4140 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map, &fb->msg_uuid);
4143 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4144 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4145 rc->msg_uuid = fb->msg_uuid;
4147 rc->msg_size = msize;
4148 rc->reassembly_timeout =
4149 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4150 rc->last_frag = GNUNET_TIME_absolute_get ();
4151 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4153 rc->reassembly_timeout.abs_value_us);
4154 GNUNET_assert (GNUNET_OK ==
4155 GNUNET_CONTAINER_multishortmap_put (
4159 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4160 target = (char *) &rc[1];
4161 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4162 rc->msg_missing = rc->msg_size;
4166 target = (char *) &rc[1];
4168 if (msize != rc->msg_size)
4171 finish_cmc_handling (cmc);
4176 fsize = ntohs (fb->header.size) - sizeof (*fb);
4177 frag_off = ntohs (fb->frag_off);
4178 memcpy (&target[frag_off], &fb[1], fsize);
4179 /* update bitfield and msg_missing */
4180 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4182 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4184 rc->bitfield[i / 8] |= (1 << (i % 8));
4189 /* Compute cummulative ACK */
4190 frag_uuid = ntohl (fb->frag_uuid);
4191 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4192 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->num_acks);
4193 rc->last_frag = GNUNET_TIME_absolute_get ();
4194 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay, cdelay);
4195 ack_now = GNUNET_NO;
4196 if (0 == rc->num_acks)
4198 /* case one: first ack */
4199 rc->frag_uuid = frag_uuid;
4200 rc->extra_acks = 0LLU;
4203 else if ((frag_uuid >= rc->frag_uuid) && (frag_uuid <= rc->frag_uuid + 64))
4205 /* case two: ack fits after existing min UUID */
4206 if ((frag_uuid == rc->frag_uuid) ||
4207 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))))
4209 /* duplicate fragment, ack now! */
4210 ack_now = GNUNET_YES;
4214 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
4218 else if ((rc->frag_uuid > frag_uuid) &&
4219 (((rc->frag_uuid == frag_uuid + 64) && (0 == rc->extra_acks)) ||
4220 ((rc->frag_uuid < frag_uuid + 64) &&
4223 ~((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))))))
4225 /* can fit ack by shifting extra acks and starting at
4226 frag_uid, test above esured that the bits we will
4227 shift 'extra_acks' by are all zero. */
4228 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
4229 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
4230 rc->frag_uuid = frag_uuid;
4233 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very
4235 ack_now = GNUNET_YES; /* maximum acks received */
4236 // FIXME: possibly also ACK based on RTT (but for that we'd need to
4237 // determine the queue used for the ACK first!)
4239 /* is reassembly complete? */
4240 if (0 != rc->msg_missing)
4243 send_fragment_ack (rc);
4244 finish_cmc_handling (cmc);
4247 /* reassembly is complete, verify result */
4248 msg = (const struct GNUNET_MessageHeader *) &rc[1];
4249 if (ntohs (msg->size) != rc->msg_size)
4252 free_reassembly_context (rc);
4253 finish_cmc_handling (cmc);
4256 /* successful reassembly */
4257 send_fragment_ack (rc);
4258 demultiplex_with_cmc (cmc, msg);
4259 /* FIXME: really free here? Might be bad if fragments are still
4260 en-route and we forget that we finished this reassembly immediately!
4261 -> keep around until timeout?
4262 -> shorten timeout based on ACK? */
4263 free_reassembly_context (rc);
4268 * Check the @a fa against the fragments associated with @a pm.
4269 * If it matches, remove the matching fragments from the transmission
4272 * @param pm pending message to check against the ack
4273 * @param fa the ack that was received
4274 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4277 check_ack_against_pm (struct PendingMessage *pm,
4278 const struct TransportFragmentAckMessage *fa)
4281 struct PendingMessage *nxt;
4282 uint32_t fs = ntohl (fa->frag_uuid);
4283 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4286 for (struct PendingMessage *frag = pm->head_frag; NULL != frag; frag = nxt)
4288 const struct TransportFragmentBox *tfb =
4289 (const struct TransportFragmentBox *) &pm[1];
4290 uint32_t fu = ntohl (tfb->frag_uuid);
4292 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4293 nxt = frag->next_frag;
4294 /* Check for exact match or match in the 'xtra' bitmask */
4296 ((fu > fs) && (fu <= fs + 64) && (0 != (1LLU << (fu - fs - 1) & xtra))))
4299 free_fragment_tree (frag);
4307 * Communicator gave us a fragment acknowledgement. Process the request.
4309 * @param cls a `struct CommunicatorMessageContext` (must call
4310 * #finish_cmc_handling() when done)
4311 * @param fa the message that was received
4314 handle_fragment_ack (void *cls, const struct TransportFragmentAckMessage *fa)
4316 struct CommunicatorMessageContext *cmc = cls;
4317 struct Neighbour *n;
4320 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4323 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4326 finish_cmc_handling (cmc);
4327 GNUNET_SERVICE_client_drop (client);
4330 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4331 matched = GNUNET_NO;
4332 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm;
4333 pm = pm->prev_neighbour)
4335 if (0 != GNUNET_memcmp (&fa->msg_uuid, &pm->msg_uuid))
4337 matched = GNUNET_YES;
4338 if (GNUNET_YES == check_ack_against_pm (pm, fa))
4340 struct GNUNET_TIME_Relative avg_ack_delay =
4341 GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4342 // FIXME: update RTT and other reliability data!
4343 // ISSUE: we don't know which of n's queues the message(s)
4344 // took (and in fact the different messages might have gone
4345 // over different queues and possibly over multiple).
4346 // => track queues with PendingMessages, and update RTT only if
4347 // the queue used is unique?
4348 // -> how can we get loss rates?
4349 // -> or, add extra state to Box and ACK to identify queue?
4350 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4351 // the queue with the fragment! (-> this logic must
4352 // be moved into check_ack_against_pm!)
4353 (void) avg_ack_delay;
4357 GNUNET_STATISTICS_update (GST_stats,
4358 "# FRAGMENT_ACKS dropped, no matching fragment",
4362 if (NULL == pm->head_frag)
4364 // if entire message is ACKed, handle that as well.
4365 // => clean up PM, any post actions?
4366 free_pending_message (pm);
4370 struct GNUNET_TIME_Relative reassembly_timeout =
4371 GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4372 // OPTIMIZE-FIXME: adjust retransmission strategy based on
4373 // reassembly_timeout!
4374 (void) reassembly_timeout;
4378 if (GNUNET_NO == matched)
4380 GNUNET_STATISTICS_update (GST_stats,
4381 "# FRAGMENT_ACKS dropped, no matching pending message",
4385 finish_cmc_handling (cmc);
4390 * Communicator gave us a reliability box. Check the message.
4392 * @param cls a `struct CommunicatorMessageContext`
4393 * @param rb the send message that was sent
4394 * @return #GNUNET_YES if message is well-formed
4397 check_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4399 GNUNET_MQ_check_boxed_message (rb);
4405 * Communicator gave us a reliability box. Process the request.
4407 * @param cls a `struct CommunicatorMessageContext` (must call
4408 * #finish_cmc_handling() when done)
4409 * @param rb the message that was received
4412 handle_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4414 struct CommunicatorMessageContext *cmc = cls;
4415 const struct GNUNET_MessageHeader *inbox =
4416 (const struct GNUNET_MessageHeader *) &rb[1];
4418 if (0 == ntohl (rb->ack_countdown))
4420 struct TransportReliabilityAckMessage *ack;
4422 /* FIXME: implement cummulative ACKs and ack_countdown,
4423 then setting the avg_ack_delay field below: */
4424 ack = GNUNET_malloc (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4425 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4427 htons (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4428 memcpy (&ack[1], &rb->msg_uuid, sizeof (struct GNUNET_ShortHashCode));
4429 route_message (&cmc->im.sender, &ack->header, RMO_DV_ALLOWED);
4431 /* continue with inner message */
4432 demultiplex_with_cmc (cmc, inbox);
4437 * Communicator gave us a reliability ack. Process the request.
4439 * @param cls a `struct CommunicatorMessageContext` (must call
4440 * #finish_cmc_handling() when done)
4441 * @param ra the message that was received
4444 handle_reliability_ack (void *cls,
4445 const struct TransportReliabilityAckMessage *ra)
4447 struct CommunicatorMessageContext *cmc = cls;
4448 struct Neighbour *n;
4449 unsigned int n_acks;
4450 const struct GNUNET_ShortHashCode *msg_uuids;
4451 struct PendingMessage *nxt;
4454 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4457 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4460 finish_cmc_handling (cmc);
4461 GNUNET_SERVICE_client_drop (client);
4464 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
4465 sizeof (struct GNUNET_ShortHashCode);
4466 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4468 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4469 matched = GNUNET_NO;
4470 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm; pm = nxt)
4474 nxt = pm->next_neighbour;
4475 in_list = GNUNET_NO;
4476 for (unsigned int i = 0; i < n_acks; i++)
4478 if (0 != GNUNET_memcmp (&msg_uuids[i], &pm->msg_uuid))
4480 in_list = GNUNET_YES;
4483 if (GNUNET_NO == in_list)
4486 /* this pm was acked! */
4487 matched = GNUNET_YES;
4488 free_pending_message (pm);
4491 struct GNUNET_TIME_Relative avg_ack_delay =
4492 GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4493 // FIXME: update RTT and other reliability data!
4494 // ISSUE: we don't know which of n's queues the message(s)
4495 // took (and in fact the different messages might have gone
4496 // over different queues and possibly over multiple).
4497 // => track queues with PendingMessages, and update RTT only if
4498 // the queue used is unique?
4499 // -> how can we get loss rates?
4500 // -> or, add extra state to MSG and ACKs to identify queue?
4501 // -> if we do this, might just do the same for the avg_ack_delay!
4502 (void) avg_ack_delay;
4505 if (GNUNET_NO == matched)
4507 GNUNET_STATISTICS_update (GST_stats,
4508 "# FRAGMENT_ACKS dropped, no matching pending message",
4512 finish_cmc_handling (cmc);
4517 * Communicator gave us a backchannel encapsulation. Check the message.
4519 * @param cls a `struct CommunicatorMessageContext`
4520 * @param be the send message that was sent
4521 * @return #GNUNET_YES if message is well-formed
4524 check_backchannel_encapsulation (
4526 const struct TransportBackchannelEncapsulationMessage *be)
4528 uint16_t size = ntohs (be->header.size);
4531 if ((size - sizeof (*be)) <
4532 (sizeof (struct TransportBackchannelRequestPayload) +
4533 sizeof (struct GNUNET_MessageHeader)))
4535 GNUNET_break_op (0);
4536 return GNUNET_SYSERR;
4543 * Communicator gave us a backchannel encapsulation. Process the request.
4544 * (We are not the origin of the backchannel here, the communicator simply
4545 * received a backchannel message and we are expected to forward it.)
4547 * @param cls a `struct CommunicatorMessageContext` (must call
4548 * #finish_cmc_handling() when done)
4549 * @param be the message that was received
4552 handle_backchannel_encapsulation (
4554 const struct TransportBackchannelEncapsulationMessage *be)
4556 struct CommunicatorMessageContext *cmc = cls;
4557 struct BackchannelKeyState key;
4558 struct GNUNET_HashCode hmac;
4562 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
4564 /* not for me, try to route to target */
4565 /* FIXME: someone needs to update be->distance! */
4566 /* FIXME: BE routing can be special, should we put all of this
4567 on 'route_message'? Maybe at least pass some more arguments? */
4568 route_message (&be->target,
4569 GNUNET_copy_message (&be->header),
4571 finish_cmc_handling (cmc);
4574 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
4575 hdr = (const char *) &be[1];
4576 hdr_len = ntohs (be->header.size) - sizeof (*be);
4577 bc_hmac (&key, &hmac, hdr, hdr_len);
4578 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
4580 /* HMAC missmatch, disard! */
4581 GNUNET_break_op (0);
4582 finish_cmc_handling (cmc);
4585 /* begin actual decryption */
4587 struct TransportBackchannelRequestPayload ppay;
4588 char body[hdr_len - sizeof (ppay)];
4590 GNUNET_assert (hdr_len >=
4591 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4592 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
4593 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
4594 bc_key_clean (&key);
4595 // FIXME: verify signatures in ppay!
4596 // => check if ephemeral key is known & valid, if not
4597 // => verify sig, cache ephemeral key
4598 // => update monotonic_time of sender for replay detection
4600 // FIXME: forward to specified communicator!
4601 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4603 finish_cmc_handling (cmc);
4608 * Task called when we should check if any of the DV paths
4609 * we have learned to a target are due for garbage collection.
4611 * Collects stale paths, and possibly frees the entire DV
4612 * entry if no paths are left. Otherwise re-schedules itself.
4614 * @param cls a `struct DistanceVector`
4617 path_cleanup_cb (void *cls)
4619 struct DistanceVector *dv = cls;
4620 struct DistanceVectorHop *pos;
4622 dv->timeout_task = NULL;
4623 while (NULL != (pos = dv->dv_head))
4625 GNUNET_assert (dv == pos->dv);
4626 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4628 free_distance_vector_hop (pos);
4636 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
4640 * Task run to check whether the hops of the @a cls still
4641 * are validated, or if we need to core about disconnection.
4643 * @param cls a `struct DistanceVector` (with core_visible set!)
4646 check_dv_path_down (void *cls)
4648 struct DistanceVector *dv = cls;
4649 struct Neighbour *n;
4651 dv->visibility_task = NULL;
4652 GNUNET_assert (GNUNET_YES == dv->core_visible);
4653 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4657 GNUNET_TIME_absolute_get_remaining (pos->path_valid_until).rel_value_us)
4659 dv->visibility_task = GNUNET_SCHEDULER_add_at (pos->path_valid_until,
4660 &check_dv_path_down,
4665 /* all paths invalid, make dv core-invisible */
4666 dv->core_visible = GNUNET_NO;
4667 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
4668 if ((NULL != n) && (GNUNET_YES == n->core_visible))
4669 return; /* no need to tell core, connection still up! */
4670 cores_send_disconnect_info (&dv->target);
4675 * The @a hop is a validated path to the respective target
4676 * peer and we should tell core about it -- and schedule
4677 * a job to revoke the state.
4679 * @param hop a path to some peer that is the reason for activation
4682 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
4684 struct DistanceVector *dv = hop->dv;
4685 struct Neighbour *n;
4687 GNUNET_assert (GNUNET_NO == dv->core_visible);
4688 GNUNET_assert (NULL == dv->visibility_task);
4690 dv->core_visible = GNUNET_YES;
4691 dv->visibility_task =
4692 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_dv_path_down, dv);
4693 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
4694 if ((NULL != n) && (GNUNET_YES == n->core_visible))
4695 return; /* no need to tell core, connection already up! */
4696 cores_send_connect_info (&dv->target,
4698 ? GNUNET_BANDWDITH_value_sum (n->quota_out,
4705 * We have learned a @a path through the network to some other peer, add it to
4706 * our DV data structure (returning #GNUNET_YES on success).
4708 * We do not add paths if we have a sufficient number of shorter
4709 * paths to this target already (returning #GNUNET_NO).
4711 * We also do not add problematic paths, like those where we lack the first
4712 * hop in our neighbour list (i.e. due to a topology change) or where some
4713 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4715 * @param path the path we learned, path[0] should be us,
4716 * and then path contains a valid path from us to `path[path_len-1]`
4717 * path[1] should be a direct neighbour (we should check!)
4718 * @param path_len number of entries on the @a path, at least three!
4719 * @param network_latency how long does the message take from us to
4720 * `path[path_len-1]`? set to "forever" if unknown
4721 * @param path_valid_until how long is this path considered validated? Maybe be
4723 * @return #GNUNET_YES on success,
4724 * #GNUNET_NO if we have better path(s) to the target
4725 * #GNUNET_SYSERR if the path is useless and/or invalid
4726 * (i.e. path[1] not a direct neighbour
4727 * or path[i+1] is a direct neighbour for i>0)
4730 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4731 unsigned int path_len,
4732 struct GNUNET_TIME_Relative network_latency,
4733 struct GNUNET_TIME_Absolute path_valid_until)
4735 struct DistanceVectorHop *hop;
4736 struct DistanceVector *dv;
4737 struct Neighbour *next_hop;
4738 unsigned int shorter_distance;
4742 /* what a boring path! not allowed! */
4744 return GNUNET_SYSERR;
4746 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
4747 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours, &path[1]);
4748 if (NULL == next_hop)
4750 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4752 return GNUNET_SYSERR;
4754 for (unsigned int i = 2; i < path_len; i++)
4755 if (NULL != GNUNET_CONTAINER_multipeermap_get (neighbours, &path[i]))
4757 /* Useless path, we have a direct connection to some hop
4758 in the middle of the path, so this one doesn't even
4759 seem terribly useful for redundancy */
4760 return GNUNET_SYSERR;
4762 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
4765 dv = GNUNET_new (struct DistanceVector);
4766 dv->target = path[path_len - 1];
4767 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4770 GNUNET_assert (GNUNET_OK ==
4771 GNUNET_CONTAINER_multipeermap_put (
4775 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4777 /* Check if we have this path already! */
4778 shorter_distance = 0;
4779 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4782 if (pos->distance < path_len - 2)
4784 /* Note that the distances in 'pos' excludes us (path[0]) and
4785 the next_hop (path[1]), so we need to subtract two
4786 and check next_hop explicitly */
4787 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
4789 int match = GNUNET_YES;
4791 for (unsigned int i = 0; i < pos->distance; i++)
4793 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
4799 if (GNUNET_YES == match)
4801 struct GNUNET_TIME_Relative last_timeout;
4803 /* Re-discovered known path, update timeout */
4804 GNUNET_STATISTICS_update (GST_stats,
4805 "# Known DV path refreshed",
4808 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4810 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4811 pos->path_valid_until =
4812 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
4813 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
4814 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
4815 if ((GNUNET_NO == dv->core_visible) &&
4816 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until)
4818 activate_core_visible_dv_path (pos);
4819 if (last_timeout.rel_value_us <
4820 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4821 DV_PATH_DISCOVERY_FREQUENCY)
4824 /* Some peer send DV learn messages too often, we are learning
4825 the same path faster than it would be useful; do not forward! */
4832 /* Count how many shorter paths we have (incl. direct
4833 neighbours) before simply giving up on this one! */
4834 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4836 /* We have a shorter path already! */
4839 /* create new DV path entry */
4840 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4841 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4842 hop->next_hop = next_hop;
4844 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4847 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4848 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4849 hop->path_valid_until = path_valid_until;
4850 hop->distance = path_len - 2;
4851 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
4852 GNUNET_CONTAINER_MDLL_insert (neighbour,
4856 if ((GNUNET_NO == dv->core_visible) &&
4857 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us))
4858 activate_core_visible_dv_path (hop);
4864 * Communicator gave us a DV learn message. Check the message.
4866 * @param cls a `struct CommunicatorMessageContext`
4867 * @param dvl the send message that was sent
4868 * @return #GNUNET_YES if message is well-formed
4871 check_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4873 uint16_t size = ntohs (dvl->header.size);
4874 uint16_t num_hops = ntohs (dvl->num_hops);
4875 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4878 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4880 GNUNET_break_op (0);
4881 return GNUNET_SYSERR;
4883 if (num_hops > MAX_DV_HOPS_ALLOWED)
4885 GNUNET_break_op (0);
4886 return GNUNET_SYSERR;
4888 for (unsigned int i = 0; i < num_hops; i++)
4890 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
4892 GNUNET_break_op (0);
4893 return GNUNET_SYSERR;
4895 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
4897 GNUNET_break_op (0);
4898 return GNUNET_SYSERR;
4906 * Build and forward a DV learn message to @a next_hop.
4908 * @param next_hop peer to send the message to
4909 * @param msg message received
4910 * @param bi_history bitmask specifying hops on path that were bidirectional
4911 * @param nhops length of the @a hops array
4912 * @param hops path the message traversed so far
4913 * @param in_time when did we receive the message, used to calculate network
4917 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4918 const struct TransportDVLearn *msg,
4919 uint16_t bi_history,
4921 const struct DVPathEntryP *hops,
4922 struct GNUNET_TIME_Absolute in_time)
4924 struct DVPathEntryP *dhops;
4925 struct TransportDVLearn *fwd;
4926 struct GNUNET_TIME_Relative nnd;
4928 /* compute message for forwarding */
4929 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4930 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4931 (nhops + 1) * sizeof (struct DVPathEntryP));
4932 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4933 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4934 (nhops + 1) * sizeof (struct DVPathEntryP));
4935 fwd->num_hops = htons (nhops + 1);
4936 fwd->bidirectional = htons (bi_history);
4937 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4938 GNUNET_TIME_relative_ntoh (
4939 msg->non_network_delay));
4940 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4941 fwd->init_sig = msg->init_sig;
4942 fwd->initiator = msg->initiator;
4943 fwd->challenge = msg->challenge;
4944 dhops = (struct DVPathEntryP *) &fwd[1];
4945 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
4946 dhops[nhops].hop = GST_my_identity;
4948 struct DvHopPS dhp = {.purpose.purpose =
4949 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4950 .purpose.size = htonl (sizeof (dhp)),
4951 .pred = dhops[nhops - 1].hop,
4953 .challenge = msg->challenge};
4955 GNUNET_assert (GNUNET_OK ==
4956 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4958 &dhops[nhops].hop_sig));
4960 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
4965 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4967 * @param init the signer
4968 * @param challenge the challenge that was signed
4969 * @param init_sig signature presumably by @a init
4970 * @return #GNUNET_OK if the signature is valid
4973 validate_dv_initiator_signature (
4974 const struct GNUNET_PeerIdentity *init,
4975 const struct GNUNET_ShortHashCode *challenge,
4976 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4978 struct DvInitPS ip = {.purpose.purpose = htonl (
4979 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4980 .purpose.size = htonl (sizeof (ip)),
4981 .challenge = *challenge};
4985 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4990 GNUNET_break_op (0);
4991 return GNUNET_SYSERR;
4998 * Communicator gave us a DV learn message. Process the request.
5000 * @param cls a `struct CommunicatorMessageContext` (must call
5001 * #finish_cmc_handling() when done)
5002 * @param dvl the message that was received
5005 handle_dv_learn (void *cls, const struct TransportDVLearn *dvl)
5007 struct CommunicatorMessageContext *cmc = cls;
5008 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
5011 uint16_t bi_history;
5012 const struct DVPathEntryP *hops;
5015 struct GNUNET_TIME_Absolute in_time;
5017 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
5018 bi_history = ntohs (dvl->bidirectional);
5019 hops = (const struct DVPathEntryP *) &dvl[1];
5023 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
5026 finish_cmc_handling (cmc);
5033 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
5036 finish_cmc_handling (cmc);
5041 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
5042 cc = cmc->tc->details.communicator.cc;
5043 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
5044 cc); // FIXME: add bi-directional flag to cc?
5045 in_time = GNUNET_TIME_absolute_get ();
5047 /* continue communicator here, everything else can happen asynchronous! */
5048 finish_cmc_handling (cmc);
5050 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
5051 the initiator signature if we send the message back to the initiator... */
5052 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
5056 GNUNET_break_op (0);
5059 // FIXME: asynchronously (!) verify hop-by-hop signatures!
5060 // => if signature verification load too high, implement random drop
5063 do_fwd = GNUNET_YES;
5064 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
5066 struct GNUNET_PeerIdentity path[nhops + 1];
5067 struct GNUNET_TIME_Relative host_latency_sum;
5068 struct GNUNET_TIME_Relative latency;
5069 struct GNUNET_TIME_Relative network_latency;
5071 /* We initiated this, learn the forward path! */
5072 path[0] = GST_my_identity;
5073 path[1] = hops[0].hop;
5074 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
5076 // Need also something to lookup initiation time
5077 // to compute RTT! -> add RTT argument here?
5078 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
5079 // (based on dvl->challenge, we can identify time of origin!)
5081 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
5082 /* assumption: latency on all links is the same */
5083 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
5085 for (unsigned int i = 2; i <= nhops; i++)
5087 struct GNUNET_TIME_Relative ilat;
5089 /* assumption: linear latency increase per hop */
5090 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
5091 path[i] = hops[i - 1].hop;
5092 learn_dv_path (path,
5095 GNUNET_TIME_relative_to_absolute (
5096 ADDRESS_VALIDATION_LIFETIME));
5098 /* as we initiated, do not forward again (would be circular!) */
5104 /* last hop was bi-directional, we could learn something here! */
5105 struct GNUNET_PeerIdentity path[nhops + 2];
5107 path[0] = GST_my_identity;
5108 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
5109 for (unsigned int i = 0; i < nhops; i++)
5113 if (0 == (bi_history & (1 << i)))
5114 break; /* i-th hop not bi-directional, stop learning! */
5117 path[i + 2] = dvl->initiator;
5121 path[i + 2] = hops[nhops - i - 2].hop;
5124 iret = learn_dv_path (path,
5126 GNUNET_TIME_UNIT_FOREVER_REL,
5127 GNUNET_TIME_UNIT_ZERO_ABS);
5128 if (GNUNET_SYSERR == iret)
5130 /* path invalid or too long to be interesting for US, thus should also
5131 not be interesting to our neighbours, cut path when forwarding to
5132 'i' hops, except of course for the one that goes back to the
5134 GNUNET_STATISTICS_update (GST_stats,
5135 "# DV learn not forwarded due invalidity of path",
5141 if ((GNUNET_NO == iret) && (nhops == i + 1))
5143 /* we have better paths, and this is the longest target,
5144 so there cannot be anything interesting later */
5145 GNUNET_STATISTICS_update (GST_stats,
5146 "# DV learn not forwarded, got better paths",
5155 if (MAX_DV_HOPS_ALLOWED == nhops)
5157 /* At limit, we're out of here! */
5158 finish_cmc_handling (cmc);
5162 /* Forward to initiator, if path non-trivial and possible */
5163 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
5164 did_initiator = GNUNET_NO;
5167 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
5169 /* send back to origin! */
5170 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
5171 did_initiator = GNUNET_YES;
5173 /* We forward under two conditions: either we still learned something
5174 ourselves (do_fwd), or the path was darn short and thus the initiator is
5175 likely to still be very interested in this (and we did NOT already
5176 send it back to the initiator) */
5177 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
5178 (GNUNET_NO == did_initiator)))
5180 /* FIXME: loop over all neighbours, pick those with low
5181 queues AND that are not yet on the path; possibly
5182 adapt threshold to nhops! */
5184 forward_dv_learn (NULL, // fill in peer from iterator here!
5196 * Communicator gave us a DV box. Check the message.
5198 * @param cls a `struct CommunicatorMessageContext`
5199 * @param dvb the send message that was sent
5200 * @return #GNUNET_YES if message is well-formed
5203 check_dv_box (void *cls, const struct TransportDVBox *dvb)
5205 uint16_t size = ntohs (dvb->header.size);
5206 uint16_t num_hops = ntohs (dvb->num_hops);
5207 const struct GNUNET_PeerIdentity *hops =
5208 (const struct GNUNET_PeerIdentity *) &dvb[1];
5209 const struct GNUNET_MessageHeader *inbox =
5210 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5215 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
5216 sizeof (struct GNUNET_MessageHeader))
5218 GNUNET_break_op (0);
5219 return GNUNET_SYSERR;
5221 isize = ntohs (inbox->size);
5223 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
5225 GNUNET_break_op (0);
5226 return GNUNET_SYSERR;
5228 itype = ntohs (inbox->type);
5229 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
5230 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
5232 GNUNET_break_op (0);
5233 return GNUNET_SYSERR;
5235 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
5237 GNUNET_break_op (0);
5238 return GNUNET_SYSERR;
5245 * Create a DV Box message and queue it for transmission to
5248 * @param next_hop peer to receive the message next
5249 * @param total_hops how many hops did the message take so far
5250 * @param num_hops length of the @a hops array
5251 * @param origin origin of the message
5252 * @param hops next peer(s) to the destination, including destination
5253 * @param payload payload of the box
5254 * @param payload_size number of bytes in @a payload
5257 forward_dv_box (struct Neighbour *next_hop,
5258 uint16_t total_hops,
5260 const struct GNUNET_PeerIdentity *origin,
5261 const struct GNUNET_PeerIdentity *hops,
5262 const void *payload,
5263 uint16_t payload_size)
5265 struct TransportDVBox *dvb;
5266 struct GNUNET_PeerIdentity *dhops;
5268 GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBox) +
5269 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5271 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
5272 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5275 htons (sizeof (struct TransportDVBox) +
5276 sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size);
5277 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5278 dvb->total_hops = htons (total_hops);
5279 dvb->num_hops = htons (num_hops);
5280 dvb->origin = *origin;
5281 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5282 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
5283 memcpy (&dhops[num_hops], payload, payload_size);
5284 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
5289 * Communicator gave us a DV box. Process the request.
5291 * @param cls a `struct CommunicatorMessageContext` (must call
5292 * #finish_cmc_handling() when done)
5293 * @param dvb the message that was received
5296 handle_dv_box (void *cls, const struct TransportDVBox *dvb)
5298 struct CommunicatorMessageContext *cmc = cls;
5299 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5300 uint16_t num_hops = ntohs (dvb->num_hops);
5301 const struct GNUNET_PeerIdentity *hops =
5302 (const struct GNUNET_PeerIdentity *) &dvb[1];
5303 const struct GNUNET_MessageHeader *inbox =
5304 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5308 /* We're trying from the end of the hops array, as we may be
5309 able to find a shortcut unknown to the origin that way */
5310 for (int i = num_hops - 1; i >= 0; i--)
5312 struct Neighbour *n;
5314 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
5316 GNUNET_break_op (0);
5317 finish_cmc_handling (cmc);
5320 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &hops[i]);
5324 ntohs (dvb->total_hops) + 1,
5325 num_hops - i - 1, /* number of hops left */
5327 &hops[i + 1], /* remaining hops */
5328 (const void *) &dvb[1],
5330 finish_cmc_handling (cmc);
5333 /* Woopsie, next hop not in neighbours, drop! */
5334 GNUNET_STATISTICS_update (GST_stats,
5335 "# DV Boxes dropped: next hop unknown",
5338 finish_cmc_handling (cmc);
5341 /* We are the target. Unbox and handle message. */
5342 cmc->im.sender = dvb->origin;
5343 cmc->total_hops = ntohs (dvb->total_hops);
5344 demultiplex_with_cmc (cmc, inbox);
5349 * Client notified us about transmission from a peer. Process the request.
5351 * @param cls a `struct TransportClient` which sent us the message
5352 * @param obm the send message that was sent
5353 * @return #GNUNET_YES if message is well-formed
5356 check_incoming_msg (void *cls,
5357 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5359 struct TransportClient *tc = cls;
5361 if (CT_COMMUNICATOR != tc->type)
5364 return GNUNET_SYSERR;
5366 GNUNET_MQ_check_boxed_message (im);
5372 * Communicator gave us a transport address validation challenge. Process the
5375 * @param cls a `struct CommunicatorMessageContext` (must call
5376 * #finish_cmc_handling() when done)
5377 * @param tvc the message that was received
5380 handle_validation_challenge (void *cls,
5381 const struct TransportValidationChallenge *tvc)
5383 struct CommunicatorMessageContext *cmc = cls;
5384 struct TransportValidationResponse *tvr;
5386 if (cmc->total_hops > 0)
5388 /* DV routing is not allowed for validation challenges! */
5389 GNUNET_break_op (0);
5390 finish_cmc_handling (cmc);
5393 tvr = GNUNET_new (struct TransportValidationResponse);
5395 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5396 tvr->header.size = htons (sizeof (*tvr));
5397 tvr->challenge = tvc->challenge;
5398 tvr->origin_time = tvc->sender_time;
5399 tvr->validity_duration = cmc->im.expected_address_validity;
5401 /* create signature */
5402 struct TransportValidationPS tvp =
5403 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5404 .purpose.size = htonl (sizeof (tvp)),
5405 .validity_duration = tvr->validity_duration,
5406 .challenge = tvc->challenge};
5408 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5412 route_message (&cmc->im.sender,
5414 RMO_ANYTHING_GOES | RMO_REDUNDANT);
5415 finish_cmc_handling (cmc);
5420 * Closure for #check_known_challenge.
5422 struct CheckKnownChallengeContext
5425 * Set to the challenge we are looking for.
5427 const struct GNUNET_ShortHashCode *challenge;
5430 * Set to a matching validation state, if one was found.
5432 struct ValidationState *vs;
5437 * Test if the validation state in @a value matches the
5438 * challenge from @a cls.
5440 * @param cls a `struct CheckKnownChallengeContext`
5441 * @param pid unused (must match though)
5442 * @param value a `struct ValidationState`
5443 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5446 check_known_challenge (void *cls,
5447 const struct GNUNET_PeerIdentity *pid,
5450 struct CheckKnownChallengeContext *ckac = cls;
5451 struct ValidationState *vs = value;
5454 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
5462 * Function called when peerstore is done storing a
5463 * validated address.
5465 * @param cls a `struct ValidationState`
5466 * @param success #GNUNET_YES on success
5469 peerstore_store_validation_cb (void *cls, int success)
5471 struct ValidationState *vs = cls;
5474 if (GNUNET_YES == success)
5476 GNUNET_STATISTICS_update (GST_stats,
5477 "# Peerstore failed to store foreign address",
5484 * Task run periodically to validate some address based on #validation_heap.
5489 validation_start_cb (void *cls);
5493 * Set the time for next_challenge of @a vs to @a new_time.
5494 * Updates the heap and if necessary reschedules the job.
5496 * @param vs validation state to update
5497 * @param new_time new time for revalidation
5500 update_next_challenge_time (struct ValidationState *vs,
5501 struct GNUNET_TIME_Absolute new_time)
5503 struct GNUNET_TIME_Relative delta;
5505 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5506 return; /* be lazy */
5507 vs->next_challenge = new_time;
5510 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
5512 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
5513 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5514 (NULL != validation_task))
5516 if (NULL != validation_task)
5517 GNUNET_SCHEDULER_cancel (validation_task);
5518 /* randomize a bit */
5519 delta.rel_value_us =
5520 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5521 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5522 new_time = GNUNET_TIME_absolute_add (new_time, delta);
5524 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
5529 * Find the queue matching @a pid and @a address.
5531 * @param pid peer the queue must go to
5532 * @param address address the queue must use
5533 * @return NULL if no such queue exists
5535 static struct Queue *
5536 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
5538 struct Neighbour *n;
5540 n = GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
5543 for (struct Queue *pos = n->queue_head; NULL != pos;
5544 pos = pos->next_neighbour)
5546 if (0 == strcmp (pos->address, address))
5554 * Task run periodically to check whether the validity of the given queue has
5555 * run its course. If so, finds either another queue to take over, or clears
5556 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
5557 * chance to take over, and if that fails, notifies CORE about the disconnect.
5559 * @param cls a `struct Queue`
5562 core_queue_visibility_check (void *cls)
5564 struct Queue *q = cls;
5566 q->visibility_task = NULL;
5567 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5569 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5570 &core_queue_visibility_check,
5574 update_neighbour_core_visibility (q->neighbour);
5579 * Check whether the CORE visibility of @a n should change. Finds either a
5580 * queue to preserve the visibility, or clears the neighbour's `core_visible`
5581 * flag. In the latter case, gives DV routes a chance to take over, and if
5582 * that fails, notifies CORE about the disconnect. If so, check whether we
5583 * need to notify CORE.
5585 * @param n neighbour to perform the check for
5588 update_neighbour_core_visibility (struct Neighbour *n)
5590 struct DistanceVector *dv;
5592 GNUNET_assert (GNUNET_YES == n->core_visible);
5593 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
5594 the #core_queue_visibility_check() task for that queue */
5595 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
5598 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5600 /* found a valid queue, use this one */
5601 q->visibility_task =
5602 GNUNET_SCHEDULER_add_at (q->validated_until,
5603 &core_queue_visibility_check,
5608 n->core_visible = GNUNET_NO;
5610 /* Check if _any_ DV route to this neighbour is currently
5611 valid, if so, do NOT tell core about the loss of direct
5612 connectivity (DV still counts!) */
5613 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
5614 if (GNUNET_YES == dv->core_visible)
5616 /* Nothing works anymore, need to tell CORE about the loss of
5618 cores_send_disconnect_info (&n->pid);
5623 * Communicator gave us a transport address validation response. Process the
5626 * @param cls a `struct CommunicatorMessageContext` (must call
5627 * #finish_cmc_handling() when done)
5628 * @param tvr the message that was received
5631 handle_validation_response (void *cls,
5632 const struct TransportValidationResponse *tvr)
5634 struct CommunicatorMessageContext *cmc = cls;
5635 struct ValidationState *vs;
5636 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
5638 struct GNUNET_TIME_Absolute origin_time;
5640 struct DistanceVector *dv;
5641 struct Neighbour *n;
5643 /* check this is one of our challenges */
5644 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5646 &check_known_challenge,
5648 if (NULL == (vs = ckac.vs))
5650 /* This can happen simply if we 'forgot' the challenge by now,
5651 i.e. because we received the validation response twice */
5652 GNUNET_STATISTICS_update (GST_stats,
5653 "# Validations dropped, challenge unknown",
5656 finish_cmc_handling (cmc);
5660 /* sanity check on origin time */
5661 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
5662 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
5663 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
5665 GNUNET_break_op (0);
5666 finish_cmc_handling (cmc);
5671 /* check signature */
5672 struct TransportValidationPS tvp =
5673 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5674 .purpose.size = htonl (sizeof (tvp)),
5675 .validity_duration = tvr->validity_duration,
5676 .challenge = tvr->challenge};
5680 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
5683 &cmc->im.sender.public_key))
5685 GNUNET_break_op (0);
5686 finish_cmc_handling (cmc);
5691 /* validity is capped by our willingness to keep track of the
5692 validation entry and the maximum the other peer allows */
5693 vs->valid_until = GNUNET_TIME_relative_to_absolute (
5694 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
5695 tvr->validity_duration),
5696 MAX_ADDRESS_VALID_UNTIL));
5697 vs->validated_until =
5698 GNUNET_TIME_absolute_min (vs->valid_until,
5699 GNUNET_TIME_relative_to_absolute (
5700 ADDRESS_VALIDATION_LIFETIME));
5701 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
5702 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
5703 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5705 sizeof (vs->challenge));
5706 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
5707 vs->validated_until,
5708 GNUNET_TIME_relative_multiply (vs->validation_rtt,
5709 VALIDATION_RTT_BUFFER_FACTOR));
5710 vs->last_challenge_use =
5711 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
5712 update_next_challenge_time (vs, vs->first_challenge_use);
5713 vs->sc = GNUNET_PEERSTORE_store (peerstore,
5716 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
5718 strlen (vs->address) + 1,
5720 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5721 &peerstore_store_validation_cb,
5723 finish_cmc_handling (cmc);
5725 /* Finally, we now possibly have a confirmed (!) working queue,
5726 update queue status (if queue still is around) */
5727 q = find_queue (&vs->pid, vs->address);
5730 GNUNET_STATISTICS_update (GST_stats,
5731 "# Queues lost at time of successful validation",
5736 q->validated_until = vs->validated_until;
5737 q->rtt = vs->validation_rtt;
5739 if (GNUNET_NO != n->core_visible)
5740 return; /* nothing changed, we are done here */
5741 n->core_visible = GNUNET_YES;
5742 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5743 &core_queue_visibility_check,
5745 /* Check if _any_ DV route to this neighbour is
5746 currently valid, if so, do NOT tell core anything! */
5747 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
5748 if ((NULL != dv) && (GNUNET_YES == dv->core_visible))
5749 return; /* nothing changed, done */
5750 /* We lacked a confirmed connection to the neighbour
5751 before, so tell CORE about it (finally!) */
5752 cores_send_connect_info (&n->pid,
5754 ? GNUNET_BANDWIDTH_value_sum (dv->quota_out,
5761 * Incoming meessage. Process the request.
5763 * @param im the send message that was received
5766 handle_incoming_msg (void *cls,
5767 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5769 struct TransportClient *tc = cls;
5770 struct CommunicatorMessageContext *cmc =
5771 GNUNET_new (struct CommunicatorMessageContext);
5775 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
5780 * Given an inbound message @a msg from a communicator @a cmc,
5781 * demultiplex it based on the type calling the right handler.
5783 * @param cmc context for demultiplexing
5784 * @param msg message to demultiplex
5787 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5788 const struct GNUNET_MessageHeader *msg)
5790 struct GNUNET_MQ_MessageHandler handlers[] =
5791 {GNUNET_MQ_hd_var_size (fragment_box,
5792 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
5793 struct TransportFragmentBox,
5795 GNUNET_MQ_hd_fixed_size (fragment_ack,
5796 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
5797 struct TransportFragmentAckMessage,
5799 GNUNET_MQ_hd_var_size (reliability_box,
5800 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5801 struct TransportReliabilityBox,
5803 GNUNET_MQ_hd_fixed_size (reliability_ack,
5804 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5805 struct TransportReliabilityAckMessage,
5807 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5808 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5809 struct TransportBackchannelEncapsulationMessage,
5811 GNUNET_MQ_hd_var_size (dv_learn,
5812 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5813 struct TransportDVLearn,
5815 GNUNET_MQ_hd_var_size (dv_box,
5816 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5817 struct TransportDVBox,
5819 GNUNET_MQ_hd_fixed_size (
5820 validation_challenge,
5821 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5822 struct TransportValidationChallenge,
5824 GNUNET_MQ_hd_fixed_size (
5825 validation_response,
5826 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5827 struct TransportValidationResponse,
5829 GNUNET_MQ_handler_end ()};
5832 ret = GNUNET_MQ_handle_message (handlers, msg);
5833 if (GNUNET_SYSERR == ret)
5836 GNUNET_SERVICE_client_drop (cmc->tc->client);
5840 if (GNUNET_NO == ret)
5842 /* unencapsulated 'raw' message */
5843 handle_raw_message (&cmc, msg);
5849 * New queue became available. Check message.
5851 * @param cls the client
5852 * @param aqm the send message that was sent
5855 check_add_queue_message (void *cls,
5856 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5858 struct TransportClient *tc = cls;
5860 if (CT_COMMUNICATOR != tc->type)
5863 return GNUNET_SYSERR;
5865 GNUNET_MQ_check_zero_termination (aqm);
5871 * Bandwidth tracker informs us that the delay until we should receive
5874 * @param cls a `struct Queue` for which the delay changed
5877 tracker_update_in_cb (void *cls)
5879 struct Queue *queue = cls;
5880 struct GNUNET_TIME_Relative in_delay;
5883 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5884 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
5885 // FIXME: how exactly do we do inbound flow control?
5890 * If necessary, generates the UUID for a @a pm
5892 * @param pm pending message to generate UUID for.
5895 set_pending_message_uuid (struct PendingMessage *pm)
5897 if (pm->msg_uuid_set)
5899 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5901 sizeof (pm->msg_uuid));
5902 pm->msg_uuid_set = GNUNET_YES;
5907 * Fragment the given @a pm to the given @a mtu. Adds
5908 * additional fragments to the neighbour as well. If the
5909 * @a mtu is too small, generates and error for the @a pm
5912 * @param pm pending message to fragment for transmission
5913 * @param mtu MTU to apply
5914 * @return new message to transmit
5916 static struct PendingMessage *
5917 fragment_message (struct PendingMessage *pm, uint16_t mtu)
5919 struct PendingMessage *ff;
5921 set_pending_message_uuid (pm);
5923 /* This invariant is established in #handle_add_queue_message() */
5924 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5926 /* select fragment for transmission, descending the tree if it has
5927 been expanded until we are at a leaf or at a fragment that is small enough
5930 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
5931 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
5933 ff = ff->head_frag; /* descent into fragmented fragments */
5936 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
5938 /* Did not yet calculate all fragments, calculate next fragment */
5939 struct PendingMessage *frag;
5940 struct TransportFragmentBox tfb;
5948 orig = (const char *) &ff[1];
5949 msize = ff->bytes_msg;
5952 const struct TransportFragmentBox *tfbo;
5954 tfbo = (const struct TransportFragmentBox *) orig;
5955 orig += sizeof (struct TransportFragmentBox);
5956 msize -= sizeof (struct TransportFragmentBox);
5957 xoff = ntohs (tfbo->frag_off);
5959 fragmax = mtu - sizeof (struct TransportFragmentBox);
5960 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
5961 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5962 sizeof (struct TransportFragmentBox) + fragsize);
5963 frag->target = pm->target;
5964 frag->frag_parent = ff;
5965 frag->timeout = pm->timeout;
5966 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5967 frag->pmt = PMT_FRAGMENT_BOX;
5968 msg = (char *) &frag[1];
5969 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
5970 tfb.header.size = htons (sizeof (struct TransportFragmentBox) + fragsize);
5971 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
5972 tfb.msg_uuid = pm->msg_uuid;
5973 tfb.frag_off = htons (ff->frag_off + xoff);
5974 tfb.msg_size = htons (pm->bytes_msg);
5975 memcpy (msg, &tfb, sizeof (tfb));
5976 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
5977 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
5978 ff->frag_off += fragsize;
5982 /* Move head to the tail and return it */
5983 GNUNET_CONTAINER_MDLL_remove (frag,
5984 ff->frag_parent->head_frag,
5985 ff->frag_parent->tail_frag,
5987 GNUNET_CONTAINER_MDLL_insert_tail (frag,
5988 ff->frag_parent->head_frag,
5989 ff->frag_parent->tail_frag,
5996 * Reliability-box the given @a pm. On error (can there be any), NULL
5997 * may be returned, otherwise the "replacement" for @a pm (which
5998 * should then be added to the respective neighbour's queue instead of
5999 * @a pm). If the @a pm is already fragmented or reliability boxed,
6000 * or itself an ACK, this function simply returns @a pm.
6002 * @param pm pending message to box for transmission over unreliabile queue
6003 * @return new message to transmit
6005 static struct PendingMessage *
6006 reliability_box_message (struct PendingMessage *pm)
6008 struct TransportReliabilityBox rbox;
6009 struct PendingMessage *bpm;
6012 if (PMT_CORE != pm->pmt)
6013 return pm; /* already fragmented or reliability boxed, or control message:
6015 if (NULL != pm->bpm)
6016 return pm->bpm; /* already computed earlier: do nothing */
6017 GNUNET_assert (NULL == pm->head_frag);
6018 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
6022 client_send_response (pm, GNUNET_NO, 0);
6025 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
6027 bpm->target = pm->target;
6028 bpm->frag_parent = pm;
6029 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
6030 bpm->timeout = pm->timeout;
6031 bpm->pmt = PMT_RELIABILITY_BOX;
6032 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
6033 set_pending_message_uuid (bpm);
6034 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
6035 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
6036 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
6037 rbox.msg_uuid = pm->msg_uuid;
6038 msg = (char *) &bpm[1];
6039 memcpy (msg, &rbox, sizeof (rbox));
6040 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
6047 * We believe we are ready to transmit a message on a queue. Double-checks
6048 * with the queue's "tracker_out" and then gives the message to the
6049 * communicator for transmission (updating the tracker, and re-scheduling
6050 * itself if applicable).
6052 * @param cls the `struct Queue` to process transmissions for
6055 transmit_on_queue (void *cls)
6057 struct Queue *queue = cls;
6058 struct Neighbour *n = queue->neighbour;
6059 struct PendingMessage *pm;
6060 struct PendingMessage *s;
6063 queue->transmit_task = NULL;
6064 if (NULL == (pm = n->pending_msg_head))
6066 /* no message pending, nothing to do here! */
6069 schedule_transmit_on_queue (queue);
6070 if (NULL != queue->transmit_task)
6071 return; /* do it later */
6073 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6074 overhead += sizeof (struct TransportReliabilityBox);
6076 if ( ( (0 != queue->mtu) &&
6077 (pm->bytes_msg + overhead > queue->mtu) ) ||
6078 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
6079 (NULL != pm->head_frag /* fragments already exist, should
6080 respect that even if MTU is 0 for
6082 s = fragment_message (s,
6085 sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
6089 /* Fragmentation failed, try next message... */
6090 schedule_transmit_on_queue (queue);
6093 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6094 s = reliability_box_message (s);
6097 /* Reliability boxing failed, try next message... */
6098 schedule_transmit_on_queue (queue);
6102 /* Pass 's' for transission to the communicator */
6103 queue_send_msg (queue, s, &s[1], s->bytes_msg);
6104 // FIXME: do something similar to the logic below
6105 // in defragmentation / reliability ACK handling!
6107 /* Check if this transmission somehow conclusively finished handing 'pm'
6108 even without any explicit ACKs */
6109 if ((PMT_CORE == s->pmt) &&
6110 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
6112 /* Full message sent, and over reliabile channel */
6113 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
6115 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
6116 queue->tc->details.communicator.cc) &&
6117 (PMT_FRAGMENT_BOX == s->pmt))
6119 struct PendingMessage *pos;
6121 /* Fragment sent over reliabile channel */
6122 free_fragment_tree (s);
6123 pos = s->frag_parent;
6124 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6126 /* check if subtree is done */
6127 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6131 pos = s->frag_parent;
6132 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6136 /* Was this the last applicable fragmment? */
6137 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
6138 client_send_response (
6141 pm->bytes_msg /* FIXME: calculate and add overheads! */);
6143 else if (PMT_CORE != pm->pmt)
6145 /* This was an acknowledgement of some type, always free */
6146 free_pending_message (pm);
6150 /* message not finished, waiting for acknowledgement */
6151 struct Neighbour *neighbour = pm->target;
6152 /* Update time by which we might retransmit 's' based on queue
6153 characteristics (i.e. RTT); it takes one RTT for the message to
6154 arrive and the ACK to come back in the best case; but the other
6155 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
6156 retransmitting. Note that in the future this heuristic should
6157 likely be improved further (measure RTT stability, consider
6158 message urgency and size when delaying ACKs, etc.) */
6159 s->next_attempt = GNUNET_TIME_relative_to_absolute (
6160 GNUNET_TIME_relative_multiply (queue->rtt, 4));
6163 struct PendingMessage *pos;
6165 /* re-insert sort in neighbour list */
6166 GNUNET_CONTAINER_MDLL_remove (neighbour,
6167 neighbour->pending_msg_head,
6168 neighbour->pending_msg_tail,
6170 pos = neighbour->pending_msg_tail;
6171 while ((NULL != pos) &&
6172 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6173 pos = pos->prev_neighbour;
6174 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
6175 neighbour->pending_msg_head,
6176 neighbour->pending_msg_tail,
6182 /* re-insert sort in fragment list */
6183 struct PendingMessage *fp = s->frag_parent;
6184 struct PendingMessage *pos;
6186 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, s);
6187 pos = fp->tail_frag;
6188 while ((NULL != pos) &&
6189 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6190 pos = pos->prev_frag;
6191 GNUNET_CONTAINER_MDLL_insert_after (frag,
6199 /* finally, re-schedule queue transmission task itself */
6200 schedule_transmit_on_queue (queue);
6205 * Bandwidth tracker informs us that the delay until we
6206 * can transmit again changed.
6208 * @param cls a `struct Queue` for which the delay changed
6211 tracker_update_out_cb (void *cls)
6213 struct Queue *queue = cls;
6214 struct Neighbour *n = queue->neighbour;
6216 if (NULL == n->pending_msg_head)
6218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6219 "Bandwidth allocation updated for empty transmission queue `%s'\n",
6221 return; /* no message pending, nothing to do here! */
6223 GNUNET_SCHEDULER_cancel (queue->transmit_task);
6224 queue->transmit_task = NULL;
6225 schedule_transmit_on_queue (queue);
6230 * Bandwidth tracker informs us that excessive outbound bandwidth was
6231 * allocated which is not being used.
6233 * @param cls a `struct Queue` for which the excess was noted
6236 tracker_excess_out_cb (void *cls)
6240 /* FIXME: trigger excess bandwidth report to core? Right now,
6241 this is done internally within transport_api2_core already,
6242 but we probably want to change the logic and trigger it
6243 from here via a message instead! */
6244 /* TODO: maybe inform someone at this point? */
6245 GNUNET_STATISTICS_update (GST_stats,
6246 "# Excess outbound bandwidth reported",
6253 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
6254 * which is not being used.
6256 * @param cls a `struct Queue` for which the excess was noted
6259 tracker_excess_in_cb (void *cls)
6263 /* TODO: maybe inform somone at this point? */
6264 GNUNET_STATISTICS_update (GST_stats,
6265 "# Excess inbound bandwidth reported",
6272 * Queue to a peer went down. Process the request.
6274 * @param cls the client
6275 * @param dqm the send message that was sent
6278 handle_del_queue_message (void *cls,
6279 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
6281 struct TransportClient *tc = cls;
6283 if (CT_COMMUNICATOR != tc->type)
6286 GNUNET_SERVICE_client_drop (tc->client);
6289 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6290 queue = queue->next_client)
6292 struct Neighbour *neighbour = queue->neighbour;
6294 if ((dqm->qid != queue->qid) ||
6295 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
6298 GNUNET_SERVICE_client_continue (tc->client);
6302 GNUNET_SERVICE_client_drop (tc->client);
6307 * Message was transmitted. Process the request.
6309 * @param cls the client
6310 * @param sma the send message that was sent
6313 handle_send_message_ack (void *cls,
6314 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
6316 struct TransportClient *tc = cls;
6317 struct QueueEntry *qe;
6319 if (CT_COMMUNICATOR != tc->type)
6322 GNUNET_SERVICE_client_drop (tc->client);
6326 /* find our queue entry matching the ACK */
6328 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6329 queue = queue->next_client)
6331 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
6333 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
6336 if (qep->mid != sma->mid)
6345 /* this should never happen */
6347 GNUNET_SERVICE_client_drop (tc->client);
6350 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6351 qe->queue->queue_tail,
6353 qe->queue->queue_length--;
6354 tc->details.communicator.total_queue_length--;
6355 GNUNET_SERVICE_client_continue (tc->client);
6357 /* if applicable, resume transmissions that waited on ACK */
6358 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
6359 tc->details.communicator.total_queue_length)
6361 /* Communicator dropped below threshold, resume all queues */
6362 GNUNET_STATISTICS_update (
6364 "# Transmission throttled due to communicator queue limit",
6367 for (struct Queue *queue = tc->details.communicator.queue_head;
6369 queue = queue->next_client)
6370 schedule_transmit_on_queue (queue);
6372 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6374 /* queue dropped below threshold; only resume this one queue */
6375 GNUNET_STATISTICS_update (GST_stats,
6376 "# Transmission throttled due to queue queue limit",
6379 schedule_transmit_on_queue (qe->queue);
6382 /* TODO: we also should react on the status! */
6383 // FIXME: this probably requires queue->pm = s assignment!
6384 // FIXME: react to communicator status about transmission request. We got:
6385 sma->status; // OK success, SYSERR failure
6392 * Iterator telling new MONITOR client about all existing
6395 * @param cls the new `struct TransportClient`
6396 * @param pid a connected peer
6397 * @param value the `struct Neighbour` with more information
6398 * @return #GNUNET_OK (continue to iterate)
6401 notify_client_queues (void *cls,
6402 const struct GNUNET_PeerIdentity *pid,
6405 struct TransportClient *tc = cls;
6406 struct Neighbour *neighbour = value;
6408 GNUNET_assert (CT_MONITOR == tc->type);
6409 for (struct Queue *q = neighbour->queue_head; NULL != q;
6410 q = q->next_neighbour)
6412 struct MonitorEvent me = {.rtt = q->rtt,
6414 .num_msg_pending = q->num_msg_pending,
6415 .num_bytes_pending = q->num_bytes_pending};
6417 notify_monitor (tc, pid, q->address, q->nt, &me);
6424 * Initialize a monitor client.
6426 * @param cls the client
6427 * @param start the start message that was sent
6430 handle_monitor_start (void *cls,
6431 const struct GNUNET_TRANSPORT_MonitorStart *start)
6433 struct TransportClient *tc = cls;
6435 if (CT_NONE != tc->type)
6438 GNUNET_SERVICE_client_drop (tc->client);
6441 tc->type = CT_MONITOR;
6442 tc->details.monitor.peer = start->peer;
6443 tc->details.monitor.one_shot = ntohl (start->one_shot);
6444 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
6445 GNUNET_SERVICE_client_mark_monitor (tc->client);
6446 GNUNET_SERVICE_client_continue (tc->client);
6451 * Find transport client providing communication service
6452 * for the protocol @a prefix.
6454 * @param prefix communicator name
6455 * @return NULL if no such transport client is available
6457 static struct TransportClient *
6458 lookup_communicator (const char *prefix)
6460 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6462 if (CT_COMMUNICATOR != tc->type)
6464 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
6468 GNUNET_ERROR_TYPE_WARNING,
6469 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6476 * Signature of a function called with a communicator @a address of a peer
6477 * @a pid that an application wants us to connect to.
6479 * @param pid target peer
6480 * @param address the address to try
6483 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
6485 static uint32_t idgen;
6486 struct TransportClient *tc;
6488 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6489 struct GNUNET_MQ_Envelope *env;
6492 prefix = GNUNET_HELLO_address_to_prefix (address);
6495 GNUNET_break (0); /* We got an invalid address!? */
6498 tc = lookup_communicator (prefix);
6501 GNUNET_STATISTICS_update (GST_stats,
6502 "# Suggestions ignored due to missing communicator",
6507 /* forward suggestion for queue creation to communicator */
6508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6509 "Request #%u for `%s' communicator to create queue to `%s'\n",
6510 (unsigned int) idgen,
6513 alen = strlen (address) + 1;
6515 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6516 cqm->request_id = htonl (idgen++);
6517 cqm->receiver = *pid;
6518 memcpy (&cqm[1], address, alen);
6519 GNUNET_MQ_send (tc->mq, env);
6524 * The queue @a q (which matches the peer and address in @a vs) is
6525 * ready for queueing. We should now queue the validation request.
6527 * @param q queue to send on
6528 * @param vs state to derive validation challenge from
6531 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
6533 struct TransportValidationChallenge tvc;
6535 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6537 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6538 tvc.header.size = htons (sizeof (tvc));
6539 tvc.reserved = htonl (0);
6540 tvc.challenge = vs->challenge;
6541 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6542 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
6547 * Task run periodically to validate some address based on #validation_heap.
6552 validation_start_cb (void *cls)
6554 struct ValidationState *vs;
6558 validation_task = NULL;
6559 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6560 /* drop validations past their expiration */
6563 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
6565 free_validation_state (vs);
6566 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6569 return; /* woopsie, no more addresses known, should only
6570 happen if we're really a lonely peer */
6571 q = find_queue (&vs->pid, vs->address);
6574 vs->awaiting_queue = GNUNET_YES;
6575 suggest_to_connect (&vs->pid, vs->address);
6578 validation_transmit_on_queue (q, vs);
6579 /* Finally, reschedule next attempt */
6580 vs->challenge_backoff =
6581 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
6582 MAX_VALIDATION_CHALLENGE_FREQ);
6583 update_next_challenge_time (vs,
6584 GNUNET_TIME_relative_to_absolute (
6585 vs->challenge_backoff));
6590 * Closure for #check_connection_quality.
6592 struct QueueQualityContext
6595 * Set to the @e k'th queue encountered.
6600 * Set to the number of quality queues encountered.
6602 unsigned int quality_count;
6605 * Set to the total number of queues encountered.
6607 unsigned int num_queues;
6610 * Decremented for each queue, for selection of the
6611 * k-th queue in @e q.
6618 * Check whether any queue to the given neighbour is
6619 * of a good "quality" and if so, increment the counter.
6620 * Also counts the total number of queues, and returns
6621 * the k-th queue found.
6623 * @param cls a `struct QueueQualityContext *` with counters
6624 * @param pid peer this is about
6625 * @param value a `struct Neighbour`
6626 * @return #GNUNET_OK (continue to iterate)
6629 check_connection_quality (void *cls,
6630 const struct GNUNET_PeerIdentity *pid,
6633 struct QueueQualityContext *ctx = cls;
6634 struct Neighbour *n = value;
6639 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6641 if (0 != q->distance)
6642 continue; /* DV does not count */
6646 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
6647 statistics and consider those as well here? */
6648 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
6649 do_inc = GNUNET_YES;
6651 if (GNUNET_YES == do_inc)
6652 ctx->quality_count++;
6658 * Task run when we CONSIDER initiating a DV learn
6659 * process. We first check that sending out a message is
6660 * even possible (queues exist), then that it is desirable
6661 * (if not, reschedule the task for later), and finally
6662 * we may then begin the job. If there are too many
6663 * entries in the #dvlearn_map, we purge the oldest entry
6669 start_dv_learn (void *cls)
6671 struct LearnLaunchEntry *lle;
6672 struct QueueQualityContext qqc;
6673 struct TransportDVLearn dvl;
6676 dvlearn_task = NULL;
6677 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
6678 return; /* lost all connectivity, cannot do learning */
6679 qqc.quality_count = 0;
6681 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6682 &check_connection_quality,
6684 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
6686 struct GNUNET_TIME_Relative delay;
6687 unsigned int factor;
6689 /* scale our retries by how far we are above the threshold */
6690 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6691 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
6692 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
6695 /* remove old entries in #dvlearn_map if it has grown too big */
6696 while (MAX_DV_LEARN_PENDING >=
6697 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6700 GNUNET_assert (GNUNET_YES ==
6701 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6704 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
6707 /* setup data structure for learning */
6708 lle = GNUNET_new (struct LearnLaunchEntry);
6709 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6711 sizeof (lle->challenge));
6712 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
6713 GNUNET_break (GNUNET_YES ==
6714 GNUNET_CONTAINER_multishortmap_put (
6718 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6719 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6720 dvl.header.size = htons (sizeof (dvl));
6721 dvl.num_hops = htons (0);
6722 dvl.bidirectional = htons (0);
6723 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6725 struct DvInitPS dvip = {.purpose.purpose = htonl (
6726 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6727 .purpose.size = htonl (sizeof (dvip)),
6728 .challenge = lle->challenge};
6730 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6734 dvl.initiator = GST_my_identity;
6735 dvl.challenge = lle->challenge;
6737 qqc.quality_count = 0;
6738 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
6741 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6742 &check_connection_quality,
6744 GNUNET_assert (NULL != qqc.q);
6746 /* Do this as close to transmission time as possible! */
6747 lle->launch_time = GNUNET_TIME_absolute_get ();
6749 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
6750 /* reschedule this job, randomizing the time it runs (but no
6752 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
6753 DV_LEARN_BASE_FREQUENCY),
6760 * A new queue has been created, check if any address validation
6761 * requests have been waiting for it.
6763 * @param cls a `struct Queue`
6764 * @param pid peer concerned (unused)
6765 * @param value a `struct ValidationState`
6766 * @return #GNUNET_NO if a match was found and we can stop looking
6769 check_validation_request_pending (void *cls,
6770 const struct GNUNET_PeerIdentity *pid,
6773 struct Queue *q = cls;
6774 struct ValidationState *vs = value;
6777 if ((GNUNET_YES == vs->awaiting_queue) &&
6778 (0 == strcmp (vs->address, q->address)))
6780 vs->awaiting_queue = GNUNET_NO;
6781 validation_transmit_on_queue (q, vs);
6789 * New queue became available. Process the request.
6791 * @param cls the client
6792 * @param aqm the send message that was sent
6795 handle_add_queue_message (void *cls,
6796 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6798 struct TransportClient *tc = cls;
6799 struct Queue *queue;
6800 struct Neighbour *neighbour;
6804 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6806 /* MTU so small as to be useless for transmissions,
6807 required for #fragment_message()! */
6808 GNUNET_break_op (0);
6809 GNUNET_SERVICE_client_drop (tc->client);
6812 neighbour = lookup_neighbour (&aqm->receiver);
6813 if (NULL == neighbour)
6815 neighbour = GNUNET_new (struct Neighbour);
6816 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6817 neighbour->pid = aqm->receiver;
6818 GNUNET_assert (GNUNET_OK ==
6819 GNUNET_CONTAINER_multipeermap_put (
6823 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6825 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6826 addr = (const char *) &aqm[1];
6828 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6830 queue->address = (const char *) &queue[1];
6831 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6832 queue->qid = aqm->qid;
6833 queue->mtu = ntohl (aqm->mtu);
6834 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6835 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6836 queue->neighbour = neighbour;
6837 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6838 &tracker_update_in_cb,
6840 GNUNET_BANDWIDTH_ZERO,
6841 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6842 &tracker_excess_in_cb,
6844 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6845 &tracker_update_out_cb,
6847 GNUNET_BANDWIDTH_ZERO,
6848 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6849 &tracker_excess_out_cb,
6851 memcpy (&queue[1], addr, addr_len);
6852 /* notify monitors about new queue */
6854 struct MonitorEvent me = {.rtt = queue->rtt, .cs = queue->cs};
6856 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
6858 GNUNET_CONTAINER_MDLL_insert (neighbour,
6859 neighbour->queue_head,
6860 neighbour->queue_tail,
6862 GNUNET_CONTAINER_MDLL_insert (client,
6863 tc->details.communicator.queue_head,
6864 tc->details.communicator.queue_tail,
6866 /* check if valdiations are waiting for the queue */
6868 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6870 &check_validation_request_pending,
6872 /* might be our first queue, try launching DV learning */
6873 if (NULL == dvlearn_task)
6874 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
6875 GNUNET_SERVICE_client_continue (tc->client);
6880 * Communicator tells us that our request to create a queue "worked", that
6881 * is setting up the queue is now in process.
6883 * @param cls the `struct TransportClient`
6884 * @param cqr confirmation message
6887 handle_queue_create_ok (void *cls,
6888 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6890 struct TransportClient *tc = cls;
6892 if (CT_COMMUNICATOR != tc->type)
6895 GNUNET_SERVICE_client_drop (tc->client);
6898 GNUNET_STATISTICS_update (GST_stats,
6899 "# Suggestions succeeded at communicator",
6902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6903 "Request #%u for communicator to create queue succeeded\n",
6904 (unsigned int) ntohs (cqr->request_id));
6905 GNUNET_SERVICE_client_continue (tc->client);
6910 * Communicator tells us that our request to create a queue failed. This usually
6911 * indicates that the provided address is simply invalid or that the
6912 * communicator's resources are exhausted.
6914 * @param cls the `struct TransportClient`
6915 * @param cqr failure message
6918 handle_queue_create_fail (
6920 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6922 struct TransportClient *tc = cls;
6924 if (CT_COMMUNICATOR != tc->type)
6927 GNUNET_SERVICE_client_drop (tc->client);
6930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6931 "Request #%u for communicator to create queue failed\n",
6932 (unsigned int) ntohs (cqr->request_id));
6933 GNUNET_STATISTICS_update (GST_stats,
6934 "# Suggestions failed in queue creation at communicator",
6937 GNUNET_SERVICE_client_continue (tc->client);
6942 * We have received a `struct ExpressPreferenceMessage` from an application
6945 * @param cls handle to the client
6946 * @param msg the start message
6949 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
6951 struct TransportClient *tc = cls;
6952 struct PeerRequest *pr;
6954 if (CT_APPLICATION != tc->type)
6957 GNUNET_SERVICE_client_drop (tc->client);
6960 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
6965 GNUNET_SERVICE_client_drop (tc->client);
6968 (void) stop_peer_request (tc, &pr->pid, pr);
6969 GNUNET_SERVICE_client_continue (tc->client);
6974 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
6975 * messages. We do nothing here, real verification is done later.
6977 * @param cls a `struct TransportClient *`
6978 * @param msg message to verify
6979 * @return #GNUNET_OK
6982 check_address_consider_verify (
6984 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6993 * Closure for #check_known_address.
6995 struct CheckKnownAddressContext
6998 * Set to the address we are looking for.
7000 const char *address;
7003 * Set to a matching validation state, if one was found.
7005 struct ValidationState *vs;
7010 * Test if the validation state in @a value matches the
7011 * address from @a cls.
7013 * @param cls a `struct CheckKnownAddressContext`
7014 * @param pid unused (must match though)
7015 * @param value a `struct ValidationState`
7016 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7019 check_known_address (void *cls,
7020 const struct GNUNET_PeerIdentity *pid,
7023 struct CheckKnownAddressContext *ckac = cls;
7024 struct ValidationState *vs = value;
7027 if (0 != strcmp (vs->address, ckac->address))
7035 * Start address validation.
7037 * @param pid peer the @a address is for
7038 * @param address an address to reach @a pid (presumably)
7039 * @param expiration when did @a pid claim @a address will become invalid
7042 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7043 const char *address,
7044 struct GNUNET_TIME_Absolute expiration)
7046 struct GNUNET_TIME_Absolute now;
7047 struct ValidationState *vs;
7048 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7050 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
7051 return; /* expired */
7052 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7054 &check_known_address,
7056 if (NULL != (vs = ckac.vs))
7058 /* if 'vs' is not currently valid, we need to speed up retrying the
7060 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7062 /* reduce backoff as we got a fresh advertisement */
7063 vs->challenge_backoff =
7064 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7065 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7067 update_next_challenge_time (vs,
7068 GNUNET_TIME_relative_to_absolute (
7069 vs->challenge_backoff));
7073 now = GNUNET_TIME_absolute_get ();
7074 vs = GNUNET_new (struct ValidationState);
7076 vs->valid_until = expiration;
7077 vs->first_challenge_use = now;
7078 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7079 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7081 sizeof (vs->challenge));
7082 vs->address = GNUNET_strdup (address);
7083 GNUNET_assert (GNUNET_YES ==
7084 GNUNET_CONTAINER_multipeermap_put (
7088 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7089 update_next_challenge_time (vs, now);
7094 * Function called by PEERSTORE for each matching record.
7096 * @param cls closure
7097 * @param record peerstore record information
7098 * @param emsg error message, or NULL if no errors
7101 handle_hello (void *cls,
7102 const struct GNUNET_PEERSTORE_Record *record,
7105 struct PeerRequest *pr = cls;
7110 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7111 "Got failure from PEERSTORE: %s\n",
7115 val = record->value;
7116 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7121 start_address_validation (&pr->pid,
7122 (const char *) record->value,
7128 * We have received a `struct ExpressPreferenceMessage` from an application
7131 * @param cls handle to the client
7132 * @param msg the start message
7135 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
7137 struct TransportClient *tc = cls;
7138 struct PeerRequest *pr;
7140 if (CT_NONE == tc->type)
7142 tc->type = CT_APPLICATION;
7143 tc->details.application.requests =
7144 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
7146 if (CT_APPLICATION != tc->type)
7149 GNUNET_SERVICE_client_drop (tc->client);
7152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7153 "Client suggested we talk to %s with preference %d at rate %u\n",
7154 GNUNET_i2s (&msg->peer),
7155 (int) ntohl (msg->pk),
7156 (int) ntohl (msg->bw.value__));
7157 pr = GNUNET_new (struct PeerRequest);
7159 pr->pid = msg->peer;
7161 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
7162 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
7163 tc->details.application.requests,
7166 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
7170 GNUNET_SERVICE_client_drop (tc->client);
7173 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
7176 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7179 GNUNET_SERVICE_client_continue (tc->client);
7184 * Given another peers address, consider checking it for validity
7185 * and then adding it to the Peerstore.
7187 * @param cls a `struct TransportClient`
7188 * @param hdr message containing the raw address data and
7189 * signature in the body, see #GNUNET_HELLO_extract_address()
7192 handle_address_consider_verify (
7194 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7196 struct TransportClient *tc = cls;
7198 enum GNUNET_NetworkType nt;
7199 struct GNUNET_TIME_Absolute expiration;
7202 // OPTIMIZE-FIXME: checking that we know this address already should
7203 // be done BEFORE checking the signature => HELLO API change!
7204 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
7206 GNUNET_HELLO_extract_address (&hdr[1],
7207 ntohs (hdr->header.size) - sizeof (*hdr),
7211 if (NULL == address)
7213 GNUNET_break_op (0);
7216 start_address_validation (&hdr->peer, address, expiration);
7217 GNUNET_free (address);
7218 GNUNET_SERVICE_client_continue (tc->client);
7223 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
7226 * @param cls a `struct TransportClient *`
7227 * @param m message to verify
7228 * @return #GNUNET_OK on success
7231 check_request_hello_validation (void *cls,
7232 const struct RequestHelloValidationMessage *m)
7235 GNUNET_MQ_check_zero_termination (m);
7241 * A client encountered an address of another peer. Consider validating it,
7242 * and if validation succeeds, persist it to PEERSTORE.
7244 * @param cls a `struct TransportClient *`
7245 * @param m message to verify
7248 handle_request_hello_validation (void *cls,
7249 const struct RequestHelloValidationMessage *m)
7251 struct TransportClient *tc = cls;
7253 start_address_validation (&m->peer,
7254 (const char *) &m[1],
7255 GNUNET_TIME_absolute_ntoh (m->expiration));
7256 GNUNET_SERVICE_client_continue (tc->client);
7261 * Free neighbour entry.
7265 * @param value a `struct Neighbour`
7266 * @return #GNUNET_OK (always)
7269 free_neighbour_cb (void *cls,
7270 const struct GNUNET_PeerIdentity *pid,
7273 struct Neighbour *neighbour = value;
7277 GNUNET_break (0); // should this ever happen?
7278 free_neighbour (neighbour);
7285 * Free DV route entry.
7289 * @param value a `struct DistanceVector`
7290 * @return #GNUNET_OK (always)
7293 free_dv_routes_cb (void *cls,
7294 const struct GNUNET_PeerIdentity *pid,
7297 struct DistanceVector *dv = value;
7308 * Free ephemeral entry.
7312 * @param value a `struct EphemeralCacheEntry`
7313 * @return #GNUNET_OK (always)
7316 free_ephemeral_cb (void *cls,
7317 const struct GNUNET_PeerIdentity *pid,
7320 struct EphemeralCacheEntry *ece = value;
7324 free_ephemeral (ece);
7330 * Free validation state.
7334 * @param value a `struct ValidationState`
7335 * @return #GNUNET_OK (always)
7338 free_validation_state_cb (void *cls,
7339 const struct GNUNET_PeerIdentity *pid,
7342 struct ValidationState *vs = value;
7346 free_validation_state (vs);
7352 * Function called when the service shuts down. Unloads our plugins
7353 * and cancels pending validations.
7355 * @param cls closure, unused
7358 do_shutdown (void *cls)
7360 struct LearnLaunchEntry *lle;
7363 if (NULL != ephemeral_task)
7365 GNUNET_SCHEDULER_cancel (ephemeral_task);
7366 ephemeral_task = NULL;
7368 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
7369 if (NULL != peerstore)
7371 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
7374 if (NULL != GST_stats)
7376 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
7379 if (NULL != GST_my_private_key)
7381 GNUNET_free (GST_my_private_key);
7382 GST_my_private_key = NULL;
7384 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7386 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7387 &free_validation_state_cb,
7389 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7390 validation_map = NULL;
7391 while (NULL != (lle = lle_head))
7393 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7396 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7398 GNUNET_CONTAINER_heap_destroy (validation_heap);
7399 validation_heap = NULL;
7400 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
7401 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7403 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7406 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7407 ephemeral_map = NULL;
7408 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7409 ephemeral_heap = NULL;
7414 * Initiate transport service.
7416 * @param cls closure
7417 * @param c configuration to use
7418 * @param service the initialized service
7422 const struct GNUNET_CONFIGURATION_Handle *c,
7423 struct GNUNET_SERVICE_Handle *service)
7429 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7430 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7431 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
7433 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7434 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7436 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7438 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7439 GST_my_private_key =
7440 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7441 if (NULL == GST_my_private_key)
7444 GNUNET_ERROR_TYPE_ERROR,
7446 "Transport service is lacking key configuration settings. Exiting.\n"));
7447 GNUNET_SCHEDULER_shutdown ();
7450 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7451 &GST_my_identity.public_key);
7452 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7453 "My identity is `%s'\n",
7454 GNUNET_i2s_full (&GST_my_identity));
7455 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
7456 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
7457 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7458 if (NULL == peerstore)
7461 GNUNET_SCHEDULER_shutdown ();
7468 * Define "main" method using service macro.
7470 GNUNET_SERVICE_MAIN (
7472 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7475 &client_disconnect_cb,
7477 /* communication with applications */
7478 GNUNET_MQ_hd_fixed_size (suggest,
7479 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7480 struct ExpressPreferenceMessage,
7482 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7483 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7484 struct ExpressPreferenceMessage,
7486 GNUNET_MQ_hd_var_size (request_hello_validation,
7487 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7488 struct RequestHelloValidationMessage,
7490 /* communication with core */
7491 GNUNET_MQ_hd_fixed_size (client_start,
7492 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7493 struct StartMessage,
7495 GNUNET_MQ_hd_var_size (client_send,
7496 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7497 struct OutboundMessage,
7499 /* communication with communicators */
7500 GNUNET_MQ_hd_var_size (communicator_available,
7501 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7502 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7504 GNUNET_MQ_hd_var_size (communicator_backchannel,
7505 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7506 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7508 GNUNET_MQ_hd_var_size (add_address,
7509 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7510 struct GNUNET_TRANSPORT_AddAddressMessage,
7512 GNUNET_MQ_hd_fixed_size (del_address,
7513 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7514 struct GNUNET_TRANSPORT_DelAddressMessage,
7516 GNUNET_MQ_hd_var_size (incoming_msg,
7517 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7518 struct GNUNET_TRANSPORT_IncomingMessage,
7520 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7521 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7522 struct GNUNET_TRANSPORT_CreateQueueResponse,
7524 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7525 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7526 struct GNUNET_TRANSPORT_CreateQueueResponse,
7528 GNUNET_MQ_hd_var_size (add_queue_message,
7529 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7530 struct GNUNET_TRANSPORT_AddQueueMessage,
7532 GNUNET_MQ_hd_var_size (address_consider_verify,
7533 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7534 struct GNUNET_TRANSPORT_AddressToVerify,
7536 GNUNET_MQ_hd_fixed_size (del_queue_message,
7537 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7538 struct GNUNET_TRANSPORT_DelQueueMessage,
7540 GNUNET_MQ_hd_fixed_size (send_message_ack,
7541 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
7542 struct GNUNET_TRANSPORT_SendMessageToAck,
7544 /* communication with monitors */
7545 GNUNET_MQ_hd_fixed_size (monitor_start,
7546 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
7547 struct GNUNET_TRANSPORT_MonitorStart,
7549 GNUNET_MQ_handler_end ());
7552 /* end of file gnunet-service-transport.c */