2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
27 * - retransmission logic
28 * - track RTT, distance, loss, etc. => requires extra data structures!
31 * - change transport-core API to provide proper flow control in both
32 * directions, allow multiple messages per peer simultaneously (tag
33 * confirmations with unique message ID), and replace quota-out with
34 * proper flow control;
35 * - if messages are below MTU, consider adding ACKs and other stuff
36 * (requires planning at receiver, and additional MST-style demultiplex
38 * - could avoid copying body of message into each fragment and keep
39 * fragments as just pointers into the original message and only
40 * fully build fragments just before transmission (optimization, should
41 * reduce CPU and memory use)
42 * - When we passively learned DV (with unconfirmed freshness), we
43 * right now add the path to our list but with a zero path_valid_until
44 * time and only use it for unconfirmed routes. However, we could consider
45 * triggering an explicit validation mechansim ourselves, specifically routing
46 * a challenge-response message over the path (OPTIMIZATION-FIXME).
48 * FIXME (without marks in the code!):
49 * - proper use/initialization of timestamps in messages exchanged
51 * - persistence of monotonic time obtained from other peers
52 * in PEERSTORE (by message type)
55 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
56 * against our pending message queue (requires additional per neighbour
57 * hash map to be maintained, avoids possible linear scan on pending msgs)
58 * - queue_send_msg and route_message both by API design have to make copies
59 * of the payload, and route_message on top of that requires a malloc/free.
60 * Change design to approximate "zero" copy better...
62 * Design realizations / discussion:
63 * - communicators do flow control by calling MQ "notify sent"
64 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
65 * or explicitly via backchannel FC ACKs. As long as the
66 * channel is not full, they may 'notify sent' even if the other
67 * peer has not yet confirmed receipt. The other peer confirming
68 * is _only_ for FC, not for more reliable transmission; reliable
69 * transmission (i.e. of fragments) is left to _transport_.
70 * - ACKs sent back in uni-directional communicators are done via
71 * the background channel API; here transport _may_ initially
72 * broadcast (with bounded # hops) if no path is known;
73 * - transport should _integrate_ DV-routing and build a view of
74 * the network; then background channel traffic can be
75 * routed via DV as well as explicit "DV" traffic.
76 * - background channel is also used for ACKs and NAT traversal support
77 * - transport service is responsible for AEAD'ing the background
78 * channel, timestamps and monotonic time are used against replay
79 * of old messages -> peerstore needs to be supplied with
80 * "latest timestamps seen" data
81 * - if transport implements DV, we likely need a 3rd peermap
82 * in addition to ephemerals and (direct) neighbours
83 * ==> check if stuff needs to be moved out of "Neighbour"
84 * - transport should encapsualte core-level messages and do its
85 * own ACKing for RTT/goodput/loss measurements _and_ fragment
89 #include "gnunet_util_lib.h"
90 #include "gnunet_statistics_service.h"
91 #include "gnunet_transport_monitor_service.h"
92 #include "gnunet_peerstore_service.h"
93 #include "gnunet_hello_lib.h"
94 #include "gnunet_signatures.h"
95 #include "transport.h"
99 * What is the size we assume for a read operation in the
100 * absence of an MTU for the purpose of flow control?
102 #define IN_PACKET_SIZE_WITHOUT_MTU 128
105 * Minimum number of hops we should forward DV learn messages
106 * even if they are NOT useful for us in hope of looping
107 * back to the initiator?
109 * FIXME: allow initiator some control here instead?
111 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
114 * Maximum DV distance allowed ever.
116 #define MAX_DV_HOPS_ALLOWED 16
119 * Maximum number of DV learning activities we may
120 * have pending at the same time.
122 #define MAX_DV_LEARN_PENDING 64
125 * Maximum number of DV paths we keep simultaneously to the same target.
127 #define MAX_DV_PATHS_TO_TARGET 3
130 * If a queue delays the next message by more than this number
131 * of seconds we log a warning. Note: this is for testing,
132 * the value chosen here might be too aggressively low!
134 #define DELAY_WARN_THRESHOLD \
135 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
138 * We only consider queues as "quality" connections when
139 * suppressing the generation of DV initiation messages if
140 * the latency of the queue is below this threshold.
142 #define DV_QUALITY_RTT_THRESHOLD \
143 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
146 * How long do we consider a DV path valid if we see no
147 * further updates on it? Note: the value chosen here might be too low!
149 #define DV_PATH_VALIDITY_TIMEOUT \
150 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
153 * How long before paths expire would we like to (re)discover DV paths? Should
154 * be below #DV_PATH_VALIDITY_TIMEOUT.
156 #define DV_PATH_DISCOVERY_FREQUENCY \
157 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
160 * How long are ephemeral keys valid?
162 #define EPHEMERAL_VALIDITY \
163 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
166 * How long do we keep partially reassembled messages around before giving up?
168 #define REASSEMBLY_EXPIRATION \
169 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
172 * What is the fastest rate at which we send challenges *if* we keep learning
173 * an address (gossip, DHT, etc.)?
175 #define FAST_VALIDATION_CHALLENGE_FREQ \
176 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
179 * What is the slowest rate at which we send challenges?
181 #define MAX_VALIDATION_CHALLENGE_FREQ \
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
185 * What is the non-randomized base frequency at which we
186 * would initiate DV learn messages?
188 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
191 * How many good connections (confirmed, bi-directional, not DV)
192 * do we need to have to suppress initiating DV learn messages?
194 #define DV_LEARN_QUALITY_THRESHOLD 100
197 * When do we forget an invalid address for sure?
199 #define MAX_ADDRESS_VALID_UNTIL \
200 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
203 * How long do we consider an address valid if we just checked?
205 #define ADDRESS_VALIDATION_LIFETIME \
206 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
209 * What is the maximum frequency at which we do address validation?
210 * A random value between 0 and this value is added when scheduling
211 * the #validation_task (both to ensure we do not validate too often,
212 * and to randomize a bit).
214 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
217 * How many network RTTs before an address validation expires should we begin
218 * trying to revalidate? (Note that the RTT used here is the one that we
219 * experienced during the last validation, not necessarily the latest RTT
222 #define VALIDATION_RTT_BUFFER_FACTOR 3
225 * How many messages can we have pending for a given communicator
226 * process before we start to throttle that communicator?
228 * Used if a communicator might be CPU-bound and cannot handle the traffic.
230 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
233 * How many messages can we have pending for a given queue (queue to
234 * a particular peer via a communicator) process before we start to
235 * throttle that queue?
237 #define QUEUE_LENGTH_LIMIT 32
240 GNUNET_NETWORK_STRUCT_BEGIN
243 * Outer layer of an encapsulated backchannel message.
245 struct TransportBackchannelEncapsulationMessage
248 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
250 struct GNUNET_MessageHeader header;
253 * Distance the backchannel message has traveled, to be updated at
254 * each hop. Used to bound the number of hops in case a backchannel
255 * message is broadcast and thus travels without routing
256 * information (during initial backchannel discovery).
261 * Target's peer identity (as backchannels may be transmitted
262 * indirectly, or even be broadcast).
264 struct GNUNET_PeerIdentity target;
267 * Ephemeral key setup by the sender for @e target, used
268 * to encrypt the payload.
270 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
273 * We use an IV here as the @e ephemeral_key is re-used for
274 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
276 struct GNUNET_ShortHashCode iv;
279 * HMAC over the ciphertext of the encrypted, variable-size
280 * body that follows. Verified via DH of @e target and
283 struct GNUNET_HashCode hmac;
285 /* Followed by encrypted, variable-size payload */
290 * Body by which a peer confirms that it is using an ephemeral key.
292 struct EphemeralConfirmation
296 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
298 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
301 * How long is this signature over the ephemeral key valid?
303 * Note that the receiver MUST IGNORE the absolute time, and only interpret
304 * the value as a mononic time and reject "older" values than the last one
305 * observed. This is necessary as we do not want to require synchronized
306 * clocks and may not have a bidirectional communication channel.
308 * Even with this, there is no real guarantee against replay achieved here,
309 * unless the latest timestamp is persisted. While persistence should be
310 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
311 * communicators must protect against replay attacks when using backchannel
314 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
317 * Target's peer identity.
319 struct GNUNET_PeerIdentity target;
322 * Ephemeral key setup by the sender for @e target, used
323 * to encrypt the payload.
325 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
330 * Plaintext of the variable-size payload that is encrypted
331 * within a `struct TransportBackchannelEncapsulationMessage`
333 struct TransportBackchannelRequestPayload
337 * Sender's peer identity.
339 struct GNUNET_PeerIdentity sender;
342 * Signature of the sender over an
343 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
345 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
348 * How long is this signature over the ephemeral key valid?
350 * Note that the receiver MUST IGNORE the absolute time, and only interpret
351 * the value as a mononic time and reject "older" values than the last one
352 * observed. This is necessary as we do not want to require synchronized
353 * clocks and may not have a bidirectional communication channel.
355 * Even with this, there is no real guarantee against replay achieved here,
356 * unless the latest timestamp is persisted. While persistence should be
357 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
358 * communicators must protect against replay attacks when using backchannel
361 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
364 * Current monotonic time of the sending transport service. Used to
365 * detect replayed messages. Note that the receiver should remember
366 * a list of the recently seen timestamps and only reject messages
367 * if the timestamp is in the list, or the list is "full" and the
368 * timestamp is smaller than the lowest in the list.
370 * Like the @e ephemeral_validity, the list of timestamps per peer should be
371 * persisted to guard against replays after restarts.
373 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
375 /* Followed by a `struct GNUNET_MessageHeader` with a message
376 for a communicator */
378 /* Followed by a 0-termianted string specifying the name of
379 the communicator which is to receive the message */
384 * Outer layer of an encapsulated unfragmented application message sent
385 * over an unreliable channel.
387 struct TransportReliabilityBox
390 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
392 struct GNUNET_MessageHeader header;
395 * Number of messages still to be sent before a commulative
396 * ACK is requested. Zero if an ACK is requested immediately.
397 * In NBO. Note that the receiver may send the ACK faster
398 * if it believes that is reasonable.
400 uint32_t ack_countdown GNUNET_PACKED;
403 * Unique ID of the message used for signalling receipt of
404 * messages sent over possibly unreliable channels. Should
407 struct GNUNET_ShortHashCode msg_uuid;
412 * Confirmation that the receiver got a
413 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
414 * confirmation may be transmitted over a completely different queue,
415 * so ACKs are identified by a combination of PID of sender and
416 * message UUID, without the queue playing any role!
418 struct TransportReliabilityAckMessage
421 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
423 struct GNUNET_MessageHeader header;
428 uint32_t reserved GNUNET_PACKED;
431 * How long was the ACK delayed relative to the average time of
432 * receipt of the messages being acknowledged? Used to calculate
433 * the average RTT by taking the receipt time of the ack minus the
434 * average transmission time of the sender minus this value.
436 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
438 /* followed by any number of `struct GNUNET_ShortHashCode`
439 messages providing ACKs */
444 * Outer layer of an encapsulated fragmented application message.
446 struct TransportFragmentBox
449 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
451 struct GNUNET_MessageHeader header;
454 * Unique ID of this fragment (and fragment transmission!). Will
455 * change even if a fragement is retransmitted to make each
456 * transmission attempt unique! Should be incremented by one for
457 * each fragment transmission. If a client receives a duplicate
458 * fragment (same @e frag_off), it must send
459 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
461 uint32_t frag_uuid GNUNET_PACKED;
464 * Original message ID for of the message that all the1
465 * fragments belong to. Must be the same for all fragments.
467 struct GNUNET_ShortHashCode msg_uuid;
470 * Offset of this fragment in the overall message.
472 uint16_t frag_off GNUNET_PACKED;
475 * Total size of the message that is being fragmented.
477 uint16_t msg_size GNUNET_PACKED;
482 * Outer layer of an fragmented application message sent over a queue
483 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
484 * received, the receiver has two RTTs or 64 further fragments with
485 * the same basic message time to send an acknowledgement, possibly
486 * acknowledging up to 65 fragments in one ACK. ACKs must also be
487 * sent immediately once all fragments were sent.
489 struct TransportFragmentAckMessage
492 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
494 struct GNUNET_MessageHeader header;
497 * Unique ID of the lowest fragment UUID being acknowledged.
499 uint32_t frag_uuid GNUNET_PACKED;
502 * Bitfield of up to 64 additional fragments following the
503 * @e msg_uuid being acknowledged by this message.
505 uint64_t extra_acks GNUNET_PACKED;
508 * Original message ID for of the message that all the
509 * fragments belong to.
511 struct GNUNET_ShortHashCode msg_uuid;
514 * How long was the ACK delayed relative to the average time of
515 * receipt of the fragments being acknowledged? Used to calculate
516 * the average RTT by taking the receipt time of the ack minus the
517 * average transmission time of the sender minus this value.
519 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
522 * How long until the receiver will stop trying reassembly
525 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
530 * Content signed by the initator during DV learning.
532 * The signature is required to prevent DDoS attacks. A peer sending out this
533 * message is potentially generating a lot of traffic that will go back to the
534 * initator, as peers receiving this message will try to let the initiator
535 * know that they got the message.
537 * Without this signature, an attacker could abuse this mechanism for traffic
538 * amplification, sending a lot of traffic to a peer by putting out this type
539 * of message with the victim's peer identity.
541 * Even with just a signature, traffic amplification would be possible via
542 * replay attacks. The @e monotonic_time limits such replay attacks, as every
543 * potential amplificator will check the @e monotonic_time and only respond
544 * (at most) once per message.
549 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
551 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
554 * Time at the initiator when generating the signature.
556 * Note that the receiver MUST IGNORE the absolute time, and only interpret
557 * the value as a mononic time and reject "older" values than the last one
558 * observed. This is necessary as we do not want to require synchronized
559 * clocks and may not have a bidirectional communication channel.
561 * Even with this, there is no real guarantee against replay achieved here,
562 * unless the latest timestamp is persisted. Persistence should be
563 * provided via PEERSTORE if possible.
565 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
568 * Challenge value used by the initiator to re-identify the path.
570 struct GNUNET_ShortHashCode challenge;
575 * Content signed by each peer during DV learning.
577 * This assues the initiator of the DV learning operation that the hop from @e
578 * pred via the signing peer to @e succ actually exists. This makes it
579 * impossible for an adversary to supply the network with bogus routes.
581 * The @e challenge is included to provide replay protection for the
582 * initiator. This way, the initiator knows that the hop existed after the
583 * original @e challenge was first transmitted, providing a freshness metric.
585 * Peers other than the initiator that passively learn paths by observing
586 * these messages do NOT benefit from this. Here, an adversary may indeed
587 * replay old messages. Thus, passively learned paths should always be
588 * immediately marked as "potentially stale".
593 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
595 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
598 * Identity of the previous peer on the path.
600 struct GNUNET_PeerIdentity pred;
603 * Identity of the next peer on the path.
605 struct GNUNET_PeerIdentity succ;
608 * Challenge value used by the initiator to re-identify the path.
610 struct GNUNET_ShortHashCode challenge;
615 * An entry describing a peer on a path in a
616 * `struct TransportDVLearn` message.
621 * Identity of a peer on the path.
623 struct GNUNET_PeerIdentity hop;
626 * Signature of this hop over the path, of purpose
627 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
629 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
634 * Internal message used by transport for distance vector learning.
635 * If @e num_hops does not exceed the threshold, peers should append
636 * themselves to the peer list and flood the message (possibly only
637 * to a subset of their neighbours to limit discoverability of the
638 * network topology). To the extend that the @e bidirectional bits
639 * are set, peers may learn the inverse paths even if they did not
642 * Unless received on a bidirectional queue and @e num_hops just
643 * zero, peers that can forward to the initator should always try to
644 * forward to the initiator.
646 struct TransportDVLearn
649 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
651 struct GNUNET_MessageHeader header;
654 * Number of hops this messages has travelled, in NBO. Zero if
657 uint16_t num_hops GNUNET_PACKED;
660 * Bitmask of the last 16 hops indicating whether they are confirmed
661 * available (without DV) in both directions or not, in NBO. Used
662 * to possibly instantly learn a path in both directions. Each peer
663 * should shift this value by one to the left, and then set the
664 * lowest bit IF the current sender can be reached from it (without
667 uint16_t bidirectional GNUNET_PACKED;
670 * Peers receiving this message and delaying forwarding to other
671 * peers for any reason should increment this value by the non-network
672 * delay created by the peer.
674 struct GNUNET_TIME_RelativeNBO non_network_delay;
677 * Signature of this hop over the path, of purpose
678 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
680 struct GNUNET_CRYPTO_EddsaSignature init_sig;
683 * Identity of the peer that started this learning activity.
685 struct GNUNET_PeerIdentity initiator;
688 * Challenge value used by the initiator to re-identify the path.
690 struct GNUNET_ShortHashCode challenge;
692 /* Followed by @e num_hops `struct DVPathEntryP` values,
693 excluding the initiator of the DV trace; the last entry is the
694 current sender; the current peer must not be included. */
699 * Outer layer of an encapsulated message send over multiple hops.
700 * The path given only includes the identities of the subsequent
701 * peers, i.e. it will be empty if we are the receiver. Each
702 * forwarding peer should scan the list from the end, and if it can,
703 * forward to the respective peer. The list should then be shortened
704 * by all the entries up to and including that peer. Each hop should
705 * also increment @e total_hops to allow the receiver to get a precise
706 * estimate on the number of hops the message travelled. Senders must
707 * provide a learned path that thus should work, but intermediaries
708 * know of a shortcut, they are allowed to send the message via that
711 * If a peer finds itself still on the list, it must drop the message.
713 struct TransportDVBox
716 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
718 struct GNUNET_MessageHeader header;
721 * Number of total hops this messages travelled. In NBO.
722 * @e origin sets this to zero, to be incremented at
725 uint16_t total_hops GNUNET_PACKED;
728 * Number of hops this messages includes. In NBO.
730 uint16_t num_hops GNUNET_PACKED;
733 * Identity of the peer that originated the message.
735 struct GNUNET_PeerIdentity origin;
737 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
738 excluding the @e origin and the current peer, the last must be
739 the ultimate target; if @e num_hops is zero, the receiver of this
740 message is the ultimate target. */
742 /* Followed by the actual message, which itself may be
743 another box, but not a DV_LEARN or DV_BOX message! */
748 * Message send to another peer to validate that it can indeed
749 * receive messages at a particular address.
751 struct TransportValidationChallenge
755 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
757 struct GNUNET_MessageHeader header;
762 uint32_t reserved GNUNET_PACKED;
765 * Challenge to be signed by the receiving peer.
767 struct GNUNET_ShortHashCode challenge;
770 * Timestamp of the sender, to be copied into the reply
771 * to allow sender to calculate RTT.
773 struct GNUNET_TIME_AbsoluteNBO sender_time;
778 * Message signed by a peer to confirm that it can indeed
779 * receive messages at a particular address.
781 struct TransportValidationPS
785 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
787 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
790 * How long does the sender believe the address on
791 * which the challenge was received to remain valid?
793 struct GNUNET_TIME_RelativeNBO validity_duration;
796 * Challenge signed by the receiving peer.
798 struct GNUNET_ShortHashCode challenge;
803 * Message send to a peer to respond to a
804 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
806 struct TransportValidationResponse
810 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
812 struct GNUNET_MessageHeader header;
817 uint32_t reserved GNUNET_PACKED;
820 * The peer's signature matching the
821 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
823 struct GNUNET_CRYPTO_EddsaSignature signature;
826 * The challenge that was signed by the receiving peer.
828 struct GNUNET_ShortHashCode challenge;
831 * Original timestamp of the sender (was @code{sender_time}),
832 * copied into the reply to allow sender to calculate RTT.
834 struct GNUNET_TIME_AbsoluteNBO origin_time;
837 * How long does the sender believe this address to remain
840 struct GNUNET_TIME_RelativeNBO validity_duration;
844 GNUNET_NETWORK_STRUCT_END
848 * What type of client is the `struct TransportClient` about?
853 * We do not know yet (client is fresh).
858 * Is the CORE service, we need to forward traffic to it.
863 * It is a monitor, forward monitor data.
868 * It is a communicator, use for communication.
873 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
880 * When did we launch this DV learning activity?
882 struct LearnLaunchEntry
886 * Kept (also) in a DLL sorted by launch time.
888 struct LearnLaunchEntry *prev;
891 * Kept (also) in a DLL sorted by launch time.
893 struct LearnLaunchEntry *next;
896 * Challenge that uniquely identifies this activity.
898 struct GNUNET_ShortHashCode challenge;
901 * When did we transmit the DV learn message (used to calculate RTT) and
902 * determine freshness of paths learned via this operation.
904 struct GNUNET_TIME_Absolute launch_time;
909 * Entry in our cache of ephemeral keys we currently use. This way, we only
910 * sign an ephemeral once per @e target, and then can re-use it over multiple
911 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
912 * signing is expensive and in some cases we may use backchannel messages a
915 struct EphemeralCacheEntry
919 * Target's peer identity (we don't re-use ephemerals
920 * to limit linkability of messages).
922 struct GNUNET_PeerIdentity target;
925 * Signature affirming @e ephemeral_key of type
926 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
928 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
931 * How long is @e sender_sig valid
933 struct GNUNET_TIME_Absolute ephemeral_validity;
938 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
941 * Our private ephemeral key.
943 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
946 * Node in the ephemeral cache for this entry.
947 * Used for expiration.
949 struct GNUNET_CONTAINER_HeapNode *hn;
954 * Client connected to the transport service.
956 struct TransportClient;
960 * A neighbour that at least one communicator is connected to.
966 * Entry in our #dv_routes table, representing a (set of) distance
967 * vector routes to a particular peer.
969 struct DistanceVector;
972 * One possible hop towards a DV target.
974 struct DistanceVectorHop
978 * Kept in a MDLL, sorted by @e timeout.
980 struct DistanceVectorHop *next_dv;
983 * Kept in a MDLL, sorted by @e timeout.
985 struct DistanceVectorHop *prev_dv;
990 struct DistanceVectorHop *next_neighbour;
995 struct DistanceVectorHop *prev_neighbour;
998 * What would be the next hop to @e target?
1000 struct Neighbour *next_hop;
1003 * Distance vector entry this hop belongs with.
1005 struct DistanceVector *dv;
1008 * Array of @e distance hops to the target, excluding @e next_hop.
1009 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1010 * at the end of this struct. Excludes the target itself!
1012 const struct GNUNET_PeerIdentity *path;
1015 * At what time do we forget about this path unless we see it again
1018 struct GNUNET_TIME_Absolute timeout;
1021 * For how long is the validation of this path considered
1023 * Set to ZERO if the path is learned by snooping on DV learn messages
1024 * initiated by other peers, and to the time at which we generated the
1025 * challenge for DV learn operations this peer initiated.
1027 struct GNUNET_TIME_Absolute path_valid_until;
1030 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1031 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1034 unsigned int distance;
1039 * Entry in our #dv_routes table, representing a (set of) distance
1040 * vector routes to a particular peer.
1042 struct DistanceVector
1046 * To which peer is this a route?
1048 struct GNUNET_PeerIdentity target;
1051 * Known paths to @e target.
1053 struct DistanceVectorHop *dv_head;
1056 * Known paths to @e target.
1058 struct DistanceVectorHop *dv_tail;
1061 * Task scheduled to purge expired paths from @e dv_head MDLL.
1063 struct GNUNET_SCHEDULER_Task *timeout_task;
1066 * Task scheduled to possibly notfiy core that this queue is no longer
1067 * counting as confirmed. Runs the #core_queue_visibility_check().
1069 struct GNUNET_SCHEDULER_Task *visibility_task;
1072 * Quota at which CORE is allowed to transmit to this peer
1073 * (note that the value CORE should actually be told is this
1074 * value plus the respective value in `struct Neighbour`).
1075 * Should match the sum of the quotas of all of the paths.
1077 * FIXME: not yet set, tricky to get right given multiple paths,
1078 * many of which may be inactive! (=> Idea: measure???)
1079 * FIXME: how do we set this value initially when we tell CORE?
1080 * Options: start at a minimum value or at literally zero?
1081 * (=> Current thought: clean would be zero!)
1083 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1086 * Is one of the DV paths in this struct 'confirmed' and thus
1087 * the cause for CORE to see this peer as connected? (Note that
1088 * the same may apply to a `struct Neighbour` at the same time.)
1095 * A queue is a message queue provided by a communicator
1096 * via which we can reach a particular neighbour.
1101 * Message awaiting transmission. See detailed comments below.
1103 struct PendingMessage;
1106 * Entry identifying transmission in one of our `struct
1107 * Queue` which still awaits an ACK. This is used to
1108 * ensure we do not overwhelm a communicator and limit the number of
1109 * messages outstanding per communicator (say in case communicator is
1110 * CPU bound) and per queue (in case bandwidth allocation exceeds
1111 * what the communicator can actually provide towards a particular
1120 struct QueueEntry *next;
1125 struct QueueEntry *prev;
1128 * Queue this entry is queued with.
1130 struct Queue *queue;
1133 * Pending message this entry is for, or NULL for none.
1135 struct PendingMessage *pm;
1138 * Message ID used for this message with the queue used for transmission.
1145 * A queue is a message queue provided by a communicator
1146 * via which we can reach a particular neighbour.
1153 struct Queue *next_neighbour;
1158 struct Queue *prev_neighbour;
1163 struct Queue *prev_client;
1168 struct Queue *next_client;
1171 * Head of DLL of unacked transmission requests.
1173 struct QueueEntry *queue_head;
1176 * End of DLL of unacked transmission requests.
1178 struct QueueEntry *queue_tail;
1181 * Which neighbour is this queue for?
1183 struct Neighbour *neighbour;
1186 * Which communicator offers this queue?
1188 struct TransportClient *tc;
1191 * Address served by the queue.
1193 const char *address;
1196 * Task scheduled for the time when this queue can (likely) transmit the
1197 * next message. Still needs to check with the @e tracker_out to be sure.
1199 struct GNUNET_SCHEDULER_Task *transmit_task;
1202 * Task scheduled to possibly notfiy core that this queue is no longer
1203 * counting as confirmed. Runs the #core_queue_visibility_check().
1205 struct GNUNET_SCHEDULER_Task *visibility_task;
1208 * Our current RTT estimate for this queue.
1210 struct GNUNET_TIME_Relative rtt;
1213 * How long do *we* consider this @e address to be valid? In the past or
1214 * zero if we have not yet validated it. Can be updated based on
1215 * challenge-response validations (via address validation logic), or when we
1216 * receive ACKs that we can definitively map to transmissions via this
1219 struct GNUNET_TIME_Absolute validated_until;
1222 * Message ID generator for transmissions on this queue.
1227 * Unique identifier of this queue with the communicator.
1232 * Maximum transmission unit supported by this queue.
1239 uint32_t num_msg_pending;
1244 uint32_t num_bytes_pending;
1247 * Length of the DLL starting at @e queue_head.
1249 unsigned int queue_length;
1252 * Network type offered by this queue.
1254 enum GNUNET_NetworkType nt;
1257 * Connection status for this queue.
1259 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1262 * How much outbound bandwidth do we have available for this queue?
1264 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1267 * How much inbound bandwidth do we have available for this queue?
1269 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1274 * Information we keep for a message that we are reassembling.
1276 struct ReassemblyContext
1280 * Original message ID for of the message that all the
1281 * fragments belong to.
1283 struct GNUNET_ShortHashCode msg_uuid;
1286 * Which neighbour is this context for?
1288 struct Neighbour *neighbour;
1291 * Entry in the reassembly heap (sorted by expiration).
1293 struct GNUNET_CONTAINER_HeapNode *hn;
1296 * Bitfield with @e msg_size bits representing the positions
1297 * where we have received fragments. When we receive a fragment,
1298 * we check the bits in @e bitfield before incrementing @e msg_missing.
1300 * Allocated after the reassembled message.
1305 * Task for sending ACK. We may send ACKs either because of hitting
1306 * the @e extra_acks limit, or based on time and @e num_acks. This
1307 * task is for the latter case.
1309 struct GNUNET_SCHEDULER_Task *ack_task;
1312 * At what time will we give up reassembly of this message?
1314 struct GNUNET_TIME_Absolute reassembly_timeout;
1317 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1318 * Should be reset to zero when @e num_acks is set to 0.
1320 struct GNUNET_TIME_Relative avg_ack_delay;
1323 * Time we received the last fragment. @e avg_ack_delay must be
1324 * incremented by now - @e last_frag multiplied by @e num_acks.
1326 struct GNUNET_TIME_Absolute last_frag;
1329 * Bitfield of up to 64 additional fragments following @e frag_uuid
1330 * to be acknowledged in the next cummulative ACK.
1332 uint64_t extra_acks;
1335 * Unique ID of the lowest fragment UUID to be acknowledged in the
1336 * next cummulative ACK. Only valid if @e num_acks > 0.
1341 * Number of ACKs we have accumulated so far. Reset to 0
1342 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1344 unsigned int num_acks;
1347 * How big is the message we are reassembling in total?
1352 * How many bytes of the message are still missing? Defragmentation
1353 * is complete when @e msg_missing == 0.
1355 uint16_t msg_missing;
1357 /* Followed by @e msg_size bytes of the (partially) defragmented original
1360 /* Followed by @e bitfield data */
1365 * A neighbour that at least one communicator is connected to.
1371 * Which peer is this about?
1373 struct GNUNET_PeerIdentity pid;
1376 * Map with `struct ReassemblyContext` structs for fragments under
1377 * reassembly. May be NULL if we currently have no fragments from
1378 * this @e pid (lazy initialization).
1380 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1383 * Heap with `struct ReassemblyContext` structs for fragments under
1384 * reassembly. May be NULL if we currently have no fragments from
1385 * this @e pid (lazy initialization).
1387 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1390 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1392 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1395 * Head of list of messages pending for this neighbour.
1397 struct PendingMessage *pending_msg_head;
1400 * Tail of list of messages pending for this neighbour.
1402 struct PendingMessage *pending_msg_tail;
1405 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1406 * purged if this neighbour goes down.
1408 struct DistanceVectorHop *dv_head;
1411 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1412 * purged if this neighbour goes down.
1414 struct DistanceVectorHop *dv_tail;
1417 * Head of DLL of queues to this peer.
1419 struct Queue *queue_head;
1422 * Tail of DLL of queues to this peer.
1424 struct Queue *queue_tail;
1427 * Task run to cleanup pending messages that have exceeded their timeout.
1429 struct GNUNET_SCHEDULER_Task *timeout_task;
1432 * Quota at which CORE is allowed to transmit to this peer
1433 * (note that the value CORE should actually be told is this
1434 * value plus the respective value in `struct DistanceVector`).
1435 * Should match the sum of the quotas of all of the queues.
1437 * FIXME: not yet set, tricky to get right given multiple queues!
1438 * (=> Idea: measure???)
1439 * FIXME: how do we set this value initially when we tell CORE?
1440 * Options: start at a minimum value or at literally zero?
1441 * (=> Current thought: clean would be zero!)
1443 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1446 * What is the earliest timeout of any message in @e pending_msg_tail?
1448 struct GNUNET_TIME_Absolute earliest_timeout;
1451 * Do we have a confirmed working queue and are thus visible to
1459 * A peer that an application (client) would like us to talk to directly.
1465 * Which peer is this about?
1467 struct GNUNET_PeerIdentity pid;
1470 * Client responsible for the request.
1472 struct TransportClient *tc;
1475 * Handle for watching the peerstore for HELLOs for this peer.
1477 struct GNUNET_PEERSTORE_WatchContext *wc;
1480 * What kind of performance preference does this @e tc have?
1482 enum GNUNET_MQ_PreferenceKind pk;
1485 * How much bandwidth would this @e tc like to see?
1487 struct GNUNET_BANDWIDTH_Value32NBO bw;
1492 * Types of different pending messages.
1494 enum PendingMessageType
1498 * Ordinary message received from the CORE service.
1505 PMT_FRAGMENT_BOX = 1,
1510 PMT_RELIABILITY_BOX = 2,
1513 * Any type of acknowledgement.
1515 PMT_ACKNOWLEDGEMENT = 3,
1518 * Control traffic generated by the TRANSPORT service itself.
1526 * Transmission request that is awaiting delivery. The original
1527 * transmission requests from CORE may be too big for some queues.
1528 * In this case, a *tree* of fragments is created. At each
1529 * level of the tree, fragments are kept in a DLL ordered by which
1530 * fragment should be sent next (at the head). The tree is searched
1531 * top-down, with the original message at the root.
1533 * To select a node for transmission, first it is checked if the
1534 * current node's message fits with the MTU. If it does not, we
1535 * either calculate the next fragment (based on @e frag_off) from the
1536 * current node, or, if all fragments have already been created,
1537 * descend to the @e head_frag. Even though the node was already
1538 * fragmented, the fragment may be too big if the fragment was
1539 * generated for a queue with a larger MTU. In this case, the node
1540 * may be fragmented again, thus creating a tree.
1542 * When acknowledgements for fragments are received, the tree
1543 * must be pruned, removing those parts that were already
1544 * acknowledged. When fragments are sent over a reliable
1545 * channel, they can be immediately removed.
1547 * If a message is ever fragmented, then the original "full" message
1548 * is never again transmitted (even if it fits below the MTU), and
1549 * only (remaining) fragments are sent.
1551 struct PendingMessage
1554 * Kept in a MDLL of messages for this @a target.
1556 struct PendingMessage *next_neighbour;
1559 * Kept in a MDLL of messages for this @a target.
1561 struct PendingMessage *prev_neighbour;
1564 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1566 struct PendingMessage *next_client;
1569 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1571 struct PendingMessage *prev_client;
1574 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1575 * #PMT_FRAGMENT_BOx)
1577 struct PendingMessage *next_frag;
1580 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1581 * #PMT_FRAGMENT_BOX)
1583 struct PendingMessage *prev_frag;
1586 * This message, reliability boxed. Only possibly available if @e pmt is
1589 struct PendingMessage *bpm;
1592 * Target of the request.
1594 struct Neighbour *target;
1597 * Set to non-NULL value if this message is currently being given to a
1598 * communicator and we are awaiting that communicator's acknowledgement.
1599 * Note that we must not retransmit a pending message while we're still
1600 * in the process of giving it to a communicator. If a pending message
1601 * is free'd while this entry is non-NULL, the @e qe reference to us
1602 * should simply be set to NULL.
1604 struct QueueEntry *qe;
1607 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1609 struct TransportClient *client;
1612 * Head of a MDLL of fragments created for this core message.
1614 struct PendingMessage *head_frag;
1617 * Tail of a MDLL of fragments created for this core message.
1619 struct PendingMessage *tail_frag;
1622 * Our parent in the fragmentation tree.
1624 struct PendingMessage *frag_parent;
1627 * At what time should we give up on the transmission (and no longer retry)?
1629 struct GNUNET_TIME_Absolute timeout;
1632 * What is the earliest time for us to retry transmission of this message?
1634 struct GNUNET_TIME_Absolute next_attempt;
1637 * UUID to use for this message (used for reassembly of fragments, only
1638 * initialized if @e msg_uuid_set is #GNUNET_YES).
1640 struct GNUNET_ShortHashCode msg_uuid;
1643 * Counter incremented per generated fragment.
1645 uint32_t frag_uuidgen;
1648 * Type of the pending message.
1650 enum PendingMessageType pmt;
1653 * Size of the original message.
1658 * Offset at which we should generate the next fragment.
1663 * #GNUNET_YES once @e msg_uuid was initialized
1665 int16_t msg_uuid_set;
1667 /* Followed by @e bytes_msg to transmit */
1672 * One of the addresses of this peer.
1674 struct AddressListEntry
1680 struct AddressListEntry *next;
1685 struct AddressListEntry *prev;
1688 * Which communicator provides this address?
1690 struct TransportClient *tc;
1693 * The actual address.
1695 const char *address;
1698 * Current context for storing this address in the peerstore.
1700 struct GNUNET_PEERSTORE_StoreContext *sc;
1703 * Task to periodically do @e st operation.
1705 struct GNUNET_SCHEDULER_Task *st;
1708 * What is a typical lifetime the communicator expects this
1709 * address to have? (Always from now.)
1711 struct GNUNET_TIME_Relative expiration;
1714 * Address identifier used by the communicator.
1719 * Network type offered by this address.
1721 enum GNUNET_NetworkType nt;
1726 * Client connected to the transport service.
1728 struct TransportClient
1734 struct TransportClient *next;
1739 struct TransportClient *prev;
1742 * Handle to the client.
1744 struct GNUNET_SERVICE_Client *client;
1747 * Message queue to the client.
1749 struct GNUNET_MQ_Handle *mq;
1752 * What type of client is this?
1754 enum ClientType type;
1760 * Information for @e type #CT_CORE.
1766 * Head of list of messages pending for this client, sorted by
1767 * transmission time ("next_attempt" + possibly internal prioritization).
1769 struct PendingMessage *pending_msg_head;
1772 * Tail of list of messages pending for this client.
1774 struct PendingMessage *pending_msg_tail;
1779 * Information for @e type #CT_MONITOR.
1785 * Peer identity to monitor the addresses of.
1786 * Zero to monitor all neighbours. Valid if
1787 * @e type is #CT_MONITOR.
1789 struct GNUNET_PeerIdentity peer;
1792 * Is this a one-shot monitor?
1800 * Information for @e type #CT_COMMUNICATOR.
1805 * If @e type is #CT_COMMUNICATOR, this communicator
1806 * supports communicating using these addresses.
1808 char *address_prefix;
1811 * Head of DLL of queues offered by this communicator.
1813 struct Queue *queue_head;
1816 * Tail of DLL of queues offered by this communicator.
1818 struct Queue *queue_tail;
1821 * Head of list of the addresses of this peer offered by this
1824 struct AddressListEntry *addr_head;
1827 * Tail of list of the addresses of this peer offered by this
1830 struct AddressListEntry *addr_tail;
1833 * Number of queue entries in all queues to this communicator. Used
1834 * throttle sending to a communicator if we see that the communicator
1835 * is globally unable to keep up.
1837 unsigned int total_queue_length;
1840 * Characteristics of this communicator.
1842 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1847 * Information for @e type #CT_APPLICATION
1853 * Map of requests for peers the given client application would like to
1854 * see connections for. Maps from PIDs to `struct PeerRequest`.
1856 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1865 * State we keep for validation activities. Each of these
1866 * is both in the #validation_heap and the #validation_map.
1868 struct ValidationState
1872 * For which peer is @a address to be validated (or possibly valid)?
1873 * Serves as key in the #validation_map.
1875 struct GNUNET_PeerIdentity pid;
1878 * How long did the peer claim this @e address to be valid? Capped at
1879 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1880 * were told about the address and the value claimed by the other peer at
1881 * that time. May be updated similarly when validation succeeds.
1883 struct GNUNET_TIME_Absolute valid_until;
1886 * How long do *we* consider this @e address to be valid?
1887 * In the past or zero if we have not yet validated it.
1889 struct GNUNET_TIME_Absolute validated_until;
1892 * When did we FIRST use the current @e challenge in a message?
1893 * Used to sanity-check @code{origin_time} in the response when
1894 * calculating the RTT. If the @code{origin_time} is not in
1895 * the expected range, the response is discarded as malicious.
1897 struct GNUNET_TIME_Absolute first_challenge_use;
1900 * When did we LAST use the current @e challenge in a message?
1901 * Used to sanity-check @code{origin_time} in the response when
1902 * calculating the RTT. If the @code{origin_time} is not in
1903 * the expected range, the response is discarded as malicious.
1905 struct GNUNET_TIME_Absolute last_challenge_use;
1908 * Next time we will send the @e challenge to the peer, if this time is past
1909 * @e valid_until, this validation state is released at this time. If the
1910 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1911 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1912 * to re-validate before the validity actually expires.
1914 struct GNUNET_TIME_Absolute next_challenge;
1917 * Current backoff factor we're applying for sending the @a challenge.
1918 * Reset to 0 if the @a challenge is confirmed upon validation.
1919 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1920 * existing value if we receive an unvalidated address again over
1921 * another channel (and thus should consider the information "fresh").
1922 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1924 struct GNUNET_TIME_Relative challenge_backoff;
1927 * Initially set to "forever". Once @e validated_until is set, this value is
1928 * set to the RTT that tells us how long it took to receive the validation.
1930 struct GNUNET_TIME_Relative validation_rtt;
1933 * The challenge we sent to the peer to get it to validate the address. Note
1934 * that we rotate the challenge whenever we update @e validated_until to
1935 * avoid attacks where a peer simply replays an old challenge in the future.
1936 * (We must not rotate more often as otherwise we may discard valid answers
1937 * due to packet losses, latency and reorderings on the network).
1939 struct GNUNET_ShortHashCode challenge;
1942 * Claimed address of the peer.
1947 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1948 * heap is used to figure out when the next validation activity should be
1951 struct GNUNET_CONTAINER_HeapNode *hn;
1954 * Handle to a PEERSTORE store operation for this @e address. NULL if
1955 * no PEERSTORE operation is pending.
1957 struct GNUNET_PEERSTORE_StoreContext *sc;
1960 * We are technically ready to send the challenge, but we are waiting for
1961 * the respective queue to become available for transmission.
1968 * Head of linked list of all clients to this service.
1970 static struct TransportClient *clients_head;
1973 * Tail of linked list of all clients to this service.
1975 static struct TransportClient *clients_tail;
1978 * Statistics handle.
1980 static struct GNUNET_STATISTICS_Handle *GST_stats;
1983 * Configuration handle.
1985 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1990 static struct GNUNET_PeerIdentity GST_my_identity;
1995 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1998 * Map from PIDs to `struct Neighbour` entries. A peer is
1999 * a neighbour if we have an MQ to it from some communicator.
2001 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2004 * Map from PIDs to `struct DistanceVector` entries describing
2005 * known paths to the peer.
2007 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2010 * Map from PIDs to `struct ValidationState` entries describing
2011 * addresses we are aware of and their validity state.
2013 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2016 * Map from challenges to `struct LearnLaunchEntry` values.
2018 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2021 * Head of a DLL sorted by launch time.
2023 static struct LearnLaunchEntry *lle_head;
2026 * Tail of a DLL sorted by launch time.
2028 static struct LearnLaunchEntry *lle_tail;
2031 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2032 * sorting addresses we are aware of by when we should next try to (re)validate
2035 static struct GNUNET_CONTAINER_Heap *validation_heap;
2038 * Database for peer's HELLOs.
2040 static struct GNUNET_PEERSTORE_Handle *peerstore;
2043 * Heap sorting `struct EphemeralCacheEntry` by their
2044 * key/signature validity.
2046 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2049 * Hash map for looking up `struct EphemeralCacheEntry`s
2050 * by peer identity. (We may have ephemerals in our
2051 * cache for which we do not have a neighbour entry,
2052 * and similar many neighbours may not need ephemerals,
2053 * so we use a second map.)
2055 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2058 * Task to free expired ephemerals.
2060 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2063 * Task run to initiate DV learning.
2065 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2068 * Task to run address validation.
2070 static struct GNUNET_SCHEDULER_Task *validation_task;
2074 * Free cached ephemeral key.
2076 * @param ece cached signature to free
2079 free_ephemeral (struct EphemeralCacheEntry *ece)
2081 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2082 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2088 * Free validation state.
2090 * @param vs validation state to free
2093 free_validation_state (struct ValidationState *vs)
2095 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2096 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2100 GNUNET_PEERSTORE_store_cancel (vs->sc);
2103 GNUNET_free (vs->address);
2109 * Lookup neighbour record for peer @a pid.
2111 * @param pid neighbour to look for
2112 * @return NULL if we do not have this peer as a neighbour
2114 static struct Neighbour *
2115 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2117 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2122 * Details about what to notify monitors about.
2127 * @deprecated To be discussed if we keep these...
2129 struct GNUNET_TIME_Absolute last_validation;
2130 struct GNUNET_TIME_Absolute valid_until;
2131 struct GNUNET_TIME_Absolute next_validation;
2134 * Current round-trip time estimate.
2136 struct GNUNET_TIME_Relative rtt;
2139 * Connection status.
2141 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2146 uint32_t num_msg_pending;
2151 uint32_t num_bytes_pending;
2156 * Free a @dvh. Callers MAY want to check if this was the last path to the
2157 * `target`, and if so call #free_dv_route to also free the associated DV
2158 * entry in #dv_routes (if not, the associated scheduler job should eventually
2161 * @param dvh hop to free
2164 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2166 struct Neighbour *n = dvh->next_hop;
2167 struct DistanceVector *dv = dvh->dv;
2169 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2170 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2176 * Free entry in #dv_routes. First frees all hops to the target, and
2177 * if there are no entries left, frees @a dv as well.
2179 * @param dv route to free
2182 free_dv_route (struct DistanceVector *dv)
2184 struct DistanceVectorHop *dvh;
2186 while (NULL != (dvh = dv->dv_head))
2187 free_distance_vector_hop (dvh);
2188 if (NULL == dv->dv_head)
2192 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2193 if (NULL != dv->visibility_task)
2194 GNUNET_SCHEDULER_cancel (dv->visibility_task);
2195 if (NULL != dv->timeout_task)
2196 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2203 * Notify monitor @a tc about an event. That @a tc
2204 * cares about the event has already been checked.
2206 * Send @a tc information in @a me about a @a peer's status with
2207 * respect to some @a address to all monitors that care.
2209 * @param tc monitor to inform
2210 * @param peer peer the information is about
2211 * @param address address the information is about
2212 * @param nt network type associated with @a address
2213 * @param me detailed information to transmit
2216 notify_monitor (struct TransportClient *tc,
2217 const struct GNUNET_PeerIdentity *peer,
2218 const char *address,
2219 enum GNUNET_NetworkType nt,
2220 const struct MonitorEvent *me)
2222 struct GNUNET_MQ_Envelope *env;
2223 struct GNUNET_TRANSPORT_MonitorData *md;
2224 size_t addr_len = strlen (address) + 1;
2226 env = GNUNET_MQ_msg_extra (md,
2228 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2229 md->nt = htonl ((uint32_t) nt);
2231 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2232 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2233 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2234 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2235 md->cs = htonl ((uint32_t) me->cs);
2236 md->num_msg_pending = htonl (me->num_msg_pending);
2237 md->num_bytes_pending = htonl (me->num_bytes_pending);
2238 memcpy (&md[1], address, addr_len);
2239 GNUNET_MQ_send (tc->mq, env);
2244 * Send information in @a me about a @a peer's status with respect
2245 * to some @a address to all monitors that care.
2247 * @param peer peer the information is about
2248 * @param address address the information is about
2249 * @param nt network type associated with @a address
2250 * @param me detailed information to transmit
2253 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2254 const char *address,
2255 enum GNUNET_NetworkType nt,
2256 const struct MonitorEvent *me)
2258 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2260 if (CT_MONITOR != tc->type)
2262 if (tc->details.monitor.one_shot)
2264 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2265 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2267 notify_monitor (tc, peer, address, nt, me);
2273 * Called whenever a client connects. Allocates our
2274 * data structures associated with that client.
2276 * @param cls closure, NULL
2277 * @param client identification of the client
2278 * @param mq message queue for the client
2279 * @return our `struct TransportClient`
2282 client_connect_cb (void *cls,
2283 struct GNUNET_SERVICE_Client *client,
2284 struct GNUNET_MQ_Handle *mq)
2286 struct TransportClient *tc;
2289 tc = GNUNET_new (struct TransportClient);
2290 tc->client = client;
2292 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2301 * @param rc data structure to free
2304 free_reassembly_context (struct ReassemblyContext *rc)
2306 struct Neighbour *n = rc->neighbour;
2308 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2309 GNUNET_assert (GNUNET_OK ==
2310 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2318 * Task run to clean up reassembly context of a neighbour that have expired.
2320 * @param cls a `struct Neighbour`
2323 reassembly_cleanup_task (void *cls)
2325 struct Neighbour *n = cls;
2326 struct ReassemblyContext *rc;
2328 n->reassembly_timeout_task = NULL;
2329 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2331 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2334 free_reassembly_context (rc);
2337 GNUNET_assert (NULL == n->reassembly_timeout_task);
2338 n->reassembly_timeout_task =
2339 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2340 &reassembly_cleanup_task,
2348 * function called to #free_reassembly_context().
2352 * @param value a `struct ReassemblyContext` to free
2353 * @return #GNUNET_OK (continue iteration)
2356 free_reassembly_cb (void *cls,
2357 const struct GNUNET_ShortHashCode *key,
2360 struct ReassemblyContext *rc = value;
2364 free_reassembly_context (rc);
2370 * Release memory used by @a neighbour.
2372 * @param neighbour neighbour entry to free
2375 free_neighbour (struct Neighbour *neighbour)
2377 struct DistanceVectorHop *dvh;
2379 GNUNET_assert (NULL == neighbour->queue_head);
2380 GNUNET_assert (GNUNET_YES ==
2381 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2384 if (NULL != neighbour->timeout_task)
2385 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2386 if (NULL != neighbour->reassembly_map)
2388 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2389 &free_reassembly_cb,
2391 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2392 neighbour->reassembly_map = NULL;
2393 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2394 neighbour->reassembly_heap = NULL;
2396 while (NULL != (dvh = neighbour->dv_head))
2398 struct DistanceVector *dv = dvh->dv;
2400 free_distance_vector_hop (dvh);
2401 if (NULL == dv->dv_head)
2404 if (NULL != neighbour->reassembly_timeout_task)
2405 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2406 GNUNET_free (neighbour);
2411 * Send message to CORE clients that we lost a connection.
2413 * @param tc client to inform (must be CORE client)
2414 * @param pid peer the connection is for
2415 * @param quota_out current quota for the peer
2418 core_send_connect_info (struct TransportClient *tc,
2419 const struct GNUNET_PeerIdentity *pid,
2420 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2422 struct GNUNET_MQ_Envelope *env;
2423 struct ConnectInfoMessage *cim;
2425 GNUNET_assert (CT_CORE == tc->type);
2426 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2427 cim->quota_out = quota_out;
2429 GNUNET_MQ_send (tc->mq, env);
2434 * Send message to CORE clients that we gained a connection
2436 * @param pid peer the queue was for
2437 * @param quota_out current quota for the peer
2440 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2441 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2443 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2445 if (CT_CORE != tc->type)
2447 core_send_connect_info (tc, pid, quota_out);
2453 * Send message to CORE clients that we lost a connection.
2455 * @param pid peer the connection was for
2458 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2460 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2462 struct GNUNET_MQ_Envelope *env;
2463 struct DisconnectInfoMessage *dim;
2465 if (CT_CORE != tc->type)
2467 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2469 GNUNET_MQ_send (tc->mq, env);
2475 * We believe we are ready to transmit a message on a queue. Double-checks
2476 * with the queue's "tracker_out" and then gives the message to the
2477 * communicator for transmission (updating the tracker, and re-scheduling
2478 * itself if applicable).
2480 * @param cls the `struct Queue` to process transmissions for
2483 transmit_on_queue (void *cls);
2487 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2488 * we should run immediately or if the message queue is empty.
2489 * Test for no task being added AND queue not being empty to
2490 * transmit immediately afterwards! This function must only
2491 * be called if the message queue is non-empty!
2493 * @param queue the queue to do scheduling for
2494 * @param inside_job set to #GNUNET_YES if called from
2495 * #transmit_on_queue() itself and NOT setting
2496 * the task means running immediately
2499 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
2501 struct Neighbour *n = queue->neighbour;
2502 struct PendingMessage *pm = n->pending_msg_head;
2503 struct GNUNET_TIME_Relative out_delay;
2506 GNUNET_assert (NULL != pm);
2507 if (queue->tc->details.communicator.total_queue_length >=
2508 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2510 GNUNET_STATISTICS_update (
2512 "# Transmission throttled due to communicator queue limit",
2517 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2519 GNUNET_STATISTICS_update (GST_stats,
2520 "# Transmission throttled due to queue queue limit",
2526 wsize = (0 == queue->mtu) ? pm->bytes_msg /* FIXME: add overheads? */
2528 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out, wsize);
2529 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (
2532 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
2533 return; /* we should run immediately! */
2534 /* queue has changed since we were scheduled, reschedule again */
2535 queue->transmit_task =
2536 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
2537 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2538 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2539 "Next transmission on queue `%s' in %s (high delay)\n",
2541 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2544 "Next transmission on queue `%s' in %s\n",
2546 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
2551 * Check whether the CORE visibility of @a n changed. If so,
2552 * check whether we need to notify CORE.
2554 * @param n neighbour to perform the check for
2557 update_neighbour_core_visibility (struct Neighbour *n);
2563 * @param queue the queue to free
2566 free_queue (struct Queue *queue)
2568 struct Neighbour *neighbour = queue->neighbour;
2569 struct TransportClient *tc = queue->tc;
2570 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
2571 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
2572 struct QueueEntry *qe;
2575 if (NULL != queue->transmit_task)
2577 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2578 queue->transmit_task = NULL;
2580 if (NULL != queue->visibility_task)
2582 GNUNET_SCHEDULER_cancel (queue->visibility_task);
2583 queue->visibility_task = NULL;
2585 GNUNET_CONTAINER_MDLL_remove (neighbour,
2586 neighbour->queue_head,
2587 neighbour->queue_tail,
2589 GNUNET_CONTAINER_MDLL_remove (client,
2590 tc->details.communicator.queue_head,
2591 tc->details.communicator.queue_tail,
2593 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
2594 tc->details.communicator.total_queue_length);
2595 while (NULL != (qe = queue->queue_head))
2597 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
2598 queue->queue_length--;
2599 tc->details.communicator.total_queue_length--;
2602 GNUNET_assert (qe == qe->pm->qe);
2607 GNUNET_assert (0 == queue->queue_length);
2608 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
2609 tc->details.communicator.total_queue_length))
2611 /* Communicator dropped below threshold, resume all queues */
2612 GNUNET_STATISTICS_update (
2614 "# Transmission throttled due to communicator queue limit",
2617 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
2619 schedule_transmit_on_queue (s, GNUNET_NO);
2621 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
2622 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2623 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2624 GNUNET_free (queue);
2626 update_neighbour_core_visibility (neighbour);
2627 cores_send_disconnect_info (&neighbour->pid);
2629 if (NULL == neighbour->queue_head)
2631 free_neighbour (neighbour);
2639 * @param ale address list entry to free
2642 free_address_list_entry (struct AddressListEntry *ale)
2644 struct TransportClient *tc = ale->tc;
2646 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2647 tc->details.communicator.addr_tail,
2649 if (NULL != ale->sc)
2651 GNUNET_PEERSTORE_store_cancel (ale->sc);
2654 if (NULL != ale->st)
2656 GNUNET_SCHEDULER_cancel (ale->st);
2664 * Stop the peer request in @a value.
2666 * @param cls a `struct TransportClient` that no longer makes the request
2667 * @param pid the peer's identity
2668 * @param value a `struct PeerRequest`
2669 * @return #GNUNET_YES (always)
2672 stop_peer_request (void *cls,
2673 const struct GNUNET_PeerIdentity *pid,
2676 struct TransportClient *tc = cls;
2677 struct PeerRequest *pr = value;
2679 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2682 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2692 * Called whenever a client is disconnected. Frees our
2693 * resources associated with that client.
2695 * @param cls closure, NULL
2696 * @param client identification of the client
2697 * @param app_ctx our `struct TransportClient`
2700 client_disconnect_cb (void *cls,
2701 struct GNUNET_SERVICE_Client *client,
2704 struct TransportClient *tc = app_ctx;
2707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2708 "Client %p disconnected, cleaning up.\n",
2710 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
2716 struct PendingMessage *pm;
2718 while (NULL != (pm = tc->details.core.pending_msg_head))
2720 GNUNET_CONTAINER_MDLL_remove (client,
2721 tc->details.core.pending_msg_head,
2722 tc->details.core.pending_msg_tail,
2730 case CT_COMMUNICATOR: {
2732 struct AddressListEntry *ale;
2734 while (NULL != (q = tc->details.communicator.queue_head))
2736 while (NULL != (ale = tc->details.communicator.addr_head))
2737 free_address_list_entry (ale);
2738 GNUNET_free (tc->details.communicator.address_prefix);
2741 case CT_APPLICATION:
2742 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2745 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2753 * Iterator telling new CORE client about all existing
2754 * connections to peers.
2756 * @param cls the new `struct TransportClient`
2757 * @param pid a connected peer
2758 * @param value the `struct Neighbour` with more information
2759 * @return #GNUNET_OK (continue to iterate)
2762 notify_client_connect_info (void *cls,
2763 const struct GNUNET_PeerIdentity *pid,
2766 struct TransportClient *tc = cls;
2767 struct Neighbour *neighbour = value;
2769 core_send_connect_info (tc, pid, neighbour->quota_out);
2775 * Initialize a "CORE" client. We got a start message from this
2776 * client, so add it to the list of clients for broadcasting of
2779 * @param cls the client
2780 * @param start the start message that was sent
2783 handle_client_start (void *cls, const struct StartMessage *start)
2785 struct TransportClient *tc = cls;
2788 options = ntohl (start->options);
2789 if ((0 != (1 & options)) &&
2790 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
2792 /* client thinks this is a different peer, reject */
2794 GNUNET_SERVICE_client_drop (tc->client);
2797 if (CT_NONE != tc->type)
2800 GNUNET_SERVICE_client_drop (tc->client);
2804 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2805 ¬ify_client_connect_info,
2807 GNUNET_SERVICE_client_continue (tc->client);
2812 * Client asked for transmission to a peer. Process the request.
2814 * @param cls the client
2815 * @param obm the send message that was sent
2818 check_client_send (void *cls, const struct OutboundMessage *obm)
2820 struct TransportClient *tc = cls;
2822 const struct GNUNET_MessageHeader *obmm;
2824 if (CT_CORE != tc->type)
2827 return GNUNET_SYSERR;
2829 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2830 if (size < sizeof (struct GNUNET_MessageHeader))
2833 return GNUNET_SYSERR;
2835 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2836 if (size != ntohs (obmm->size))
2839 return GNUNET_SYSERR;
2846 * Free fragment tree below @e root, excluding @e root itself.
2848 * @param root root of the tree to free
2851 free_fragment_tree (struct PendingMessage *root)
2853 struct PendingMessage *frag;
2855 while (NULL != (frag = root->head_frag))
2857 free_fragment_tree (frag);
2858 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2865 * Release memory associated with @a pm and remove @a pm from associated
2866 * data structures. @a pm must be a top-level pending message and not
2867 * a fragment in the tree. The entire tree is freed (if applicable).
2869 * @param pm the pending message to free
2872 free_pending_message (struct PendingMessage *pm)
2874 struct TransportClient *tc = pm->client;
2875 struct Neighbour *target = pm->target;
2879 GNUNET_CONTAINER_MDLL_remove (client,
2880 tc->details.core.pending_msg_head,
2881 tc->details.core.pending_msg_tail,
2884 GNUNET_CONTAINER_MDLL_remove (neighbour,
2885 target->pending_msg_head,
2886 target->pending_msg_tail,
2888 free_fragment_tree (pm);
2891 GNUNET_assert (pm == pm->qe->pm);
2894 GNUNET_free_non_null (pm->bpm);
2900 * Send a response to the @a pm that we have processed a
2901 * "send" request with status @a success. We
2902 * transmitted @a bytes_physical on the actual wire.
2903 * Sends a confirmation to the "core" client responsible
2904 * for the original request and free's @a pm.
2906 * @param pm handle to the original pending message
2907 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2908 * for transmission failure
2909 * @param bytes_physical amount of bandwidth consumed
2912 client_send_response (struct PendingMessage *pm,
2914 uint32_t bytes_physical)
2916 struct TransportClient *tc = pm->client;
2917 struct Neighbour *target = pm->target;
2918 struct GNUNET_MQ_Envelope *env;
2919 struct SendOkMessage *som;
2923 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2924 som->success = htonl ((uint32_t) success);
2925 som->bytes_msg = htons (pm->bytes_msg);
2926 som->bytes_physical = htonl (bytes_physical);
2927 som->peer = target->pid;
2928 GNUNET_MQ_send (tc->mq, env);
2930 free_pending_message (pm);
2935 * Checks the message queue for a neighbour for messages that have timed
2936 * out and purges them.
2938 * @param cls a `struct Neighbour`
2941 check_queue_timeouts (void *cls)
2943 struct Neighbour *n = cls;
2944 struct PendingMessage *pm;
2945 struct GNUNET_TIME_Absolute now;
2946 struct GNUNET_TIME_Absolute earliest_timeout;
2948 n->timeout_task = NULL;
2949 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2950 now = GNUNET_TIME_absolute_get ();
2951 for (struct PendingMessage *pos = n->pending_msg_head; NULL != pos; pos = pm)
2953 pm = pos->next_neighbour;
2954 if (pos->timeout.abs_value_us <= now.abs_value_us)
2956 GNUNET_STATISTICS_update (GST_stats,
2957 "# messages dropped (timeout before confirmation)",
2960 client_send_response (pm, GNUNET_NO, 0);
2964 GNUNET_TIME_absolute_min (earliest_timeout, pos->timeout);
2966 n->earliest_timeout = earliest_timeout;
2967 if (NULL != n->pending_msg_head)
2969 GNUNET_SCHEDULER_add_at (earliest_timeout, &check_queue_timeouts, n);
2974 * Client asked for transmission to a peer. Process the request.
2976 * @param cls the client
2977 * @param obm the send message that was sent
2980 handle_client_send (void *cls, const struct OutboundMessage *obm)
2982 struct TransportClient *tc = cls;
2983 struct PendingMessage *pm;
2984 const struct GNUNET_MessageHeader *obmm;
2985 struct Neighbour *target;
2989 GNUNET_assert (CT_CORE == tc->type);
2990 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2991 bytes_msg = ntohs (obmm->size);
2992 target = lookup_neighbour (&obm->peer);
2995 /* Failure: don't have this peer as a neighbour (anymore).
2996 Might have gone down asynchronously, so this is NOT
2997 a protocol violation by CORE. Still count the event,
2998 as this should be rare. */
2999 struct GNUNET_MQ_Envelope *env;
3000 struct SendOkMessage *som;
3002 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3003 som->success = htonl (GNUNET_SYSERR);
3004 som->bytes_msg = htonl (bytes_msg);
3005 som->bytes_physical = htonl (0);
3006 som->peer = obm->peer;
3007 GNUNET_MQ_send (tc->mq, env);
3008 GNUNET_SERVICE_client_continue (tc->client);
3009 GNUNET_STATISTICS_update (GST_stats,
3010 "# messages dropped (neighbour unknown)",
3015 was_empty = (NULL == target->pending_msg_head);
3016 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
3018 pm->target = target;
3019 pm->bytes_msg = bytes_msg;
3021 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
3022 memcpy (&pm[1], &obm[1], bytes_msg);
3023 GNUNET_CONTAINER_MDLL_insert (neighbour,
3024 target->pending_msg_head,
3025 target->pending_msg_tail,
3027 GNUNET_CONTAINER_MDLL_insert (client,
3028 tc->details.core.pending_msg_head,
3029 tc->details.core.pending_msg_tail,
3031 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
3033 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
3034 if (NULL != target->timeout_task)
3035 GNUNET_SCHEDULER_cancel (target->timeout_task);
3036 target->timeout_task = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
3037 &check_queue_timeouts,
3041 return; /* all queues must already be busy */
3042 for (struct Queue *queue = target->queue_head; NULL != queue;
3043 queue = queue->next_neighbour)
3045 /* try transmission on any queue that is idle */
3046 if (NULL == queue->transmit_task)
3047 queue->transmit_task =
3048 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3054 * Communicator started. Test message is well-formed.
3056 * @param cls the client
3057 * @param cam the send message that was sent
3060 check_communicator_available (
3062 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3064 struct TransportClient *tc = cls;
3067 if (CT_NONE != tc->type)
3070 return GNUNET_SYSERR;
3072 tc->type = CT_COMMUNICATOR;
3073 size = ntohs (cam->header.size) - sizeof (*cam);
3075 return GNUNET_OK; /* receive-only communicator */
3076 GNUNET_MQ_check_zero_termination (cam);
3082 * Communicator started. Process the request.
3084 * @param cls the client
3085 * @param cam the send message that was sent
3088 handle_communicator_available (
3090 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3092 struct TransportClient *tc = cls;
3095 size = ntohs (cam->header.size) - sizeof (*cam);
3097 return; /* receive-only communicator */
3098 tc->details.communicator.address_prefix =
3099 GNUNET_strdup ((const char *) &cam[1]);
3100 tc->details.communicator.cc =
3101 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3102 GNUNET_SERVICE_client_continue (tc->client);
3107 * Communicator requests backchannel transmission. Check the request.
3109 * @param cls the client
3110 * @param cb the send message that was sent
3111 * @return #GNUNET_OK if message is well-formed
3114 check_communicator_backchannel (
3116 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3118 const struct GNUNET_MessageHeader *inbox;
3124 msize = ntohs (cb->header.size) - sizeof (*cb);
3125 if (UINT16_MAX - msize >
3126 sizeof (struct TransportBackchannelEncapsulationMessage) +
3127 sizeof (struct TransportBackchannelRequestPayload))
3130 return GNUNET_SYSERR;
3132 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3133 isize = ntohs (inbox->size);
3137 return GNUNET_SYSERR;
3139 is = (const char *) inbox;
3142 GNUNET_assert (msize > 0);
3143 if ('\0' != is[msize - 1])
3146 return GNUNET_SYSERR;
3153 * Remove memory used by expired ephemeral keys.
3158 expire_ephemerals (void *cls)
3160 struct EphemeralCacheEntry *ece;
3163 ephemeral_task = NULL;
3164 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3166 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3169 free_ephemeral (ece);
3172 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3181 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3182 * one, cache it and return it.
3184 * @param pid peer to look up ephemeral for
3185 * @param private_key[out] set to the private key
3186 * @param ephemeral_key[out] set to the key
3187 * @param ephemeral_sender_sig[out] set to the signature
3188 * @param ephemeral_validity[out] set to the validity expiration time
3191 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3192 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3193 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3194 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3195 struct GNUNET_TIME_Absolute *ephemeral_validity)
3197 struct EphemeralCacheEntry *ece;
3198 struct EphemeralConfirmation ec;
3200 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
3201 if ((NULL != ece) &&
3202 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
3205 free_ephemeral (ece);
3210 ece = GNUNET_new (struct EphemeralCacheEntry);
3212 ece->ephemeral_validity =
3213 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3214 EPHEMERAL_VALIDITY);
3215 GNUNET_assert (GNUNET_OK ==
3216 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3217 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
3218 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3219 ec.purpose.size = htonl (sizeof (ec));
3221 ec.ephemeral_key = ece->ephemeral_key;
3222 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3226 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3228 ece->ephemeral_validity.abs_value_us);
3229 GNUNET_assert (GNUNET_OK ==
3230 GNUNET_CONTAINER_multipeermap_put (
3234 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3235 if (NULL == ephemeral_task)
3236 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3240 *private_key = ece->private_key;
3241 *ephemeral_key = ece->ephemeral_key;
3242 *ephemeral_sender_sig = ece->sender_sig;
3243 *ephemeral_validity = ece->ephemeral_validity;
3248 * Send the control message @a payload on @a queue.
3250 * @param queue the queue to use for transmission
3251 * @param pm pending message to update once transmission is done, may be NULL!
3252 * @param payload the payload to send (encapsulated in a
3253 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
3254 * @param payload_size number of bytes in @a payload
3257 queue_send_msg (struct Queue *queue,
3258 struct PendingMessage *pm,
3259 const void *payload,
3260 size_t payload_size)
3262 struct Neighbour *n = queue->neighbour;
3263 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3264 struct GNUNET_MQ_Envelope *env;
3266 env = GNUNET_MQ_msg_extra (smt,
3268 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3269 smt->qid = queue->qid;
3270 smt->mid = queue->mid_gen;
3271 smt->receiver = n->pid;
3272 memcpy (&smt[1], payload, payload_size);
3274 /* Pass the env to the communicator of queue for transmission. */
3275 struct QueueEntry *qe;
3277 qe = GNUNET_new (struct QueueEntry);
3278 qe->mid = queue->mid_gen++;
3283 GNUNET_assert (NULL == pm->qe);
3286 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
3287 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3288 queue->queue_length++;
3289 queue->tc->details.communicator.total_queue_length++;
3290 GNUNET_MQ_send (queue->tc->mq, env);
3296 * Which transmission options are allowable for transmission?
3297 * Interpreted bit-wise!
3299 enum RouteMessageOptions
3302 * Only confirmed, non-DV direct neighbours.
3307 * We are allowed to use DV routing for this @a hdr
3312 * We are allowed to use unconfirmed queues or DV routes for this message
3314 RMO_UNCONFIRMED_ALLOWED = 2,
3317 * Reliable and unreliable, DV and non-DV are all acceptable.
3319 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
3322 * If we have multiple choices, it is OK to send this message
3323 * over multiple channels at the same time to improve loss tolerance.
3324 * (We do at most 2 transmissions.)
3331 * Pick a queue of @a n under constraints @a options and schedule
3332 * transmission of @a hdr.
3334 * @param n neighbour to send to
3335 * @param hdr message to send as payload
3336 * @param options whether queues must be confirmed or not,
3337 * and whether we may pick multiple (2) queues
3340 route_via_neighbour (const struct Neighbour *n,
3341 const struct GNUNET_MessageHeader *hdr,
3342 enum RouteMessageOptions options)
3344 struct GNUNET_TIME_Absolute now;
3345 unsigned int candidates;
3349 /* Pick one or two 'random' queues from n (under constraints of options) */
3350 now = GNUNET_TIME_absolute_get ();
3351 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
3352 weight in the future; weight could be assigned by observed
3353 bandwidth (note: not sure if we should do this for this type
3354 of control traffic though). */
3356 for (struct Queue *pos = n->queue_head; NULL != pos;
3357 pos = pos->next_neighbour)
3359 /* Count the queue with the visibility task in all cases, as
3360 otherwise we may end up with no queues just because the
3361 time for the visibility task just expired but the scheduler
3362 just ran this task first */
3363 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
3364 (pos->validated_until.abs_value_us > now.abs_value_us) ||
3365 (NULL != pos->visibility_task))
3368 if (0 == candidates)
3370 /* Given that we above check for pos->visibility task,
3371 this should be strictly impossible. */
3375 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3376 if (0 == (options & RMO_REDUNDANT))
3377 sel2 = candidates; /* picks none! */
3379 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
3381 for (struct Queue *pos = n->queue_head; NULL != pos;
3382 pos = pos->next_neighbour)
3384 /* Count the queue with the visibility task in all cases, as
3385 otherwise we may end up with no queues just because the
3386 time for the visibility task just expired but the scheduler
3387 just ran this task first */
3388 if ((pos->validated_until.abs_value_us > now.abs_value_us) ||
3389 (NULL != pos->visibility_task))
3391 if ((sel1 == candidates) || (sel2 == candidates))
3392 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
3400 * Given a distance vector path @a dvh route @a payload to
3401 * the ultimate destination respecting @a options.
3402 * Sets up the boxed message and queues it at the next hop.
3404 * @param dvh choice of the path for the message
3405 * @param payload body to transmit
3406 * @param options options to use for control
3409 forward_via_dvh (const struct DistanceVectorHop *dvh,
3410 const struct GNUNET_MessageHeader *payload,
3411 enum RouteMessageOptions options)
3413 uint16_t mlen = ntohs (payload->size);
3414 char boxram[sizeof (struct TransportDVBox) +
3415 (dvh->distance + 1) * sizeof (struct GNUNET_PeerIdentity) +
3417 struct TransportDVBox *box = (struct TransportDVBox *) boxram;
3418 struct GNUNET_PeerIdentity *path = (struct GNUNET_PeerIdentity *) &box[1];
3420 box->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3421 box->header.size = htons (sizeof (boxram));
3422 box->total_hops = htons (0);
3423 box->num_hops = htons (dvh->distance + 1);
3424 box->origin = GST_my_identity;
3425 memcpy (path, dvh->path, dvh->distance * sizeof (struct GNUNET_PeerIdentity));
3426 path[dvh->distance] = dvh->dv->target;
3427 memcpy (&path[dvh->distance + 1], payload, mlen);
3428 route_via_neighbour (dvh->next_hop, &box->header, options);
3433 * Pick a path of @a dv under constraints @a options and schedule
3434 * transmission of @a hdr.
3436 * @param n neighbour to send to
3437 * @param hdr message to send as payload
3438 * @param options whether path must be confirmed or not
3439 * and whether we may pick multiple (2) paths
3442 route_via_dv (const struct DistanceVector *dv,
3443 const struct GNUNET_MessageHeader *hdr,
3444 enum RouteMessageOptions options)
3446 struct DistanceVectorHop *h1;
3447 struct DistanceVectorHop *h2;
3452 /* Pick random vectors, but weighted by distance, giving more weight
3453 to shorter vectors */
3455 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3458 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3459 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3460 .rel_value_us == 0))
3461 continue; /* pos unconfirmed and confirmed required */
3462 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3469 choice1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3470 choice2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3474 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3477 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3479 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3480 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3481 .rel_value_us == 0))
3482 continue; /* pos unconfirmed and confirmed required */
3483 if ((num_dv <= choice1) && (num_dv + delta > choice1))
3485 if ((num_dv <= choice2) && (num_dv + delta > choice2))
3489 forward_via_dvh (h1, hdr, options & (~RMO_REDUNDANT));
3490 if (0 == (options & RMO_REDUNDANT))
3491 forward_via_dvh (h2, hdr, options & (~RMO_REDUNDANT));
3496 * We need to transmit @a hdr to @a target. If necessary, this may
3497 * involve DV routing.
3499 * @param target peer to receive @a hdr
3500 * @param hdr header of the message to route and #GNUNET_free()
3501 * @param options which transmission channels are allowed
3504 route_message (const struct GNUNET_PeerIdentity *target,
3505 struct GNUNET_MessageHeader *hdr,
3506 enum RouteMessageOptions options)
3508 struct Neighbour *n;
3509 struct DistanceVector *dv;
3511 n = GNUNET_CONTAINER_multipeermap_get (neighbours, target);
3512 dv = (0 != (options & RMO_DV_ALLOWED))
3513 ? GNUNET_CONTAINER_multipeermap_get (dv_routes, target)
3515 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
3517 /* if confirmed is required, and we do not have anything
3518 confirmed, drop respective options */
3519 if ((NULL != n) && (GNUNET_NO == n->core_visible))
3521 if ((NULL != dv) && (GNUNET_NO == dv->core_visible))
3524 if ((NULL == n) && (NULL == dv))
3526 GNUNET_STATISTICS_update (GST_stats,
3527 "# Messages dropped in routing: no acceptable method",
3533 /* If both dv and n are possible and we must choose:
3534 flip a coin for the choice between the two; for now 50/50 */
3535 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
3537 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
3542 if ((NULL != n) && (NULL != dv))
3543 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
3544 enough for redunancy, so clear the flag. */
3547 route_via_neighbour (n, hdr, options);
3551 route_via_dv (dv, hdr, options);
3558 * Structure of the key material used to encrypt backchannel messages.
3560 struct BackchannelKeyState
3563 * State of our block cipher.
3565 gcry_cipher_hd_t cipher;
3568 * Actual key material.
3574 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
3576 struct GNUNET_CRYPTO_AuthKey hmac_key;
3579 * Symmetric key to use for encryption.
3581 char aes_key[256 / 8];
3584 * Counter value to use during setup.
3586 char aes_ctr[128 / 8];
3593 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
3594 const struct GNUNET_ShortHashCode *iv,
3595 struct BackchannelKeyState *key)
3597 /* must match #dh_key_derive_eph_pub */
3598 GNUNET_assert (GNUNET_YES ==
3599 GNUNET_CRYPTO_kdf (&key->material,
3600 sizeof (key->material),
3601 "transport-backchannel-key",
3602 strlen ("transport-backchannel-key"),
3607 gcry_cipher_open (&key->cipher,
3608 GCRY_CIPHER_AES256 /* low level: go for speed */,
3609 GCRY_CIPHER_MODE_CTR,
3611 gcry_cipher_setkey (key->cipher,
3612 &key->material.aes_key,
3613 sizeof (key->material.aes_key));
3614 gcry_cipher_setctr (key->cipher,
3615 &key->material.aes_ctr,
3616 sizeof (key->material.aes_ctr));
3621 * Derive backchannel encryption key material from @a priv_ephemeral
3622 * and @a target and @a iv.
3624 * @param priv_ephemeral ephemeral private key to use
3625 * @param target the target peer to encrypt to
3626 * @param iv unique IV to use
3627 * @param key[out] set to the key material
3630 dh_key_derive_eph_pid (
3631 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
3632 const struct GNUNET_PeerIdentity *target,
3633 const struct GNUNET_ShortHashCode *iv,
3634 struct BackchannelKeyState *key)
3636 struct GNUNET_HashCode km;
3638 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
3639 &target->public_key,
3641 bc_setup_key_state_from_km (&km, iv, key);
3646 * Derive backchannel encryption key material from #GST_my_private_key
3647 * and @a pub_ephemeral and @a iv.
3649 * @param priv_ephemeral ephemeral private key to use
3650 * @param target the target peer to encrypt to
3651 * @param iv unique IV to use
3652 * @param key[out] set to the key material
3655 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
3656 const struct GNUNET_ShortHashCode *iv,
3657 struct BackchannelKeyState *key)
3659 struct GNUNET_HashCode km;
3661 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
3664 bc_setup_key_state_from_km (&km, iv, key);
3669 * Do HMAC calculation for backchannel messages over @a data using key
3670 * material from @a key.
3672 * @param key key material (from DH)
3673 * @param hmac[out] set to the HMAC
3674 * @param data data to perform HMAC calculation over
3675 * @param data_size number of bytes in @a data
3678 bc_hmac (const struct BackchannelKeyState *key,
3679 struct GNUNET_HashCode *hmac,
3683 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
3688 * Perform backchannel encryption using symmetric secret in @a key
3689 * to encrypt data from @a in to @a dst.
3691 * @param key[in,out] key material to use
3692 * @param dst where to write the result
3693 * @param in input data to encrypt (plaintext)
3694 * @param in_size number of bytes of input in @a in and available at @a dst
3697 bc_encrypt (struct BackchannelKeyState *key,
3703 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
3708 * Perform backchannel encryption using symmetric secret in @a key
3709 * to encrypt data from @a in to @a dst.
3711 * @param key[in,out] key material to use
3712 * @param ciph cipher text to decrypt
3713 * @param out[out] output data to generate (plaintext)
3714 * @param out_size number of bytes of input in @a ciph and available in @a out
3717 bc_decrypt (struct BackchannelKeyState *key,
3723 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
3728 * Clean up key material in @a key.
3730 * @param key key material to clean up (memory must not be free'd!)
3733 bc_key_clean (struct BackchannelKeyState *key)
3735 gcry_cipher_close (key->cipher);
3736 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
3741 * Communicator requests backchannel transmission. Process the request.
3743 * @param cls the client
3744 * @param cb the send message that was sent
3747 handle_communicator_backchannel (
3749 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3751 struct TransportClient *tc = cls;
3752 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3753 struct GNUNET_TIME_Absolute ephemeral_validity;
3754 struct TransportBackchannelEncapsulationMessage *enc;
3755 struct TransportBackchannelRequestPayload ppay;
3756 struct BackchannelKeyState key;
3760 /* encapsulate and encrypt message */
3761 msize = ntohs (cb->header.size) - sizeof (*cb) +
3762 sizeof (struct TransportBackchannelRequestPayload);
3763 enc = GNUNET_malloc (sizeof (*enc) + msize);
3765 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3766 enc->header.size = htons (sizeof (*enc) + msize);
3767 enc->target = cb->pid;
3768 lookup_ephemeral (&cb->pid,
3770 &enc->ephemeral_key,
3772 &ephemeral_validity);
3773 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3776 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
3777 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3778 ppay.monotonic_time =
3779 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3780 mpos = (char *) &enc[1];
3781 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
3784 &mpos[sizeof (ppay)],
3785 ntohs (cb->header.size) - sizeof (*cb));
3789 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
3790 bc_key_clean (&key);
3791 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
3792 GNUNET_SERVICE_client_continue (tc->client);
3797 * Address of our peer added. Test message is well-formed.
3799 * @param cls the client
3800 * @param aam the send message that was sent
3801 * @return #GNUNET_OK if message is well-formed
3804 check_add_address (void *cls,
3805 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3807 struct TransportClient *tc = cls;
3809 if (CT_COMMUNICATOR != tc->type)
3812 return GNUNET_SYSERR;
3814 GNUNET_MQ_check_zero_termination (aam);
3820 * Ask peerstore to store our address.
3822 * @param cls an `struct AddressListEntry *`
3825 store_pi (void *cls);
3829 * Function called when peerstore is done storing our address.
3831 * @param cls a `struct AddressListEntry`
3832 * @param success #GNUNET_YES if peerstore was successful
3835 peerstore_store_own_cb (void *cls, int success)
3837 struct AddressListEntry *ale = cls;
3840 if (GNUNET_YES != success)
3841 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3842 "Failed to store our own address `%s' in peerstore!\n",
3844 /* refresh period is 1/4 of expiration time, that should be plenty
3845 without being excessive. */
3847 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3855 * Ask peerstore to store our address.
3857 * @param cls an `struct AddressListEntry *`
3860 store_pi (void *cls)
3862 struct AddressListEntry *ale = cls;
3865 struct GNUNET_TIME_Absolute expiration;
3868 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3869 GNUNET_HELLO_sign_address (ale->address,
3875 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3878 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3882 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3883 &peerstore_store_own_cb,
3886 if (NULL == ale->sc)
3888 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3889 "Failed to store our address `%s' with peerstore\n",
3892 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
3898 * Address of our peer added. Process the request.
3900 * @param cls the client
3901 * @param aam the send message that was sent
3904 handle_add_address (void *cls,
3905 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3907 struct TransportClient *tc = cls;
3908 struct AddressListEntry *ale;
3911 slen = ntohs (aam->header.size) - sizeof (*aam);
3912 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3914 ale->address = (const char *) &ale[1];
3915 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3916 ale->aid = aam->aid;
3917 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3918 memcpy (&ale[1], &aam[1], slen);
3919 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3920 tc->details.communicator.addr_tail,
3922 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
3923 GNUNET_SERVICE_client_continue (tc->client);
3928 * Address of our peer deleted. Process the request.
3930 * @param cls the client
3931 * @param dam the send message that was sent
3934 handle_del_address (void *cls,
3935 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3937 struct TransportClient *tc = cls;
3939 if (CT_COMMUNICATOR != tc->type)
3942 GNUNET_SERVICE_client_drop (tc->client);
3945 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3949 if (dam->aid != ale->aid)
3951 GNUNET_assert (ale->tc == tc);
3952 free_address_list_entry (ale);
3953 GNUNET_SERVICE_client_continue (tc->client);
3956 GNUNET_SERVICE_client_drop (tc->client);
3961 * Context from #handle_incoming_msg(). Closure for many
3962 * message handlers below.
3964 struct CommunicatorMessageContext
3967 * Which communicator provided us with the message.
3969 struct TransportClient *tc;
3972 * Additional information for flow control and about the sender.
3974 struct GNUNET_TRANSPORT_IncomingMessage im;
3977 * Number of hops the message has travelled (if DV-routed).
3978 * FIXME: make use of this in ACK handling!
3980 uint16_t total_hops;
3985 * Given an inbound message @a msg from a communicator @a cmc,
3986 * demultiplex it based on the type calling the right handler.
3988 * @param cmc context for demultiplexing
3989 * @param msg message to demultiplex
3992 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3993 const struct GNUNET_MessageHeader *msg);
3997 * Send ACK to communicator (if requested) and free @a cmc.
3999 * @param cmc context for which we are done handling the message
4002 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4004 if (0 != ntohl (cmc->im.fc_on))
4006 /* send ACK when done to communicator for flow control! */
4007 struct GNUNET_MQ_Envelope *env;
4008 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4010 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4011 ack->reserved = htonl (0);
4012 ack->fc_id = cmc->im.fc_id;
4013 ack->sender = cmc->im.sender;
4014 GNUNET_MQ_send (cmc->tc->mq, env);
4016 GNUNET_SERVICE_client_continue (cmc->tc->client);
4022 * Communicator gave us an unencapsulated message to pass as-is to
4023 * CORE. Process the request.
4025 * @param cls a `struct CommunicatorMessageContext` (must call
4026 * #finish_cmc_handling() when done)
4027 * @param mh the message that was received
4030 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4032 struct CommunicatorMessageContext *cmc = cls;
4033 uint16_t size = ntohs (mh->size);
4035 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4036 (size < sizeof (struct GNUNET_MessageHeader)))
4038 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4041 finish_cmc_handling (cmc);
4042 GNUNET_SERVICE_client_drop (client);
4045 /* Forward to all CORE clients */
4046 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4048 struct GNUNET_MQ_Envelope *env;
4049 struct InboundMessage *im;
4051 if (CT_CORE != tc->type)
4053 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4054 im->peer = cmc->im.sender;
4055 memcpy (&im[1], mh, size);
4056 GNUNET_MQ_send (tc->mq, env);
4058 /* FIXME: consider doing this _only_ once the message
4059 was drained from the CORE MQs to extend flow control to CORE!
4060 (basically, increment counter in cmc, decrement on MQ send continuation! */
4061 finish_cmc_handling (cmc);
4066 * Communicator gave us a fragment box. Check the message.
4068 * @param cls a `struct CommunicatorMessageContext`
4069 * @param fb the send message that was sent
4070 * @return #GNUNET_YES if message is well-formed
4073 check_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4075 uint16_t size = ntohs (fb->header.size);
4076 uint16_t bsize = size - sizeof (*fb);
4080 GNUNET_break_op (0);
4081 return GNUNET_SYSERR;
4083 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4085 GNUNET_break_op (0);
4086 return GNUNET_SYSERR;
4088 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4090 GNUNET_break_op (0);
4091 return GNUNET_SYSERR;
4098 * Generate a fragment acknowledgement for an @a rc.
4100 * @param rc context to generate ACK for, @a rc ACK state is reset
4103 send_fragment_ack (struct ReassemblyContext *rc)
4105 struct TransportFragmentAckMessage *ack;
4107 ack = GNUNET_new (struct TransportFragmentAckMessage);
4108 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
4109 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
4110 ack->frag_uuid = htonl (rc->frag_uuid);
4111 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
4112 ack->msg_uuid = rc->msg_uuid;
4113 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
4114 if (0 == rc->msg_missing)
4115 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4116 GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
4118 ack->reassembly_timeout = GNUNET_TIME_relative_hton (
4119 GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
4120 route_message (&rc->neighbour->pid, &ack->header, RMO_DV_ALLOWED);
4121 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
4123 rc->extra_acks = 0LLU;
4128 * Communicator gave us a fragment. Process the request.
4130 * @param cls a `struct CommunicatorMessageContext` (must call
4131 * #finish_cmc_handling() when done)
4132 * @param fb the message that was received
4135 handle_fragment_box (void *cls, const struct TransportFragmentBox *fb)
4137 struct CommunicatorMessageContext *cmc = cls;
4138 struct Neighbour *n;
4139 struct ReassemblyContext *rc;
4140 const struct GNUNET_MessageHeader *msg;
4146 struct GNUNET_TIME_Relative cdelay;
4149 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4152 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4155 finish_cmc_handling (cmc);
4156 GNUNET_SERVICE_client_drop (client);
4159 if (NULL == n->reassembly_map)
4161 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_YES);
4162 n->reassembly_heap =
4163 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
4164 n->reassembly_timeout_task =
4165 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
4166 &reassembly_cleanup_task,
4169 msize = ntohs (fb->msg_size);
4170 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map, &fb->msg_uuid);
4173 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
4174 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
4175 rc->msg_uuid = fb->msg_uuid;
4177 rc->msg_size = msize;
4178 rc->reassembly_timeout =
4179 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
4180 rc->last_frag = GNUNET_TIME_absolute_get ();
4181 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
4183 rc->reassembly_timeout.abs_value_us);
4184 GNUNET_assert (GNUNET_OK ==
4185 GNUNET_CONTAINER_multishortmap_put (
4189 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4190 target = (char *) &rc[1];
4191 rc->bitfield = (uint8_t *) (target + rc->msg_size);
4192 rc->msg_missing = rc->msg_size;
4196 target = (char *) &rc[1];
4198 if (msize != rc->msg_size)
4201 finish_cmc_handling (cmc);
4206 fsize = ntohs (fb->header.size) - sizeof (*fb);
4207 frag_off = ntohs (fb->frag_off);
4208 memcpy (&target[frag_off], &fb[1], fsize);
4209 /* update bitfield and msg_missing */
4210 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
4212 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
4214 rc->bitfield[i / 8] |= (1 << (i % 8));
4219 /* Compute cummulative ACK */
4220 frag_uuid = ntohl (fb->frag_uuid);
4221 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
4222 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->num_acks);
4223 rc->last_frag = GNUNET_TIME_absolute_get ();
4224 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay, cdelay);
4225 ack_now = GNUNET_NO;
4226 if (0 == rc->num_acks)
4228 /* case one: first ack */
4229 rc->frag_uuid = frag_uuid;
4230 rc->extra_acks = 0LLU;
4233 else if ((frag_uuid >= rc->frag_uuid) && (frag_uuid <= rc->frag_uuid + 64))
4235 /* case two: ack fits after existing min UUID */
4236 if ((frag_uuid == rc->frag_uuid) ||
4237 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))))
4239 /* duplicate fragment, ack now! */
4240 ack_now = GNUNET_YES;
4244 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
4248 else if ((rc->frag_uuid > frag_uuid) &&
4249 (((rc->frag_uuid == frag_uuid + 64) && (0 == rc->extra_acks)) ||
4250 ((rc->frag_uuid < frag_uuid + 64) &&
4253 ~((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))))))
4255 /* can fit ack by shifting extra acks and starting at
4256 frag_uid, test above esured that the bits we will
4257 shift 'extra_acks' by are all zero. */
4258 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
4259 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
4260 rc->frag_uuid = frag_uuid;
4263 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very
4265 ack_now = GNUNET_YES; /* maximum acks received */
4266 // FIXME: possibly also ACK based on RTT (but for that we'd need to
4267 // determine the queue used for the ACK first!)
4269 /* is reassembly complete? */
4270 if (0 != rc->msg_missing)
4273 send_fragment_ack (rc);
4274 finish_cmc_handling (cmc);
4277 /* reassembly is complete, verify result */
4278 msg = (const struct GNUNET_MessageHeader *) &rc[1];
4279 if (ntohs (msg->size) != rc->msg_size)
4282 free_reassembly_context (rc);
4283 finish_cmc_handling (cmc);
4286 /* successful reassembly */
4287 send_fragment_ack (rc);
4288 demultiplex_with_cmc (cmc, msg);
4289 /* FIXME: really free here? Might be bad if fragments are still
4290 en-route and we forget that we finished this reassembly immediately!
4291 -> keep around until timeout?
4292 -> shorten timeout based on ACK? */
4293 free_reassembly_context (rc);
4298 * Check the @a fa against the fragments associated with @a pm.
4299 * If it matches, remove the matching fragments from the transmission
4302 * @param pm pending message to check against the ack
4303 * @param fa the ack that was received
4304 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
4307 check_ack_against_pm (struct PendingMessage *pm,
4308 const struct TransportFragmentAckMessage *fa)
4311 struct PendingMessage *nxt;
4312 uint32_t fs = ntohl (fa->frag_uuid);
4313 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
4316 for (struct PendingMessage *frag = pm->head_frag; NULL != frag; frag = nxt)
4318 const struct TransportFragmentBox *tfb =
4319 (const struct TransportFragmentBox *) &pm[1];
4320 uint32_t fu = ntohl (tfb->frag_uuid);
4322 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
4323 nxt = frag->next_frag;
4324 /* Check for exact match or match in the 'xtra' bitmask */
4326 ((fu > fs) && (fu <= fs + 64) && (0 != (1LLU << (fu - fs - 1) & xtra))))
4329 free_fragment_tree (frag);
4337 * Communicator gave us a fragment acknowledgement. Process the request.
4339 * @param cls a `struct CommunicatorMessageContext` (must call
4340 * #finish_cmc_handling() when done)
4341 * @param fa the message that was received
4344 handle_fragment_ack (void *cls, const struct TransportFragmentAckMessage *fa)
4346 struct CommunicatorMessageContext *cmc = cls;
4347 struct Neighbour *n;
4350 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4353 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4356 finish_cmc_handling (cmc);
4357 GNUNET_SERVICE_client_drop (client);
4360 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4361 matched = GNUNET_NO;
4362 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm;
4363 pm = pm->prev_neighbour)
4365 if (0 != GNUNET_memcmp (&fa->msg_uuid, &pm->msg_uuid))
4367 matched = GNUNET_YES;
4368 if (GNUNET_YES == check_ack_against_pm (pm, fa))
4370 struct GNUNET_TIME_Relative avg_ack_delay =
4371 GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
4372 // FIXME: update RTT and other reliability data!
4373 // ISSUE: we don't know which of n's queues the message(s)
4374 // took (and in fact the different messages might have gone
4375 // over different queues and possibly over multiple).
4376 // => track queues with PendingMessages, and update RTT only if
4377 // the queue used is unique?
4378 // -> how can we get loss rates?
4379 // -> or, add extra state to Box and ACK to identify queue?
4380 // IDEA: generate MULTIPLE frag-uuids per fragment and track
4381 // the queue with the fragment! (-> this logic must
4382 // be moved into check_ack_against_pm!)
4383 (void) avg_ack_delay;
4387 GNUNET_STATISTICS_update (GST_stats,
4388 "# FRAGMENT_ACKS dropped, no matching fragment",
4392 if (NULL == pm->head_frag)
4394 // if entire message is ACKed, handle that as well.
4395 // => clean up PM, any post actions?
4396 free_pending_message (pm);
4400 struct GNUNET_TIME_Relative reassembly_timeout =
4401 GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
4402 // OPTIMIZE-FIXME: adjust retransmission strategy based on
4403 // reassembly_timeout!
4404 (void) reassembly_timeout;
4408 if (GNUNET_NO == matched)
4410 GNUNET_STATISTICS_update (GST_stats,
4411 "# FRAGMENT_ACKS dropped, no matching pending message",
4415 finish_cmc_handling (cmc);
4420 * Communicator gave us a reliability box. Check the message.
4422 * @param cls a `struct CommunicatorMessageContext`
4423 * @param rb the send message that was sent
4424 * @return #GNUNET_YES if message is well-formed
4427 check_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4429 GNUNET_MQ_check_boxed_message (rb);
4435 * Communicator gave us a reliability box. Process the request.
4437 * @param cls a `struct CommunicatorMessageContext` (must call
4438 * #finish_cmc_handling() when done)
4439 * @param rb the message that was received
4442 handle_reliability_box (void *cls, const struct TransportReliabilityBox *rb)
4444 struct CommunicatorMessageContext *cmc = cls;
4445 const struct GNUNET_MessageHeader *inbox =
4446 (const struct GNUNET_MessageHeader *) &rb[1];
4448 if (0 == ntohl (rb->ack_countdown))
4450 struct TransportReliabilityAckMessage *ack;
4452 /* FIXME: implement cummulative ACKs and ack_countdown,
4453 then setting the avg_ack_delay field below: */
4454 ack = GNUNET_malloc (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4455 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4457 htons (sizeof (*ack) + sizeof (struct GNUNET_ShortHashCode));
4458 memcpy (&ack[1], &rb->msg_uuid, sizeof (struct GNUNET_ShortHashCode));
4459 route_message (&cmc->im.sender, &ack->header, RMO_DV_ALLOWED);
4461 /* continue with inner message */
4462 demultiplex_with_cmc (cmc, inbox);
4467 * Communicator gave us a reliability ack. Process the request.
4469 * @param cls a `struct CommunicatorMessageContext` (must call
4470 * #finish_cmc_handling() when done)
4471 * @param ra the message that was received
4474 handle_reliability_ack (void *cls,
4475 const struct TransportReliabilityAckMessage *ra)
4477 struct CommunicatorMessageContext *cmc = cls;
4478 struct Neighbour *n;
4479 unsigned int n_acks;
4480 const struct GNUNET_ShortHashCode *msg_uuids;
4481 struct PendingMessage *nxt;
4484 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &cmc->im.sender);
4487 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4490 finish_cmc_handling (cmc);
4491 GNUNET_SERVICE_client_drop (client);
4494 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
4495 sizeof (struct GNUNET_ShortHashCode);
4496 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
4498 /* FIXME-OPTIMIZE: maybe use another hash map here? */
4499 matched = GNUNET_NO;
4500 for (struct PendingMessage *pm = n->pending_msg_head; NULL != pm; pm = nxt)
4504 nxt = pm->next_neighbour;
4505 in_list = GNUNET_NO;
4506 for (unsigned int i = 0; i < n_acks; i++)
4508 if (0 != GNUNET_memcmp (&msg_uuids[i], &pm->msg_uuid))
4510 in_list = GNUNET_YES;
4513 if (GNUNET_NO == in_list)
4516 /* this pm was acked! */
4517 matched = GNUNET_YES;
4518 free_pending_message (pm);
4521 struct GNUNET_TIME_Relative avg_ack_delay =
4522 GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
4523 // FIXME: update RTT and other reliability data!
4524 // ISSUE: we don't know which of n's queues the message(s)
4525 // took (and in fact the different messages might have gone
4526 // over different queues and possibly over multiple).
4527 // => track queues with PendingMessages, and update RTT only if
4528 // the queue used is unique?
4529 // -> how can we get loss rates?
4530 // -> or, add extra state to MSG and ACKs to identify queue?
4531 // -> if we do this, might just do the same for the avg_ack_delay!
4532 (void) avg_ack_delay;
4535 if (GNUNET_NO == matched)
4537 GNUNET_STATISTICS_update (GST_stats,
4538 "# FRAGMENT_ACKS dropped, no matching pending message",
4542 finish_cmc_handling (cmc);
4547 * Communicator gave us a backchannel encapsulation. Check the message.
4549 * @param cls a `struct CommunicatorMessageContext`
4550 * @param be the send message that was sent
4551 * @return #GNUNET_YES if message is well-formed
4554 check_backchannel_encapsulation (
4556 const struct TransportBackchannelEncapsulationMessage *be)
4558 uint16_t size = ntohs (be->header.size);
4561 if ((size - sizeof (*be)) <
4562 (sizeof (struct TransportBackchannelRequestPayload) +
4563 sizeof (struct GNUNET_MessageHeader)))
4565 GNUNET_break_op (0);
4566 return GNUNET_SYSERR;
4573 * Communicator gave us a backchannel encapsulation. Process the request.
4574 * (We are not the origin of the backchannel here, the communicator simply
4575 * received a backchannel message and we are expected to forward it.)
4577 * @param cls a `struct CommunicatorMessageContext` (must call
4578 * #finish_cmc_handling() when done)
4579 * @param be the message that was received
4582 handle_backchannel_encapsulation (
4584 const struct TransportBackchannelEncapsulationMessage *be)
4586 struct CommunicatorMessageContext *cmc = cls;
4587 struct BackchannelKeyState key;
4588 struct GNUNET_HashCode hmac;
4592 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
4594 /* not for me, try to route to target */
4595 /* FIXME: someone needs to update be->distance! */
4596 /* FIXME: BE routing can be special, should we put all of this
4597 on 'route_message'? Maybe at least pass some more arguments? */
4598 route_message (&be->target,
4599 GNUNET_copy_message (&be->header),
4601 finish_cmc_handling (cmc);
4604 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
4605 hdr = (const char *) &be[1];
4606 hdr_len = ntohs (be->header.size) - sizeof (*be);
4607 bc_hmac (&key, &hmac, hdr, hdr_len);
4608 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
4610 /* HMAC missmatch, disard! */
4611 GNUNET_break_op (0);
4612 finish_cmc_handling (cmc);
4615 /* begin actual decryption */
4617 struct TransportBackchannelRequestPayload ppay;
4618 char body[hdr_len - sizeof (ppay)];
4620 GNUNET_assert (hdr_len >=
4621 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
4622 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
4623 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
4624 bc_key_clean (&key);
4625 // FIXME: verify signatures in ppay!
4626 // => check if ephemeral key is known & valid, if not
4627 // => verify sig, cache ephemeral key
4628 // => update monotonic_time of sender for replay detection
4630 // FIXME: forward to specified communicator!
4631 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4633 finish_cmc_handling (cmc);
4638 * Task called when we should check if any of the DV paths
4639 * we have learned to a target are due for garbage collection.
4641 * Collects stale paths, and possibly frees the entire DV
4642 * entry if no paths are left. Otherwise re-schedules itself.
4644 * @param cls a `struct DistanceVector`
4647 path_cleanup_cb (void *cls)
4649 struct DistanceVector *dv = cls;
4650 struct DistanceVectorHop *pos;
4652 dv->timeout_task = NULL;
4653 while (NULL != (pos = dv->dv_head))
4655 GNUNET_assert (dv == pos->dv);
4656 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4658 free_distance_vector_hop (pos);
4666 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
4670 * Task run to check whether the hops of the @a cls still
4671 * are validated, or if we need to core about disconnection.
4673 * @param cls a `struct DistanceVector` (with core_visible set!)
4676 check_dv_path_down (void *cls)
4678 struct DistanceVector *dv = cls;
4679 struct Neighbour *n;
4681 dv->visibility_task = NULL;
4682 GNUNET_assert (GNUNET_YES == dv->core_visible);
4683 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4687 GNUNET_TIME_absolute_get_remaining (pos->path_valid_until).rel_value_us)
4689 dv->visibility_task = GNUNET_SCHEDULER_add_at (pos->path_valid_until,
4690 &check_dv_path_down,
4695 /* all paths invalid, make dv core-invisible */
4696 dv->core_visible = GNUNET_NO;
4697 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
4698 if ((NULL != n) && (GNUNET_YES == n->core_visible))
4699 return; /* no need to tell core, connection still up! */
4700 cores_send_disconnect_info (&dv->target);
4705 * The @a hop is a validated path to the respective target
4706 * peer and we should tell core about it -- and schedule
4707 * a job to revoke the state.
4709 * @param hop a path to some peer that is the reason for activation
4712 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
4714 struct DistanceVector *dv = hop->dv;
4715 struct Neighbour *n;
4717 GNUNET_assert (GNUNET_NO == dv->core_visible);
4718 GNUNET_assert (NULL == dv->visibility_task);
4720 dv->core_visible = GNUNET_YES;
4721 dv->visibility_task =
4722 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_dv_path_down, dv);
4723 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &dv->target);
4724 if ((NULL != n) && (GNUNET_YES == n->core_visible))
4725 return; /* no need to tell core, connection already up! */
4726 cores_send_connect_info (&dv->target,
4728 ? GNUNET_BANDWIDTH_value_sum (n->quota_out,
4735 * We have learned a @a path through the network to some other peer, add it to
4736 * our DV data structure (returning #GNUNET_YES on success).
4738 * We do not add paths if we have a sufficient number of shorter
4739 * paths to this target already (returning #GNUNET_NO).
4741 * We also do not add problematic paths, like those where we lack the first
4742 * hop in our neighbour list (i.e. due to a topology change) or where some
4743 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4745 * @param path the path we learned, path[0] should be us,
4746 * and then path contains a valid path from us to `path[path_len-1]`
4747 * path[1] should be a direct neighbour (we should check!)
4748 * @param path_len number of entries on the @a path, at least three!
4749 * @param network_latency how long does the message take from us to
4750 * `path[path_len-1]`? set to "forever" if unknown
4751 * @param path_valid_until how long is this path considered validated? Maybe be
4753 * @return #GNUNET_YES on success,
4754 * #GNUNET_NO if we have better path(s) to the target
4755 * #GNUNET_SYSERR if the path is useless and/or invalid
4756 * (i.e. path[1] not a direct neighbour
4757 * or path[i+1] is a direct neighbour for i>0)
4760 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4761 unsigned int path_len,
4762 struct GNUNET_TIME_Relative network_latency,
4763 struct GNUNET_TIME_Absolute path_valid_until)
4765 struct DistanceVectorHop *hop;
4766 struct DistanceVector *dv;
4767 struct Neighbour *next_hop;
4768 unsigned int shorter_distance;
4772 /* what a boring path! not allowed! */
4774 return GNUNET_SYSERR;
4776 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
4777 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours, &path[1]);
4778 if (NULL == next_hop)
4780 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4782 return GNUNET_SYSERR;
4784 for (unsigned int i = 2; i < path_len; i++)
4785 if (NULL != GNUNET_CONTAINER_multipeermap_get (neighbours, &path[i]))
4787 /* Useless path, we have a direct connection to some hop
4788 in the middle of the path, so this one doesn't even
4789 seem terribly useful for redundancy */
4790 return GNUNET_SYSERR;
4792 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
4795 dv = GNUNET_new (struct DistanceVector);
4796 dv->target = path[path_len - 1];
4797 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4800 GNUNET_assert (GNUNET_OK ==
4801 GNUNET_CONTAINER_multipeermap_put (
4805 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4807 /* Check if we have this path already! */
4808 shorter_distance = 0;
4809 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4812 if (pos->distance < path_len - 2)
4814 /* Note that the distances in 'pos' excludes us (path[0]) and
4815 the next_hop (path[1]), so we need to subtract two
4816 and check next_hop explicitly */
4817 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
4819 int match = GNUNET_YES;
4821 for (unsigned int i = 0; i < pos->distance; i++)
4823 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
4829 if (GNUNET_YES == match)
4831 struct GNUNET_TIME_Relative last_timeout;
4833 /* Re-discovered known path, update timeout */
4834 GNUNET_STATISTICS_update (GST_stats,
4835 "# Known DV path refreshed",
4838 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4840 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4841 pos->path_valid_until =
4842 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
4843 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
4844 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
4845 if ((GNUNET_NO == dv->core_visible) &&
4846 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until)
4848 activate_core_visible_dv_path (pos);
4849 if (last_timeout.rel_value_us <
4850 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4851 DV_PATH_DISCOVERY_FREQUENCY)
4854 /* Some peer send DV learn messages too often, we are learning
4855 the same path faster than it would be useful; do not forward! */
4862 /* Count how many shorter paths we have (incl. direct
4863 neighbours) before simply giving up on this one! */
4864 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4866 /* We have a shorter path already! */
4869 /* create new DV path entry */
4870 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4871 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4872 hop->next_hop = next_hop;
4874 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4877 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4878 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4879 hop->path_valid_until = path_valid_until;
4880 hop->distance = path_len - 2;
4881 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
4882 GNUNET_CONTAINER_MDLL_insert (neighbour,
4886 if ((GNUNET_NO == dv->core_visible) &&
4887 (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us))
4888 activate_core_visible_dv_path (hop);
4894 * Communicator gave us a DV learn message. Check the message.
4896 * @param cls a `struct CommunicatorMessageContext`
4897 * @param dvl the send message that was sent
4898 * @return #GNUNET_YES if message is well-formed
4901 check_dv_learn (void *cls, const struct TransportDVLearn *dvl)
4903 uint16_t size = ntohs (dvl->header.size);
4904 uint16_t num_hops = ntohs (dvl->num_hops);
4905 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4908 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4910 GNUNET_break_op (0);
4911 return GNUNET_SYSERR;
4913 if (num_hops > MAX_DV_HOPS_ALLOWED)
4915 GNUNET_break_op (0);
4916 return GNUNET_SYSERR;
4918 for (unsigned int i = 0; i < num_hops; i++)
4920 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
4922 GNUNET_break_op (0);
4923 return GNUNET_SYSERR;
4925 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
4927 GNUNET_break_op (0);
4928 return GNUNET_SYSERR;
4936 * Build and forward a DV learn message to @a next_hop.
4938 * @param next_hop peer to send the message to
4939 * @param msg message received
4940 * @param bi_history bitmask specifying hops on path that were bidirectional
4941 * @param nhops length of the @a hops array
4942 * @param hops path the message traversed so far
4943 * @param in_time when did we receive the message, used to calculate network
4947 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4948 const struct TransportDVLearn *msg,
4949 uint16_t bi_history,
4951 const struct DVPathEntryP *hops,
4952 struct GNUNET_TIME_Absolute in_time)
4954 struct DVPathEntryP *dhops;
4955 struct TransportDVLearn *fwd;
4956 struct GNUNET_TIME_Relative nnd;
4958 /* compute message for forwarding */
4959 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4960 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4961 (nhops + 1) * sizeof (struct DVPathEntryP));
4962 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4963 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4964 (nhops + 1) * sizeof (struct DVPathEntryP));
4965 fwd->num_hops = htons (nhops + 1);
4966 fwd->bidirectional = htons (bi_history);
4967 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4968 GNUNET_TIME_relative_ntoh (
4969 msg->non_network_delay));
4970 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4971 fwd->init_sig = msg->init_sig;
4972 fwd->initiator = msg->initiator;
4973 fwd->challenge = msg->challenge;
4974 dhops = (struct DVPathEntryP *) &fwd[1];
4975 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
4976 dhops[nhops].hop = GST_my_identity;
4978 struct DvHopPS dhp = {.purpose.purpose =
4979 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4980 .purpose.size = htonl (sizeof (dhp)),
4981 .pred = dhops[nhops - 1].hop,
4983 .challenge = msg->challenge};
4985 GNUNET_assert (GNUNET_OK ==
4986 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4988 &dhops[nhops].hop_sig));
4990 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
4995 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4997 * @param init the signer
4998 * @param challenge the challenge that was signed
4999 * @param init_sig signature presumably by @a init
5000 * @return #GNUNET_OK if the signature is valid
5003 validate_dv_initiator_signature (
5004 const struct GNUNET_PeerIdentity *init,
5005 const struct GNUNET_ShortHashCode *challenge,
5006 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
5008 struct DvInitPS ip = {.purpose.purpose = htonl (
5009 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
5010 .purpose.size = htonl (sizeof (ip)),
5011 .challenge = *challenge};
5015 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
5020 GNUNET_break_op (0);
5021 return GNUNET_SYSERR;
5028 * Communicator gave us a DV learn message. Process the request.
5030 * @param cls a `struct CommunicatorMessageContext` (must call
5031 * #finish_cmc_handling() when done)
5032 * @param dvl the message that was received
5035 handle_dv_learn (void *cls, const struct TransportDVLearn *dvl)
5037 struct CommunicatorMessageContext *cmc = cls;
5038 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
5041 uint16_t bi_history;
5042 const struct DVPathEntryP *hops;
5045 struct GNUNET_TIME_Absolute in_time;
5047 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
5048 bi_history = ntohs (dvl->bidirectional);
5049 hops = (const struct DVPathEntryP *) &dvl[1];
5053 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
5056 finish_cmc_handling (cmc);
5063 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
5066 finish_cmc_handling (cmc);
5071 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
5072 cc = cmc->tc->details.communicator.cc;
5073 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
5074 cc); // FIXME: add bi-directional flag to cc?
5075 in_time = GNUNET_TIME_absolute_get ();
5077 /* continue communicator here, everything else can happen asynchronous! */
5078 finish_cmc_handling (cmc);
5080 /* OPTIMIZE-FIXME: Technically, we only need to bother checking
5081 the initiator signature if we send the message back to the initiator... */
5082 if (GNUNET_OK != validate_dv_initiator_signature (&dvl->initiator,
5086 GNUNET_break_op (0);
5089 // FIXME: asynchronously (!) verify hop-by-hop signatures!
5090 // => if signature verification load too high, implement random drop
5093 do_fwd = GNUNET_YES;
5094 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
5096 struct GNUNET_PeerIdentity path[nhops + 1];
5097 struct GNUNET_TIME_Relative host_latency_sum;
5098 struct GNUNET_TIME_Relative latency;
5099 struct GNUNET_TIME_Relative network_latency;
5101 /* We initiated this, learn the forward path! */
5102 path[0] = GST_my_identity;
5103 path[1] = hops[0].hop;
5104 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
5106 // Need also something to lookup initiation time
5107 // to compute RTT! -> add RTT argument here?
5108 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
5109 // (based on dvl->challenge, we can identify time of origin!)
5111 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
5112 /* assumption: latency on all links is the same */
5113 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
5115 for (unsigned int i = 2; i <= nhops; i++)
5117 struct GNUNET_TIME_Relative ilat;
5119 /* assumption: linear latency increase per hop */
5120 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
5121 path[i] = hops[i - 1].hop;
5122 learn_dv_path (path,
5125 GNUNET_TIME_relative_to_absolute (
5126 ADDRESS_VALIDATION_LIFETIME));
5128 /* as we initiated, do not forward again (would be circular!) */
5134 /* last hop was bi-directional, we could learn something here! */
5135 struct GNUNET_PeerIdentity path[nhops + 2];
5137 path[0] = GST_my_identity;
5138 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
5139 for (unsigned int i = 0; i < nhops; i++)
5143 if (0 == (bi_history & (1 << i)))
5144 break; /* i-th hop not bi-directional, stop learning! */
5147 path[i + 2] = dvl->initiator;
5151 path[i + 2] = hops[nhops - i - 2].hop;
5154 iret = learn_dv_path (path,
5156 GNUNET_TIME_UNIT_FOREVER_REL,
5157 GNUNET_TIME_UNIT_ZERO_ABS);
5158 if (GNUNET_SYSERR == iret)
5160 /* path invalid or too long to be interesting for US, thus should also
5161 not be interesting to our neighbours, cut path when forwarding to
5162 'i' hops, except of course for the one that goes back to the
5164 GNUNET_STATISTICS_update (GST_stats,
5165 "# DV learn not forwarded due invalidity of path",
5171 if ((GNUNET_NO == iret) && (nhops == i + 1))
5173 /* we have better paths, and this is the longest target,
5174 so there cannot be anything interesting later */
5175 GNUNET_STATISTICS_update (GST_stats,
5176 "# DV learn not forwarded, got better paths",
5185 if (MAX_DV_HOPS_ALLOWED == nhops)
5187 /* At limit, we're out of here! */
5188 finish_cmc_handling (cmc);
5192 /* Forward to initiator, if path non-trivial and possible */
5193 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
5194 did_initiator = GNUNET_NO;
5197 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
5199 /* send back to origin! */
5200 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
5201 did_initiator = GNUNET_YES;
5203 /* We forward under two conditions: either we still learned something
5204 ourselves (do_fwd), or the path was darn short and thus the initiator is
5205 likely to still be very interested in this (and we did NOT already
5206 send it back to the initiator) */
5207 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
5208 (GNUNET_NO == did_initiator)))
5210 /* FIXME: loop over all neighbours, pick those with low
5211 queues AND that are not yet on the path; possibly
5212 adapt threshold to nhops! */
5214 forward_dv_learn (NULL, // fill in peer from iterator here!
5226 * Communicator gave us a DV box. Check the message.
5228 * @param cls a `struct CommunicatorMessageContext`
5229 * @param dvb the send message that was sent
5230 * @return #GNUNET_YES if message is well-formed
5233 check_dv_box (void *cls, const struct TransportDVBox *dvb)
5235 uint16_t size = ntohs (dvb->header.size);
5236 uint16_t num_hops = ntohs (dvb->num_hops);
5237 const struct GNUNET_PeerIdentity *hops =
5238 (const struct GNUNET_PeerIdentity *) &dvb[1];
5239 const struct GNUNET_MessageHeader *inbox =
5240 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5245 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
5246 sizeof (struct GNUNET_MessageHeader))
5248 GNUNET_break_op (0);
5249 return GNUNET_SYSERR;
5251 isize = ntohs (inbox->size);
5253 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
5255 GNUNET_break_op (0);
5256 return GNUNET_SYSERR;
5258 itype = ntohs (inbox->type);
5259 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
5260 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
5262 GNUNET_break_op (0);
5263 return GNUNET_SYSERR;
5265 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
5267 GNUNET_break_op (0);
5268 return GNUNET_SYSERR;
5275 * Create a DV Box message and queue it for transmission to
5278 * @param next_hop peer to receive the message next
5279 * @param total_hops how many hops did the message take so far
5280 * @param num_hops length of the @a hops array
5281 * @param origin origin of the message
5282 * @param hops next peer(s) to the destination, including destination
5283 * @param payload payload of the box
5284 * @param payload_size number of bytes in @a payload
5287 forward_dv_box (struct Neighbour *next_hop,
5288 uint16_t total_hops,
5290 const struct GNUNET_PeerIdentity *origin,
5291 const struct GNUNET_PeerIdentity *hops,
5292 const void *payload,
5293 uint16_t payload_size)
5295 struct TransportDVBox *dvb;
5296 struct GNUNET_PeerIdentity *dhops;
5298 GNUNET_assert (UINT16_MAX < sizeof (struct TransportDVBox) +
5299 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5301 dvb = GNUNET_malloc (sizeof (struct TransportDVBox) +
5302 sizeof (struct GNUNET_PeerIdentity) * num_hops +
5305 htons (sizeof (struct TransportDVBox) +
5306 sizeof (struct GNUNET_PeerIdentity) * num_hops + payload_size);
5307 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5308 dvb->total_hops = htons (total_hops);
5309 dvb->num_hops = htons (num_hops);
5310 dvb->origin = *origin;
5311 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
5312 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
5313 memcpy (&dhops[num_hops], payload, payload_size);
5314 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
5319 * Communicator gave us a DV box. Process the request.
5321 * @param cls a `struct CommunicatorMessageContext` (must call
5322 * #finish_cmc_handling() when done)
5323 * @param dvb the message that was received
5326 handle_dv_box (void *cls, const struct TransportDVBox *dvb)
5328 struct CommunicatorMessageContext *cmc = cls;
5329 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
5330 uint16_t num_hops = ntohs (dvb->num_hops);
5331 const struct GNUNET_PeerIdentity *hops =
5332 (const struct GNUNET_PeerIdentity *) &dvb[1];
5333 const struct GNUNET_MessageHeader *inbox =
5334 (const struct GNUNET_MessageHeader *) &hops[num_hops];
5338 /* We're trying from the end of the hops array, as we may be
5339 able to find a shortcut unknown to the origin that way */
5340 for (int i = num_hops - 1; i >= 0; i--)
5342 struct Neighbour *n;
5344 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
5346 GNUNET_break_op (0);
5347 finish_cmc_handling (cmc);
5350 n = GNUNET_CONTAINER_multipeermap_get (neighbours, &hops[i]);
5354 ntohs (dvb->total_hops) + 1,
5355 num_hops - i - 1, /* number of hops left */
5357 &hops[i + 1], /* remaining hops */
5358 (const void *) &dvb[1],
5360 finish_cmc_handling (cmc);
5363 /* Woopsie, next hop not in neighbours, drop! */
5364 GNUNET_STATISTICS_update (GST_stats,
5365 "# DV Boxes dropped: next hop unknown",
5368 finish_cmc_handling (cmc);
5371 /* We are the target. Unbox and handle message. */
5372 cmc->im.sender = dvb->origin;
5373 cmc->total_hops = ntohs (dvb->total_hops);
5374 demultiplex_with_cmc (cmc, inbox);
5379 * Client notified us about transmission from a peer. Process the request.
5381 * @param cls a `struct TransportClient` which sent us the message
5382 * @param obm the send message that was sent
5383 * @return #GNUNET_YES if message is well-formed
5386 check_incoming_msg (void *cls,
5387 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5389 struct TransportClient *tc = cls;
5391 if (CT_COMMUNICATOR != tc->type)
5394 return GNUNET_SYSERR;
5396 GNUNET_MQ_check_boxed_message (im);
5402 * Communicator gave us a transport address validation challenge. Process the
5405 * @param cls a `struct CommunicatorMessageContext` (must call
5406 * #finish_cmc_handling() when done)
5407 * @param tvc the message that was received
5410 handle_validation_challenge (void *cls,
5411 const struct TransportValidationChallenge *tvc)
5413 struct CommunicatorMessageContext *cmc = cls;
5414 struct TransportValidationResponse *tvr;
5416 if (cmc->total_hops > 0)
5418 /* DV routing is not allowed for validation challenges! */
5419 GNUNET_break_op (0);
5420 finish_cmc_handling (cmc);
5423 tvr = GNUNET_new (struct TransportValidationResponse);
5425 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
5426 tvr->header.size = htons (sizeof (*tvr));
5427 tvr->challenge = tvc->challenge;
5428 tvr->origin_time = tvc->sender_time;
5429 tvr->validity_duration = cmc->im.expected_address_validity;
5431 /* create signature */
5432 struct TransportValidationPS tvp =
5433 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5434 .purpose.size = htonl (sizeof (tvp)),
5435 .validity_duration = tvr->validity_duration,
5436 .challenge = tvc->challenge};
5438 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
5442 route_message (&cmc->im.sender,
5444 RMO_ANYTHING_GOES | RMO_REDUNDANT);
5445 finish_cmc_handling (cmc);
5450 * Closure for #check_known_challenge.
5452 struct CheckKnownChallengeContext
5455 * Set to the challenge we are looking for.
5457 const struct GNUNET_ShortHashCode *challenge;
5460 * Set to a matching validation state, if one was found.
5462 struct ValidationState *vs;
5467 * Test if the validation state in @a value matches the
5468 * challenge from @a cls.
5470 * @param cls a `struct CheckKnownChallengeContext`
5471 * @param pid unused (must match though)
5472 * @param value a `struct ValidationState`
5473 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5476 check_known_challenge (void *cls,
5477 const struct GNUNET_PeerIdentity *pid,
5480 struct CheckKnownChallengeContext *ckac = cls;
5481 struct ValidationState *vs = value;
5484 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
5492 * Function called when peerstore is done storing a
5493 * validated address.
5495 * @param cls a `struct ValidationState`
5496 * @param success #GNUNET_YES on success
5499 peerstore_store_validation_cb (void *cls, int success)
5501 struct ValidationState *vs = cls;
5504 if (GNUNET_YES == success)
5506 GNUNET_STATISTICS_update (GST_stats,
5507 "# Peerstore failed to store foreign address",
5514 * Task run periodically to validate some address based on #validation_heap.
5519 validation_start_cb (void *cls);
5523 * Set the time for next_challenge of @a vs to @a new_time.
5524 * Updates the heap and if necessary reschedules the job.
5526 * @param vs validation state to update
5527 * @param new_time new time for revalidation
5530 update_next_challenge_time (struct ValidationState *vs,
5531 struct GNUNET_TIME_Absolute new_time)
5533 struct GNUNET_TIME_Relative delta;
5535 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
5536 return; /* be lazy */
5537 vs->next_challenge = new_time;
5540 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
5542 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
5543 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
5544 (NULL != validation_task))
5546 if (NULL != validation_task)
5547 GNUNET_SCHEDULER_cancel (validation_task);
5548 /* randomize a bit */
5549 delta.rel_value_us =
5550 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5551 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
5552 new_time = GNUNET_TIME_absolute_add (new_time, delta);
5554 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
5559 * Find the queue matching @a pid and @a address.
5561 * @param pid peer the queue must go to
5562 * @param address address the queue must use
5563 * @return NULL if no such queue exists
5565 static struct Queue *
5566 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
5568 struct Neighbour *n;
5570 n = GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
5573 for (struct Queue *pos = n->queue_head; NULL != pos;
5574 pos = pos->next_neighbour)
5576 if (0 == strcmp (pos->address, address))
5584 * Task run periodically to check whether the validity of the given queue has
5585 * run its course. If so, finds either another queue to take over, or clears
5586 * the neighbour's `core_visible` flag. In the latter case, gives DV routes a
5587 * chance to take over, and if that fails, notifies CORE about the disconnect.
5589 * @param cls a `struct Queue`
5592 core_queue_visibility_check (void *cls)
5594 struct Queue *q = cls;
5596 q->visibility_task = NULL;
5597 if (0 != GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5599 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5600 &core_queue_visibility_check,
5604 update_neighbour_core_visibility (q->neighbour);
5609 * Check whether the CORE visibility of @a n should change. Finds either a
5610 * queue to preserve the visibility, or clears the neighbour's `core_visible`
5611 * flag. In the latter case, gives DV routes a chance to take over, and if
5612 * that fails, notifies CORE about the disconnect. If so, check whether we
5613 * need to notify CORE.
5615 * @param n neighbour to perform the check for
5618 update_neighbour_core_visibility (struct Neighbour *n)
5620 struct DistanceVector *dv;
5622 GNUNET_assert (GNUNET_YES == n->core_visible);
5623 /* Check if _any_ queue of this neighbour is still valid, if so, schedule
5624 the #core_queue_visibility_check() task for that queue */
5625 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
5628 GNUNET_TIME_absolute_get_remaining (q->validated_until).rel_value_us)
5630 /* found a valid queue, use this one */
5631 q->visibility_task =
5632 GNUNET_SCHEDULER_add_at (q->validated_until,
5633 &core_queue_visibility_check,
5638 n->core_visible = GNUNET_NO;
5640 /* Check if _any_ DV route to this neighbour is currently
5641 valid, if so, do NOT tell core about the loss of direct
5642 connectivity (DV still counts!) */
5643 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
5644 if (GNUNET_YES == dv->core_visible)
5646 /* Nothing works anymore, need to tell CORE about the loss of
5648 cores_send_disconnect_info (&n->pid);
5653 * Communicator gave us a transport address validation response. Process the
5656 * @param cls a `struct CommunicatorMessageContext` (must call
5657 * #finish_cmc_handling() when done)
5658 * @param tvr the message that was received
5661 handle_validation_response (void *cls,
5662 const struct TransportValidationResponse *tvr)
5664 struct CommunicatorMessageContext *cmc = cls;
5665 struct ValidationState *vs;
5666 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
5668 struct GNUNET_TIME_Absolute origin_time;
5670 struct DistanceVector *dv;
5671 struct Neighbour *n;
5673 /* check this is one of our challenges */
5674 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5676 &check_known_challenge,
5678 if (NULL == (vs = ckac.vs))
5680 /* This can happen simply if we 'forgot' the challenge by now,
5681 i.e. because we received the validation response twice */
5682 GNUNET_STATISTICS_update (GST_stats,
5683 "# Validations dropped, challenge unknown",
5686 finish_cmc_handling (cmc);
5690 /* sanity check on origin time */
5691 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
5692 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
5693 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
5695 GNUNET_break_op (0);
5696 finish_cmc_handling (cmc);
5701 /* check signature */
5702 struct TransportValidationPS tvp =
5703 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
5704 .purpose.size = htonl (sizeof (tvp)),
5705 .validity_duration = tvr->validity_duration,
5706 .challenge = tvr->challenge};
5710 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
5713 &cmc->im.sender.public_key))
5715 GNUNET_break_op (0);
5716 finish_cmc_handling (cmc);
5721 /* validity is capped by our willingness to keep track of the
5722 validation entry and the maximum the other peer allows */
5723 vs->valid_until = GNUNET_TIME_relative_to_absolute (
5724 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
5725 tvr->validity_duration),
5726 MAX_ADDRESS_VALID_UNTIL));
5727 vs->validated_until =
5728 GNUNET_TIME_absolute_min (vs->valid_until,
5729 GNUNET_TIME_relative_to_absolute (
5730 ADDRESS_VALIDATION_LIFETIME));
5731 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
5732 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
5733 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5735 sizeof (vs->challenge));
5736 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
5737 vs->validated_until,
5738 GNUNET_TIME_relative_multiply (vs->validation_rtt,
5739 VALIDATION_RTT_BUFFER_FACTOR));
5740 vs->last_challenge_use =
5741 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
5742 update_next_challenge_time (vs, vs->first_challenge_use);
5743 vs->sc = GNUNET_PEERSTORE_store (peerstore,
5746 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
5748 strlen (vs->address) + 1,
5750 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5751 &peerstore_store_validation_cb,
5753 finish_cmc_handling (cmc);
5755 /* Finally, we now possibly have a confirmed (!) working queue,
5756 update queue status (if queue still is around) */
5757 q = find_queue (&vs->pid, vs->address);
5760 GNUNET_STATISTICS_update (GST_stats,
5761 "# Queues lost at time of successful validation",
5766 q->validated_until = vs->validated_until;
5767 q->rtt = vs->validation_rtt;
5769 if (GNUNET_NO != n->core_visible)
5770 return; /* nothing changed, we are done here */
5771 n->core_visible = GNUNET_YES;
5772 q->visibility_task = GNUNET_SCHEDULER_add_at (q->validated_until,
5773 &core_queue_visibility_check,
5775 /* Check if _any_ DV route to this neighbour is
5776 currently valid, if so, do NOT tell core anything! */
5777 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &n->pid);
5778 if ((NULL != dv) && (GNUNET_YES == dv->core_visible))
5779 return; /* nothing changed, done */
5780 /* We lacked a confirmed connection to the neighbour
5781 before, so tell CORE about it (finally!) */
5782 cores_send_connect_info (&n->pid,
5784 ? GNUNET_BANDWIDTH_value_sum (dv->quota_out,
5791 * Incoming meessage. Process the request.
5793 * @param im the send message that was received
5796 handle_incoming_msg (void *cls,
5797 const struct GNUNET_TRANSPORT_IncomingMessage *im)
5799 struct TransportClient *tc = cls;
5800 struct CommunicatorMessageContext *cmc =
5801 GNUNET_new (struct CommunicatorMessageContext);
5805 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
5810 * Given an inbound message @a msg from a communicator @a cmc,
5811 * demultiplex it based on the type calling the right handler.
5813 * @param cmc context for demultiplexing
5814 * @param msg message to demultiplex
5817 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5818 const struct GNUNET_MessageHeader *msg)
5820 struct GNUNET_MQ_MessageHandler handlers[] =
5821 {GNUNET_MQ_hd_var_size (fragment_box,
5822 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
5823 struct TransportFragmentBox,
5825 GNUNET_MQ_hd_fixed_size (fragment_ack,
5826 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
5827 struct TransportFragmentAckMessage,
5829 GNUNET_MQ_hd_var_size (reliability_box,
5830 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5831 struct TransportReliabilityBox,
5833 GNUNET_MQ_hd_fixed_size (reliability_ack,
5834 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5835 struct TransportReliabilityAckMessage,
5837 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5838 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5839 struct TransportBackchannelEncapsulationMessage,
5841 GNUNET_MQ_hd_var_size (dv_learn,
5842 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5843 struct TransportDVLearn,
5845 GNUNET_MQ_hd_var_size (dv_box,
5846 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5847 struct TransportDVBox,
5849 GNUNET_MQ_hd_fixed_size (
5850 validation_challenge,
5851 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5852 struct TransportValidationChallenge,
5854 GNUNET_MQ_hd_fixed_size (
5855 validation_response,
5856 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5857 struct TransportValidationResponse,
5859 GNUNET_MQ_handler_end ()};
5862 ret = GNUNET_MQ_handle_message (handlers, msg);
5863 if (GNUNET_SYSERR == ret)
5866 GNUNET_SERVICE_client_drop (cmc->tc->client);
5870 if (GNUNET_NO == ret)
5872 /* unencapsulated 'raw' message */
5873 handle_raw_message (&cmc, msg);
5879 * New queue became available. Check message.
5881 * @param cls the client
5882 * @param aqm the send message that was sent
5885 check_add_queue_message (void *cls,
5886 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5888 struct TransportClient *tc = cls;
5890 if (CT_COMMUNICATOR != tc->type)
5893 return GNUNET_SYSERR;
5895 GNUNET_MQ_check_zero_termination (aqm);
5901 * Bandwidth tracker informs us that the delay until we should receive
5904 * @param cls a `struct Queue` for which the delay changed
5907 tracker_update_in_cb (void *cls)
5909 struct Queue *queue = cls;
5910 struct GNUNET_TIME_Relative in_delay;
5913 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5914 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, rsize);
5915 // FIXME: how exactly do we do inbound flow control?
5920 * If necessary, generates the UUID for a @a pm
5922 * @param pm pending message to generate UUID for.
5925 set_pending_message_uuid (struct PendingMessage *pm)
5927 if (pm->msg_uuid_set)
5929 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5931 sizeof (pm->msg_uuid));
5932 pm->msg_uuid_set = GNUNET_YES;
5937 * Fragment the given @a pm to the given @a mtu. Adds
5938 * additional fragments to the neighbour as well. If the
5939 * @a mtu is too small, generates and error for the @a pm
5942 * @param pm pending message to fragment for transmission
5943 * @param mtu MTU to apply
5944 * @return new message to transmit
5946 static struct PendingMessage *
5947 fragment_message (struct PendingMessage *pm, uint16_t mtu)
5949 struct PendingMessage *ff;
5951 set_pending_message_uuid (pm);
5953 /* This invariant is established in #handle_add_queue_message() */
5954 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5956 /* select fragment for transmission, descending the tree if it has
5957 been expanded until we are at a leaf or at a fragment that is small enough
5960 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
5961 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
5963 ff = ff->head_frag; /* descent into fragmented fragments */
5966 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
5968 /* Did not yet calculate all fragments, calculate next fragment */
5969 struct PendingMessage *frag;
5970 struct TransportFragmentBox tfb;
5978 orig = (const char *) &ff[1];
5979 msize = ff->bytes_msg;
5982 const struct TransportFragmentBox *tfbo;
5984 tfbo = (const struct TransportFragmentBox *) orig;
5985 orig += sizeof (struct TransportFragmentBox);
5986 msize -= sizeof (struct TransportFragmentBox);
5987 xoff = ntohs (tfbo->frag_off);
5989 fragmax = mtu - sizeof (struct TransportFragmentBox);
5990 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
5991 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5992 sizeof (struct TransportFragmentBox) + fragsize);
5993 frag->target = pm->target;
5994 frag->frag_parent = ff;
5995 frag->timeout = pm->timeout;
5996 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5997 frag->pmt = PMT_FRAGMENT_BOX;
5998 msg = (char *) &frag[1];
5999 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
6000 tfb.header.size = htons (sizeof (struct TransportFragmentBox) + fragsize);
6001 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
6002 tfb.msg_uuid = pm->msg_uuid;
6003 tfb.frag_off = htons (ff->frag_off + xoff);
6004 tfb.msg_size = htons (pm->bytes_msg);
6005 memcpy (msg, &tfb, sizeof (tfb));
6006 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
6007 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
6008 ff->frag_off += fragsize;
6012 /* Move head to the tail and return it */
6013 GNUNET_CONTAINER_MDLL_remove (frag,
6014 ff->frag_parent->head_frag,
6015 ff->frag_parent->tail_frag,
6017 GNUNET_CONTAINER_MDLL_insert_tail (frag,
6018 ff->frag_parent->head_frag,
6019 ff->frag_parent->tail_frag,
6026 * Reliability-box the given @a pm. On error (can there be any), NULL
6027 * may be returned, otherwise the "replacement" for @a pm (which
6028 * should then be added to the respective neighbour's queue instead of
6029 * @a pm). If the @a pm is already fragmented or reliability boxed,
6030 * or itself an ACK, this function simply returns @a pm.
6032 * @param pm pending message to box for transmission over unreliabile queue
6033 * @return new message to transmit
6035 static struct PendingMessage *
6036 reliability_box_message (struct PendingMessage *pm)
6038 struct TransportReliabilityBox rbox;
6039 struct PendingMessage *bpm;
6042 if (PMT_CORE != pm->pmt)
6043 return pm; /* already fragmented or reliability boxed, or control message:
6045 if (NULL != pm->bpm)
6046 return pm->bpm; /* already computed earlier: do nothing */
6047 GNUNET_assert (NULL == pm->head_frag);
6048 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
6052 client_send_response (pm, GNUNET_NO, 0);
6055 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
6057 bpm->target = pm->target;
6058 bpm->frag_parent = pm;
6059 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
6060 bpm->timeout = pm->timeout;
6061 bpm->pmt = PMT_RELIABILITY_BOX;
6062 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
6063 set_pending_message_uuid (bpm);
6064 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
6065 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
6066 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
6067 rbox.msg_uuid = pm->msg_uuid;
6068 msg = (char *) &bpm[1];
6069 memcpy (msg, &rbox, sizeof (rbox));
6070 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
6077 * Change the value of the `next_attempt` field of @a pm
6078 * to @a next_attempt and re-order @a pm in the transmission
6079 * list as required by the new timestmap.
6081 * @param pm a pending message to update
6082 * @param next_attempt timestamp to use
6085 update_pm_next_attempt (struct PendingMessage *pm,
6086 struct GNUNET_TIME_Absolute next_attempt)
6088 struct Neighbour *neighbour = pm->target;
6090 pm->next_attempt = next_attempt;
6091 if (NULL == pm->frag_parent)
6093 struct PendingMessage *pos;
6095 /* re-insert sort in neighbour list */
6096 GNUNET_CONTAINER_MDLL_remove (neighbour,
6097 neighbour->pending_msg_head,
6098 neighbour->pending_msg_tail,
6100 pos = neighbour->pending_msg_tail;
6101 while ((NULL != pos) &&
6102 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6103 pos = pos->prev_neighbour;
6104 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
6105 neighbour->pending_msg_head,
6106 neighbour->pending_msg_tail,
6112 /* re-insert sort in fragment list */
6113 struct PendingMessage *fp = pm->frag_parent;
6114 struct PendingMessage *pos;
6116 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
6117 pos = fp->tail_frag;
6118 while ((NULL != pos) &&
6119 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
6120 pos = pos->prev_frag;
6121 GNUNET_CONTAINER_MDLL_insert_after (frag,
6131 * We believe we are ready to transmit a message on a queue. Double-checks
6132 * with the queue's "tracker_out" and then gives the message to the
6133 * communicator for transmission (updating the tracker, and re-scheduling
6134 * itself if applicable).
6136 * @param cls the `struct Queue` to process transmissions for
6139 transmit_on_queue (void *cls)
6141 struct Queue *queue = cls;
6142 struct Neighbour *n = queue->neighbour;
6143 struct PendingMessage *pm;
6144 struct PendingMessage *s;
6147 queue->transmit_task = NULL;
6148 if (NULL == (pm = n->pending_msg_head))
6150 /* no message pending, nothing to do here! */
6155 /* message still pending with communciator!
6156 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
6159 schedule_transmit_on_queue (queue, GNUNET_YES);
6160 if (NULL != queue->transmit_task)
6161 return; /* do it later */
6163 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6164 overhead += sizeof (struct TransportReliabilityBox);
6166 if ( ( (0 != queue->mtu) &&
6167 (pm->bytes_msg + overhead > queue->mtu) ) ||
6168 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
6169 (NULL != pm->head_frag /* fragments already exist, should
6170 respect that even if MTU is 0 for
6172 s = fragment_message (s,
6175 sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
6179 /* Fragmentation failed, try next message... */
6180 schedule_transmit_on_queue (queue, GNUNET_NO);
6183 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
6184 s = reliability_box_message (s);
6187 /* Reliability boxing failed, try next message... */
6188 schedule_transmit_on_queue (queue, GNUNET_NO);
6192 /* Pass 's' for transission to the communicator */
6193 queue_send_msg (queue, s, &s[1], s->bytes_msg);
6194 // FIXME: do something similar to the logic below
6195 // in defragmentation / reliability ACK handling!
6197 /* Check if this transmission somehow conclusively finished handing 'pm'
6198 even without any explicit ACKs */
6199 if ((PMT_CORE == s->pmt) &&
6200 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
6202 /* Full message sent, and over reliabile channel */
6203 client_send_response (pm, GNUNET_YES, pm->bytes_msg);
6205 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
6206 queue->tc->details.communicator.cc) &&
6207 (PMT_FRAGMENT_BOX == s->pmt))
6209 struct PendingMessage *pos;
6211 /* Fragment sent over reliabile channel */
6212 free_fragment_tree (s);
6213 pos = s->frag_parent;
6214 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6216 /* check if subtree is done */
6217 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6221 pos = s->frag_parent;
6222 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
6226 /* Was this the last applicable fragmment? */
6227 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
6228 client_send_response (
6231 pm->bytes_msg /* FIXME: calculate and add overheads! */);
6233 else if (PMT_CORE != pm->pmt)
6235 /* This was an acknowledgement of some type, always free */
6236 free_pending_message (pm);
6240 /* Message not finished, waiting for acknowledgement.
6241 Update time by which we might retransmit 's' based on queue
6242 characteristics (i.e. RTT); it takes one RTT for the message to
6243 arrive and the ACK to come back in the best case; but the other
6244 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
6245 retransmitting. Note that in the future this heuristic should
6246 likely be improved further (measure RTT stability, consider
6247 message urgency and size when delaying ACKs, etc.) */
6248 update_pm_next_attempt (s,
6249 GNUNET_TIME_relative_to_absolute (
6250 GNUNET_TIME_relative_multiply (queue->rtt, 4)));
6253 /* finally, re-schedule queue transmission task itself */
6254 schedule_transmit_on_queue (queue, GNUNET_NO);
6259 * Bandwidth tracker informs us that the delay until we
6260 * can transmit again changed.
6262 * @param cls a `struct Queue` for which the delay changed
6265 tracker_update_out_cb (void *cls)
6267 struct Queue *queue = cls;
6268 struct Neighbour *n = queue->neighbour;
6270 if (NULL == n->pending_msg_head)
6272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6273 "Bandwidth allocation updated for empty transmission queue `%s'\n",
6275 return; /* no message pending, nothing to do here! */
6277 GNUNET_SCHEDULER_cancel (queue->transmit_task);
6278 queue->transmit_task = NULL;
6279 schedule_transmit_on_queue (queue, GNUNET_NO);
6284 * Bandwidth tracker informs us that excessive outbound bandwidth was
6285 * allocated which is not being used.
6287 * @param cls a `struct Queue` for which the excess was noted
6290 tracker_excess_out_cb (void *cls)
6294 /* FIXME: trigger excess bandwidth report to core? Right now,
6295 this is done internally within transport_api2_core already,
6296 but we probably want to change the logic and trigger it
6297 from here via a message instead! */
6298 /* TODO: maybe inform someone at this point? */
6299 GNUNET_STATISTICS_update (GST_stats,
6300 "# Excess outbound bandwidth reported",
6307 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
6308 * which is not being used.
6310 * @param cls a `struct Queue` for which the excess was noted
6313 tracker_excess_in_cb (void *cls)
6317 /* TODO: maybe inform somone at this point? */
6318 GNUNET_STATISTICS_update (GST_stats,
6319 "# Excess inbound bandwidth reported",
6326 * Queue to a peer went down. Process the request.
6328 * @param cls the client
6329 * @param dqm the send message that was sent
6332 handle_del_queue_message (void *cls,
6333 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
6335 struct TransportClient *tc = cls;
6337 if (CT_COMMUNICATOR != tc->type)
6340 GNUNET_SERVICE_client_drop (tc->client);
6343 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6344 queue = queue->next_client)
6346 struct Neighbour *neighbour = queue->neighbour;
6348 if ((dqm->qid != queue->qid) ||
6349 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
6352 GNUNET_SERVICE_client_continue (tc->client);
6356 GNUNET_SERVICE_client_drop (tc->client);
6361 * Message was transmitted. Process the request.
6363 * @param cls the client
6364 * @param sma the send message that was sent
6367 handle_send_message_ack (void *cls,
6368 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
6370 struct TransportClient *tc = cls;
6371 struct QueueEntry *qe;
6372 struct PendingMessage *pm;
6374 if (CT_COMMUNICATOR != tc->type)
6377 GNUNET_SERVICE_client_drop (tc->client);
6381 /* find our queue entry matching the ACK */
6383 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
6384 queue = queue->next_client)
6386 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
6388 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
6391 if (qep->mid != sma->mid)
6400 /* this should never happen */
6402 GNUNET_SERVICE_client_drop (tc->client);
6405 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
6406 qe->queue->queue_tail,
6408 qe->queue->queue_length--;
6409 tc->details.communicator.total_queue_length--;
6410 GNUNET_SERVICE_client_continue (tc->client);
6412 /* if applicable, resume transmissions that waited on ACK */
6413 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
6414 tc->details.communicator.total_queue_length)
6416 /* Communicator dropped below threshold, resume all queues
6417 incident with this client! */
6418 GNUNET_STATISTICS_update (
6420 "# Transmission throttled due to communicator queue limit",
6423 for (struct Queue *queue = tc->details.communicator.queue_head;
6425 queue = queue->next_client)
6426 schedule_transmit_on_queue (queue, GNUNET_NO);
6428 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
6430 /* queue dropped below threshold; only resume this one queue */
6431 GNUNET_STATISTICS_update (GST_stats,
6432 "# Transmission throttled due to queue queue limit",
6435 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
6438 if (NULL != (pm = qe->pm))
6440 struct Neighbour *n;
6442 GNUNET_assert (qe == pm->qe);
6444 /* If waiting for this communicator may have blocked transmission
6445 of pm on other queues for this neighbour, force schedule
6446 transmit on queue for queues of the neighbour */
6448 if (n->pending_msg_head == pm)
6450 for (struct Queue *queue = n->queue_head; NULL != queue;
6451 queue = queue->next_neighbour)
6452 schedule_transmit_on_queue (queue, GNUNET_NO);
6454 if (GNUNET_OK != ntohl (sma->status))
6457 GNUNET_ERROR_TYPE_INFO,
6458 "Queue failed in transmission, will try retransmission immediately\n");
6459 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
6467 * Iterator telling new MONITOR client about all existing
6470 * @param cls the new `struct TransportClient`
6471 * @param pid a connected peer
6472 * @param value the `struct Neighbour` with more information
6473 * @return #GNUNET_OK (continue to iterate)
6476 notify_client_queues (void *cls,
6477 const struct GNUNET_PeerIdentity *pid,
6480 struct TransportClient *tc = cls;
6481 struct Neighbour *neighbour = value;
6483 GNUNET_assert (CT_MONITOR == tc->type);
6484 for (struct Queue *q = neighbour->queue_head; NULL != q;
6485 q = q->next_neighbour)
6487 struct MonitorEvent me = {.rtt = q->rtt,
6489 .num_msg_pending = q->num_msg_pending,
6490 .num_bytes_pending = q->num_bytes_pending};
6492 notify_monitor (tc, pid, q->address, q->nt, &me);
6499 * Initialize a monitor client.
6501 * @param cls the client
6502 * @param start the start message that was sent
6505 handle_monitor_start (void *cls,
6506 const struct GNUNET_TRANSPORT_MonitorStart *start)
6508 struct TransportClient *tc = cls;
6510 if (CT_NONE != tc->type)
6513 GNUNET_SERVICE_client_drop (tc->client);
6516 tc->type = CT_MONITOR;
6517 tc->details.monitor.peer = start->peer;
6518 tc->details.monitor.one_shot = ntohl (start->one_shot);
6519 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
6520 GNUNET_SERVICE_client_mark_monitor (tc->client);
6521 GNUNET_SERVICE_client_continue (tc->client);
6526 * Find transport client providing communication service
6527 * for the protocol @a prefix.
6529 * @param prefix communicator name
6530 * @return NULL if no such transport client is available
6532 static struct TransportClient *
6533 lookup_communicator (const char *prefix)
6535 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6537 if (CT_COMMUNICATOR != tc->type)
6539 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
6543 GNUNET_ERROR_TYPE_WARNING,
6544 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
6551 * Signature of a function called with a communicator @a address of a peer
6552 * @a pid that an application wants us to connect to.
6554 * @param pid target peer
6555 * @param address the address to try
6558 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
6560 static uint32_t idgen;
6561 struct TransportClient *tc;
6563 struct GNUNET_TRANSPORT_CreateQueue *cqm;
6564 struct GNUNET_MQ_Envelope *env;
6567 prefix = GNUNET_HELLO_address_to_prefix (address);
6570 GNUNET_break (0); /* We got an invalid address!? */
6573 tc = lookup_communicator (prefix);
6576 GNUNET_STATISTICS_update (GST_stats,
6577 "# Suggestions ignored due to missing communicator",
6582 /* forward suggestion for queue creation to communicator */
6583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6584 "Request #%u for `%s' communicator to create queue to `%s'\n",
6585 (unsigned int) idgen,
6588 alen = strlen (address) + 1;
6590 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
6591 cqm->request_id = htonl (idgen++);
6592 cqm->receiver = *pid;
6593 memcpy (&cqm[1], address, alen);
6594 GNUNET_MQ_send (tc->mq, env);
6599 * The queue @a q (which matches the peer and address in @a vs) is
6600 * ready for queueing. We should now queue the validation request.
6602 * @param q queue to send on
6603 * @param vs state to derive validation challenge from
6606 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
6608 struct TransportValidationChallenge tvc;
6610 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
6612 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
6613 tvc.header.size = htons (sizeof (tvc));
6614 tvc.reserved = htonl (0);
6615 tvc.challenge = vs->challenge;
6616 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
6617 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
6622 * Task run periodically to validate some address based on #validation_heap.
6627 validation_start_cb (void *cls)
6629 struct ValidationState *vs;
6633 validation_task = NULL;
6634 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6635 /* drop validations past their expiration */
6638 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
6640 free_validation_state (vs);
6641 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
6644 return; /* woopsie, no more addresses known, should only
6645 happen if we're really a lonely peer */
6646 q = find_queue (&vs->pid, vs->address);
6649 vs->awaiting_queue = GNUNET_YES;
6650 suggest_to_connect (&vs->pid, vs->address);
6653 validation_transmit_on_queue (q, vs);
6654 /* Finally, reschedule next attempt */
6655 vs->challenge_backoff =
6656 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
6657 MAX_VALIDATION_CHALLENGE_FREQ);
6658 update_next_challenge_time (vs,
6659 GNUNET_TIME_relative_to_absolute (
6660 vs->challenge_backoff));
6665 * Closure for #check_connection_quality.
6667 struct QueueQualityContext
6670 * Set to the @e k'th queue encountered.
6675 * Set to the number of quality queues encountered.
6677 unsigned int quality_count;
6680 * Set to the total number of queues encountered.
6682 unsigned int num_queues;
6685 * Decremented for each queue, for selection of the
6686 * k-th queue in @e q.
6693 * Check whether any queue to the given neighbour is
6694 * of a good "quality" and if so, increment the counter.
6695 * Also counts the total number of queues, and returns
6696 * the k-th queue found.
6698 * @param cls a `struct QueueQualityContext *` with counters
6699 * @param pid peer this is about
6700 * @param value a `struct Neighbour`
6701 * @return #GNUNET_OK (continue to iterate)
6704 check_connection_quality (void *cls,
6705 const struct GNUNET_PeerIdentity *pid,
6708 struct QueueQualityContext *ctx = cls;
6709 struct Neighbour *n = value;
6714 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
6719 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
6720 statistics and consider those as well here? */
6721 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
6722 do_inc = GNUNET_YES;
6724 if (GNUNET_YES == do_inc)
6725 ctx->quality_count++;
6731 * Task run when we CONSIDER initiating a DV learn
6732 * process. We first check that sending out a message is
6733 * even possible (queues exist), then that it is desirable
6734 * (if not, reschedule the task for later), and finally
6735 * we may then begin the job. If there are too many
6736 * entries in the #dvlearn_map, we purge the oldest entry
6742 start_dv_learn (void *cls)
6744 struct LearnLaunchEntry *lle;
6745 struct QueueQualityContext qqc;
6746 struct TransportDVLearn dvl;
6749 dvlearn_task = NULL;
6750 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
6751 return; /* lost all connectivity, cannot do learning */
6752 qqc.quality_count = 0;
6754 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6755 &check_connection_quality,
6757 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
6759 struct GNUNET_TIME_Relative delay;
6760 unsigned int factor;
6762 /* scale our retries by how far we are above the threshold */
6763 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6764 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
6765 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
6768 /* remove old entries in #dvlearn_map if it has grown too big */
6769 while (MAX_DV_LEARN_PENDING >=
6770 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6773 GNUNET_assert (GNUNET_YES ==
6774 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6777 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
6780 /* setup data structure for learning */
6781 lle = GNUNET_new (struct LearnLaunchEntry);
6782 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6784 sizeof (lle->challenge));
6785 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
6786 GNUNET_break (GNUNET_YES ==
6787 GNUNET_CONTAINER_multishortmap_put (
6791 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6792 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6793 dvl.header.size = htons (sizeof (dvl));
6794 dvl.num_hops = htons (0);
6795 dvl.bidirectional = htons (0);
6796 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6798 struct DvInitPS dvip = {.purpose.purpose = htonl (
6799 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6800 .purpose.size = htonl (sizeof (dvip)),
6801 .challenge = lle->challenge};
6803 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6807 dvl.initiator = GST_my_identity;
6808 dvl.challenge = lle->challenge;
6810 qqc.quality_count = 0;
6811 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
6814 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6815 &check_connection_quality,
6817 GNUNET_assert (NULL != qqc.q);
6819 /* Do this as close to transmission time as possible! */
6820 lle->launch_time = GNUNET_TIME_absolute_get ();
6822 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
6823 /* reschedule this job, randomizing the time it runs (but no
6825 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
6826 DV_LEARN_BASE_FREQUENCY),
6833 * A new queue has been created, check if any address validation
6834 * requests have been waiting for it.
6836 * @param cls a `struct Queue`
6837 * @param pid peer concerned (unused)
6838 * @param value a `struct ValidationState`
6839 * @return #GNUNET_NO if a match was found and we can stop looking
6842 check_validation_request_pending (void *cls,
6843 const struct GNUNET_PeerIdentity *pid,
6846 struct Queue *q = cls;
6847 struct ValidationState *vs = value;
6850 if ((GNUNET_YES == vs->awaiting_queue) &&
6851 (0 == strcmp (vs->address, q->address)))
6853 vs->awaiting_queue = GNUNET_NO;
6854 validation_transmit_on_queue (q, vs);
6862 * New queue became available. Process the request.
6864 * @param cls the client
6865 * @param aqm the send message that was sent
6868 handle_add_queue_message (void *cls,
6869 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6871 struct TransportClient *tc = cls;
6872 struct Queue *queue;
6873 struct Neighbour *neighbour;
6877 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6879 /* MTU so small as to be useless for transmissions,
6880 required for #fragment_message()! */
6881 GNUNET_break_op (0);
6882 GNUNET_SERVICE_client_drop (tc->client);
6885 neighbour = lookup_neighbour (&aqm->receiver);
6886 if (NULL == neighbour)
6888 neighbour = GNUNET_new (struct Neighbour);
6889 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6890 neighbour->pid = aqm->receiver;
6891 GNUNET_assert (GNUNET_OK ==
6892 GNUNET_CONTAINER_multipeermap_put (
6896 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6898 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6899 addr = (const char *) &aqm[1];
6901 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6903 queue->address = (const char *) &queue[1];
6904 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6905 queue->qid = aqm->qid;
6906 queue->mtu = ntohl (aqm->mtu);
6907 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6908 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6909 queue->neighbour = neighbour;
6910 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6911 &tracker_update_in_cb,
6913 GNUNET_BANDWIDTH_ZERO,
6914 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6915 &tracker_excess_in_cb,
6917 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6918 &tracker_update_out_cb,
6920 GNUNET_BANDWIDTH_ZERO,
6921 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6922 &tracker_excess_out_cb,
6924 memcpy (&queue[1], addr, addr_len);
6925 /* notify monitors about new queue */
6927 struct MonitorEvent me = {.rtt = queue->rtt, .cs = queue->cs};
6929 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
6931 GNUNET_CONTAINER_MDLL_insert (neighbour,
6932 neighbour->queue_head,
6933 neighbour->queue_tail,
6935 GNUNET_CONTAINER_MDLL_insert (client,
6936 tc->details.communicator.queue_head,
6937 tc->details.communicator.queue_tail,
6939 /* check if valdiations are waiting for the queue */
6941 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6943 &check_validation_request_pending,
6945 /* might be our first queue, try launching DV learning */
6946 if (NULL == dvlearn_task)
6947 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
6948 GNUNET_SERVICE_client_continue (tc->client);
6953 * Communicator tells us that our request to create a queue "worked", that
6954 * is setting up the queue is now in process.
6956 * @param cls the `struct TransportClient`
6957 * @param cqr confirmation message
6960 handle_queue_create_ok (void *cls,
6961 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6963 struct TransportClient *tc = cls;
6965 if (CT_COMMUNICATOR != tc->type)
6968 GNUNET_SERVICE_client_drop (tc->client);
6971 GNUNET_STATISTICS_update (GST_stats,
6972 "# Suggestions succeeded at communicator",
6975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6976 "Request #%u for communicator to create queue succeeded\n",
6977 (unsigned int) ntohs (cqr->request_id));
6978 GNUNET_SERVICE_client_continue (tc->client);
6983 * Communicator tells us that our request to create a queue failed. This usually
6984 * indicates that the provided address is simply invalid or that the
6985 * communicator's resources are exhausted.
6987 * @param cls the `struct TransportClient`
6988 * @param cqr failure message
6991 handle_queue_create_fail (
6993 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6995 struct TransportClient *tc = cls;
6997 if (CT_COMMUNICATOR != tc->type)
7000 GNUNET_SERVICE_client_drop (tc->client);
7003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7004 "Request #%u for communicator to create queue failed\n",
7005 (unsigned int) ntohs (cqr->request_id));
7006 GNUNET_STATISTICS_update (GST_stats,
7007 "# Suggestions failed in queue creation at communicator",
7010 GNUNET_SERVICE_client_continue (tc->client);
7015 * We have received a `struct ExpressPreferenceMessage` from an application
7018 * @param cls handle to the client
7019 * @param msg the start message
7022 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
7024 struct TransportClient *tc = cls;
7025 struct PeerRequest *pr;
7027 if (CT_APPLICATION != tc->type)
7030 GNUNET_SERVICE_client_drop (tc->client);
7033 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
7038 GNUNET_SERVICE_client_drop (tc->client);
7041 (void) stop_peer_request (tc, &pr->pid, pr);
7042 GNUNET_SERVICE_client_continue (tc->client);
7047 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
7048 * messages. We do nothing here, real verification is done later.
7050 * @param cls a `struct TransportClient *`
7051 * @param msg message to verify
7052 * @return #GNUNET_OK
7055 check_address_consider_verify (
7057 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7066 * Closure for #check_known_address.
7068 struct CheckKnownAddressContext
7071 * Set to the address we are looking for.
7073 const char *address;
7076 * Set to a matching validation state, if one was found.
7078 struct ValidationState *vs;
7083 * Test if the validation state in @a value matches the
7084 * address from @a cls.
7086 * @param cls a `struct CheckKnownAddressContext`
7087 * @param pid unused (must match though)
7088 * @param value a `struct ValidationState`
7089 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7092 check_known_address (void *cls,
7093 const struct GNUNET_PeerIdentity *pid,
7096 struct CheckKnownAddressContext *ckac = cls;
7097 struct ValidationState *vs = value;
7100 if (0 != strcmp (vs->address, ckac->address))
7108 * Start address validation.
7110 * @param pid peer the @a address is for
7111 * @param address an address to reach @a pid (presumably)
7112 * @param expiration when did @a pid claim @a address will become invalid
7115 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7116 const char *address,
7117 struct GNUNET_TIME_Absolute expiration)
7119 struct GNUNET_TIME_Absolute now;
7120 struct ValidationState *vs;
7121 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7123 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
7124 return; /* expired */
7125 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7127 &check_known_address,
7129 if (NULL != (vs = ckac.vs))
7131 /* if 'vs' is not currently valid, we need to speed up retrying the
7133 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7135 /* reduce backoff as we got a fresh advertisement */
7136 vs->challenge_backoff =
7137 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7138 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7140 update_next_challenge_time (vs,
7141 GNUNET_TIME_relative_to_absolute (
7142 vs->challenge_backoff));
7146 now = GNUNET_TIME_absolute_get ();
7147 vs = GNUNET_new (struct ValidationState);
7149 vs->valid_until = expiration;
7150 vs->first_challenge_use = now;
7151 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7152 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7154 sizeof (vs->challenge));
7155 vs->address = GNUNET_strdup (address);
7156 GNUNET_assert (GNUNET_YES ==
7157 GNUNET_CONTAINER_multipeermap_put (
7161 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7162 update_next_challenge_time (vs, now);
7167 * Function called by PEERSTORE for each matching record.
7169 * @param cls closure
7170 * @param record peerstore record information
7171 * @param emsg error message, or NULL if no errors
7174 handle_hello (void *cls,
7175 const struct GNUNET_PEERSTORE_Record *record,
7178 struct PeerRequest *pr = cls;
7183 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7184 "Got failure from PEERSTORE: %s\n",
7188 val = record->value;
7189 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7194 start_address_validation (&pr->pid,
7195 (const char *) record->value,
7201 * We have received a `struct ExpressPreferenceMessage` from an application
7204 * @param cls handle to the client
7205 * @param msg the start message
7208 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
7210 struct TransportClient *tc = cls;
7211 struct PeerRequest *pr;
7213 if (CT_NONE == tc->type)
7215 tc->type = CT_APPLICATION;
7216 tc->details.application.requests =
7217 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
7219 if (CT_APPLICATION != tc->type)
7222 GNUNET_SERVICE_client_drop (tc->client);
7225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7226 "Client suggested we talk to %s with preference %d at rate %u\n",
7227 GNUNET_i2s (&msg->peer),
7228 (int) ntohl (msg->pk),
7229 (int) ntohl (msg->bw.value__));
7230 pr = GNUNET_new (struct PeerRequest);
7232 pr->pid = msg->peer;
7234 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
7235 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
7236 tc->details.application.requests,
7239 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
7243 GNUNET_SERVICE_client_drop (tc->client);
7246 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
7249 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7252 GNUNET_SERVICE_client_continue (tc->client);
7257 * Given another peers address, consider checking it for validity
7258 * and then adding it to the Peerstore.
7260 * @param cls a `struct TransportClient`
7261 * @param hdr message containing the raw address data and
7262 * signature in the body, see #GNUNET_HELLO_extract_address()
7265 handle_address_consider_verify (
7267 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
7269 struct TransportClient *tc = cls;
7271 enum GNUNET_NetworkType nt;
7272 struct GNUNET_TIME_Absolute expiration;
7275 // OPTIMIZE-FIXME: checking that we know this address already should
7276 // be done BEFORE checking the signature => HELLO API change!
7277 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification / validation?!
7279 GNUNET_HELLO_extract_address (&hdr[1],
7280 ntohs (hdr->header.size) - sizeof (*hdr),
7284 if (NULL == address)
7286 GNUNET_break_op (0);
7289 start_address_validation (&hdr->peer, address, expiration);
7290 GNUNET_free (address);
7291 GNUNET_SERVICE_client_continue (tc->client);
7296 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
7299 * @param cls a `struct TransportClient *`
7300 * @param m message to verify
7301 * @return #GNUNET_OK on success
7304 check_request_hello_validation (void *cls,
7305 const struct RequestHelloValidationMessage *m)
7308 GNUNET_MQ_check_zero_termination (m);
7314 * A client encountered an address of another peer. Consider validating it,
7315 * and if validation succeeds, persist it to PEERSTORE.
7317 * @param cls a `struct TransportClient *`
7318 * @param m message to verify
7321 handle_request_hello_validation (void *cls,
7322 const struct RequestHelloValidationMessage *m)
7324 struct TransportClient *tc = cls;
7326 start_address_validation (&m->peer,
7327 (const char *) &m[1],
7328 GNUNET_TIME_absolute_ntoh (m->expiration));
7329 GNUNET_SERVICE_client_continue (tc->client);
7334 * Free neighbour entry.
7338 * @param value a `struct Neighbour`
7339 * @return #GNUNET_OK (always)
7342 free_neighbour_cb (void *cls,
7343 const struct GNUNET_PeerIdentity *pid,
7346 struct Neighbour *neighbour = value;
7350 GNUNET_break (0); // should this ever happen?
7351 free_neighbour (neighbour);
7358 * Free DV route entry.
7362 * @param value a `struct DistanceVector`
7363 * @return #GNUNET_OK (always)
7366 free_dv_routes_cb (void *cls,
7367 const struct GNUNET_PeerIdentity *pid,
7370 struct DistanceVector *dv = value;
7381 * Free ephemeral entry.
7385 * @param value a `struct EphemeralCacheEntry`
7386 * @return #GNUNET_OK (always)
7389 free_ephemeral_cb (void *cls,
7390 const struct GNUNET_PeerIdentity *pid,
7393 struct EphemeralCacheEntry *ece = value;
7397 free_ephemeral (ece);
7403 * Free validation state.
7407 * @param value a `struct ValidationState`
7408 * @return #GNUNET_OK (always)
7411 free_validation_state_cb (void *cls,
7412 const struct GNUNET_PeerIdentity *pid,
7415 struct ValidationState *vs = value;
7419 free_validation_state (vs);
7425 * Function called when the service shuts down. Unloads our plugins
7426 * and cancels pending validations.
7428 * @param cls closure, unused
7431 do_shutdown (void *cls)
7433 struct LearnLaunchEntry *lle;
7436 if (NULL != ephemeral_task)
7438 GNUNET_SCHEDULER_cancel (ephemeral_task);
7439 ephemeral_task = NULL;
7441 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
7442 if (NULL != peerstore)
7444 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
7447 if (NULL != GST_stats)
7449 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
7452 if (NULL != GST_my_private_key)
7454 GNUNET_free (GST_my_private_key);
7455 GST_my_private_key = NULL;
7457 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
7459 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
7460 &free_validation_state_cb,
7462 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
7463 validation_map = NULL;
7464 while (NULL != (lle = lle_head))
7466 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
7469 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
7471 GNUNET_CONTAINER_heap_destroy (validation_heap);
7472 validation_heap = NULL;
7473 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
7474 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
7476 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
7479 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
7480 ephemeral_map = NULL;
7481 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
7482 ephemeral_heap = NULL;
7487 * Initiate transport service.
7489 * @param cls closure
7490 * @param c configuration to use
7491 * @param service the initialized service
7495 const struct GNUNET_CONFIGURATION_Handle *c,
7496 struct GNUNET_SERVICE_Handle *service)
7502 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7503 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7504 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
7506 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7507 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
7509 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
7511 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
7512 GST_my_private_key =
7513 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
7514 if (NULL == GST_my_private_key)
7517 GNUNET_ERROR_TYPE_ERROR,
7519 "Transport service is lacking key configuration settings. Exiting.\n"));
7520 GNUNET_SCHEDULER_shutdown ();
7523 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
7524 &GST_my_identity.public_key);
7525 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7526 "My identity is `%s'\n",
7527 GNUNET_i2s_full (&GST_my_identity));
7528 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
7529 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
7530 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
7531 if (NULL == peerstore)
7534 GNUNET_SCHEDULER_shutdown ();
7541 * Define "main" method using service macro.
7543 GNUNET_SERVICE_MAIN (
7545 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
7548 &client_disconnect_cb,
7550 /* communication with applications */
7551 GNUNET_MQ_hd_fixed_size (suggest,
7552 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
7553 struct ExpressPreferenceMessage,
7555 GNUNET_MQ_hd_fixed_size (suggest_cancel,
7556 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
7557 struct ExpressPreferenceMessage,
7559 GNUNET_MQ_hd_var_size (request_hello_validation,
7560 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
7561 struct RequestHelloValidationMessage,
7563 /* communication with core */
7564 GNUNET_MQ_hd_fixed_size (client_start,
7565 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
7566 struct StartMessage,
7568 GNUNET_MQ_hd_var_size (client_send,
7569 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
7570 struct OutboundMessage,
7572 /* communication with communicators */
7573 GNUNET_MQ_hd_var_size (communicator_available,
7574 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
7575 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
7577 GNUNET_MQ_hd_var_size (communicator_backchannel,
7578 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
7579 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
7581 GNUNET_MQ_hd_var_size (add_address,
7582 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
7583 struct GNUNET_TRANSPORT_AddAddressMessage,
7585 GNUNET_MQ_hd_fixed_size (del_address,
7586 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
7587 struct GNUNET_TRANSPORT_DelAddressMessage,
7589 GNUNET_MQ_hd_var_size (incoming_msg,
7590 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
7591 struct GNUNET_TRANSPORT_IncomingMessage,
7593 GNUNET_MQ_hd_fixed_size (queue_create_ok,
7594 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
7595 struct GNUNET_TRANSPORT_CreateQueueResponse,
7597 GNUNET_MQ_hd_fixed_size (queue_create_fail,
7598 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
7599 struct GNUNET_TRANSPORT_CreateQueueResponse,
7601 GNUNET_MQ_hd_var_size (add_queue_message,
7602 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
7603 struct GNUNET_TRANSPORT_AddQueueMessage,
7605 GNUNET_MQ_hd_var_size (address_consider_verify,
7606 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
7607 struct GNUNET_TRANSPORT_AddressToVerify,
7609 GNUNET_MQ_hd_fixed_size (del_queue_message,
7610 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
7611 struct GNUNET_TRANSPORT_DelQueueMessage,
7613 GNUNET_MQ_hd_fixed_size (send_message_ack,
7614 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
7615 struct GNUNET_TRANSPORT_SendMessageToAck,
7617 /* communication with monitors */
7618 GNUNET_MQ_hd_fixed_size (monitor_start,
7619 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
7620 struct GNUNET_TRANSPORT_MonitorStart,
7622 GNUNET_MQ_handler_end ());
7625 /* end of file gnunet-service-transport.c */