2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
26 * - figure out how to transmit (selective) ACKs in case of uni-directional
27 * communicators (with/without core? DV-only?) When do we use ACKs?
28 * => communicators use selective ACKs for flow control
29 * => transport uses message-level ACKs for RTT, fragment confirmation
30 * => integrate DV into transport, use neither core nor communicators
31 * but rather give communicators transport-encapsulated messages
32 * (which could be core-data, background-channel traffic, or
33 * transport-to-transport traffic)
36 * - route_message() implementation, including using DV data structures
37 * (but not when routing certain message types, like DV learn,
38 * MUST pay attention to content here -- or pass extra flags?)
39 * - retransmission logic
40 * - track RTT, distance, loss, etc. => requires extra data structures!
43 * - change transport-core API to provide proper flow control in both
44 * directions, allow multiple messages per peer simultaneously (tag
45 * confirmations with unique message ID), and replace quota-out with
46 * proper flow control;
47 * - if messages are below MTU, consider adding ACKs and other stuff
48 * (requires planning at receiver, and additional MST-style demultiplex
50 * - could avoid copying body of message into each fragment and keep
51 * fragments as just pointers into the original message and only
52 * fully build fragments just before transmission (optimization, should
53 * reduce CPU and memory use)
55 * FIXME (without marks in the code!):
56 * - proper use/initialization of timestamps in messages exchanged
60 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
61 * against our pending message queue (requires additional per neighbour
62 * hash map to be maintained, avoids possible linear scan on pending msgs)
64 * Design realizations / discussion:
65 * - communicators do flow control by calling MQ "notify sent"
66 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
67 * or explicitly via backchannel FC ACKs. As long as the
68 * channel is not full, they may 'notify sent' even if the other
69 * peer has not yet confirmed receipt. The other peer confirming
70 * is _only_ for FC, not for more reliable transmission; reliable
71 * transmission (i.e. of fragments) is left to _transport_.
72 * - ACKs sent back in uni-directional communicators are done via
73 * the background channel API; here transport _may_ initially
74 * broadcast (with bounded # hops) if no path is known;
75 * - transport should _integrate_ DV-routing and build a view of
76 * the network; then background channel traffic can be
77 * routed via DV as well as explicit "DV" traffic.
78 * - background channel is also used for ACKs and NAT traversal support
79 * - transport service is responsible for AEAD'ing the background
80 * channel, timestamps and monotonic time are used against replay
81 * of old messages -> peerstore needs to be supplied with
82 * "latest timestamps seen" data
83 * - if transport implements DV, we likely need a 3rd peermap
84 * in addition to ephemerals and (direct) neighbours
85 * ==> check if stuff needs to be moved out of "Neighbour"
86 * - transport should encapsualte core-level messages and do its
87 * own ACKing for RTT/goodput/loss measurements _and_ fragment
91 #include "gnunet_util_lib.h"
92 #include "gnunet_statistics_service.h"
93 #include "gnunet_transport_monitor_service.h"
94 #include "gnunet_peerstore_service.h"
95 #include "gnunet_hello_lib.h"
96 #include "gnunet_signatures.h"
97 #include "transport.h"
101 * What is the size we assume for a read operation in the
102 * absence of an MTU for the purpose of flow control?
104 #define IN_PACKET_SIZE_WITHOUT_MTU 128
107 * Minimum number of hops we should forward DV learn messages
108 * even if they are NOT useful for us in hope of looping
109 * back to the initiator?
111 * FIXME: allow initiator some control here instead?
113 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
116 * Maximum DV distance allowed ever.
118 #define MAX_DV_HOPS_ALLOWED 16
121 * Maximum number of DV learning activities we may
122 * have pending at the same time.
124 #define MAX_DV_LEARN_PENDING 64
127 * Maximum number of DV paths we keep simultaneously to the same target.
129 #define MAX_DV_PATHS_TO_TARGET 3
132 * If a queue delays the next message by more than this number
133 * of seconds we log a warning. Note: this is for testing,
134 * the value chosen here might be too aggressively low!
136 #define DELAY_WARN_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
139 * We only consider queues as "quality" connections when
140 * suppressing the generation of DV initiation messages if
141 * the latency of the queue is below this threshold.
143 #define DV_QUALITY_RTT_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
146 * How long do we consider a DV path valid if we see no
147 * further updates on it? Note: the value chosen here might be too low!
149 #define DV_PATH_VALIDITY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
152 * How long before paths expire would we like to (re)discover DV paths? Should
153 * be below #DV_PATH_VALIDITY_TIMEOUT.
155 #define DV_PATH_DISCOVERY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
158 * How long are ephemeral keys valid?
160 #define EPHEMERAL_VALIDITY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
163 * How long do we keep partially reassembled messages around before giving up?
165 #define REASSEMBLY_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
168 * What is the fastest rate at which we send challenges *if* we keep learning
169 * an address (gossip, DHT, etc.)?
171 #define FAST_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
174 * What is the slowest rate at which we send challenges?
176 #define MAX_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
179 * What is the non-randomized base frequency at which we
180 * would initiate DV learn messages?
182 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
185 * How many good connections (confirmed, bi-directional, not DV)
186 * do we need to have to suppress initiating DV learn messages?
188 #define DV_LEARN_QUALITY_THRESHOLD 100
191 * When do we forget an invalid address for sure?
193 #define MAX_ADDRESS_VALID_UNTIL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
195 * How long do we consider an address valid if we just checked?
197 #define ADDRESS_VALIDATION_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
200 * What is the maximum frequency at which we do address validation?
201 * A random value between 0 and this value is added when scheduling
202 * the #validation_task (both to ensure we do not validate too often,
203 * and to randomize a bit).
205 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
208 * How many network RTTs before an address validation expires should we begin
209 * trying to revalidate? (Note that the RTT used here is the one that we
210 * experienced during the last validation, not necessarily the latest RTT
213 #define VALIDATION_RTT_BUFFER_FACTOR 3
216 * How many messages can we have pending for a given communicator
217 * process before we start to throttle that communicator?
219 * Used if a communicator might be CPU-bound and cannot handle the traffic.
221 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
224 * How many messages can we have pending for a given queue (queue to
225 * a particular peer via a communicator) process before we start to
226 * throttle that queue?
228 #define QUEUE_LENGTH_LIMIT 32
231 GNUNET_NETWORK_STRUCT_BEGIN
234 * Outer layer of an encapsulated backchannel message.
236 struct TransportBackchannelEncapsulationMessage
239 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
241 struct GNUNET_MessageHeader header;
244 * Distance the backchannel message has traveled, to be updated at
245 * each hop. Used to bound the number of hops in case a backchannel
246 * message is broadcast and thus travels without routing
247 * information (during initial backchannel discovery).
252 * Target's peer identity (as backchannels may be transmitted
253 * indirectly, or even be broadcast).
255 struct GNUNET_PeerIdentity target;
258 * Ephemeral key setup by the sender for @e target, used
259 * to encrypt the payload.
261 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
264 * We use an IV here as the @e ephemeral_key is re-used for
265 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
267 struct GNUNET_ShortHashCode iv;
270 * HMAC over the ciphertext of the encrypted, variable-size
271 * body that follows. Verified via DH of @e target and
274 struct GNUNET_HashCode hmac;
276 /* Followed by encrypted, variable-size payload */
281 * Body by which a peer confirms that it is using an ephemeral key.
283 struct EphemeralConfirmation
287 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
289 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
292 * How long is this signature over the ephemeral key valid?
294 * Note that the receiver MUST IGNORE the absolute time, and only interpret
295 * the value as a mononic time and reject "older" values than the last one
296 * observed. This is necessary as we do not want to require synchronized
297 * clocks and may not have a bidirectional communication channel.
299 * Even with this, there is no real guarantee against replay achieved here,
300 * unless the latest timestamp is persisted. While persistence should be
301 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
302 * communicators must protect against replay attacks when using backchannel
305 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
308 * Target's peer identity.
310 struct GNUNET_PeerIdentity target;
313 * Ephemeral key setup by the sender for @e target, used
314 * to encrypt the payload.
316 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
322 * Plaintext of the variable-size payload that is encrypted
323 * within a `struct TransportBackchannelEncapsulationMessage`
325 struct TransportBackchannelRequestPayload
329 * Sender's peer identity.
331 struct GNUNET_PeerIdentity sender;
334 * Signature of the sender over an
335 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
337 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
340 * How long is this signature over the ephemeral key valid?
342 * Note that the receiver MUST IGNORE the absolute time, and only interpret
343 * the value as a mononic time and reject "older" values than the last one
344 * observed. This is necessary as we do not want to require synchronized
345 * clocks and may not have a bidirectional communication channel.
347 * Even with this, there is no real guarantee against replay achieved here,
348 * unless the latest timestamp is persisted. While persistence should be
349 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
350 * communicators must protect against replay attacks when using backchannel
353 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
356 * Current monotonic time of the sending transport service. Used to
357 * detect replayed messages. Note that the receiver should remember
358 * a list of the recently seen timestamps and only reject messages
359 * if the timestamp is in the list, or the list is "full" and the
360 * timestamp is smaller than the lowest in the list.
362 * Like the @e ephemeral_validity, the list of timestamps per peer should be
363 * persisted to guard against replays after restarts.
365 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
367 /* Followed by a `struct GNUNET_MessageHeader` with a message
368 for a communicator */
370 /* Followed by a 0-termianted string specifying the name of
371 the communicator which is to receive the message */
377 * Outer layer of an encapsulated unfragmented application message sent
378 * over an unreliable channel.
380 struct TransportReliabilityBox
383 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
385 struct GNUNET_MessageHeader header;
388 * Number of messages still to be sent before a commulative
389 * ACK is requested. Zero if an ACK is requested immediately.
390 * In NBO. Note that the receiver may send the ACK faster
391 * if it believes that is reasonable.
393 uint32_t ack_countdown GNUNET_PACKED;
396 * Unique ID of the message used for signalling receipt of
397 * messages sent over possibly unreliable channels. Should
400 struct GNUNET_ShortHashCode msg_uuid;
405 * Confirmation that the receiver got a
406 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
407 * confirmation may be transmitted over a completely different queue,
408 * so ACKs are identified by a combination of PID of sender and
409 * message UUID, without the queue playing any role!
411 struct TransportReliabilityAckMessage
414 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
416 struct GNUNET_MessageHeader header;
421 uint32_t reserved GNUNET_PACKED;
424 * How long was the ACK delayed relative to the average time of
425 * receipt of the messages being acknowledged? Used to calculate
426 * the average RTT by taking the receipt time of the ack minus the
427 * average transmission time of the sender minus this value.
429 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
431 /* followed by any number of `struct GNUNET_ShortHashCode`
432 messages providing ACKs */
437 * Outer layer of an encapsulated fragmented application message.
439 struct TransportFragmentBox
442 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
444 struct GNUNET_MessageHeader header;
447 * Unique ID of this fragment (and fragment transmission!). Will
448 * change even if a fragement is retransmitted to make each
449 * transmission attempt unique! Should be incremented by one for
450 * each fragment transmission. If a client receives a duplicate
451 * fragment (same @e frag_off), it must send
452 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
454 uint32_t frag_uuid GNUNET_PACKED;
457 * Original message ID for of the message that all the1
458 * fragments belong to. Must be the same for all fragments.
460 struct GNUNET_ShortHashCode msg_uuid;
463 * Offset of this fragment in the overall message.
465 uint16_t frag_off GNUNET_PACKED;
468 * Total size of the message that is being fragmented.
470 uint16_t msg_size GNUNET_PACKED;
476 * Outer layer of an fragmented application message sent over a queue
477 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
478 * received, the receiver has two RTTs or 64 further fragments with
479 * the same basic message time to send an acknowledgement, possibly
480 * acknowledging up to 65 fragments in one ACK. ACKs must also be
481 * sent immediately once all fragments were sent.
483 struct TransportFragmentAckMessage
486 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
488 struct GNUNET_MessageHeader header;
491 * Unique ID of the lowest fragment UUID being acknowledged.
493 uint32_t frag_uuid GNUNET_PACKED;
496 * Bitfield of up to 64 additional fragments following the
497 * @e msg_uuid being acknowledged by this message.
499 uint64_t extra_acks GNUNET_PACKED;
502 * Original message ID for of the message that all the
503 * fragments belong to.
505 struct GNUNET_ShortHashCode msg_uuid;
508 * How long was the ACK delayed relative to the average time of
509 * receipt of the fragments being acknowledged? Used to calculate
510 * the average RTT by taking the receipt time of the ack minus the
511 * average transmission time of the sender minus this value.
513 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
516 * How long until the receiver will stop trying reassembly
519 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
524 * Content signed by the initator during DV learning.
526 * The signature is required to prevent DDoS attacks. A peer sending out this
527 * message is potentially generating a lot of traffic that will go back to the
528 * initator, as peers receiving this message will try to let the initiator
529 * know that they got the message.
531 * Without this signature, an attacker could abuse this mechanism for traffic
532 * amplification, sending a lot of traffic to a peer by putting out this type
533 * of message with the victim's peer identity.
535 * Even with just a signature, traffic amplification would be possible via
536 * replay attacks. The @e monotonic_time limits such replay attacks, as every
537 * potential amplificator will check the @e monotonic_time and only respond
538 * (at most) once per message.
543 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
545 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
548 * Time at the initiator when generating the signature.
550 * Note that the receiver MUST IGNORE the absolute time, and only interpret
551 * the value as a mononic time and reject "older" values than the last one
552 * observed. This is necessary as we do not want to require synchronized
553 * clocks and may not have a bidirectional communication channel.
555 * Even with this, there is no real guarantee against replay achieved here,
556 * unless the latest timestamp is persisted. Persistence should be
557 * provided via PEERSTORE if possible.
559 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
562 * Challenge value used by the initiator to re-identify the path.
564 struct GNUNET_ShortHashCode challenge;
570 * Content signed by each peer during DV learning.
572 * This assues the initiator of the DV learning operation that the hop from @e
573 * pred via the signing peer to @e succ actually exists. This makes it
574 * impossible for an adversary to supply the network with bogus routes.
576 * The @e challenge is included to provide replay protection for the
577 * initiator. This way, the initiator knows that the hop existed after the
578 * original @e challenge was first transmitted, providing a freshness metric.
580 * Peers other than the initiator that passively learn paths by observing
581 * these messages do NOT benefit from this. Here, an adversary may indeed
582 * replay old messages. Thus, passively learned paths should always be
583 * immediately marked as "potentially stale".
588 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
590 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
593 * Identity of the previous peer on the path.
595 struct GNUNET_PeerIdentity pred;
598 * Identity of the next peer on the path.
600 struct GNUNET_PeerIdentity succ;
603 * Challenge value used by the initiator to re-identify the path.
605 struct GNUNET_ShortHashCode challenge;
611 * An entry describing a peer on a path in a
612 * `struct TransportDVLearn` message.
617 * Identity of a peer on the path.
619 struct GNUNET_PeerIdentity hop;
622 * Signature of this hop over the path, of purpose
623 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
625 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
631 * Internal message used by transport for distance vector learning.
632 * If @e num_hops does not exceed the threshold, peers should append
633 * themselves to the peer list and flood the message (possibly only
634 * to a subset of their neighbours to limit discoverability of the
635 * network topology). To the extend that the @e bidirectional bits
636 * are set, peers may learn the inverse paths even if they did not
639 * Unless received on a bidirectional queue and @e num_hops just
640 * zero, peers that can forward to the initator should always try to
641 * forward to the initiator.
643 struct TransportDVLearn
646 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
648 struct GNUNET_MessageHeader header;
651 * Number of hops this messages has travelled, in NBO. Zero if
654 uint16_t num_hops GNUNET_PACKED;
657 * Bitmask of the last 16 hops indicating whether they are confirmed
658 * available (without DV) in both directions or not, in NBO. Used
659 * to possibly instantly learn a path in both directions. Each peer
660 * should shift this value by one to the left, and then set the
661 * lowest bit IF the current sender can be reached from it (without
664 uint16_t bidirectional GNUNET_PACKED;
667 * Peers receiving this message and delaying forwarding to other
668 * peers for any reason should increment this value by the non-network
669 * delay created by the peer.
671 struct GNUNET_TIME_RelativeNBO non_network_delay;
674 * Signature of this hop over the path, of purpose
675 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
677 struct GNUNET_CRYPTO_EddsaSignature init_sig;
680 * Identity of the peer that started this learning activity.
682 struct GNUNET_PeerIdentity initiator;
685 * Challenge value used by the initiator to re-identify the path.
687 struct GNUNET_ShortHashCode challenge;
689 /* Followed by @e num_hops `struct DVPathEntryP` values,
690 excluding the initiator of the DV trace; the last entry is the
691 current sender; the current peer must not be included. */
697 * Outer layer of an encapsulated message send over multiple hops.
698 * The path given only includes the identities of the subsequent
699 * peers, i.e. it will be empty if we are the receiver. Each
700 * forwarding peer should scan the list from the end, and if it can,
701 * forward to the respective peer. The list should then be shortened
702 * by all the entries up to and including that peer. Each hop should
703 * also increment @e total_hops to allow the receiver to get a precise
704 * estimate on the number of hops the message travelled. Senders must
705 * provide a learned path that thus should work, but intermediaries
706 * know of a shortcut, they are allowed to send the message via that
709 * If a peer finds itself still on the list, it must drop the message.
711 struct TransportDVBox
714 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
716 struct GNUNET_MessageHeader header;
719 * Number of total hops this messages travelled. In NBO.
720 * @e origin sets this to zero, to be incremented at
723 uint16_t total_hops GNUNET_PACKED;
726 * Number of hops this messages includes. In NBO.
728 uint16_t num_hops GNUNET_PACKED;
731 * Identity of the peer that originated the message.
733 struct GNUNET_PeerIdentity origin;
735 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
736 excluding the @e origin and the current peer, the last must be
737 the ultimate target; if @e num_hops is zero, the receiver of this
738 message is the ultimate target. */
740 /* Followed by the actual message, which itself may be
741 another box, but not a DV_LEARN or DV_BOX message! */
746 * Message send to another peer to validate that it can indeed
747 * receive messages at a particular address.
749 struct TransportValidationChallenge
753 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
755 struct GNUNET_MessageHeader header;
760 uint32_t reserved GNUNET_PACKED;
763 * Challenge to be signed by the receiving peer.
765 struct GNUNET_ShortHashCode challenge;
768 * Timestamp of the sender, to be copied into the reply
769 * to allow sender to calculate RTT.
771 struct GNUNET_TIME_AbsoluteNBO sender_time;
776 * Message signed by a peer to confirm that it can indeed
777 * receive messages at a particular address.
779 struct TransportValidationPS
783 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
785 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
788 * How long does the sender believe the address on
789 * which the challenge was received to remain valid?
791 struct GNUNET_TIME_RelativeNBO validity_duration;
794 * Challenge signed by the receiving peer.
796 struct GNUNET_ShortHashCode challenge;
802 * Message send to a peer to respond to a
803 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
805 struct TransportValidationResponse
809 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
811 struct GNUNET_MessageHeader header;
816 uint32_t reserved GNUNET_PACKED;
819 * The peer's signature matching the
820 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
822 struct GNUNET_CRYPTO_EddsaSignature signature;
825 * The challenge that was signed by the receiving peer.
827 struct GNUNET_ShortHashCode challenge;
830 * Original timestamp of the sender (was @code{sender_time}),
831 * copied into the reply to allow sender to calculate RTT.
833 struct GNUNET_TIME_AbsoluteNBO origin_time;
836 * How long does the sender believe this address to remain
839 struct GNUNET_TIME_RelativeNBO validity_duration;
844 GNUNET_NETWORK_STRUCT_END
848 * What type of client is the `struct TransportClient` about?
853 * We do not know yet (client is fresh).
858 * Is the CORE service, we need to forward traffic to it.
863 * It is a monitor, forward monitor data.
868 * It is a communicator, use for communication.
873 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
880 * When did we launch this DV learning activity?
882 struct LearnLaunchEntry
886 * Kept (also) in a DLL sorted by launch time.
888 struct LearnLaunchEntry *prev;
891 * Kept (also) in a DLL sorted by launch time.
893 struct LearnLaunchEntry *next;
896 * Challenge that uniquely identifies this activity.
898 struct GNUNET_ShortHashCode challenge;
901 * When did we transmit the DV learn message (used to calculate RTT) and
902 * determine freshness of paths learned via this operation.
904 struct GNUNET_TIME_Absolute launch_time;
910 * Entry in our cache of ephemeral keys we currently use. This way, we only
911 * sign an ephemeral once per @e target, and then can re-use it over multiple
912 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
913 * signing is expensive and in some cases we may use backchannel messages a
916 struct EphemeralCacheEntry
920 * Target's peer identity (we don't re-use ephemerals
921 * to limit linkability of messages).
923 struct GNUNET_PeerIdentity target;
926 * Signature affirming @e ephemeral_key of type
927 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
929 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
932 * How long is @e sender_sig valid
934 struct GNUNET_TIME_Absolute ephemeral_validity;
939 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
942 * Our private ephemeral key.
944 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
947 * Node in the ephemeral cache for this entry.
948 * Used for expiration.
950 struct GNUNET_CONTAINER_HeapNode *hn;
955 * Client connected to the transport service.
957 struct TransportClient;
961 * A neighbour that at least one communicator is connected to.
967 * Entry in our #dv_routes table, representing a (set of) distance
968 * vector routes to a particular peer.
970 struct DistanceVector;
973 * One possible hop towards a DV target.
975 struct DistanceVectorHop
979 * Kept in a MDLL, sorted by @e timeout.
981 struct DistanceVectorHop *next_dv;
984 * Kept in a MDLL, sorted by @e timeout.
986 struct DistanceVectorHop *prev_dv;
991 struct DistanceVectorHop *next_neighbour;
996 struct DistanceVectorHop *prev_neighbour;
999 * What would be the next hop to @e target?
1001 struct Neighbour *next_hop;
1004 * Distance vector entry this hop belongs with.
1006 struct DistanceVector *dv;
1009 * Array of @e distance hops to the target, excluding @e next_hop.
1010 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1011 * at the end of this struct.
1013 const struct GNUNET_PeerIdentity *path;
1016 * At what time do we forget about this path unless we see it again
1019 struct GNUNET_TIME_Absolute timeout;
1022 * After what time do we know for sure that the path must have existed?
1023 * Set to ZERO if the path is learned by snooping on DV learn messages
1024 * initiated by other peers, and to the time at which we generated the
1025 * challenge for DV learn operations this peer initiated.
1027 struct GNUNET_TIME_Absolute freshness;
1030 * How many hops in total to the `target` (excluding @e next_hop and `target` itself),
1031 * thus 0 still means a distance of 2 hops (to @e next_hop and then to `target`)?
1033 unsigned int distance;
1038 * Entry in our #dv_routes table, representing a (set of) distance
1039 * vector routes to a particular peer.
1041 struct DistanceVector
1045 * To which peer is this a route?
1047 struct GNUNET_PeerIdentity target;
1050 * Known paths to @e target.
1052 struct DistanceVectorHop *dv_head;
1055 * Known paths to @e target.
1057 struct DistanceVectorHop *dv_tail;
1060 * Task scheduled to purge expired paths from @e dv_head MDLL.
1062 struct GNUNET_SCHEDULER_Task *timeout_task;
1067 * A queue is a message queue provided by a communicator
1068 * via which we can reach a particular neighbour.
1074 * Entry identifying transmission in one of our `struct
1075 * Queue` which still awaits an ACK. This is used to
1076 * ensure we do not overwhelm a communicator and limit the number of
1077 * messages outstanding per communicator (say in case communicator is
1078 * CPU bound) and per queue (in case bandwidth allocation exceeds
1079 * what the communicator can actually provide towards a particular
1088 struct QueueEntry *next;
1093 struct QueueEntry *prev;
1096 * Queue this entry is queued with.
1098 struct Queue *queue;
1101 * Message ID used for this message with the queue used for transmission.
1108 * A queue is a message queue provided by a communicator
1109 * via which we can reach a particular neighbour.
1116 struct Queue *next_neighbour;
1121 struct Queue *prev_neighbour;
1126 struct Queue *prev_client;
1131 struct Queue *next_client;
1134 * Head of DLL of unacked transmission requests.
1136 struct QueueEntry *queue_head;
1139 * End of DLL of unacked transmission requests.
1141 struct QueueEntry *queue_tail;
1144 * Which neighbour is this queue for?
1146 struct Neighbour *neighbour;
1149 * Which communicator offers this queue?
1151 struct TransportClient *tc;
1154 * Address served by the queue.
1156 const char *address;
1159 * Task scheduled for the time when this queue can (likely) transmit the
1160 * next message. Still needs to check with the @e tracker_out to be sure.
1162 struct GNUNET_SCHEDULER_Task *transmit_task;
1165 * Our current RTT estimate for this queue.
1167 struct GNUNET_TIME_Relative rtt;
1170 * Message ID generator for transmissions on this queue.
1175 * Unique identifier of this queue with the communicator.
1180 * Maximum transmission unit supported by this queue.
1185 * Distance to the target of this queue.
1186 * FIXME: needed? DV is done differently these days...
1193 uint32_t num_msg_pending;
1198 uint32_t num_bytes_pending;
1201 * Length of the DLL starting at @e queue_head.
1203 unsigned int queue_length;
1206 * Network type offered by this queue.
1208 enum GNUNET_NetworkType nt;
1211 * Connection status for this queue.
1213 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1216 * How much outbound bandwidth do we have available for this queue?
1218 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1221 * How much inbound bandwidth do we have available for this queue?
1223 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1228 * Information we keep for a message that we are reassembling.
1230 struct ReassemblyContext
1234 * Original message ID for of the message that all the
1235 * fragments belong to.
1237 struct GNUNET_ShortHashCode msg_uuid;
1240 * Which neighbour is this context for?
1242 struct Neighbour *neighbour;
1245 * Entry in the reassembly heap (sorted by expiration).
1247 struct GNUNET_CONTAINER_HeapNode *hn;
1250 * Bitfield with @e msg_size bits representing the positions
1251 * where we have received fragments. When we receive a fragment,
1252 * we check the bits in @e bitfield before incrementing @e msg_missing.
1254 * Allocated after the reassembled message.
1259 * Task for sending ACK. We may send ACKs either because of hitting
1260 * the @e extra_acks limit, or based on time and @e num_acks. This
1261 * task is for the latter case.
1263 struct GNUNET_SCHEDULER_Task *ack_task;
1266 * At what time will we give up reassembly of this message?
1268 struct GNUNET_TIME_Absolute reassembly_timeout;
1271 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1272 * Should be reset to zero when @e num_acks is set to 0.
1274 struct GNUNET_TIME_Relative avg_ack_delay;
1277 * Time we received the last fragment. @e avg_ack_delay must be
1278 * incremented by now - @e last_frag multiplied by @e num_acks.
1280 struct GNUNET_TIME_Absolute last_frag;
1283 * Bitfield of up to 64 additional fragments following @e frag_uuid
1284 * to be acknowledged in the next cummulative ACK.
1286 uint64_t extra_acks;
1289 * Unique ID of the lowest fragment UUID to be acknowledged in the
1290 * next cummulative ACK. Only valid if @e num_acks > 0.
1295 * Number of ACKs we have accumulated so far. Reset to 0
1296 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1298 unsigned int num_acks;
1301 * How big is the message we are reassembling in total?
1306 * How many bytes of the message are still missing? Defragmentation
1307 * is complete when @e msg_missing == 0.
1309 uint16_t msg_missing;
1311 /* Followed by @e msg_size bytes of the (partially) defragmented original message */
1313 /* Followed by @e bitfield data */
1318 * A neighbour that at least one communicator is connected to.
1324 * Which peer is this about?
1326 struct GNUNET_PeerIdentity pid;
1329 * Map with `struct ReassemblyContext` structs for fragments under
1330 * reassembly. May be NULL if we currently have no fragments from
1331 * this @e pid (lazy initialization).
1333 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1336 * Heap with `struct ReassemblyContext` structs for fragments under
1337 * reassembly. May be NULL if we currently have no fragments from
1338 * this @e pid (lazy initialization).
1340 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1343 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1345 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1348 * Head of list of messages pending for this neighbour.
1350 struct PendingMessage *pending_msg_head;
1353 * Tail of list of messages pending for this neighbour.
1355 struct PendingMessage *pending_msg_tail;
1358 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1359 * purged if this neighbour goes down.
1361 struct DistanceVectorHop *dv_head;
1364 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1365 * purged if this neighbour goes down.
1367 struct DistanceVectorHop *dv_tail;
1370 * Head of DLL of queues to this peer.
1372 struct Queue *queue_head;
1375 * Tail of DLL of queues to this peer.
1377 struct Queue *queue_tail;
1380 * Task run to cleanup pending messages that have exceeded their timeout.
1382 struct GNUNET_SCHEDULER_Task *timeout_task;
1385 * Quota at which CORE is allowed to transmit to this peer.
1387 * FIXME: not yet used, tricky to get right given multiple queues!
1388 * (=> Idea: measure???)
1389 * FIXME: how do we set this value initially when we tell CORE?
1390 * Options: start at a minimum value or at literally zero?
1391 * (=> Current thought: clean would be zero!)
1393 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1396 * What is the earliest timeout of any message in @e pending_msg_tail?
1398 struct GNUNET_TIME_Absolute earliest_timeout;
1404 * A peer that an application (client) would like us to talk to directly.
1410 * Which peer is this about?
1412 struct GNUNET_PeerIdentity pid;
1415 * Client responsible for the request.
1417 struct TransportClient *tc;
1420 * Handle for watching the peerstore for HELLOs for this peer.
1422 struct GNUNET_PEERSTORE_WatchContext *wc;
1425 * What kind of performance preference does this @e tc have?
1427 enum GNUNET_MQ_PreferenceKind pk;
1430 * How much bandwidth would this @e tc like to see?
1432 struct GNUNET_BANDWIDTH_Value32NBO bw;
1438 * Types of different pending messages.
1440 enum PendingMessageType
1444 * Ordinary message received from the CORE service.
1451 PMT_FRAGMENT_BOX = 1,
1456 PMT_RELIABILITY_BOX = 2,
1459 * Any type of acknowledgement.
1461 PMT_ACKNOWLEDGEMENT = 3,
1464 * Control traffic generated by the TRANSPORT service itself.
1472 * Transmission request that is awaiting delivery. The original
1473 * transmission requests from CORE may be too big for some queues.
1474 * In this case, a *tree* of fragments is created. At each
1475 * level of the tree, fragments are kept in a DLL ordered by which
1476 * fragment should be sent next (at the head). The tree is searched
1477 * top-down, with the original message at the root.
1479 * To select a node for transmission, first it is checked if the
1480 * current node's message fits with the MTU. If it does not, we
1481 * either calculate the next fragment (based on @e frag_off) from the
1482 * current node, or, if all fragments have already been created,
1483 * descend to the @e head_frag. Even though the node was already
1484 * fragmented, the fragment may be too big if the fragment was
1485 * generated for a queue with a larger MTU. In this case, the node
1486 * may be fragmented again, thus creating a tree.
1488 * When acknowledgements for fragments are received, the tree
1489 * must be pruned, removing those parts that were already
1490 * acknowledged. When fragments are sent over a reliable
1491 * channel, they can be immediately removed.
1493 * If a message is ever fragmented, then the original "full" message
1494 * is never again transmitted (even if it fits below the MTU), and
1495 * only (remaining) fragments are sent.
1497 struct PendingMessage
1500 * Kept in a MDLL of messages for this @a target.
1502 struct PendingMessage *next_neighbour;
1505 * Kept in a MDLL of messages for this @a target.
1507 struct PendingMessage *prev_neighbour;
1510 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1512 struct PendingMessage *next_client;
1515 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1517 struct PendingMessage *prev_client;
1520 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOx)
1522 struct PendingMessage *next_frag;
1525 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOX)
1527 struct PendingMessage *prev_frag;
1530 * This message, reliability boxed. Only possibly available if @e pmt is #PMT_CORE.
1532 struct PendingMessage *bpm;
1535 * Target of the request.
1537 struct Neighbour *target;
1540 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1542 struct TransportClient *client;
1545 * Head of a MDLL of fragments created for this core message.
1547 struct PendingMessage *head_frag;
1550 * Tail of a MDLL of fragments created for this core message.
1552 struct PendingMessage *tail_frag;
1555 * Our parent in the fragmentation tree.
1557 struct PendingMessage *frag_parent;
1560 * At what time should we give up on the transmission (and no longer retry)?
1562 struct GNUNET_TIME_Absolute timeout;
1565 * What is the earliest time for us to retry transmission of this message?
1567 struct GNUNET_TIME_Absolute next_attempt;
1570 * UUID to use for this message (used for reassembly of fragments, only
1571 * initialized if @e msg_uuid_set is #GNUNET_YES).
1573 struct GNUNET_ShortHashCode msg_uuid;
1576 * Counter incremented per generated fragment.
1578 uint32_t frag_uuidgen;
1581 * Type of the pending message.
1583 enum PendingMessageType pmt;
1586 * Size of the original message.
1591 * Offset at which we should generate the next fragment.
1596 * #GNUNET_YES once @e msg_uuid was initialized
1598 int16_t msg_uuid_set;
1600 /* Followed by @e bytes_msg to transmit */
1605 * One of the addresses of this peer.
1607 struct AddressListEntry
1613 struct AddressListEntry *next;
1618 struct AddressListEntry *prev;
1621 * Which communicator provides this address?
1623 struct TransportClient *tc;
1626 * The actual address.
1628 const char *address;
1631 * Current context for storing this address in the peerstore.
1633 struct GNUNET_PEERSTORE_StoreContext *sc;
1636 * Task to periodically do @e st operation.
1638 struct GNUNET_SCHEDULER_Task *st;
1641 * What is a typical lifetime the communicator expects this
1642 * address to have? (Always from now.)
1644 struct GNUNET_TIME_Relative expiration;
1647 * Address identifier used by the communicator.
1652 * Network type offered by this address.
1654 enum GNUNET_NetworkType nt;
1660 * Client connected to the transport service.
1662 struct TransportClient
1668 struct TransportClient *next;
1673 struct TransportClient *prev;
1676 * Handle to the client.
1678 struct GNUNET_SERVICE_Client *client;
1681 * Message queue to the client.
1683 struct GNUNET_MQ_Handle *mq;
1686 * What type of client is this?
1688 enum ClientType type;
1694 * Information for @e type #CT_CORE.
1699 * Head of list of messages pending for this client, sorted by
1700 * transmission time ("next_attempt" + possibly internal prioritization).
1702 struct PendingMessage *pending_msg_head;
1705 * Tail of list of messages pending for this client.
1707 struct PendingMessage *pending_msg_tail;
1712 * Information for @e type #CT_MONITOR.
1717 * Peer identity to monitor the addresses of.
1718 * Zero to monitor all neighbours. Valid if
1719 * @e type is #CT_MONITOR.
1721 struct GNUNET_PeerIdentity peer;
1724 * Is this a one-shot monitor?
1732 * Information for @e type #CT_COMMUNICATOR.
1736 * If @e type is #CT_COMMUNICATOR, this communicator
1737 * supports communicating using these addresses.
1739 char *address_prefix;
1742 * Head of DLL of queues offered by this communicator.
1744 struct Queue *queue_head;
1747 * Tail of DLL of queues offered by this communicator.
1749 struct Queue *queue_tail;
1752 * Head of list of the addresses of this peer offered by this communicator.
1754 struct AddressListEntry *addr_head;
1757 * Tail of list of the addresses of this peer offered by this communicator.
1759 struct AddressListEntry *addr_tail;
1762 * Number of queue entries in all queues to this communicator. Used
1763 * throttle sending to a communicator if we see that the communicator
1764 * is globally unable to keep up.
1766 unsigned int total_queue_length;
1769 * Characteristics of this communicator.
1771 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1776 * Information for @e type #CT_APPLICATION
1781 * Map of requests for peers the given client application would like to
1782 * see connections for. Maps from PIDs to `struct PeerRequest`.
1784 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1794 * State we keep for validation activities. Each of these
1795 * is both in the #validation_heap and the #validation_map.
1797 struct ValidationState
1801 * For which peer is @a address to be validated (or possibly valid)?
1802 * Serves as key in the #validation_map.
1804 struct GNUNET_PeerIdentity pid;
1807 * How long did the peer claim this @e address to be valid? Capped at
1808 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1809 * were told about the address and the value claimed by the other peer at
1810 * that time. May be updated similarly when validation succeeds.
1812 struct GNUNET_TIME_Absolute valid_until;
1815 * How long do *we* consider this @e address to be valid?
1816 * In the past or zero if we have not yet validated it.
1818 struct GNUNET_TIME_Absolute validated_until;
1821 * When did we FIRST use the current @e challenge in a message?
1822 * Used to sanity-check @code{origin_time} in the response when
1823 * calculating the RTT. If the @code{origin_time} is not in
1824 * the expected range, the response is discarded as malicious.
1826 struct GNUNET_TIME_Absolute first_challenge_use;
1829 * When did we LAST use the current @e challenge in a message?
1830 * Used to sanity-check @code{origin_time} in the response when
1831 * calculating the RTT. If the @code{origin_time} is not in
1832 * the expected range, the response is discarded as malicious.
1834 struct GNUNET_TIME_Absolute last_challenge_use;
1837 * Next time we will send the @e challenge to the peer, if this time is past
1838 * @e valid_until, this validation state is released at this time. If the
1839 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1840 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1841 * to re-validate before the validity actually expires.
1843 struct GNUNET_TIME_Absolute next_challenge;
1846 * Current backoff factor we're applying for sending the @a challenge.
1847 * Reset to 0 if the @a challenge is confirmed upon validation.
1848 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1849 * existing value if we receive an unvalidated address again over
1850 * another channel (and thus should consider the information "fresh").
1851 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1853 struct GNUNET_TIME_Relative challenge_backoff;
1856 * Initially set to "forever". Once @e validated_until is set, this value is
1857 * set to the RTT that tells us how long it took to receive the validation.
1859 struct GNUNET_TIME_Relative validation_rtt;
1862 * The challenge we sent to the peer to get it to validate the address. Note
1863 * that we rotate the challenge whenever we update @e validated_until to
1864 * avoid attacks where a peer simply replays an old challenge in the future.
1865 * (We must not rotate more often as otherwise we may discard valid answers
1866 * due to packet losses, latency and reorderings on the network).
1868 struct GNUNET_ShortHashCode challenge;
1871 * Claimed address of the peer.
1876 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1877 * heap is used to figure out when the next validation activity should be
1880 struct GNUNET_CONTAINER_HeapNode *hn;
1883 * Handle to a PEERSTORE store operation for this @e address. NULL if
1884 * no PEERSTORE operation is pending.
1886 struct GNUNET_PEERSTORE_StoreContext *sc;
1889 * We are technically ready to send the challenge, but we are waiting for
1890 * the respective queue to become available for transmission.
1898 * Head of linked list of all clients to this service.
1900 static struct TransportClient *clients_head;
1903 * Tail of linked list of all clients to this service.
1905 static struct TransportClient *clients_tail;
1908 * Statistics handle.
1910 static struct GNUNET_STATISTICS_Handle *GST_stats;
1913 * Configuration handle.
1915 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1920 static struct GNUNET_PeerIdentity GST_my_identity;
1925 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1928 * Map from PIDs to `struct Neighbour` entries. A peer is
1929 * a neighbour if we have an MQ to it from some communicator.
1931 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1934 * Map from PIDs to `struct DistanceVector` entries describing
1935 * known paths to the peer.
1937 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
1940 * Map from PIDs to `struct ValidationState` entries describing
1941 * addresses we are aware of and their validity state.
1943 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
1946 * Map from challenges to `struct LearnLaunchEntry` values.
1948 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
1951 * Head of a DLL sorted by launch time.
1953 static struct LearnLaunchEntry *lle_head;
1956 * Tail of a DLL sorted by launch time.
1958 static struct LearnLaunchEntry *lle_tail;
1961 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
1962 * sorting addresses we are aware of by when we should next try to (re)validate
1965 static struct GNUNET_CONTAINER_Heap *validation_heap;
1968 * Database for peer's HELLOs.
1970 static struct GNUNET_PEERSTORE_Handle *peerstore;
1973 * Heap sorting `struct EphemeralCacheEntry` by their
1974 * key/signature validity.
1976 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
1979 * Hash map for looking up `struct EphemeralCacheEntry`s
1980 * by peer identity. (We may have ephemerals in our
1981 * cache for which we do not have a neighbour entry,
1982 * and similar many neighbours may not need ephemerals,
1983 * so we use a second map.)
1985 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
1988 * Task to free expired ephemerals.
1990 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
1993 * Task run to initiate DV learning.
1995 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
1998 * Task to run address validation.
2000 static struct GNUNET_SCHEDULER_Task *validation_task;
2004 * Free cached ephemeral key.
2006 * @param ece cached signature to free
2009 free_ephemeral (struct EphemeralCacheEntry *ece)
2011 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map,
2014 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2020 * Free validation state.
2022 * @param vs validation state to free
2025 free_validation_state (struct ValidationState *vs)
2027 GNUNET_CONTAINER_multipeermap_remove (validation_map,
2030 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2034 GNUNET_PEERSTORE_store_cancel (vs->sc);
2037 GNUNET_free (vs->address);
2043 * Lookup neighbour record for peer @a pid.
2045 * @param pid neighbour to look for
2046 * @return NULL if we do not have this peer as a neighbour
2048 static struct Neighbour *
2049 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2051 return GNUNET_CONTAINER_multipeermap_get (neighbours,
2057 * Details about what to notify monitors about.
2062 * @deprecated To be discussed if we keep these...
2064 struct GNUNET_TIME_Absolute last_validation;
2065 struct GNUNET_TIME_Absolute valid_until;
2066 struct GNUNET_TIME_Absolute next_validation;
2069 * Current round-trip time estimate.
2071 struct GNUNET_TIME_Relative rtt;
2074 * Connection status.
2076 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2081 uint32_t num_msg_pending;
2086 uint32_t num_bytes_pending;
2093 * Free a @dvh. Callers MAY want to check if this was the last path to the
2094 * `target`, and if so call #free_dv_route to also free the associated DV
2095 * entry in #dv_routes (if not, the associated scheduler job should eventually
2098 * @param dvh hop to free
2101 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2103 struct Neighbour *n = dvh->next_hop;
2104 struct DistanceVector *dv = dvh->dv;
2106 GNUNET_CONTAINER_MDLL_remove (neighbour,
2110 GNUNET_CONTAINER_MDLL_remove (dv,
2119 * Free entry in #dv_routes. First frees all hops to the target, and
2120 * if there are no entries left, frees @a dv as well.
2122 * @param dv route to free
2125 free_dv_route (struct DistanceVector *dv)
2127 struct DistanceVectorHop *dvh;
2129 while (NULL != (dvh = dv->dv_head))
2130 free_distance_vector_hop (dvh);
2131 if (NULL == dv->dv_head)
2133 GNUNET_assert (GNUNET_YES ==
2134 GNUNET_CONTAINER_multipeermap_remove (dv_routes,
2137 if (NULL != dv->timeout_task)
2138 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2145 * Notify monitor @a tc about an event. That @a tc
2146 * cares about the event has already been checked.
2148 * Send @a tc information in @a me about a @a peer's status with
2149 * respect to some @a address to all monitors that care.
2151 * @param tc monitor to inform
2152 * @param peer peer the information is about
2153 * @param address address the information is about
2154 * @param nt network type associated with @a address
2155 * @param me detailed information to transmit
2158 notify_monitor (struct TransportClient *tc,
2159 const struct GNUNET_PeerIdentity *peer,
2160 const char *address,
2161 enum GNUNET_NetworkType nt,
2162 const struct MonitorEvent *me)
2164 struct GNUNET_MQ_Envelope *env;
2165 struct GNUNET_TRANSPORT_MonitorData *md;
2166 size_t addr_len = strlen (address) + 1;
2168 env = GNUNET_MQ_msg_extra (md,
2170 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2171 md->nt = htonl ((uint32_t) nt);
2173 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2174 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2175 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2176 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2177 md->cs = htonl ((uint32_t) me->cs);
2178 md->num_msg_pending = htonl (me->num_msg_pending);
2179 md->num_bytes_pending = htonl (me->num_bytes_pending);
2183 GNUNET_MQ_send (tc->mq,
2189 * Send information in @a me about a @a peer's status with respect
2190 * to some @a address to all monitors that care.
2192 * @param peer peer the information is about
2193 * @param address address the information is about
2194 * @param nt network type associated with @a address
2195 * @param me detailed information to transmit
2198 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2199 const char *address,
2200 enum GNUNET_NetworkType nt,
2201 const struct MonitorEvent *me)
2203 for (struct TransportClient *tc = clients_head;
2207 if (CT_MONITOR != tc->type)
2209 if (tc->details.monitor.one_shot)
2211 if ( (0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2212 (0 != GNUNET_memcmp (&tc->details.monitor.peer,
2225 * Called whenever a client connects. Allocates our
2226 * data structures associated with that client.
2228 * @param cls closure, NULL
2229 * @param client identification of the client
2230 * @param mq message queue for the client
2231 * @return our `struct TransportClient`
2234 client_connect_cb (void *cls,
2235 struct GNUNET_SERVICE_Client *client,
2236 struct GNUNET_MQ_Handle *mq)
2238 struct TransportClient *tc;
2241 tc = GNUNET_new (struct TransportClient);
2242 tc->client = client;
2244 GNUNET_CONTAINER_DLL_insert (clients_head,
2247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2248 "Client %p connected\n",
2257 * @param rc data structure to free
2260 free_reassembly_context (struct ReassemblyContext *rc)
2262 struct Neighbour *n = rc->neighbour;
2264 GNUNET_assert (rc ==
2265 GNUNET_CONTAINER_heap_remove_node (rc->hn));
2266 GNUNET_assert (GNUNET_OK ==
2267 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2275 * Task run to clean up reassembly context of a neighbour that have expired.
2277 * @param cls a `struct Neighbour`
2280 reassembly_cleanup_task (void *cls)
2282 struct Neighbour *n = cls;
2283 struct ReassemblyContext *rc;
2285 n->reassembly_timeout_task = NULL;
2286 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2288 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout).rel_value_us)
2290 free_reassembly_context (rc);
2293 GNUNET_assert (NULL == n->reassembly_timeout_task);
2294 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2295 &reassembly_cleanup_task,
2303 * function called to #free_reassembly_context().
2307 * @param value a `struct ReassemblyContext` to free
2308 * @return #GNUNET_OK (continue iteration)
2311 free_reassembly_cb (void *cls,
2312 const struct GNUNET_ShortHashCode *key,
2315 struct ReassemblyContext *rc = value;
2319 free_reassembly_context (rc);
2325 * Release memory used by @a neighbour.
2327 * @param neighbour neighbour entry to free
2330 free_neighbour (struct Neighbour *neighbour)
2332 struct DistanceVectorHop *dvh;
2334 GNUNET_assert (NULL == neighbour->queue_head);
2335 GNUNET_assert (GNUNET_YES ==
2336 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2339 if (NULL != neighbour->timeout_task)
2340 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2341 if (NULL != neighbour->reassembly_map)
2343 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2344 &free_reassembly_cb,
2346 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2347 neighbour->reassembly_map = NULL;
2348 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2349 neighbour->reassembly_heap = NULL;
2351 while (NULL != (dvh = neighbour->dv_head))
2353 struct DistanceVector *dv = dvh->dv;
2355 free_distance_vector_hop (dvh);
2356 if (NULL == dv->dv_head)
2359 if (NULL != neighbour->reassembly_timeout_task)
2360 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2361 GNUNET_free (neighbour);
2366 * Send message to CORE clients that we lost a connection.
2368 * @param tc client to inform (must be CORE client)
2369 * @param pid peer the connection is for
2370 * @param quota_out current quota for the peer
2373 core_send_connect_info (struct TransportClient *tc,
2374 const struct GNUNET_PeerIdentity *pid,
2375 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2377 struct GNUNET_MQ_Envelope *env;
2378 struct ConnectInfoMessage *cim;
2380 GNUNET_assert (CT_CORE == tc->type);
2381 env = GNUNET_MQ_msg (cim,
2382 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2383 cim->quota_out = quota_out;
2385 GNUNET_MQ_send (tc->mq,
2391 * Send message to CORE clients that we gained a connection
2393 * @param pid peer the queue was for
2394 * @param quota_out current quota for the peer
2397 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2398 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2400 for (struct TransportClient *tc = clients_head;
2404 if (CT_CORE != tc->type)
2406 core_send_connect_info (tc,
2414 * Send message to CORE clients that we lost a connection.
2416 * @param pid peer the connection was for
2419 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2421 for (struct TransportClient *tc = clients_head;
2425 struct GNUNET_MQ_Envelope *env;
2426 struct DisconnectInfoMessage *dim;
2428 if (CT_CORE != tc->type)
2430 env = GNUNET_MQ_msg (dim,
2431 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2433 GNUNET_MQ_send (tc->mq,
2440 * We believe we are ready to transmit a message on a queue. Double-checks
2441 * with the queue's "tracker_out" and then gives the message to the
2442 * communicator for transmission (updating the tracker, and re-scheduling
2443 * itself if applicable).
2445 * @param cls the `struct Queue` to process transmissions for
2448 transmit_on_queue (void *cls);
2452 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2453 * we should run immediately or if the message queue is empty.
2454 * Test for no task being added AND queue not being empty to
2455 * transmit immediately afterwards! This function must only
2456 * be called if the message queue is non-empty!
2458 * @param queue the queue to do scheduling for
2461 schedule_transmit_on_queue (struct Queue *queue)
2463 struct Neighbour *n = queue->neighbour;
2464 struct PendingMessage *pm = n->pending_msg_head;
2465 struct GNUNET_TIME_Relative out_delay;
2468 GNUNET_assert (NULL != pm);
2469 if (queue->tc->details.communicator.total_queue_length >=
2470 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2472 GNUNET_STATISTICS_update (GST_stats,
2473 "# Transmission throttled due to communicator queue limit",
2478 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2480 GNUNET_STATISTICS_update (GST_stats,
2481 "# Transmission throttled due to queue queue limit",
2487 wsize = (0 == queue->mtu)
2488 ? pm->bytes_msg /* FIXME: add overheads? */
2490 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out,
2492 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (pm->next_attempt),
2494 if (0 == out_delay.rel_value_us)
2495 return; /* we should run immediately! */
2496 /* queue has changed since we were scheduled, reschedule again */
2497 queue->transmit_task
2498 = GNUNET_SCHEDULER_add_delayed (out_delay,
2501 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2502 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2503 "Next transmission on queue `%s' in %s (high delay)\n",
2505 GNUNET_STRINGS_relative_time_to_string (out_delay,
2508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2509 "Next transmission on queue `%s' in %s\n",
2511 GNUNET_STRINGS_relative_time_to_string (out_delay,
2519 * @param queue the queue to free
2522 free_queue (struct Queue *queue)
2524 struct Neighbour *neighbour = queue->neighbour;
2525 struct TransportClient *tc = queue->tc;
2526 struct MonitorEvent me = {
2527 .cs = GNUNET_TRANSPORT_CS_DOWN,
2528 .rtt = GNUNET_TIME_UNIT_FOREVER_REL
2530 struct QueueEntry *qe;
2533 if (NULL != queue->transmit_task)
2535 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2536 queue->transmit_task = NULL;
2538 GNUNET_CONTAINER_MDLL_remove (neighbour,
2539 neighbour->queue_head,
2540 neighbour->queue_tail,
2542 GNUNET_CONTAINER_MDLL_remove (client,
2543 tc->details.communicator.queue_head,
2544 tc->details.communicator.queue_tail,
2546 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >= tc->details.communicator.total_queue_length);
2547 while (NULL != (qe = queue->queue_head))
2549 GNUNET_CONTAINER_DLL_remove (queue->queue_head,
2552 queue->queue_length--;
2553 tc->details.communicator.total_queue_length--;
2556 GNUNET_assert (0 == queue->queue_length);
2558 (COMMUNICATOR_TOTAL_QUEUE_LIMIT < tc->details.communicator.total_queue_length) )
2560 /* Communicator dropped below threshold, resume all queues */
2561 GNUNET_STATISTICS_update (GST_stats,
2562 "# Transmission throttled due to communicator queue limit",
2565 for (struct Queue *s = tc->details.communicator.queue_head;
2568 schedule_transmit_on_queue (s);
2570 notify_monitors (&neighbour->pid,
2574 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2575 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2576 GNUNET_free (queue);
2577 if (NULL == neighbour->queue_head)
2579 cores_send_disconnect_info (&neighbour->pid);
2580 free_neighbour (neighbour);
2588 * @param ale address list entry to free
2591 free_address_list_entry (struct AddressListEntry *ale)
2593 struct TransportClient *tc = ale->tc;
2595 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2596 tc->details.communicator.addr_tail,
2598 if (NULL != ale->sc)
2600 GNUNET_PEERSTORE_store_cancel (ale->sc);
2603 if (NULL != ale->st)
2605 GNUNET_SCHEDULER_cancel (ale->st);
2613 * Stop the peer request in @a value.
2615 * @param cls a `struct TransportClient` that no longer makes the request
2616 * @param pid the peer's identity
2617 * @param value a `struct PeerRequest`
2618 * @return #GNUNET_YES (always)
2621 stop_peer_request (void *cls,
2622 const struct GNUNET_PeerIdentity *pid,
2625 struct TransportClient *tc = cls;
2626 struct PeerRequest *pr = value;
2628 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2629 GNUNET_assert (GNUNET_YES ==
2630 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2640 * Called whenever a client is disconnected. Frees our
2641 * resources associated with that client.
2643 * @param cls closure, NULL
2644 * @param client identification of the client
2645 * @param app_ctx our `struct TransportClient`
2648 client_disconnect_cb (void *cls,
2649 struct GNUNET_SERVICE_Client *client,
2652 struct TransportClient *tc = app_ctx;
2655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2656 "Client %p disconnected, cleaning up.\n",
2658 GNUNET_CONTAINER_DLL_remove (clients_head,
2667 struct PendingMessage *pm;
2669 while (NULL != (pm = tc->details.core.pending_msg_head))
2671 GNUNET_CONTAINER_MDLL_remove (client,
2672 tc->details.core.pending_msg_head,
2673 tc->details.core.pending_msg_tail,
2681 case CT_COMMUNICATOR:
2684 struct AddressListEntry *ale;
2686 while (NULL != (q = tc->details.communicator.queue_head))
2688 while (NULL != (ale = tc->details.communicator.addr_head))
2689 free_address_list_entry (ale);
2690 GNUNET_free (tc->details.communicator.address_prefix);
2693 case CT_APPLICATION:
2694 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2697 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2705 * Iterator telling new CORE client about all existing
2706 * connections to peers.
2708 * @param cls the new `struct TransportClient`
2709 * @param pid a connected peer
2710 * @param value the `struct Neighbour` with more information
2711 * @return #GNUNET_OK (continue to iterate)
2714 notify_client_connect_info (void *cls,
2715 const struct GNUNET_PeerIdentity *pid,
2718 struct TransportClient *tc = cls;
2719 struct Neighbour *neighbour = value;
2721 core_send_connect_info (tc,
2723 neighbour->quota_out);
2729 * Initialize a "CORE" client. We got a start message from this
2730 * client, so add it to the list of clients for broadcasting of
2733 * @param cls the client
2734 * @param start the start message that was sent
2737 handle_client_start (void *cls,
2738 const struct StartMessage *start)
2740 struct TransportClient *tc = cls;
2743 options = ntohl (start->options);
2744 if ( (0 != (1 & options)) &&
2746 GNUNET_memcmp (&start->self,
2747 &GST_my_identity)) )
2749 /* client thinks this is a different peer, reject */
2751 GNUNET_SERVICE_client_drop (tc->client);
2754 if (CT_NONE != tc->type)
2757 GNUNET_SERVICE_client_drop (tc->client);
2761 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2762 ¬ify_client_connect_info,
2764 GNUNET_SERVICE_client_continue (tc->client);
2769 * Client asked for transmission to a peer. Process the request.
2771 * @param cls the client
2772 * @param obm the send message that was sent
2775 check_client_send (void *cls,
2776 const struct OutboundMessage *obm)
2778 struct TransportClient *tc = cls;
2780 const struct GNUNET_MessageHeader *obmm;
2782 if (CT_CORE != tc->type)
2785 return GNUNET_SYSERR;
2787 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2788 if (size < sizeof (struct GNUNET_MessageHeader))
2791 return GNUNET_SYSERR;
2793 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2794 if (size != ntohs (obmm->size))
2797 return GNUNET_SYSERR;
2804 * Free fragment tree below @e root, excluding @e root itself.
2806 * @param root root of the tree to free
2809 free_fragment_tree (struct PendingMessage *root)
2811 struct PendingMessage *frag;
2813 while (NULL != (frag = root->head_frag))
2815 free_fragment_tree (frag);
2816 GNUNET_CONTAINER_MDLL_remove (frag,
2826 * Release memory associated with @a pm and remove @a pm from associated
2827 * data structures. @a pm must be a top-level pending message and not
2828 * a fragment in the tree. The entire tree is freed (if applicable).
2830 * @param pm the pending message to free
2833 free_pending_message (struct PendingMessage *pm)
2835 struct TransportClient *tc = pm->client;
2836 struct Neighbour *target = pm->target;
2840 GNUNET_CONTAINER_MDLL_remove (client,
2841 tc->details.core.pending_msg_head,
2842 tc->details.core.pending_msg_tail,
2845 GNUNET_CONTAINER_MDLL_remove (neighbour,
2846 target->pending_msg_head,
2847 target->pending_msg_tail,
2849 free_fragment_tree (pm);
2850 GNUNET_free_non_null (pm->bpm);
2856 * Send a response to the @a pm that we have processed a
2857 * "send" request with status @a success. We
2858 * transmitted @a bytes_physical on the actual wire.
2859 * Sends a confirmation to the "core" client responsible
2860 * for the original request and free's @a pm.
2862 * @param pm handle to the original pending message
2863 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2864 * for transmission failure
2865 * @param bytes_physical amount of bandwidth consumed
2868 client_send_response (struct PendingMessage *pm,
2870 uint32_t bytes_physical)
2872 struct TransportClient *tc = pm->client;
2873 struct Neighbour *target = pm->target;
2874 struct GNUNET_MQ_Envelope *env;
2875 struct SendOkMessage *som;
2879 env = GNUNET_MQ_msg (som,
2880 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2881 som->success = htonl ((uint32_t) success);
2882 som->bytes_msg = htons (pm->bytes_msg);
2883 som->bytes_physical = htonl (bytes_physical);
2884 som->peer = target->pid;
2885 GNUNET_MQ_send (tc->mq,
2888 free_pending_message (pm);
2893 * Checks the message queue for a neighbour for messages that have timed
2894 * out and purges them.
2896 * @param cls a `struct Neighbour`
2899 check_queue_timeouts (void *cls)
2901 struct Neighbour *n = cls;
2902 struct PendingMessage *pm;
2903 struct GNUNET_TIME_Absolute now;
2904 struct GNUNET_TIME_Absolute earliest_timeout;
2906 n->timeout_task = NULL;
2907 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2908 now = GNUNET_TIME_absolute_get ();
2909 for (struct PendingMessage *pos = n->pending_msg_head;
2913 pm = pos->next_neighbour;
2914 if (pos->timeout.abs_value_us <= now.abs_value_us)
2916 GNUNET_STATISTICS_update (GST_stats,
2917 "# messages dropped (timeout before confirmation)",
2920 client_send_response (pm,
2925 earliest_timeout = GNUNET_TIME_absolute_min (earliest_timeout,
2928 n->earliest_timeout = earliest_timeout;
2929 if (NULL != n->pending_msg_head)
2930 n->timeout_task = GNUNET_SCHEDULER_add_at (earliest_timeout,
2931 &check_queue_timeouts,
2937 * Client asked for transmission to a peer. Process the request.
2939 * @param cls the client
2940 * @param obm the send message that was sent
2943 handle_client_send (void *cls,
2944 const struct OutboundMessage *obm)
2946 struct TransportClient *tc = cls;
2947 struct PendingMessage *pm;
2948 const struct GNUNET_MessageHeader *obmm;
2949 struct Neighbour *target;
2953 GNUNET_assert (CT_CORE == tc->type);
2954 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2955 bytes_msg = ntohs (obmm->size);
2956 target = lookup_neighbour (&obm->peer);
2959 /* Failure: don't have this peer as a neighbour (anymore).
2960 Might have gone down asynchronously, so this is NOT
2961 a protocol violation by CORE. Still count the event,
2962 as this should be rare. */
2963 struct GNUNET_MQ_Envelope *env;
2964 struct SendOkMessage *som;
2966 env = GNUNET_MQ_msg (som,
2967 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2968 som->success = htonl (GNUNET_SYSERR);
2969 som->bytes_msg = htonl (bytes_msg);
2970 som->bytes_physical = htonl (0);
2971 som->peer = obm->peer;
2972 GNUNET_MQ_send (tc->mq,
2974 GNUNET_SERVICE_client_continue (tc->client);
2975 GNUNET_STATISTICS_update (GST_stats,
2976 "# messages dropped (neighbour unknown)",
2981 was_empty = (NULL == target->pending_msg_head);
2982 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2984 pm->target = target;
2985 pm->bytes_msg = bytes_msg;
2986 pm->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2990 GNUNET_CONTAINER_MDLL_insert (neighbour,
2991 target->pending_msg_head,
2992 target->pending_msg_tail,
2994 GNUNET_CONTAINER_MDLL_insert (client,
2995 tc->details.core.pending_msg_head,
2996 tc->details.core.pending_msg_tail,
2998 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3000 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3001 if (NULL != target->timeout_task)
3002 GNUNET_SCHEDULER_cancel (target->timeout_task);
3003 target->timeout_task
3004 = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3005 &check_queue_timeouts,
3009 return; /* all queues must already be busy */
3010 for (struct Queue *queue = target->queue_head;
3012 queue = queue->next_neighbour)
3014 /* try transmission on any queue that is idle */
3015 if (NULL == queue->transmit_task)
3016 queue->transmit_task = GNUNET_SCHEDULER_add_now (&transmit_on_queue,
3023 * Communicator started. Test message is well-formed.
3025 * @param cls the client
3026 * @param cam the send message that was sent
3029 check_communicator_available (void *cls,
3030 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3032 struct TransportClient *tc = cls;
3035 if (CT_NONE != tc->type)
3038 return GNUNET_SYSERR;
3040 tc->type = CT_COMMUNICATOR;
3041 size = ntohs (cam->header.size) - sizeof (*cam);
3043 return GNUNET_OK; /* receive-only communicator */
3044 GNUNET_MQ_check_zero_termination (cam);
3050 * Communicator started. Process the request.
3052 * @param cls the client
3053 * @param cam the send message that was sent
3056 handle_communicator_available (void *cls,
3057 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3059 struct TransportClient *tc = cls;
3062 size = ntohs (cam->header.size) - sizeof (*cam);
3064 return; /* receive-only communicator */
3065 tc->details.communicator.address_prefix
3066 = GNUNET_strdup ((const char *) &cam[1]);
3067 tc->details.communicator.cc
3068 = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3069 GNUNET_SERVICE_client_continue (tc->client);
3074 * Communicator requests backchannel transmission. Check the request.
3076 * @param cls the client
3077 * @param cb the send message that was sent
3078 * @return #GNUNET_OK if message is well-formed
3081 check_communicator_backchannel (void *cls,
3082 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3084 const struct GNUNET_MessageHeader *inbox;
3090 msize = ntohs (cb->header.size) - sizeof (*cb);
3091 if (UINT16_MAX - msize >
3092 sizeof (struct TransportBackchannelEncapsulationMessage) +
3093 sizeof (struct TransportBackchannelRequestPayload) )
3096 return GNUNET_SYSERR;
3098 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3099 isize = ntohs (inbox->size);
3103 return GNUNET_SYSERR;
3105 is = (const char *) inbox;
3108 GNUNET_assert (msize > 0);
3109 if ('\0' != is[msize-1])
3112 return GNUNET_SYSERR;
3119 * Remove memory used by expired ephemeral keys.
3124 expire_ephemerals (void *cls)
3126 struct EphemeralCacheEntry *ece;
3129 ephemeral_task = NULL;
3130 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3132 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us)
3134 free_ephemeral (ece);
3137 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3146 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3147 * one, cache it and return it.
3149 * @param pid peer to look up ephemeral for
3150 * @param private_key[out] set to the private key
3151 * @param ephemeral_key[out] set to the key
3152 * @param ephemeral_sender_sig[out] set to the signature
3153 * @param ephemeral_validity[out] set to the validity expiration time
3156 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3157 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3158 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3159 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3160 struct GNUNET_TIME_Absolute *ephemeral_validity)
3162 struct EphemeralCacheEntry *ece;
3163 struct EphemeralConfirmation ec;
3165 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map,
3167 if ( (NULL != ece) &&
3168 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us) )
3170 free_ephemeral (ece);
3175 ece = GNUNET_new (struct EphemeralCacheEntry);
3177 ece->ephemeral_validity = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3178 EPHEMERAL_VALIDITY);
3179 GNUNET_assert (GNUNET_OK ==
3180 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3181 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key,
3182 &ece->ephemeral_key);
3183 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3184 ec.purpose.size = htonl (sizeof (ec));
3186 ec.ephemeral_key = ece->ephemeral_key;
3187 GNUNET_assert (GNUNET_OK ==
3188 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3191 ece->hn = GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3193 ece->ephemeral_validity.abs_value_us);
3194 GNUNET_assert (GNUNET_OK ==
3195 GNUNET_CONTAINER_multipeermap_put (ephemeral_map,
3198 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3199 if (NULL == ephemeral_task)
3200 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3204 *private_key = ece->private_key;
3205 *ephemeral_key = ece->ephemeral_key;
3206 *ephemeral_sender_sig = ece->sender_sig;
3207 *ephemeral_validity = ece->ephemeral_validity;
3212 * We need to transmit @a hdr to @a target. If necessary, this may
3213 * involve DV routing or even broadcasting and fragmentation.
3215 * @param target peer to receive @a hdr
3216 * @param hdr header of the message to route
3219 route_message (const struct GNUNET_PeerIdentity *target,
3220 struct GNUNET_MessageHeader *hdr)
3222 // FIXME: this one is tricky:
3223 // - we could try a direct, reliable channel
3224 // - if that is unavailable / for load balancing, we may try:
3225 // * multiple (?) direct unreliable channels - depending on loss rate?
3226 // * some (?) DV channels - if above unavailable / too lossy?
3227 // * _random_ other peers ("broadcasting") in hope of *discovering*
3228 // a path back! - if all else fails
3229 // => need more on DV first!
3231 // FIXME: send hdr to target, free hdr (possibly using DV, possibly broadcasting)
3237 * Structure of the key material used to encrypt backchannel messages.
3239 struct BackchannelKeyState
3242 * State of our block cipher.
3244 gcry_cipher_hd_t cipher;
3247 * Actual key material.
3252 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3254 struct GNUNET_CRYPTO_AuthKey hmac_key;
3257 * Symmetric key to use for encryption.
3259 char aes_key[256/8];
3262 * Counter value to use during setup.
3264 char aes_ctr[128/8];
3271 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3272 const struct GNUNET_ShortHashCode *iv,
3273 struct BackchannelKeyState *key)
3275 /* must match #dh_key_derive_eph_pub */
3276 GNUNET_assert (GNUNET_YES ==
3277 GNUNET_CRYPTO_kdf (&key->material,
3278 sizeof (key->material),
3279 "transport-backchannel-key",
3280 strlen ("transport-backchannel-key"),
3285 gcry_cipher_open (&key->cipher,
3286 GCRY_CIPHER_AES256 /* low level: go for speed */,
3287 GCRY_CIPHER_MODE_CTR,
3289 gcry_cipher_setkey (key->cipher,
3290 &key->material.aes_key,
3291 sizeof (key->material.aes_key));
3292 gcry_cipher_setctr (key->cipher,
3293 &key->material.aes_ctr,
3294 sizeof (key->material.aes_ctr));
3299 * Derive backchannel encryption key material from @a priv_ephemeral
3300 * and @a target and @a iv.
3302 * @param priv_ephemeral ephemeral private key to use
3303 * @param target the target peer to encrypt to
3304 * @param iv unique IV to use
3305 * @param key[out] set to the key material
3308 dh_key_derive_eph_pid (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3309 const struct GNUNET_PeerIdentity *target,
3310 const struct GNUNET_ShortHashCode *iv,
3311 struct BackchannelKeyState *key)
3313 struct GNUNET_HashCode km;
3315 GNUNET_assert (GNUNET_YES ==
3316 GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3317 &target->public_key,
3319 bc_setup_key_state_from_km (&km,
3326 * Derive backchannel encryption key material from #GST_my_private_key
3327 * and @a pub_ephemeral and @a iv.
3329 * @param priv_ephemeral ephemeral private key to use
3330 * @param target the target peer to encrypt to
3331 * @param iv unique IV to use
3332 * @param key[out] set to the key material
3335 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3336 const struct GNUNET_ShortHashCode *iv,
3337 struct BackchannelKeyState *key)
3339 struct GNUNET_HashCode km;
3341 GNUNET_assert (GNUNET_YES ==
3342 GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3345 bc_setup_key_state_from_km (&km,
3352 * Do HMAC calculation for backchannel messages over @a data using key
3353 * material from @a key.
3355 * @param key key material (from DH)
3356 * @param hmac[out] set to the HMAC
3357 * @param data data to perform HMAC calculation over
3358 * @param data_size number of bytes in @a data
3361 bc_hmac (const struct BackchannelKeyState *key,
3362 struct GNUNET_HashCode *hmac,
3366 GNUNET_CRYPTO_hmac (&key->material.hmac_key,
3374 * Perform backchannel encryption using symmetric secret in @a key
3375 * to encrypt data from @a in to @a dst.
3377 * @param key[in,out] key material to use
3378 * @param dst where to write the result
3379 * @param in input data to encrypt (plaintext)
3380 * @param in_size number of bytes of input in @a in and available at @a dst
3383 bc_encrypt (struct BackchannelKeyState *key,
3389 gcry_cipher_encrypt (key->cipher,
3398 * Perform backchannel encryption using symmetric secret in @a key
3399 * to encrypt data from @a in to @a dst.
3401 * @param key[in,out] key material to use
3402 * @param ciph cipher text to decrypt
3403 * @param out[out] output data to generate (plaintext)
3404 * @param out_size number of bytes of input in @a ciph and available in @a out
3407 bc_decrypt (struct BackchannelKeyState *key,
3413 gcry_cipher_decrypt (key->cipher,
3422 * Clean up key material in @a key.
3424 * @param key key material to clean up (memory must not be free'd!)
3427 bc_key_clean (struct BackchannelKeyState *key)
3429 gcry_cipher_close (key->cipher);
3430 GNUNET_CRYPTO_zero_keys (&key->material,
3431 sizeof (key->material));
3436 * Communicator requests backchannel transmission. Process the request.
3438 * @param cls the client
3439 * @param cb the send message that was sent
3442 handle_communicator_backchannel (void *cls,
3443 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3445 struct TransportClient *tc = cls;
3446 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3447 struct GNUNET_TIME_Absolute ephemeral_validity;
3448 struct TransportBackchannelEncapsulationMessage *enc;
3449 struct TransportBackchannelRequestPayload ppay;
3450 struct BackchannelKeyState key;
3454 /* encapsulate and encrypt message */
3455 msize = ntohs (cb->header.size) - sizeof (*cb) + sizeof (struct TransportBackchannelRequestPayload);
3456 enc = GNUNET_malloc (sizeof (*enc) + msize);
3457 enc->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3458 enc->header.size = htons (sizeof (*enc) + msize);
3459 enc->target = cb->pid;
3460 lookup_ephemeral (&cb->pid,
3462 &enc->ephemeral_key,
3464 &ephemeral_validity);
3465 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3468 dh_key_derive_eph_pid (&private_key,
3472 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3473 ppay.monotonic_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3474 mpos = (char *) &enc[1];
3481 &mpos[sizeof (ppay)],
3482 ntohs (cb->header.size) - sizeof (*cb));
3486 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3487 bc_key_clean (&key);
3488 route_message (&cb->pid,
3490 GNUNET_SERVICE_client_continue (tc->client);
3495 * Address of our peer added. Test message is well-formed.
3497 * @param cls the client
3498 * @param aam the send message that was sent
3499 * @return #GNUNET_OK if message is well-formed
3502 check_add_address (void *cls,
3503 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3505 struct TransportClient *tc = cls;
3507 if (CT_COMMUNICATOR != tc->type)
3510 return GNUNET_SYSERR;
3512 GNUNET_MQ_check_zero_termination (aam);
3518 * Ask peerstore to store our address.
3520 * @param cls an `struct AddressListEntry *`
3523 store_pi (void *cls);
3527 * Function called when peerstore is done storing our address.
3529 * @param cls a `struct AddressListEntry`
3530 * @param success #GNUNET_YES if peerstore was successful
3533 peerstore_store_own_cb (void *cls,
3536 struct AddressListEntry *ale = cls;
3539 if (GNUNET_YES != success)
3540 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3541 "Failed to store our own address `%s' in peerstore!\n",
3543 /* refresh period is 1/4 of expiration time, that should be plenty
3544 without being excessive. */
3545 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3553 * Ask peerstore to store our address.
3555 * @param cls an `struct AddressListEntry *`
3558 store_pi (void *cls)
3560 struct AddressListEntry *ale = cls;
3563 struct GNUNET_TIME_Absolute expiration;
3566 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3567 GNUNET_HELLO_sign_address (ale->address,
3573 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3576 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3580 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3581 &peerstore_store_own_cb,
3584 if (NULL == ale->sc)
3586 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3587 "Failed to store our address `%s' with peerstore\n",
3589 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
3597 * Address of our peer added. Process the request.
3599 * @param cls the client
3600 * @param aam the send message that was sent
3603 handle_add_address (void *cls,
3604 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3606 struct TransportClient *tc = cls;
3607 struct AddressListEntry *ale;
3610 slen = ntohs (aam->header.size) - sizeof (*aam);
3611 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3613 ale->address = (const char *) &ale[1];
3614 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3615 ale->aid = aam->aid;
3616 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3620 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3621 tc->details.communicator.addr_tail,
3623 ale->st = GNUNET_SCHEDULER_add_now (&store_pi,
3625 GNUNET_SERVICE_client_continue (tc->client);
3630 * Address of our peer deleted. Process the request.
3632 * @param cls the client
3633 * @param dam the send message that was sent
3636 handle_del_address (void *cls,
3637 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3639 struct TransportClient *tc = cls;
3641 if (CT_COMMUNICATOR != tc->type)
3644 GNUNET_SERVICE_client_drop (tc->client);
3647 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3651 if (dam->aid != ale->aid)
3653 GNUNET_assert (ale->tc == tc);
3654 free_address_list_entry (ale);
3655 GNUNET_SERVICE_client_continue (tc->client);
3658 GNUNET_SERVICE_client_drop (tc->client);
3663 * Context from #handle_incoming_msg(). Closure for many
3664 * message handlers below.
3666 struct CommunicatorMessageContext
3669 * Which communicator provided us with the message.
3671 struct TransportClient *tc;
3674 * Additional information for flow control and about the sender.
3676 struct GNUNET_TRANSPORT_IncomingMessage im;
3679 * Number of hops the message has travelled (if DV-routed).
3680 * FIXME: make use of this in ACK handling!
3682 uint16_t total_hops;
3687 * Given an inbound message @a msg from a communicator @a cmc,
3688 * demultiplex it based on the type calling the right handler.
3690 * @param cmc context for demultiplexing
3691 * @param msg message to demultiplex
3694 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3695 const struct GNUNET_MessageHeader *msg);
3699 * Send ACK to communicator (if requested) and free @a cmc.
3701 * @param cmc context for which we are done handling the message
3704 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3706 if (0 != ntohl (cmc->im.fc_on))
3708 /* send ACK when done to communicator for flow control! */
3709 struct GNUNET_MQ_Envelope *env;
3710 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3712 env = GNUNET_MQ_msg (ack,
3713 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3714 ack->reserved = htonl (0);
3715 ack->fc_id = cmc->im.fc_id;
3716 ack->sender = cmc->im.sender;
3717 GNUNET_MQ_send (cmc->tc->mq,
3720 GNUNET_SERVICE_client_continue (cmc->tc->client);
3726 * Communicator gave us an unencapsulated message to pass as-is to
3727 * CORE. Process the request.
3729 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3730 * @param mh the message that was received
3733 handle_raw_message (void *cls,
3734 const struct GNUNET_MessageHeader *mh)
3736 struct CommunicatorMessageContext *cmc = cls;
3737 uint16_t size = ntohs (mh->size);
3739 if ( (size > UINT16_MAX - sizeof (struct InboundMessage)) ||
3740 (size < sizeof (struct GNUNET_MessageHeader)) )
3742 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3745 finish_cmc_handling (cmc);
3746 GNUNET_SERVICE_client_drop (client);
3749 /* Forward to all CORE clients */
3750 for (struct TransportClient *tc = clients_head;
3754 struct GNUNET_MQ_Envelope *env;
3755 struct InboundMessage *im;
3757 if (CT_CORE != tc->type)
3759 env = GNUNET_MQ_msg_extra (im,
3761 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3762 im->peer = cmc->im.sender;
3766 GNUNET_MQ_send (tc->mq,
3769 /* FIXME: consider doing this _only_ once the message
3770 was drained from the CORE MQs to extend flow control to CORE!
3771 (basically, increment counter in cmc, decrement on MQ send continuation! */
3772 finish_cmc_handling (cmc);
3777 * Communicator gave us a fragment box. Check the message.
3779 * @param cls a `struct CommunicatorMessageContext`
3780 * @param fb the send message that was sent
3781 * @return #GNUNET_YES if message is well-formed
3784 check_fragment_box (void *cls,
3785 const struct TransportFragmentBox *fb)
3787 uint16_t size = ntohs (fb->header.size);
3788 uint16_t bsize = size - sizeof (*fb);
3792 GNUNET_break_op (0);
3793 return GNUNET_SYSERR;
3795 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
3797 GNUNET_break_op (0);
3798 return GNUNET_SYSERR;
3800 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
3802 GNUNET_break_op (0);
3803 return GNUNET_SYSERR;
3810 * Generate a fragment acknowledgement for an @a rc.
3812 * @param rc context to generate ACK for, @a rc ACK state is reset
3815 send_fragment_ack (struct ReassemblyContext *rc)
3817 struct TransportFragmentAckMessage *ack;
3819 ack = GNUNET_new (struct TransportFragmentAckMessage);
3820 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
3821 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
3822 ack->frag_uuid = htonl (rc->frag_uuid);
3823 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
3824 ack->msg_uuid = rc->msg_uuid;
3825 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
3826 if (0 == rc->msg_missing)
3827 ack->reassembly_timeout
3828 = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
3830 ack->reassembly_timeout
3831 = GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
3832 route_message (&rc->neighbour->pid,
3834 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
3836 rc->extra_acks = 0LLU;
3841 * Communicator gave us a fragment. Process the request.
3843 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3844 * @param fb the message that was received
3847 handle_fragment_box (void *cls,
3848 const struct TransportFragmentBox *fb)
3850 struct CommunicatorMessageContext *cmc = cls;
3851 struct Neighbour *n;
3852 struct ReassemblyContext *rc;
3853 const struct GNUNET_MessageHeader *msg;
3859 struct GNUNET_TIME_Relative cdelay;
3862 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
3866 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3869 finish_cmc_handling (cmc);
3870 GNUNET_SERVICE_client_drop (client);
3873 if (NULL == n->reassembly_map)
3875 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8,
3877 n->reassembly_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3878 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
3879 &reassembly_cleanup_task,
3882 msize = ntohs (fb->msg_size);
3883 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map,
3887 rc = GNUNET_malloc (sizeof (*rc) +
3888 msize + /* reassembly payload buffer */
3889 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
3890 rc->msg_uuid = fb->msg_uuid;
3892 rc->msg_size = msize;
3893 rc->reassembly_timeout = GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
3894 rc->last_frag = GNUNET_TIME_absolute_get ();
3895 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
3897 rc->reassembly_timeout.abs_value_us);
3898 GNUNET_assert (GNUNET_OK ==
3899 GNUNET_CONTAINER_multishortmap_put (n->reassembly_map,
3902 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3903 target = (char *) &rc[1];
3904 rc->bitfield = (uint8_t *) (target + rc->msg_size);
3905 rc->msg_missing = rc->msg_size;
3909 target = (char *) &rc[1];
3911 if (msize != rc->msg_size)
3914 finish_cmc_handling (cmc);
3919 fsize = ntohs (fb->header.size) - sizeof (*fb);
3920 frag_off = ntohs (fb->frag_off);
3921 memcpy (&target[frag_off],
3924 /* update bitfield and msg_missing */
3925 for (unsigned int i=frag_off;i<frag_off+fsize;i++)
3927 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
3929 rc->bitfield[i / 8] |= (1 << (i % 8));
3934 /* Compute cummulative ACK */
3935 frag_uuid = ntohl (fb->frag_uuid);
3936 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
3937 cdelay = GNUNET_TIME_relative_multiply (cdelay,
3939 rc->last_frag = GNUNET_TIME_absolute_get ();
3940 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay,
3942 ack_now = GNUNET_NO;
3943 if (0 == rc->num_acks)
3945 /* case one: first ack */
3946 rc->frag_uuid = frag_uuid;
3947 rc->extra_acks = 0LLU;
3950 else if ( (frag_uuid >= rc->frag_uuid) &&
3951 (frag_uuid <= rc->frag_uuid + 64) )
3953 /* case two: ack fits after existing min UUID */
3954 if ( (frag_uuid == rc->frag_uuid) ||
3955 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))) )
3957 /* duplicate fragment, ack now! */
3958 ack_now = GNUNET_YES;
3962 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
3966 else if ( (rc->frag_uuid > frag_uuid) &&
3967 ( ( (rc->frag_uuid == frag_uuid + 64) &&
3968 (0 == rc->extra_acks) ) ||
3969 ( (rc->frag_uuid < frag_uuid + 64) &&
3970 (rc->extra_acks == (rc->extra_acks & ~ ((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))) ) ) )
3972 /* can fit ack by shifting extra acks and starting at
3973 frag_uid, test above esured that the bits we will
3974 shift 'extra_acks' by are all zero. */
3975 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
3976 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
3977 rc->frag_uuid = frag_uuid;
3980 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very aggressive. */
3981 ack_now = GNUNET_YES; /* maximum acks received */
3982 // FIXME: possibly also ACK based on RTT (but for that we'd need to
3983 // determine the queue used for the ACK first!)
3985 /* is reassembly complete? */
3986 if (0 != rc->msg_missing)
3989 send_fragment_ack (rc);
3990 finish_cmc_handling (cmc);
3993 /* reassembly is complete, verify result */
3994 msg = (const struct GNUNET_MessageHeader *) &rc[1];
3995 if (ntohs (msg->size) != rc->msg_size)
3998 free_reassembly_context (rc);
3999 finish_cmc_handling (cmc);
4002 /* successful reassembly */
4003 send_fragment_ack (rc);
4004 demultiplex_with_cmc (cmc,
4006 /* FIXME: really free here? Might be bad if fragments are still
4007 en-route and we forget that we finished this reassembly immediately!
4008 -> keep around until timeout?
4009 -> shorten timeout based on ACK? */
4010 free_reassembly_context (rc);
4015 * Check the @a fa against the fragments associated with @a pm.
4016 * If it matches, remove the matching fragments from the transmission
4019 * @param pm pending message to check against the ack
4020 * @param fa the ack that was received
4021 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4024 check_ack_against_pm (struct PendingMessage *pm,
4025 const struct TransportFragmentAckMessage *fa)
4028 struct PendingMessage *nxt;
4029 uint32_t fs = ntohl (fa->frag_uuid);
4030 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4033 for (struct PendingMessage *frag = pm->head_frag;
4037 const struct TransportFragmentBox *tfb
4038 = (const struct TransportFragmentBox *) &pm[1];
4039 uint32_t fu = ntohl (tfb->frag_uuid);
4041 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4042 nxt = frag->next_frag;
4043 /* Check for exact match or match in the 'xtra' bitmask */
4047 (0 != (1LLU << (fu - fs - 1) & xtra)) ) )
4050 free_fragment_tree (frag);
4058 * Communicator gave us a fragment acknowledgement. Process the request.
4060 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4061 * @param fa the message that was received
4064 handle_fragment_ack (void *cls,
4065 const struct TransportFragmentAckMessage *fa)
4067 struct CommunicatorMessageContext *cmc = cls;
4068 struct Neighbour *n;
4071 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
4075 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4078 finish_cmc_handling (cmc);
4079 GNUNET_SERVICE_client_drop (client);
4082 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4083 matched = GNUNET_NO;
4084 for (struct PendingMessage *pm = n->pending_msg_head;
4086 pm = pm->prev_neighbour)
4089 GNUNET_memcmp (&fa->msg_uuid,
4092 matched = GNUNET_YES;
4094 check_ack_against_pm (pm,
4097 struct GNUNET_TIME_Relative avg_ack_delay
4098 = GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4099 // FIXME: update RTT and other reliability data!
4100 // ISSUE: we don't know which of n's queues the message(s)
4101 // took (and in fact the different messages might have gone
4102 // over different queues and possibly over multiple).
4103 // => track queues with PendingMessages, and update RTT only if
4104 // the queue used is unique?
4105 // -> how can we get loss rates?
4106 // -> or, add extra state to Box and ACK to identify queue?
4107 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4108 // the queue with the fragment! (-> this logic must
4109 // be moved into check_ack_against_pm!)
4110 (void) avg_ack_delay;
4114 GNUNET_STATISTICS_update (GST_stats,
4115 "# FRAGMENT_ACKS dropped, no matching fragment",
4119 if (NULL == pm->head_frag)
4121 // if entire message is ACKed, handle that as well.
4122 // => clean up PM, any post actions?
4123 free_pending_message (pm);
4127 struct GNUNET_TIME_Relative reassembly_timeout
4128 = GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4129 // OPTIMIZE-FIXME: adjust retransmission strategy based on reassembly_timeout!
4130 (void) reassembly_timeout;
4134 if (GNUNET_NO == matched)
4136 GNUNET_STATISTICS_update (GST_stats,
4137 "# FRAGMENT_ACKS dropped, no matching pending message",
4141 finish_cmc_handling (cmc);
4146 * Communicator gave us a reliability box. Check the message.
4148 * @param cls a `struct CommunicatorMessageContext`
4149 * @param rb the send message that was sent
4150 * @return #GNUNET_YES if message is well-formed
4153 check_reliability_box (void *cls,
4154 const struct TransportReliabilityBox *rb)
4156 GNUNET_MQ_check_boxed_message (rb);
4162 * Communicator gave us a reliability box. Process the request.
4164 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4165 * @param rb the message that was received
4168 handle_reliability_box (void *cls,
4169 const struct TransportReliabilityBox *rb)
4171 struct CommunicatorMessageContext *cmc = cls;
4172 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &rb[1];
4174 if (0 == ntohl (rb->ack_countdown))
4176 struct TransportReliabilityAckMessage *ack;
4178 /* FIXME: implement cummulative ACKs and ack_countdown,
4179 then setting the avg_ack_delay field below: */
4180 ack = GNUNET_malloc (sizeof (*ack) +
4181 sizeof (struct GNUNET_ShortHashCode));
4182 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4183 ack->header.size = htons (sizeof (*ack) +
4184 sizeof (struct GNUNET_ShortHashCode));
4187 sizeof (struct GNUNET_ShortHashCode));
4188 route_message (&cmc->im.sender,
4191 /* continue with inner message */
4192 demultiplex_with_cmc (cmc,
4198 * Communicator gave us a reliability ack. Process the request.
4200 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4201 * @param ra the message that was received
4204 handle_reliability_ack (void *cls,
4205 const struct TransportReliabilityAckMessage *ra)
4207 struct CommunicatorMessageContext *cmc = cls;
4208 struct Neighbour *n;
4209 unsigned int n_acks;
4210 const struct GNUNET_ShortHashCode *msg_uuids;
4211 struct PendingMessage *nxt;
4214 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
4218 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4221 finish_cmc_handling (cmc);
4222 GNUNET_SERVICE_client_drop (client);
4225 n_acks = (ntohs (ra->header.size) - sizeof (*ra))
4226 / sizeof (struct GNUNET_ShortHashCode);
4227 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4229 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4230 matched = GNUNET_NO;
4231 for (struct PendingMessage *pm = n->pending_msg_head;
4237 nxt = pm->next_neighbour;
4238 in_list = GNUNET_NO;
4239 for (unsigned int i=0;i<n_acks;i++)
4242 GNUNET_memcmp (&msg_uuids[i],
4245 in_list = GNUNET_YES;
4248 if (GNUNET_NO == in_list)
4251 /* this pm was acked! */
4252 matched = GNUNET_YES;
4253 free_pending_message (pm);
4256 struct GNUNET_TIME_Relative avg_ack_delay
4257 = GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4258 // FIXME: update RTT and other reliability data!
4259 // ISSUE: we don't know which of n's queues the message(s)
4260 // took (and in fact the different messages might have gone
4261 // over different queues and possibly over multiple).
4262 // => track queues with PendingMessages, and update RTT only if
4263 // the queue used is unique?
4264 // -> how can we get loss rates?
4265 // -> or, add extra state to MSG and ACKs to identify queue?
4266 // -> if we do this, might just do the same for the avg_ack_delay!
4267 (void) avg_ack_delay;
4270 if (GNUNET_NO == matched)
4272 GNUNET_STATISTICS_update (GST_stats,
4273 "# FRAGMENT_ACKS dropped, no matching pending message",
4277 finish_cmc_handling (cmc);
4282 * Communicator gave us a backchannel encapsulation. Check the message.
4284 * @param cls a `struct CommunicatorMessageContext`
4285 * @param be the send message that was sent
4286 * @return #GNUNET_YES if message is well-formed
4289 check_backchannel_encapsulation (void *cls,
4290 const struct TransportBackchannelEncapsulationMessage *be)
4292 uint16_t size = ntohs (be->header.size);
4295 if (size - sizeof (*be) <
4296 sizeof (struct TransportBackchannelRequestPayload) +
4297 sizeof (struct GNUNET_MessageHeader) )
4299 GNUNET_break_op (0);
4300 return GNUNET_SYSERR;
4307 * Communicator gave us a backchannel encapsulation. Process the request.
4309 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4310 * @param be the message that was received
4313 handle_backchannel_encapsulation (void *cls,
4314 const struct TransportBackchannelEncapsulationMessage *be)
4316 struct CommunicatorMessageContext *cmc = cls;
4317 struct BackchannelKeyState key;
4318 struct GNUNET_HashCode hmac;
4322 if (0 != GNUNET_memcmp (&be->target,
4325 /* not for me, try to route to target */
4326 /* FIXME: someone needs to update be->distance! */
4327 /* FIXME: BE routing can be special, should we put all of this
4328 on 'route_message'? Maybe at least pass some more arguments? */
4329 route_message (&be->target,
4330 GNUNET_copy_message (&be->header));
4331 finish_cmc_handling (cmc);
4334 dh_key_derive_eph_pub (&be->ephemeral_key,
4337 hdr = (const char *) &be[1];
4338 hdr_len = ntohs (be->header.size) - sizeof (*be);
4344 GNUNET_memcmp (&hmac,
4347 /* HMAC missmatch, disard! */
4348 GNUNET_break_op (0);
4349 finish_cmc_handling (cmc);
4352 /* begin actual decryption */
4354 struct TransportBackchannelRequestPayload ppay;
4355 char body[hdr_len - sizeof (ppay)];
4357 GNUNET_assert (hdr_len >= sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4364 &hdr[sizeof (ppay)],
4365 hdr_len - sizeof (ppay));
4366 bc_key_clean (&key);
4367 // FIXME: verify signatures in ppay!
4368 // => check if ephemeral key is known & valid, if not
4369 // => verify sig, cache ephemeral key
4370 // => update monotonic_time of sender for replay detection
4372 // FIXME: forward to specified communicator!
4373 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4375 finish_cmc_handling (cmc);
4380 * Task called when we should check if any of the DV paths
4381 * we have learned to a target are due for garbage collection.
4383 * Collects stale paths, and possibly frees the entire DV
4384 * entry if no paths are left. Otherwise re-schedules itself.
4386 * @param cls a `struct DistanceVector`
4389 path_cleanup_cb (void *cls)
4391 struct DistanceVector *dv = cls;
4392 struct DistanceVectorHop *pos;
4394 dv->timeout_task = NULL;
4395 while (NULL != (pos = dv->dv_head))
4397 GNUNET_assert (dv == pos->dv);
4398 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4400 free_distance_vector_hop (pos);
4407 dv->timeout_task = GNUNET_SCHEDULER_add_at (pos->timeout,
4414 * We have learned a @a path through the network to some other peer, add it to
4415 * our DV data structure (returning #GNUNET_YES on success).
4417 * We do not add paths if we have a sufficient number of shorter
4418 * paths to this target already (returning #GNUNET_NO).
4420 * We also do not add problematic paths, like those where we lack the first
4421 * hop in our neighbour list (i.e. due to a topology change) or where some
4422 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4424 * @param path the path we learned, path[0] should be us,
4425 * and then path contains a valid path from us to `path[path_len-1]`
4426 * path[1] should be a direct neighbour (we should check!)
4427 * @param path_len number of entries on the @a path, at least three!
4428 * @param network_latency how long does the message take from us to `path[path_len-1]`?
4429 * set to "forever" if unknown
4430 * @return #GNUNET_YES on success,
4431 * #GNUNET_NO if we have better path(s) to the target
4432 * #GNUNET_SYSERR if the path is useless and/or invalid
4433 * (i.e. path[1] not a direct neighbour
4434 * or path[i+1] is a direct neighbour for i>0)
4437 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4438 unsigned int path_len,
4439 struct GNUNET_TIME_Relative network_latency)
4441 struct DistanceVectorHop *hop;
4442 struct DistanceVector *dv;
4443 struct Neighbour *next_hop;
4444 unsigned int shorter_distance;
4448 /* what a boring path! not allowed! */
4450 return GNUNET_SYSERR;
4453 GNUNET_memcmp (&GST_my_identity,
4455 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours,
4457 if (NULL == next_hop)
4459 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4461 return GNUNET_SYSERR;
4463 for (unsigned int i=2;i<path_len;i++)
4465 GNUNET_CONTAINER_multipeermap_get (neighbours,
4468 /* Useless path, we have a direct connection to some hop
4469 in the middle of the path, so this one doesn't even
4470 seem terribly useful for redundancy */
4471 return GNUNET_SYSERR;
4473 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes,
4474 &path[path_len - 1]);
4477 dv = GNUNET_new (struct DistanceVector);
4478 dv->target = path[path_len - 1];
4479 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4482 GNUNET_assert (GNUNET_OK ==
4483 GNUNET_CONTAINER_multipeermap_put (dv_routes,
4486 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4488 /* Check if we have this path already! */
4489 shorter_distance = 0;
4490 for (struct DistanceVectorHop *pos = dv->dv_head;
4494 if (pos->distance < path_len - 2)
4496 /* Note that the distances in 'pos' excludes us (path[0]) and
4497 the next_hop (path[1]), so we need to subtract two
4498 and check next_hop explicitly */
4499 if ( (pos->distance == path_len - 2) &&
4500 (pos->next_hop == next_hop) )
4502 int match = GNUNET_YES;
4504 for (unsigned int i=0;i<pos->distance;i++)
4507 GNUNET_memcmp (&pos->path[i],
4514 if (GNUNET_YES == match)
4516 struct GNUNET_TIME_Relative last_timeout;
4518 /* Re-discovered known path, update timeout */
4519 GNUNET_STATISTICS_update (GST_stats,
4520 "# Known DV path refreshed",
4523 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4525 = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4526 GNUNET_CONTAINER_MDLL_remove (dv,
4530 GNUNET_CONTAINER_MDLL_insert (dv,
4534 if (last_timeout.rel_value_us <
4535 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4536 DV_PATH_DISCOVERY_FREQUENCY).rel_value_us)
4538 /* Some peer send DV learn messages too often, we are learning
4539 the same path faster than it would be useful; do not forward! */
4546 /* Count how many shorter paths we have (incl. direct
4547 neighbours) before simply giving up on this one! */
4548 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4550 /* We have a shorter path already! */
4553 /* create new DV path entry */
4554 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4555 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4556 hop->next_hop = next_hop;
4558 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4561 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4562 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4563 hop->distance = path_len - 2;
4564 GNUNET_CONTAINER_MDLL_insert (dv,
4568 GNUNET_CONTAINER_MDLL_insert (neighbour,
4577 * Communicator gave us a DV learn message. Check the message.
4579 * @param cls a `struct CommunicatorMessageContext`
4580 * @param dvl the send message that was sent
4581 * @return #GNUNET_YES if message is well-formed
4584 check_dv_learn (void *cls,
4585 const struct TransportDVLearn *dvl)
4587 uint16_t size = ntohs (dvl->header.size);
4588 uint16_t num_hops = ntohs (dvl->num_hops);
4589 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4592 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4594 GNUNET_break_op (0);
4595 return GNUNET_SYSERR;
4597 if (num_hops > MAX_DV_HOPS_ALLOWED)
4599 GNUNET_break_op (0);
4600 return GNUNET_SYSERR;
4602 for (unsigned int i=0;i<num_hops;i++)
4604 if (0 == GNUNET_memcmp (&dvl->initiator,
4607 GNUNET_break_op (0);
4608 return GNUNET_SYSERR;
4610 if (0 == GNUNET_memcmp (&GST_my_identity,
4613 GNUNET_break_op (0);
4614 return GNUNET_SYSERR;
4622 * Build and forward a DV learn message to @a next_hop.
4624 * @param next_hop peer to send the message to
4625 * @param msg message received
4626 * @param bi_history bitmask specifying hops on path that were bidirectional
4627 * @param nhops length of the @a hops array
4628 * @param hops path the message traversed so far
4629 * @param in_time when did we receive the message, used to calculate network delay
4632 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4633 const struct TransportDVLearn *msg,
4634 uint16_t bi_history,
4636 const struct DVPathEntryP *hops,
4637 struct GNUNET_TIME_Absolute in_time)
4639 struct DVPathEntryP *dhops;
4640 struct TransportDVLearn *fwd;
4641 struct GNUNET_TIME_Relative nnd;
4643 /* compute message for forwarding */
4644 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4645 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4646 (nhops + 1) * sizeof (struct DVPathEntryP));
4647 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4648 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4649 (nhops + 1) * sizeof (struct DVPathEntryP));
4650 fwd->num_hops = htons (nhops + 1);
4651 fwd->bidirectional = htons (bi_history);
4652 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4653 GNUNET_TIME_relative_ntoh (msg->non_network_delay));
4654 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4655 fwd->init_sig = msg->init_sig;
4656 fwd->initiator = msg->initiator;
4657 fwd->challenge = msg->challenge;
4658 dhops = (struct DVPathEntryP *) &fwd[1];
4659 GNUNET_memcpy (dhops,
4661 sizeof (struct DVPathEntryP) * nhops);
4662 dhops[nhops].hop = GST_my_identity;
4664 struct DvHopPS dhp = {
4665 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4666 .purpose.size = htonl (sizeof (dhp)),
4667 .pred = dhops[nhops-1].hop,
4669 .challenge = msg->challenge
4672 GNUNET_assert (GNUNET_OK ==
4673 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4675 &dhops[nhops].hop_sig));
4677 route_message (next_hop,
4683 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4685 * @param init the signer
4686 * @param challenge the challenge that was signed
4687 * @param init_sig signature presumably by @a init
4688 * @return #GNUNET_OK if the signature is valid
4691 validate_dv_initiator_signature (const struct GNUNET_PeerIdentity *init,
4692 const struct GNUNET_ShortHashCode *challenge,
4693 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4695 struct DvInitPS ip = {
4696 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4697 .purpose.size = htonl (sizeof (ip)),
4698 .challenge = *challenge
4702 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4707 GNUNET_break_op (0);
4708 return GNUNET_SYSERR;
4715 * Communicator gave us a DV learn message. Process the request.
4717 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4718 * @param dvl the message that was received
4721 handle_dv_learn (void *cls,
4722 const struct TransportDVLearn *dvl)
4724 struct CommunicatorMessageContext *cmc = cls;
4725 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
4728 uint16_t bi_history;
4729 const struct DVPathEntryP *hops;
4732 struct GNUNET_TIME_Absolute in_time;
4734 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
4735 bi_history = ntohs (dvl->bidirectional);
4736 hops = (const struct DVPathEntryP *) &dvl[1];
4740 if (0 != GNUNET_memcmp (&dvl->initiator,
4744 finish_cmc_handling (cmc);
4751 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop,
4755 finish_cmc_handling (cmc);
4760 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
4761 cc = cmc->tc->details.communicator.cc;
4762 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE == cc); // FIXME: add bi-directional flag to cc?
4763 in_time = GNUNET_TIME_absolute_get ();
4765 /* continue communicator here, everything else can happen asynchronous! */
4766 finish_cmc_handling (cmc);
4768 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
4769 the initiator signature if we send the message back to the initiator... */
4771 validate_dv_initiator_signature (&dvl->initiator,
4775 GNUNET_break_op (0);
4778 // FIXME: asynchronously (!) verify hop-by-hop signatures!
4779 // => if signature verification load too high, implement random drop strategy!?
4781 do_fwd = GNUNET_YES;
4782 if (0 == GNUNET_memcmp (&GST_my_identity,
4785 struct GNUNET_PeerIdentity path[nhops + 1];
4786 struct GNUNET_TIME_Relative host_latency_sum;
4787 struct GNUNET_TIME_Relative latency;
4788 struct GNUNET_TIME_Relative network_latency;
4790 /* We initiated this, learn the forward path! */
4791 path[0] = GST_my_identity;
4792 path[1] = hops[0].hop;
4793 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
4795 // Need also something to lookup initiation time
4796 // to compute RTT! -> add RTT argument here?
4797 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
4798 // (based on dvl->challenge, we can identify time of origin!)
4800 network_latency = GNUNET_TIME_relative_subtract (latency,
4802 /* assumption: latency on all links is the same */
4803 network_latency = GNUNET_TIME_relative_divide (network_latency,
4806 for (unsigned int i=2;i<=nhops;i++)
4808 struct GNUNET_TIME_Relative ilat;
4810 /* assumption: linear latency increase per hop */
4811 ilat = GNUNET_TIME_relative_multiply (network_latency,
4813 path[i] = hops[i-1].hop;
4814 learn_dv_path (path,
4818 /* as we initiated, do not forward again (would be circular!) */
4824 /* last hop was bi-directional, we could learn something here! */
4825 struct GNUNET_PeerIdentity path[nhops + 2];
4827 path[0] = GST_my_identity;
4828 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
4829 for (unsigned int i=0;i<nhops;i++)
4833 if (0 == (bi_history & (1 << i)))
4834 break; /* i-th hop not bi-directional, stop learning! */
4837 path[i + 2] = dvl->initiator;
4841 path[i + 2] = hops[nhops - i - 2].hop;
4844 iret = learn_dv_path (path,
4846 GNUNET_TIME_UNIT_FOREVER_REL);
4847 if (GNUNET_SYSERR == iret)
4849 /* path invalid or too long to be interesting for US, thus should also
4850 not be interesting to our neighbours, cut path when forwarding to
4851 'i' hops, except of course for the one that goes back to the
4853 GNUNET_STATISTICS_update (GST_stats,
4854 "# DV learn not forwarded due invalidity of path",
4860 if ( (GNUNET_NO == iret) &&
4863 /* we have better paths, and this is the longest target,
4864 so there cannot be anything interesting later */
4865 GNUNET_STATISTICS_update (GST_stats,
4866 "# DV learn not forwarded, got better paths",
4875 if (MAX_DV_HOPS_ALLOWED == nhops)
4877 /* At limit, we're out of here! */
4878 finish_cmc_handling (cmc);
4882 /* Forward to initiator, if path non-trivial and possible */
4883 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
4884 did_initiator = GNUNET_NO;
4887 GNUNET_CONTAINER_multipeermap_contains (neighbours,
4890 /* send back to origin! */
4891 forward_dv_learn (&dvl->initiator,
4897 did_initiator = GNUNET_YES;
4899 /* We forward under two conditions: either we still learned something
4900 ourselves (do_fwd), or the path was darn short and thus the initiator is
4901 likely to still be very interested in this (and we did NOT already
4902 send it back to the initiator) */
4904 ( (nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
4905 (GNUNET_NO == did_initiator) ) )
4907 /* FIXME: loop over all neighbours, pick those with low
4908 queues AND that are not yet on the path; possibly
4909 adapt threshold to nhops! */
4911 forward_dv_learn (NULL, // fill in peer from iterator here!
4923 * Communicator gave us a DV box. Check the message.
4925 * @param cls a `struct CommunicatorMessageContext`
4926 * @param dvb the send message that was sent
4927 * @return #GNUNET_YES if message is well-formed
4930 check_dv_box (void *cls,
4931 const struct TransportDVBox *dvb)
4933 uint16_t size = ntohs (dvb->header.size);
4934 uint16_t num_hops = ntohs (dvb->num_hops);
4935 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
4936 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
4941 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct GNUNET_MessageHeader))
4943 GNUNET_break_op (0);
4944 return GNUNET_SYSERR;
4946 isize = ntohs (inbox->size);
4947 if (size != sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
4949 GNUNET_break_op (0);
4950 return GNUNET_SYSERR;
4952 itype = ntohs (inbox->type);
4953 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
4954 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype) )
4956 GNUNET_break_op (0);
4957 return GNUNET_SYSERR;
4960 GNUNET_memcmp (&dvb->origin,
4963 GNUNET_break_op (0);
4964 return GNUNET_SYSERR;
4971 * Create a DV Box message and queue it for transmission to
4974 * @param next_hop peer to receive the message next
4975 * @param total_hops how many hops did the message take so far
4976 * @param num_hops length of the @a hops array
4977 * @param origin origin of the message
4978 * @param hops next peer(s) to the destination, including destination
4979 * @param payload payload of the box
4980 * @param payload_size number of bytes in @a payload
4983 forward_dv_box (struct Neighbour *next_hop,
4984 uint16_t total_hops,
4986 const struct GNUNET_PeerIdentity *origin,
4987 const struct GNUNET_PeerIdentity *hops,
4988 const void *payload,
4989 uint16_t payload_size)
4991 struct TransportDVBox *dvb;
4992 struct GNUNET_PeerIdentity *dhops;
4994 GNUNET_assert (UINT16_MAX <
4995 sizeof (struct TransportDVBox) +
4996 sizeof (struct GNUNET_PeerIdentity) * num_hops +
4998 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
4999 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5001 dvb->header.size = htons (sizeof (struct TransportDVBox) +
5002 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5004 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5005 dvb->total_hops = htons (total_hops);
5006 dvb->num_hops = htons (num_hops);
5007 dvb->origin = *origin;
5008 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5011 num_hops * sizeof (struct GNUNET_PeerIdentity));
5012 memcpy (&dhops[num_hops],
5015 route_message (&next_hop->pid,
5021 * Communicator gave us a DV box. Process the request.
5023 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
5024 * @param dvb the message that was received
5027 handle_dv_box (void *cls,
5028 const struct TransportDVBox *dvb)
5030 struct CommunicatorMessageContext *cmc = cls;
5031 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5032 uint16_t num_hops = ntohs (dvb->num_hops);
5033 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
5034 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
5038 /* We're trying from the end of the hops array, as we may be
5039 able to find a shortcut unknown to the origin that way */
5040 for (int i=num_hops-1;i>=0;i--)
5042 struct Neighbour *n;
5045 GNUNET_memcmp (&hops[i],
5048 GNUNET_break_op (0);
5049 finish_cmc_handling (cmc);
5052 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
5057 ntohs (dvb->total_hops) + 1,
5058 num_hops - i - 1, /* number of hops left */
5060 &hops[i+1], /* remaining hops */
5061 (const void *) &dvb[1],
5063 finish_cmc_handling (cmc);
5066 /* Woopsie, next hop not in neighbours, drop! */
5067 GNUNET_STATISTICS_update (GST_stats,
5068 "# DV Boxes dropped: next hop unknown",
5071 finish_cmc_handling (cmc);
5074 /* We are the target. Unbox and handle message. */
5075 cmc->im.sender = dvb->origin;
5076 cmc->total_hops = ntohs (dvb->total_hops);
5077 demultiplex_with_cmc (cmc,
5083 * Client notified us about transmission from a peer. Process the request.
5085 * @param cls a `struct TransportClient` which sent us the message
5086 * @param obm the send message that was sent
5087 * @return #GNUNET_YES if message is well-formed
5090 check_incoming_msg (void *cls,
5091 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5093 struct TransportClient *tc = cls;
5095 if (CT_COMMUNICATOR != tc->type)
5098 return GNUNET_SYSERR;
5100 GNUNET_MQ_check_boxed_message (im);
5106 * Communicator gave us a transport address validation challenge. Process the request.
5108 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
5109 * @param tvc the message that was received
5112 handle_validation_challenge (void *cls,
5113 const struct TransportValidationChallenge *tvc)
5115 struct CommunicatorMessageContext *cmc = cls;
5116 struct TransportValidationResponse *tvr;
5118 if (cmc->total_hops > 0)
5120 /* DV routing is not allowed for validation challenges! */
5121 GNUNET_break_op (0);
5122 finish_cmc_handling (cmc);
5125 tvr = GNUNET_new (struct TransportValidationResponse);
5126 tvr->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5127 tvr->header.size = htons (sizeof (*tvr));
5128 tvr->challenge = tvc->challenge;
5129 tvr->origin_time = tvc->sender_time;
5130 tvr->validity_duration = cmc->im.expected_address_validity;
5132 /* create signature */
5133 struct TransportValidationPS tvp = {
5134 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5135 .purpose.size = htonl (sizeof (tvp)),
5136 .validity_duration = tvr->validity_duration,
5137 .challenge = tvc->challenge
5140 GNUNET_assert (GNUNET_OK ==
5141 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5145 route_message (&cmc->im.sender,
5147 finish_cmc_handling (cmc);
5152 * Closure for #check_known_challenge.
5154 struct CheckKnownChallengeContext
5157 * Set to the challenge we are looking for.
5159 const struct GNUNET_ShortHashCode *challenge;
5162 * Set to a matching validation state, if one was found.
5164 struct ValidationState *vs;
5169 * Test if the validation state in @a value matches the
5170 * challenge from @a cls.
5172 * @param cls a `struct CheckKnownChallengeContext`
5173 * @param pid unused (must match though)
5174 * @param value a `struct ValidationState`
5175 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5178 check_known_challenge (void *cls,
5179 const struct GNUNET_PeerIdentity *pid,
5182 struct CheckKnownChallengeContext *ckac = cls;
5183 struct ValidationState *vs = value;
5186 if (0 != GNUNET_memcmp (&vs->challenge,
5195 * Function called when peerstore is done storing a
5196 * validated address.
5198 * @param cls a `struct ValidationState`
5199 * @param success #GNUNET_YES on success
5202 peerstore_store_validation_cb (void *cls,
5205 struct ValidationState *vs = cls;
5208 if (GNUNET_YES == success)
5210 GNUNET_STATISTICS_update (GST_stats,
5211 "# Peerstore failed to store foreign address",
5218 * Task run periodically to validate some address based on #validation_heap.
5223 validation_start_cb (void *cls);
5227 * Set the time for next_challenge of @a vs to @a new_time.
5228 * Updates the heap and if necessary reschedules the job.
5230 * @param vs validation state to update
5231 * @param new_time new time for revalidation
5234 update_next_challenge_time (struct ValidationState *vs,
5235 struct GNUNET_TIME_Absolute new_time)
5237 struct GNUNET_TIME_Relative delta;
5239 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5240 return; /* be lazy */
5241 vs->next_challenge = new_time;
5243 vs->hn = GNUNET_CONTAINER_heap_insert (validation_heap,
5245 new_time.abs_value_us);
5247 GNUNET_CONTAINER_heap_update_cost (vs->hn,
5248 new_time.abs_value_us);
5249 if ( (vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5250 (NULL != validation_task) )
5252 if (NULL != validation_task)
5253 GNUNET_SCHEDULER_cancel (validation_task);
5254 /* randomize a bit */
5255 delta.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5256 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5257 new_time = GNUNET_TIME_absolute_add (new_time,
5259 validation_task = GNUNET_SCHEDULER_add_at (new_time,
5260 &validation_start_cb,
5266 * Communicator gave us a transport address validation response. Process the request.
5268 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
5269 * @param tvr the message that was received
5272 handle_validation_response (void *cls,
5273 const struct TransportValidationResponse *tvr)
5275 struct CommunicatorMessageContext *cmc = cls;
5276 struct ValidationState *vs;
5277 struct CheckKnownChallengeContext ckac = {
5278 .challenge = &tvr->challenge,
5281 struct GNUNET_TIME_Absolute origin_time;
5283 /* check this is one of our challenges */
5284 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5286 &check_known_challenge,
5288 if (NULL == (vs = ckac.vs))
5290 /* This can happen simply if we 'forgot' the challenge by now,
5291 i.e. because we received the validation response twice */
5292 GNUNET_STATISTICS_update (GST_stats,
5293 "# Validations dropped, challenge unknown",
5296 finish_cmc_handling (cmc);
5300 /* sanity check on origin time */
5301 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
5302 if ( (origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
5303 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us) )
5305 GNUNET_break_op (0);
5306 finish_cmc_handling (cmc);
5311 /* check signature */
5312 struct TransportValidationPS tvp = {
5313 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5314 .purpose.size = htonl (sizeof (tvp)),
5315 .validity_duration = tvr->validity_duration,
5316 .challenge = tvr->challenge
5320 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
5323 &cmc->im.sender.public_key))
5325 GNUNET_break_op (0);
5326 finish_cmc_handling (cmc);
5331 /* validity is capped by our willingness to keep track of the
5332 validation entry and the maximum the other peer allows */
5334 = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (tvr->validity_duration),
5335 MAX_ADDRESS_VALID_UNTIL));
5337 = GNUNET_TIME_absolute_min (vs->valid_until,
5338 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME));
5339 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
5340 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
5341 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5343 sizeof (vs->challenge));
5344 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (vs->validated_until,
5345 GNUNET_TIME_relative_multiply (vs->validation_rtt,
5346 VALIDATION_RTT_BUFFER_FACTOR));
5347 vs->last_challenge_use = GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
5348 update_next_challenge_time (vs,
5349 vs->first_challenge_use);
5350 vs->sc = GNUNET_PEERSTORE_store (peerstore,
5353 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
5355 strlen (vs->address) + 1,
5357 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5358 &peerstore_store_validation_cb,
5360 // FIXME: should we find the matching queue and update the RTT?
5361 finish_cmc_handling (cmc);
5366 * Incoming meessage. Process the request.
5368 * @param im the send message that was received
5371 handle_incoming_msg (void *cls,
5372 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5374 struct TransportClient *tc = cls;
5375 struct CommunicatorMessageContext *cmc = GNUNET_new (struct CommunicatorMessageContext);
5379 demultiplex_with_cmc (cmc,
5380 (const struct GNUNET_MessageHeader *) &im[1]);
5385 * Given an inbound message @a msg from a communicator @a cmc,
5386 * demultiplex it based on the type calling the right handler.
5388 * @param cmc context for demultiplexing
5389 * @param msg message to demultiplex
5392 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5393 const struct GNUNET_MessageHeader *msg)
5395 struct GNUNET_MQ_MessageHandler handlers[] = {
5396 GNUNET_MQ_hd_var_size (fragment_box,
5397 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
5398 struct TransportFragmentBox,
5400 GNUNET_MQ_hd_fixed_size (fragment_ack,
5401 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
5402 struct TransportFragmentAckMessage,
5404 GNUNET_MQ_hd_var_size (reliability_box,
5405 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5406 struct TransportReliabilityBox,
5408 GNUNET_MQ_hd_fixed_size (reliability_ack,
5409 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5410 struct TransportReliabilityAckMessage,
5412 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5413 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5414 struct TransportBackchannelEncapsulationMessage,
5416 GNUNET_MQ_hd_var_size (dv_learn,
5417 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5418 struct TransportDVLearn,
5420 GNUNET_MQ_hd_var_size (dv_box,
5421 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5422 struct TransportDVBox,
5424 GNUNET_MQ_hd_fixed_size (validation_challenge,
5425 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5426 struct TransportValidationChallenge,
5428 GNUNET_MQ_hd_fixed_size (validation_response,
5429 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5430 struct TransportValidationResponse,
5432 GNUNET_MQ_handler_end()
5436 ret = GNUNET_MQ_handle_message (handlers,
5438 if (GNUNET_SYSERR == ret)
5441 GNUNET_SERVICE_client_drop (cmc->tc->client);
5445 if (GNUNET_NO == ret)
5447 /* unencapsulated 'raw' message */
5448 handle_raw_message (&cmc,
5455 * New queue became available. Check message.
5457 * @param cls the client
5458 * @param aqm the send message that was sent
5461 check_add_queue_message (void *cls,
5462 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5464 struct TransportClient *tc = cls;
5466 if (CT_COMMUNICATOR != tc->type)
5469 return GNUNET_SYSERR;
5471 GNUNET_MQ_check_zero_termination (aqm);
5477 * Bandwidth tracker informs us that the delay until we should receive
5480 * @param cls a `struct Queue` for which the delay changed
5483 tracker_update_in_cb (void *cls)
5485 struct Queue *queue = cls;
5486 struct GNUNET_TIME_Relative in_delay;
5489 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5490 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in,
5492 // FIXME: how exactly do we do inbound flow control?
5497 * If necessary, generates the UUID for a @a pm
5499 * @param pm pending message to generate UUID for.
5502 set_pending_message_uuid (struct PendingMessage *pm)
5504 if (pm->msg_uuid_set)
5506 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5508 sizeof (pm->msg_uuid));
5509 pm->msg_uuid_set = GNUNET_YES;
5514 * Fragment the given @a pm to the given @a mtu. Adds
5515 * additional fragments to the neighbour as well. If the
5516 * @a mtu is too small, generates and error for the @a pm
5519 * @param pm pending message to fragment for transmission
5520 * @param mtu MTU to apply
5521 * @return new message to transmit
5523 static struct PendingMessage *
5524 fragment_message (struct PendingMessage *pm,
5527 struct PendingMessage *ff;
5529 set_pending_message_uuid (pm);
5531 /* This invariant is established in #handle_add_queue_message() */
5532 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5534 /* select fragment for transmission, descending the tree if it has
5535 been expanded until we are at a leaf or at a fragment that is small enough */
5537 while ( ( (ff->bytes_msg > mtu) ||
5539 (ff->frag_off == ff->bytes_msg) &&
5540 (NULL != ff->head_frag) )
5542 ff = ff->head_frag; /* descent into fragmented fragments */
5545 if ( ( (ff->bytes_msg > mtu) ||
5547 (pm->frag_off < pm->bytes_msg) )
5549 /* Did not yet calculate all fragments, calculate next fragment */
5550 struct PendingMessage *frag;
5551 struct TransportFragmentBox tfb;
5559 orig = (const char *) &ff[1];
5560 msize = ff->bytes_msg;
5563 const struct TransportFragmentBox *tfbo;
5565 tfbo = (const struct TransportFragmentBox *) orig;
5566 orig += sizeof (struct TransportFragmentBox);
5567 msize -= sizeof (struct TransportFragmentBox);
5568 xoff = ntohs (tfbo->frag_off);
5570 fragmax = mtu - sizeof (struct TransportFragmentBox);
5571 fragsize = GNUNET_MIN (msize - ff->frag_off,
5573 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5574 sizeof (struct TransportFragmentBox) +
5576 frag->target = pm->target;
5577 frag->frag_parent = ff;
5578 frag->timeout = pm->timeout;
5579 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5580 frag->pmt = PMT_FRAGMENT_BOX;
5581 msg = (char *) &frag[1];
5582 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
5583 tfb.header.size = htons (sizeof (struct TransportFragmentBox) +
5585 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
5586 tfb.msg_uuid = pm->msg_uuid;
5587 tfb.frag_off = htons (ff->frag_off + xoff);
5588 tfb.msg_size = htons (pm->bytes_msg);
5592 memcpy (&msg[sizeof (tfb)],
5593 &orig[ff->frag_off],
5595 GNUNET_CONTAINER_MDLL_insert (frag,
5599 ff->frag_off += fragsize;
5603 /* Move head to the tail and return it */
5604 GNUNET_CONTAINER_MDLL_remove (frag,
5605 ff->frag_parent->head_frag,
5606 ff->frag_parent->tail_frag,
5608 GNUNET_CONTAINER_MDLL_insert_tail (frag,
5609 ff->frag_parent->head_frag,
5610 ff->frag_parent->tail_frag,
5617 * Reliability-box the given @a pm. On error (can there be any), NULL
5618 * may be returned, otherwise the "replacement" for @a pm (which
5619 * should then be added to the respective neighbour's queue instead of
5620 * @a pm). If the @a pm is already fragmented or reliability boxed,
5621 * or itself an ACK, this function simply returns @a pm.
5623 * @param pm pending message to box for transmission over unreliabile queue
5624 * @return new message to transmit
5626 static struct PendingMessage *
5627 reliability_box_message (struct PendingMessage *pm)
5629 struct TransportReliabilityBox rbox;
5630 struct PendingMessage *bpm;
5633 if (PMT_CORE != pm->pmt)
5634 return pm; /* already fragmented or reliability boxed, or control message: do nothing */
5635 if (NULL != pm->bpm)
5636 return pm->bpm; /* already computed earlier: do nothing */
5637 GNUNET_assert (NULL == pm->head_frag);
5638 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
5642 client_send_response (pm,
5647 bpm = GNUNET_malloc (sizeof (struct PendingMessage) +
5650 bpm->target = pm->target;
5651 bpm->frag_parent = pm;
5652 GNUNET_CONTAINER_MDLL_insert (frag,
5656 bpm->timeout = pm->timeout;
5657 bpm->pmt = PMT_RELIABILITY_BOX;
5658 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
5659 set_pending_message_uuid (bpm);
5660 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
5661 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
5662 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
5663 rbox.msg_uuid = pm->msg_uuid;
5664 msg = (char *) &bpm[1];
5668 memcpy (&msg[sizeof (rbox)],
5677 * Send the control message @a payload on @a queue.
5679 * @param queue the queue to use for transmission
5680 * @param pm pending message to update once transmission is done, may be NULL!
5681 * @param payload the payload to send (encapsulated in a
5682 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
5683 * @param payload_size number of bytes in @a payload
5686 queue_send_msg (struct Queue *queue,
5687 struct PendingMessage *pm,
5688 const void *payload,
5689 size_t payload_size)
5691 struct Neighbour *n = queue->neighbour;
5692 struct GNUNET_TRANSPORT_SendMessageTo *smt;
5693 struct GNUNET_MQ_Envelope *env;
5695 env = GNUNET_MQ_msg_extra (smt,
5697 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
5698 smt->qid = queue->qid;
5699 smt->mid = queue->mid_gen;
5700 smt->receiver = n->pid;
5705 /* Pass the env to the communicator of queue for transmission. */
5706 struct QueueEntry *qe;
5708 qe = GNUNET_new (struct QueueEntry);
5709 qe->mid = queue->mid_gen++;
5711 // qe->pm = pm; // FIXME: not so easy, reference management on 'free(s)'!
5712 // (also, note that pm may be NULL!)
5713 GNUNET_CONTAINER_DLL_insert (queue->queue_head,
5716 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5717 queue->queue_length++;
5718 queue->tc->details.communicator.total_queue_length++;
5719 GNUNET_MQ_send (queue->tc->mq,
5726 * We believe we are ready to transmit a message on a queue. Double-checks
5727 * with the queue's "tracker_out" and then gives the message to the
5728 * communicator for transmission (updating the tracker, and re-scheduling
5729 * itself if applicable).
5731 * @param cls the `struct Queue` to process transmissions for
5734 transmit_on_queue (void *cls)
5736 struct Queue *queue = cls;
5737 struct Neighbour *n = queue->neighbour;
5738 struct PendingMessage *pm;
5739 struct PendingMessage *s;
5742 queue->transmit_task = NULL;
5743 if (NULL == (pm = n->pending_msg_head))
5745 /* no message pending, nothing to do here! */
5748 schedule_transmit_on_queue (queue);
5749 if (NULL != queue->transmit_task)
5750 return; /* do it later */
5752 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5753 overhead += sizeof (struct TransportReliabilityBox);
5755 if ( ( (0 != queue->mtu) &&
5756 (pm->bytes_msg + overhead > queue->mtu) ) ||
5757 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
5758 (NULL != pm->head_frag /* fragments already exist, should
5759 respect that even if MTU is 0 for
5761 s = fragment_message (s,
5763 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
5767 /* Fragmentation failed, try next message... */
5768 schedule_transmit_on_queue (queue);
5771 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5772 s = reliability_box_message (s);
5775 /* Reliability boxing failed, try next message... */
5776 schedule_transmit_on_queue (queue);
5780 /* Pass 's' for transission to the communicator */
5781 queue_send_msg (queue,
5785 // FIXME: do something similar to the logic below
5786 // in defragmentation / reliability ACK handling!
5788 /* Check if this transmission somehow conclusively finished handing 'pm'
5789 even without any explicit ACKs */
5790 if ( (PMT_CORE == s->pmt) &&
5791 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) )
5793 /* Full message sent, and over reliabile channel */
5794 client_send_response (pm,
5798 else if ( (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) &&
5799 (PMT_FRAGMENT_BOX == s->pmt) )
5801 struct PendingMessage *pos;
5803 /* Fragment sent over reliabile channel */
5804 free_fragment_tree (s);
5805 pos = s->frag_parent;
5806 GNUNET_CONTAINER_MDLL_remove (frag,
5811 /* check if subtree is done */
5812 while ( (NULL == pos->head_frag) &&
5813 (pos->frag_off == pos->bytes_msg) &&
5817 pos = s->frag_parent;
5818 GNUNET_CONTAINER_MDLL_remove (frag,
5825 /* Was this the last applicable fragmment? */
5826 if ( (NULL == pm->head_frag) &&
5827 (pm->frag_off == pm->bytes_msg) )
5828 client_send_response (pm,
5830 pm->bytes_msg /* FIXME: calculate and add overheads! */);
5832 else if (PMT_CORE != pm->pmt)
5834 /* This was an acknowledgement of some type, always free */
5835 free_pending_message (pm);
5839 /* message not finished, waiting for acknowledgement */
5840 struct Neighbour *neighbour = pm->target;
5841 /* Update time by which we might retransmit 's' based on queue
5842 characteristics (i.e. RTT); it takes one RTT for the message to
5843 arrive and the ACK to come back in the best case; but the other
5844 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
5845 retransmitting. Note that in the future this heuristic should
5846 likely be improved further (measure RTT stability, consider
5847 message urgency and size when delaying ACKs, etc.) */
5848 s->next_attempt = GNUNET_TIME_relative_to_absolute
5849 (GNUNET_TIME_relative_multiply (queue->rtt,
5853 struct PendingMessage *pos;
5855 /* re-insert sort in neighbour list */
5856 GNUNET_CONTAINER_MDLL_remove (neighbour,
5857 neighbour->pending_msg_head,
5858 neighbour->pending_msg_tail,
5860 pos = neighbour->pending_msg_tail;
5861 while ( (NULL != pos) &&
5862 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5863 pos = pos->prev_neighbour;
5864 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
5865 neighbour->pending_msg_head,
5866 neighbour->pending_msg_tail,
5872 /* re-insert sort in fragment list */
5873 struct PendingMessage *fp = s->frag_parent;
5874 struct PendingMessage *pos;
5876 GNUNET_CONTAINER_MDLL_remove (frag,
5880 pos = fp->tail_frag;
5881 while ( (NULL != pos) &&
5882 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5883 pos = pos->prev_frag;
5884 GNUNET_CONTAINER_MDLL_insert_after (frag,
5892 /* finally, re-schedule queue transmission task itself */
5893 schedule_transmit_on_queue (queue);
5898 * Bandwidth tracker informs us that the delay until we
5899 * can transmit again changed.
5901 * @param cls a `struct Queue` for which the delay changed
5904 tracker_update_out_cb (void *cls)
5906 struct Queue *queue = cls;
5907 struct Neighbour *n = queue->neighbour;
5909 if (NULL == n->pending_msg_head)
5911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5912 "Bandwidth allocation updated for empty transmission queue `%s'\n",
5914 return; /* no message pending, nothing to do here! */
5916 GNUNET_SCHEDULER_cancel (queue->transmit_task);
5917 queue->transmit_task = NULL;
5918 schedule_transmit_on_queue (queue);
5923 * Bandwidth tracker informs us that excessive outbound bandwidth was
5924 * allocated which is not being used.
5926 * @param cls a `struct Queue` for which the excess was noted
5929 tracker_excess_out_cb (void *cls)
5933 /* FIXME: trigger excess bandwidth report to core? Right now,
5934 this is done internally within transport_api2_core already,
5935 but we probably want to change the logic and trigger it
5936 from here via a message instead! */
5937 /* TODO: maybe inform someone at this point? */
5938 GNUNET_STATISTICS_update (GST_stats,
5939 "# Excess outbound bandwidth reported",
5947 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
5948 * which is not being used.
5950 * @param cls a `struct Queue` for which the excess was noted
5953 tracker_excess_in_cb (void *cls)
5957 /* TODO: maybe inform somone at this point? */
5958 GNUNET_STATISTICS_update (GST_stats,
5959 "# Excess inbound bandwidth reported",
5966 * Queue to a peer went down. Process the request.
5968 * @param cls the client
5969 * @param dqm the send message that was sent
5972 handle_del_queue_message (void *cls,
5973 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
5975 struct TransportClient *tc = cls;
5977 if (CT_COMMUNICATOR != tc->type)
5980 GNUNET_SERVICE_client_drop (tc->client);
5983 for (struct Queue *queue = tc->details.communicator.queue_head;
5985 queue = queue->next_client)
5987 struct Neighbour *neighbour = queue->neighbour;
5989 if ( (dqm->qid != queue->qid) ||
5990 (0 != GNUNET_memcmp (&dqm->receiver,
5994 GNUNET_SERVICE_client_continue (tc->client);
5998 GNUNET_SERVICE_client_drop (tc->client);
6003 * Message was transmitted. Process the request.
6005 * @param cls the client
6006 * @param sma the send message that was sent
6009 handle_send_message_ack (void *cls,
6010 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
6012 struct TransportClient *tc = cls;
6013 struct QueueEntry *qe;
6015 if (CT_COMMUNICATOR != tc->type)
6018 GNUNET_SERVICE_client_drop (tc->client);
6022 /* find our queue entry matching the ACK */
6024 for (struct Queue *queue = tc->details.communicator.queue_head;
6026 queue = queue->next_client)
6028 if (0 != GNUNET_memcmp (&queue->neighbour->pid,
6031 for (struct QueueEntry *qep = queue->queue_head;
6035 if (qep->mid != sma->mid)
6044 /* this should never happen */
6046 GNUNET_SERVICE_client_drop (tc->client);
6049 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6050 qe->queue->queue_tail,
6052 qe->queue->queue_length--;
6053 tc->details.communicator.total_queue_length--;
6054 GNUNET_SERVICE_client_continue (tc->client);
6056 /* if applicable, resume transmissions that waited on ACK */
6057 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 == tc->details.communicator.total_queue_length)
6059 /* Communicator dropped below threshold, resume all queues */
6060 GNUNET_STATISTICS_update (GST_stats,
6061 "# Transmission throttled due to communicator queue limit",
6064 for (struct Queue *queue = tc->details.communicator.queue_head;
6066 queue = queue->next_client)
6067 schedule_transmit_on_queue (queue);
6069 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6071 /* queue dropped below threshold; only resume this one queue */
6072 GNUNET_STATISTICS_update (GST_stats,
6073 "# Transmission throttled due to queue queue limit",
6076 schedule_transmit_on_queue (qe->queue);
6079 /* TODO: we also should react on the status! */
6080 // FIXME: this probably requires queue->pm = s assignment!
6081 // FIXME: react to communicator status about transmission request. We got:
6082 sma->status; // OK success, SYSERR failure
6089 * Iterator telling new MONITOR client about all existing
6092 * @param cls the new `struct TransportClient`
6093 * @param pid a connected peer
6094 * @param value the `struct Neighbour` with more information
6095 * @return #GNUNET_OK (continue to iterate)
6098 notify_client_queues (void *cls,
6099 const struct GNUNET_PeerIdentity *pid,
6102 struct TransportClient *tc = cls;
6103 struct Neighbour *neighbour = value;
6105 GNUNET_assert (CT_MONITOR == tc->type);
6106 for (struct Queue *q = neighbour->queue_head;
6108 q = q->next_neighbour)
6110 struct MonitorEvent me = {
6113 .num_msg_pending = q->num_msg_pending,
6114 .num_bytes_pending = q->num_bytes_pending
6128 * Initialize a monitor client.
6130 * @param cls the client
6131 * @param start the start message that was sent
6134 handle_monitor_start (void *cls,
6135 const struct GNUNET_TRANSPORT_MonitorStart *start)
6137 struct TransportClient *tc = cls;
6139 if (CT_NONE != tc->type)
6142 GNUNET_SERVICE_client_drop (tc->client);
6145 tc->type = CT_MONITOR;
6146 tc->details.monitor.peer = start->peer;
6147 tc->details.monitor.one_shot = ntohl (start->one_shot);
6148 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6149 ¬ify_client_queues,
6151 GNUNET_SERVICE_client_mark_monitor (tc->client);
6152 GNUNET_SERVICE_client_continue (tc->client);
6157 * Find transport client providing communication service
6158 * for the protocol @a prefix.
6160 * @param prefix communicator name
6161 * @return NULL if no such transport client is available
6163 static struct TransportClient *
6164 lookup_communicator (const char *prefix)
6166 for (struct TransportClient *tc = clients_head;
6170 if (CT_COMMUNICATOR != tc->type)
6172 if (0 == strcmp (prefix,
6173 tc->details.communicator.address_prefix))
6176 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6177 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6184 * Signature of a function called with a communicator @a address of a peer
6185 * @a pid that an application wants us to connect to.
6187 * @param pid target peer
6188 * @param address the address to try
6191 suggest_to_connect (const struct GNUNET_PeerIdentity *pid,
6192 const char *address)
6194 static uint32_t idgen;
6195 struct TransportClient *tc;
6197 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6198 struct GNUNET_MQ_Envelope *env;
6201 prefix = GNUNET_HELLO_address_to_prefix (address);
6204 GNUNET_break (0); /* We got an invalid address!? */
6207 tc = lookup_communicator (prefix);
6210 GNUNET_STATISTICS_update (GST_stats,
6211 "# Suggestions ignored due to missing communicator",
6216 /* forward suggestion for queue creation to communicator */
6217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6218 "Request #%u for `%s' communicator to create queue to `%s'\n",
6219 (unsigned int) idgen,
6222 alen = strlen (address) + 1;
6223 env = GNUNET_MQ_msg_extra (cqm,
6225 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6226 cqm->request_id = htonl (idgen++);
6227 cqm->receiver = *pid;
6231 GNUNET_MQ_send (tc->mq,
6237 * The queue @a q (which matches the peer and address in @a vs) is
6238 * ready for queueing. We should now queue the validation request.
6240 * @param q queue to send on
6241 * @param vs state to derive validation challenge from
6244 validation_transmit_on_queue (struct Queue *q,
6245 struct ValidationState *vs)
6247 struct TransportValidationChallenge tvc;
6249 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6250 tvc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6251 tvc.header.size = htons (sizeof (tvc));
6252 tvc.reserved = htonl (0);
6253 tvc.challenge = vs->challenge;
6254 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6263 * Task run periodically to validate some address based on #validation_heap.
6268 validation_start_cb (void *cls)
6270 struct ValidationState *vs;
6271 struct Neighbour *n;
6275 validation_task = NULL;
6276 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6277 /* drop validations past their expiration */
6278 while ( (NULL != vs) &&
6279 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us) )
6281 free_validation_state (vs);
6282 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6285 return; /* woopsie, no more addresses known, should only
6286 happen if we're really a lonely peer */
6287 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
6292 for (struct Queue *pos = n->queue_head;
6294 pos = pos->next_neighbour)
6296 if (0 == strcmp (pos->address,
6306 vs->awaiting_queue = GNUNET_YES;
6307 suggest_to_connect (&vs->pid,
6311 validation_transmit_on_queue (q,
6313 /* Finally, reschedule next attempt */
6314 vs->challenge_backoff = GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
6315 MAX_VALIDATION_CHALLENGE_FREQ);
6316 update_next_challenge_time (vs,
6317 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
6322 * Closure for #check_connection_quality.
6324 struct QueueQualityContext
6327 * Set to the @e k'th queue encountered.
6332 * Set to the number of quality queues encountered.
6334 unsigned int quality_count;
6337 * Set to the total number of queues encountered.
6339 unsigned int num_queues;
6342 * Decremented for each queue, for selection of the
6343 * k-th queue in @e q.
6351 * Check whether any queue to the given neighbour is
6352 * of a good "quality" and if so, increment the counter.
6353 * Also counts the total number of queues, and returns
6354 * the k-th queue found.
6356 * @param cls a `struct QueueQualityContext *` with counters
6357 * @param pid peer this is about
6358 * @param value a `struct Neighbour`
6359 * @return #GNUNET_OK (continue to iterate)
6362 check_connection_quality (void *cls,
6363 const struct GNUNET_PeerIdentity *pid,
6366 struct QueueQualityContext *ctx = cls;
6367 struct Neighbour *n = value;
6372 for (struct Queue *q = n->queue_head;
6374 q = q->next_neighbour)
6376 if (0 != q->distance)
6377 continue; /* DV does not count */
6381 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
6382 statistics and consider those as well here? */
6383 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
6384 do_inc = GNUNET_YES;
6386 if (GNUNET_YES == do_inc)
6387 ctx->quality_count++;
6393 * Task run when we CONSIDER initiating a DV learn
6394 * process. We first check that sending out a message is
6395 * even possible (queues exist), then that it is desirable
6396 * (if not, reschedule the task for later), and finally
6397 * we may then begin the job. If there are too many
6398 * entries in the #dvlearn_map, we purge the oldest entry
6404 start_dv_learn (void *cls)
6406 struct LearnLaunchEntry *lle;
6407 struct QueueQualityContext qqc;
6408 struct TransportDVLearn dvl;
6411 dvlearn_task = NULL;
6413 GNUNET_CONTAINER_multipeermap_size (neighbours))
6414 return; /* lost all connectivity, cannot do learning */
6415 qqc.quality_count = 0;
6417 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6418 &check_connection_quality,
6420 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
6422 struct GNUNET_TIME_Relative delay;
6423 unsigned int factor;
6425 /* scale our retries by how far we are above the threshold */
6426 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6427 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY,
6429 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay,
6434 /* remove old entries in #dvlearn_map if it has grown too big */
6435 while (MAX_DV_LEARN_PENDING >=
6436 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6439 GNUNET_assert (GNUNET_YES ==
6440 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6443 GNUNET_CONTAINER_DLL_remove (lle_head,
6448 /* setup data structure for learning */
6449 lle = GNUNET_new (struct LearnLaunchEntry);
6450 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6452 sizeof (lle->challenge));
6453 GNUNET_CONTAINER_DLL_insert (lle_head,
6456 GNUNET_break (GNUNET_YES ==
6457 GNUNET_CONTAINER_multishortmap_put (dvlearn_map,
6460 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6461 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6462 dvl.header.size = htons (sizeof (dvl));
6463 dvl.num_hops = htons (0);
6464 dvl.bidirectional = htons (0);
6465 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6467 struct DvInitPS dvip = {
6468 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6469 .purpose.size = htonl (sizeof (dvip)),
6470 .challenge = lle->challenge
6473 GNUNET_assert (GNUNET_OK ==
6474 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6478 dvl.initiator = GST_my_identity;
6479 dvl.challenge = lle->challenge;
6481 qqc.quality_count = 0;
6482 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
6486 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6487 &check_connection_quality,
6489 GNUNET_assert (NULL != qqc.q);
6491 /* Do this as close to transmission time as possible! */
6492 lle->launch_time = GNUNET_TIME_absolute_get ();
6494 queue_send_msg (qqc.q,
6498 /* reschedule this job, randomizing the time it runs (but no
6501 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (DV_LEARN_BASE_FREQUENCY),
6508 * A new queue has been created, check if any address validation
6509 * requests have been waiting for it.
6511 * @param cls a `struct Queue`
6512 * @param pid peer concerned (unused)
6513 * @param value a `struct ValidationState`
6514 * @return #GNUNET_NO if a match was found and we can stop looking
6517 check_validation_request_pending (void *cls,
6518 const struct GNUNET_PeerIdentity *pid,
6521 struct Queue *q = cls;
6522 struct ValidationState *vs = value;
6525 if ( (GNUNET_YES == vs->awaiting_queue) &&
6526 (0 == strcmp (vs->address,
6529 vs->awaiting_queue = GNUNET_NO;
6530 validation_transmit_on_queue (q,
6539 * New queue became available. Process the request.
6541 * @param cls the client
6542 * @param aqm the send message that was sent
6545 handle_add_queue_message (void *cls,
6546 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6548 struct TransportClient *tc = cls;
6549 struct Queue *queue;
6550 struct Neighbour *neighbour;
6554 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6556 /* MTU so small as to be useless for transmissions,
6557 required for #fragment_message()! */
6558 GNUNET_break_op (0);
6559 GNUNET_SERVICE_client_drop (tc->client);
6562 neighbour = lookup_neighbour (&aqm->receiver);
6563 if (NULL == neighbour)
6565 neighbour = GNUNET_new (struct Neighbour);
6566 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6567 neighbour->pid = aqm->receiver;
6568 GNUNET_assert (GNUNET_OK ==
6569 GNUNET_CONTAINER_multipeermap_put (neighbours,
6572 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6573 cores_send_connect_info (&neighbour->pid,
6574 GNUNET_BANDWIDTH_ZERO);
6576 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6577 addr = (const char *) &aqm[1];
6579 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6581 queue->address = (const char *) &queue[1];
6582 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6583 queue->qid = aqm->qid;
6584 queue->mtu = ntohl (aqm->mtu);
6585 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6586 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6587 queue->neighbour = neighbour;
6588 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6589 &tracker_update_in_cb,
6591 GNUNET_BANDWIDTH_ZERO,
6592 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6593 &tracker_excess_in_cb,
6595 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6596 &tracker_update_out_cb,
6598 GNUNET_BANDWIDTH_ZERO,
6599 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6600 &tracker_excess_out_cb,
6605 /* notify monitors about new queue */
6607 struct MonitorEvent me = {
6612 notify_monitors (&neighbour->pid,
6617 GNUNET_CONTAINER_MDLL_insert (neighbour,
6618 neighbour->queue_head,
6619 neighbour->queue_tail,
6621 GNUNET_CONTAINER_MDLL_insert (client,
6622 tc->details.communicator.queue_head,
6623 tc->details.communicator.queue_tail,
6625 /* check if valdiations are waiting for the queue */
6626 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6628 &check_validation_request_pending,
6630 /* might be our first queue, try launching DV learning */
6631 if (NULL == dvlearn_task)
6632 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn,
6634 GNUNET_SERVICE_client_continue (tc->client);
6639 * Communicator tells us that our request to create a queue "worked", that
6640 * is setting up the queue is now in process.
6642 * @param cls the `struct TransportClient`
6643 * @param cqr confirmation message
6646 handle_queue_create_ok (void *cls,
6647 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6649 struct TransportClient *tc = cls;
6651 if (CT_COMMUNICATOR != tc->type)
6654 GNUNET_SERVICE_client_drop (tc->client);
6657 GNUNET_STATISTICS_update (GST_stats,
6658 "# Suggestions succeeded at communicator",
6661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6662 "Request #%u for communicator to create queue succeeded\n",
6663 (unsigned int) ntohs (cqr->request_id));
6664 GNUNET_SERVICE_client_continue (tc->client);
6669 * Communicator tells us that our request to create a queue failed. This usually
6670 * indicates that the provided address is simply invalid or that the communicator's
6671 * resources are exhausted.
6673 * @param cls the `struct TransportClient`
6674 * @param cqr failure message
6677 handle_queue_create_fail (void *cls,
6678 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6680 struct TransportClient *tc = cls;
6682 if (CT_COMMUNICATOR != tc->type)
6685 GNUNET_SERVICE_client_drop (tc->client);
6688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6689 "Request #%u for communicator to create queue failed\n",
6690 (unsigned int) ntohs (cqr->request_id));
6691 GNUNET_STATISTICS_update (GST_stats,
6692 "# Suggestions failed in queue creation at communicator",
6695 GNUNET_SERVICE_client_continue (tc->client);
6700 * We have received a `struct ExpressPreferenceMessage` from an application client.
6702 * @param cls handle to the client
6703 * @param msg the start message
6706 handle_suggest_cancel (void *cls,
6707 const struct ExpressPreferenceMessage *msg)
6709 struct TransportClient *tc = cls;
6710 struct PeerRequest *pr;
6712 if (CT_APPLICATION != tc->type)
6715 GNUNET_SERVICE_client_drop (tc->client);
6718 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
6723 GNUNET_SERVICE_client_drop (tc->client);
6726 (void) stop_peer_request (tc,
6729 GNUNET_SERVICE_client_continue (tc->client);
6734 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
6735 * messages. We do nothing here, real verification is done later.
6737 * @param cls a `struct TransportClient *`
6738 * @param msg message to verify
6739 * @return #GNUNET_OK
6742 check_address_consider_verify (void *cls,
6743 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6752 * Closure for #check_known_address.
6754 struct CheckKnownAddressContext
6757 * Set to the address we are looking for.
6759 const char *address;
6762 * Set to a matching validation state, if one was found.
6764 struct ValidationState *vs;
6769 * Test if the validation state in @a value matches the
6770 * address from @a cls.
6772 * @param cls a `struct CheckKnownAddressContext`
6773 * @param pid unused (must match though)
6774 * @param value a `struct ValidationState`
6775 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6778 check_known_address (void *cls,
6779 const struct GNUNET_PeerIdentity *pid,
6782 struct CheckKnownAddressContext *ckac = cls;
6783 struct ValidationState *vs = value;
6786 if (0 != strcmp (vs->address,
6795 * Start address validation.
6797 * @param pid peer the @a address is for
6798 * @param address an address to reach @a pid (presumably)
6799 * @param expiration when did @a pid claim @a address will become invalid
6802 start_address_validation (const struct GNUNET_PeerIdentity *pid,
6803 const char *address,
6804 struct GNUNET_TIME_Absolute expiration)
6806 struct GNUNET_TIME_Absolute now;
6807 struct ValidationState *vs;
6808 struct CheckKnownAddressContext ckac = {
6813 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
6814 return; /* expired */
6815 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6817 &check_known_address,
6819 if (NULL != (vs = ckac.vs))
6821 /* if 'vs' is not currently valid, we need to speed up retrying the validation */
6822 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
6824 /* reduce backoff as we got a fresh advertisement */
6825 vs->challenge_backoff = GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
6826 GNUNET_TIME_relative_divide (vs->challenge_backoff,
6828 update_next_challenge_time (vs,
6829 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
6833 now = GNUNET_TIME_absolute_get();
6834 vs = GNUNET_new (struct ValidationState);
6836 vs->valid_until = expiration;
6837 vs->first_challenge_use = now;
6838 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6839 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6841 sizeof (vs->challenge));
6842 vs->address = GNUNET_strdup (address);
6843 GNUNET_assert (GNUNET_YES ==
6844 GNUNET_CONTAINER_multipeermap_put (validation_map,
6847 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6848 update_next_challenge_time (vs,
6854 * Function called by PEERSTORE for each matching record.
6856 * @param cls closure
6857 * @param record peerstore record information
6858 * @param emsg error message, or NULL if no errors
6861 handle_hello (void *cls,
6862 const struct GNUNET_PEERSTORE_Record *record,
6865 struct PeerRequest *pr = cls;
6870 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6871 "Got failure from PEERSTORE: %s\n",
6875 val = record->value;
6876 if ( (0 == record->value_size) ||
6877 ('\0' != val[record->value_size - 1]) )
6882 start_address_validation (&pr->pid,
6883 (const char *) record->value,
6889 * We have received a `struct ExpressPreferenceMessage` from an application client.
6891 * @param cls handle to the client
6892 * @param msg the start message
6895 handle_suggest (void *cls,
6896 const struct ExpressPreferenceMessage *msg)
6898 struct TransportClient *tc = cls;
6899 struct PeerRequest *pr;
6901 if (CT_NONE == tc->type)
6903 tc->type = CT_APPLICATION;
6904 tc->details.application.requests
6905 = GNUNET_CONTAINER_multipeermap_create (16,
6908 if (CT_APPLICATION != tc->type)
6911 GNUNET_SERVICE_client_drop (tc->client);
6914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6915 "Client suggested we talk to %s with preference %d at rate %u\n",
6916 GNUNET_i2s (&msg->peer),
6917 (int) ntohl (msg->pk),
6918 (int) ntohl (msg->bw.value__));
6919 pr = GNUNET_new (struct PeerRequest);
6921 pr->pid = msg->peer;
6923 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
6925 GNUNET_CONTAINER_multipeermap_put (tc->details.application.requests,
6928 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
6932 GNUNET_SERVICE_client_drop (tc->client);
6935 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
6938 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
6941 GNUNET_SERVICE_client_continue (tc->client);
6946 * Given another peers address, consider checking it for validity
6947 * and then adding it to the Peerstore.
6949 * @param cls a `struct TransportClient`
6950 * @param hdr message containing the raw address data and
6951 * signature in the body, see #GNUNET_HELLO_extract_address()
6954 handle_address_consider_verify (void *cls,
6955 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6957 struct TransportClient *tc = cls;
6959 enum GNUNET_NetworkType nt;
6960 struct GNUNET_TIME_Absolute expiration;
6963 // OPTIMIZE-FIXME: checking that we know this address already should
6964 // be done BEFORE checking the signature => HELLO API change!
6965 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
6966 address = GNUNET_HELLO_extract_address (&hdr[1],
6967 ntohs (hdr->header.size) - sizeof (*hdr),
6971 if (NULL == address)
6973 GNUNET_break_op (0);
6976 start_address_validation (&hdr->peer,
6979 GNUNET_free (address);
6980 GNUNET_SERVICE_client_continue (tc->client);
6985 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
6988 * @param cls a `struct TransportClient *`
6989 * @param m message to verify
6990 * @return #GNUNET_OK on success
6993 check_request_hello_validation (void *cls,
6994 const struct RequestHelloValidationMessage *m)
6997 GNUNET_MQ_check_zero_termination (m);
7003 * A client encountered an address of another peer. Consider validating it,
7004 * and if validation succeeds, persist it to PEERSTORE.
7006 * @param cls a `struct TransportClient *`
7007 * @param m message to verify
7010 handle_request_hello_validation (void *cls,
7011 const struct RequestHelloValidationMessage *m)
7013 struct TransportClient *tc = cls;
7015 start_address_validation (&m->peer,
7016 (const char *) &m[1],
7017 GNUNET_TIME_absolute_ntoh (m->expiration));
7018 GNUNET_SERVICE_client_continue (tc->client);
7023 * Free neighbour entry.
7027 * @param value a `struct Neighbour`
7028 * @return #GNUNET_OK (always)
7031 free_neighbour_cb (void *cls,
7032 const struct GNUNET_PeerIdentity *pid,
7035 struct Neighbour *neighbour = value;
7039 GNUNET_break (0); // should this ever happen?
7040 free_neighbour (neighbour);
7047 * Free DV route entry.
7051 * @param value a `struct DistanceVector`
7052 * @return #GNUNET_OK (always)
7055 free_dv_routes_cb (void *cls,
7056 const struct GNUNET_PeerIdentity *pid,
7059 struct DistanceVector *dv = value;
7070 * Free ephemeral entry.
7074 * @param value a `struct EphemeralCacheEntry`
7075 * @return #GNUNET_OK (always)
7078 free_ephemeral_cb (void *cls,
7079 const struct GNUNET_PeerIdentity *pid,
7082 struct EphemeralCacheEntry *ece = value;
7086 free_ephemeral (ece);
7092 * Free validation state.
7096 * @param value a `struct ValidationState`
7097 * @return #GNUNET_OK (always)
7100 free_validation_state_cb (void *cls,
7101 const struct GNUNET_PeerIdentity *pid,
7104 struct ValidationState *vs = value;
7108 free_validation_state (vs);
7114 * Function called when the service shuts down. Unloads our plugins
7115 * and cancels pending validations.
7117 * @param cls closure, unused
7120 do_shutdown (void *cls)
7122 struct LearnLaunchEntry *lle;
7125 if (NULL != ephemeral_task)
7127 GNUNET_SCHEDULER_cancel (ephemeral_task);
7128 ephemeral_task = NULL;
7130 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7133 if (NULL != peerstore)
7135 GNUNET_PEERSTORE_disconnect (peerstore,
7139 if (NULL != GST_stats)
7141 GNUNET_STATISTICS_destroy (GST_stats,
7145 if (NULL != GST_my_private_key)
7147 GNUNET_free (GST_my_private_key);
7148 GST_my_private_key = NULL;
7150 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7152 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7153 &free_validation_state_cb,
7155 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7156 validation_map = NULL;
7157 while (NULL != (lle = lle_head))
7159 GNUNET_CONTAINER_DLL_remove (lle_head,
7164 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7166 GNUNET_CONTAINER_heap_destroy (validation_heap);
7167 validation_heap = NULL;
7168 GNUNET_CONTAINER_multipeermap_iterate (dv_routes,
7171 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7173 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7176 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7177 ephemeral_map = NULL;
7178 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7179 ephemeral_heap = NULL;
7184 * Initiate transport service.
7186 * @param cls closure
7187 * @param c configuration to use
7188 * @param service the initialized service
7192 const struct GNUNET_CONFIGURATION_Handle *c,
7193 struct GNUNET_SERVICE_Handle *service)
7199 neighbours = GNUNET_CONTAINER_multipeermap_create (1024,
7201 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024,
7203 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32,
7205 ephemeral_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7206 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7208 validation_map = GNUNET_CONTAINER_multipeermap_create (1024,
7210 validation_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7211 GST_my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7212 if (NULL == GST_my_private_key)
7214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7215 _("Transport service is lacking key configuration settings. Exiting.\n"));
7216 GNUNET_SCHEDULER_shutdown ();
7219 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7220 &GST_my_identity.public_key);
7221 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
7222 "My identity is `%s'\n",
7223 GNUNET_i2s_full (&GST_my_identity));
7224 GST_stats = GNUNET_STATISTICS_create ("transport",
7226 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
7228 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7229 if (NULL == peerstore)
7232 GNUNET_SCHEDULER_shutdown ();
7239 * Define "main" method using service macro.
7243 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7246 &client_disconnect_cb,
7248 /* communication with applications */
7249 GNUNET_MQ_hd_fixed_size (suggest,
7250 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7251 struct ExpressPreferenceMessage,
7253 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7254 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7255 struct ExpressPreferenceMessage,
7257 GNUNET_MQ_hd_var_size (request_hello_validation,
7258 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7259 struct RequestHelloValidationMessage,
7261 /* communication with core */
7262 GNUNET_MQ_hd_fixed_size (client_start,
7263 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7264 struct StartMessage,
7266 GNUNET_MQ_hd_var_size (client_send,
7267 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7268 struct OutboundMessage,
7270 /* communication with communicators */
7271 GNUNET_MQ_hd_var_size (communicator_available,
7272 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7273 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7275 GNUNET_MQ_hd_var_size (communicator_backchannel,
7276 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7277 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7279 GNUNET_MQ_hd_var_size (add_address,
7280 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7281 struct GNUNET_TRANSPORT_AddAddressMessage,
7283 GNUNET_MQ_hd_fixed_size (del_address,
7284 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7285 struct GNUNET_TRANSPORT_DelAddressMessage,
7287 GNUNET_MQ_hd_var_size (incoming_msg,
7288 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7289 struct GNUNET_TRANSPORT_IncomingMessage,
7291 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7292 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7293 struct GNUNET_TRANSPORT_CreateQueueResponse,
7295 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7296 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7297 struct GNUNET_TRANSPORT_CreateQueueResponse,
7299 GNUNET_MQ_hd_var_size (add_queue_message,
7300 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7301 struct GNUNET_TRANSPORT_AddQueueMessage,
7303 GNUNET_MQ_hd_var_size (address_consider_verify,
7304 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7305 struct GNUNET_TRANSPORT_AddressToVerify,
7307 GNUNET_MQ_hd_fixed_size (del_queue_message,
7308 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7309 struct GNUNET_TRANSPORT_DelQueueMessage,
7311 GNUNET_MQ_hd_fixed_size (send_message_ack,
7312 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
7313 struct GNUNET_TRANSPORT_SendMessageToAck,
7315 /* communication with monitors */
7316 GNUNET_MQ_hd_fixed_size (monitor_start,
7317 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
7318 struct GNUNET_TRANSPORT_MonitorStart,
7320 GNUNET_MQ_handler_end ());
7323 /* end of file gnunet-service-transport.c */