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 * - FIXMEs: missing communicator-protocol wrappers around messages
37 * passed in MQ transmission requests on queues (see FIXME in code)
38 * - route_message() implementation, including using DV data structures
39 * (but not when routing certain message types, like DV learn,
40 * MUST pay attention to content here -- or pass extra flags?)
41 * - retransmission logic
42 * - track RTT, distance, loss, etc. => requires extra data structures!
45 * - change transport-core API to provide proper flow control in both
46 * directions, allow multiple messages per peer simultaneously (tag
47 * confirmations with unique message ID), and replace quota-out with
48 * proper flow control;
49 * - if messages are below MTU, consider adding ACKs and other stuff
50 * (requires planning at receiver, and additional MST-style demultiplex
52 * - could avoid copying body of message into each fragment and keep
53 * fragments as just pointers into the original message and only
54 * fully build fragments just before transmission (optimization, should
55 * reduce CPU and memory use)
57 * FIXME (without marks in the code!):
58 * - proper use/initialization of timestamps in messages exchanged
62 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
63 * against our pending message queue (requires additional per neighbour
64 * hash map to be maintained, avoids possible linear scan on pending msgs)
66 * Design realizations / discussion:
67 * - communicators do flow control by calling MQ "notify sent"
68 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
69 * or explicitly via backchannel FC ACKs. As long as the
70 * channel is not full, they may 'notify sent' even if the other
71 * peer has not yet confirmed receipt. The other peer confirming
72 * is _only_ for FC, not for more reliable transmission; reliable
73 * transmission (i.e. of fragments) is left to _transport_.
74 * - ACKs sent back in uni-directional communicators are done via
75 * the background channel API; here transport _may_ initially
76 * broadcast (with bounded # hops) if no path is known;
77 * - transport should _integrate_ DV-routing and build a view of
78 * the network; then background channel traffic can be
79 * routed via DV as well as explicit "DV" traffic.
80 * - background channel is also used for ACKs and NAT traversal support
81 * - transport service is responsible for AEAD'ing the background
82 * channel, timestamps and monotonic time are used against replay
83 * of old messages -> peerstore needs to be supplied with
84 * "latest timestamps seen" data
85 * - if transport implements DV, we likely need a 3rd peermap
86 * in addition to ephemerals and (direct) neighbours
87 * ==> check if stuff needs to be moved out of "Neighbour"
88 * - transport should encapsualte core-level messages and do its
89 * own ACKing for RTT/goodput/loss measurements _and_ fragment
93 #include "gnunet_util_lib.h"
94 #include "gnunet_statistics_service.h"
95 #include "gnunet_transport_monitor_service.h"
96 #include "gnunet_peerstore_service.h"
97 #include "gnunet_hello_lib.h"
98 #include "gnunet_signatures.h"
99 #include "transport.h"
103 * What is the size we assume for a read operation in the
104 * absence of an MTU for the purpose of flow control?
106 #define IN_PACKET_SIZE_WITHOUT_MTU 128
109 * Minimum number of hops we should forward DV learn messages
110 * even if they are NOT useful for us in hope of looping
111 * back to the initiator?
113 * FIXME: allow initiator some control here instead?
115 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
118 * Maximum DV distance allowed ever.
120 #define MAX_DV_HOPS_ALLOWED 16
123 * Maximum number of DV learning activities we may
124 * have pending at the same time.
126 #define MAX_DV_LEARN_PENDING 64
129 * Maximum number of DV paths we keep simultaneously to the same target.
131 #define MAX_DV_PATHS_TO_TARGET 3
134 * If a queue delays the next message by more than this number
135 * of seconds we log a warning. Note: this is for testing,
136 * the value chosen here might be too aggressively low!
138 #define DELAY_WARN_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
141 * We only consider queues as "quality" connections when
142 * suppressing the generation of DV initiation messages if
143 * the latency of the queue is below this threshold.
145 #define DV_QUALITY_RTT_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
148 * How long do we consider a DV path valid if we see no
149 * further updates on it? Note: the value chosen here might be too low!
151 #define DV_PATH_VALIDITY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
154 * How long before paths expire would we like to (re)discover DV paths? Should
155 * be below #DV_PATH_VALIDITY_TIMEOUT.
157 #define DV_PATH_DISCOVERY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
160 * How long are ephemeral keys valid?
162 #define EPHEMERAL_VALIDITY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
165 * How long do we keep partially reassembled messages around before giving up?
167 #define REASSEMBLY_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
170 * What is the fastest rate at which we send challenges *if* we keep learning
171 * an address (gossip, DHT, etc.)?
173 #define FAST_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
176 * What is the slowest rate at which we send challenges?
178 #define MAX_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
181 * What is the non-randomized base frequency at which we
182 * would initiate DV learn messages?
184 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
187 * How many good connections (confirmed, bi-directional, not DV)
188 * do we need to have to suppress initiating DV learn messages?
190 #define DV_LEARN_QUALITY_THRESHOLD 100
193 * When do we forget an invalid address for sure?
195 #define MAX_ADDRESS_VALID_UNTIL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
197 * How long do we consider an address valid if we just checked?
199 #define ADDRESS_VALIDATION_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
202 * What is the maximum frequency at which we do address validation?
203 * A random value between 0 and this value is added when scheduling
204 * the #validation_task (both to ensure we do not validate too often,
205 * and to randomize a bit).
207 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
210 * How many network RTTs before an address validation expires should we begin
211 * trying to revalidate? (Note that the RTT used here is the one that we
212 * experienced during the last validation, not necessarily the latest RTT
215 #define VALIDATION_RTT_BUFFER_FACTOR 3
218 * How many messages can we have pending for a given communicator
219 * process before we start to throttle that communicator?
221 * Used if a communicator might be CPU-bound and cannot handle the traffic.
223 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
226 * How many messages can we have pending for a given queue (queue to
227 * a particular peer via a communicator) process before we start to
228 * throttle that queue?
230 #define QUEUE_LENGTH_LIMIT 32
233 GNUNET_NETWORK_STRUCT_BEGIN
236 * Outer layer of an encapsulated backchannel message.
238 struct TransportBackchannelEncapsulationMessage
241 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
243 struct GNUNET_MessageHeader header;
246 * Distance the backchannel message has traveled, to be updated at
247 * each hop. Used to bound the number of hops in case a backchannel
248 * message is broadcast and thus travels without routing
249 * information (during initial backchannel discovery).
254 * Target's peer identity (as backchannels may be transmitted
255 * indirectly, or even be broadcast).
257 struct GNUNET_PeerIdentity target;
260 * Ephemeral key setup by the sender for @e target, used
261 * to encrypt the payload.
263 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
266 * We use an IV here as the @e ephemeral_key is re-used for
267 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
269 struct GNUNET_ShortHashCode iv;
272 * HMAC over the ciphertext of the encrypted, variable-size
273 * body that follows. Verified via DH of @e target and
276 struct GNUNET_HashCode hmac;
278 /* Followed by encrypted, variable-size payload */
283 * Body by which a peer confirms that it is using an ephemeral key.
285 struct EphemeralConfirmation
289 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
291 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
294 * How long is this signature over the ephemeral key valid?
296 * Note that the receiver MUST IGNORE the absolute time, and only interpret
297 * the value as a mononic time and reject "older" values than the last one
298 * observed. This is necessary as we do not want to require synchronized
299 * clocks and may not have a bidirectional communication channel.
301 * Even with this, there is no real guarantee against replay achieved here,
302 * unless the latest timestamp is persisted. While persistence should be
303 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
304 * communicators must protect against replay attacks when using backchannel
307 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
310 * Target's peer identity.
312 struct GNUNET_PeerIdentity target;
315 * Ephemeral key setup by the sender for @e target, used
316 * to encrypt the payload.
318 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
324 * Plaintext of the variable-size payload that is encrypted
325 * within a `struct TransportBackchannelEncapsulationMessage`
327 struct TransportBackchannelRequestPayload
331 * Sender's peer identity.
333 struct GNUNET_PeerIdentity sender;
336 * Signature of the sender over an
337 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
339 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
342 * How long is this signature over the ephemeral key valid?
344 * Note that the receiver MUST IGNORE the absolute time, and only interpret
345 * the value as a mononic time and reject "older" values than the last one
346 * observed. This is necessary as we do not want to require synchronized
347 * clocks and may not have a bidirectional communication channel.
349 * Even with this, there is no real guarantee against replay achieved here,
350 * unless the latest timestamp is persisted. While persistence should be
351 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
352 * communicators must protect against replay attacks when using backchannel
355 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
358 * Current monotonic time of the sending transport service. Used to
359 * detect replayed messages. Note that the receiver should remember
360 * a list of the recently seen timestamps and only reject messages
361 * if the timestamp is in the list, or the list is "full" and the
362 * timestamp is smaller than the lowest in the list.
364 * Like the @e ephemeral_validity, the list of timestamps per peer should be
365 * persisted to guard against replays after restarts.
367 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
369 /* Followed by a `struct GNUNET_MessageHeader` with a message
370 for a communicator */
372 /* Followed by a 0-termianted string specifying the name of
373 the communicator which is to receive the message */
379 * Outer layer of an encapsulated unfragmented application message sent
380 * over an unreliable channel.
382 struct TransportReliabilityBox
385 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
387 struct GNUNET_MessageHeader header;
390 * Number of messages still to be sent before a commulative
391 * ACK is requested. Zero if an ACK is requested immediately.
392 * In NBO. Note that the receiver may send the ACK faster
393 * if it believes that is reasonable.
395 uint32_t ack_countdown GNUNET_PACKED;
398 * Unique ID of the message used for signalling receipt of
399 * messages sent over possibly unreliable channels. Should
402 struct GNUNET_ShortHashCode msg_uuid;
407 * Confirmation that the receiver got a
408 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
409 * confirmation may be transmitted over a completely different queue,
410 * so ACKs are identified by a combination of PID of sender and
411 * message UUID, without the queue playing any role!
413 struct TransportReliabilityAckMessage
416 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
418 struct GNUNET_MessageHeader header;
423 uint32_t reserved GNUNET_PACKED;
426 * How long was the ACK delayed relative to the average time of
427 * receipt of the messages being acknowledged? Used to calculate
428 * the average RTT by taking the receipt time of the ack minus the
429 * average transmission time of the sender minus this value.
431 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
433 /* followed by any number of `struct GNUNET_ShortHashCode`
434 messages providing ACKs */
439 * Outer layer of an encapsulated fragmented application message.
441 struct TransportFragmentBox
444 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
446 struct GNUNET_MessageHeader header;
449 * Unique ID of this fragment (and fragment transmission!). Will
450 * change even if a fragement is retransmitted to make each
451 * transmission attempt unique! Should be incremented by one for
452 * each fragment transmission. If a client receives a duplicate
453 * fragment (same @e frag_off), it must send
454 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
456 uint32_t frag_uuid GNUNET_PACKED;
459 * Original message ID for of the message that all the1
460 * fragments belong to. Must be the same for all fragments.
462 struct GNUNET_ShortHashCode msg_uuid;
465 * Offset of this fragment in the overall message.
467 uint16_t frag_off GNUNET_PACKED;
470 * Total size of the message that is being fragmented.
472 uint16_t msg_size GNUNET_PACKED;
478 * Outer layer of an fragmented application message sent over a queue
479 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
480 * received, the receiver has two RTTs or 64 further fragments with
481 * the same basic message time to send an acknowledgement, possibly
482 * acknowledging up to 65 fragments in one ACK. ACKs must also be
483 * sent immediately once all fragments were sent.
485 struct TransportFragmentAckMessage
488 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
490 struct GNUNET_MessageHeader header;
493 * Unique ID of the lowest fragment UUID being acknowledged.
495 uint32_t frag_uuid GNUNET_PACKED;
498 * Bitfield of up to 64 additional fragments following the
499 * @e msg_uuid being acknowledged by this message.
501 uint64_t extra_acks GNUNET_PACKED;
504 * Original message ID for of the message that all the
505 * fragments belong to.
507 struct GNUNET_ShortHashCode msg_uuid;
510 * How long was the ACK delayed relative to the average time of
511 * receipt of the fragments being acknowledged? Used to calculate
512 * the average RTT by taking the receipt time of the ack minus the
513 * average transmission time of the sender minus this value.
515 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
518 * How long until the receiver will stop trying reassembly
521 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
526 * Content signed by the initator during DV learning.
528 * The signature is required to prevent DDoS attacks. A peer sending out this
529 * message is potentially generating a lot of traffic that will go back to the
530 * initator, as peers receiving this message will try to let the initiator
531 * know that they got the message.
533 * Without this signature, an attacker could abuse this mechanism for traffic
534 * amplification, sending a lot of traffic to a peer by putting out this type
535 * of message with the victim's peer identity.
537 * Even with just a signature, traffic amplification would be possible via
538 * replay attacks. The @e monotonic_time limits such replay attacks, as every
539 * potential amplificator will check the @e monotonic_time and only respond
540 * (at most) once per message.
545 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
547 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
550 * Time at the initiator when generating the signature.
552 * Note that the receiver MUST IGNORE the absolute time, and only interpret
553 * the value as a mononic time and reject "older" values than the last one
554 * observed. This is necessary as we do not want to require synchronized
555 * clocks and may not have a bidirectional communication channel.
557 * Even with this, there is no real guarantee against replay achieved here,
558 * unless the latest timestamp is persisted. Persistence should be
559 * provided via PEERSTORE if possible.
561 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
564 * Challenge value used by the initiator to re-identify the path.
566 struct GNUNET_ShortHashCode challenge;
572 * Content signed by each peer during DV learning.
574 * This assues the initiator of the DV learning operation that the hop from @e
575 * pred via the signing peer to @e succ actually exists. This makes it
576 * impossible for an adversary to supply the network with bogus routes.
578 * The @e challenge is included to provide replay protection for the
579 * initiator. This way, the initiator knows that the hop existed after the
580 * original @e challenge was first transmitted, providing a freshness metric.
582 * Peers other than the initiator that passively learn paths by observing
583 * these messages do NOT benefit from this. Here, an adversary may indeed
584 * replay old messages. Thus, passively learned paths should always be
585 * immediately marked as "potentially stale".
590 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
592 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
595 * Identity of the previous peer on the path.
597 struct GNUNET_PeerIdentity pred;
600 * Identity of the next peer on the path.
602 struct GNUNET_PeerIdentity succ;
605 * Challenge value used by the initiator to re-identify the path.
607 struct GNUNET_ShortHashCode challenge;
613 * An entry describing a peer on a path in a
614 * `struct TransportDVLearn` message.
619 * Identity of a peer on the path.
621 struct GNUNET_PeerIdentity hop;
624 * Signature of this hop over the path, of purpose
625 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
627 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
633 * Internal message used by transport for distance vector learning.
634 * If @e num_hops does not exceed the threshold, peers should append
635 * themselves to the peer list and flood the message (possibly only
636 * to a subset of their neighbours to limit discoverability of the
637 * network topology). To the extend that the @e bidirectional bits
638 * are set, peers may learn the inverse paths even if they did not
641 * Unless received on a bidirectional queue and @e num_hops just
642 * zero, peers that can forward to the initator should always try to
643 * forward to the initiator.
645 struct TransportDVLearn
648 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
650 struct GNUNET_MessageHeader header;
653 * Number of hops this messages has travelled, in NBO. Zero if
656 uint16_t num_hops GNUNET_PACKED;
659 * Bitmask of the last 16 hops indicating whether they are confirmed
660 * available (without DV) in both directions or not, in NBO. Used
661 * to possibly instantly learn a path in both directions. Each peer
662 * should shift this value by one to the left, and then set the
663 * lowest bit IF the current sender can be reached from it (without
666 uint16_t bidirectional GNUNET_PACKED;
669 * Peers receiving this message and delaying forwarding to other
670 * peers for any reason should increment this value by the non-network
671 * delay created by the peer.
673 struct GNUNET_TIME_RelativeNBO non_network_delay;
676 * Signature of this hop over the path, of purpose
677 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
679 struct GNUNET_CRYPTO_EddsaSignature init_sig;
682 * Identity of the peer that started this learning activity.
684 struct GNUNET_PeerIdentity initiator;
687 * Challenge value used by the initiator to re-identify the path.
689 struct GNUNET_ShortHashCode challenge;
691 /* Followed by @e num_hops `struct DVPathEntryP` values,
692 excluding the initiator of the DV trace; the last entry is the
693 current sender; the current peer must not be included. */
699 * Outer layer of an encapsulated message send over multiple hops.
700 * The path given only includes the identities of the subsequent
701 * peers, i.e. it will be empty if we are the receiver. Each
702 * forwarding peer should scan the list from the end, and if it can,
703 * forward to the respective peer. The list should then be shortened
704 * by all the entries up to and including that peer. Each hop should
705 * also increment @e total_hops to allow the receiver to get a precise
706 * estimate on the number of hops the message travelled. Senders must
707 * provide a learned path that thus should work, but intermediaries
708 * know of a shortcut, they are allowed to send the message via that
711 * If a peer finds itself still on the list, it must drop the message.
713 struct TransportDVBox
716 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
718 struct GNUNET_MessageHeader header;
721 * Number of total hops this messages travelled. In NBO.
722 * @e origin sets this to zero, to be incremented at
725 uint16_t total_hops GNUNET_PACKED;
728 * Number of hops this messages includes. In NBO.
730 uint16_t num_hops GNUNET_PACKED;
733 * Identity of the peer that originated the message.
735 struct GNUNET_PeerIdentity origin;
737 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
738 excluding the @e origin and the current peer, the last must be
739 the ultimate target; if @e num_hops is zero, the receiver of this
740 message is the ultimate target. */
742 /* Followed by the actual message, which itself may be
743 another box, but not a DV_LEARN or DV_BOX message! */
748 * Message send to another peer to validate that it can indeed
749 * receive messages at a particular address.
751 struct TransportValidationChallenge
755 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
757 struct GNUNET_MessageHeader header;
762 uint32_t reserved GNUNET_PACKED;
765 * Challenge to be signed by the receiving peer.
767 struct GNUNET_ShortHashCode challenge;
770 * Timestamp of the sender, to be copied into the reply
771 * to allow sender to calculate RTT.
773 struct GNUNET_TIME_AbsoluteNBO sender_time;
778 * Message signed by a peer to confirm that it can indeed
779 * receive messages at a particular address.
781 struct TransportValidationPS
785 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
787 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
790 * How long does the sender believe the address on
791 * which the challenge was received to remain valid?
793 struct GNUNET_TIME_RelativeNBO validity_duration;
796 * Challenge signed by the receiving peer.
798 struct GNUNET_ShortHashCode challenge;
804 * Message send to a peer to respond to a
805 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
807 struct TransportValidationResponse
811 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
813 struct GNUNET_MessageHeader header;
818 uint32_t reserved GNUNET_PACKED;
821 * The peer's signature matching the
822 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
824 struct GNUNET_CRYPTO_EddsaSignature signature;
827 * The challenge that was signed by the receiving peer.
829 struct GNUNET_ShortHashCode challenge;
832 * Original timestamp of the sender (was @code{sender_time}),
833 * copied into the reply to allow sender to calculate RTT.
835 struct GNUNET_TIME_AbsoluteNBO origin_time;
838 * How long does the sender believe this address to remain
841 struct GNUNET_TIME_RelativeNBO validity_duration;
846 GNUNET_NETWORK_STRUCT_END
850 * What type of client is the `struct TransportClient` about?
855 * We do not know yet (client is fresh).
860 * Is the CORE service, we need to forward traffic to it.
865 * It is a monitor, forward monitor data.
870 * It is a communicator, use for communication.
875 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
882 * When did we launch this DV learning activity?
884 struct LearnLaunchEntry
888 * Kept (also) in a DLL sorted by launch time.
890 struct LearnLaunchEntry *prev;
893 * Kept (also) in a DLL sorted by launch time.
895 struct LearnLaunchEntry *next;
898 * Challenge that uniquely identifies this activity.
900 struct GNUNET_ShortHashCode challenge;
903 * When did we transmit the DV learn message (used to calculate RTT) and
904 * determine freshness of paths learned via this operation.
906 struct GNUNET_TIME_Absolute launch_time;
912 * Entry in our cache of ephemeral keys we currently use. This way, we only
913 * sign an ephemeral once per @e target, and then can re-use it over multiple
914 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
915 * signing is expensive and in some cases we may use backchannel messages a
918 struct EphemeralCacheEntry
922 * Target's peer identity (we don't re-use ephemerals
923 * to limit linkability of messages).
925 struct GNUNET_PeerIdentity target;
928 * Signature affirming @e ephemeral_key of type
929 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
931 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
934 * How long is @e sender_sig valid
936 struct GNUNET_TIME_Absolute ephemeral_validity;
941 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
944 * Our private ephemeral key.
946 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
949 * Node in the ephemeral cache for this entry.
950 * Used for expiration.
952 struct GNUNET_CONTAINER_HeapNode *hn;
957 * Client connected to the transport service.
959 struct TransportClient;
963 * A neighbour that at least one communicator is connected to.
969 * Entry in our #dv_routes table, representing a (set of) distance
970 * vector routes to a particular peer.
972 struct DistanceVector;
975 * One possible hop towards a DV target.
977 struct DistanceVectorHop
981 * Kept in a MDLL, sorted by @e timeout.
983 struct DistanceVectorHop *next_dv;
986 * Kept in a MDLL, sorted by @e timeout.
988 struct DistanceVectorHop *prev_dv;
993 struct DistanceVectorHop *next_neighbour;
998 struct DistanceVectorHop *prev_neighbour;
1001 * What would be the next hop to @e target?
1003 struct Neighbour *next_hop;
1006 * Distance vector entry this hop belongs with.
1008 struct DistanceVector *dv;
1011 * Array of @e distance hops to the target, excluding @e next_hop.
1012 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1013 * at the end of this struct.
1015 const struct GNUNET_PeerIdentity *path;
1018 * At what time do we forget about this path unless we see it again
1021 struct GNUNET_TIME_Absolute timeout;
1024 * After what time do we know for sure that the path must have existed?
1025 * Set to ZERO if the path is learned by snooping on DV learn messages
1026 * initiated by other peers, and to the time at which we generated the
1027 * challenge for DV learn operations this peer initiated.
1029 struct GNUNET_TIME_Absolute freshness;
1032 * How many hops in total to the `target` (excluding @e next_hop and `target` itself),
1033 * thus 0 still means a distance of 2 hops (to @e next_hop and then to `target`)?
1035 unsigned int distance;
1040 * Entry in our #dv_routes table, representing a (set of) distance
1041 * vector routes to a particular peer.
1043 struct DistanceVector
1047 * To which peer is this a route?
1049 struct GNUNET_PeerIdentity target;
1052 * Known paths to @e target.
1054 struct DistanceVectorHop *dv_head;
1057 * Known paths to @e target.
1059 struct DistanceVectorHop *dv_tail;
1062 * Task scheduled to purge expired paths from @e dv_head MDLL.
1064 struct GNUNET_SCHEDULER_Task *timeout_task;
1069 * A queue is a message queue provided by a communicator
1070 * via which we can reach a particular neighbour.
1076 * Entry identifying transmission in one of our `struct
1077 * Queue` which still awaits an ACK. This is used to
1078 * ensure we do not overwhelm a communicator and limit the number of
1079 * messages outstanding per communicator (say in case communicator is
1080 * CPU bound) and per queue (in case bandwidth allocation exceeds
1081 * what the communicator can actually provide towards a particular
1090 struct QueueEntry *next;
1095 struct QueueEntry *prev;
1098 * Queue this entry is queued with.
1100 struct Queue *queue;
1103 * Message ID used for this message with the queue used for transmission.
1110 * A queue is a message queue provided by a communicator
1111 * via which we can reach a particular neighbour.
1118 struct Queue *next_neighbour;
1123 struct Queue *prev_neighbour;
1128 struct Queue *prev_client;
1133 struct Queue *next_client;
1136 * Head of DLL of unacked transmission requests.
1138 struct QueueEntry *queue_head;
1141 * End of DLL of unacked transmission requests.
1143 struct QueueEntry *queue_tail;
1146 * Which neighbour is this queue for?
1148 struct Neighbour *neighbour;
1151 * Which communicator offers this queue?
1153 struct TransportClient *tc;
1156 * Address served by the queue.
1158 const char *address;
1161 * Task scheduled for the time when this queue can (likely) transmit the
1162 * next message. Still needs to check with the @e tracker_out to be sure.
1164 struct GNUNET_SCHEDULER_Task *transmit_task;
1167 * Our current RTT estimate for this queue.
1169 struct GNUNET_TIME_Relative rtt;
1172 * Message ID generator for transmissions on this queue.
1177 * Unique identifier of this queue with the communicator.
1182 * Maximum transmission unit supported by this queue.
1187 * Distance to the target of this queue.
1188 * FIXME: needed? DV is done differently these days...
1195 uint32_t num_msg_pending;
1200 uint32_t num_bytes_pending;
1203 * Length of the DLL starting at @e queue_head.
1205 unsigned int queue_length;
1208 * Network type offered by this queue.
1210 enum GNUNET_NetworkType nt;
1213 * Connection status for this queue.
1215 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1218 * How much outbound bandwidth do we have available for this queue?
1220 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1223 * How much inbound bandwidth do we have available for this queue?
1225 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1230 * Information we keep for a message that we are reassembling.
1232 struct ReassemblyContext
1236 * Original message ID for of the message that all the
1237 * fragments belong to.
1239 struct GNUNET_ShortHashCode msg_uuid;
1242 * Which neighbour is this context for?
1244 struct Neighbour *neighbour;
1247 * Entry in the reassembly heap (sorted by expiration).
1249 struct GNUNET_CONTAINER_HeapNode *hn;
1252 * Bitfield with @e msg_size bits representing the positions
1253 * where we have received fragments. When we receive a fragment,
1254 * we check the bits in @e bitfield before incrementing @e msg_missing.
1256 * Allocated after the reassembled message.
1261 * Task for sending ACK. We may send ACKs either because of hitting
1262 * the @e extra_acks limit, or based on time and @e num_acks. This
1263 * task is for the latter case.
1265 struct GNUNET_SCHEDULER_Task *ack_task;
1268 * At what time will we give up reassembly of this message?
1270 struct GNUNET_TIME_Absolute reassembly_timeout;
1273 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1274 * Should be reset to zero when @e num_acks is set to 0.
1276 struct GNUNET_TIME_Relative avg_ack_delay;
1279 * Time we received the last fragment. @e avg_ack_delay must be
1280 * incremented by now - @e last_frag multiplied by @e num_acks.
1282 struct GNUNET_TIME_Absolute last_frag;
1285 * Bitfield of up to 64 additional fragments following @e frag_uuid
1286 * to be acknowledged in the next cummulative ACK.
1288 uint64_t extra_acks;
1291 * Unique ID of the lowest fragment UUID to be acknowledged in the
1292 * next cummulative ACK. Only valid if @e num_acks > 0.
1297 * Number of ACKs we have accumulated so far. Reset to 0
1298 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1300 unsigned int num_acks;
1303 * How big is the message we are reassembling in total?
1308 * How many bytes of the message are still missing? Defragmentation
1309 * is complete when @e msg_missing == 0.
1311 uint16_t msg_missing;
1313 /* Followed by @e msg_size bytes of the (partially) defragmented original message */
1315 /* Followed by @e bitfield data */
1320 * A neighbour that at least one communicator is connected to.
1326 * Which peer is this about?
1328 struct GNUNET_PeerIdentity pid;
1331 * Map with `struct ReassemblyContext` structs for fragments under
1332 * reassembly. May be NULL if we currently have no fragments from
1333 * this @e pid (lazy initialization).
1335 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1338 * Heap with `struct ReassemblyContext` structs for fragments under
1339 * reassembly. May be NULL if we currently have no fragments from
1340 * this @e pid (lazy initialization).
1342 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1345 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1347 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1350 * Head of list of messages pending for this neighbour.
1352 struct PendingMessage *pending_msg_head;
1355 * Tail of list of messages pending for this neighbour.
1357 struct PendingMessage *pending_msg_tail;
1360 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1361 * purged if this neighbour goes down.
1363 struct DistanceVectorHop *dv_head;
1366 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1367 * purged if this neighbour goes down.
1369 struct DistanceVectorHop *dv_tail;
1372 * Head of DLL of queues to this peer.
1374 struct Queue *queue_head;
1377 * Tail of DLL of queues to this peer.
1379 struct Queue *queue_tail;
1382 * Task run to cleanup pending messages that have exceeded their timeout.
1384 struct GNUNET_SCHEDULER_Task *timeout_task;
1387 * Quota at which CORE is allowed to transmit to this peer.
1389 * FIXME: not yet used, tricky to get right given multiple queues!
1390 * (=> Idea: measure???)
1391 * FIXME: how do we set this value initially when we tell CORE?
1392 * Options: start at a minimum value or at literally zero?
1393 * (=> Current thought: clean would be zero!)
1395 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1398 * What is the earliest timeout of any message in @e pending_msg_tail?
1400 struct GNUNET_TIME_Absolute earliest_timeout;
1406 * A peer that an application (client) would like us to talk to directly.
1412 * Which peer is this about?
1414 struct GNUNET_PeerIdentity pid;
1417 * Client responsible for the request.
1419 struct TransportClient *tc;
1422 * Handle for watching the peerstore for HELLOs for this peer.
1424 struct GNUNET_PEERSTORE_WatchContext *wc;
1427 * What kind of performance preference does this @e tc have?
1429 enum GNUNET_MQ_PreferenceKind pk;
1432 * How much bandwidth would this @e tc like to see?
1434 struct GNUNET_BANDWIDTH_Value32NBO bw;
1440 * Types of different pending messages.
1442 enum PendingMessageType
1446 * Ordinary message received from the CORE service.
1453 PMT_FRAGMENT_BOX = 1,
1458 PMT_RELIABILITY_BOX = 2,
1461 * Any type of acknowledgement.
1463 PMT_ACKNOWLEDGEMENT = 3
1469 * Transmission request that is awaiting delivery. The original
1470 * transmission requests from CORE may be too big for some queues.
1471 * In this case, a *tree* of fragments is created. At each
1472 * level of the tree, fragments are kept in a DLL ordered by which
1473 * fragment should be sent next (at the head). The tree is searched
1474 * top-down, with the original message at the root.
1476 * To select a node for transmission, first it is checked if the
1477 * current node's message fits with the MTU. If it does not, we
1478 * either calculate the next fragment (based on @e frag_off) from the
1479 * current node, or, if all fragments have already been created,
1480 * descend to the @e head_frag. Even though the node was already
1481 * fragmented, the fragment may be too big if the fragment was
1482 * generated for a queue with a larger MTU. In this case, the node
1483 * may be fragmented again, thus creating a tree.
1485 * When acknowledgements for fragments are received, the tree
1486 * must be pruned, removing those parts that were already
1487 * acknowledged. When fragments are sent over a reliable
1488 * channel, they can be immediately removed.
1490 * If a message is ever fragmented, then the original "full" message
1491 * is never again transmitted (even if it fits below the MTU), and
1492 * only (remaining) fragments are sent.
1494 struct PendingMessage
1497 * Kept in a MDLL of messages for this @a target.
1499 struct PendingMessage *next_neighbour;
1502 * Kept in a MDLL of messages for this @a target.
1504 struct PendingMessage *prev_neighbour;
1507 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1509 struct PendingMessage *next_client;
1512 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1514 struct PendingMessage *prev_client;
1517 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOx)
1519 struct PendingMessage *next_frag;
1522 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOX)
1524 struct PendingMessage *prev_frag;
1527 * This message, reliability boxed. Only possibly available if @e pmt is #PMT_CORE.
1529 struct PendingMessage *bpm;
1532 * Target of the request.
1534 struct Neighbour *target;
1537 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1539 struct TransportClient *client;
1542 * Head of a MDLL of fragments created for this core message.
1544 struct PendingMessage *head_frag;
1547 * Tail of a MDLL of fragments created for this core message.
1549 struct PendingMessage *tail_frag;
1552 * Our parent in the fragmentation tree.
1554 struct PendingMessage *frag_parent;
1557 * At what time should we give up on the transmission (and no longer retry)?
1559 struct GNUNET_TIME_Absolute timeout;
1562 * What is the earliest time for us to retry transmission of this message?
1564 struct GNUNET_TIME_Absolute next_attempt;
1567 * UUID to use for this message (used for reassembly of fragments, only
1568 * initialized if @e msg_uuid_set is #GNUNET_YES).
1570 struct GNUNET_ShortHashCode msg_uuid;
1573 * Counter incremented per generated fragment.
1575 uint32_t frag_uuidgen;
1578 * Type of the pending message.
1580 enum PendingMessageType pmt;
1583 * Size of the original message.
1588 * Offset at which we should generate the next fragment.
1593 * #GNUNET_YES once @e msg_uuid was initialized
1595 int16_t msg_uuid_set;
1597 /* Followed by @e bytes_msg to transmit */
1602 * One of the addresses of this peer.
1604 struct AddressListEntry
1610 struct AddressListEntry *next;
1615 struct AddressListEntry *prev;
1618 * Which communicator provides this address?
1620 struct TransportClient *tc;
1623 * The actual address.
1625 const char *address;
1628 * Current context for storing this address in the peerstore.
1630 struct GNUNET_PEERSTORE_StoreContext *sc;
1633 * Task to periodically do @e st operation.
1635 struct GNUNET_SCHEDULER_Task *st;
1638 * What is a typical lifetime the communicator expects this
1639 * address to have? (Always from now.)
1641 struct GNUNET_TIME_Relative expiration;
1644 * Address identifier used by the communicator.
1649 * Network type offered by this address.
1651 enum GNUNET_NetworkType nt;
1657 * Client connected to the transport service.
1659 struct TransportClient
1665 struct TransportClient *next;
1670 struct TransportClient *prev;
1673 * Handle to the client.
1675 struct GNUNET_SERVICE_Client *client;
1678 * Message queue to the client.
1680 struct GNUNET_MQ_Handle *mq;
1683 * What type of client is this?
1685 enum ClientType type;
1691 * Information for @e type #CT_CORE.
1696 * Head of list of messages pending for this client, sorted by
1697 * transmission time ("next_attempt" + possibly internal prioritization).
1699 struct PendingMessage *pending_msg_head;
1702 * Tail of list of messages pending for this client.
1704 struct PendingMessage *pending_msg_tail;
1709 * Information for @e type #CT_MONITOR.
1714 * Peer identity to monitor the addresses of.
1715 * Zero to monitor all neighbours. Valid if
1716 * @e type is #CT_MONITOR.
1718 struct GNUNET_PeerIdentity peer;
1721 * Is this a one-shot monitor?
1729 * Information for @e type #CT_COMMUNICATOR.
1733 * If @e type is #CT_COMMUNICATOR, this communicator
1734 * supports communicating using these addresses.
1736 char *address_prefix;
1739 * Head of DLL of queues offered by this communicator.
1741 struct Queue *queue_head;
1744 * Tail of DLL of queues offered by this communicator.
1746 struct Queue *queue_tail;
1749 * Head of list of the addresses of this peer offered by this communicator.
1751 struct AddressListEntry *addr_head;
1754 * Tail of list of the addresses of this peer offered by this communicator.
1756 struct AddressListEntry *addr_tail;
1759 * Number of queue entries in all queues to this communicator. Used
1760 * throttle sending to a communicator if we see that the communicator
1761 * is globally unable to keep up.
1763 unsigned int total_queue_length;
1766 * Characteristics of this communicator.
1768 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1773 * Information for @e type #CT_APPLICATION
1778 * Map of requests for peers the given client application would like to
1779 * see connections for. Maps from PIDs to `struct PeerRequest`.
1781 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1791 * State we keep for validation activities. Each of these
1792 * is both in the #validation_heap and the #validation_map.
1794 struct ValidationState
1798 * For which peer is @a address to be validated (or possibly valid)?
1799 * Serves as key in the #validation_map.
1801 struct GNUNET_PeerIdentity pid;
1804 * How long did the peer claim this @e address to be valid? Capped at
1805 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1806 * were told about the address and the value claimed by the other peer at
1807 * that time. May be updated similarly when validation succeeds.
1809 struct GNUNET_TIME_Absolute valid_until;
1812 * How long do *we* consider this @e address to be valid?
1813 * In the past or zero if we have not yet validated it.
1815 struct GNUNET_TIME_Absolute validated_until;
1818 * When did we FIRST use the current @e challenge in a message?
1819 * Used to sanity-check @code{origin_time} in the response when
1820 * calculating the RTT. If the @code{origin_time} is not in
1821 * the expected range, the response is discarded as malicious.
1823 struct GNUNET_TIME_Absolute first_challenge_use;
1826 * When did we LAST use the current @e challenge in a message?
1827 * Used to sanity-check @code{origin_time} in the response when
1828 * calculating the RTT. If the @code{origin_time} is not in
1829 * the expected range, the response is discarded as malicious.
1831 struct GNUNET_TIME_Absolute last_challenge_use;
1834 * Next time we will send the @e challenge to the peer, if this time is past
1835 * @e valid_until, this validation state is released at this time. If the
1836 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1837 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1838 * to re-validate before the validity actually expires.
1840 struct GNUNET_TIME_Absolute next_challenge;
1843 * Current backoff factor we're applying for sending the @a challenge.
1844 * Reset to 0 if the @a challenge is confirmed upon validation.
1845 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1846 * existing value if we receive an unvalidated address again over
1847 * another channel (and thus should consider the information "fresh").
1848 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1850 struct GNUNET_TIME_Relative challenge_backoff;
1853 * Initially set to "forever". Once @e validated_until is set, this value is
1854 * set to the RTT that tells us how long it took to receive the validation.
1856 struct GNUNET_TIME_Relative validation_rtt;
1859 * The challenge we sent to the peer to get it to validate the address. Note
1860 * that we rotate the challenge whenever we update @e validated_until to
1861 * avoid attacks where a peer simply replays an old challenge in the future.
1862 * (We must not rotate more often as otherwise we may discard valid answers
1863 * due to packet losses, latency and reorderings on the network).
1865 struct GNUNET_ShortHashCode challenge;
1868 * Claimed address of the peer.
1873 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1874 * heap is used to figure out when the next validation activity should be
1877 struct GNUNET_CONTAINER_HeapNode *hn;
1880 * Handle to a PEERSTORE store operation for this @e address. NULL if
1881 * no PEERSTORE operation is pending.
1883 struct GNUNET_PEERSTORE_StoreContext *sc;
1886 * We are technically ready to send the challenge, but we are waiting for
1887 * the respective queue to become available for transmission.
1895 * Head of linked list of all clients to this service.
1897 static struct TransportClient *clients_head;
1900 * Tail of linked list of all clients to this service.
1902 static struct TransportClient *clients_tail;
1905 * Statistics handle.
1907 static struct GNUNET_STATISTICS_Handle *GST_stats;
1910 * Configuration handle.
1912 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1917 static struct GNUNET_PeerIdentity GST_my_identity;
1922 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1925 * Map from PIDs to `struct Neighbour` entries. A peer is
1926 * a neighbour if we have an MQ to it from some communicator.
1928 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1931 * Map from PIDs to `struct DistanceVector` entries describing
1932 * known paths to the peer.
1934 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
1937 * Map from PIDs to `struct ValidationState` entries describing
1938 * addresses we are aware of and their validity state.
1940 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
1943 * Map from challenges to `struct LearnLaunchEntry` values.
1945 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
1948 * Head of a DLL sorted by launch time.
1950 static struct LearnLaunchEntry *lle_head;
1953 * Tail of a DLL sorted by launch time.
1955 static struct LearnLaunchEntry *lle_tail;
1958 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
1959 * sorting addresses we are aware of by when we should next try to (re)validate
1962 static struct GNUNET_CONTAINER_Heap *validation_heap;
1965 * Database for peer's HELLOs.
1967 static struct GNUNET_PEERSTORE_Handle *peerstore;
1970 * Heap sorting `struct EphemeralCacheEntry` by their
1971 * key/signature validity.
1973 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
1976 * Hash map for looking up `struct EphemeralCacheEntry`s
1977 * by peer identity. (We may have ephemerals in our
1978 * cache for which we do not have a neighbour entry,
1979 * and similar many neighbours may not need ephemerals,
1980 * so we use a second map.)
1982 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
1985 * Task to free expired ephemerals.
1987 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
1990 * Task run to initiate DV learning.
1992 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
1995 * Task to run address validation.
1997 static struct GNUNET_SCHEDULER_Task *validation_task;
2001 * Free cached ephemeral key.
2003 * @param ece cached signature to free
2006 free_ephemeral (struct EphemeralCacheEntry *ece)
2008 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map,
2011 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2017 * Free validation state.
2019 * @param vs validation state to free
2022 free_validation_state (struct ValidationState *vs)
2024 GNUNET_CONTAINER_multipeermap_remove (validation_map,
2027 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2031 GNUNET_PEERSTORE_store_cancel (vs->sc);
2034 GNUNET_free (vs->address);
2040 * Lookup neighbour record for peer @a pid.
2042 * @param pid neighbour to look for
2043 * @return NULL if we do not have this peer as a neighbour
2045 static struct Neighbour *
2046 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2048 return GNUNET_CONTAINER_multipeermap_get (neighbours,
2054 * Details about what to notify monitors about.
2059 * @deprecated To be discussed if we keep these...
2061 struct GNUNET_TIME_Absolute last_validation;
2062 struct GNUNET_TIME_Absolute valid_until;
2063 struct GNUNET_TIME_Absolute next_validation;
2066 * Current round-trip time estimate.
2068 struct GNUNET_TIME_Relative rtt;
2071 * Connection status.
2073 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2078 uint32_t num_msg_pending;
2083 uint32_t num_bytes_pending;
2090 * Free a @dvh. Callers MAY want to check if this was the last path to the
2091 * `target`, and if so call #free_dv_route to also free the associated DV
2092 * entry in #dv_routes (if not, the associated scheduler job should eventually
2095 * @param dvh hop to free
2098 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2100 struct Neighbour *n = dvh->next_hop;
2101 struct DistanceVector *dv = dvh->dv;
2103 GNUNET_CONTAINER_MDLL_remove (neighbour,
2107 GNUNET_CONTAINER_MDLL_remove (dv,
2116 * Free entry in #dv_routes. First frees all hops to the target, and
2117 * if there are no entries left, frees @a dv as well.
2119 * @param dv route to free
2122 free_dv_route (struct DistanceVector *dv)
2124 struct DistanceVectorHop *dvh;
2126 while (NULL != (dvh = dv->dv_head))
2127 free_distance_vector_hop (dvh);
2128 if (NULL == dv->dv_head)
2130 GNUNET_assert (GNUNET_YES ==
2131 GNUNET_CONTAINER_multipeermap_remove (dv_routes,
2134 if (NULL != dv->timeout_task)
2135 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2142 * Notify monitor @a tc about an event. That @a tc
2143 * cares about the event has already been checked.
2145 * Send @a tc information in @a me about a @a peer's status with
2146 * respect to some @a address to all monitors that care.
2148 * @param tc monitor to inform
2149 * @param peer peer the information is about
2150 * @param address address the information is about
2151 * @param nt network type associated with @a address
2152 * @param me detailed information to transmit
2155 notify_monitor (struct TransportClient *tc,
2156 const struct GNUNET_PeerIdentity *peer,
2157 const char *address,
2158 enum GNUNET_NetworkType nt,
2159 const struct MonitorEvent *me)
2161 struct GNUNET_MQ_Envelope *env;
2162 struct GNUNET_TRANSPORT_MonitorData *md;
2163 size_t addr_len = strlen (address) + 1;
2165 env = GNUNET_MQ_msg_extra (md,
2167 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2168 md->nt = htonl ((uint32_t) nt);
2170 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2171 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2172 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2173 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2174 md->cs = htonl ((uint32_t) me->cs);
2175 md->num_msg_pending = htonl (me->num_msg_pending);
2176 md->num_bytes_pending = htonl (me->num_bytes_pending);
2180 GNUNET_MQ_send (tc->mq,
2186 * Send information in @a me about a @a peer's status with respect
2187 * to some @a address to all monitors that care.
2189 * @param peer peer the information is about
2190 * @param address address the information is about
2191 * @param nt network type associated with @a address
2192 * @param me detailed information to transmit
2195 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2196 const char *address,
2197 enum GNUNET_NetworkType nt,
2198 const struct MonitorEvent *me)
2200 for (struct TransportClient *tc = clients_head;
2204 if (CT_MONITOR != tc->type)
2206 if (tc->details.monitor.one_shot)
2208 if ( (0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2209 (0 != GNUNET_memcmp (&tc->details.monitor.peer,
2222 * Called whenever a client connects. Allocates our
2223 * data structures associated with that client.
2225 * @param cls closure, NULL
2226 * @param client identification of the client
2227 * @param mq message queue for the client
2228 * @return our `struct TransportClient`
2231 client_connect_cb (void *cls,
2232 struct GNUNET_SERVICE_Client *client,
2233 struct GNUNET_MQ_Handle *mq)
2235 struct TransportClient *tc;
2238 tc = GNUNET_new (struct TransportClient);
2239 tc->client = client;
2241 GNUNET_CONTAINER_DLL_insert (clients_head,
2244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2245 "Client %p connected\n",
2254 * @param rc data structure to free
2257 free_reassembly_context (struct ReassemblyContext *rc)
2259 struct Neighbour *n = rc->neighbour;
2261 GNUNET_assert (rc ==
2262 GNUNET_CONTAINER_heap_remove_node (rc->hn));
2263 GNUNET_assert (GNUNET_OK ==
2264 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2272 * Task run to clean up reassembly context of a neighbour that have expired.
2274 * @param cls a `struct Neighbour`
2277 reassembly_cleanup_task (void *cls)
2279 struct Neighbour *n = cls;
2280 struct ReassemblyContext *rc;
2282 n->reassembly_timeout_task = NULL;
2283 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2285 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout).rel_value_us)
2287 free_reassembly_context (rc);
2290 GNUNET_assert (NULL == n->reassembly_timeout_task);
2291 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2292 &reassembly_cleanup_task,
2300 * function called to #free_reassembly_context().
2304 * @param value a `struct ReassemblyContext` to free
2305 * @return #GNUNET_OK (continue iteration)
2308 free_reassembly_cb (void *cls,
2309 const struct GNUNET_ShortHashCode *key,
2312 struct ReassemblyContext *rc = value;
2316 free_reassembly_context (rc);
2322 * Release memory used by @a neighbour.
2324 * @param neighbour neighbour entry to free
2327 free_neighbour (struct Neighbour *neighbour)
2329 struct DistanceVectorHop *dvh;
2331 GNUNET_assert (NULL == neighbour->queue_head);
2332 GNUNET_assert (GNUNET_YES ==
2333 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2336 if (NULL != neighbour->timeout_task)
2337 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2338 if (NULL != neighbour->reassembly_map)
2340 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2341 &free_reassembly_cb,
2343 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2344 neighbour->reassembly_map = NULL;
2345 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2346 neighbour->reassembly_heap = NULL;
2348 while (NULL != (dvh = neighbour->dv_head))
2350 struct DistanceVector *dv = dvh->dv;
2352 free_distance_vector_hop (dvh);
2353 if (NULL == dv->dv_head)
2356 if (NULL != neighbour->reassembly_timeout_task)
2357 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2358 GNUNET_free (neighbour);
2363 * Send message to CORE clients that we lost a connection.
2365 * @param tc client to inform (must be CORE client)
2366 * @param pid peer the connection is for
2367 * @param quota_out current quota for the peer
2370 core_send_connect_info (struct TransportClient *tc,
2371 const struct GNUNET_PeerIdentity *pid,
2372 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2374 struct GNUNET_MQ_Envelope *env;
2375 struct ConnectInfoMessage *cim;
2377 GNUNET_assert (CT_CORE == tc->type);
2378 env = GNUNET_MQ_msg (cim,
2379 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2380 cim->quota_out = quota_out;
2382 GNUNET_MQ_send (tc->mq,
2388 * Send message to CORE clients that we gained a connection
2390 * @param pid peer the queue was for
2391 * @param quota_out current quota for the peer
2394 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2395 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2397 for (struct TransportClient *tc = clients_head;
2401 if (CT_CORE != tc->type)
2403 core_send_connect_info (tc,
2411 * Send message to CORE clients that we lost a connection.
2413 * @param pid peer the connection was for
2416 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2418 for (struct TransportClient *tc = clients_head;
2422 struct GNUNET_MQ_Envelope *env;
2423 struct DisconnectInfoMessage *dim;
2425 if (CT_CORE != tc->type)
2427 env = GNUNET_MQ_msg (dim,
2428 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2430 GNUNET_MQ_send (tc->mq,
2437 * We believe we are ready to transmit a message on a queue. Double-checks
2438 * with the queue's "tracker_out" and then gives the message to the
2439 * communicator for transmission (updating the tracker, and re-scheduling
2440 * itself if applicable).
2442 * @param cls the `struct Queue` to process transmissions for
2445 transmit_on_queue (void *cls);
2449 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2450 * we should run immediately or if the message queue is empty.
2451 * Test for no task being added AND queue not being empty to
2452 * transmit immediately afterwards! This function must only
2453 * be called if the message queue is non-empty!
2455 * @param queue the queue to do scheduling for
2458 schedule_transmit_on_queue (struct Queue *queue)
2460 struct Neighbour *n = queue->neighbour;
2461 struct PendingMessage *pm = n->pending_msg_head;
2462 struct GNUNET_TIME_Relative out_delay;
2465 GNUNET_assert (NULL != pm);
2466 if (queue->tc->details.communicator.total_queue_length >=
2467 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2469 GNUNET_STATISTICS_update (GST_stats,
2470 "# Transmission throttled due to communicator queue limit",
2475 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2477 GNUNET_STATISTICS_update (GST_stats,
2478 "# Transmission throttled due to queue queue limit",
2484 wsize = (0 == queue->mtu)
2485 ? pm->bytes_msg /* FIXME: add overheads? */
2487 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out,
2489 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (pm->next_attempt),
2491 if (0 == out_delay.rel_value_us)
2492 return; /* we should run immediately! */
2493 /* queue has changed since we were scheduled, reschedule again */
2494 queue->transmit_task
2495 = GNUNET_SCHEDULER_add_delayed (out_delay,
2498 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2499 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2500 "Next transmission on queue `%s' in %s (high delay)\n",
2502 GNUNET_STRINGS_relative_time_to_string (out_delay,
2505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2506 "Next transmission on queue `%s' in %s\n",
2508 GNUNET_STRINGS_relative_time_to_string (out_delay,
2516 * @param queue the queue to free
2519 free_queue (struct Queue *queue)
2521 struct Neighbour *neighbour = queue->neighbour;
2522 struct TransportClient *tc = queue->tc;
2523 struct MonitorEvent me = {
2524 .cs = GNUNET_TRANSPORT_CS_DOWN,
2525 .rtt = GNUNET_TIME_UNIT_FOREVER_REL
2527 struct QueueEntry *qe;
2530 if (NULL != queue->transmit_task)
2532 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2533 queue->transmit_task = NULL;
2535 GNUNET_CONTAINER_MDLL_remove (neighbour,
2536 neighbour->queue_head,
2537 neighbour->queue_tail,
2539 GNUNET_CONTAINER_MDLL_remove (client,
2540 tc->details.communicator.queue_head,
2541 tc->details.communicator.queue_tail,
2543 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >= tc->details.communicator.total_queue_length);
2544 while (NULL != (qe = queue->queue_head))
2546 GNUNET_CONTAINER_DLL_remove (queue->queue_head,
2549 queue->queue_length--;
2550 tc->details.communicator.total_queue_length--;
2553 GNUNET_assert (0 == queue->queue_length);
2555 (COMMUNICATOR_TOTAL_QUEUE_LIMIT < tc->details.communicator.total_queue_length) )
2557 /* Communicator dropped below threshold, resume all queues */
2558 GNUNET_STATISTICS_update (GST_stats,
2559 "# Transmission throttled due to communicator queue limit",
2562 for (struct Queue *s = tc->details.communicator.queue_head;
2565 schedule_transmit_on_queue (s);
2567 notify_monitors (&neighbour->pid,
2571 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2572 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2573 GNUNET_free (queue);
2574 if (NULL == neighbour->queue_head)
2576 cores_send_disconnect_info (&neighbour->pid);
2577 free_neighbour (neighbour);
2585 * @param ale address list entry to free
2588 free_address_list_entry (struct AddressListEntry *ale)
2590 struct TransportClient *tc = ale->tc;
2592 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2593 tc->details.communicator.addr_tail,
2595 if (NULL != ale->sc)
2597 GNUNET_PEERSTORE_store_cancel (ale->sc);
2600 if (NULL != ale->st)
2602 GNUNET_SCHEDULER_cancel (ale->st);
2610 * Stop the peer request in @a value.
2612 * @param cls a `struct TransportClient` that no longer makes the request
2613 * @param pid the peer's identity
2614 * @param value a `struct PeerRequest`
2615 * @return #GNUNET_YES (always)
2618 stop_peer_request (void *cls,
2619 const struct GNUNET_PeerIdentity *pid,
2622 struct TransportClient *tc = cls;
2623 struct PeerRequest *pr = value;
2625 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2626 GNUNET_assert (GNUNET_YES ==
2627 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2637 * Called whenever a client is disconnected. Frees our
2638 * resources associated with that client.
2640 * @param cls closure, NULL
2641 * @param client identification of the client
2642 * @param app_ctx our `struct TransportClient`
2645 client_disconnect_cb (void *cls,
2646 struct GNUNET_SERVICE_Client *client,
2649 struct TransportClient *tc = app_ctx;
2652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2653 "Client %p disconnected, cleaning up.\n",
2655 GNUNET_CONTAINER_DLL_remove (clients_head,
2664 struct PendingMessage *pm;
2666 while (NULL != (pm = tc->details.core.pending_msg_head))
2668 GNUNET_CONTAINER_MDLL_remove (client,
2669 tc->details.core.pending_msg_head,
2670 tc->details.core.pending_msg_tail,
2678 case CT_COMMUNICATOR:
2681 struct AddressListEntry *ale;
2683 while (NULL != (q = tc->details.communicator.queue_head))
2685 while (NULL != (ale = tc->details.communicator.addr_head))
2686 free_address_list_entry (ale);
2687 GNUNET_free (tc->details.communicator.address_prefix);
2690 case CT_APPLICATION:
2691 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2694 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2702 * Iterator telling new CORE client about all existing
2703 * connections to peers.
2705 * @param cls the new `struct TransportClient`
2706 * @param pid a connected peer
2707 * @param value the `struct Neighbour` with more information
2708 * @return #GNUNET_OK (continue to iterate)
2711 notify_client_connect_info (void *cls,
2712 const struct GNUNET_PeerIdentity *pid,
2715 struct TransportClient *tc = cls;
2716 struct Neighbour *neighbour = value;
2718 core_send_connect_info (tc,
2720 neighbour->quota_out);
2726 * Initialize a "CORE" client. We got a start message from this
2727 * client, so add it to the list of clients for broadcasting of
2730 * @param cls the client
2731 * @param start the start message that was sent
2734 handle_client_start (void *cls,
2735 const struct StartMessage *start)
2737 struct TransportClient *tc = cls;
2740 options = ntohl (start->options);
2741 if ( (0 != (1 & options)) &&
2743 GNUNET_memcmp (&start->self,
2744 &GST_my_identity)) )
2746 /* client thinks this is a different peer, reject */
2748 GNUNET_SERVICE_client_drop (tc->client);
2751 if (CT_NONE != tc->type)
2754 GNUNET_SERVICE_client_drop (tc->client);
2758 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2759 ¬ify_client_connect_info,
2761 GNUNET_SERVICE_client_continue (tc->client);
2766 * Client asked for transmission to a peer. Process the request.
2768 * @param cls the client
2769 * @param obm the send message that was sent
2772 check_client_send (void *cls,
2773 const struct OutboundMessage *obm)
2775 struct TransportClient *tc = cls;
2777 const struct GNUNET_MessageHeader *obmm;
2779 if (CT_CORE != tc->type)
2782 return GNUNET_SYSERR;
2784 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2785 if (size < sizeof (struct GNUNET_MessageHeader))
2788 return GNUNET_SYSERR;
2790 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2791 if (size != ntohs (obmm->size))
2794 return GNUNET_SYSERR;
2801 * Free fragment tree below @e root, excluding @e root itself.
2803 * @param root root of the tree to free
2806 free_fragment_tree (struct PendingMessage *root)
2808 struct PendingMessage *frag;
2810 while (NULL != (frag = root->head_frag))
2812 free_fragment_tree (frag);
2813 GNUNET_CONTAINER_MDLL_remove (frag,
2823 * Release memory associated with @a pm and remove @a pm from associated
2824 * data structures. @a pm must be a top-level pending message and not
2825 * a fragment in the tree. The entire tree is freed (if applicable).
2827 * @param pm the pending message to free
2830 free_pending_message (struct PendingMessage *pm)
2832 struct TransportClient *tc = pm->client;
2833 struct Neighbour *target = pm->target;
2837 GNUNET_CONTAINER_MDLL_remove (client,
2838 tc->details.core.pending_msg_head,
2839 tc->details.core.pending_msg_tail,
2842 GNUNET_CONTAINER_MDLL_remove (neighbour,
2843 target->pending_msg_head,
2844 target->pending_msg_tail,
2846 free_fragment_tree (pm);
2847 GNUNET_free_non_null (pm->bpm);
2853 * Send a response to the @a pm that we have processed a
2854 * "send" request with status @a success. We
2855 * transmitted @a bytes_physical on the actual wire.
2856 * Sends a confirmation to the "core" client responsible
2857 * for the original request and free's @a pm.
2859 * @param pm handle to the original pending message
2860 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2861 * for transmission failure
2862 * @param bytes_physical amount of bandwidth consumed
2865 client_send_response (struct PendingMessage *pm,
2867 uint32_t bytes_physical)
2869 struct TransportClient *tc = pm->client;
2870 struct Neighbour *target = pm->target;
2871 struct GNUNET_MQ_Envelope *env;
2872 struct SendOkMessage *som;
2876 env = GNUNET_MQ_msg (som,
2877 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2878 som->success = htonl ((uint32_t) success);
2879 som->bytes_msg = htons (pm->bytes_msg);
2880 som->bytes_physical = htonl (bytes_physical);
2881 som->peer = target->pid;
2882 GNUNET_MQ_send (tc->mq,
2885 free_pending_message (pm);
2890 * Checks the message queue for a neighbour for messages that have timed
2891 * out and purges them.
2893 * @param cls a `struct Neighbour`
2896 check_queue_timeouts (void *cls)
2898 struct Neighbour *n = cls;
2899 struct PendingMessage *pm;
2900 struct GNUNET_TIME_Absolute now;
2901 struct GNUNET_TIME_Absolute earliest_timeout;
2903 n->timeout_task = NULL;
2904 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2905 now = GNUNET_TIME_absolute_get ();
2906 for (struct PendingMessage *pos = n->pending_msg_head;
2910 pm = pos->next_neighbour;
2911 if (pos->timeout.abs_value_us <= now.abs_value_us)
2913 GNUNET_STATISTICS_update (GST_stats,
2914 "# messages dropped (timeout before confirmation)",
2917 client_send_response (pm,
2922 earliest_timeout = GNUNET_TIME_absolute_min (earliest_timeout,
2925 n->earliest_timeout = earliest_timeout;
2926 if (NULL != n->pending_msg_head)
2927 n->timeout_task = GNUNET_SCHEDULER_add_at (earliest_timeout,
2928 &check_queue_timeouts,
2934 * Client asked for transmission to a peer. Process the request.
2936 * @param cls the client
2937 * @param obm the send message that was sent
2940 handle_client_send (void *cls,
2941 const struct OutboundMessage *obm)
2943 struct TransportClient *tc = cls;
2944 struct PendingMessage *pm;
2945 const struct GNUNET_MessageHeader *obmm;
2946 struct Neighbour *target;
2950 GNUNET_assert (CT_CORE == tc->type);
2951 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2952 bytes_msg = ntohs (obmm->size);
2953 target = lookup_neighbour (&obm->peer);
2956 /* Failure: don't have this peer as a neighbour (anymore).
2957 Might have gone down asynchronously, so this is NOT
2958 a protocol violation by CORE. Still count the event,
2959 as this should be rare. */
2960 struct GNUNET_MQ_Envelope *env;
2961 struct SendOkMessage *som;
2963 env = GNUNET_MQ_msg (som,
2964 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2965 som->success = htonl (GNUNET_SYSERR);
2966 som->bytes_msg = htonl (bytes_msg);
2967 som->bytes_physical = htonl (0);
2968 som->peer = obm->peer;
2969 GNUNET_MQ_send (tc->mq,
2971 GNUNET_SERVICE_client_continue (tc->client);
2972 GNUNET_STATISTICS_update (GST_stats,
2973 "# messages dropped (neighbour unknown)",
2978 was_empty = (NULL == target->pending_msg_head);
2979 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2981 pm->target = target;
2982 pm->bytes_msg = bytes_msg;
2983 pm->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2987 GNUNET_CONTAINER_MDLL_insert (neighbour,
2988 target->pending_msg_head,
2989 target->pending_msg_tail,
2991 GNUNET_CONTAINER_MDLL_insert (client,
2992 tc->details.core.pending_msg_head,
2993 tc->details.core.pending_msg_tail,
2995 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
2997 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
2998 if (NULL != target->timeout_task)
2999 GNUNET_SCHEDULER_cancel (target->timeout_task);
3000 target->timeout_task
3001 = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3002 &check_queue_timeouts,
3006 return; /* all queues must already be busy */
3007 for (struct Queue *queue = target->queue_head;
3009 queue = queue->next_neighbour)
3011 /* try transmission on any queue that is idle */
3012 if (NULL == queue->transmit_task)
3013 queue->transmit_task = GNUNET_SCHEDULER_add_now (&transmit_on_queue,
3020 * Communicator started. Test message is well-formed.
3022 * @param cls the client
3023 * @param cam the send message that was sent
3026 check_communicator_available (void *cls,
3027 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3029 struct TransportClient *tc = cls;
3032 if (CT_NONE != tc->type)
3035 return GNUNET_SYSERR;
3037 tc->type = CT_COMMUNICATOR;
3038 size = ntohs (cam->header.size) - sizeof (*cam);
3040 return GNUNET_OK; /* receive-only communicator */
3041 GNUNET_MQ_check_zero_termination (cam);
3047 * Communicator started. Process the request.
3049 * @param cls the client
3050 * @param cam the send message that was sent
3053 handle_communicator_available (void *cls,
3054 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3056 struct TransportClient *tc = cls;
3059 size = ntohs (cam->header.size) - sizeof (*cam);
3061 return; /* receive-only communicator */
3062 tc->details.communicator.address_prefix
3063 = GNUNET_strdup ((const char *) &cam[1]);
3064 tc->details.communicator.cc
3065 = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3066 GNUNET_SERVICE_client_continue (tc->client);
3071 * Communicator requests backchannel transmission. Check the request.
3073 * @param cls the client
3074 * @param cb the send message that was sent
3075 * @return #GNUNET_OK if message is well-formed
3078 check_communicator_backchannel (void *cls,
3079 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3081 const struct GNUNET_MessageHeader *inbox;
3087 msize = ntohs (cb->header.size) - sizeof (*cb);
3088 if (UINT16_MAX - msize >
3089 sizeof (struct TransportBackchannelEncapsulationMessage) +
3090 sizeof (struct TransportBackchannelRequestPayload) )
3093 return GNUNET_SYSERR;
3095 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3096 isize = ntohs (inbox->size);
3100 return GNUNET_SYSERR;
3102 is = (const char *) inbox;
3105 GNUNET_assert (msize > 0);
3106 if ('\0' != is[msize-1])
3109 return GNUNET_SYSERR;
3116 * Remove memory used by expired ephemeral keys.
3121 expire_ephemerals (void *cls)
3123 struct EphemeralCacheEntry *ece;
3126 ephemeral_task = NULL;
3127 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3129 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us)
3131 free_ephemeral (ece);
3134 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3143 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3144 * one, cache it and return it.
3146 * @param pid peer to look up ephemeral for
3147 * @param private_key[out] set to the private key
3148 * @param ephemeral_key[out] set to the key
3149 * @param ephemeral_sender_sig[out] set to the signature
3150 * @param ephemeral_validity[out] set to the validity expiration time
3153 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3154 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3155 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3156 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3157 struct GNUNET_TIME_Absolute *ephemeral_validity)
3159 struct EphemeralCacheEntry *ece;
3160 struct EphemeralConfirmation ec;
3162 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map,
3164 if ( (NULL != ece) &&
3165 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us) )
3167 free_ephemeral (ece);
3172 ece = GNUNET_new (struct EphemeralCacheEntry);
3174 ece->ephemeral_validity = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3175 EPHEMERAL_VALIDITY);
3176 GNUNET_assert (GNUNET_OK ==
3177 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3178 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key,
3179 &ece->ephemeral_key);
3180 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3181 ec.purpose.size = htonl (sizeof (ec));
3183 ec.ephemeral_key = ece->ephemeral_key;
3184 GNUNET_assert (GNUNET_OK ==
3185 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3188 ece->hn = GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3190 ece->ephemeral_validity.abs_value_us);
3191 GNUNET_assert (GNUNET_OK ==
3192 GNUNET_CONTAINER_multipeermap_put (ephemeral_map,
3195 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3196 if (NULL == ephemeral_task)
3197 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3201 *private_key = ece->private_key;
3202 *ephemeral_key = ece->ephemeral_key;
3203 *ephemeral_sender_sig = ece->sender_sig;
3204 *ephemeral_validity = ece->ephemeral_validity;
3209 * We need to transmit @a hdr to @a target. If necessary, this may
3210 * involve DV routing or even broadcasting and fragmentation.
3212 * @param target peer to receive @a hdr
3213 * @param hdr header of the message to route
3216 route_message (const struct GNUNET_PeerIdentity *target,
3217 struct GNUNET_MessageHeader *hdr)
3219 // FIXME: this one is tricky:
3220 // - we could try a direct, reliable channel
3221 // - if that is unavailable / for load balancing, we may try:
3222 // * multiple (?) direct unreliable channels - depending on loss rate?
3223 // * some (?) DV channels - if above unavailable / too lossy?
3224 // * _random_ other peers ("broadcasting") in hope of *discovering*
3225 // a path back! - if all else fails
3226 // => need more on DV first!
3228 // FIXME: send hdr to target, free hdr (possibly using DV, possibly broadcasting)
3234 * Structure of the key material used to encrypt backchannel messages.
3236 struct BackchannelKeyState
3239 * State of our block cipher.
3241 gcry_cipher_hd_t cipher;
3244 * Actual key material.
3249 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3251 struct GNUNET_CRYPTO_AuthKey hmac_key;
3254 * Symmetric key to use for encryption.
3256 char aes_key[256/8];
3259 * Counter value to use during setup.
3261 char aes_ctr[128/8];
3268 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3269 const struct GNUNET_ShortHashCode *iv,
3270 struct BackchannelKeyState *key)
3272 /* must match #dh_key_derive_eph_pub */
3273 GNUNET_assert (GNUNET_YES ==
3274 GNUNET_CRYPTO_kdf (&key->material,
3275 sizeof (key->material),
3276 "transport-backchannel-key",
3277 strlen ("transport-backchannel-key"),
3282 gcry_cipher_open (&key->cipher,
3283 GCRY_CIPHER_AES256 /* low level: go for speed */,
3284 GCRY_CIPHER_MODE_CTR,
3286 gcry_cipher_setkey (key->cipher,
3287 &key->material.aes_key,
3288 sizeof (key->material.aes_key));
3289 gcry_cipher_setctr (key->cipher,
3290 &key->material.aes_ctr,
3291 sizeof (key->material.aes_ctr));
3296 * Derive backchannel encryption key material from @a priv_ephemeral
3297 * and @a target and @a iv.
3299 * @param priv_ephemeral ephemeral private key to use
3300 * @param target the target peer to encrypt to
3301 * @param iv unique IV to use
3302 * @param key[out] set to the key material
3305 dh_key_derive_eph_pid (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3306 const struct GNUNET_PeerIdentity *target,
3307 const struct GNUNET_ShortHashCode *iv,
3308 struct BackchannelKeyState *key)
3310 struct GNUNET_HashCode km;
3312 GNUNET_assert (GNUNET_YES ==
3313 GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3314 &target->public_key,
3316 bc_setup_key_state_from_km (&km,
3323 * Derive backchannel encryption key material from #GST_my_private_key
3324 * and @a pub_ephemeral and @a iv.
3326 * @param priv_ephemeral ephemeral private key to use
3327 * @param target the target peer to encrypt to
3328 * @param iv unique IV to use
3329 * @param key[out] set to the key material
3332 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3333 const struct GNUNET_ShortHashCode *iv,
3334 struct BackchannelKeyState *key)
3336 struct GNUNET_HashCode km;
3338 GNUNET_assert (GNUNET_YES ==
3339 GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3342 bc_setup_key_state_from_km (&km,
3349 * Do HMAC calculation for backchannel messages over @a data using key
3350 * material from @a key.
3352 * @param key key material (from DH)
3353 * @param hmac[out] set to the HMAC
3354 * @param data data to perform HMAC calculation over
3355 * @param data_size number of bytes in @a data
3358 bc_hmac (const struct BackchannelKeyState *key,
3359 struct GNUNET_HashCode *hmac,
3363 GNUNET_CRYPTO_hmac (&key->material.hmac_key,
3371 * Perform backchannel encryption using symmetric secret in @a key
3372 * to encrypt data from @a in to @a dst.
3374 * @param key[in,out] key material to use
3375 * @param dst where to write the result
3376 * @param in input data to encrypt (plaintext)
3377 * @param in_size number of bytes of input in @a in and available at @a dst
3380 bc_encrypt (struct BackchannelKeyState *key,
3386 gcry_cipher_encrypt (key->cipher,
3395 * Perform backchannel encryption using symmetric secret in @a key
3396 * to encrypt data from @a in to @a dst.
3398 * @param key[in,out] key material to use
3399 * @param ciph cipher text to decrypt
3400 * @param out[out] output data to generate (plaintext)
3401 * @param out_size number of bytes of input in @a ciph and available in @a out
3404 bc_decrypt (struct BackchannelKeyState *key,
3410 gcry_cipher_decrypt (key->cipher,
3419 * Clean up key material in @a key.
3421 * @param key key material to clean up (memory must not be free'd!)
3424 bc_key_clean (struct BackchannelKeyState *key)
3426 gcry_cipher_close (key->cipher);
3427 GNUNET_CRYPTO_zero_keys (&key->material,
3428 sizeof (key->material));
3433 * Communicator requests backchannel transmission. Process the request.
3435 * @param cls the client
3436 * @param cb the send message that was sent
3439 handle_communicator_backchannel (void *cls,
3440 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3442 struct TransportClient *tc = cls;
3443 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3444 struct GNUNET_TIME_Absolute ephemeral_validity;
3445 struct TransportBackchannelEncapsulationMessage *enc;
3446 struct TransportBackchannelRequestPayload ppay;
3447 struct BackchannelKeyState key;
3451 /* encapsulate and encrypt message */
3452 msize = ntohs (cb->header.size) - sizeof (*cb) + sizeof (struct TransportBackchannelRequestPayload);
3453 enc = GNUNET_malloc (sizeof (*enc) + msize);
3454 enc->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3455 enc->header.size = htons (sizeof (*enc) + msize);
3456 enc->target = cb->pid;
3457 lookup_ephemeral (&cb->pid,
3459 &enc->ephemeral_key,
3461 &ephemeral_validity);
3462 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3465 dh_key_derive_eph_pid (&private_key,
3469 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3470 ppay.monotonic_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3471 mpos = (char *) &enc[1];
3478 &mpos[sizeof (ppay)],
3479 ntohs (cb->header.size) - sizeof (*cb));
3483 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3484 bc_key_clean (&key);
3485 route_message (&cb->pid,
3487 GNUNET_SERVICE_client_continue (tc->client);
3492 * Address of our peer added. Test message is well-formed.
3494 * @param cls the client
3495 * @param aam the send message that was sent
3496 * @return #GNUNET_OK if message is well-formed
3499 check_add_address (void *cls,
3500 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3502 struct TransportClient *tc = cls;
3504 if (CT_COMMUNICATOR != tc->type)
3507 return GNUNET_SYSERR;
3509 GNUNET_MQ_check_zero_termination (aam);
3515 * Ask peerstore to store our address.
3517 * @param cls an `struct AddressListEntry *`
3520 store_pi (void *cls);
3524 * Function called when peerstore is done storing our address.
3526 * @param cls a `struct AddressListEntry`
3527 * @param success #GNUNET_YES if peerstore was successful
3530 peerstore_store_own_cb (void *cls,
3533 struct AddressListEntry *ale = cls;
3536 if (GNUNET_YES != success)
3537 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3538 "Failed to store our own address `%s' in peerstore!\n",
3540 /* refresh period is 1/4 of expiration time, that should be plenty
3541 without being excessive. */
3542 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3550 * Ask peerstore to store our address.
3552 * @param cls an `struct AddressListEntry *`
3555 store_pi (void *cls)
3557 struct AddressListEntry *ale = cls;
3560 struct GNUNET_TIME_Absolute expiration;
3563 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3564 GNUNET_HELLO_sign_address (ale->address,
3570 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3573 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3577 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3578 &peerstore_store_own_cb,
3581 if (NULL == ale->sc)
3583 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3584 "Failed to store our address `%s' with peerstore\n",
3586 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
3594 * Address of our peer added. Process the request.
3596 * @param cls the client
3597 * @param aam the send message that was sent
3600 handle_add_address (void *cls,
3601 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3603 struct TransportClient *tc = cls;
3604 struct AddressListEntry *ale;
3607 slen = ntohs (aam->header.size) - sizeof (*aam);
3608 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3610 ale->address = (const char *) &ale[1];
3611 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3612 ale->aid = aam->aid;
3613 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3617 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3618 tc->details.communicator.addr_tail,
3620 ale->st = GNUNET_SCHEDULER_add_now (&store_pi,
3622 GNUNET_SERVICE_client_continue (tc->client);
3627 * Address of our peer deleted. Process the request.
3629 * @param cls the client
3630 * @param dam the send message that was sent
3633 handle_del_address (void *cls,
3634 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3636 struct TransportClient *tc = cls;
3638 if (CT_COMMUNICATOR != tc->type)
3641 GNUNET_SERVICE_client_drop (tc->client);
3644 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3648 if (dam->aid != ale->aid)
3650 GNUNET_assert (ale->tc == tc);
3651 free_address_list_entry (ale);
3652 GNUNET_SERVICE_client_continue (tc->client);
3655 GNUNET_SERVICE_client_drop (tc->client);
3660 * Context from #handle_incoming_msg(). Closure for many
3661 * message handlers below.
3663 struct CommunicatorMessageContext
3666 * Which communicator provided us with the message.
3668 struct TransportClient *tc;
3671 * Additional information for flow control and about the sender.
3673 struct GNUNET_TRANSPORT_IncomingMessage im;
3676 * Number of hops the message has travelled (if DV-routed).
3677 * FIXME: make use of this in ACK handling!
3679 uint16_t total_hops;
3684 * Given an inbound message @a msg from a communicator @a cmc,
3685 * demultiplex it based on the type calling the right handler.
3687 * @param cmc context for demultiplexing
3688 * @param msg message to demultiplex
3691 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3692 const struct GNUNET_MessageHeader *msg);
3696 * Send ACK to communicator (if requested) and free @a cmc.
3698 * @param cmc context for which we are done handling the message
3701 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3703 if (0 != ntohl (cmc->im.fc_on))
3705 /* send ACK when done to communicator for flow control! */
3706 struct GNUNET_MQ_Envelope *env;
3707 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3709 env = GNUNET_MQ_msg (ack,
3710 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3711 ack->reserved = htonl (0);
3712 ack->fc_id = cmc->im.fc_id;
3713 ack->sender = cmc->im.sender;
3714 GNUNET_MQ_send (cmc->tc->mq,
3717 GNUNET_SERVICE_client_continue (cmc->tc->client);
3723 * Communicator gave us an unencapsulated message to pass as-is to
3724 * CORE. Process the request.
3726 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3727 * @param mh the message that was received
3730 handle_raw_message (void *cls,
3731 const struct GNUNET_MessageHeader *mh)
3733 struct CommunicatorMessageContext *cmc = cls;
3734 uint16_t size = ntohs (mh->size);
3736 if ( (size > UINT16_MAX - sizeof (struct InboundMessage)) ||
3737 (size < sizeof (struct GNUNET_MessageHeader)) )
3739 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3742 finish_cmc_handling (cmc);
3743 GNUNET_SERVICE_client_drop (client);
3746 /* Forward to all CORE clients */
3747 for (struct TransportClient *tc = clients_head;
3751 struct GNUNET_MQ_Envelope *env;
3752 struct InboundMessage *im;
3754 if (CT_CORE != tc->type)
3756 env = GNUNET_MQ_msg_extra (im,
3758 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3759 im->peer = cmc->im.sender;
3763 GNUNET_MQ_send (tc->mq,
3766 /* FIXME: consider doing this _only_ once the message
3767 was drained from the CORE MQs to extend flow control to CORE!
3768 (basically, increment counter in cmc, decrement on MQ send continuation! */
3769 finish_cmc_handling (cmc);
3774 * Communicator gave us a fragment box. Check the message.
3776 * @param cls a `struct CommunicatorMessageContext`
3777 * @param fb the send message that was sent
3778 * @return #GNUNET_YES if message is well-formed
3781 check_fragment_box (void *cls,
3782 const struct TransportFragmentBox *fb)
3784 uint16_t size = ntohs (fb->header.size);
3785 uint16_t bsize = size - sizeof (*fb);
3789 GNUNET_break_op (0);
3790 return GNUNET_SYSERR;
3792 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
3794 GNUNET_break_op (0);
3795 return GNUNET_SYSERR;
3797 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
3799 GNUNET_break_op (0);
3800 return GNUNET_SYSERR;
3807 * Generate a fragment acknowledgement for an @a rc.
3809 * @param rc context to generate ACK for, @a rc ACK state is reset
3812 send_fragment_ack (struct ReassemblyContext *rc)
3814 struct TransportFragmentAckMessage *ack;
3816 ack = GNUNET_new (struct TransportFragmentAckMessage);
3817 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
3818 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
3819 ack->frag_uuid = htonl (rc->frag_uuid);
3820 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
3821 ack->msg_uuid = rc->msg_uuid;
3822 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
3823 if (0 == rc->msg_missing)
3824 ack->reassembly_timeout
3825 = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
3827 ack->reassembly_timeout
3828 = GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
3829 route_message (&rc->neighbour->pid,
3831 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
3833 rc->extra_acks = 0LLU;
3838 * Communicator gave us a fragment. Process the request.
3840 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3841 * @param fb the message that was received
3844 handle_fragment_box (void *cls,
3845 const struct TransportFragmentBox *fb)
3847 struct CommunicatorMessageContext *cmc = cls;
3848 struct Neighbour *n;
3849 struct ReassemblyContext *rc;
3850 const struct GNUNET_MessageHeader *msg;
3856 struct GNUNET_TIME_Relative cdelay;
3859 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
3863 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3866 finish_cmc_handling (cmc);
3867 GNUNET_SERVICE_client_drop (client);
3870 if (NULL == n->reassembly_map)
3872 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8,
3874 n->reassembly_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3875 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
3876 &reassembly_cleanup_task,
3879 msize = ntohs (fb->msg_size);
3880 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map,
3884 rc = GNUNET_malloc (sizeof (*rc) +
3885 msize + /* reassembly payload buffer */
3886 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
3887 rc->msg_uuid = fb->msg_uuid;
3889 rc->msg_size = msize;
3890 rc->reassembly_timeout = GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
3891 rc->last_frag = GNUNET_TIME_absolute_get ();
3892 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
3894 rc->reassembly_timeout.abs_value_us);
3895 GNUNET_assert (GNUNET_OK ==
3896 GNUNET_CONTAINER_multishortmap_put (n->reassembly_map,
3899 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3900 target = (char *) &rc[1];
3901 rc->bitfield = (uint8_t *) (target + rc->msg_size);
3902 rc->msg_missing = rc->msg_size;
3906 target = (char *) &rc[1];
3908 if (msize != rc->msg_size)
3911 finish_cmc_handling (cmc);
3916 fsize = ntohs (fb->header.size) - sizeof (*fb);
3917 frag_off = ntohs (fb->frag_off);
3918 memcpy (&target[frag_off],
3921 /* update bitfield and msg_missing */
3922 for (unsigned int i=frag_off;i<frag_off+fsize;i++)
3924 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
3926 rc->bitfield[i / 8] |= (1 << (i % 8));
3931 /* Compute cummulative ACK */
3932 frag_uuid = ntohl (fb->frag_uuid);
3933 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
3934 cdelay = GNUNET_TIME_relative_multiply (cdelay,
3936 rc->last_frag = GNUNET_TIME_absolute_get ();
3937 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay,
3939 ack_now = GNUNET_NO;
3940 if (0 == rc->num_acks)
3942 /* case one: first ack */
3943 rc->frag_uuid = frag_uuid;
3944 rc->extra_acks = 0LLU;
3947 else if ( (frag_uuid >= rc->frag_uuid) &&
3948 (frag_uuid <= rc->frag_uuid + 64) )
3950 /* case two: ack fits after existing min UUID */
3951 if ( (frag_uuid == rc->frag_uuid) ||
3952 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))) )
3954 /* duplicate fragment, ack now! */
3955 ack_now = GNUNET_YES;
3959 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
3963 else if ( (rc->frag_uuid > frag_uuid) &&
3964 ( ( (rc->frag_uuid == frag_uuid + 64) &&
3965 (0 == rc->extra_acks) ) ||
3966 ( (rc->frag_uuid < frag_uuid + 64) &&
3967 (rc->extra_acks == (rc->extra_acks & ~ ((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))) ) ) )
3969 /* can fit ack by shifting extra acks and starting at
3970 frag_uid, test above esured that the bits we will
3971 shift 'extra_acks' by are all zero. */
3972 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
3973 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
3974 rc->frag_uuid = frag_uuid;
3977 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very aggressive. */
3978 ack_now = GNUNET_YES; /* maximum acks received */
3979 // FIXME: possibly also ACK based on RTT (but for that we'd need to
3980 // determine the queue used for the ACK first!)
3982 /* is reassembly complete? */
3983 if (0 != rc->msg_missing)
3986 send_fragment_ack (rc);
3987 finish_cmc_handling (cmc);
3990 /* reassembly is complete, verify result */
3991 msg = (const struct GNUNET_MessageHeader *) &rc[1];
3992 if (ntohs (msg->size) != rc->msg_size)
3995 free_reassembly_context (rc);
3996 finish_cmc_handling (cmc);
3999 /* successful reassembly */
4000 send_fragment_ack (rc);
4001 demultiplex_with_cmc (cmc,
4003 /* FIXME: really free here? Might be bad if fragments are still
4004 en-route and we forget that we finished this reassembly immediately!
4005 -> keep around until timeout?
4006 -> shorten timeout based on ACK? */
4007 free_reassembly_context (rc);
4012 * Check the @a fa against the fragments associated with @a pm.
4013 * If it matches, remove the matching fragments from the transmission
4016 * @param pm pending message to check against the ack
4017 * @param fa the ack that was received
4018 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4021 check_ack_against_pm (struct PendingMessage *pm,
4022 const struct TransportFragmentAckMessage *fa)
4025 struct PendingMessage *nxt;
4026 uint32_t fs = ntohl (fa->frag_uuid);
4027 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4030 for (struct PendingMessage *frag = pm->head_frag;
4034 const struct TransportFragmentBox *tfb
4035 = (const struct TransportFragmentBox *) &pm[1];
4036 uint32_t fu = ntohl (tfb->frag_uuid);
4038 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4039 nxt = frag->next_frag;
4040 /* Check for exact match or match in the 'xtra' bitmask */
4044 (0 != (1LLU << (fu - fs - 1) & xtra)) ) )
4047 free_fragment_tree (frag);
4055 * Communicator gave us a fragment acknowledgement. Process the request.
4057 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4058 * @param fa the message that was received
4061 handle_fragment_ack (void *cls,
4062 const struct TransportFragmentAckMessage *fa)
4064 struct CommunicatorMessageContext *cmc = cls;
4065 struct Neighbour *n;
4068 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
4072 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4075 finish_cmc_handling (cmc);
4076 GNUNET_SERVICE_client_drop (client);
4079 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4080 matched = GNUNET_NO;
4081 for (struct PendingMessage *pm = n->pending_msg_head;
4083 pm = pm->prev_neighbour)
4086 GNUNET_memcmp (&fa->msg_uuid,
4089 matched = GNUNET_YES;
4091 check_ack_against_pm (pm,
4094 struct GNUNET_TIME_Relative avg_ack_delay
4095 = GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4096 // FIXME: update RTT and other reliability data!
4097 // ISSUE: we don't know which of n's queues the message(s)
4098 // took (and in fact the different messages might have gone
4099 // over different queues and possibly over multiple).
4100 // => track queues with PendingMessages, and update RTT only if
4101 // the queue used is unique?
4102 // -> how can we get loss rates?
4103 // -> or, add extra state to Box and ACK to identify queue?
4104 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4105 // the queue with the fragment! (-> this logic must
4106 // be moved into check_ack_against_pm!)
4107 (void) avg_ack_delay;
4111 GNUNET_STATISTICS_update (GST_stats,
4112 "# FRAGMENT_ACKS dropped, no matching fragment",
4116 if (NULL == pm->head_frag)
4118 // if entire message is ACKed, handle that as well.
4119 // => clean up PM, any post actions?
4120 free_pending_message (pm);
4124 struct GNUNET_TIME_Relative reassembly_timeout
4125 = GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4126 // OPTIMIZE-FIXME: adjust retransmission strategy based on reassembly_timeout!
4127 (void) reassembly_timeout;
4131 if (GNUNET_NO == matched)
4133 GNUNET_STATISTICS_update (GST_stats,
4134 "# FRAGMENT_ACKS dropped, no matching pending message",
4138 finish_cmc_handling (cmc);
4143 * Communicator gave us a reliability box. Check the message.
4145 * @param cls a `struct CommunicatorMessageContext`
4146 * @param rb the send message that was sent
4147 * @return #GNUNET_YES if message is well-formed
4150 check_reliability_box (void *cls,
4151 const struct TransportReliabilityBox *rb)
4153 GNUNET_MQ_check_boxed_message (rb);
4159 * Communicator gave us a reliability box. Process the request.
4161 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4162 * @param rb the message that was received
4165 handle_reliability_box (void *cls,
4166 const struct TransportReliabilityBox *rb)
4168 struct CommunicatorMessageContext *cmc = cls;
4169 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &rb[1];
4171 if (0 == ntohl (rb->ack_countdown))
4173 struct TransportReliabilityAckMessage *ack;
4175 /* FIXME: implement cummulative ACKs and ack_countdown,
4176 then setting the avg_ack_delay field below: */
4177 ack = GNUNET_malloc (sizeof (*ack) +
4178 sizeof (struct GNUNET_ShortHashCode));
4179 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4180 ack->header.size = htons (sizeof (*ack) +
4181 sizeof (struct GNUNET_ShortHashCode));
4184 sizeof (struct GNUNET_ShortHashCode));
4185 route_message (&cmc->im.sender,
4188 /* continue with inner message */
4189 demultiplex_with_cmc (cmc,
4195 * Communicator gave us a reliability ack. Process the request.
4197 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4198 * @param ra the message that was received
4201 handle_reliability_ack (void *cls,
4202 const struct TransportReliabilityAckMessage *ra)
4204 struct CommunicatorMessageContext *cmc = cls;
4205 struct Neighbour *n;
4206 unsigned int n_acks;
4207 const struct GNUNET_ShortHashCode *msg_uuids;
4208 struct PendingMessage *nxt;
4211 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
4215 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4218 finish_cmc_handling (cmc);
4219 GNUNET_SERVICE_client_drop (client);
4222 n_acks = (ntohs (ra->header.size) - sizeof (*ra))
4223 / sizeof (struct GNUNET_ShortHashCode);
4224 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4226 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4227 matched = GNUNET_NO;
4228 for (struct PendingMessage *pm = n->pending_msg_head;
4234 nxt = pm->next_neighbour;
4235 in_list = GNUNET_NO;
4236 for (unsigned int i=0;i<n_acks;i++)
4239 GNUNET_memcmp (&msg_uuids[i],
4242 in_list = GNUNET_YES;
4245 if (GNUNET_NO == in_list)
4248 /* this pm was acked! */
4249 matched = GNUNET_YES;
4250 free_pending_message (pm);
4253 struct GNUNET_TIME_Relative avg_ack_delay
4254 = GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4255 // FIXME: update RTT and other reliability data!
4256 // ISSUE: we don't know which of n's queues the message(s)
4257 // took (and in fact the different messages might have gone
4258 // over different queues and possibly over multiple).
4259 // => track queues with PendingMessages, and update RTT only if
4260 // the queue used is unique?
4261 // -> how can we get loss rates?
4262 // -> or, add extra state to MSG and ACKs to identify queue?
4263 // -> if we do this, might just do the same for the avg_ack_delay!
4264 (void) avg_ack_delay;
4267 if (GNUNET_NO == matched)
4269 GNUNET_STATISTICS_update (GST_stats,
4270 "# FRAGMENT_ACKS dropped, no matching pending message",
4274 finish_cmc_handling (cmc);
4279 * Communicator gave us a backchannel encapsulation. Check the message.
4281 * @param cls a `struct CommunicatorMessageContext`
4282 * @param be the send message that was sent
4283 * @return #GNUNET_YES if message is well-formed
4286 check_backchannel_encapsulation (void *cls,
4287 const struct TransportBackchannelEncapsulationMessage *be)
4289 uint16_t size = ntohs (be->header.size);
4292 if (size - sizeof (*be) <
4293 sizeof (struct TransportBackchannelRequestPayload) +
4294 sizeof (struct GNUNET_MessageHeader) )
4296 GNUNET_break_op (0);
4297 return GNUNET_SYSERR;
4304 * Communicator gave us a backchannel encapsulation. Process the request.
4306 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4307 * @param be the message that was received
4310 handle_backchannel_encapsulation (void *cls,
4311 const struct TransportBackchannelEncapsulationMessage *be)
4313 struct CommunicatorMessageContext *cmc = cls;
4314 struct BackchannelKeyState key;
4315 struct GNUNET_HashCode hmac;
4319 if (0 != GNUNET_memcmp (&be->target,
4322 /* not for me, try to route to target */
4323 /* FIXME: someone needs to update be->distance! */
4324 /* FIXME: BE routing can be special, should we put all of this
4325 on 'route_message'? Maybe at least pass some more arguments? */
4326 route_message (&be->target,
4327 GNUNET_copy_message (&be->header));
4328 finish_cmc_handling (cmc);
4331 dh_key_derive_eph_pub (&be->ephemeral_key,
4334 hdr = (const char *) &be[1];
4335 hdr_len = ntohs (be->header.size) - sizeof (*be);
4341 GNUNET_memcmp (&hmac,
4344 /* HMAC missmatch, disard! */
4345 GNUNET_break_op (0);
4346 finish_cmc_handling (cmc);
4349 /* begin actual decryption */
4351 struct TransportBackchannelRequestPayload ppay;
4352 char body[hdr_len - sizeof (ppay)];
4354 GNUNET_assert (hdr_len >= sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4361 &hdr[sizeof (ppay)],
4362 hdr_len - sizeof (ppay));
4363 bc_key_clean (&key);
4364 // FIXME: verify signatures in ppay!
4365 // => check if ephemeral key is known & valid, if not
4366 // => verify sig, cache ephemeral key
4367 // => update monotonic_time of sender for replay detection
4369 // FIXME: forward to specified communicator!
4370 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4372 finish_cmc_handling (cmc);
4377 * Task called when we should check if any of the DV paths
4378 * we have learned to a target are due for garbage collection.
4380 * Collects stale paths, and possibly frees the entire DV
4381 * entry if no paths are left. Otherwise re-schedules itself.
4383 * @param cls a `struct DistanceVector`
4386 path_cleanup_cb (void *cls)
4388 struct DistanceVector *dv = cls;
4389 struct DistanceVectorHop *pos;
4391 dv->timeout_task = NULL;
4392 while (NULL != (pos = dv->dv_head))
4394 GNUNET_assert (dv == pos->dv);
4395 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4397 free_distance_vector_hop (pos);
4404 dv->timeout_task = GNUNET_SCHEDULER_add_at (pos->timeout,
4411 * We have learned a @a path through the network to some other peer, add it to
4412 * our DV data structure (returning #GNUNET_YES on success).
4414 * We do not add paths if we have a sufficient number of shorter
4415 * paths to this target already (returning #GNUNET_NO).
4417 * We also do not add problematic paths, like those where we lack the first
4418 * hop in our neighbour list (i.e. due to a topology change) or where some
4419 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4421 * @param path the path we learned, path[0] should be us,
4422 * and then path contains a valid path from us to `path[path_len-1]`
4423 * path[1] should be a direct neighbour (we should check!)
4424 * @param path_len number of entries on the @a path, at least three!
4425 * @param network_latency how long does the message take from us to `path[path_len-1]`?
4426 * set to "forever" if unknown
4427 * @return #GNUNET_YES on success,
4428 * #GNUNET_NO if we have better path(s) to the target
4429 * #GNUNET_SYSERR if the path is useless and/or invalid
4430 * (i.e. path[1] not a direct neighbour
4431 * or path[i+1] is a direct neighbour for i>0)
4434 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4435 unsigned int path_len,
4436 struct GNUNET_TIME_Relative network_latency)
4438 struct DistanceVectorHop *hop;
4439 struct DistanceVector *dv;
4440 struct Neighbour *next_hop;
4441 unsigned int shorter_distance;
4445 /* what a boring path! not allowed! */
4447 return GNUNET_SYSERR;
4450 GNUNET_memcmp (&GST_my_identity,
4452 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours,
4454 if (NULL == next_hop)
4456 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4458 return GNUNET_SYSERR;
4460 for (unsigned int i=2;i<path_len;i++)
4462 GNUNET_CONTAINER_multipeermap_get (neighbours,
4465 /* Useless path, we have a direct connection to some hop
4466 in the middle of the path, so this one doesn't even
4467 seem terribly useful for redundancy */
4468 return GNUNET_SYSERR;
4470 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes,
4471 &path[path_len - 1]);
4474 dv = GNUNET_new (struct DistanceVector);
4475 dv->target = path[path_len - 1];
4476 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4479 GNUNET_assert (GNUNET_OK ==
4480 GNUNET_CONTAINER_multipeermap_put (dv_routes,
4483 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4485 /* Check if we have this path already! */
4486 shorter_distance = 0;
4487 for (struct DistanceVectorHop *pos = dv->dv_head;
4491 if (pos->distance < path_len - 2)
4493 /* Note that the distances in 'pos' excludes us (path[0]) and
4494 the next_hop (path[1]), so we need to subtract two
4495 and check next_hop explicitly */
4496 if ( (pos->distance == path_len - 2) &&
4497 (pos->next_hop == next_hop) )
4499 int match = GNUNET_YES;
4501 for (unsigned int i=0;i<pos->distance;i++)
4504 GNUNET_memcmp (&pos->path[i],
4511 if (GNUNET_YES == match)
4513 struct GNUNET_TIME_Relative last_timeout;
4515 /* Re-discovered known path, update timeout */
4516 GNUNET_STATISTICS_update (GST_stats,
4517 "# Known DV path refreshed",
4520 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4522 = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4523 GNUNET_CONTAINER_MDLL_remove (dv,
4527 GNUNET_CONTAINER_MDLL_insert (dv,
4531 if (last_timeout.rel_value_us <
4532 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4533 DV_PATH_DISCOVERY_FREQUENCY).rel_value_us)
4535 /* Some peer send DV learn messages too often, we are learning
4536 the same path faster than it would be useful; do not forward! */
4543 /* Count how many shorter paths we have (incl. direct
4544 neighbours) before simply giving up on this one! */
4545 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4547 /* We have a shorter path already! */
4550 /* create new DV path entry */
4551 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4552 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4553 hop->next_hop = next_hop;
4555 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4558 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4559 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4560 hop->distance = path_len - 2;
4561 GNUNET_CONTAINER_MDLL_insert (dv,
4565 GNUNET_CONTAINER_MDLL_insert (neighbour,
4574 * Communicator gave us a DV learn message. Check the message.
4576 * @param cls a `struct CommunicatorMessageContext`
4577 * @param dvl the send message that was sent
4578 * @return #GNUNET_YES if message is well-formed
4581 check_dv_learn (void *cls,
4582 const struct TransportDVLearn *dvl)
4584 uint16_t size = ntohs (dvl->header.size);
4585 uint16_t num_hops = ntohs (dvl->num_hops);
4586 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4589 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4591 GNUNET_break_op (0);
4592 return GNUNET_SYSERR;
4594 if (num_hops > MAX_DV_HOPS_ALLOWED)
4596 GNUNET_break_op (0);
4597 return GNUNET_SYSERR;
4599 for (unsigned int i=0;i<num_hops;i++)
4601 if (0 == GNUNET_memcmp (&dvl->initiator,
4604 GNUNET_break_op (0);
4605 return GNUNET_SYSERR;
4607 if (0 == GNUNET_memcmp (&GST_my_identity,
4610 GNUNET_break_op (0);
4611 return GNUNET_SYSERR;
4619 * Build and forward a DV learn message to @a next_hop.
4621 * @param next_hop peer to send the message to
4622 * @param msg message received
4623 * @param bi_history bitmask specifying hops on path that were bidirectional
4624 * @param nhops length of the @a hops array
4625 * @param hops path the message traversed so far
4626 * @param in_time when did we receive the message, used to calculate network delay
4629 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4630 const struct TransportDVLearn *msg,
4631 uint16_t bi_history,
4633 const struct DVPathEntryP *hops,
4634 struct GNUNET_TIME_Absolute in_time)
4636 struct DVPathEntryP *dhops;
4637 struct TransportDVLearn *fwd;
4638 struct GNUNET_TIME_Relative nnd;
4640 /* compute message for forwarding */
4641 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4642 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4643 (nhops + 1) * sizeof (struct DVPathEntryP));
4644 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4645 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4646 (nhops + 1) * sizeof (struct DVPathEntryP));
4647 fwd->num_hops = htons (nhops + 1);
4648 fwd->bidirectional = htons (bi_history);
4649 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4650 GNUNET_TIME_relative_ntoh (msg->non_network_delay));
4651 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4652 fwd->init_sig = msg->init_sig;
4653 fwd->initiator = msg->initiator;
4654 fwd->challenge = msg->challenge;
4655 dhops = (struct DVPathEntryP *) &fwd[1];
4656 GNUNET_memcpy (dhops,
4658 sizeof (struct DVPathEntryP) * nhops);
4659 dhops[nhops].hop = GST_my_identity;
4661 struct DvHopPS dhp = {
4662 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4663 .purpose.size = htonl (sizeof (dhp)),
4664 .pred = dhops[nhops-1].hop,
4666 .challenge = msg->challenge
4669 GNUNET_assert (GNUNET_OK ==
4670 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4672 &dhops[nhops].hop_sig));
4674 route_message (next_hop,
4680 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4682 * @param init the signer
4683 * @param challenge the challenge that was signed
4684 * @param init_sig signature presumably by @a init
4685 * @return #GNUNET_OK if the signature is valid
4688 validate_dv_initiator_signature (const struct GNUNET_PeerIdentity *init,
4689 const struct GNUNET_ShortHashCode *challenge,
4690 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4692 struct DvInitPS ip = {
4693 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4694 .purpose.size = htonl (sizeof (ip)),
4695 .challenge = *challenge
4699 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4704 GNUNET_break_op (0);
4705 return GNUNET_SYSERR;
4712 * Communicator gave us a DV learn message. Process the request.
4714 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4715 * @param dvl the message that was received
4718 handle_dv_learn (void *cls,
4719 const struct TransportDVLearn *dvl)
4721 struct CommunicatorMessageContext *cmc = cls;
4722 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
4725 uint16_t bi_history;
4726 const struct DVPathEntryP *hops;
4729 struct GNUNET_TIME_Absolute in_time;
4731 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
4732 bi_history = ntohs (dvl->bidirectional);
4733 hops = (const struct DVPathEntryP *) &dvl[1];
4737 if (0 != GNUNET_memcmp (&dvl->initiator,
4741 finish_cmc_handling (cmc);
4748 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop,
4752 finish_cmc_handling (cmc);
4757 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
4758 cc = cmc->tc->details.communicator.cc;
4759 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE == cc); // FIXME: add bi-directional flag to cc?
4760 in_time = GNUNET_TIME_absolute_get ();
4762 /* continue communicator here, everything else can happen asynchronous! */
4763 finish_cmc_handling (cmc);
4765 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
4766 the initiator signature if we send the message back to the initiator... */
4768 validate_dv_initiator_signature (&dvl->initiator,
4772 GNUNET_break_op (0);
4775 // FIXME: asynchronously (!) verify hop-by-hop signatures!
4776 // => if signature verification load too high, implement random drop strategy!?
4778 do_fwd = GNUNET_YES;
4779 if (0 == GNUNET_memcmp (&GST_my_identity,
4782 struct GNUNET_PeerIdentity path[nhops + 1];
4783 struct GNUNET_TIME_Relative host_latency_sum;
4784 struct GNUNET_TIME_Relative latency;
4785 struct GNUNET_TIME_Relative network_latency;
4787 /* We initiated this, learn the forward path! */
4788 path[0] = GST_my_identity;
4789 path[1] = hops[0].hop;
4790 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
4792 // Need also something to lookup initiation time
4793 // to compute RTT! -> add RTT argument here?
4794 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
4795 // (based on dvl->challenge, we can identify time of origin!)
4797 network_latency = GNUNET_TIME_relative_subtract (latency,
4799 /* assumption: latency on all links is the same */
4800 network_latency = GNUNET_TIME_relative_divide (network_latency,
4803 for (unsigned int i=2;i<=nhops;i++)
4805 struct GNUNET_TIME_Relative ilat;
4807 /* assumption: linear latency increase per hop */
4808 ilat = GNUNET_TIME_relative_multiply (network_latency,
4810 path[i] = hops[i-1].hop;
4811 learn_dv_path (path,
4815 /* as we initiated, do not forward again (would be circular!) */
4821 /* last hop was bi-directional, we could learn something here! */
4822 struct GNUNET_PeerIdentity path[nhops + 2];
4824 path[0] = GST_my_identity;
4825 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
4826 for (unsigned int i=0;i<nhops;i++)
4830 if (0 == (bi_history & (1 << i)))
4831 break; /* i-th hop not bi-directional, stop learning! */
4834 path[i + 2] = dvl->initiator;
4838 path[i + 2] = hops[nhops - i - 2].hop;
4841 iret = learn_dv_path (path,
4843 GNUNET_TIME_UNIT_FOREVER_REL);
4844 if (GNUNET_SYSERR == iret)
4846 /* path invalid or too long to be interesting for US, thus should also
4847 not be interesting to our neighbours, cut path when forwarding to
4848 'i' hops, except of course for the one that goes back to the
4850 GNUNET_STATISTICS_update (GST_stats,
4851 "# DV learn not forwarded due invalidity of path",
4857 if ( (GNUNET_NO == iret) &&
4860 /* we have better paths, and this is the longest target,
4861 so there cannot be anything interesting later */
4862 GNUNET_STATISTICS_update (GST_stats,
4863 "# DV learn not forwarded, got better paths",
4872 if (MAX_DV_HOPS_ALLOWED == nhops)
4874 /* At limit, we're out of here! */
4875 finish_cmc_handling (cmc);
4879 /* Forward to initiator, if path non-trivial and possible */
4880 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
4881 did_initiator = GNUNET_NO;
4884 GNUNET_CONTAINER_multipeermap_contains (neighbours,
4887 /* send back to origin! */
4888 forward_dv_learn (&dvl->initiator,
4894 did_initiator = GNUNET_YES;
4896 /* We forward under two conditions: either we still learned something
4897 ourselves (do_fwd), or the path was darn short and thus the initiator is
4898 likely to still be very interested in this (and we did NOT already
4899 send it back to the initiator) */
4901 ( (nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
4902 (GNUNET_NO == did_initiator) ) )
4904 /* FIXME: loop over all neighbours, pick those with low
4905 queues AND that are not yet on the path; possibly
4906 adapt threshold to nhops! */
4908 forward_dv_learn (NULL, // fill in peer from iterator here!
4920 * Communicator gave us a DV box. Check the message.
4922 * @param cls a `struct CommunicatorMessageContext`
4923 * @param dvb the send message that was sent
4924 * @return #GNUNET_YES if message is well-formed
4927 check_dv_box (void *cls,
4928 const struct TransportDVBox *dvb)
4930 uint16_t size = ntohs (dvb->header.size);
4931 uint16_t num_hops = ntohs (dvb->num_hops);
4932 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
4933 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
4938 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct GNUNET_MessageHeader))
4940 GNUNET_break_op (0);
4941 return GNUNET_SYSERR;
4943 isize = ntohs (inbox->size);
4944 if (size != sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
4946 GNUNET_break_op (0);
4947 return GNUNET_SYSERR;
4949 itype = ntohs (inbox->type);
4950 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
4951 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype) )
4953 GNUNET_break_op (0);
4954 return GNUNET_SYSERR;
4957 GNUNET_memcmp (&dvb->origin,
4960 GNUNET_break_op (0);
4961 return GNUNET_SYSERR;
4968 * Create a DV Box message and queue it for transmission to
4971 * @param next_hop peer to receive the message next
4972 * @param total_hops how many hops did the message take so far
4973 * @param num_hops length of the @a hops array
4974 * @param origin origin of the message
4975 * @param hops next peer(s) to the destination, including destination
4976 * @param payload payload of the box
4977 * @param payload_size number of bytes in @a payload
4980 forward_dv_box (struct Neighbour *next_hop,
4981 uint16_t total_hops,
4983 const struct GNUNET_PeerIdentity *origin,
4984 const struct GNUNET_PeerIdentity *hops,
4985 const void *payload,
4986 uint16_t payload_size)
4988 struct TransportDVBox *dvb;
4989 struct GNUNET_PeerIdentity *dhops;
4991 GNUNET_assert (UINT16_MAX <
4992 sizeof (struct TransportDVBox) +
4993 sizeof (struct GNUNET_PeerIdentity) * num_hops +
4995 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
4996 sizeof (struct GNUNET_PeerIdentity) * num_hops +
4998 dvb->header.size = htons (sizeof (struct TransportDVBox) +
4999 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5001 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5002 dvb->total_hops = htons (total_hops);
5003 dvb->num_hops = htons (num_hops);
5004 dvb->origin = *origin;
5005 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5008 num_hops * sizeof (struct GNUNET_PeerIdentity));
5009 memcpy (&dhops[num_hops],
5012 route_message (&next_hop->pid,
5018 * Communicator gave us a DV box. Process the request.
5020 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
5021 * @param dvb the message that was received
5024 handle_dv_box (void *cls,
5025 const struct TransportDVBox *dvb)
5027 struct CommunicatorMessageContext *cmc = cls;
5028 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5029 uint16_t num_hops = ntohs (dvb->num_hops);
5030 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
5031 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
5035 /* We're trying from the end of the hops array, as we may be
5036 able to find a shortcut unknown to the origin that way */
5037 for (int i=num_hops-1;i>=0;i--)
5039 struct Neighbour *n;
5042 GNUNET_memcmp (&hops[i],
5045 GNUNET_break_op (0);
5046 finish_cmc_handling (cmc);
5049 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
5054 ntohs (dvb->total_hops) + 1,
5055 num_hops - i - 1, /* number of hops left */
5057 &hops[i+1], /* remaining hops */
5058 (const void *) &dvb[1],
5060 finish_cmc_handling (cmc);
5063 /* Woopsie, next hop not in neighbours, drop! */
5064 GNUNET_STATISTICS_update (GST_stats,
5065 "# DV Boxes dropped: next hop unknown",
5068 finish_cmc_handling (cmc);
5071 /* We are the target. Unbox and handle message. */
5072 cmc->im.sender = dvb->origin;
5073 cmc->total_hops = ntohs (dvb->total_hops);
5074 demultiplex_with_cmc (cmc,
5080 * Client notified us about transmission from a peer. Process the request.
5082 * @param cls a `struct TransportClient` which sent us the message
5083 * @param obm the send message that was sent
5084 * @return #GNUNET_YES if message is well-formed
5087 check_incoming_msg (void *cls,
5088 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5090 struct TransportClient *tc = cls;
5092 if (CT_COMMUNICATOR != tc->type)
5095 return GNUNET_SYSERR;
5097 GNUNET_MQ_check_boxed_message (im);
5103 * Communicator gave us a transport address validation challenge. Process the request.
5105 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
5106 * @param tvc the message that was received
5109 handle_validation_challenge (void *cls,
5110 const struct TransportValidationChallenge *tvc)
5112 struct CommunicatorMessageContext *cmc = cls;
5113 struct TransportValidationResponse *tvr;
5115 if (cmc->total_hops > 0)
5117 /* DV routing is not allowed for validation challenges! */
5118 GNUNET_break_op (0);
5119 finish_cmc_handling (cmc);
5122 tvr = GNUNET_new (struct TransportValidationResponse);
5123 tvr->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5124 tvr->header.size = htons (sizeof (*tvr));
5125 tvr->challenge = tvc->challenge;
5126 tvr->origin_time = tvc->sender_time;
5127 tvr->validity_duration = cmc->im.expected_address_validity;
5129 /* create signature */
5130 struct TransportValidationPS tvp = {
5131 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5132 .purpose.size = htonl (sizeof (tvp)),
5133 .validity_duration = tvr->validity_duration,
5134 .challenge = tvc->challenge
5137 GNUNET_assert (GNUNET_OK ==
5138 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5142 route_message (&cmc->im.sender,
5144 finish_cmc_handling (cmc);
5149 * Closure for #check_known_challenge.
5151 struct CheckKnownChallengeContext
5154 * Set to the challenge we are looking for.
5156 const struct GNUNET_ShortHashCode *challenge;
5159 * Set to a matching validation state, if one was found.
5161 struct ValidationState *vs;
5166 * Test if the validation state in @a value matches the
5167 * challenge from @a cls.
5169 * @param cls a `struct CheckKnownChallengeContext`
5170 * @param pid unused (must match though)
5171 * @param value a `struct ValidationState`
5172 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5175 check_known_challenge (void *cls,
5176 const struct GNUNET_PeerIdentity *pid,
5179 struct CheckKnownChallengeContext *ckac = cls;
5180 struct ValidationState *vs = value;
5183 if (0 != GNUNET_memcmp (&vs->challenge,
5192 * Function called when peerstore is done storing a
5193 * validated address.
5195 * @param cls a `struct ValidationState`
5196 * @param success #GNUNET_YES on success
5199 peerstore_store_validation_cb (void *cls,
5202 struct ValidationState *vs = cls;
5205 if (GNUNET_YES == success)
5207 GNUNET_STATISTICS_update (GST_stats,
5208 "# Peerstore failed to store foreign address",
5215 * Task run periodically to validate some address based on #validation_heap.
5220 validation_start_cb (void *cls);
5224 * Set the time for next_challenge of @a vs to @a new_time.
5225 * Updates the heap and if necessary reschedules the job.
5227 * @param vs validation state to update
5228 * @param new_time new time for revalidation
5231 update_next_challenge_time (struct ValidationState *vs,
5232 struct GNUNET_TIME_Absolute new_time)
5234 struct GNUNET_TIME_Relative delta;
5236 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5237 return; /* be lazy */
5238 vs->next_challenge = new_time;
5240 vs->hn = GNUNET_CONTAINER_heap_insert (validation_heap,
5242 new_time.abs_value_us);
5244 GNUNET_CONTAINER_heap_update_cost (vs->hn,
5245 new_time.abs_value_us);
5246 if ( (vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5247 (NULL != validation_task) )
5249 if (NULL != validation_task)
5250 GNUNET_SCHEDULER_cancel (validation_task);
5251 /* randomize a bit */
5252 delta.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5253 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5254 new_time = GNUNET_TIME_absolute_add (new_time,
5256 validation_task = GNUNET_SCHEDULER_add_at (new_time,
5257 &validation_start_cb,
5263 * Communicator gave us a transport address validation response. Process the request.
5265 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
5266 * @param tvr the message that was received
5269 handle_validation_response (void *cls,
5270 const struct TransportValidationResponse *tvr)
5272 struct CommunicatorMessageContext *cmc = cls;
5273 struct ValidationState *vs;
5274 struct CheckKnownChallengeContext ckac = {
5275 .challenge = &tvr->challenge,
5278 struct GNUNET_TIME_Absolute origin_time;
5280 /* check this is one of our challenges */
5281 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5283 &check_known_challenge,
5285 if (NULL == (vs = ckac.vs))
5287 /* This can happen simply if we 'forgot' the challenge by now,
5288 i.e. because we received the validation response twice */
5289 GNUNET_STATISTICS_update (GST_stats,
5290 "# Validations dropped, challenge unknown",
5293 finish_cmc_handling (cmc);
5297 /* sanity check on origin time */
5298 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
5299 if ( (origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
5300 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us) )
5302 GNUNET_break_op (0);
5303 finish_cmc_handling (cmc);
5308 /* check signature */
5309 struct TransportValidationPS tvp = {
5310 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5311 .purpose.size = htonl (sizeof (tvp)),
5312 .validity_duration = tvr->validity_duration,
5313 .challenge = tvr->challenge
5317 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
5320 &cmc->im.sender.public_key))
5322 GNUNET_break_op (0);
5323 finish_cmc_handling (cmc);
5328 /* validity is capped by our willingness to keep track of the
5329 validation entry and the maximum the other peer allows */
5331 = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (tvr->validity_duration),
5332 MAX_ADDRESS_VALID_UNTIL));
5334 = GNUNET_TIME_absolute_min (vs->valid_until,
5335 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME));
5336 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
5337 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
5338 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5340 sizeof (vs->challenge));
5341 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (vs->validated_until,
5342 GNUNET_TIME_relative_multiply (vs->validation_rtt,
5343 VALIDATION_RTT_BUFFER_FACTOR));
5344 vs->last_challenge_use = GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
5345 update_next_challenge_time (vs,
5346 vs->first_challenge_use);
5347 vs->sc = GNUNET_PEERSTORE_store (peerstore,
5350 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
5352 strlen (vs->address) + 1,
5354 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5355 &peerstore_store_validation_cb,
5357 // FIXME: should we find the matching queue and update the RTT?
5358 finish_cmc_handling (cmc);
5363 * Incoming meessage. Process the request.
5365 * @param im the send message that was received
5368 handle_incoming_msg (void *cls,
5369 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5371 struct TransportClient *tc = cls;
5372 struct CommunicatorMessageContext *cmc = GNUNET_new (struct CommunicatorMessageContext);
5376 demultiplex_with_cmc (cmc,
5377 (const struct GNUNET_MessageHeader *) &im[1]);
5382 * Given an inbound message @a msg from a communicator @a cmc,
5383 * demultiplex it based on the type calling the right handler.
5385 * @param cmc context for demultiplexing
5386 * @param msg message to demultiplex
5389 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5390 const struct GNUNET_MessageHeader *msg)
5392 struct GNUNET_MQ_MessageHandler handlers[] = {
5393 GNUNET_MQ_hd_var_size (fragment_box,
5394 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
5395 struct TransportFragmentBox,
5397 GNUNET_MQ_hd_fixed_size (fragment_ack,
5398 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
5399 struct TransportFragmentAckMessage,
5401 GNUNET_MQ_hd_var_size (reliability_box,
5402 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5403 struct TransportReliabilityBox,
5405 GNUNET_MQ_hd_fixed_size (reliability_ack,
5406 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5407 struct TransportReliabilityAckMessage,
5409 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5410 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5411 struct TransportBackchannelEncapsulationMessage,
5413 GNUNET_MQ_hd_var_size (dv_learn,
5414 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5415 struct TransportDVLearn,
5417 GNUNET_MQ_hd_var_size (dv_box,
5418 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5419 struct TransportDVBox,
5421 GNUNET_MQ_hd_fixed_size (validation_challenge,
5422 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5423 struct TransportValidationChallenge,
5425 GNUNET_MQ_hd_fixed_size (validation_response,
5426 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5427 struct TransportValidationResponse,
5429 GNUNET_MQ_handler_end()
5433 ret = GNUNET_MQ_handle_message (handlers,
5435 if (GNUNET_SYSERR == ret)
5438 GNUNET_SERVICE_client_drop (cmc->tc->client);
5442 if (GNUNET_NO == ret)
5444 /* unencapsulated 'raw' message */
5445 handle_raw_message (&cmc,
5452 * New queue became available. Check message.
5454 * @param cls the client
5455 * @param aqm the send message that was sent
5458 check_add_queue_message (void *cls,
5459 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5461 struct TransportClient *tc = cls;
5463 if (CT_COMMUNICATOR != tc->type)
5466 return GNUNET_SYSERR;
5468 GNUNET_MQ_check_zero_termination (aqm);
5474 * Bandwidth tracker informs us that the delay until we should receive
5477 * @param cls a `struct Queue` for which the delay changed
5480 tracker_update_in_cb (void *cls)
5482 struct Queue *queue = cls;
5483 struct GNUNET_TIME_Relative in_delay;
5486 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5487 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in,
5489 // FIXME: how exactly do we do inbound flow control?
5494 * If necessary, generates the UUID for a @a pm
5496 * @param pm pending message to generate UUID for.
5499 set_pending_message_uuid (struct PendingMessage *pm)
5501 if (pm->msg_uuid_set)
5503 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5505 sizeof (pm->msg_uuid));
5506 pm->msg_uuid_set = GNUNET_YES;
5511 * Fragment the given @a pm to the given @a mtu. Adds
5512 * additional fragments to the neighbour as well. If the
5513 * @a mtu is too small, generates and error for the @a pm
5516 * @param pm pending message to fragment for transmission
5517 * @param mtu MTU to apply
5518 * @return new message to transmit
5520 static struct PendingMessage *
5521 fragment_message (struct PendingMessage *pm,
5524 struct PendingMessage *ff;
5526 set_pending_message_uuid (pm);
5528 /* This invariant is established in #handle_add_queue_message() */
5529 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5531 /* select fragment for transmission, descending the tree if it has
5532 been expanded until we are at a leaf or at a fragment that is small enough */
5534 while ( ( (ff->bytes_msg > mtu) ||
5536 (ff->frag_off == ff->bytes_msg) &&
5537 (NULL != ff->head_frag) )
5539 ff = ff->head_frag; /* descent into fragmented fragments */
5542 if ( ( (ff->bytes_msg > mtu) ||
5544 (pm->frag_off < pm->bytes_msg) )
5546 /* Did not yet calculate all fragments, calculate next fragment */
5547 struct PendingMessage *frag;
5548 struct TransportFragmentBox tfb;
5556 orig = (const char *) &ff[1];
5557 msize = ff->bytes_msg;
5560 const struct TransportFragmentBox *tfbo;
5562 tfbo = (const struct TransportFragmentBox *) orig;
5563 orig += sizeof (struct TransportFragmentBox);
5564 msize -= sizeof (struct TransportFragmentBox);
5565 xoff = ntohs (tfbo->frag_off);
5567 fragmax = mtu - sizeof (struct TransportFragmentBox);
5568 fragsize = GNUNET_MIN (msize - ff->frag_off,
5570 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5571 sizeof (struct TransportFragmentBox) +
5573 frag->target = pm->target;
5574 frag->frag_parent = ff;
5575 frag->timeout = pm->timeout;
5576 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5577 frag->pmt = PMT_FRAGMENT_BOX;
5578 msg = (char *) &frag[1];
5579 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
5580 tfb.header.size = htons (sizeof (struct TransportFragmentBox) +
5582 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
5583 tfb.msg_uuid = pm->msg_uuid;
5584 tfb.frag_off = htons (ff->frag_off + xoff);
5585 tfb.msg_size = htons (pm->bytes_msg);
5589 memcpy (&msg[sizeof (tfb)],
5590 &orig[ff->frag_off],
5592 GNUNET_CONTAINER_MDLL_insert (frag,
5596 ff->frag_off += fragsize;
5600 /* Move head to the tail and return it */
5601 GNUNET_CONTAINER_MDLL_remove (frag,
5602 ff->frag_parent->head_frag,
5603 ff->frag_parent->tail_frag,
5605 GNUNET_CONTAINER_MDLL_insert_tail (frag,
5606 ff->frag_parent->head_frag,
5607 ff->frag_parent->tail_frag,
5614 * Reliability-box the given @a pm. On error (can there be any), NULL
5615 * may be returned, otherwise the "replacement" for @a pm (which
5616 * should then be added to the respective neighbour's queue instead of
5617 * @a pm). If the @a pm is already fragmented or reliability boxed,
5618 * or itself an ACK, this function simply returns @a pm.
5620 * @param pm pending message to box for transmission over unreliabile queue
5621 * @return new message to transmit
5623 static struct PendingMessage *
5624 reliability_box_message (struct PendingMessage *pm)
5626 struct TransportReliabilityBox rbox;
5627 struct PendingMessage *bpm;
5630 if (PMT_CORE != pm->pmt)
5631 return pm; /* already fragmented or reliability boxed, or control message: do nothing */
5632 if (NULL != pm->bpm)
5633 return pm->bpm; /* already computed earlier: do nothing */
5634 GNUNET_assert (NULL == pm->head_frag);
5635 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
5639 client_send_response (pm,
5644 bpm = GNUNET_malloc (sizeof (struct PendingMessage) +
5647 bpm->target = pm->target;
5648 bpm->frag_parent = pm;
5649 GNUNET_CONTAINER_MDLL_insert (frag,
5653 bpm->timeout = pm->timeout;
5654 bpm->pmt = PMT_RELIABILITY_BOX;
5655 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
5656 set_pending_message_uuid (bpm);
5657 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
5658 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
5659 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
5660 rbox.msg_uuid = pm->msg_uuid;
5661 msg = (char *) &bpm[1];
5665 memcpy (&msg[sizeof (rbox)],
5674 * We believe we are ready to transmit a message on a queue. Double-checks
5675 * with the queue's "tracker_out" and then gives the message to the
5676 * communicator for transmission (updating the tracker, and re-scheduling
5677 * itself if applicable).
5679 * @param cls the `struct Queue` to process transmissions for
5682 transmit_on_queue (void *cls)
5684 struct Queue *queue = cls;
5685 struct Neighbour *n = queue->neighbour;
5686 struct PendingMessage *pm;
5687 struct PendingMessage *s;
5689 struct GNUNET_TRANSPORT_SendMessageTo *smt;
5690 struct GNUNET_MQ_Envelope *env;
5692 queue->transmit_task = NULL;
5693 if (NULL == (pm = n->pending_msg_head))
5695 /* no message pending, nothing to do here! */
5698 schedule_transmit_on_queue (queue);
5699 if (NULL != queue->transmit_task)
5700 return; /* do it later */
5702 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5703 overhead += sizeof (struct TransportReliabilityBox);
5705 if ( ( (0 != queue->mtu) &&
5706 (pm->bytes_msg + overhead > queue->mtu) ) ||
5707 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
5708 (NULL != pm->head_frag /* fragments already exist, should
5709 respect that even if MTU is 0 for
5711 s = fragment_message (s,
5713 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
5717 /* Fragmentation failed, try next message... */
5718 schedule_transmit_on_queue (queue);
5721 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5722 s = reliability_box_message (s);
5725 /* Reliability boxing failed, try next message... */
5726 schedule_transmit_on_queue (queue);
5730 /* Pass 's' for transission to the communicator */
5731 env = GNUNET_MQ_msg_extra (smt,
5733 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
5734 smt->qid = queue->qid;
5735 smt->mid = queue->mid_gen;
5736 smt->receiver = n->pid;
5741 /* Pass the env to the communicator of queue for transmission. */
5742 struct QueueEntry *qe;
5744 qe = GNUNET_new (struct QueueEntry);
5745 qe->mid = queue->mid_gen++;
5747 // qe->pm = s; // FIXME: not so easy, reference management on 'free(s)'!
5748 GNUNET_CONTAINER_DLL_insert (queue->queue_head,
5751 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5752 queue->queue_length++;
5753 queue->tc->details.communicator.total_queue_length++;
5754 GNUNET_MQ_send (queue->tc->mq,
5758 // FIXME: do something similar to the logic below
5759 // in defragmentation / reliability ACK handling!
5761 /* Check if this transmission somehow conclusively finished handing 'pm'
5762 even without any explicit ACKs */
5763 if ( (PMT_CORE == s->pmt) &&
5764 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) )
5766 /* Full message sent, and over reliabile channel */
5767 client_send_response (pm,
5771 else if ( (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) &&
5772 (PMT_FRAGMENT_BOX == s->pmt) )
5774 struct PendingMessage *pos;
5776 /* Fragment sent over reliabile channel */
5777 free_fragment_tree (s);
5778 pos = s->frag_parent;
5779 GNUNET_CONTAINER_MDLL_remove (frag,
5784 /* check if subtree is done */
5785 while ( (NULL == pos->head_frag) &&
5786 (pos->frag_off == pos->bytes_msg) &&
5790 pos = s->frag_parent;
5791 GNUNET_CONTAINER_MDLL_remove (frag,
5798 /* Was this the last applicable fragmment? */
5799 if ( (NULL == pm->head_frag) &&
5800 (pm->frag_off == pm->bytes_msg) )
5801 client_send_response (pm,
5803 pm->bytes_msg /* FIXME: calculate and add overheads! */);
5805 else if (PMT_CORE != pm->pmt)
5807 /* This was an acknowledgement of some type, always free */
5808 free_pending_message (pm);
5812 /* message not finished, waiting for acknowledgement */
5813 struct Neighbour *neighbour = pm->target;
5814 /* Update time by which we might retransmit 's' based on queue
5815 characteristics (i.e. RTT); it takes one RTT for the message to
5816 arrive and the ACK to come back in the best case; but the other
5817 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
5818 retransmitting. Note that in the future this heuristic should
5819 likely be improved further (measure RTT stability, consider
5820 message urgency and size when delaying ACKs, etc.) */
5821 s->next_attempt = GNUNET_TIME_relative_to_absolute
5822 (GNUNET_TIME_relative_multiply (queue->rtt,
5826 struct PendingMessage *pos;
5828 /* re-insert sort in neighbour list */
5829 GNUNET_CONTAINER_MDLL_remove (neighbour,
5830 neighbour->pending_msg_head,
5831 neighbour->pending_msg_tail,
5833 pos = neighbour->pending_msg_tail;
5834 while ( (NULL != pos) &&
5835 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5836 pos = pos->prev_neighbour;
5837 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
5838 neighbour->pending_msg_head,
5839 neighbour->pending_msg_tail,
5845 /* re-insert sort in fragment list */
5846 struct PendingMessage *fp = s->frag_parent;
5847 struct PendingMessage *pos;
5849 GNUNET_CONTAINER_MDLL_remove (frag,
5853 pos = fp->tail_frag;
5854 while ( (NULL != pos) &&
5855 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5856 pos = pos->prev_frag;
5857 GNUNET_CONTAINER_MDLL_insert_after (frag,
5865 /* finally, re-schedule queue transmission task itself */
5866 schedule_transmit_on_queue (queue);
5871 * Bandwidth tracker informs us that the delay until we
5872 * can transmit again changed.
5874 * @param cls a `struct Queue` for which the delay changed
5877 tracker_update_out_cb (void *cls)
5879 struct Queue *queue = cls;
5880 struct Neighbour *n = queue->neighbour;
5882 if (NULL == n->pending_msg_head)
5884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5885 "Bandwidth allocation updated for empty transmission queue `%s'\n",
5887 return; /* no message pending, nothing to do here! */
5889 GNUNET_SCHEDULER_cancel (queue->transmit_task);
5890 queue->transmit_task = NULL;
5891 schedule_transmit_on_queue (queue);
5896 * Bandwidth tracker informs us that excessive outbound bandwidth was
5897 * allocated which is not being used.
5899 * @param cls a `struct Queue` for which the excess was noted
5902 tracker_excess_out_cb (void *cls)
5906 /* FIXME: trigger excess bandwidth report to core? Right now,
5907 this is done internally within transport_api2_core already,
5908 but we probably want to change the logic and trigger it
5909 from here via a message instead! */
5910 /* TODO: maybe inform someone at this point? */
5911 GNUNET_STATISTICS_update (GST_stats,
5912 "# Excess outbound bandwidth reported",
5920 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
5921 * which is not being used.
5923 * @param cls a `struct Queue` for which the excess was noted
5926 tracker_excess_in_cb (void *cls)
5930 /* TODO: maybe inform somone at this point? */
5931 GNUNET_STATISTICS_update (GST_stats,
5932 "# Excess inbound bandwidth reported",
5939 * Queue to a peer went down. Process the request.
5941 * @param cls the client
5942 * @param dqm the send message that was sent
5945 handle_del_queue_message (void *cls,
5946 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
5948 struct TransportClient *tc = cls;
5950 if (CT_COMMUNICATOR != tc->type)
5953 GNUNET_SERVICE_client_drop (tc->client);
5956 for (struct Queue *queue = tc->details.communicator.queue_head;
5958 queue = queue->next_client)
5960 struct Neighbour *neighbour = queue->neighbour;
5962 if ( (dqm->qid != queue->qid) ||
5963 (0 != GNUNET_memcmp (&dqm->receiver,
5967 GNUNET_SERVICE_client_continue (tc->client);
5971 GNUNET_SERVICE_client_drop (tc->client);
5976 * Message was transmitted. Process the request.
5978 * @param cls the client
5979 * @param sma the send message that was sent
5982 handle_send_message_ack (void *cls,
5983 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
5985 struct TransportClient *tc = cls;
5986 struct QueueEntry *qe;
5988 if (CT_COMMUNICATOR != tc->type)
5991 GNUNET_SERVICE_client_drop (tc->client);
5995 /* find our queue entry matching the ACK */
5997 for (struct Queue *queue = tc->details.communicator.queue_head;
5999 queue = queue->next_client)
6001 if (0 != GNUNET_memcmp (&queue->neighbour->pid,
6004 for (struct QueueEntry *qep = queue->queue_head;
6008 if (qep->mid != sma->mid)
6017 /* this should never happen */
6019 GNUNET_SERVICE_client_drop (tc->client);
6022 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6023 qe->queue->queue_tail,
6025 qe->queue->queue_length--;
6026 tc->details.communicator.total_queue_length--;
6027 GNUNET_SERVICE_client_continue (tc->client);
6029 /* if applicable, resume transmissions that waited on ACK */
6030 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 == tc->details.communicator.total_queue_length)
6032 /* Communicator dropped below threshold, resume all queues */
6033 GNUNET_STATISTICS_update (GST_stats,
6034 "# Transmission throttled due to communicator queue limit",
6037 for (struct Queue *queue = tc->details.communicator.queue_head;
6039 queue = queue->next_client)
6040 schedule_transmit_on_queue (queue);
6042 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6044 /* queue dropped below threshold; only resume this one queue */
6045 GNUNET_STATISTICS_update (GST_stats,
6046 "# Transmission throttled due to queue queue limit",
6049 schedule_transmit_on_queue (qe->queue);
6052 /* TODO: we also should react on the status! */
6053 // FIXME: this probably requires queue->pm = s assignment!
6054 // FIXME: react to communicator status about transmission request. We got:
6055 sma->status; // OK success, SYSERR failure
6062 * Iterator telling new MONITOR client about all existing
6065 * @param cls the new `struct TransportClient`
6066 * @param pid a connected peer
6067 * @param value the `struct Neighbour` with more information
6068 * @return #GNUNET_OK (continue to iterate)
6071 notify_client_queues (void *cls,
6072 const struct GNUNET_PeerIdentity *pid,
6075 struct TransportClient *tc = cls;
6076 struct Neighbour *neighbour = value;
6078 GNUNET_assert (CT_MONITOR == tc->type);
6079 for (struct Queue *q = neighbour->queue_head;
6081 q = q->next_neighbour)
6083 struct MonitorEvent me = {
6086 .num_msg_pending = q->num_msg_pending,
6087 .num_bytes_pending = q->num_bytes_pending
6101 * Initialize a monitor client.
6103 * @param cls the client
6104 * @param start the start message that was sent
6107 handle_monitor_start (void *cls,
6108 const struct GNUNET_TRANSPORT_MonitorStart *start)
6110 struct TransportClient *tc = cls;
6112 if (CT_NONE != tc->type)
6115 GNUNET_SERVICE_client_drop (tc->client);
6118 tc->type = CT_MONITOR;
6119 tc->details.monitor.peer = start->peer;
6120 tc->details.monitor.one_shot = ntohl (start->one_shot);
6121 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6122 ¬ify_client_queues,
6124 GNUNET_SERVICE_client_mark_monitor (tc->client);
6125 GNUNET_SERVICE_client_continue (tc->client);
6130 * Find transport client providing communication service
6131 * for the protocol @a prefix.
6133 * @param prefix communicator name
6134 * @return NULL if no such transport client is available
6136 static struct TransportClient *
6137 lookup_communicator (const char *prefix)
6139 for (struct TransportClient *tc = clients_head;
6143 if (CT_COMMUNICATOR != tc->type)
6145 if (0 == strcmp (prefix,
6146 tc->details.communicator.address_prefix))
6149 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6150 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6157 * Signature of a function called with a communicator @a address of a peer
6158 * @a pid that an application wants us to connect to.
6160 * @param pid target peer
6161 * @param address the address to try
6164 suggest_to_connect (const struct GNUNET_PeerIdentity *pid,
6165 const char *address)
6167 static uint32_t idgen;
6168 struct TransportClient *tc;
6170 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6171 struct GNUNET_MQ_Envelope *env;
6174 prefix = GNUNET_HELLO_address_to_prefix (address);
6177 GNUNET_break (0); /* We got an invalid address!? */
6180 tc = lookup_communicator (prefix);
6183 GNUNET_STATISTICS_update (GST_stats,
6184 "# Suggestions ignored due to missing communicator",
6189 /* forward suggestion for queue creation to communicator */
6190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6191 "Request #%u for `%s' communicator to create queue to `%s'\n",
6192 (unsigned int) idgen,
6195 alen = strlen (address) + 1;
6196 env = GNUNET_MQ_msg_extra (cqm,
6198 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6199 cqm->request_id = htonl (idgen++);
6200 cqm->receiver = *pid;
6204 GNUNET_MQ_send (tc->mq,
6210 * The queue @a q (which matches the peer and address in @a vs) is
6211 * ready for queueing. We should now queue the validation request.
6213 * @param q queue to send on
6214 * @param vs state to derive validation challenge from
6217 validation_transmit_on_queue (struct Queue *q,
6218 struct ValidationState *vs)
6220 struct GNUNET_MQ_Envelope *env;
6221 struct TransportValidationChallenge *tvc;
6223 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6224 env = GNUNET_MQ_msg (tvc,
6225 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6226 tvc->reserved = htonl (0);
6227 tvc->challenge = vs->challenge;
6228 tvc->sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6229 // FIXME: not so easy, need to BOX this message
6230 // in a transmission request! (mistake also done elsewhere!)
6231 GNUNET_MQ_send (q->tc->mq,
6237 * Task run periodically to validate some address based on #validation_heap.
6242 validation_start_cb (void *cls)
6244 struct ValidationState *vs;
6245 struct Neighbour *n;
6249 validation_task = NULL;
6250 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6251 /* drop validations past their expiration */
6252 while ( (NULL != vs) &&
6253 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us) )
6255 free_validation_state (vs);
6256 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6259 return; /* woopsie, no more addresses known, should only
6260 happen if we're really a lonely peer */
6261 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
6266 for (struct Queue *pos = n->queue_head;
6268 pos = pos->next_neighbour)
6270 if (0 == strcmp (pos->address,
6280 vs->awaiting_queue = GNUNET_YES;
6281 suggest_to_connect (&vs->pid,
6285 validation_transmit_on_queue (q,
6287 /* Finally, reschedule next attempt */
6288 vs->challenge_backoff = GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
6289 MAX_VALIDATION_CHALLENGE_FREQ);
6290 update_next_challenge_time (vs,
6291 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
6296 * Closure for #check_connection_quality.
6298 struct QueueQualityContext
6301 * Set to the @e k'th queue encountered.
6306 * Set to the number of quality queues encountered.
6308 unsigned int quality_count;
6311 * Set to the total number of queues encountered.
6313 unsigned int num_queues;
6316 * Decremented for each queue, for selection of the
6317 * k-th queue in @e q.
6325 * Check whether any queue to the given neighbour is
6326 * of a good "quality" and if so, increment the counter.
6327 * Also counts the total number of queues, and returns
6328 * the k-th queue found.
6330 * @param cls a `struct QueueQualityContext *` with counters
6331 * @param pid peer this is about
6332 * @param value a `struct Neighbour`
6333 * @return #GNUNET_OK (continue to iterate)
6336 check_connection_quality (void *cls,
6337 const struct GNUNET_PeerIdentity *pid,
6340 struct QueueQualityContext *ctx = cls;
6341 struct Neighbour *n = value;
6346 for (struct Queue *q = n->queue_head;
6348 q = q->next_neighbour)
6350 if (0 != q->distance)
6351 continue; /* DV does not count */
6355 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
6356 statistics and consider those as well here? */
6357 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
6358 do_inc = GNUNET_YES;
6360 if (GNUNET_YES == do_inc)
6361 ctx->quality_count++;
6367 * Task run when we CONSIDER initiating a DV learn
6368 * process. We first check that sending out a message is
6369 * even possible (queues exist), then that it is desirable
6370 * (if not, reschedule the task for later), and finally
6371 * we may then begin the job. If there are too many
6372 * entries in the #dvlearn_map, we purge the oldest entry
6378 start_dv_learn (void *cls)
6380 struct LearnLaunchEntry *lle;
6381 struct QueueQualityContext qqc;
6382 struct GNUNET_MQ_Envelope *env;
6383 struct TransportDVLearn *dvl;
6386 dvlearn_task = NULL;
6388 GNUNET_CONTAINER_multipeermap_size (neighbours))
6389 return; /* lost all connectivity, cannot do learning */
6390 qqc.quality_count = 0;
6392 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6393 &check_connection_quality,
6395 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
6397 struct GNUNET_TIME_Relative delay;
6398 unsigned int factor;
6400 /* scale our retries by how far we are above the threshold */
6401 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6402 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY,
6404 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay,
6409 /* remove old entries in #dvlearn_map if it has grown too big */
6410 while (MAX_DV_LEARN_PENDING >=
6411 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6414 GNUNET_assert (GNUNET_YES ==
6415 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6418 GNUNET_CONTAINER_DLL_remove (lle_head,
6423 /* setup data structure for learning */
6424 lle = GNUNET_new (struct LearnLaunchEntry);
6425 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6427 sizeof (lle->challenge));
6428 GNUNET_CONTAINER_DLL_insert (lle_head,
6431 GNUNET_break (GNUNET_YES ==
6432 GNUNET_CONTAINER_multishortmap_put (dvlearn_map,
6435 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6436 env = GNUNET_MQ_msg (dvl,
6437 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6438 dvl->num_hops = htons (0);
6439 dvl->bidirectional = htons (0);
6440 dvl->non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6442 struct DvInitPS dvip = {
6443 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6444 .purpose.size = htonl (sizeof (dvip)),
6445 .challenge = lle->challenge
6448 GNUNET_assert (GNUNET_OK ==
6449 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6453 dvl->initiator = GST_my_identity;
6454 dvl->challenge = lle->challenge;
6456 qqc.quality_count = 0;
6457 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
6461 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6462 &check_connection_quality,
6464 GNUNET_assert (NULL != qqc.q);
6466 /* Do this as close to transmission time as possible! */
6467 lle->launch_time = GNUNET_TIME_absolute_get ();
6468 // FIXME: not so easy, need to BOX this message
6469 // in a transmission request! (mistake also done elsewhere!)
6470 GNUNET_MQ_send (qqc.q->tc->mq,
6473 /* reschedule this job, randomizing the time it runs (but no
6476 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (DV_LEARN_BASE_FREQUENCY),
6483 * A new queue has been created, check if any address validation
6484 * requests have been waiting for it.
6486 * @param cls a `struct Queue`
6487 * @param pid peer concerned (unused)
6488 * @param value a `struct ValidationState`
6489 * @return #GNUNET_NO if a match was found and we can stop looking
6492 check_validation_request_pending (void *cls,
6493 const struct GNUNET_PeerIdentity *pid,
6496 struct Queue *q = cls;
6497 struct ValidationState *vs = value;
6500 if ( (GNUNET_YES == vs->awaiting_queue) &&
6501 (0 == strcmp (vs->address,
6504 vs->awaiting_queue = GNUNET_NO;
6505 validation_transmit_on_queue (q,
6514 * New queue became available. Process the request.
6516 * @param cls the client
6517 * @param aqm the send message that was sent
6520 handle_add_queue_message (void *cls,
6521 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6523 struct TransportClient *tc = cls;
6524 struct Queue *queue;
6525 struct Neighbour *neighbour;
6529 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6531 /* MTU so small as to be useless for transmissions,
6532 required for #fragment_message()! */
6533 GNUNET_break_op (0);
6534 GNUNET_SERVICE_client_drop (tc->client);
6537 neighbour = lookup_neighbour (&aqm->receiver);
6538 if (NULL == neighbour)
6540 neighbour = GNUNET_new (struct Neighbour);
6541 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6542 neighbour->pid = aqm->receiver;
6543 GNUNET_assert (GNUNET_OK ==
6544 GNUNET_CONTAINER_multipeermap_put (neighbours,
6547 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6548 cores_send_connect_info (&neighbour->pid,
6549 GNUNET_BANDWIDTH_ZERO);
6551 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6552 addr = (const char *) &aqm[1];
6554 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6556 queue->address = (const char *) &queue[1];
6557 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6558 queue->qid = aqm->qid;
6559 queue->mtu = ntohl (aqm->mtu);
6560 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6561 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6562 queue->neighbour = neighbour;
6563 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6564 &tracker_update_in_cb,
6566 GNUNET_BANDWIDTH_ZERO,
6567 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6568 &tracker_excess_in_cb,
6570 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6571 &tracker_update_out_cb,
6573 GNUNET_BANDWIDTH_ZERO,
6574 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6575 &tracker_excess_out_cb,
6580 /* notify monitors about new queue */
6582 struct MonitorEvent me = {
6587 notify_monitors (&neighbour->pid,
6592 GNUNET_CONTAINER_MDLL_insert (neighbour,
6593 neighbour->queue_head,
6594 neighbour->queue_tail,
6596 GNUNET_CONTAINER_MDLL_insert (client,
6597 tc->details.communicator.queue_head,
6598 tc->details.communicator.queue_tail,
6600 /* check if valdiations are waiting for the queue */
6601 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6603 &check_validation_request_pending,
6605 /* might be our first queue, try launching DV learning */
6606 if (NULL == dvlearn_task)
6607 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn,
6609 GNUNET_SERVICE_client_continue (tc->client);
6614 * Communicator tells us that our request to create a queue "worked", that
6615 * is setting up the queue is now in process.
6617 * @param cls the `struct TransportClient`
6618 * @param cqr confirmation message
6621 handle_queue_create_ok (void *cls,
6622 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6624 struct TransportClient *tc = cls;
6626 if (CT_COMMUNICATOR != tc->type)
6629 GNUNET_SERVICE_client_drop (tc->client);
6632 GNUNET_STATISTICS_update (GST_stats,
6633 "# Suggestions succeeded at communicator",
6636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6637 "Request #%u for communicator to create queue succeeded\n",
6638 (unsigned int) ntohs (cqr->request_id));
6639 GNUNET_SERVICE_client_continue (tc->client);
6644 * Communicator tells us that our request to create a queue failed. This usually
6645 * indicates that the provided address is simply invalid or that the communicator's
6646 * resources are exhausted.
6648 * @param cls the `struct TransportClient`
6649 * @param cqr failure message
6652 handle_queue_create_fail (void *cls,
6653 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6655 struct TransportClient *tc = cls;
6657 if (CT_COMMUNICATOR != tc->type)
6660 GNUNET_SERVICE_client_drop (tc->client);
6663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6664 "Request #%u for communicator to create queue failed\n",
6665 (unsigned int) ntohs (cqr->request_id));
6666 GNUNET_STATISTICS_update (GST_stats,
6667 "# Suggestions failed in queue creation at communicator",
6670 GNUNET_SERVICE_client_continue (tc->client);
6675 * We have received a `struct ExpressPreferenceMessage` from an application client.
6677 * @param cls handle to the client
6678 * @param msg the start message
6681 handle_suggest_cancel (void *cls,
6682 const struct ExpressPreferenceMessage *msg)
6684 struct TransportClient *tc = cls;
6685 struct PeerRequest *pr;
6687 if (CT_APPLICATION != tc->type)
6690 GNUNET_SERVICE_client_drop (tc->client);
6693 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
6698 GNUNET_SERVICE_client_drop (tc->client);
6701 (void) stop_peer_request (tc,
6704 GNUNET_SERVICE_client_continue (tc->client);
6709 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
6710 * messages. We do nothing here, real verification is done later.
6712 * @param cls a `struct TransportClient *`
6713 * @param msg message to verify
6714 * @return #GNUNET_OK
6717 check_address_consider_verify (void *cls,
6718 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6727 * Closure for #check_known_address.
6729 struct CheckKnownAddressContext
6732 * Set to the address we are looking for.
6734 const char *address;
6737 * Set to a matching validation state, if one was found.
6739 struct ValidationState *vs;
6744 * Test if the validation state in @a value matches the
6745 * address from @a cls.
6747 * @param cls a `struct CheckKnownAddressContext`
6748 * @param pid unused (must match though)
6749 * @param value a `struct ValidationState`
6750 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6753 check_known_address (void *cls,
6754 const struct GNUNET_PeerIdentity *pid,
6757 struct CheckKnownAddressContext *ckac = cls;
6758 struct ValidationState *vs = value;
6761 if (0 != strcmp (vs->address,
6770 * Start address validation.
6772 * @param pid peer the @a address is for
6773 * @param address an address to reach @a pid (presumably)
6774 * @param expiration when did @a pid claim @a address will become invalid
6777 start_address_validation (const struct GNUNET_PeerIdentity *pid,
6778 const char *address,
6779 struct GNUNET_TIME_Absolute expiration)
6781 struct GNUNET_TIME_Absolute now;
6782 struct ValidationState *vs;
6783 struct CheckKnownAddressContext ckac = {
6788 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
6789 return; /* expired */
6790 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6792 &check_known_address,
6794 if (NULL != (vs = ckac.vs))
6796 /* if 'vs' is not currently valid, we need to speed up retrying the validation */
6797 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
6799 /* reduce backoff as we got a fresh advertisement */
6800 vs->challenge_backoff = GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
6801 GNUNET_TIME_relative_divide (vs->challenge_backoff,
6803 update_next_challenge_time (vs,
6804 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
6808 now = GNUNET_TIME_absolute_get();
6809 vs = GNUNET_new (struct ValidationState);
6811 vs->valid_until = expiration;
6812 vs->first_challenge_use = now;
6813 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6814 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6816 sizeof (vs->challenge));
6817 vs->address = GNUNET_strdup (address);
6818 GNUNET_assert (GNUNET_YES ==
6819 GNUNET_CONTAINER_multipeermap_put (validation_map,
6822 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6823 update_next_challenge_time (vs,
6829 * Function called by PEERSTORE for each matching record.
6831 * @param cls closure
6832 * @param record peerstore record information
6833 * @param emsg error message, or NULL if no errors
6836 handle_hello (void *cls,
6837 const struct GNUNET_PEERSTORE_Record *record,
6840 struct PeerRequest *pr = cls;
6845 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6846 "Got failure from PEERSTORE: %s\n",
6850 val = record->value;
6851 if ( (0 == record->value_size) ||
6852 ('\0' != val[record->value_size - 1]) )
6857 start_address_validation (&pr->pid,
6858 (const char *) record->value,
6864 * We have received a `struct ExpressPreferenceMessage` from an application client.
6866 * @param cls handle to the client
6867 * @param msg the start message
6870 handle_suggest (void *cls,
6871 const struct ExpressPreferenceMessage *msg)
6873 struct TransportClient *tc = cls;
6874 struct PeerRequest *pr;
6876 if (CT_NONE == tc->type)
6878 tc->type = CT_APPLICATION;
6879 tc->details.application.requests
6880 = GNUNET_CONTAINER_multipeermap_create (16,
6883 if (CT_APPLICATION != tc->type)
6886 GNUNET_SERVICE_client_drop (tc->client);
6889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6890 "Client suggested we talk to %s with preference %d at rate %u\n",
6891 GNUNET_i2s (&msg->peer),
6892 (int) ntohl (msg->pk),
6893 (int) ntohl (msg->bw.value__));
6894 pr = GNUNET_new (struct PeerRequest);
6896 pr->pid = msg->peer;
6898 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
6900 GNUNET_CONTAINER_multipeermap_put (tc->details.application.requests,
6903 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
6907 GNUNET_SERVICE_client_drop (tc->client);
6910 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
6913 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
6916 GNUNET_SERVICE_client_continue (tc->client);
6921 * Given another peers address, consider checking it for validity
6922 * and then adding it to the Peerstore.
6924 * @param cls a `struct TransportClient`
6925 * @param hdr message containing the raw address data and
6926 * signature in the body, see #GNUNET_HELLO_extract_address()
6929 handle_address_consider_verify (void *cls,
6930 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6932 struct TransportClient *tc = cls;
6934 enum GNUNET_NetworkType nt;
6935 struct GNUNET_TIME_Absolute expiration;
6938 // OPTIMIZE-FIXME: checking that we know this address already should
6939 // be done BEFORE checking the signature => HELLO API change!
6940 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
6941 address = GNUNET_HELLO_extract_address (&hdr[1],
6942 ntohs (hdr->header.size) - sizeof (*hdr),
6946 if (NULL == address)
6948 GNUNET_break_op (0);
6951 start_address_validation (&hdr->peer,
6954 GNUNET_free (address);
6955 GNUNET_SERVICE_client_continue (tc->client);
6960 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
6963 * @param cls a `struct TransportClient *`
6964 * @param m message to verify
6965 * @return #GNUNET_OK on success
6968 check_request_hello_validation (void *cls,
6969 const struct RequestHelloValidationMessage *m)
6972 GNUNET_MQ_check_zero_termination (m);
6978 * A client encountered an address of another peer. Consider validating it,
6979 * and if validation succeeds, persist it to PEERSTORE.
6981 * @param cls a `struct TransportClient *`
6982 * @param m message to verify
6985 handle_request_hello_validation (void *cls,
6986 const struct RequestHelloValidationMessage *m)
6988 struct TransportClient *tc = cls;
6990 start_address_validation (&m->peer,
6991 (const char *) &m[1],
6992 GNUNET_TIME_absolute_ntoh (m->expiration));
6993 GNUNET_SERVICE_client_continue (tc->client);
6998 * Free neighbour entry.
7002 * @param value a `struct Neighbour`
7003 * @return #GNUNET_OK (always)
7006 free_neighbour_cb (void *cls,
7007 const struct GNUNET_PeerIdentity *pid,
7010 struct Neighbour *neighbour = value;
7014 GNUNET_break (0); // should this ever happen?
7015 free_neighbour (neighbour);
7022 * Free DV route entry.
7026 * @param value a `struct DistanceVector`
7027 * @return #GNUNET_OK (always)
7030 free_dv_routes_cb (void *cls,
7031 const struct GNUNET_PeerIdentity *pid,
7034 struct DistanceVector *dv = value;
7045 * Free ephemeral entry.
7049 * @param value a `struct EphemeralCacheEntry`
7050 * @return #GNUNET_OK (always)
7053 free_ephemeral_cb (void *cls,
7054 const struct GNUNET_PeerIdentity *pid,
7057 struct EphemeralCacheEntry *ece = value;
7061 free_ephemeral (ece);
7067 * Free validation state.
7071 * @param value a `struct ValidationState`
7072 * @return #GNUNET_OK (always)
7075 free_validation_state_cb (void *cls,
7076 const struct GNUNET_PeerIdentity *pid,
7079 struct ValidationState *vs = value;
7083 free_validation_state (vs);
7089 * Function called when the service shuts down. Unloads our plugins
7090 * and cancels pending validations.
7092 * @param cls closure, unused
7095 do_shutdown (void *cls)
7097 struct LearnLaunchEntry *lle;
7100 if (NULL != ephemeral_task)
7102 GNUNET_SCHEDULER_cancel (ephemeral_task);
7103 ephemeral_task = NULL;
7105 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7108 if (NULL != peerstore)
7110 GNUNET_PEERSTORE_disconnect (peerstore,
7114 if (NULL != GST_stats)
7116 GNUNET_STATISTICS_destroy (GST_stats,
7120 if (NULL != GST_my_private_key)
7122 GNUNET_free (GST_my_private_key);
7123 GST_my_private_key = NULL;
7125 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7127 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7128 &free_validation_state_cb,
7130 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7131 validation_map = NULL;
7132 while (NULL != (lle = lle_head))
7134 GNUNET_CONTAINER_DLL_remove (lle_head,
7139 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7141 GNUNET_CONTAINER_heap_destroy (validation_heap);
7142 validation_heap = NULL;
7143 GNUNET_CONTAINER_multipeermap_iterate (dv_routes,
7146 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7148 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7151 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7152 ephemeral_map = NULL;
7153 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7154 ephemeral_heap = NULL;
7159 * Initiate transport service.
7161 * @param cls closure
7162 * @param c configuration to use
7163 * @param service the initialized service
7167 const struct GNUNET_CONFIGURATION_Handle *c,
7168 struct GNUNET_SERVICE_Handle *service)
7174 neighbours = GNUNET_CONTAINER_multipeermap_create (1024,
7176 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024,
7178 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32,
7180 ephemeral_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7181 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7183 validation_map = GNUNET_CONTAINER_multipeermap_create (1024,
7185 validation_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7186 GST_my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7187 if (NULL == GST_my_private_key)
7189 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7190 _("Transport service is lacking key configuration settings. Exiting.\n"));
7191 GNUNET_SCHEDULER_shutdown ();
7194 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7195 &GST_my_identity.public_key);
7196 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
7197 "My identity is `%s'\n",
7198 GNUNET_i2s_full (&GST_my_identity));
7199 GST_stats = GNUNET_STATISTICS_create ("transport",
7201 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
7203 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7204 if (NULL == peerstore)
7207 GNUNET_SCHEDULER_shutdown ();
7214 * Define "main" method using service macro.
7218 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7221 &client_disconnect_cb,
7223 /* communication with applications */
7224 GNUNET_MQ_hd_fixed_size (suggest,
7225 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7226 struct ExpressPreferenceMessage,
7228 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7229 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7230 struct ExpressPreferenceMessage,
7232 GNUNET_MQ_hd_var_size (request_hello_validation,
7233 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7234 struct RequestHelloValidationMessage,
7236 /* communication with core */
7237 GNUNET_MQ_hd_fixed_size (client_start,
7238 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7239 struct StartMessage,
7241 GNUNET_MQ_hd_var_size (client_send,
7242 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7243 struct OutboundMessage,
7245 /* communication with communicators */
7246 GNUNET_MQ_hd_var_size (communicator_available,
7247 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7248 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7250 GNUNET_MQ_hd_var_size (communicator_backchannel,
7251 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7252 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7254 GNUNET_MQ_hd_var_size (add_address,
7255 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7256 struct GNUNET_TRANSPORT_AddAddressMessage,
7258 GNUNET_MQ_hd_fixed_size (del_address,
7259 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7260 struct GNUNET_TRANSPORT_DelAddressMessage,
7262 GNUNET_MQ_hd_var_size (incoming_msg,
7263 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7264 struct GNUNET_TRANSPORT_IncomingMessage,
7266 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7267 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7268 struct GNUNET_TRANSPORT_CreateQueueResponse,
7270 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7271 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7272 struct GNUNET_TRANSPORT_CreateQueueResponse,
7274 GNUNET_MQ_hd_var_size (add_queue_message,
7275 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7276 struct GNUNET_TRANSPORT_AddQueueMessage,
7278 GNUNET_MQ_hd_var_size (address_consider_verify,
7279 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7280 struct GNUNET_TRANSPORT_AddressToVerify,
7282 GNUNET_MQ_hd_fixed_size (del_queue_message,
7283 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7284 struct GNUNET_TRANSPORT_DelQueueMessage,
7286 GNUNET_MQ_hd_fixed_size (send_message_ack,
7287 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
7288 struct GNUNET_TRANSPORT_SendMessageToAck,
7290 /* communication with monitors */
7291 GNUNET_MQ_hd_fixed_size (monitor_start,
7292 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
7293 struct GNUNET_TRANSPORT_MonitorStart,
7295 GNUNET_MQ_handler_end ());
7298 /* end of file gnunet-service-transport.c */