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
26 * - figure out how to transmit (selective) ACKs in case of uni-directional
27 * communicators (with/without core? DV-only?) When do we use ACKs?
28 * => communicators use selective ACKs for flow control
29 * => transport uses message-level ACKs for RTT, fragment confirmation
30 * => integrate DV into transport, use neither core nor communicators
31 * but rather give communicators transport-encapsulated messages
32 * (which could be core-data, background-channel traffic, or
33 * transport-to-transport traffic)
36 * - route_message() implementation, including using DV data structures
37 * (but not when routing certain message types, like DV learn,
38 * looks like now like we need two flags (DV/no-DV, confirmed-only,
40 * + NOTE: do NOT use PendingMessage for route_message(), as that is
41 * for fragmentation/reliability and ultimately core flow control!
42 * => route_message() should pick the queue
43 * => in case of DV routing, route_message should BOX the message, too.
44 * - We currently do NEVER tell CORE also about DV-connections (core_visible
45 * of `struct DistanceVector` is simply never set!)
46 * + When? Easy if we initiated the DV and got the challenge; do that NOW
47 * BUT what we passively learned DV (unconfirmed freshness)
48 * => Do we trigger Challenge->Response there as well, or 'wait' for
49 * our own DV initiations to discover?
50 * => What about DV routes that expire? Do we also only count on
51 * our own DV initiations for maintenance here, or do we
52 * try to specifically re-confirm the existence of a particular path?
53 * => OPITMIZATION-FIXME!
54 * + Where do we track what we told core? Careful: need to check
55 * the "core_visible' flag in both neighbours and DV before
56 * sending out notifications to CORE!
57 * - retransmission logic
58 * - track RTT, distance, loss, etc. => requires extra data structures!
61 * - change transport-core API to provide proper flow control in both
62 * directions, allow multiple messages per peer simultaneously (tag
63 * confirmations with unique message ID), and replace quota-out with
64 * proper flow control;
65 * - if messages are below MTU, consider adding ACKs and other stuff
66 * (requires planning at receiver, and additional MST-style demultiplex
68 * - could avoid copying body of message into each fragment and keep
69 * fragments as just pointers into the original message and only
70 * fully build fragments just before transmission (optimization, should
71 * reduce CPU and memory use)
73 * FIXME (without marks in the code!):
74 * - proper use/initialization of timestamps in messages exchanged
76 * - persistence of monotonic time obtained from other peers
77 * in PEERSTORE (by message type)
80 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
81 * against our pending message queue (requires additional per neighbour
82 * hash map to be maintained, avoids possible linear scan on pending msgs)
83 * - queue_send_msg and route_message both by API design have to make copies
84 * of the payload, and route_message on top of that requires a malloc/free.
85 * Change design to approximate "zero" copy better...
87 * Design realizations / discussion:
88 * - communicators do flow control by calling MQ "notify sent"
89 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
90 * or explicitly via backchannel FC ACKs. As long as the
91 * channel is not full, they may 'notify sent' even if the other
92 * peer has not yet confirmed receipt. The other peer confirming
93 * is _only_ for FC, not for more reliable transmission; reliable
94 * transmission (i.e. of fragments) is left to _transport_.
95 * - ACKs sent back in uni-directional communicators are done via
96 * the background channel API; here transport _may_ initially
97 * broadcast (with bounded # hops) if no path is known;
98 * - transport should _integrate_ DV-routing and build a view of
99 * the network; then background channel traffic can be
100 * routed via DV as well as explicit "DV" traffic.
101 * - background channel is also used for ACKs and NAT traversal support
102 * - transport service is responsible for AEAD'ing the background
103 * channel, timestamps and monotonic time are used against replay
104 * of old messages -> peerstore needs to be supplied with
105 * "latest timestamps seen" data
106 * - if transport implements DV, we likely need a 3rd peermap
107 * in addition to ephemerals and (direct) neighbours
108 * ==> check if stuff needs to be moved out of "Neighbour"
109 * - transport should encapsualte core-level messages and do its
110 * own ACKing for RTT/goodput/loss measurements _and_ fragment
113 #include "platform.h"
114 #include "gnunet_util_lib.h"
115 #include "gnunet_statistics_service.h"
116 #include "gnunet_transport_monitor_service.h"
117 #include "gnunet_peerstore_service.h"
118 #include "gnunet_hello_lib.h"
119 #include "gnunet_signatures.h"
120 #include "transport.h"
124 * What is the size we assume for a read operation in the
125 * absence of an MTU for the purpose of flow control?
127 #define IN_PACKET_SIZE_WITHOUT_MTU 128
130 * Minimum number of hops we should forward DV learn messages
131 * even if they are NOT useful for us in hope of looping
132 * back to the initiator?
134 * FIXME: allow initiator some control here instead?
136 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
139 * Maximum DV distance allowed ever.
141 #define MAX_DV_HOPS_ALLOWED 16
144 * Maximum number of DV learning activities we may
145 * have pending at the same time.
147 #define MAX_DV_LEARN_PENDING 64
150 * Maximum number of DV paths we keep simultaneously to the same target.
152 #define MAX_DV_PATHS_TO_TARGET 3
155 * If a queue delays the next message by more than this number
156 * of seconds we log a warning. Note: this is for testing,
157 * the value chosen here might be too aggressively low!
159 #define DELAY_WARN_THRESHOLD \
160 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
163 * We only consider queues as "quality" connections when
164 * suppressing the generation of DV initiation messages if
165 * the latency of the queue is below this threshold.
167 #define DV_QUALITY_RTT_THRESHOLD \
168 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
171 * How long do we consider a DV path valid if we see no
172 * further updates on it? Note: the value chosen here might be too low!
174 #define DV_PATH_VALIDITY_TIMEOUT \
175 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
178 * How long before paths expire would we like to (re)discover DV paths? Should
179 * be below #DV_PATH_VALIDITY_TIMEOUT.
181 #define DV_PATH_DISCOVERY_FREQUENCY \
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
185 * How long are ephemeral keys valid?
187 #define EPHEMERAL_VALIDITY \
188 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
191 * How long do we keep partially reassembled messages around before giving up?
193 #define REASSEMBLY_EXPIRATION \
194 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
197 * What is the fastest rate at which we send challenges *if* we keep learning
198 * an address (gossip, DHT, etc.)?
200 #define FAST_VALIDATION_CHALLENGE_FREQ \
201 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
204 * What is the slowest rate at which we send challenges?
206 #define MAX_VALIDATION_CHALLENGE_FREQ \
207 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
210 * What is the non-randomized base frequency at which we
211 * would initiate DV learn messages?
213 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
216 * How many good connections (confirmed, bi-directional, not DV)
217 * do we need to have to suppress initiating DV learn messages?
219 #define DV_LEARN_QUALITY_THRESHOLD 100
222 * When do we forget an invalid address for sure?
224 #define MAX_ADDRESS_VALID_UNTIL \
225 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
228 * How long do we consider an address valid if we just checked?
230 #define ADDRESS_VALIDATION_LIFETIME \
231 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
234 * What is the maximum frequency at which we do address validation?
235 * A random value between 0 and this value is added when scheduling
236 * the #validation_task (both to ensure we do not validate too often,
237 * and to randomize a bit).
239 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
242 * How many network RTTs before an address validation expires should we begin
243 * trying to revalidate? (Note that the RTT used here is the one that we
244 * experienced during the last validation, not necessarily the latest RTT
247 #define VALIDATION_RTT_BUFFER_FACTOR 3
250 * How many messages can we have pending for a given communicator
251 * process before we start to throttle that communicator?
253 * Used if a communicator might be CPU-bound and cannot handle the traffic.
255 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
258 * How many messages can we have pending for a given queue (queue to
259 * a particular peer via a communicator) process before we start to
260 * throttle that queue?
262 #define QUEUE_LENGTH_LIMIT 32
265 GNUNET_NETWORK_STRUCT_BEGIN
268 * Outer layer of an encapsulated backchannel message.
270 struct TransportBackchannelEncapsulationMessage
273 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
275 struct GNUNET_MessageHeader header;
278 * Distance the backchannel message has traveled, to be updated at
279 * each hop. Used to bound the number of hops in case a backchannel
280 * message is broadcast and thus travels without routing
281 * information (during initial backchannel discovery).
286 * Target's peer identity (as backchannels may be transmitted
287 * indirectly, or even be broadcast).
289 struct GNUNET_PeerIdentity target;
292 * Ephemeral key setup by the sender for @e target, used
293 * to encrypt the payload.
295 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
298 * We use an IV here as the @e ephemeral_key is re-used for
299 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
301 struct GNUNET_ShortHashCode iv;
304 * HMAC over the ciphertext of the encrypted, variable-size
305 * body that follows. Verified via DH of @e target and
308 struct GNUNET_HashCode hmac;
310 /* Followed by encrypted, variable-size payload */
315 * Body by which a peer confirms that it is using an ephemeral key.
317 struct EphemeralConfirmation
321 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
323 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
326 * How long is this signature over the ephemeral key valid?
328 * Note that the receiver MUST IGNORE the absolute time, and only interpret
329 * the value as a mononic time and reject "older" values than the last one
330 * observed. This is necessary as we do not want to require synchronized
331 * clocks and may not have a bidirectional communication channel.
333 * Even with this, there is no real guarantee against replay achieved here,
334 * unless the latest timestamp is persisted. While persistence should be
335 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
336 * communicators must protect against replay attacks when using backchannel
339 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
342 * Target's peer identity.
344 struct GNUNET_PeerIdentity target;
347 * Ephemeral key setup by the sender for @e target, used
348 * to encrypt the payload.
350 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
355 * Plaintext of the variable-size payload that is encrypted
356 * within a `struct TransportBackchannelEncapsulationMessage`
358 struct TransportBackchannelRequestPayload
362 * Sender's peer identity.
364 struct GNUNET_PeerIdentity sender;
367 * Signature of the sender over an
368 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
370 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
373 * How long is this signature over the ephemeral key valid?
375 * Note that the receiver MUST IGNORE the absolute time, and only interpret
376 * the value as a mononic time and reject "older" values than the last one
377 * observed. This is necessary as we do not want to require synchronized
378 * clocks and may not have a bidirectional communication channel.
380 * Even with this, there is no real guarantee against replay achieved here,
381 * unless the latest timestamp is persisted. While persistence should be
382 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
383 * communicators must protect against replay attacks when using backchannel
386 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
389 * Current monotonic time of the sending transport service. Used to
390 * detect replayed messages. Note that the receiver should remember
391 * a list of the recently seen timestamps and only reject messages
392 * if the timestamp is in the list, or the list is "full" and the
393 * timestamp is smaller than the lowest in the list.
395 * Like the @e ephemeral_validity, the list of timestamps per peer should be
396 * persisted to guard against replays after restarts.
398 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
400 /* Followed by a `struct GNUNET_MessageHeader` with a message
401 for a communicator */
403 /* Followed by a 0-termianted string specifying the name of
404 the communicator which is to receive the message */
409 * Outer layer of an encapsulated unfragmented application message sent
410 * over an unreliable channel.
412 struct TransportReliabilityBox
415 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
417 struct GNUNET_MessageHeader header;
420 * Number of messages still to be sent before a commulative
421 * ACK is requested. Zero if an ACK is requested immediately.
422 * In NBO. Note that the receiver may send the ACK faster
423 * if it believes that is reasonable.
425 uint32_t ack_countdown GNUNET_PACKED;
428 * Unique ID of the message used for signalling receipt of
429 * messages sent over possibly unreliable channels. Should
432 struct GNUNET_ShortHashCode msg_uuid;
437 * Confirmation that the receiver got a
438 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
439 * confirmation may be transmitted over a completely different queue,
440 * so ACKs are identified by a combination of PID of sender and
441 * message UUID, without the queue playing any role!
443 struct TransportReliabilityAckMessage
446 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
448 struct GNUNET_MessageHeader header;
453 uint32_t reserved GNUNET_PACKED;
456 * How long was the ACK delayed relative to the average time of
457 * receipt of the messages being acknowledged? Used to calculate
458 * the average RTT by taking the receipt time of the ack minus the
459 * average transmission time of the sender minus this value.
461 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
463 /* followed by any number of `struct GNUNET_ShortHashCode`
464 messages providing ACKs */
469 * Outer layer of an encapsulated fragmented application message.
471 struct TransportFragmentBox
474 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
476 struct GNUNET_MessageHeader header;
479 * Unique ID of this fragment (and fragment transmission!). Will
480 * change even if a fragement is retransmitted to make each
481 * transmission attempt unique! Should be incremented by one for
482 * each fragment transmission. If a client receives a duplicate
483 * fragment (same @e frag_off), it must send
484 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
486 uint32_t frag_uuid GNUNET_PACKED;
489 * Original message ID for of the message that all the1
490 * fragments belong to. Must be the same for all fragments.
492 struct GNUNET_ShortHashCode msg_uuid;
495 * Offset of this fragment in the overall message.
497 uint16_t frag_off GNUNET_PACKED;
500 * Total size of the message that is being fragmented.
502 uint16_t msg_size GNUNET_PACKED;
507 * Outer layer of an fragmented application message sent over a queue
508 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
509 * received, the receiver has two RTTs or 64 further fragments with
510 * the same basic message time to send an acknowledgement, possibly
511 * acknowledging up to 65 fragments in one ACK. ACKs must also be
512 * sent immediately once all fragments were sent.
514 struct TransportFragmentAckMessage
517 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
519 struct GNUNET_MessageHeader header;
522 * Unique ID of the lowest fragment UUID being acknowledged.
524 uint32_t frag_uuid GNUNET_PACKED;
527 * Bitfield of up to 64 additional fragments following the
528 * @e msg_uuid being acknowledged by this message.
530 uint64_t extra_acks GNUNET_PACKED;
533 * Original message ID for of the message that all the
534 * fragments belong to.
536 struct GNUNET_ShortHashCode msg_uuid;
539 * How long was the ACK delayed relative to the average time of
540 * receipt of the fragments being acknowledged? Used to calculate
541 * the average RTT by taking the receipt time of the ack minus the
542 * average transmission time of the sender minus this value.
544 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
547 * How long until the receiver will stop trying reassembly
550 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
555 * Content signed by the initator during DV learning.
557 * The signature is required to prevent DDoS attacks. A peer sending out this
558 * message is potentially generating a lot of traffic that will go back to the
559 * initator, as peers receiving this message will try to let the initiator
560 * know that they got the message.
562 * Without this signature, an attacker could abuse this mechanism for traffic
563 * amplification, sending a lot of traffic to a peer by putting out this type
564 * of message with the victim's peer identity.
566 * Even with just a signature, traffic amplification would be possible via
567 * replay attacks. The @e monotonic_time limits such replay attacks, as every
568 * potential amplificator will check the @e monotonic_time and only respond
569 * (at most) once per message.
574 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
576 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
579 * Time at the initiator when generating the signature.
581 * Note that the receiver MUST IGNORE the absolute time, and only interpret
582 * the value as a mononic time and reject "older" values than the last one
583 * observed. This is necessary as we do not want to require synchronized
584 * clocks and may not have a bidirectional communication channel.
586 * Even with this, there is no real guarantee against replay achieved here,
587 * unless the latest timestamp is persisted. Persistence should be
588 * provided via PEERSTORE if possible.
590 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
593 * Challenge value used by the initiator to re-identify the path.
595 struct GNUNET_ShortHashCode challenge;
600 * Content signed by each peer during DV learning.
602 * This assues the initiator of the DV learning operation that the hop from @e
603 * pred via the signing peer to @e succ actually exists. This makes it
604 * impossible for an adversary to supply the network with bogus routes.
606 * The @e challenge is included to provide replay protection for the
607 * initiator. This way, the initiator knows that the hop existed after the
608 * original @e challenge was first transmitted, providing a freshness metric.
610 * Peers other than the initiator that passively learn paths by observing
611 * these messages do NOT benefit from this. Here, an adversary may indeed
612 * replay old messages. Thus, passively learned paths should always be
613 * immediately marked as "potentially stale".
618 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
620 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
623 * Identity of the previous peer on the path.
625 struct GNUNET_PeerIdentity pred;
628 * Identity of the next peer on the path.
630 struct GNUNET_PeerIdentity succ;
633 * Challenge value used by the initiator to re-identify the path.
635 struct GNUNET_ShortHashCode challenge;
640 * An entry describing a peer on a path in a
641 * `struct TransportDVLearn` message.
646 * Identity of a peer on the path.
648 struct GNUNET_PeerIdentity hop;
651 * Signature of this hop over the path, of purpose
652 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
654 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
659 * Internal message used by transport for distance vector learning.
660 * If @e num_hops does not exceed the threshold, peers should append
661 * themselves to the peer list and flood the message (possibly only
662 * to a subset of their neighbours to limit discoverability of the
663 * network topology). To the extend that the @e bidirectional bits
664 * are set, peers may learn the inverse paths even if they did not
667 * Unless received on a bidirectional queue and @e num_hops just
668 * zero, peers that can forward to the initator should always try to
669 * forward to the initiator.
671 struct TransportDVLearn
674 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
676 struct GNUNET_MessageHeader header;
679 * Number of hops this messages has travelled, in NBO. Zero if
682 uint16_t num_hops GNUNET_PACKED;
685 * Bitmask of the last 16 hops indicating whether they are confirmed
686 * available (without DV) in both directions or not, in NBO. Used
687 * to possibly instantly learn a path in both directions. Each peer
688 * should shift this value by one to the left, and then set the
689 * lowest bit IF the current sender can be reached from it (without
692 uint16_t bidirectional GNUNET_PACKED;
695 * Peers receiving this message and delaying forwarding to other
696 * peers for any reason should increment this value by the non-network
697 * delay created by the peer.
699 struct GNUNET_TIME_RelativeNBO non_network_delay;
702 * Signature of this hop over the path, of purpose
703 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
705 struct GNUNET_CRYPTO_EddsaSignature init_sig;
708 * Identity of the peer that started this learning activity.
710 struct GNUNET_PeerIdentity initiator;
713 * Challenge value used by the initiator to re-identify the path.
715 struct GNUNET_ShortHashCode challenge;
717 /* Followed by @e num_hops `struct DVPathEntryP` values,
718 excluding the initiator of the DV trace; the last entry is the
719 current sender; the current peer must not be included. */
724 * Outer layer of an encapsulated message send over multiple hops.
725 * The path given only includes the identities of the subsequent
726 * peers, i.e. it will be empty if we are the receiver. Each
727 * forwarding peer should scan the list from the end, and if it can,
728 * forward to the respective peer. The list should then be shortened
729 * by all the entries up to and including that peer. Each hop should
730 * also increment @e total_hops to allow the receiver to get a precise
731 * estimate on the number of hops the message travelled. Senders must
732 * provide a learned path that thus should work, but intermediaries
733 * know of a shortcut, they are allowed to send the message via that
736 * If a peer finds itself still on the list, it must drop the message.
738 struct TransportDVBox
741 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
743 struct GNUNET_MessageHeader header;
746 * Number of total hops this messages travelled. In NBO.
747 * @e origin sets this to zero, to be incremented at
750 uint16_t total_hops GNUNET_PACKED;
753 * Number of hops this messages includes. In NBO.
755 uint16_t num_hops GNUNET_PACKED;
758 * Identity of the peer that originated the message.
760 struct GNUNET_PeerIdentity origin;
762 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
763 excluding the @e origin and the current peer, the last must be
764 the ultimate target; if @e num_hops is zero, the receiver of this
765 message is the ultimate target. */
767 /* Followed by the actual message, which itself may be
768 another box, but not a DV_LEARN or DV_BOX message! */
773 * Message send to another peer to validate that it can indeed
774 * receive messages at a particular address.
776 struct TransportValidationChallenge
780 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
782 struct GNUNET_MessageHeader header;
787 uint32_t reserved GNUNET_PACKED;
790 * Challenge to be signed by the receiving peer.
792 struct GNUNET_ShortHashCode challenge;
795 * Timestamp of the sender, to be copied into the reply
796 * to allow sender to calculate RTT.
798 struct GNUNET_TIME_AbsoluteNBO sender_time;
803 * Message signed by a peer to confirm that it can indeed
804 * receive messages at a particular address.
806 struct TransportValidationPS
810 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
812 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
815 * How long does the sender believe the address on
816 * which the challenge was received to remain valid?
818 struct GNUNET_TIME_RelativeNBO validity_duration;
821 * Challenge signed by the receiving peer.
823 struct GNUNET_ShortHashCode challenge;
828 * Message send to a peer to respond to a
829 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
831 struct TransportValidationResponse
835 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
837 struct GNUNET_MessageHeader header;
842 uint32_t reserved GNUNET_PACKED;
845 * The peer's signature matching the
846 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
848 struct GNUNET_CRYPTO_EddsaSignature signature;
851 * The challenge that was signed by the receiving peer.
853 struct GNUNET_ShortHashCode challenge;
856 * Original timestamp of the sender (was @code{sender_time}),
857 * copied into the reply to allow sender to calculate RTT.
859 struct GNUNET_TIME_AbsoluteNBO origin_time;
862 * How long does the sender believe this address to remain
865 struct GNUNET_TIME_RelativeNBO validity_duration;
869 GNUNET_NETWORK_STRUCT_END
873 * What type of client is the `struct TransportClient` about?
878 * We do not know yet (client is fresh).
883 * Is the CORE service, we need to forward traffic to it.
888 * It is a monitor, forward monitor data.
893 * It is a communicator, use for communication.
898 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
905 * When did we launch this DV learning activity?
907 struct LearnLaunchEntry
911 * Kept (also) in a DLL sorted by launch time.
913 struct LearnLaunchEntry *prev;
916 * Kept (also) in a DLL sorted by launch time.
918 struct LearnLaunchEntry *next;
921 * Challenge that uniquely identifies this activity.
923 struct GNUNET_ShortHashCode challenge;
926 * When did we transmit the DV learn message (used to calculate RTT) and
927 * determine freshness of paths learned via this operation.
929 struct GNUNET_TIME_Absolute launch_time;
934 * Entry in our cache of ephemeral keys we currently use. This way, we only
935 * sign an ephemeral once per @e target, and then can re-use it over multiple
936 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
937 * signing is expensive and in some cases we may use backchannel messages a
940 struct EphemeralCacheEntry
944 * Target's peer identity (we don't re-use ephemerals
945 * to limit linkability of messages).
947 struct GNUNET_PeerIdentity target;
950 * Signature affirming @e ephemeral_key of type
951 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
953 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
956 * How long is @e sender_sig valid
958 struct GNUNET_TIME_Absolute ephemeral_validity;
963 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
966 * Our private ephemeral key.
968 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
971 * Node in the ephemeral cache for this entry.
972 * Used for expiration.
974 struct GNUNET_CONTAINER_HeapNode *hn;
979 * Client connected to the transport service.
981 struct TransportClient;
985 * A neighbour that at least one communicator is connected to.
991 * Entry in our #dv_routes table, representing a (set of) distance
992 * vector routes to a particular peer.
994 struct DistanceVector;
997 * One possible hop towards a DV target.
999 struct DistanceVectorHop
1003 * Kept in a MDLL, sorted by @e timeout.
1005 struct DistanceVectorHop *next_dv;
1008 * Kept in a MDLL, sorted by @e timeout.
1010 struct DistanceVectorHop *prev_dv;
1015 struct DistanceVectorHop *next_neighbour;
1020 struct DistanceVectorHop *prev_neighbour;
1023 * What would be the next hop to @e target?
1025 struct Neighbour *next_hop;
1028 * Distance vector entry this hop belongs with.
1030 struct DistanceVector *dv;
1033 * Array of @e distance hops to the target, excluding @e next_hop.
1034 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1035 * at the end of this struct. Excludes the target itself!
1037 const struct GNUNET_PeerIdentity *path;
1040 * At what time do we forget about this path unless we see it again
1043 struct GNUNET_TIME_Absolute timeout;
1046 * After what time do we know for sure that the path must have existed?
1047 * Set to ZERO if the path is learned by snooping on DV learn messages
1048 * initiated by other peers, and to the time at which we generated the
1049 * challenge for DV learn operations this peer initiated.
1051 * FIXME: freshness is currently never set!
1053 struct GNUNET_TIME_Absolute freshness;
1056 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1057 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1060 unsigned int distance;
1065 * Entry in our #dv_routes table, representing a (set of) distance
1066 * vector routes to a particular peer.
1068 struct DistanceVector
1072 * To which peer is this a route?
1074 struct GNUNET_PeerIdentity target;
1077 * Known paths to @e target.
1079 struct DistanceVectorHop *dv_head;
1082 * Known paths to @e target.
1084 struct DistanceVectorHop *dv_tail;
1087 * Task scheduled to purge expired paths from @e dv_head MDLL.
1089 struct GNUNET_SCHEDULER_Task *timeout_task;
1092 * Is one of the DV paths in this struct 'confirmed' and thus
1093 * the cause for CORE to see this peer as connected? (Note that
1094 * the same may apply to a `struct Neighbour` at the same time.)
1101 * A queue is a message queue provided by a communicator
1102 * via which we can reach a particular neighbour.
1108 * Entry identifying transmission in one of our `struct
1109 * Queue` which still awaits an ACK. This is used to
1110 * ensure we do not overwhelm a communicator and limit the number of
1111 * messages outstanding per communicator (say in case communicator is
1112 * CPU bound) and per queue (in case bandwidth allocation exceeds
1113 * what the communicator can actually provide towards a particular
1122 struct QueueEntry *next;
1127 struct QueueEntry *prev;
1130 * Queue this entry is queued with.
1132 struct Queue *queue;
1135 * Message ID used for this message with the queue used for transmission.
1142 * A queue is a message queue provided by a communicator
1143 * via which we can reach a particular neighbour.
1150 struct Queue *next_neighbour;
1155 struct Queue *prev_neighbour;
1160 struct Queue *prev_client;
1165 struct Queue *next_client;
1168 * Head of DLL of unacked transmission requests.
1170 struct QueueEntry *queue_head;
1173 * End of DLL of unacked transmission requests.
1175 struct QueueEntry *queue_tail;
1178 * Which neighbour is this queue for?
1180 struct Neighbour *neighbour;
1183 * Which communicator offers this queue?
1185 struct TransportClient *tc;
1188 * Address served by the queue.
1190 const char *address;
1193 * Task scheduled for the time when this queue can (likely) transmit the
1194 * next message. Still needs to check with the @e tracker_out to be sure.
1196 struct GNUNET_SCHEDULER_Task *transmit_task;
1199 * Task scheduled to possibly notfiy core that this queue is no longer
1200 * counting as confirmed. Runs the #core_queue_visibility_check().
1202 struct GNUNET_SCHEDULER_Task *visibility_task;
1205 * Our current RTT estimate for this queue.
1207 struct GNUNET_TIME_Relative rtt;
1210 * How long do *we* consider this @e address to be valid? In the past or
1211 * zero if we have not yet validated it. Can be updated based on
1212 * challenge-response validations (via address validation logic), or when we
1213 * receive ACKs that we can definitively map to transmissions via this
1216 struct GNUNET_TIME_Absolute validated_until;
1219 * Message ID generator for transmissions on this queue.
1224 * Unique identifier of this queue with the communicator.
1229 * Maximum transmission unit supported by this queue.
1234 * Distance to the target of this queue.
1235 * FIXME: needed? DV is done differently these days...
1242 uint32_t num_msg_pending;
1247 uint32_t num_bytes_pending;
1250 * Length of the DLL starting at @e queue_head.
1252 unsigned int queue_length;
1255 * Network type offered by this queue.
1257 enum GNUNET_NetworkType nt;
1260 * Connection status for this queue.
1262 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1265 * How much outbound bandwidth do we have available for this queue?
1267 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1270 * How much inbound bandwidth do we have available for this queue?
1272 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1277 * Information we keep for a message that we are reassembling.
1279 struct ReassemblyContext
1283 * Original message ID for of the message that all the
1284 * fragments belong to.
1286 struct GNUNET_ShortHashCode msg_uuid;
1289 * Which neighbour is this context for?
1291 struct Neighbour *neighbour;
1294 * Entry in the reassembly heap (sorted by expiration).
1296 struct GNUNET_CONTAINER_HeapNode *hn;
1299 * Bitfield with @e msg_size bits representing the positions
1300 * where we have received fragments. When we receive a fragment,
1301 * we check the bits in @e bitfield before incrementing @e msg_missing.
1303 * Allocated after the reassembled message.
1308 * Task for sending ACK. We may send ACKs either because of hitting
1309 * the @e extra_acks limit, or based on time and @e num_acks. This
1310 * task is for the latter case.
1312 struct GNUNET_SCHEDULER_Task *ack_task;
1315 * At what time will we give up reassembly of this message?
1317 struct GNUNET_TIME_Absolute reassembly_timeout;
1320 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1321 * Should be reset to zero when @e num_acks is set to 0.
1323 struct GNUNET_TIME_Relative avg_ack_delay;
1326 * Time we received the last fragment. @e avg_ack_delay must be
1327 * incremented by now - @e last_frag multiplied by @e num_acks.
1329 struct GNUNET_TIME_Absolute last_frag;
1332 * Bitfield of up to 64 additional fragments following @e frag_uuid
1333 * to be acknowledged in the next cummulative ACK.
1335 uint64_t extra_acks;
1338 * Unique ID of the lowest fragment UUID to be acknowledged in the
1339 * next cummulative ACK. Only valid if @e num_acks > 0.
1344 * Number of ACKs we have accumulated so far. Reset to 0
1345 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1347 unsigned int num_acks;
1350 * How big is the message we are reassembling in total?
1355 * How many bytes of the message are still missing? Defragmentation
1356 * is complete when @e msg_missing == 0.
1358 uint16_t msg_missing;
1360 /* Followed by @e msg_size bytes of the (partially) defragmented original
1363 /* Followed by @e bitfield data */
1368 * A neighbour that at least one communicator is connected to.
1374 * Which peer is this about?
1376 struct GNUNET_PeerIdentity pid;
1379 * Map with `struct ReassemblyContext` structs for fragments under
1380 * reassembly. May be NULL if we currently have no fragments from
1381 * this @e pid (lazy initialization).
1383 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1386 * Heap with `struct ReassemblyContext` structs for fragments under
1387 * reassembly. May be NULL if we currently have no fragments from
1388 * this @e pid (lazy initialization).
1390 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1393 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1395 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1398 * Head of list of messages pending for this neighbour.
1400 struct PendingMessage *pending_msg_head;
1403 * Tail of list of messages pending for this neighbour.
1405 struct PendingMessage *pending_msg_tail;
1408 * Head 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_head;
1414 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1415 * purged if this neighbour goes down.
1417 struct DistanceVectorHop *dv_tail;
1420 * Head of DLL of queues to this peer.
1422 struct Queue *queue_head;
1425 * Tail of DLL of queues to this peer.
1427 struct Queue *queue_tail;
1430 * Task run to cleanup pending messages that have exceeded their timeout.
1432 struct GNUNET_SCHEDULER_Task *timeout_task;
1435 * Quota at which CORE is allowed to transmit to this peer.
1437 * FIXME: not yet used, tricky to get right given multiple queues!
1438 * (=> Idea: measure???)
1439 * FIXME: how do we set this value initially when we tell CORE?
1440 * Options: start at a minimum value or at literally zero?
1441 * (=> Current thought: clean would be zero!)
1443 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1446 * What is the earliest timeout of any message in @e pending_msg_tail?
1448 struct GNUNET_TIME_Absolute earliest_timeout;
1451 * Do we have a confirmed working queue and are thus visible to
1459 * A peer that an application (client) would like us to talk to directly.
1465 * Which peer is this about?
1467 struct GNUNET_PeerIdentity pid;
1470 * Client responsible for the request.
1472 struct TransportClient *tc;
1475 * Handle for watching the peerstore for HELLOs for this peer.
1477 struct GNUNET_PEERSTORE_WatchContext *wc;
1480 * What kind of performance preference does this @e tc have?
1482 enum GNUNET_MQ_PreferenceKind pk;
1485 * How much bandwidth would this @e tc like to see?
1487 struct GNUNET_BANDWIDTH_Value32NBO bw;
1492 * Types of different pending messages.
1494 enum PendingMessageType
1498 * Ordinary message received from the CORE service.
1505 PMT_FRAGMENT_BOX = 1,
1510 PMT_RELIABILITY_BOX = 2,
1513 * Any type of acknowledgement.
1515 PMT_ACKNOWLEDGEMENT = 3,
1518 * Control traffic generated by the TRANSPORT service itself.
1526 * Transmission request that is awaiting delivery. The original
1527 * transmission requests from CORE may be too big for some queues.
1528 * In this case, a *tree* of fragments is created. At each
1529 * level of the tree, fragments are kept in a DLL ordered by which
1530 * fragment should be sent next (at the head). The tree is searched
1531 * top-down, with the original message at the root.
1533 * To select a node for transmission, first it is checked if the
1534 * current node's message fits with the MTU. If it does not, we
1535 * either calculate the next fragment (based on @e frag_off) from the
1536 * current node, or, if all fragments have already been created,
1537 * descend to the @e head_frag. Even though the node was already
1538 * fragmented, the fragment may be too big if the fragment was
1539 * generated for a queue with a larger MTU. In this case, the node
1540 * may be fragmented again, thus creating a tree.
1542 * When acknowledgements for fragments are received, the tree
1543 * must be pruned, removing those parts that were already
1544 * acknowledged. When fragments are sent over a reliable
1545 * channel, they can be immediately removed.
1547 * If a message is ever fragmented, then the original "full" message
1548 * is never again transmitted (even if it fits below the MTU), and
1549 * only (remaining) fragments are sent.
1551 struct PendingMessage
1554 * Kept in a MDLL of messages for this @a target.
1556 struct PendingMessage *next_neighbour;
1559 * Kept in a MDLL of messages for this @a target.
1561 struct PendingMessage *prev_neighbour;
1564 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1566 struct PendingMessage *next_client;
1569 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1571 struct PendingMessage *prev_client;
1574 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1575 * #PMT_FRAGMENT_BOx)
1577 struct PendingMessage *next_frag;
1580 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1581 * #PMT_FRAGMENT_BOX)
1583 struct PendingMessage *prev_frag;
1586 * This message, reliability boxed. Only possibly available if @e pmt is
1589 struct PendingMessage *bpm;
1592 * Target of the request.
1594 struct Neighbour *target;
1597 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1599 struct TransportClient *client;
1602 * Head of a MDLL of fragments created for this core message.
1604 struct PendingMessage *head_frag;
1607 * Tail of a MDLL of fragments created for this core message.
1609 struct PendingMessage *tail_frag;
1612 * Our parent in the fragmentation tree.
1614 struct PendingMessage *frag_parent;
1617 * At what time should we give up on the transmission (and no longer retry)?
1619 struct GNUNET_TIME_Absolute timeout;
1622 * What is the earliest time for us to retry transmission of this message?
1624 struct GNUNET_TIME_Absolute next_attempt;
1627 * UUID to use for this message (used for reassembly of fragments, only
1628 * initialized if @e msg_uuid_set is #GNUNET_YES).
1630 struct GNUNET_ShortHashCode msg_uuid;
1633 * Counter incremented per generated fragment.
1635 uint32_t frag_uuidgen;
1638 * Type of the pending message.
1640 enum PendingMessageType pmt;
1643 * Size of the original message.
1648 * Offset at which we should generate the next fragment.
1653 * #GNUNET_YES once @e msg_uuid was initialized
1655 int16_t msg_uuid_set;
1657 /* Followed by @e bytes_msg to transmit */
1662 * One of the addresses of this peer.
1664 struct AddressListEntry
1670 struct AddressListEntry *next;
1675 struct AddressListEntry *prev;
1678 * Which communicator provides this address?
1680 struct TransportClient *tc;
1683 * The actual address.
1685 const char *address;
1688 * Current context for storing this address in the peerstore.
1690 struct GNUNET_PEERSTORE_StoreContext *sc;
1693 * Task to periodically do @e st operation.
1695 struct GNUNET_SCHEDULER_Task *st;
1698 * What is a typical lifetime the communicator expects this
1699 * address to have? (Always from now.)
1701 struct GNUNET_TIME_Relative expiration;
1704 * Address identifier used by the communicator.
1709 * Network type offered by this address.
1711 enum GNUNET_NetworkType nt;
1716 * Client connected to the transport service.
1718 struct TransportClient
1724 struct TransportClient *next;
1729 struct TransportClient *prev;
1732 * Handle to the client.
1734 struct GNUNET_SERVICE_Client *client;
1737 * Message queue to the client.
1739 struct GNUNET_MQ_Handle *mq;
1742 * What type of client is this?
1744 enum ClientType type;
1750 * Information for @e type #CT_CORE.
1756 * Head of list of messages pending for this client, sorted by
1757 * transmission time ("next_attempt" + possibly internal prioritization).
1759 struct PendingMessage *pending_msg_head;
1762 * Tail of list of messages pending for this client.
1764 struct PendingMessage *pending_msg_tail;
1769 * Information for @e type #CT_MONITOR.
1775 * Peer identity to monitor the addresses of.
1776 * Zero to monitor all neighbours. Valid if
1777 * @e type is #CT_MONITOR.
1779 struct GNUNET_PeerIdentity peer;
1782 * Is this a one-shot monitor?
1790 * Information for @e type #CT_COMMUNICATOR.
1795 * If @e type is #CT_COMMUNICATOR, this communicator
1796 * supports communicating using these addresses.
1798 char *address_prefix;
1801 * Head of DLL of queues offered by this communicator.
1803 struct Queue *queue_head;
1806 * Tail of DLL of queues offered by this communicator.
1808 struct Queue *queue_tail;
1811 * Head of list of the addresses of this peer offered by this
1814 struct AddressListEntry *addr_head;
1817 * Tail of list of the addresses of this peer offered by this
1820 struct AddressListEntry *addr_tail;
1823 * Number of queue entries in all queues to this communicator. Used
1824 * throttle sending to a communicator if we see that the communicator
1825 * is globally unable to keep up.
1827 unsigned int total_queue_length;
1830 * Characteristics of this communicator.
1832 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1837 * Information for @e type #CT_APPLICATION
1843 * Map of requests for peers the given client application would like to
1844 * see connections for. Maps from PIDs to `struct PeerRequest`.
1846 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1855 * State we keep for validation activities. Each of these
1856 * is both in the #validation_heap and the #validation_map.
1858 struct ValidationState
1862 * For which peer is @a address to be validated (or possibly valid)?
1863 * Serves as key in the #validation_map.
1865 struct GNUNET_PeerIdentity pid;
1868 * How long did the peer claim this @e address to be valid? Capped at
1869 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1870 * were told about the address and the value claimed by the other peer at
1871 * that time. May be updated similarly when validation succeeds.
1873 struct GNUNET_TIME_Absolute valid_until;
1876 * How long do *we* consider this @e address to be valid?
1877 * In the past or zero if we have not yet validated it.
1879 struct GNUNET_TIME_Absolute validated_until;
1882 * When did we FIRST use the current @e challenge in a message?
1883 * Used to sanity-check @code{origin_time} in the response when
1884 * calculating the RTT. If the @code{origin_time} is not in
1885 * the expected range, the response is discarded as malicious.
1887 struct GNUNET_TIME_Absolute first_challenge_use;
1890 * When did we LAST use the current @e challenge in a message?
1891 * Used to sanity-check @code{origin_time} in the response when
1892 * calculating the RTT. If the @code{origin_time} is not in
1893 * the expected range, the response is discarded as malicious.
1895 struct GNUNET_TIME_Absolute last_challenge_use;
1898 * Next time we will send the @e challenge to the peer, if this time is past
1899 * @e valid_until, this validation state is released at this time. If the
1900 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1901 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1902 * to re-validate before the validity actually expires.
1904 struct GNUNET_TIME_Absolute next_challenge;
1907 * Current backoff factor we're applying for sending the @a challenge.
1908 * Reset to 0 if the @a challenge is confirmed upon validation.
1909 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1910 * existing value if we receive an unvalidated address again over
1911 * another channel (and thus should consider the information "fresh").
1912 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1914 struct GNUNET_TIME_Relative challenge_backoff;
1917 * Initially set to "forever". Once @e validated_until is set, this value is
1918 * set to the RTT that tells us how long it took to receive the validation.
1920 struct GNUNET_TIME_Relative validation_rtt;
1923 * The challenge we sent to the peer to get it to validate the address. Note
1924 * that we rotate the challenge whenever we update @e validated_until to
1925 * avoid attacks where a peer simply replays an old challenge in the future.
1926 * (We must not rotate more often as otherwise we may discard valid answers
1927 * due to packet losses, latency and reorderings on the network).
1929 struct GNUNET_ShortHashCode challenge;
1932 * Claimed address of the peer.
1937 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1938 * heap is used to figure out when the next validation activity should be
1941 struct GNUNET_CONTAINER_HeapNode *hn;
1944 * Handle to a PEERSTORE store operation for this @e address. NULL if
1945 * no PEERSTORE operation is pending.
1947 struct GNUNET_PEERSTORE_StoreContext *sc;
1950 * We are technically ready to send the challenge, but we are waiting for
1951 * the respective queue to become available for transmission.
1958 * Head of linked list of all clients to this service.
1960 static struct TransportClient *clients_head;
1963 * Tail of linked list of all clients to this service.
1965 static struct TransportClient *clients_tail;
1968 * Statistics handle.
1970 static struct GNUNET_STATISTICS_Handle *GST_stats;
1973 * Configuration handle.
1975 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1980 static struct GNUNET_PeerIdentity GST_my_identity;
1985 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1988 * Map from PIDs to `struct Neighbour` entries. A peer is
1989 * a neighbour if we have an MQ to it from some communicator.
1991 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1994 * Map from PIDs to `struct DistanceVector` entries describing
1995 * known paths to the peer.
1997 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2000 * Map from PIDs to `struct ValidationState` entries describing
2001 * addresses we are aware of and their validity state.
2003 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2006 * Map from challenges to `struct LearnLaunchEntry` values.
2008 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2011 * Head of a DLL sorted by launch time.
2013 static struct LearnLaunchEntry *lle_head;
2016 * Tail of a DLL sorted by launch time.
2018 static struct LearnLaunchEntry *lle_tail;
2021 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2022 * sorting addresses we are aware of by when we should next try to (re)validate
2025 static struct GNUNET_CONTAINER_Heap *validation_heap;
2028 * Database for peer's HELLOs.
2030 static struct GNUNET_PEERSTORE_Handle *peerstore;
2033 * Heap sorting `struct EphemeralCacheEntry` by their
2034 * key/signature validity.
2036 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2039 * Hash map for looking up `struct EphemeralCacheEntry`s
2040 * by peer identity. (We may have ephemerals in our
2041 * cache for which we do not have a neighbour entry,
2042 * and similar many neighbours may not need ephemerals,
2043 * so we use a second map.)
2045 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2048 * Task to free expired ephemerals.
2050 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2053 * Task run to initiate DV learning.
2055 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2058 * Task to run address validation.
2060 static struct GNUNET_SCHEDULER_Task *validation_task;
2064 * Free cached ephemeral key.
2066 * @param ece cached signature to free
2069 free_ephemeral (struct EphemeralCacheEntry *ece)
2071 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2072 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2078 * Free validation state.
2080 * @param vs validation state to free
2083 free_validation_state (struct ValidationState *vs)
2085 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2086 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2090 GNUNET_PEERSTORE_store_cancel (vs->sc);
2093 GNUNET_free (vs->address);
2099 * Lookup neighbour record for peer @a pid.
2101 * @param pid neighbour to look for
2102 * @return NULL if we do not have this peer as a neighbour
2104 static struct Neighbour *
2105 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2107 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2112 * Details about what to notify monitors about.
2117 * @deprecated To be discussed if we keep these...
2119 struct GNUNET_TIME_Absolute last_validation;
2120 struct GNUNET_TIME_Absolute valid_until;
2121 struct GNUNET_TIME_Absolute next_validation;
2124 * Current round-trip time estimate.
2126 struct GNUNET_TIME_Relative rtt;
2129 * Connection status.
2131 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2136 uint32_t num_msg_pending;
2141 uint32_t num_bytes_pending;
2146 * Free a @dvh. Callers MAY want to check if this was the last path to the
2147 * `target`, and if so call #free_dv_route to also free the associated DV
2148 * entry in #dv_routes (if not, the associated scheduler job should eventually
2151 * @param dvh hop to free
2154 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2156 struct Neighbour *n = dvh->next_hop;
2157 struct DistanceVector *dv = dvh->dv;
2159 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2160 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2166 * Free entry in #dv_routes. First frees all hops to the target, and
2167 * if there are no entries left, frees @a dv as well.
2169 * @param dv route to free
2172 free_dv_route (struct DistanceVector *dv)
2174 struct DistanceVectorHop *dvh;
2176 while (NULL != (dvh = dv->dv_head))
2177 free_distance_vector_hop (dvh);
2178 if (NULL == dv->dv_head)
2182 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2183 if (NULL != dv->timeout_task)
2184 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2191 * Notify monitor @a tc about an event. That @a tc
2192 * cares about the event has already been checked.
2194 * Send @a tc information in @a me about a @a peer's status with
2195 * respect to some @a address to all monitors that care.
2197 * @param tc monitor to inform
2198 * @param peer peer the information is about
2199 * @param address address the information is about
2200 * @param nt network type associated with @a address
2201 * @param me detailed information to transmit
2204 notify_monitor (struct TransportClient *tc,
2205 const struct GNUNET_PeerIdentity *peer,
2206 const char *address,
2207 enum GNUNET_NetworkType nt,
2208 const struct MonitorEvent *me)
2210 struct GNUNET_MQ_Envelope *env;
2211 struct GNUNET_TRANSPORT_MonitorData *md;
2212 size_t addr_len = strlen (address) + 1;
2214 env = GNUNET_MQ_msg_extra (md,
2216 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2217 md->nt = htonl ((uint32_t) nt);
2219 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2220 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2221 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2222 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2223 md->cs = htonl ((uint32_t) me->cs);
2224 md->num_msg_pending = htonl (me->num_msg_pending);
2225 md->num_bytes_pending = htonl (me->num_bytes_pending);
2226 memcpy (&md[1], address, addr_len);
2227 GNUNET_MQ_send (tc->mq, env);
2232 * Send information in @a me about a @a peer's status with respect
2233 * to some @a address to all monitors that care.
2235 * @param peer peer the information is about
2236 * @param address address the information is about
2237 * @param nt network type associated with @a address
2238 * @param me detailed information to transmit
2241 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2242 const char *address,
2243 enum GNUNET_NetworkType nt,
2244 const struct MonitorEvent *me)
2246 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2248 if (CT_MONITOR != tc->type)
2250 if (tc->details.monitor.one_shot)
2252 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2253 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2255 notify_monitor (tc, peer, address, nt, me);
2261 * Called whenever a client connects. Allocates our
2262 * data structures associated with that client.
2264 * @param cls closure, NULL
2265 * @param client identification of the client
2266 * @param mq message queue for the client
2267 * @return our `struct TransportClient`
2270 client_connect_cb (void *cls,
2271 struct GNUNET_SERVICE_Client *client,
2272 struct GNUNET_MQ_Handle *mq)
2274 struct TransportClient *tc;
2277 tc = GNUNET_new (struct TransportClient);
2278 tc->client = client;
2280 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2289 * @param rc data structure to free
2292 free_reassembly_context (struct ReassemblyContext *rc)
2294 struct Neighbour *n = rc->neighbour;
2296 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2297 GNUNET_assert (GNUNET_OK ==
2298 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2306 * Task run to clean up reassembly context of a neighbour that have expired.
2308 * @param cls a `struct Neighbour`
2311 reassembly_cleanup_task (void *cls)
2313 struct Neighbour *n = cls;
2314 struct ReassemblyContext *rc;
2316 n->reassembly_timeout_task = NULL;
2317 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2319 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2322 free_reassembly_context (rc);
2325 GNUNET_assert (NULL == n->reassembly_timeout_task);
2326 n->reassembly_timeout_task =
2327 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2328 &reassembly_cleanup_task,
2336 * function called to #free_reassembly_context().
2340 * @param value a `struct ReassemblyContext` to free
2341 * @return #GNUNET_OK (continue iteration)
2344 free_reassembly_cb (void *cls,
2345 const struct GNUNET_ShortHashCode *key,
2348 struct ReassemblyContext *rc = value;
2352 free_reassembly_context (rc);
2358 * Release memory used by @a neighbour.
2360 * @param neighbour neighbour entry to free
2363 free_neighbour (struct Neighbour *neighbour)
2365 struct DistanceVectorHop *dvh;
2367 GNUNET_assert (NULL == neighbour->queue_head);
2368 GNUNET_assert (GNUNET_YES ==
2369 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2372 if (NULL != neighbour->timeout_task)
2373 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2374 if (NULL != neighbour->reassembly_map)
2376 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2377 &free_reassembly_cb,
2379 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2380 neighbour->reassembly_map = NULL;
2381 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2382 neighbour->reassembly_heap = NULL;
2384 while (NULL != (dvh = neighbour->dv_head))
2386 struct DistanceVector *dv = dvh->dv;
2388 free_distance_vector_hop (dvh);
2389 if (NULL == dv->dv_head)
2392 if (NULL != neighbour->reassembly_timeout_task)
2393 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2394 GNUNET_free (neighbour);
2399 * Send message to CORE clients that we lost a connection.
2401 * @param tc client to inform (must be CORE client)
2402 * @param pid peer the connection is for
2403 * @param quota_out current quota for the peer
2406 core_send_connect_info (struct TransportClient *tc,
2407 const struct GNUNET_PeerIdentity *pid,
2408 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2410 struct GNUNET_MQ_Envelope *env;
2411 struct ConnectInfoMessage *cim;
2413 GNUNET_assert (CT_CORE == tc->type);
2414 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2415 cim->quota_out = quota_out;
2417 GNUNET_MQ_send (tc->mq, env);
2422 * Send message to CORE clients that we gained a connection
2424 * @param pid peer the queue was for
2425 * @param quota_out current quota for the peer
2428 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2429 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2431 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2433 if (CT_CORE != tc->type)
2435 core_send_connect_info (tc, pid, quota_out);
2441 * Send message to CORE clients that we lost a connection.
2443 * @param pid peer the connection was for
2446 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2448 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2450 struct GNUNET_MQ_Envelope *env;
2451 struct DisconnectInfoMessage *dim;
2453 if (CT_CORE != tc->type)
2455 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2457 GNUNET_MQ_send (tc->mq, env);
2463 * We believe we are ready to transmit a message on a queue. Double-checks
2464 * with the queue's "tracker_out" and then gives the message to the
2465 * communicator for transmission (updating the tracker, and re-scheduling
2466 * itself if applicable).
2468 * @param cls the `struct Queue` to process transmissions for
2471 transmit_on_queue (void *cls);
2475 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2476 * we should run immediately or if the message queue is empty.
2477 * Test for no task being added AND queue not being empty to
2478 * transmit immediately afterwards! This function must only
2479 * be called if the message queue is non-empty!
2481 * @param queue the queue to do scheduling for
2484 schedule_transmit_on_queue (struct Queue *queue)
2486 struct Neighbour *n = queue->neighbour;
2487 struct PendingMessage *pm = n->pending_msg_head;
2488 struct GNUNET_TIME_Relative out_delay;
2491 GNUNET_assert (NULL != pm);
2492 if (queue->tc->details.communicator.total_queue_length >=
2493 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2495 GNUNET_STATISTICS_update (
2497 "# Transmission throttled due to communicator queue limit",
2502 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2504 GNUNET_STATISTICS_update (GST_stats,
2505 "# Transmission throttled due to queue queue limit",
2511 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
2513 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
2514 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
2517 if (0 == out_delay.rel_value_us)
2518 return; /* we should run immediately! */
2519 /* queue has changed since we were scheduled, reschedule again */
2520 queue->transmit_task =
2521 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
2522 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2523 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2524 "Next transmission on queue `%s' in %s (high delay)\n",
2526 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2529 "Next transmission on queue `%s' in %s\n",
2531 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2536 * Check whether the CORE visibility of @a n changed. If so,
2537 * check whether we need to notify CORE.
2539 * @param n neighbour to perform the check for
2542 update_neighbour_core_visibility (struct Neighbour *n);
2548 * @param queue the queue to free
2551 free_queue (struct Queue *queue)
2553 struct Neighbour *neighbour = queue->neighbour;
2554 struct TransportClient *tc = queue->tc;
2555 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
2556 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
2557 struct QueueEntry *qe;
2560 if (NULL != queue->transmit_task)
2562 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2563 queue->transmit_task = NULL;
2565 if (NULL != queue->visibility_task)
2567 GNUNET_SCHEDULER_cancel (queue->visibility_task);
2568 queue->visibility_task = NULL;
2570 GNUNET_CONTAINER_MDLL_remove (neighbour,
2571 neighbour->queue_head,
2572 neighbour->queue_tail,
2574 GNUNET_CONTAINER_MDLL_remove (client,
2575 tc->details.communicator.queue_head,
2576 tc->details.communicator.queue_tail,
2578 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
2579 tc->details.communicator.total_queue_length);
2580 while (NULL != (qe = queue->queue_head))
2582 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
2583 queue->queue_length--;
2584 tc->details.communicator.total_queue_length--;
2587 GNUNET_assert (0 == queue->queue_length);
2588 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
2589 tc->details.communicator.total_queue_length))
2591 /* Communicator dropped below threshold, resume all queues */
2592 GNUNET_STATISTICS_update (
2594 "# Transmission throttled due to communicator queue limit",
2597 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
2599 schedule_transmit_on_queue (s);
2601 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
2602 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2603 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2604 GNUNET_free (queue);
2606 update_neighbour_core_visibility (neighbour);
2607 cores_send_disconnect_info (&neighbour->pid);
2609 if (NULL == neighbour->queue_head)
2611 free_neighbour (neighbour);
2619 * @param ale address list entry to free
2622 free_address_list_entry (struct AddressListEntry *ale)
2624 struct TransportClient *tc = ale->tc;
2626 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2627 tc->details.communicator.addr_tail,
2629 if (NULL != ale->sc)
2631 GNUNET_PEERSTORE_store_cancel (ale->sc);
2634 if (NULL != ale->st)
2636 GNUNET_SCHEDULER_cancel (ale->st);
2644 * Stop the peer request in @a value.
2646 * @param cls a `struct TransportClient` that no longer makes the request
2647 * @param pid the peer's identity
2648 * @param value a `struct PeerRequest`
2649 * @return #GNUNET_YES (always)
2652 stop_peer_request (void *cls,
2653 const struct GNUNET_PeerIdentity *pid,
2656 struct TransportClient *tc = cls;
2657 struct PeerRequest *pr = value;
2659 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2662 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2672 * Called whenever a client is disconnected. Frees our
2673 * resources associated with that client.
2675 * @param cls closure, NULL
2676 * @param client identification of the client
2677 * @param app_ctx our `struct TransportClient`
2680 client_disconnect_cb (void *cls,
2681 struct GNUNET_SERVICE_Client *client,
2684 struct TransportClient *tc = app_ctx;
2687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2688 "Client %p disconnected, cleaning up.\n",
2690 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
2696 struct PendingMessage *pm;
2698 while (NULL != (pm = tc->details.core.pending_msg_head))
2700 GNUNET_CONTAINER_MDLL_remove (client,
2701 tc->details.core.pending_msg_head,
2702 tc->details.core.pending_msg_tail,
2710 case CT_COMMUNICATOR: {
2712 struct AddressListEntry *ale;
2714 while (NULL != (q = tc->details.communicator.queue_head))
2716 while (NULL != (ale = tc->details.communicator.addr_head))
2717 free_address_list_entry (ale);
2718 GNUNET_free (tc->details.communicator.address_prefix);
2721 case CT_APPLICATION:
2722 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2725 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2733 * Iterator telling new CORE client about all existing
2734 * connections to peers.
2736 * @param cls the new `struct TransportClient`
2737 * @param pid a connected peer
2738 * @param value the `struct Neighbour` with more information
2739 * @return #GNUNET_OK (continue to iterate)
2742 notify_client_connect_info (void *cls,
2743 const struct GNUNET_PeerIdentity *pid,
2746 struct TransportClient *tc = cls;
2747 struct Neighbour *neighbour = value;
2749 core_send_connect_info (tc, pid, neighbour->quota_out);
2755 * Initialize a "CORE" client. We got a start message from this
2756 * client, so add it to the list of clients for broadcasting of
2759 * @param cls the client
2760 * @param start the start message that was sent
2763 handle_client_start (void *cls, const struct StartMessage *start)
2765 struct TransportClient *tc = cls;
2768 options = ntohl (start->options);
2769 if ((0 != (1 & options)) &&
2770 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
2772 /* client thinks this is a different peer, reject */
2774 GNUNET_SERVICE_client_drop (tc->client);
2777 if (CT_NONE != tc->type)
2780 GNUNET_SERVICE_client_drop (tc->client);
2784 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2785 ¬ify_client_connect_info,
2787 GNUNET_SERVICE_client_continue (tc->client);
2792 * Client asked for transmission to a peer. Process the request.
2794 * @param cls the client
2795 * @param obm the send message that was sent
2798 check_client_send (void *cls, const struct OutboundMessage *obm)
2800 struct TransportClient *tc = cls;
2802 const struct GNUNET_MessageHeader *obmm;
2804 if (CT_CORE != tc->type)
2807 return GNUNET_SYSERR;
2809 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2810 if (size < sizeof (struct GNUNET_MessageHeader))
2813 return GNUNET_SYSERR;
2815 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2816 if (size != ntohs (obmm->size))
2819 return GNUNET_SYSERR;
2826 * Free fragment tree below @e root, excluding @e root itself.
2828 * @param root root of the tree to free
2831 free_fragment_tree (struct PendingMessage *root)
2833 struct PendingMessage *frag;
2835 while (NULL != (frag = root->head_frag))
2837 free_fragment_tree (frag);
2838 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2845 * Release memory associated with @a pm and remove @a pm from associated
2846 * data structures. @a pm must be a top-level pending message and not
2847 * a fragment in the tree. The entire tree is freed (if applicable).
2849 * @param pm the pending message to free
2852 free_pending_message (struct PendingMessage *pm)
2854 struct TransportClient *tc = pm->client;
2855 struct Neighbour *target = pm->target;
2859 GNUNET_CONTAINER_MDLL_remove (client,
2860 tc->details.core.pending_msg_head,
2861 tc->details.core.pending_msg_tail,
2864 GNUNET_CONTAINER_MDLL_remove (neighbour,
2865 target->pending_msg_head,
2866 target->pending_msg_tail,
2868 free_fragment_tree (pm);
2869 GNUNET_free_non_null (pm->bpm);
2875 * Send a response to the @a pm that we have processed a
2876 * "send" request with status @a success. We
2877 * transmitted @a bytes_physical on the actual wire.
2878 * Sends a confirmation to the "core" client responsible
2879 * for the original request and free's @a pm.
2881 * @param pm handle to the original pending message
2882 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2883 * for transmission failure
2884 * @param bytes_physical amount of bandwidth consumed
2887 client_send_response (struct PendingMessage *pm,
2889 uint32_t bytes_physical)
2891 struct TransportClient *tc = pm->client;
2892 struct Neighbour *target = pm->target;
2893 struct GNUNET_MQ_Envelope *env;
2894 struct SendOkMessage *som;
2898 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2899 som->success = htonl ((uint32_t) success);
2900 som->bytes_msg = htons (pm->bytes_msg);
2901 som->bytes_physical = htonl (bytes_physical);
2902 som->peer = target->pid;
2903 GNUNET_MQ_send (tc->mq, env);
2905 free_pending_message (pm);
2910 * Checks the message queue for a neighbour for messages that have timed
2911 * out and purges them.
2913 * @param cls a `struct Neighbour`
2916 check_queue_timeouts (void *cls)
2918 struct Neighbour *n = cls;
2919 struct PendingMessage *pm;
2920 struct GNUNET_TIME_Absolute now;
2921 struct GNUNET_TIME_Absolute earliest_timeout;
2923 n->timeout_task = NULL;
2924 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2925 now = GNUNET_TIME_absolute_get ();
2926 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
2928 pm = pos->next_neighbour;
2929 if (pos->timeout.abs_value_us <= now.abs_value_us)
2931 GNUNET_STATISTICS_update (GST_stats,
2932 "# messages dropped (timeout before confirmation)",
2935 client_send_response (pm, GNUNET_NO, 0);
2939 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
2941 n->earliest_timeout = earliest_timeout;
2942 if (NULL != n->pending_msg_head)
2944 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
2949 * Client asked for transmission to a peer. Process the request.
2951 * @param cls the client
2952 * @param obm the send message that was sent
2955 handle_client_send (void *cls, const struct OutboundMessage *obm)
2957 struct TransportClient *tc = cls;
2958 struct PendingMessage *pm;
2959 const struct GNUNET_MessageHeader *obmm;
2960 struct Neighbour *target;
2964 GNUNET_assert (CT_CORE == tc->type);
2965 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2966 bytes_msg = ntohs (obmm->size);
2967 target = lookup_neighbour (&obm->peer);
2970 /* Failure: don't have this peer as a neighbour (anymore).
2971 Might have gone down asynchronously, so this is NOT
2972 a protocol violation by CORE. Still count the event,
2973 as this should be rare. */
2974 struct GNUNET_MQ_Envelope *env;
2975 struct SendOkMessage *som;
2977 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2978 som->success = htonl (GNUNET_SYSERR);
2979 som->bytes_msg = htonl (bytes_msg);
2980 som->bytes_physical = htonl (0);
2981 som->peer = obm->peer;
2982 GNUNET_MQ_send (tc->mq, env);
2983 GNUNET_SERVICE_client_continue (tc->client);
2984 GNUNET_STATISTICS_update (GST_stats,
2985 "# messages dropped (neighbour unknown)",
2990 was_empty = (NULL == target->pending_msg_head);
2991 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2993 pm->target = target;
2994 pm->bytes_msg = bytes_msg;
2996 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2997 memcpy (&pm[1], &obm[1], bytes_msg);
2998 GNUNET_CONTAINER_MDLL_insert (neighbour,
2999 target->pending_msg_head,
3000 target->pending_msg_tail,
3002 GNUNET_CONTAINER_MDLL_insert (client,
3003 tc->details.core.pending_msg_head,
3004 tc->details.core.pending_msg_tail,
3006 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3008 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3009 if (NULL != target->timeout_task)
3010 GNUNET_SCHEDULER_cancel (target->timeout_task);
3011 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3012 &check_queue_timeouts,
3016 return; /* all queues must already be busy */
3017 for (struct Queue *queue = target->queue_head; NULL != queue;
3018 queue = queue->next_neighbour)
3020 /* try transmission on any queue that is idle */
3021 if (NULL == queue->transmit_task)
3022 queue->transmit_task =
3023 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3029 * Communicator started. Test message is well-formed.
3031 * @param cls the client
3032 * @param cam the send message that was sent
3035 check_communicator_available (
3037 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3039 struct TransportClient *tc = cls;
3042 if (CT_NONE != tc->type)
3045 return GNUNET_SYSERR;
3047 tc->type = CT_COMMUNICATOR;
3048 size = ntohs (cam->header.size) - sizeof (*cam);
3050 return GNUNET_OK; /* receive-only communicator */
3051 GNUNET_MQ_check_zero_termination (cam);
3057 * Communicator started. Process the request.
3059 * @param cls the client
3060 * @param cam the send message that was sent
3063 handle_communicator_available (
3065 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3067 struct TransportClient *tc = cls;
3070 size = ntohs (cam->header.size) - sizeof (*cam);
3072 return; /* receive-only communicator */
3073 tc->details.communicator.address_prefix =
3074 GNUNET_strdup ((const char *) &cam[1]);
3075 tc->details.communicator.cc =
3076 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3077 GNUNET_SERVICE_client_continue (tc->client);
3082 * Communicator requests backchannel transmission. Check the request.
3084 * @param cls the client
3085 * @param cb the send message that was sent
3086 * @return #GNUNET_OK if message is well-formed
3089 check_communicator_backchannel (
3091 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3093 const struct GNUNET_MessageHeader *inbox;
3099 msize = ntohs (cb->header.size) - sizeof (*cb);
3100 if (UINT16_MAX - msize >
3101 sizeof (struct TransportBackchannelEncapsulationMessage) +
3102 sizeof (struct TransportBackchannelRequestPayload))
3105 return GNUNET_SYSERR;
3107 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3108 isize = ntohs (inbox->size);
3112 return GNUNET_SYSERR;
3114 is = (const char *) inbox;
3117 GNUNET_assert (msize > 0);
3118 if ('\0' != is[msize - 1])
3121 return GNUNET_SYSERR;
3128 * Remove memory used by expired ephemeral keys.
3133 expire_ephemerals (void *cls)
3135 struct EphemeralCacheEntry *ece;
3138 ephemeral_task = NULL;
3139 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3141 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3144 free_ephemeral (ece);
3147 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3156 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3157 * one, cache it and return it.
3159 * @param pid peer to look up ephemeral for
3160 * @param private_key[out] set to the private key
3161 * @param ephemeral_key[out] set to the key
3162 * @param ephemeral_sender_sig[out] set to the signature
3163 * @param ephemeral_validity[out] set to the validity expiration time
3166 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3167 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3168 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3169 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3170 struct GNUNET_TIME_Absolute *ephemeral_validity)
3172 struct EphemeralCacheEntry *ece;
3173 struct EphemeralConfirmation ec;
3175 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3176 if ((NULL != ece) &&
3177 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3180 free_ephemeral (ece);
3185 ece = GNUNET_new (struct EphemeralCacheEntry);
3187 ece->ephemeral_validity =
3188 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3189 EPHEMERAL_VALIDITY);
3190 GNUNET_assert (GNUNET_OK ==
3191 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3192 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3193 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3194 ec.purpose.size = htonl (sizeof (ec));
3196 ec.ephemeral_key = ece->ephemeral_key;
3197 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3201 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3203 ece->ephemeral_validity.abs_value_us);
3204 GNUNET_assert (GNUNET_OK ==
3205 GNUNET_CONTAINER_multipeermap_put (
3209 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3210 if (NULL == ephemeral_task)
3211 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3215 *private_key = ece->private_key;
3216 *ephemeral_key = ece->ephemeral_key;
3217 *ephemeral_sender_sig = ece->sender_sig;
3218 *ephemeral_validity = ece->ephemeral_validity;
3223 * Send the control message @a payload on @a queue.
3225 * @param queue the queue to use for transmission
3226 * @param pm pending message to update once transmission is done, may be NULL!
3227 * @param payload the payload to send (encapsulated in a
3228 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3229 * @param payload_size number of bytes in @a payload
3232 queue_send_msg (struct Queue *queue,
3233 struct PendingMessage *pm,
3234 const void *payload,
3235 size_t payload_size)
3237 struct Neighbour *n = queue->neighbour;
3238 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3239 struct GNUNET_MQ_Envelope *env;
3241 env = GNUNET_MQ_msg_extra (smt,
3243 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3244 smt->qid = queue->qid;
3245 smt->mid = queue->mid_gen;
3246 smt->receiver = n->pid;
3247 memcpy (&smt[1], payload, payload_size);
3249 /* Pass the env to the communicator of queue for transmission. */
3250 struct QueueEntry *qe;
3252 qe = GNUNET_new (struct QueueEntry);
3253 qe->mid = queue->mid_gen++;
3255 // qe->pm = pm; // FIXME: not so easy, reference management on 'free(s)'!
3256 // (also, note that pm may be NULL!)
3257 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3258 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3259 queue->queue_length++;
3260 queue->tc->details.communicator.total_queue_length++;
3261 GNUNET_MQ_send (queue->tc->mq, env);
3267 * Which transmission options are allowable for transmission?
3268 * Interpreted bit-wise!
3270 enum RouteMessageOptions
3273 * Only confirmed, non-DV direct neighbours.
3278 * We are allowed to use DV routing for this @a hdr
3283 * We are allowed to use unconfirmed queues or DV routes for this message
3285 RMO_UNCONFIRMED_ALLOWED = 2,
3288 * Reliable and unreliable, DV and non-DV are all acceptable.
3290 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
3293 * If we have multiple choices, it is OK to send this message
3294 * over multiple channels at the same time to improve loss tolerance.
3295 * (We do at most 2 transmissions.)
3302 * Pick a queue of @a n under constraints @a options and schedule
3303 * transmission of @a hdr.
3305 * @param n neighbour to send to
3306 * @param hdr message to send as payload
3307 * @param options whether queues must be confirmed or not,
3308 * and whether we may pick multiple (2) queues
3311 route_via_neighbour (const struct Neighbour *n,
3312 const struct GNUNET_MessageHeader *hdr,
3313 enum RouteMessageOptions options)
3315 struct GNUNET_TIME_Absolute now;
3316 unsigned int candidates;
3320 /* Pick one or two 'random' queues from n (under constraints of options) */
3321 now = GNUNET_TIME_absolute_get ();
3322 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
3323 weight in the future; weight could be assigned by observed
3324 bandwidth (note: not sure if we should do this for this type
3325 of control traffic though). */
3327 for (struct Queue *pos = n->queue_head; NULL != pos;
3328 pos = pos->next_neighbour)
3330 /* Count the queue with the visibility task in all cases, as
3331 otherwise we may end up with no queues just because the
3332 time for the visibility task just expired but the scheduler
3333 just ran this task first */
3334 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
3335 (pos->validated_until.abs_value_us > now.abs_value_us) ||
3336 (NULL != pos->visibility_task))
3339 if (0 == candidates)
3341 /* Given that we above check for pos->visibility task,
3342 this should be strictly impossible. */
3346 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3347 if (0 == (options & RMO_REDUNDANT))
3348 sel2 = candidates; /* picks none! */
3350 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3352 for (struct Queue *pos = n->queue_head; NULL != pos;
3353 pos = pos->next_neighbour)
3355 /* Count the queue with the visibility task in all cases, as
3356 otherwise we may end up with no queues just because the
3357 time for the visibility task just expired but the scheduler
3358 just ran this task first */
3359 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
3360 (NULL != pos->visibility_task))
3362 if ((sel1 == candidates) || (sel2 == candidates))
3363 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
3371 * Given a distance vector path @a dvh route @a payload to
3372 * the ultimate destination respecting @a options.
3373 * Sets up the boxed message and queues it at the next hop.
3375 * @param dvh choice of the path for the message
3376 * @param payload body to transmit
3377 * @param options options to use for control
3380 forward_via_dvh (const struct DistanceVectorHop *dvh,
3381 const struct GNUNET_MessageHeader *payload,
3382 enum RouteMessageOptions options)
3384 uint16_t mlen = ntohs (payload->size);
3385 char boxram[sizeof (struct TransportDVBox) +
3386 (dvh->distance + 1) * sizeof (struct GNUNET_PeerIdentity) +
3388 struct TransportDVBox *box = (struct TransportDVBox *) boxram;
3389 struct GNUNET_PeerIdentity *path = (struct GNUNET_PeerIdentity *) &box[1];
3391 box->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3392 box->header.size = htons (sizeof (boxram));
3393 box->total_hops = htons (0);
3394 box->num_hops = htons (dvh->distance + 1);
3395 box->origin = GST_my_identity;
3396 memcpy (path, dvh->path, dvh->distance * sizeof (struct GNUNET_PeerIdentity));
3397 path[dvh->distance] = dvh->dv->target;
3398 memcpy (&path[dvh->distance + 1], payload, mlen);
3399 route_via_neighbour (dvh->next_hop, &box->header, options);
3404 * Pick a path of @a dv under constraints @a options and schedule
3405 * transmission of @a hdr.
3407 * @param n neighbour to send to
3408 * @param hdr message to send as payload
3409 * @param options whether path must be confirmed or not
3410 * and whether we may pick multiple (2) paths
3413 route_via_dv (const struct DistanceVector *dv,
3414 const struct GNUNET_MessageHeader *hdr,
3415 enum RouteMessageOptions options)
3417 struct DistanceVectorHop *h1;
3418 struct DistanceVectorHop *h2;
3423 /* Pick random vectors, but weighted by distance, giving more weight
3424 to shorter vectors */
3426 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3429 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3430 (GNUNET_TIME_absolute_get_duration (pos->freshness).rel_value_us >
3431 ADDRESS_VALIDATION_LIFETIME.rel_value_us))
3432 continue; /* pos unconfirmed and confirmed required */
3433 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3440 choice1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3441 choice2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3445 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3448 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3450 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3451 (GNUNET_TIME_absolute_get_duration (pos->freshness).rel_value_us >
3452 ADDRESS_VALIDATION_LIFETIME.rel_value_us))
3453 continue; /* pos unconfirmed and confirmed required */
3454 if ((num_dv <= choice1) && (num_dv + delta > choice1))
3456 if ((num_dv <= choice2) && (num_dv + delta > choice2))
3460 forward_via_dvh (h1, hdr, options & (~RMO_REDUNDANT));
3461 if (0 == (options & RMO_REDUNDANT))
3462 forward_via_dvh (h2, hdr, options & (~RMO_REDUNDANT));
3467 * We need to transmit @a hdr to @a target. If necessary, this may
3468 * involve DV routing.
3470 * @param target peer to receive @a hdr
3471 * @param hdr header of the message to route and #GNUNET_free()
3472 * @param options which transmission channels are allowed
3475 route_message (const struct GNUNET_PeerIdentity *target,
3476 struct GNUNET_MessageHeader *hdr,
3477 enum RouteMessageOptions options)
3479 struct Neighbour *n;
3480 struct DistanceVector *dv;
3482 n = GNUNET_CONTAINER_multipeermap_get (neighbours, target);
3483 dv = (0 != (options & RMO_DV_ALLOWED))
3484 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
3486 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
3488 /* if confirmed is required, and we do not have anything
3489 confirmed, drop respective options */
3490 if ((NULL != n) && (GNUNET_NO == n->core_visible))
3492 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
3495 if ((NULL == n) && (NULL == dv))
3497 GNUNET_STATISTICS_update (GST_stats,
3498 "# Messages dropped in routing: no acceptable method",
3504 /* If both dv and n are possible and we must choose:
3505 flip a coin for the choice between the two; for now 50/50 */
3506 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
3508 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
3513 if ((NULL != n) && (NULL != dv))
3514 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
3515 enough for redunancy, so clear the flag. */
3518 route_via_neighbour (n, hdr, options);
3522 route_via_dv (dv, hdr, options);
3529 * Structure of the key material used to encrypt backchannel messages.
3531 struct BackchannelKeyState
3534 * State of our block cipher.
3536 gcry_cipher_hd_t cipher;
3539 * Actual key material.
3545 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3547 struct GNUNET_CRYPTO_AuthKey hmac_key;
3550 * Symmetric key to use for encryption.
3552 char aes_key[256 / 8];
3555 * Counter value to use during setup.
3557 char aes_ctr[128 / 8];
3564 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3565 const struct GNUNET_ShortHashCode *iv,
3566 struct BackchannelKeyState *key)
3568 /* must match #dh_key_derive_eph_pub */
3569 GNUNET_assert (GNUNET_YES ==
3570 GNUNET_CRYPTO_kdf (&key->material,
3571 sizeof (key->material),
3572 "transport-backchannel-key",
3573 strlen ("transport-backchannel-key"),
3578 gcry_cipher_open (&key->cipher,
3579 GCRY_CIPHER_AES256 /* low level: go for speed */,
3580 GCRY_CIPHER_MODE_CTR,
3582 gcry_cipher_setkey (key->cipher,
3583 &key->material.aes_key,
3584 sizeof (key->material.aes_key));
3585 gcry_cipher_setctr (key->cipher,
3586 &key->material.aes_ctr,
3587 sizeof (key->material.aes_ctr));
3592 * Derive backchannel encryption key material from @a priv_ephemeral
3593 * and @a target and @a iv.
3595 * @param priv_ephemeral ephemeral private key to use
3596 * @param target the target peer to encrypt to
3597 * @param iv unique IV to use
3598 * @param key[out] set to the key material
3601 dh_key_derive_eph_pid (
3602 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3603 const struct GNUNET_PeerIdentity *target,
3604 const struct GNUNET_ShortHashCode *iv,
3605 struct BackchannelKeyState *key)
3607 struct GNUNET_HashCode km;
3609 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3610 &target->public_key,
3612 bc_setup_key_state_from_km (&km, iv, key);
3617 * Derive backchannel encryption key material from #GST_my_private_key
3618 * and @a pub_ephemeral and @a iv.
3620 * @param priv_ephemeral ephemeral private key to use
3621 * @param target the target peer to encrypt to
3622 * @param iv unique IV to use
3623 * @param key[out] set to the key material
3626 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3627 const struct GNUNET_ShortHashCode *iv,
3628 struct BackchannelKeyState *key)
3630 struct GNUNET_HashCode km;
3632 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3635 bc_setup_key_state_from_km (&km, iv, key);
3640 * Do HMAC calculation for backchannel messages over @a data using key
3641 * material from @a key.
3643 * @param key key material (from DH)
3644 * @param hmac[out] set to the HMAC
3645 * @param data data to perform HMAC calculation over
3646 * @param data_size number of bytes in @a data
3649 bc_hmac (const struct BackchannelKeyState *key,
3650 struct GNUNET_HashCode *hmac,
3654 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
3659 * Perform backchannel encryption using symmetric secret in @a key
3660 * to encrypt data from @a in to @a dst.
3662 * @param key[in,out] key material to use
3663 * @param dst where to write the result
3664 * @param in input data to encrypt (plaintext)
3665 * @param in_size number of bytes of input in @a in and available at @a dst
3668 bc_encrypt (struct BackchannelKeyState *key,
3674 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
3679 * Perform backchannel encryption using symmetric secret in @a key
3680 * to encrypt data from @a in to @a dst.
3682 * @param key[in,out] key material to use
3683 * @param ciph cipher text to decrypt
3684 * @param out[out] output data to generate (plaintext)
3685 * @param out_size number of bytes of input in @a ciph and available in @a out
3688 bc_decrypt (struct BackchannelKeyState *key,
3694 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
3699 * Clean up key material in @a key.
3701 * @param key key material to clean up (memory must not be free'd!)
3704 bc_key_clean (struct BackchannelKeyState *key)
3706 gcry_cipher_close (key->cipher);
3707 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
3712 * Communicator requests backchannel transmission. Process the request.
3714 * @param cls the client
3715 * @param cb the send message that was sent
3718 handle_communicator_backchannel (
3720 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3722 struct TransportClient *tc = cls;
3723 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3724 struct GNUNET_TIME_Absolute ephemeral_validity;
3725 struct TransportBackchannelEncapsulationMessage *enc;
3726 struct TransportBackchannelRequestPayload ppay;
3727 struct BackchannelKeyState key;
3731 /* encapsulate and encrypt message */
3732 msize = ntohs (cb->header.size) - sizeof (*cb) +
3733 sizeof (struct TransportBackchannelRequestPayload);
3734 enc = GNUNET_malloc (sizeof (*enc) + msize);
3736 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3737 enc->header.size = htons (sizeof (*enc) + msize);
3738 enc->target = cb->pid;
3739 lookup_ephemeral (&cb->pid,
3741 &enc->ephemeral_key,
3743 &ephemeral_validity);
3744 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3747 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
3748 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3749 ppay.monotonic_time =
3750 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3751 mpos = (char *) &enc[1];
3752 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
3755 &mpos[sizeof (ppay)],
3756 ntohs (cb->header.size) - sizeof (*cb));
3760 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3761 bc_key_clean (&key);
3762 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
3763 GNUNET_SERVICE_client_continue (tc->client);
3768 * Address of our peer added. Test message is well-formed.
3770 * @param cls the client
3771 * @param aam the send message that was sent
3772 * @return #GNUNET_OK if message is well-formed
3775 check_add_address (void *cls,
3776 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3778 struct TransportClient *tc = cls;
3780 if (CT_COMMUNICATOR != tc->type)
3783 return GNUNET_SYSERR;
3785 GNUNET_MQ_check_zero_termination (aam);
3791 * Ask peerstore to store our address.
3793 * @param cls an `struct AddressListEntry *`
3796 store_pi (void *cls);
3800 * Function called when peerstore is done storing our address.
3802 * @param cls a `struct AddressListEntry`
3803 * @param success #GNUNET_YES if peerstore was successful
3806 peerstore_store_own_cb (void *cls, int success)
3808 struct AddressListEntry *ale = cls;
3811 if (GNUNET_YES != success)
3812 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3813 "Failed to store our own address `%s' in peerstore!\n",
3815 /* refresh period is 1/4 of expiration time, that should be plenty
3816 without being excessive. */
3818 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3826 * Ask peerstore to store our address.
3828 * @param cls an `struct AddressListEntry *`
3831 store_pi (void *cls)
3833 struct AddressListEntry *ale = cls;
3836 struct GNUNET_TIME_Absolute expiration;
3839 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3840 GNUNET_HELLO_sign_address (ale->address,
3846 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3849 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3853 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3854 &peerstore_store_own_cb,
3857 if (NULL == ale->sc)
3859 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3860 "Failed to store our address `%s' with peerstore\n",
3863 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
3869 * Address of our peer added. Process the request.
3871 * @param cls the client
3872 * @param aam the send message that was sent
3875 handle_add_address (void *cls,
3876 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3878 struct TransportClient *tc = cls;
3879 struct AddressListEntry *ale;
3882 slen = ntohs (aam->header.size) - sizeof (*aam);
3883 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3885 ale->address = (const char *) &ale[1];
3886 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3887 ale->aid = aam->aid;
3888 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3889 memcpy (&ale[1], &aam[1], slen);
3890 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3891 tc->details.communicator.addr_tail,
3893 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
3894 GNUNET_SERVICE_client_continue (tc->client);
3899 * Address of our peer deleted. Process the request.
3901 * @param cls the client
3902 * @param dam the send message that was sent
3905 handle_del_address (void *cls,
3906 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3908 struct TransportClient *tc = cls;
3910 if (CT_COMMUNICATOR != tc->type)
3913 GNUNET_SERVICE_client_drop (tc->client);
3916 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3920 if (dam->aid != ale->aid)
3922 GNUNET_assert (ale->tc == tc);
3923 free_address_list_entry (ale);
3924 GNUNET_SERVICE_client_continue (tc->client);
3927 GNUNET_SERVICE_client_drop (tc->client);
3932 * Context from #handle_incoming_msg(). Closure for many
3933 * message handlers below.
3935 struct CommunicatorMessageContext
3938 * Which communicator provided us with the message.
3940 struct TransportClient *tc;
3943 * Additional information for flow control and about the sender.
3945 struct GNUNET_TRANSPORT_IncomingMessage im;
3948 * Number of hops the message has travelled (if DV-routed).
3949 * FIXME: make use of this in ACK handling!
3951 uint16_t total_hops;
3956 * Given an inbound message @a msg from a communicator @a cmc,
3957 * demultiplex it based on the type calling the right handler.
3959 * @param cmc context for demultiplexing
3960 * @param msg message to demultiplex
3963 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3964 const struct GNUNET_MessageHeader *msg);
3968 * Send ACK to communicator (if requested) and free @a cmc.
3970 * @param cmc context for which we are done handling the message
3973 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3975 if (0 != ntohl (cmc->im.fc_on))
3977 /* send ACK when done to communicator for flow control! */
3978 struct GNUNET_MQ_Envelope *env;
3979 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3981 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3982 ack->reserved = htonl (0);
3983 ack->fc_id = cmc->im.fc_id;
3984 ack->sender = cmc->im.sender;
3985 GNUNET_MQ_send (cmc->tc->mq, env);
3987 GNUNET_SERVICE_client_continue (cmc->tc->client);
3993 * Communicator gave us an unencapsulated message to pass as-is to
3994 * CORE. Process the request.
3996 * @param cls a `struct CommunicatorMessageContext` (must call
3997 * #finish_cmc_handling() when done)
3998 * @param mh the message that was received
4001 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4003 struct CommunicatorMessageContext *cmc = cls;
4004 uint16_t size = ntohs (mh->size);
4006 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4007 (size < sizeof (struct GNUNET_MessageHeader)))
4009 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4012 finish_cmc_handling (cmc);
4013 GNUNET_SERVICE_client_drop (client);
4016 /* Forward to all CORE clients */
4017 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4019 struct GNUNET_MQ_Envelope *env;
4020 struct InboundMessage *im;
4022 if (CT_CORE != tc->type)
4024 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4025 im->peer = cmc->im.sender;
4026 memcpy (&im[1], mh, size);
4027 GNUNET_MQ_send (tc->mq, env);
4029 /* FIXME: consider doing this _only_ once the message
4030 was drained from the CORE MQs to extend flow control to CORE!
4031 (basically, increment counter in cmc, decrement on MQ send continuation! */
4032 finish_cmc_handling (cmc);
4037 * Communicator gave us a fragment box. Check the message.
4039 * @param cls a `struct CommunicatorMessageContext`
4040 * @param fb the send message that was sent
4041 * @return #GNUNET_YES if message is well-formed
4044 check_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4046 uint16_t size = ntohs (fb->header.size);
4047 uint16_t bsize = size - sizeof (*fb);
4051 GNUNET_break_op (0);
4052 return GNUNET_SYSERR;
4054 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4056 GNUNET_break_op (0);
4057 return GNUNET_SYSERR;
4059 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4061 GNUNET_break_op (0);
4062 return GNUNET_SYSERR;
4069 * Generate a fragment acknowledgement for an @a rc.
4071 * @param rc context to generate ACK for, @a rc ACK state is reset
4074 send_fragment_ack (struct ReassemblyContext *rc)
4076 struct TransportFragmentAckMessage *ack;
4078 ack = GNUNET_new (struct TransportFragmentAckMessage);
4079 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
4080 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
4081 ack->frag_uuid = htonl (rc->frag_uuid);
4082 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
4083 ack->msg_uuid = rc->msg_uuid;
4084 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
4085 if (0 == rc->msg_missing)
4086 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4087 GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
4089 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4090 GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
4091 route_message (&rc->neighbour->pid, &ack->header, RMO_DV_ALLOWED);
4092 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
4094 rc->extra_acks = 0LLU;
4099 * Communicator gave us a fragment. Process the request.
4101 * @param cls a `struct CommunicatorMessageContext` (must call
4102 * #finish_cmc_handling() when done)
4103 * @param fb the message that was received
4106 handle_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4108 struct CommunicatorMessageContext *cmc = cls;
4109 struct Neighbour *n;
4110 struct ReassemblyContext *rc;
4111 const struct GNUNET_MessageHeader *msg;
4117 struct GNUNET_TIME_Relative cdelay;
4120 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4123 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4126 finish_cmc_handling (cmc);
4127 GNUNET_SERVICE_client_drop (client);
4130 if (NULL == n->reassembly_map)
4132 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_YES);
4133 n->reassembly_heap =
4134 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4135 n->reassembly_timeout_task =
4136 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4137 &reassembly_cleanup_task,
4140 msize = ntohs (fb->msg_size);
4141 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map, &fb->msg_uuid);
4144 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4145 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4146 rc->msg_uuid = fb->msg_uuid;
4148 rc->msg_size = msize;
4149 rc->reassembly_timeout =
4150 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4151 rc->last_frag = GNUNET_TIME_absolute_get ();
4152 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4154 rc->reassembly_timeout.abs_value_us);
4155 GNUNET_assert (GNUNET_OK ==
4156 GNUNET_CONTAINER_multishortmap_put (
4160 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4161 target = (char *) &rc[1];
4162 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4163 rc->msg_missing = rc->msg_size;
4167 target = (char *) &rc[1];
4169 if (msize != rc->msg_size)
4172 finish_cmc_handling (cmc);
4177 fsize = ntohs (fb->header.size) - sizeof (*fb);
4178 frag_off = ntohs (fb->frag_off);
4179 memcpy (&target[frag_off], &fb[1], fsize);
4180 /* update bitfield and msg_missing */
4181 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4183 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4185 rc->bitfield[i / 8] |= (1 << (i % 8));
4190 /* Compute cummulative ACK */
4191 frag_uuid = ntohl (fb->frag_uuid);
4192 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4193 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->num_acks);
4194 rc->last_frag = GNUNET_TIME_absolute_get ();
4195 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay, cdelay);
4196 ack_now = GNUNET_NO;
4197 if (0 == rc->num_acks)
4199 /* case one: first ack */
4200 rc->frag_uuid = frag_uuid;
4201 rc->extra_acks = 0LLU;
4204 else if ((frag_uuid >= rc->frag_uuid) && (frag_uuid <= rc->frag_uuid + 64))
4206 /* case two: ack fits after existing min UUID */
4207 if ((frag_uuid == rc->frag_uuid) ||
4208 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))))
4210 /* duplicate fragment, ack now! */
4211 ack_now = GNUNET_YES;
4215 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
4219 else if ((rc->frag_uuid > frag_uuid) &&
4220 (((rc->frag_uuid == frag_uuid + 64) && (0 == rc->extra_acks)) ||
4221 ((rc->frag_uuid < frag_uuid + 64) &&
4224 ~((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))))))
4226 /* can fit ack by shifting extra acks and starting at
4227 frag_uid, test above esured that the bits we will
4228 shift 'extra_acks' by are all zero. */
4229 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
4230 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
4231 rc->frag_uuid = frag_uuid;
4234 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very
4236 ack_now = GNUNET_YES; /* maximum acks received */
4237 // FIXME: possibly also ACK based on RTT (but for that we'd need to
4238 // determine the queue used for the ACK first!)
4240 /* is reassembly complete? */
4241 if (0 != rc->msg_missing)
4244 send_fragment_ack (rc);
4245 finish_cmc_handling (cmc);
4248 /* reassembly is complete, verify result */
4249 msg = (const struct GNUNET_MessageHeader *) &rc[1];
4250 if (ntohs (msg->size) != rc->msg_size)
4253 free_reassembly_context (rc);
4254 finish_cmc_handling (cmc);
4257 /* successful reassembly */
4258 send_fragment_ack (rc);
4259 demultiplex_with_cmc (cmc, msg);
4260 /* FIXME: really free here? Might be bad if fragments are still
4261 en-route and we forget that we finished this reassembly immediately!
4262 -> keep around until timeout?
4263 -> shorten timeout based on ACK? */
4264 free_reassembly_context (rc);
4269 * Check the @a fa against the fragments associated with @a pm.
4270 * If it matches, remove the matching fragments from the transmission
4273 * @param pm pending message to check against the ack
4274 * @param fa the ack that was received
4275 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4278 check_ack_against_pm (struct PendingMessage *pm,
4279 const struct TransportFragmentAckMessage *fa)
4282 struct PendingMessage *nxt;
4283 uint32_t fs = ntohl (fa->frag_uuid);
4284 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4287 for (struct PendingMessage *frag = pm->head_frag; NULL != frag; frag = nxt)
4289 const struct TransportFragmentBox *tfb =
4290 (const struct TransportFragmentBox *) &pm[1];
4291 uint32_t fu = ntohl (tfb->frag_uuid);
4293 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4294 nxt = frag->next_frag;
4295 /* Check for exact match or match in the 'xtra' bitmask */
4297 ((fu > fs) && (fu <= fs + 64) && (0 != (1LLU << (fu - fs - 1) & xtra))))
4300 free_fragment_tree (frag);
4308 * Communicator gave us a fragment acknowledgement. Process the request.
4310 * @param cls a `struct CommunicatorMessageContext` (must call
4311 * #finish_cmc_handling() when done)
4312 * @param fa the message that was received
4315 handle_fragment_ack (void *cls, const struct TransportFragmentAckMessage *fa)
4317 struct CommunicatorMessageContext *cmc = cls;
4318 struct Neighbour *n;
4321 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4324 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4327 finish_cmc_handling (cmc);
4328 GNUNET_SERVICE_client_drop (client);
4331 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4332 matched = GNUNET_NO;
4333 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm;
4334 pm = pm->prev_neighbour)
4336 if (0 != GNUNET_memcmp (&fa->msg_uuid, &pm->msg_uuid))
4338 matched = GNUNET_YES;
4339 if (GNUNET_YES == check_ack_against_pm (pm, fa))
4341 struct GNUNET_TIME_Relative avg_ack_delay =
4342 GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4343 // FIXME: update RTT and other reliability data!
4344 // ISSUE: we don't know which of n's queues the message(s)
4345 // took (and in fact the different messages might have gone
4346 // over different queues and possibly over multiple).
4347 // => track queues with PendingMessages, and update RTT only if
4348 // the queue used is unique?
4349 // -> how can we get loss rates?
4350 // -> or, add extra state to Box and ACK to identify queue?
4351 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4352 // the queue with the fragment! (-> this logic must
4353 // be moved into check_ack_against_pm!)
4354 (void) avg_ack_delay;
4358 GNUNET_STATISTICS_update (GST_stats,
4359 "# FRAGMENT_ACKS dropped, no matching fragment",
4363 if (NULL == pm->head_frag)
4365 // if entire message is ACKed, handle that as well.
4366 // => clean up PM, any post actions?
4367 free_pending_message (pm);
4371 struct GNUNET_TIME_Relative reassembly_timeout =
4372 GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4373 // OPTIMIZE-FIXME: adjust retransmission strategy based on
4374 // reassembly_timeout!
4375 (void) reassembly_timeout;
4379 if (GNUNET_NO == matched)
4381 GNUNET_STATISTICS_update (GST_stats,
4382 "# FRAGMENT_ACKS dropped, no matching pending message",
4386 finish_cmc_handling (cmc);
4391 * Communicator gave us a reliability box. Check the message.
4393 * @param cls a `struct CommunicatorMessageContext`
4394 * @param rb the send message that was sent
4395 * @return #GNUNET_YES if message is well-formed
4398 check_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4400 GNUNET_MQ_check_boxed_message (rb);
4406 * Communicator gave us a reliability box. Process the request.
4408 * @param cls a `struct CommunicatorMessageContext` (must call
4409 * #finish_cmc_handling() when done)
4410 * @param rb the message that was received
4413 handle_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4415 struct CommunicatorMessageContext *cmc = cls;
4416 const struct GNUNET_MessageHeader *inbox =
4417 (const struct GNUNET_MessageHeader *) &rb[1];
4419 if (0 == ntohl (rb->ack_countdown))
4421 struct TransportReliabilityAckMessage *ack;
4423 /* FIXME: implement cummulative ACKs and ack_countdown,
4424 then setting the avg_ack_delay field below: */
4425 ack = GNUNET_malloc (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4426 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4428 htons (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4429 memcpy (&ack[1], &rb->msg_uuid, sizeof (struct GNUNET_ShortHashCode));
4430 route_message (&cmc->im.sender, &ack->header, RMO_DV_ALLOWED);
4432 /* continue with inner message */
4433 demultiplex_with_cmc (cmc, inbox);
4438 * Communicator gave us a reliability ack. Process the request.
4440 * @param cls a `struct CommunicatorMessageContext` (must call
4441 * #finish_cmc_handling() when done)
4442 * @param ra the message that was received
4445 handle_reliability_ack (void *cls,
4446 const struct TransportReliabilityAckMessage *ra)
4448 struct CommunicatorMessageContext *cmc = cls;
4449 struct Neighbour *n;
4450 unsigned int n_acks;
4451 const struct GNUNET_ShortHashCode *msg_uuids;
4452 struct PendingMessage *nxt;
4455 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4458 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4461 finish_cmc_handling (cmc);
4462 GNUNET_SERVICE_client_drop (client);
4465 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
4466 sizeof (struct GNUNET_ShortHashCode);
4467 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4469 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4470 matched = GNUNET_NO;
4471 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm; pm = nxt)
4475 nxt = pm->next_neighbour;
4476 in_list = GNUNET_NO;
4477 for (unsigned int i = 0; i < n_acks; i++)
4479 if (0 != GNUNET_memcmp (&msg_uuids[i], &pm->msg_uuid))
4481 in_list = GNUNET_YES;
4484 if (GNUNET_NO == in_list)
4487 /* this pm was acked! */
4488 matched = GNUNET_YES;
4489 free_pending_message (pm);
4492 struct GNUNET_TIME_Relative avg_ack_delay =
4493 GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4494 // FIXME: update RTT and other reliability data!
4495 // ISSUE: we don't know which of n's queues the message(s)
4496 // took (and in fact the different messages might have gone
4497 // over different queues and possibly over multiple).
4498 // => track queues with PendingMessages, and update RTT only if
4499 // the queue used is unique?
4500 // -> how can we get loss rates?
4501 // -> or, add extra state to MSG and ACKs to identify queue?
4502 // -> if we do this, might just do the same for the avg_ack_delay!
4503 (void) avg_ack_delay;
4506 if (GNUNET_NO == matched)
4508 GNUNET_STATISTICS_update (GST_stats,
4509 "# FRAGMENT_ACKS dropped, no matching pending message",
4513 finish_cmc_handling (cmc);
4518 * Communicator gave us a backchannel encapsulation. Check the message.
4520 * @param cls a `struct CommunicatorMessageContext`
4521 * @param be the send message that was sent
4522 * @return #GNUNET_YES if message is well-formed
4525 check_backchannel_encapsulation (
4527 const struct TransportBackchannelEncapsulationMessage *be)
4529 uint16_t size = ntohs (be->header.size);
4532 if ((size - sizeof (*be)) <
4533 (sizeof (struct TransportBackchannelRequestPayload) +
4534 sizeof (struct GNUNET_MessageHeader)))
4536 GNUNET_break_op (0);
4537 return GNUNET_SYSERR;
4544 * Communicator gave us a backchannel encapsulation. Process the request.
4545 * (We are not the origin of the backchannel here, the communicator simply
4546 * received a backchannel message and we are expected to forward it.)
4548 * @param cls a `struct CommunicatorMessageContext` (must call
4549 * #finish_cmc_handling() when done)
4550 * @param be the message that was received
4553 handle_backchannel_encapsulation (
4555 const struct TransportBackchannelEncapsulationMessage *be)
4557 struct CommunicatorMessageContext *cmc = cls;
4558 struct BackchannelKeyState key;
4559 struct GNUNET_HashCode hmac;
4563 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
4565 /* not for me, try to route to target */
4566 /* FIXME: someone needs to update be->distance! */
4567 /* FIXME: BE routing can be special, should we put all of this
4568 on 'route_message'? Maybe at least pass some more arguments? */
4569 route_message (&be->target,
4570 GNUNET_copy_message (&be->header),
4572 finish_cmc_handling (cmc);
4575 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
4576 hdr = (const char *) &be[1];
4577 hdr_len = ntohs (be->header.size) - sizeof (*be);
4578 bc_hmac (&key, &hmac, hdr, hdr_len);
4579 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
4581 /* HMAC missmatch, disard! */
4582 GNUNET_break_op (0);
4583 finish_cmc_handling (cmc);
4586 /* begin actual decryption */
4588 struct TransportBackchannelRequestPayload ppay;
4589 char body[hdr_len - sizeof (ppay)];
4591 GNUNET_assert (hdr_len >=
4592 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4593 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
4594 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
4595 bc_key_clean (&key);
4596 // FIXME: verify signatures in ppay!
4597 // => check if ephemeral key is known & valid, if not
4598 // => verify sig, cache ephemeral key
4599 // => update monotonic_time of sender for replay detection
4601 // FIXME: forward to specified communicator!
4602 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4604 finish_cmc_handling (cmc);
4609 * Task called when we should check if any of the DV paths
4610 * we have learned to a target are due for garbage collection.
4612 * Collects stale paths, and possibly frees the entire DV
4613 * entry if no paths are left. Otherwise re-schedules itself.
4615 * @param cls a `struct DistanceVector`
4618 path_cleanup_cb (void *cls)
4620 struct DistanceVector *dv = cls;
4621 struct DistanceVectorHop *pos;
4623 dv->timeout_task = NULL;
4624 while (NULL != (pos = dv->dv_head))
4626 GNUNET_assert (dv == pos->dv);
4627 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4629 free_distance_vector_hop (pos);
4637 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
4642 * We have learned a @a path through the network to some other peer, add it to
4643 * our DV data structure (returning #GNUNET_YES on success).
4645 * We do not add paths if we have a sufficient number of shorter
4646 * paths to this target already (returning #GNUNET_NO).
4648 * We also do not add problematic paths, like those where we lack the first
4649 * hop in our neighbour list (i.e. due to a topology change) or where some
4650 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4652 * @param path the path we learned, path[0] should be us,
4653 * and then path contains a valid path from us to `path[path_len-1]`
4654 * path[1] should be a direct neighbour (we should check!)
4655 * @param path_len number of entries on the @a path, at least three!
4656 * @param network_latency how long does the message take from us to
4657 * `path[path_len-1]`? set to "forever" if unknown
4658 * @return #GNUNET_YES on success,
4659 * #GNUNET_NO if we have better path(s) to the target
4660 * #GNUNET_SYSERR if the path is useless and/or invalid
4661 * (i.e. path[1] not a direct neighbour
4662 * or path[i+1] is a direct neighbour for i>0)
4665 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4666 unsigned int path_len,
4667 struct GNUNET_TIME_Relative network_latency)
4669 struct DistanceVectorHop *hop;
4670 struct DistanceVector *dv;
4671 struct Neighbour *next_hop;
4672 unsigned int shorter_distance;
4676 /* what a boring path! not allowed! */
4678 return GNUNET_SYSERR;
4680 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
4681 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours, &path[1]);
4682 if (NULL == next_hop)
4684 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4686 return GNUNET_SYSERR;
4688 for (unsigned int i = 2; i < path_len; i++)
4689 if (NULL != GNUNET_CONTAINER_multipeermap_get (neighbours, &path[i]))
4691 /* Useless path, we have a direct connection to some hop
4692 in the middle of the path, so this one doesn't even
4693 seem terribly useful for redundancy */
4694 return GNUNET_SYSERR;
4696 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
4699 dv = GNUNET_new (struct DistanceVector);
4700 dv->target = path[path_len - 1];
4701 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4704 GNUNET_assert (GNUNET_OK ==
4705 GNUNET_CONTAINER_multipeermap_put (
4709 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4711 /* Check if we have this path already! */
4712 shorter_distance = 0;
4713 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4716 if (pos->distance < path_len - 2)
4718 /* Note that the distances in 'pos' excludes us (path[0]) and
4719 the next_hop (path[1]), so we need to subtract two
4720 and check next_hop explicitly */
4721 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
4723 int match = GNUNET_YES;
4725 for (unsigned int i = 0; i < pos->distance; i++)
4727 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
4733 if (GNUNET_YES == match)
4735 struct GNUNET_TIME_Relative last_timeout;
4737 /* Re-discovered known path, update timeout */
4738 GNUNET_STATISTICS_update (GST_stats,
4739 "# Known DV path refreshed",
4742 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4744 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4745 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
4746 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
4747 if (last_timeout.rel_value_us <
4748 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4749 DV_PATH_DISCOVERY_FREQUENCY)
4752 /* Some peer send DV learn messages too often, we are learning
4753 the same path faster than it would be useful; do not forward! */
4760 /* Count how many shorter paths we have (incl. direct
4761 neighbours) before simply giving up on this one! */
4762 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4764 /* We have a shorter path already! */
4767 /* create new DV path entry */
4768 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4769 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4770 hop->next_hop = next_hop;
4772 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4775 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4776 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4777 hop->distance = path_len - 2;
4778 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
4779 GNUNET_CONTAINER_MDLL_insert (neighbour,
4788 * Communicator gave us a DV learn message. Check the message.
4790 * @param cls a `struct CommunicatorMessageContext`
4791 * @param dvl the send message that was sent
4792 * @return #GNUNET_YES if message is well-formed
4795 check_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4797 uint16_t size = ntohs (dvl->header.size);
4798 uint16_t num_hops = ntohs (dvl->num_hops);
4799 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4802 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4804 GNUNET_break_op (0);
4805 return GNUNET_SYSERR;
4807 if (num_hops > MAX_DV_HOPS_ALLOWED)
4809 GNUNET_break_op (0);
4810 return GNUNET_SYSERR;
4812 for (unsigned int i = 0; i < num_hops; i++)
4814 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
4816 GNUNET_break_op (0);
4817 return GNUNET_SYSERR;
4819 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
4821 GNUNET_break_op (0);
4822 return GNUNET_SYSERR;
4830 * Build and forward a DV learn message to @a next_hop.
4832 * @param next_hop peer to send the message to
4833 * @param msg message received
4834 * @param bi_history bitmask specifying hops on path that were bidirectional
4835 * @param nhops length of the @a hops array
4836 * @param hops path the message traversed so far
4837 * @param in_time when did we receive the message, used to calculate network
4841 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4842 const struct TransportDVLearn *msg,
4843 uint16_t bi_history,
4845 const struct DVPathEntryP *hops,
4846 struct GNUNET_TIME_Absolute in_time)
4848 struct DVPathEntryP *dhops;
4849 struct TransportDVLearn *fwd;
4850 struct GNUNET_TIME_Relative nnd;
4852 /* compute message for forwarding */
4853 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4854 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4855 (nhops + 1) * sizeof (struct DVPathEntryP));
4856 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4857 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4858 (nhops + 1) * sizeof (struct DVPathEntryP));
4859 fwd->num_hops = htons (nhops + 1);
4860 fwd->bidirectional = htons (bi_history);
4861 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4862 GNUNET_TIME_relative_ntoh (
4863 msg->non_network_delay));
4864 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4865 fwd->init_sig = msg->init_sig;
4866 fwd->initiator = msg->initiator;
4867 fwd->challenge = msg->challenge;
4868 dhops = (struct DVPathEntryP *) &fwd[1];
4869 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
4870 dhops[nhops].hop = GST_my_identity;
4872 struct DvHopPS dhp = {.purpose.purpose =
4873 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4874 .purpose.size = htonl (sizeof (dhp)),
4875 .pred = dhops[nhops - 1].hop,
4877 .challenge = msg->challenge};
4879 GNUNET_assert (GNUNET_OK ==
4880 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4882 &dhops[nhops].hop_sig));
4884 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
4889 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4891 * @param init the signer
4892 * @param challenge the challenge that was signed
4893 * @param init_sig signature presumably by @a init
4894 * @return #GNUNET_OK if the signature is valid
4897 validate_dv_initiator_signature (
4898 const struct GNUNET_PeerIdentity *init,
4899 const struct GNUNET_ShortHashCode *challenge,
4900 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4902 struct DvInitPS ip = {.purpose.purpose = htonl (
4903 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4904 .purpose.size = htonl (sizeof (ip)),
4905 .challenge = *challenge};
4909 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4914 GNUNET_break_op (0);
4915 return GNUNET_SYSERR;
4922 * Communicator gave us a DV learn message. Process the request.
4924 * @param cls a `struct CommunicatorMessageContext` (must call
4925 * #finish_cmc_handling() when done)
4926 * @param dvl the message that was received
4929 handle_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4931 struct CommunicatorMessageContext *cmc = cls;
4932 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
4935 uint16_t bi_history;
4936 const struct DVPathEntryP *hops;
4939 struct GNUNET_TIME_Absolute in_time;
4941 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
4942 bi_history = ntohs (dvl->bidirectional);
4943 hops = (const struct DVPathEntryP *) &dvl[1];
4947 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
4950 finish_cmc_handling (cmc);
4957 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
4960 finish_cmc_handling (cmc);
4965 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
4966 cc = cmc->tc->details.communicator.cc;
4967 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
4968 cc); // FIXME: add bi-directional flag to cc?
4969 in_time = GNUNET_TIME_absolute_get ();
4971 /* continue communicator here, everything else can happen asynchronous! */
4972 finish_cmc_handling (cmc);
4974 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
4975 the initiator signature if we send the message back to the initiator... */
4976 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
4980 GNUNET_break_op (0);
4983 // FIXME: asynchronously (!) verify hop-by-hop signatures!
4984 // => if signature verification load too high, implement random drop
4987 do_fwd = GNUNET_YES;
4988 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
4990 struct GNUNET_PeerIdentity path[nhops + 1];
4991 struct GNUNET_TIME_Relative host_latency_sum;
4992 struct GNUNET_TIME_Relative latency;
4993 struct GNUNET_TIME_Relative network_latency;
4995 /* We initiated this, learn the forward path! */
4996 path[0] = GST_my_identity;
4997 path[1] = hops[0].hop;
4998 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
5000 // Need also something to lookup initiation time
5001 // to compute RTT! -> add RTT argument here?
5002 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
5003 // (based on dvl->challenge, we can identify time of origin!)
5005 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
5006 /* assumption: latency on all links is the same */
5007 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
5009 for (unsigned int i = 2; i <= nhops; i++)
5011 struct GNUNET_TIME_Relative ilat;
5013 /* assumption: linear latency increase per hop */
5014 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
5015 path[i] = hops[i - 1].hop;
5016 // FIXME: mark ALL of these as *confirmed* (with what timeout?)
5017 // -- and schedule a job for the confirmation to time out! --
5018 // and possibly do #cores_send_connect_info() if
5019 // the respective neighbour is NOT confirmed yet!
5020 learn_dv_path (path, i, ilat);
5022 /* as we initiated, do not forward again (would be circular!) */
5028 /* last hop was bi-directional, we could learn something here! */
5029 struct GNUNET_PeerIdentity path[nhops + 2];
5031 path[0] = GST_my_identity;
5032 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
5033 for (unsigned int i = 0; i < nhops; i++)
5037 if (0 == (bi_history & (1 << i)))
5038 break; /* i-th hop not bi-directional, stop learning! */
5041 path[i + 2] = dvl->initiator;
5045 path[i + 2] = hops[nhops - i - 2].hop;
5048 iret = learn_dv_path (path, i + 2, GNUNET_TIME_UNIT_FOREVER_REL);
5049 if (GNUNET_SYSERR == iret)
5051 /* path invalid or too long to be interesting for US, thus should also
5052 not be interesting to our neighbours, cut path when forwarding to
5053 'i' hops, except of course for the one that goes back to the
5055 GNUNET_STATISTICS_update (GST_stats,
5056 "# DV learn not forwarded due invalidity of path",
5062 if ((GNUNET_NO == iret) && (nhops == i + 1))
5064 /* we have better paths, and this is the longest target,
5065 so there cannot be anything interesting later */
5066 GNUNET_STATISTICS_update (GST_stats,
5067 "# DV learn not forwarded, got better paths",
5076 if (MAX_DV_HOPS_ALLOWED == nhops)
5078 /* At limit, we're out of here! */
5079 finish_cmc_handling (cmc);
5083 /* Forward to initiator, if path non-trivial and possible */
5084 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
5085 did_initiator = GNUNET_NO;
5088 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
5090 /* send back to origin! */
5091 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
5092 did_initiator = GNUNET_YES;
5094 /* We forward under two conditions: either we still learned something
5095 ourselves (do_fwd), or the path was darn short and thus the initiator is
5096 likely to still be very interested in this (and we did NOT already
5097 send it back to the initiator) */
5098 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
5099 (GNUNET_NO == did_initiator)))
5101 /* FIXME: loop over all neighbours, pick those with low
5102 queues AND that are not yet on the path; possibly
5103 adapt threshold to nhops! */
5105 forward_dv_learn (NULL, // fill in peer from iterator here!
5117 * Communicator gave us a DV box. Check the message.
5119 * @param cls a `struct CommunicatorMessageContext`
5120 * @param dvb the send message that was sent
5121 * @return #GNUNET_YES if message is well-formed
5124 check_dv_box (void *cls, const struct TransportDVBox *dvb)
5126 uint16_t size = ntohs (dvb->header.size);
5127 uint16_t num_hops = ntohs (dvb->num_hops);
5128 const struct GNUNET_PeerIdentity *hops =
5129 (const struct GNUNET_PeerIdentity *) &dvb[1];
5130 const struct GNUNET_MessageHeader *inbox =
5131 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5136 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
5137 sizeof (struct GNUNET_MessageHeader))
5139 GNUNET_break_op (0);
5140 return GNUNET_SYSERR;
5142 isize = ntohs (inbox->size);
5144 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
5146 GNUNET_break_op (0);
5147 return GNUNET_SYSERR;
5149 itype = ntohs (inbox->type);
5150 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
5151 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
5153 GNUNET_break_op (0);
5154 return GNUNET_SYSERR;
5156 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
5158 GNUNET_break_op (0);
5159 return GNUNET_SYSERR;
5166 * Create a DV Box message and queue it for transmission to
5169 * @param next_hop peer to receive the message next
5170 * @param total_hops how many hops did the message take so far
5171 * @param num_hops length of the @a hops array
5172 * @param origin origin of the message
5173 * @param hops next peer(s) to the destination, including destination
5174 * @param payload payload of the box
5175 * @param payload_size number of bytes in @a payload
5178 forward_dv_box (struct Neighbour *next_hop,
5179 uint16_t total_hops,
5181 const struct GNUNET_PeerIdentity *origin,
5182 const struct GNUNET_PeerIdentity *hops,
5183 const void *payload,
5184 uint16_t payload_size)
5186 struct TransportDVBox *dvb;
5187 struct GNUNET_PeerIdentity *dhops;
5189 GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBox) +
5190 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5192 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
5193 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5196 htons (sizeof (struct TransportDVBox) +
5197 sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size);
5198 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5199 dvb->total_hops = htons (total_hops);
5200 dvb->num_hops = htons (num_hops);
5201 dvb->origin = *origin;
5202 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5203 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
5204 memcpy (&dhops[num_hops], payload, payload_size);
5205 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
5210 * Communicator gave us a DV box. Process the request.
5212 * @param cls a `struct CommunicatorMessageContext` (must call
5213 * #finish_cmc_handling() when done)
5214 * @param dvb the message that was received
5217 handle_dv_box (void *cls, const struct TransportDVBox *dvb)
5219 struct CommunicatorMessageContext *cmc = cls;
5220 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5221 uint16_t num_hops = ntohs (dvb->num_hops);
5222 const struct GNUNET_PeerIdentity *hops =
5223 (const struct GNUNET_PeerIdentity *) &dvb[1];
5224 const struct GNUNET_MessageHeader *inbox =
5225 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5229 /* We're trying from the end of the hops array, as we may be
5230 able to find a shortcut unknown to the origin that way */
5231 for (int i = num_hops - 1; i >= 0; i--)
5233 struct Neighbour *n;
5235 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
5237 GNUNET_break_op (0);
5238 finish_cmc_handling (cmc);
5241 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &hops[i]);
5245 ntohs (dvb->total_hops) + 1,
5246 num_hops - i - 1, /* number of hops left */
5248 &hops[i + 1], /* remaining hops */
5249 (const void *) &dvb[1],
5251 finish_cmc_handling (cmc);
5254 /* Woopsie, next hop not in neighbours, drop! */
5255 GNUNET_STATISTICS_update (GST_stats,
5256 "# DV Boxes dropped: next hop unknown",
5259 finish_cmc_handling (cmc);
5262 /* We are the target. Unbox and handle message. */
5263 cmc->im.sender = dvb->origin;
5264 cmc->total_hops = ntohs (dvb->total_hops);
5265 demultiplex_with_cmc (cmc, inbox);
5270 * Client notified us about transmission from a peer. Process the request.
5272 * @param cls a `struct TransportClient` which sent us the message
5273 * @param obm the send message that was sent
5274 * @return #GNUNET_YES if message is well-formed
5277 check_incoming_msg (void *cls,
5278 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5280 struct TransportClient *tc = cls;
5282 if (CT_COMMUNICATOR != tc->type)
5285 return GNUNET_SYSERR;
5287 GNUNET_MQ_check_boxed_message (im);
5293 * Communicator gave us a transport address validation challenge. Process the
5296 * @param cls a `struct CommunicatorMessageContext` (must call
5297 * #finish_cmc_handling() when done)
5298 * @param tvc the message that was received
5301 handle_validation_challenge (void *cls,
5302 const struct TransportValidationChallenge *tvc)
5304 struct CommunicatorMessageContext *cmc = cls;
5305 struct TransportValidationResponse *tvr;
5307 if (cmc->total_hops > 0)
5309 /* DV routing is not allowed for validation challenges! */
5310 GNUNET_break_op (0);
5311 finish_cmc_handling (cmc);
5314 tvr = GNUNET_new (struct TransportValidationResponse);
5316 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5317 tvr->header.size = htons (sizeof (*tvr));
5318 tvr->challenge = tvc->challenge;
5319 tvr->origin_time = tvc->sender_time;
5320 tvr->validity_duration = cmc->im.expected_address_validity;
5322 /* create signature */
5323 struct TransportValidationPS tvp =
5324 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5325 .purpose.size = htonl (sizeof (tvp)),
5326 .validity_duration = tvr->validity_duration,
5327 .challenge = tvc->challenge};
5329 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5333 route_message (&cmc->im.sender,
5335 RMO_ANYTHING_GOES | RMO_REDUNDANT);
5336 finish_cmc_handling (cmc);
5341 * Closure for #check_known_challenge.
5343 struct CheckKnownChallengeContext
5346 * Set to the challenge we are looking for.
5348 const struct GNUNET_ShortHashCode *challenge;
5351 * Set to a matching validation state, if one was found.
5353 struct ValidationState *vs;
5358 * Test if the validation state in @a value matches the
5359 * challenge from @a cls.
5361 * @param cls a `struct CheckKnownChallengeContext`
5362 * @param pid unused (must match though)
5363 * @param value a `struct ValidationState`
5364 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5367 check_known_challenge (void *cls,
5368 const struct GNUNET_PeerIdentity *pid,
5371 struct CheckKnownChallengeContext *ckac = cls;
5372 struct ValidationState *vs = value;
5375 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
5383 * Function called when peerstore is done storing a
5384 * validated address.
5386 * @param cls a `struct ValidationState`
5387 * @param success #GNUNET_YES on success
5390 peerstore_store_validation_cb (void *cls, int success)
5392 struct ValidationState *vs = cls;
5395 if (GNUNET_YES == success)
5397 GNUNET_STATISTICS_update (GST_stats,
5398 "# Peerstore failed to store foreign address",
5405 * Task run periodically to validate some address based on #validation_heap.
5410 validation_start_cb (void *cls);
5414 * Set the time for next_challenge of @a vs to @a new_time.
5415 * Updates the heap and if necessary reschedules the job.
5417 * @param vs validation state to update
5418 * @param new_time new time for revalidation
5421 update_next_challenge_time (struct ValidationState *vs,
5422 struct GNUNET_TIME_Absolute new_time)
5424 struct GNUNET_TIME_Relative delta;
5426 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5427 return; /* be lazy */
5428 vs->next_challenge = new_time;
5431 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
5433 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
5434 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5435 (NULL != validation_task))
5437 if (NULL != validation_task)
5438 GNUNET_SCHEDULER_cancel (validation_task);
5439 /* randomize a bit */
5440 delta.rel_value_us =
5441 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5442 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5443 new_time = GNUNET_TIME_absolute_add (new_time, delta);
5445 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
5450 * Find the queue matching @a pid and @a address.
5452 * @param pid peer the queue must go to
5453 * @param address address the queue must use
5454 * @return NULL if no such queue exists
5456 static struct Queue *
5457 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
5459 struct Neighbour *n;
5461 n = GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
5464 for (struct Queue *pos = n->queue_head; NULL != pos;
5465 pos = pos->next_neighbour)
5467 if (0 == strcmp (pos->address, address))
5475 * Task run periodically to check whether the validity of the given queue has
5476 * run its course. If so, finds either another queue to take over, or clears
5477 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
5478 * chance to take over, and if that fails, notifies CORE about the disconnect.
5480 * @param cls a `struct Queue`
5483 core_queue_visibility_check (void *cls)
5485 struct Queue *q = cls;
5487 q->visibility_task = NULL;
5488 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5490 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5491 &core_queue_visibility_check,
5495 update_neighbour_core_visibility (q->neighbour);
5500 * Check whether the CORE visibility of @a n should change. Finds either a
5501 * queue to preserve the visibility, or clears the neighbour's `core_visible`
5502 * flag. In the latter case, gives DV routes a chance to take over, and if
5503 * that fails, notifies CORE about the disconnect. If so, check whether we
5504 * need to notify CORE.
5506 * @param n neighbour to perform the check for
5509 update_neighbour_core_visibility (struct Neighbour *n)
5511 struct DistanceVector *dv;
5513 GNUNET_assert (GNUNET_YES == n->core_visible);
5514 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
5515 the #core_queue_visibility_check() task for that queue */
5516 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
5519 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5521 /* found a valid queue, use this one */
5522 q->visibility_task =
5523 GNUNET_SCHEDULER_add_at (q->validated_until,
5524 &core_queue_visibility_check,
5529 n->core_visible = GNUNET_NO;
5531 /* Check if _any_ DV route to this neighbour is currently
5532 valid, if so, do NOT tell core about the loss of direct
5533 connectivity (DV still counts!) */
5534 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
5535 if (GNUNET_YES == dv->core_visible)
5537 /* Nothing works anymore, need to tell CORE about the loss of
5539 cores_send_disconnect_info (&n->pid);
5544 * Communicator gave us a transport address validation response. Process the
5547 * @param cls a `struct CommunicatorMessageContext` (must call
5548 * #finish_cmc_handling() when done)
5549 * @param tvr the message that was received
5552 handle_validation_response (void *cls,
5553 const struct TransportValidationResponse *tvr)
5555 struct CommunicatorMessageContext *cmc = cls;
5556 struct ValidationState *vs;
5557 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
5559 struct GNUNET_TIME_Absolute origin_time;
5561 struct DistanceVector *dv;
5563 /* check this is one of our challenges */
5564 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5566 &check_known_challenge,
5568 if (NULL == (vs = ckac.vs))
5570 /* This can happen simply if we 'forgot' the challenge by now,
5571 i.e. because we received the validation response twice */
5572 GNUNET_STATISTICS_update (GST_stats,
5573 "# Validations dropped, challenge unknown",
5576 finish_cmc_handling (cmc);
5580 /* sanity check on origin time */
5581 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
5582 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
5583 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
5585 GNUNET_break_op (0);
5586 finish_cmc_handling (cmc);
5591 /* check signature */
5592 struct TransportValidationPS tvp =
5593 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5594 .purpose.size = htonl (sizeof (tvp)),
5595 .validity_duration = tvr->validity_duration,
5596 .challenge = tvr->challenge};
5600 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
5603 &cmc->im.sender.public_key))
5605 GNUNET_break_op (0);
5606 finish_cmc_handling (cmc);
5611 /* validity is capped by our willingness to keep track of the
5612 validation entry and the maximum the other peer allows */
5613 vs->valid_until = GNUNET_TIME_relative_to_absolute (
5614 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
5615 tvr->validity_duration),
5616 MAX_ADDRESS_VALID_UNTIL));
5617 vs->validated_until =
5618 GNUNET_TIME_absolute_min (vs->valid_until,
5619 GNUNET_TIME_relative_to_absolute (
5620 ADDRESS_VALIDATION_LIFETIME));
5621 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
5622 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
5623 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5625 sizeof (vs->challenge));
5626 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
5627 vs->validated_until,
5628 GNUNET_TIME_relative_multiply (vs->validation_rtt,
5629 VALIDATION_RTT_BUFFER_FACTOR));
5630 vs->last_challenge_use =
5631 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
5632 update_next_challenge_time (vs, vs->first_challenge_use);
5633 vs->sc = GNUNET_PEERSTORE_store (peerstore,
5636 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
5638 strlen (vs->address) + 1,
5640 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5641 &peerstore_store_validation_cb,
5643 finish_cmc_handling (cmc);
5645 /* Finally, we now possibly have a confirmed (!) working queue,
5646 update queue status (if queue still is around) */
5647 q = find_queue (&vs->pid, vs->address);
5650 GNUNET_STATISTICS_update (GST_stats,
5651 "# Queues lost at time of successful validation",
5656 q->validated_until = vs->validated_until;
5657 q->rtt = vs->validation_rtt;
5658 if (GNUNET_NO != q->neighbour->core_visible)
5659 return; /* nothing changed, we are done here */
5660 q->neighbour->core_visible = GNUNET_YES;
5661 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5662 &core_queue_visibility_check,
5664 /* Check if _any_ DV route to this neighbour is
5665 currently valid, if so, do NOT tell core anything! */
5666 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &q->neighbour->pid);
5667 if (GNUNET_YES == dv->core_visible)
5668 return; /* nothing changed, done */
5669 /* We lacked a confirmed connection to the neighbour
5670 before, so tell CORE about it (finally!) */
5671 cores_send_connect_info (&q->neighbour->pid, GNUNET_BANDWIDTH_ZERO);
5676 * Incoming meessage. Process the request.
5678 * @param im the send message that was received
5681 handle_incoming_msg (void *cls,
5682 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5684 struct TransportClient *tc = cls;
5685 struct CommunicatorMessageContext *cmc =
5686 GNUNET_new (struct CommunicatorMessageContext);
5690 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
5695 * Given an inbound message @a msg from a communicator @a cmc,
5696 * demultiplex it based on the type calling the right handler.
5698 * @param cmc context for demultiplexing
5699 * @param msg message to demultiplex
5702 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5703 const struct GNUNET_MessageHeader *msg)
5705 struct GNUNET_MQ_MessageHandler handlers[] =
5706 {GNUNET_MQ_hd_var_size (fragment_box,
5707 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
5708 struct TransportFragmentBox,
5710 GNUNET_MQ_hd_fixed_size (fragment_ack,
5711 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
5712 struct TransportFragmentAckMessage,
5714 GNUNET_MQ_hd_var_size (reliability_box,
5715 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5716 struct TransportReliabilityBox,
5718 GNUNET_MQ_hd_fixed_size (reliability_ack,
5719 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5720 struct TransportReliabilityAckMessage,
5722 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5723 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5724 struct TransportBackchannelEncapsulationMessage,
5726 GNUNET_MQ_hd_var_size (dv_learn,
5727 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5728 struct TransportDVLearn,
5730 GNUNET_MQ_hd_var_size (dv_box,
5731 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5732 struct TransportDVBox,
5734 GNUNET_MQ_hd_fixed_size (
5735 validation_challenge,
5736 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5737 struct TransportValidationChallenge,
5739 GNUNET_MQ_hd_fixed_size (
5740 validation_response,
5741 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5742 struct TransportValidationResponse,
5744 GNUNET_MQ_handler_end ()};
5747 ret = GNUNET_MQ_handle_message (handlers, msg);
5748 if (GNUNET_SYSERR == ret)
5751 GNUNET_SERVICE_client_drop (cmc->tc->client);
5755 if (GNUNET_NO == ret)
5757 /* unencapsulated 'raw' message */
5758 handle_raw_message (&cmc, msg);
5764 * New queue became available. Check message.
5766 * @param cls the client
5767 * @param aqm the send message that was sent
5770 check_add_queue_message (void *cls,
5771 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5773 struct TransportClient *tc = cls;
5775 if (CT_COMMUNICATOR != tc->type)
5778 return GNUNET_SYSERR;
5780 GNUNET_MQ_check_zero_termination (aqm);
5786 * Bandwidth tracker informs us that the delay until we should receive
5789 * @param cls a `struct Queue` for which the delay changed
5792 tracker_update_in_cb (void *cls)
5794 struct Queue *queue = cls;
5795 struct GNUNET_TIME_Relative in_delay;
5798 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5799 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
5800 // FIXME: how exactly do we do inbound flow control?
5805 * If necessary, generates the UUID for a @a pm
5807 * @param pm pending message to generate UUID for.
5810 set_pending_message_uuid (struct PendingMessage *pm)
5812 if (pm->msg_uuid_set)
5814 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5816 sizeof (pm->msg_uuid));
5817 pm->msg_uuid_set = GNUNET_YES;
5822 * Fragment the given @a pm to the given @a mtu. Adds
5823 * additional fragments to the neighbour as well. If the
5824 * @a mtu is too small, generates and error for the @a pm
5827 * @param pm pending message to fragment for transmission
5828 * @param mtu MTU to apply
5829 * @return new message to transmit
5831 static struct PendingMessage *
5832 fragment_message (struct PendingMessage *pm, uint16_t mtu)
5834 struct PendingMessage *ff;
5836 set_pending_message_uuid (pm);
5838 /* This invariant is established in #handle_add_queue_message() */
5839 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5841 /* select fragment for transmission, descending the tree if it has
5842 been expanded until we are at a leaf or at a fragment that is small enough
5845 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
5846 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
5848 ff = ff->head_frag; /* descent into fragmented fragments */
5851 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
5853 /* Did not yet calculate all fragments, calculate next fragment */
5854 struct PendingMessage *frag;
5855 struct TransportFragmentBox tfb;
5863 orig = (const char *) &ff[1];
5864 msize = ff->bytes_msg;
5867 const struct TransportFragmentBox *tfbo;
5869 tfbo = (const struct TransportFragmentBox *) orig;
5870 orig += sizeof (struct TransportFragmentBox);
5871 msize -= sizeof (struct TransportFragmentBox);
5872 xoff = ntohs (tfbo->frag_off);
5874 fragmax = mtu - sizeof (struct TransportFragmentBox);
5875 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
5876 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5877 sizeof (struct TransportFragmentBox) + fragsize);
5878 frag->target = pm->target;
5879 frag->frag_parent = ff;
5880 frag->timeout = pm->timeout;
5881 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5882 frag->pmt = PMT_FRAGMENT_BOX;
5883 msg = (char *) &frag[1];
5884 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
5885 tfb.header.size = htons (sizeof (struct TransportFragmentBox) + fragsize);
5886 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
5887 tfb.msg_uuid = pm->msg_uuid;
5888 tfb.frag_off = htons (ff->frag_off + xoff);
5889 tfb.msg_size = htons (pm->bytes_msg);
5890 memcpy (msg, &tfb, sizeof (tfb));
5891 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
5892 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
5893 ff->frag_off += fragsize;
5897 /* Move head to the tail and return it */
5898 GNUNET_CONTAINER_MDLL_remove (frag,
5899 ff->frag_parent->head_frag,
5900 ff->frag_parent->tail_frag,
5902 GNUNET_CONTAINER_MDLL_insert_tail (frag,
5903 ff->frag_parent->head_frag,
5904 ff->frag_parent->tail_frag,
5911 * Reliability-box the given @a pm. On error (can there be any), NULL
5912 * may be returned, otherwise the "replacement" for @a pm (which
5913 * should then be added to the respective neighbour's queue instead of
5914 * @a pm). If the @a pm is already fragmented or reliability boxed,
5915 * or itself an ACK, this function simply returns @a pm.
5917 * @param pm pending message to box for transmission over unreliabile queue
5918 * @return new message to transmit
5920 static struct PendingMessage *
5921 reliability_box_message (struct PendingMessage *pm)
5923 struct TransportReliabilityBox rbox;
5924 struct PendingMessage *bpm;
5927 if (PMT_CORE != pm->pmt)
5928 return pm; /* already fragmented or reliability boxed, or control message:
5930 if (NULL != pm->bpm)
5931 return pm->bpm; /* already computed earlier: do nothing */
5932 GNUNET_assert (NULL == pm->head_frag);
5933 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
5937 client_send_response (pm, GNUNET_NO, 0);
5940 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
5942 bpm->target = pm->target;
5943 bpm->frag_parent = pm;
5944 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
5945 bpm->timeout = pm->timeout;
5946 bpm->pmt = PMT_RELIABILITY_BOX;
5947 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
5948 set_pending_message_uuid (bpm);
5949 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
5950 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
5951 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
5952 rbox.msg_uuid = pm->msg_uuid;
5953 msg = (char *) &bpm[1];
5954 memcpy (msg, &rbox, sizeof (rbox));
5955 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
5962 * We believe we are ready to transmit a message on a queue. Double-checks
5963 * with the queue's "tracker_out" and then gives the message to the
5964 * communicator for transmission (updating the tracker, and re-scheduling
5965 * itself if applicable).
5967 * @param cls the `struct Queue` to process transmissions for
5970 transmit_on_queue (void *cls)
5972 struct Queue *queue = cls;
5973 struct Neighbour *n = queue->neighbour;
5974 struct PendingMessage *pm;
5975 struct PendingMessage *s;
5978 queue->transmit_task = NULL;
5979 if (NULL == (pm = n->pending_msg_head))
5981 /* no message pending, nothing to do here! */
5984 schedule_transmit_on_queue (queue);
5985 if (NULL != queue->transmit_task)
5986 return; /* do it later */
5988 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5989 overhead += sizeof (struct TransportReliabilityBox);
5991 if ( ( (0 != queue->mtu) &&
5992 (pm->bytes_msg + overhead > queue->mtu) ) ||
5993 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
5994 (NULL != pm->head_frag /* fragments already exist, should
5995 respect that even if MTU is 0 for
5997 s = fragment_message (s,
6000 sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
6004 /* Fragmentation failed, try next message... */
6005 schedule_transmit_on_queue (queue);
6008 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6009 s = reliability_box_message (s);
6012 /* Reliability boxing failed, try next message... */
6013 schedule_transmit_on_queue (queue);
6017 /* Pass 's' for transission to the communicator */
6018 queue_send_msg (queue, s, &s[1], s->bytes_msg);
6019 // FIXME: do something similar to the logic below
6020 // in defragmentation / reliability ACK handling!
6022 /* Check if this transmission somehow conclusively finished handing 'pm'
6023 even without any explicit ACKs */
6024 if ((PMT_CORE == s->pmt) &&
6025 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
6027 /* Full message sent, and over reliabile channel */
6028 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
6030 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
6031 queue->tc->details.communicator.cc) &&
6032 (PMT_FRAGMENT_BOX == s->pmt))
6034 struct PendingMessage *pos;
6036 /* Fragment sent over reliabile channel */
6037 free_fragment_tree (s);
6038 pos = s->frag_parent;
6039 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6041 /* check if subtree is done */
6042 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6046 pos = s->frag_parent;
6047 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6051 /* Was this the last applicable fragmment? */
6052 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
6053 client_send_response (
6056 pm->bytes_msg /* FIXME: calculate and add overheads! */);
6058 else if (PMT_CORE != pm->pmt)
6060 /* This was an acknowledgement of some type, always free */
6061 free_pending_message (pm);
6065 /* message not finished, waiting for acknowledgement */
6066 struct Neighbour *neighbour = pm->target;
6067 /* Update time by which we might retransmit 's' based on queue
6068 characteristics (i.e. RTT); it takes one RTT for the message to
6069 arrive and the ACK to come back in the best case; but the other
6070 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
6071 retransmitting. Note that in the future this heuristic should
6072 likely be improved further (measure RTT stability, consider
6073 message urgency and size when delaying ACKs, etc.) */
6074 s->next_attempt = GNUNET_TIME_relative_to_absolute (
6075 GNUNET_TIME_relative_multiply (queue->rtt, 4));
6078 struct PendingMessage *pos;
6080 /* re-insert sort in neighbour list */
6081 GNUNET_CONTAINER_MDLL_remove (neighbour,
6082 neighbour->pending_msg_head,
6083 neighbour->pending_msg_tail,
6085 pos = neighbour->pending_msg_tail;
6086 while ((NULL != pos) &&
6087 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6088 pos = pos->prev_neighbour;
6089 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
6090 neighbour->pending_msg_head,
6091 neighbour->pending_msg_tail,
6097 /* re-insert sort in fragment list */
6098 struct PendingMessage *fp = s->frag_parent;
6099 struct PendingMessage *pos;
6101 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, s);
6102 pos = fp->tail_frag;
6103 while ((NULL != pos) &&
6104 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6105 pos = pos->prev_frag;
6106 GNUNET_CONTAINER_MDLL_insert_after (frag,
6114 /* finally, re-schedule queue transmission task itself */
6115 schedule_transmit_on_queue (queue);
6120 * Bandwidth tracker informs us that the delay until we
6121 * can transmit again changed.
6123 * @param cls a `struct Queue` for which the delay changed
6126 tracker_update_out_cb (void *cls)
6128 struct Queue *queue = cls;
6129 struct Neighbour *n = queue->neighbour;
6131 if (NULL == n->pending_msg_head)
6133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6134 "Bandwidth allocation updated for empty transmission queue `%s'\n",
6136 return; /* no message pending, nothing to do here! */
6138 GNUNET_SCHEDULER_cancel (queue->transmit_task);
6139 queue->transmit_task = NULL;
6140 schedule_transmit_on_queue (queue);
6145 * Bandwidth tracker informs us that excessive outbound bandwidth was
6146 * allocated which is not being used.
6148 * @param cls a `struct Queue` for which the excess was noted
6151 tracker_excess_out_cb (void *cls)
6155 /* FIXME: trigger excess bandwidth report to core? Right now,
6156 this is done internally within transport_api2_core already,
6157 but we probably want to change the logic and trigger it
6158 from here via a message instead! */
6159 /* TODO: maybe inform someone at this point? */
6160 GNUNET_STATISTICS_update (GST_stats,
6161 "# Excess outbound bandwidth reported",
6168 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
6169 * which is not being used.
6171 * @param cls a `struct Queue` for which the excess was noted
6174 tracker_excess_in_cb (void *cls)
6178 /* TODO: maybe inform somone at this point? */
6179 GNUNET_STATISTICS_update (GST_stats,
6180 "# Excess inbound bandwidth reported",
6187 * Queue to a peer went down. Process the request.
6189 * @param cls the client
6190 * @param dqm the send message that was sent
6193 handle_del_queue_message (void *cls,
6194 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
6196 struct TransportClient *tc = cls;
6198 if (CT_COMMUNICATOR != tc->type)
6201 GNUNET_SERVICE_client_drop (tc->client);
6204 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6205 queue = queue->next_client)
6207 struct Neighbour *neighbour = queue->neighbour;
6209 if ((dqm->qid != queue->qid) ||
6210 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
6213 GNUNET_SERVICE_client_continue (tc->client);
6217 GNUNET_SERVICE_client_drop (tc->client);
6222 * Message was transmitted. Process the request.
6224 * @param cls the client
6225 * @param sma the send message that was sent
6228 handle_send_message_ack (void *cls,
6229 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
6231 struct TransportClient *tc = cls;
6232 struct QueueEntry *qe;
6234 if (CT_COMMUNICATOR != tc->type)
6237 GNUNET_SERVICE_client_drop (tc->client);
6241 /* find our queue entry matching the ACK */
6243 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6244 queue = queue->next_client)
6246 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
6248 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
6251 if (qep->mid != sma->mid)
6260 /* this should never happen */
6262 GNUNET_SERVICE_client_drop (tc->client);
6265 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6266 qe->queue->queue_tail,
6268 qe->queue->queue_length--;
6269 tc->details.communicator.total_queue_length--;
6270 GNUNET_SERVICE_client_continue (tc->client);
6272 /* if applicable, resume transmissions that waited on ACK */
6273 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
6274 tc->details.communicator.total_queue_length)
6276 /* Communicator dropped below threshold, resume all queues */
6277 GNUNET_STATISTICS_update (
6279 "# Transmission throttled due to communicator queue limit",
6282 for (struct Queue *queue = tc->details.communicator.queue_head;
6284 queue = queue->next_client)
6285 schedule_transmit_on_queue (queue);
6287 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6289 /* queue dropped below threshold; only resume this one queue */
6290 GNUNET_STATISTICS_update (GST_stats,
6291 "# Transmission throttled due to queue queue limit",
6294 schedule_transmit_on_queue (qe->queue);
6297 /* TODO: we also should react on the status! */
6298 // FIXME: this probably requires queue->pm = s assignment!
6299 // FIXME: react to communicator status about transmission request. We got:
6300 sma->status; // OK success, SYSERR failure
6307 * Iterator telling new MONITOR client about all existing
6310 * @param cls the new `struct TransportClient`
6311 * @param pid a connected peer
6312 * @param value the `struct Neighbour` with more information
6313 * @return #GNUNET_OK (continue to iterate)
6316 notify_client_queues (void *cls,
6317 const struct GNUNET_PeerIdentity *pid,
6320 struct TransportClient *tc = cls;
6321 struct Neighbour *neighbour = value;
6323 GNUNET_assert (CT_MONITOR == tc->type);
6324 for (struct Queue *q = neighbour->queue_head; NULL != q;
6325 q = q->next_neighbour)
6327 struct MonitorEvent me = {.rtt = q->rtt,
6329 .num_msg_pending = q->num_msg_pending,
6330 .num_bytes_pending = q->num_bytes_pending};
6332 notify_monitor (tc, pid, q->address, q->nt, &me);
6339 * Initialize a monitor client.
6341 * @param cls the client
6342 * @param start the start message that was sent
6345 handle_monitor_start (void *cls,
6346 const struct GNUNET_TRANSPORT_MonitorStart *start)
6348 struct TransportClient *tc = cls;
6350 if (CT_NONE != tc->type)
6353 GNUNET_SERVICE_client_drop (tc->client);
6356 tc->type = CT_MONITOR;
6357 tc->details.monitor.peer = start->peer;
6358 tc->details.monitor.one_shot = ntohl (start->one_shot);
6359 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
6360 GNUNET_SERVICE_client_mark_monitor (tc->client);
6361 GNUNET_SERVICE_client_continue (tc->client);
6366 * Find transport client providing communication service
6367 * for the protocol @a prefix.
6369 * @param prefix communicator name
6370 * @return NULL if no such transport client is available
6372 static struct TransportClient *
6373 lookup_communicator (const char *prefix)
6375 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6377 if (CT_COMMUNICATOR != tc->type)
6379 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
6383 GNUNET_ERROR_TYPE_WARNING,
6384 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6391 * Signature of a function called with a communicator @a address of a peer
6392 * @a pid that an application wants us to connect to.
6394 * @param pid target peer
6395 * @param address the address to try
6398 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
6400 static uint32_t idgen;
6401 struct TransportClient *tc;
6403 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6404 struct GNUNET_MQ_Envelope *env;
6407 prefix = GNUNET_HELLO_address_to_prefix (address);
6410 GNUNET_break (0); /* We got an invalid address!? */
6413 tc = lookup_communicator (prefix);
6416 GNUNET_STATISTICS_update (GST_stats,
6417 "# Suggestions ignored due to missing communicator",
6422 /* forward suggestion for queue creation to communicator */
6423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6424 "Request #%u for `%s' communicator to create queue to `%s'\n",
6425 (unsigned int) idgen,
6428 alen = strlen (address) + 1;
6430 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6431 cqm->request_id = htonl (idgen++);
6432 cqm->receiver = *pid;
6433 memcpy (&cqm[1], address, alen);
6434 GNUNET_MQ_send (tc->mq, env);
6439 * The queue @a q (which matches the peer and address in @a vs) is
6440 * ready for queueing. We should now queue the validation request.
6442 * @param q queue to send on
6443 * @param vs state to derive validation challenge from
6446 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
6448 struct TransportValidationChallenge tvc;
6450 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6452 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6453 tvc.header.size = htons (sizeof (tvc));
6454 tvc.reserved = htonl (0);
6455 tvc.challenge = vs->challenge;
6456 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6457 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
6462 * Task run periodically to validate some address based on #validation_heap.
6467 validation_start_cb (void *cls)
6469 struct ValidationState *vs;
6473 validation_task = NULL;
6474 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6475 /* drop validations past their expiration */
6478 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
6480 free_validation_state (vs);
6481 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6484 return; /* woopsie, no more addresses known, should only
6485 happen if we're really a lonely peer */
6486 q = find_queue (&vs->pid, vs->address);
6489 vs->awaiting_queue = GNUNET_YES;
6490 suggest_to_connect (&vs->pid, vs->address);
6493 validation_transmit_on_queue (q, vs);
6494 /* Finally, reschedule next attempt */
6495 vs->challenge_backoff =
6496 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
6497 MAX_VALIDATION_CHALLENGE_FREQ);
6498 update_next_challenge_time (vs,
6499 GNUNET_TIME_relative_to_absolute (
6500 vs->challenge_backoff));
6505 * Closure for #check_connection_quality.
6507 struct QueueQualityContext
6510 * Set to the @e k'th queue encountered.
6515 * Set to the number of quality queues encountered.
6517 unsigned int quality_count;
6520 * Set to the total number of queues encountered.
6522 unsigned int num_queues;
6525 * Decremented for each queue, for selection of the
6526 * k-th queue in @e q.
6533 * Check whether any queue to the given neighbour is
6534 * of a good "quality" and if so, increment the counter.
6535 * Also counts the total number of queues, and returns
6536 * the k-th queue found.
6538 * @param cls a `struct QueueQualityContext *` with counters
6539 * @param pid peer this is about
6540 * @param value a `struct Neighbour`
6541 * @return #GNUNET_OK (continue to iterate)
6544 check_connection_quality (void *cls,
6545 const struct GNUNET_PeerIdentity *pid,
6548 struct QueueQualityContext *ctx = cls;
6549 struct Neighbour *n = value;
6554 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6556 if (0 != q->distance)
6557 continue; /* DV does not count */
6561 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
6562 statistics and consider those as well here? */
6563 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
6564 do_inc = GNUNET_YES;
6566 if (GNUNET_YES == do_inc)
6567 ctx->quality_count++;
6573 * Task run when we CONSIDER initiating a DV learn
6574 * process. We first check that sending out a message is
6575 * even possible (queues exist), then that it is desirable
6576 * (if not, reschedule the task for later), and finally
6577 * we may then begin the job. If there are too many
6578 * entries in the #dvlearn_map, we purge the oldest entry
6584 start_dv_learn (void *cls)
6586 struct LearnLaunchEntry *lle;
6587 struct QueueQualityContext qqc;
6588 struct TransportDVLearn dvl;
6591 dvlearn_task = NULL;
6592 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
6593 return; /* lost all connectivity, cannot do learning */
6594 qqc.quality_count = 0;
6596 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6597 &check_connection_quality,
6599 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
6601 struct GNUNET_TIME_Relative delay;
6602 unsigned int factor;
6604 /* scale our retries by how far we are above the threshold */
6605 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6606 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
6607 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
6610 /* remove old entries in #dvlearn_map if it has grown too big */
6611 while (MAX_DV_LEARN_PENDING >=
6612 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6615 GNUNET_assert (GNUNET_YES ==
6616 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6619 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
6622 /* setup data structure for learning */
6623 lle = GNUNET_new (struct LearnLaunchEntry);
6624 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6626 sizeof (lle->challenge));
6627 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
6628 GNUNET_break (GNUNET_YES ==
6629 GNUNET_CONTAINER_multishortmap_put (
6633 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6634 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6635 dvl.header.size = htons (sizeof (dvl));
6636 dvl.num_hops = htons (0);
6637 dvl.bidirectional = htons (0);
6638 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6640 struct DvInitPS dvip = {.purpose.purpose = htonl (
6641 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6642 .purpose.size = htonl (sizeof (dvip)),
6643 .challenge = lle->challenge};
6645 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6649 dvl.initiator = GST_my_identity;
6650 dvl.challenge = lle->challenge;
6652 qqc.quality_count = 0;
6653 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
6656 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6657 &check_connection_quality,
6659 GNUNET_assert (NULL != qqc.q);
6661 /* Do this as close to transmission time as possible! */
6662 lle->launch_time = GNUNET_TIME_absolute_get ();
6664 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
6665 /* reschedule this job, randomizing the time it runs (but no
6667 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
6668 DV_LEARN_BASE_FREQUENCY),
6675 * A new queue has been created, check if any address validation
6676 * requests have been waiting for it.
6678 * @param cls a `struct Queue`
6679 * @param pid peer concerned (unused)
6680 * @param value a `struct ValidationState`
6681 * @return #GNUNET_NO if a match was found and we can stop looking
6684 check_validation_request_pending (void *cls,
6685 const struct GNUNET_PeerIdentity *pid,
6688 struct Queue *q = cls;
6689 struct ValidationState *vs = value;
6692 if ((GNUNET_YES == vs->awaiting_queue) &&
6693 (0 == strcmp (vs->address, q->address)))
6695 vs->awaiting_queue = GNUNET_NO;
6696 validation_transmit_on_queue (q, vs);
6704 * New queue became available. Process the request.
6706 * @param cls the client
6707 * @param aqm the send message that was sent
6710 handle_add_queue_message (void *cls,
6711 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6713 struct TransportClient *tc = cls;
6714 struct Queue *queue;
6715 struct Neighbour *neighbour;
6719 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6721 /* MTU so small as to be useless for transmissions,
6722 required for #fragment_message()! */
6723 GNUNET_break_op (0);
6724 GNUNET_SERVICE_client_drop (tc->client);
6727 neighbour = lookup_neighbour (&aqm->receiver);
6728 if (NULL == neighbour)
6730 neighbour = GNUNET_new (struct Neighbour);
6731 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6732 neighbour->pid = aqm->receiver;
6733 GNUNET_assert (GNUNET_OK ==
6734 GNUNET_CONTAINER_multipeermap_put (
6738 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6740 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6741 addr = (const char *) &aqm[1];
6743 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6745 queue->address = (const char *) &queue[1];
6746 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6747 queue->qid = aqm->qid;
6748 queue->mtu = ntohl (aqm->mtu);
6749 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6750 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6751 queue->neighbour = neighbour;
6752 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6753 &tracker_update_in_cb,
6755 GNUNET_BANDWIDTH_ZERO,
6756 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6757 &tracker_excess_in_cb,
6759 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6760 &tracker_update_out_cb,
6762 GNUNET_BANDWIDTH_ZERO,
6763 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6764 &tracker_excess_out_cb,
6766 memcpy (&queue[1], addr, addr_len);
6767 /* notify monitors about new queue */
6769 struct MonitorEvent me = {.rtt = queue->rtt, .cs = queue->cs};
6771 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
6773 GNUNET_CONTAINER_MDLL_insert (neighbour,
6774 neighbour->queue_head,
6775 neighbour->queue_tail,
6777 GNUNET_CONTAINER_MDLL_insert (client,
6778 tc->details.communicator.queue_head,
6779 tc->details.communicator.queue_tail,
6781 /* check if valdiations are waiting for the queue */
6783 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6785 &check_validation_request_pending,
6787 /* might be our first queue, try launching DV learning */
6788 if (NULL == dvlearn_task)
6789 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
6790 GNUNET_SERVICE_client_continue (tc->client);
6795 * Communicator tells us that our request to create a queue "worked", that
6796 * is setting up the queue is now in process.
6798 * @param cls the `struct TransportClient`
6799 * @param cqr confirmation message
6802 handle_queue_create_ok (void *cls,
6803 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6805 struct TransportClient *tc = cls;
6807 if (CT_COMMUNICATOR != tc->type)
6810 GNUNET_SERVICE_client_drop (tc->client);
6813 GNUNET_STATISTICS_update (GST_stats,
6814 "# Suggestions succeeded at communicator",
6817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6818 "Request #%u for communicator to create queue succeeded\n",
6819 (unsigned int) ntohs (cqr->request_id));
6820 GNUNET_SERVICE_client_continue (tc->client);
6825 * Communicator tells us that our request to create a queue failed. This usually
6826 * indicates that the provided address is simply invalid or that the
6827 * communicator's resources are exhausted.
6829 * @param cls the `struct TransportClient`
6830 * @param cqr failure message
6833 handle_queue_create_fail (
6835 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6837 struct TransportClient *tc = cls;
6839 if (CT_COMMUNICATOR != tc->type)
6842 GNUNET_SERVICE_client_drop (tc->client);
6845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6846 "Request #%u for communicator to create queue failed\n",
6847 (unsigned int) ntohs (cqr->request_id));
6848 GNUNET_STATISTICS_update (GST_stats,
6849 "# Suggestions failed in queue creation at communicator",
6852 GNUNET_SERVICE_client_continue (tc->client);
6857 * We have received a `struct ExpressPreferenceMessage` from an application
6860 * @param cls handle to the client
6861 * @param msg the start message
6864 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
6866 struct TransportClient *tc = cls;
6867 struct PeerRequest *pr;
6869 if (CT_APPLICATION != tc->type)
6872 GNUNET_SERVICE_client_drop (tc->client);
6875 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
6880 GNUNET_SERVICE_client_drop (tc->client);
6883 (void) stop_peer_request (tc, &pr->pid, pr);
6884 GNUNET_SERVICE_client_continue (tc->client);
6889 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
6890 * messages. We do nothing here, real verification is done later.
6892 * @param cls a `struct TransportClient *`
6893 * @param msg message to verify
6894 * @return #GNUNET_OK
6897 check_address_consider_verify (
6899 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6908 * Closure for #check_known_address.
6910 struct CheckKnownAddressContext
6913 * Set to the address we are looking for.
6915 const char *address;
6918 * Set to a matching validation state, if one was found.
6920 struct ValidationState *vs;
6925 * Test if the validation state in @a value matches the
6926 * address from @a cls.
6928 * @param cls a `struct CheckKnownAddressContext`
6929 * @param pid unused (must match though)
6930 * @param value a `struct ValidationState`
6931 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6934 check_known_address (void *cls,
6935 const struct GNUNET_PeerIdentity *pid,
6938 struct CheckKnownAddressContext *ckac = cls;
6939 struct ValidationState *vs = value;
6942 if (0 != strcmp (vs->address, ckac->address))
6950 * Start address validation.
6952 * @param pid peer the @a address is for
6953 * @param address an address to reach @a pid (presumably)
6954 * @param expiration when did @a pid claim @a address will become invalid
6957 start_address_validation (const struct GNUNET_PeerIdentity *pid,
6958 const char *address,
6959 struct GNUNET_TIME_Absolute expiration)
6961 struct GNUNET_TIME_Absolute now;
6962 struct ValidationState *vs;
6963 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
6965 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
6966 return; /* expired */
6967 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6969 &check_known_address,
6971 if (NULL != (vs = ckac.vs))
6973 /* if 'vs' is not currently valid, we need to speed up retrying the
6975 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
6977 /* reduce backoff as we got a fresh advertisement */
6978 vs->challenge_backoff =
6979 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
6980 GNUNET_TIME_relative_divide (vs->challenge_backoff,
6982 update_next_challenge_time (vs,
6983 GNUNET_TIME_relative_to_absolute (
6984 vs->challenge_backoff));
6988 now = GNUNET_TIME_absolute_get ();
6989 vs = GNUNET_new (struct ValidationState);
6991 vs->valid_until = expiration;
6992 vs->first_challenge_use = now;
6993 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6994 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6996 sizeof (vs->challenge));
6997 vs->address = GNUNET_strdup (address);
6998 GNUNET_assert (GNUNET_YES ==
6999 GNUNET_CONTAINER_multipeermap_put (
7003 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7004 update_next_challenge_time (vs, now);
7009 * Function called by PEERSTORE for each matching record.
7011 * @param cls closure
7012 * @param record peerstore record information
7013 * @param emsg error message, or NULL if no errors
7016 handle_hello (void *cls,
7017 const struct GNUNET_PEERSTORE_Record *record,
7020 struct PeerRequest *pr = cls;
7025 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7026 "Got failure from PEERSTORE: %s\n",
7030 val = record->value;
7031 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7036 start_address_validation (&pr->pid,
7037 (const char *) record->value,
7043 * We have received a `struct ExpressPreferenceMessage` from an application
7046 * @param cls handle to the client
7047 * @param msg the start message
7050 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
7052 struct TransportClient *tc = cls;
7053 struct PeerRequest *pr;
7055 if (CT_NONE == tc->type)
7057 tc->type = CT_APPLICATION;
7058 tc->details.application.requests =
7059 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
7061 if (CT_APPLICATION != tc->type)
7064 GNUNET_SERVICE_client_drop (tc->client);
7067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7068 "Client suggested we talk to %s with preference %d at rate %u\n",
7069 GNUNET_i2s (&msg->peer),
7070 (int) ntohl (msg->pk),
7071 (int) ntohl (msg->bw.value__));
7072 pr = GNUNET_new (struct PeerRequest);
7074 pr->pid = msg->peer;
7076 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
7077 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
7078 tc->details.application.requests,
7081 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
7085 GNUNET_SERVICE_client_drop (tc->client);
7088 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
7091 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7094 GNUNET_SERVICE_client_continue (tc->client);
7099 * Given another peers address, consider checking it for validity
7100 * and then adding it to the Peerstore.
7102 * @param cls a `struct TransportClient`
7103 * @param hdr message containing the raw address data and
7104 * signature in the body, see #GNUNET_HELLO_extract_address()
7107 handle_address_consider_verify (
7109 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7111 struct TransportClient *tc = cls;
7113 enum GNUNET_NetworkType nt;
7114 struct GNUNET_TIME_Absolute expiration;
7117 // OPTIMIZE-FIXME: checking that we know this address already should
7118 // be done BEFORE checking the signature => HELLO API change!
7119 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
7121 GNUNET_HELLO_extract_address (&hdr[1],
7122 ntohs (hdr->header.size) - sizeof (*hdr),
7126 if (NULL == address)
7128 GNUNET_break_op (0);
7131 start_address_validation (&hdr->peer, address, expiration);
7132 GNUNET_free (address);
7133 GNUNET_SERVICE_client_continue (tc->client);
7138 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
7141 * @param cls a `struct TransportClient *`
7142 * @param m message to verify
7143 * @return #GNUNET_OK on success
7146 check_request_hello_validation (void *cls,
7147 const struct RequestHelloValidationMessage *m)
7150 GNUNET_MQ_check_zero_termination (m);
7156 * A client encountered an address of another peer. Consider validating it,
7157 * and if validation succeeds, persist it to PEERSTORE.
7159 * @param cls a `struct TransportClient *`
7160 * @param m message to verify
7163 handle_request_hello_validation (void *cls,
7164 const struct RequestHelloValidationMessage *m)
7166 struct TransportClient *tc = cls;
7168 start_address_validation (&m->peer,
7169 (const char *) &m[1],
7170 GNUNET_TIME_absolute_ntoh (m->expiration));
7171 GNUNET_SERVICE_client_continue (tc->client);
7176 * Free neighbour entry.
7180 * @param value a `struct Neighbour`
7181 * @return #GNUNET_OK (always)
7184 free_neighbour_cb (void *cls,
7185 const struct GNUNET_PeerIdentity *pid,
7188 struct Neighbour *neighbour = value;
7192 GNUNET_break (0); // should this ever happen?
7193 free_neighbour (neighbour);
7200 * Free DV route entry.
7204 * @param value a `struct DistanceVector`
7205 * @return #GNUNET_OK (always)
7208 free_dv_routes_cb (void *cls,
7209 const struct GNUNET_PeerIdentity *pid,
7212 struct DistanceVector *dv = value;
7223 * Free ephemeral entry.
7227 * @param value a `struct EphemeralCacheEntry`
7228 * @return #GNUNET_OK (always)
7231 free_ephemeral_cb (void *cls,
7232 const struct GNUNET_PeerIdentity *pid,
7235 struct EphemeralCacheEntry *ece = value;
7239 free_ephemeral (ece);
7245 * Free validation state.
7249 * @param value a `struct ValidationState`
7250 * @return #GNUNET_OK (always)
7253 free_validation_state_cb (void *cls,
7254 const struct GNUNET_PeerIdentity *pid,
7257 struct ValidationState *vs = value;
7261 free_validation_state (vs);
7267 * Function called when the service shuts down. Unloads our plugins
7268 * and cancels pending validations.
7270 * @param cls closure, unused
7273 do_shutdown (void *cls)
7275 struct LearnLaunchEntry *lle;
7278 if (NULL != ephemeral_task)
7280 GNUNET_SCHEDULER_cancel (ephemeral_task);
7281 ephemeral_task = NULL;
7283 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
7284 if (NULL != peerstore)
7286 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
7289 if (NULL != GST_stats)
7291 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
7294 if (NULL != GST_my_private_key)
7296 GNUNET_free (GST_my_private_key);
7297 GST_my_private_key = NULL;
7299 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7301 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7302 &free_validation_state_cb,
7304 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7305 validation_map = NULL;
7306 while (NULL != (lle = lle_head))
7308 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7311 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7313 GNUNET_CONTAINER_heap_destroy (validation_heap);
7314 validation_heap = NULL;
7315 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
7316 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7318 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7321 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7322 ephemeral_map = NULL;
7323 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7324 ephemeral_heap = NULL;
7329 * Initiate transport service.
7331 * @param cls closure
7332 * @param c configuration to use
7333 * @param service the initialized service
7337 const struct GNUNET_CONFIGURATION_Handle *c,
7338 struct GNUNET_SERVICE_Handle *service)
7344 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7345 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7346 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
7348 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7349 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7351 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7353 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7354 GST_my_private_key =
7355 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7356 if (NULL == GST_my_private_key)
7359 GNUNET_ERROR_TYPE_ERROR,
7361 "Transport service is lacking key configuration settings. Exiting.\n"));
7362 GNUNET_SCHEDULER_shutdown ();
7365 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7366 &GST_my_identity.public_key);
7367 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7368 "My identity is `%s'\n",
7369 GNUNET_i2s_full (&GST_my_identity));
7370 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
7371 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
7372 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7373 if (NULL == peerstore)
7376 GNUNET_SCHEDULER_shutdown ();
7383 * Define "main" method using service macro.
7385 GNUNET_SERVICE_MAIN (
7387 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7390 &client_disconnect_cb,
7392 /* communication with applications */
7393 GNUNET_MQ_hd_fixed_size (suggest,
7394 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7395 struct ExpressPreferenceMessage,
7397 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7398 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7399 struct ExpressPreferenceMessage,
7401 GNUNET_MQ_hd_var_size (request_hello_validation,
7402 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7403 struct RequestHelloValidationMessage,
7405 /* communication with core */
7406 GNUNET_MQ_hd_fixed_size (client_start,
7407 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7408 struct StartMessage,
7410 GNUNET_MQ_hd_var_size (client_send,
7411 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7412 struct OutboundMessage,
7414 /* communication with communicators */
7415 GNUNET_MQ_hd_var_size (communicator_available,
7416 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7417 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7419 GNUNET_MQ_hd_var_size (communicator_backchannel,
7420 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7421 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7423 GNUNET_MQ_hd_var_size (add_address,
7424 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7425 struct GNUNET_TRANSPORT_AddAddressMessage,
7427 GNUNET_MQ_hd_fixed_size (del_address,
7428 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7429 struct GNUNET_TRANSPORT_DelAddressMessage,
7431 GNUNET_MQ_hd_var_size (incoming_msg,
7432 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7433 struct GNUNET_TRANSPORT_IncomingMessage,
7435 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7436 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7437 struct GNUNET_TRANSPORT_CreateQueueResponse,
7439 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7440 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7441 struct GNUNET_TRANSPORT_CreateQueueResponse,
7443 GNUNET_MQ_hd_var_size (add_queue_message,
7444 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7445 struct GNUNET_TRANSPORT_AddQueueMessage,
7447 GNUNET_MQ_hd_var_size (address_consider_verify,
7448 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7449 struct GNUNET_TRANSPORT_AddressToVerify,
7451 GNUNET_MQ_hd_fixed_size (del_queue_message,
7452 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7453 struct GNUNET_TRANSPORT_DelQueueMessage,
7455 GNUNET_MQ_hd_fixed_size (send_message_ack,
7456 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
7457 struct GNUNET_TRANSPORT_SendMessageToAck,
7459 /* communication with monitors */
7460 GNUNET_MQ_hd_fixed_size (monitor_start,
7461 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
7462 struct GNUNET_TRANSPORT_MonitorStart,
7464 GNUNET_MQ_handler_end ());
7467 /* end of file gnunet-service-transport.c */