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 * - FIXME-FC: realize transport-to-transport flow control (needed in case
28 * communicators do not offer flow control).
29 * We do transmit FC window sizes now. Left:
31 * - Throttle sending if "outbound_fc_window_size_used" reaches limit
32 * - Send *new* challenge when we get close to the limit (including
33 * at the beginning when the limit is zero!)
34 * - Retransmit challenge if it goes unanswered!
37 * - send challenges via DV (when DVH is confirmed *and* we care about
38 * the target to get window size, or when DVH is unconfirmed (passive
39 * learning!) to confirm it!)
40 * - handle challenge responses in this case (note: validity period of addresses
42 * - if available, try to use DV paths when trying to establish
43 * virtual link for a `struct IncomingRequest`. (i.e. if DVH is
44 * unconfirmed, incoming requests also trigger challenge-via-DV!)
46 * - review retransmission logic, right now there is no smartness there!
47 * => congestion control, etc [PERFORMANCE-BASICS]
50 * - When forwarding DV learn messages, if a peer is reached that
51 * has a *bidirectional* link to the origin beyond 1st hop,
52 * do NOT forward it to peers _other_ than the origin, as
53 * there is clearly a better path directly from the origin to
54 * whatever else we could reach.
55 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
56 * => Need 128 bit hash map though! [BANDWIDTH, MEMORY]
57 * - queue_send_msg by API design has to make a copy
58 * of the payload, and route_message on top of that requires a malloc/free.
59 * Change design to approximate "zero" copy better... [CPU]
60 * - could avoid copying body of message into each fragment and keep
61 * fragments as just pointers into the original message and only
62 * fully build fragments just before transmission (optimization, should
63 * reduce CPU and memory use) [CPU, MEMORY]
64 * - if messages are below MTU, consider adding ACKs and other stuff
65 * to the same transmission to avoid tiny messages (requires planning at
66 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
67 * - When we passively learned DV (with unconfirmed freshness), we
68 * right now add the path to our list but with a zero path_valid_until
69 * time and only use it for unconfirmed routes. However, we could consider
70 * triggering an explicit validation mechansim ourselves, specifically routing
71 * a challenge-response message over the path [ROUTING]
72 * - Track ACK losses based on ACK-counter [ROUTING]
73 * - Fragments send over a reliable channel could do without the
74 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
75 * (-> have 2nd type of acknowledgment message; low priority, as we
76 * do not have an MTU-limited *reliable* communicator)
77 * - Adapt available_fc_window_size, using larger values for high-bandwidth
78 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
79 * - Set last_window_consum_limit promise properly based on
80 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
81 * - re-sending challenge response without a challenge when we have
82 * significantly increased the FC window (upon CORE being done with messages)
83 * so as to avoid the sender having to give us a fresh challenge [BANDWIDTH]
84 * Also can re-use signature in this case [CPU]. Marked with "TODO-M1"
86 * Design realizations / discussion:
87 * - communicators do flow control by calling MQ "notify sent"
88 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
89 * or explicitly via backchannel FC ACKs. As long as the
90 * channel is not full, they may 'notify sent' even if the other
91 * peer has not yet confirmed receipt. The other peer confirming
92 * is _only_ for FC, not for more reliable transmission; reliable
93 * transmission (i.e. of fragments) is left to _transport_.
94 * - ACKs sent back in uni-directional communicators are done via
95 * the background channel API; here transport _may_ initially
96 * broadcast (with bounded # hops) if no path is known;
97 * - transport should _integrate_ DV-routing and build a view of
98 * the network; then background channel traffic can be
99 * routed via DV as well as explicit "DV" traffic.
100 * - background channel is also used for ACKs and NAT traversal support
101 * - transport service is responsible for AEAD'ing the background
102 * channel, timestamps and monotonic time are used against replay
103 * of old messages -> peerstore needs to be supplied with
104 * "latest timestamps seen" data
105 * - if transport implements DV, we likely need a 3rd peermap
106 * in addition to ephemerals and (direct) neighbours
107 * ==> check if stuff needs to be moved out of "Neighbour"
108 * - transport should encapsualte core-level messages and do its
109 * own ACKing for RTT/goodput/loss measurements _and_ fragment
112 #include "platform.h"
113 #include "gnunet_util_lib.h"
114 #include "gnunet_statistics_service.h"
115 #include "gnunet_transport_monitor_service.h"
116 #include "gnunet_peerstore_service.h"
117 #include "gnunet_hello_lib.h"
118 #include "gnunet_signatures.h"
119 #include "transport.h"
122 * Maximum number of messages we acknowledge together in one
123 * cummulative ACK. Larger values may save a bit of bandwidth.
125 #define MAX_CUMMULATIVE_ACKS 64
128 * What is the size we assume for a read operation in the
129 * absence of an MTU for the purpose of flow control?
131 #define IN_PACKET_SIZE_WITHOUT_MTU 128
134 * Number of slots we keep of historic data for computation of
135 * goodput / message loss ratio.
137 #define GOODPUT_AGING_SLOTS 4
140 * How big is the flow control window size by default;
141 * limits per-neighbour RAM utilization.
143 #define DEFAULT_WINDOW_SIZE (128 * 1024)
146 * For how many incoming connections do we try to create a
147 * virtual link for (at the same time!). This does NOT
148 * limit the number of incoming connections, just the number
149 * for which we are actively trying to find working addresses
150 * in the absence (!) of our own applications wanting the
153 #define MAX_INCOMING_REQUEST 16
156 * Maximum number of peers we select for forwarding DVInit
157 * messages at the same time (excluding initiator).
159 #define MAX_DV_DISCOVERY_SELECTION 16
162 * Window size. How many messages to the same target do we pass
163 * to CORE without a RECV_OK in between? Small values limit
164 * thoughput, large values will increase latency.
166 * FIXME-OPTIMIZE: find out what good values are experimentally,
167 * maybe set adaptively (i.e. to observed available bandwidth).
169 #define RECV_WINDOW_SIZE 4
172 * Minimum number of hops we should forward DV learn messages
173 * even if they are NOT useful for us in hope of looping
174 * back to the initiator?
176 * FIXME: allow initiator some control here instead?
178 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
181 * Maximum DV distance allowed ever.
183 #define MAX_DV_HOPS_ALLOWED 16
186 * Maximum number of DV learning activities we may
187 * have pending at the same time.
189 #define MAX_DV_LEARN_PENDING 64
192 * Maximum number of DV paths we keep simultaneously to the same target.
194 #define MAX_DV_PATHS_TO_TARGET 3
197 * If a queue delays the next message by more than this number
198 * of seconds we log a warning. Note: this is for testing,
199 * the value chosen here might be too aggressively low!
201 #define DELAY_WARN_THRESHOLD \
202 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
205 * If a DVBox could not be forwarded after this number of
206 * seconds we drop it.
208 #define DV_FORWARD_TIMEOUT \
209 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
212 * We only consider queues as "quality" connections when
213 * suppressing the generation of DV initiation messages if
214 * the latency of the queue is below this threshold.
216 #define DV_QUALITY_RTT_THRESHOLD \
217 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
220 * How long do we consider a DV path valid if we see no
221 * further updates on it? Note: the value chosen here might be too low!
223 #define DV_PATH_VALIDITY_TIMEOUT \
224 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
227 * How long do we cache backchannel (struct Backtalker) information
228 * after a backchannel goes inactive?
230 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
231 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
234 * How long before paths expire would we like to (re)discover DV paths? Should
235 * be below #DV_PATH_VALIDITY_TIMEOUT.
237 #define DV_PATH_DISCOVERY_FREQUENCY \
238 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
241 * How long are ephemeral keys valid?
243 #define EPHEMERAL_VALIDITY \
244 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
247 * How long do we keep partially reassembled messages around before giving up?
249 #define REASSEMBLY_EXPIRATION \
250 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
253 * What is the fastest rate at which we send challenges *if* we keep learning
254 * an address (gossip, DHT, etc.)?
256 #define FAST_VALIDATION_CHALLENGE_FREQ \
257 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
260 * What is the slowest rate at which we send challenges?
262 #define MAX_VALIDATION_CHALLENGE_FREQ \
263 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
266 * How long until we forget about historic accumulators and thus
267 * reset the ACK counter? Should exceed the maximum time an
268 * active connection experiences without an ACK.
270 #define ACK_CUMMULATOR_TIMEOUT \
271 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
274 * What is the non-randomized base frequency at which we
275 * would initiate DV learn messages?
277 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
280 * How many good connections (confirmed, bi-directional, not DV)
281 * do we need to have to suppress initiating DV learn messages?
283 #define DV_LEARN_QUALITY_THRESHOLD 100
286 * When do we forget an invalid address for sure?
288 #define MAX_ADDRESS_VALID_UNTIL \
289 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
292 * How long do we consider an address valid if we just checked?
294 #define ADDRESS_VALIDATION_LIFETIME \
295 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
298 * What is the maximum frequency at which we do address validation?
299 * A random value between 0 and this value is added when scheduling
300 * the #validation_task (both to ensure we do not validate too often,
301 * and to randomize a bit).
303 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
306 * How many network RTTs before an address validation expires should we begin
307 * trying to revalidate? (Note that the RTT used here is the one that we
308 * experienced during the last validation, not necessarily the latest RTT
311 #define VALIDATION_RTT_BUFFER_FACTOR 3
314 * How many messages can we have pending for a given communicator
315 * process before we start to throttle that communicator?
317 * Used if a communicator might be CPU-bound and cannot handle the traffic.
319 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
322 * How many messages can we have pending for a given queue (queue to
323 * a particular peer via a communicator) process before we start to
324 * throttle that queue?
326 #define QUEUE_LENGTH_LIMIT 32
329 GNUNET_NETWORK_STRUCT_BEGIN
332 * Unique identifier we attach to a message.
337 * Unique value, generated by incrementing the
338 * `message_uuid_ctr` of `struct Neighbour`.
340 uint64_t uuid GNUNET_PACKED;
345 * Unique identifier to map an acknowledgement to a transmission.
347 struct AcknowledgementUUIDP
350 * The UUID value. Not actually a hash, but a random value.
352 struct GNUNET_ShortHashCode value;
357 * Type of a nonce used for challenges.
359 struct ChallengeNonceP
362 * The value of the nonce. Note that this is NOT a hash.
364 struct GNUNET_ShortHashCode value;
369 * Outer layer of an encapsulated backchannel message.
371 struct TransportBackchannelEncapsulationMessage
374 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
376 struct GNUNET_MessageHeader header;
378 /* Followed by *another* message header which is the message to
381 /* Followed by a 0-terminated name of the communicator */
386 * Body by which a peer confirms that it is using an ephemeral key.
388 struct EphemeralConfirmationPS
392 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
394 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
397 * How long is this signature over the ephemeral key valid?
399 * Note that the receiver MUST IGNORE the absolute time, and only interpret
400 * the value as a mononic time and reject "older" values than the last one
401 * observed. This is necessary as we do not want to require synchronized
402 * clocks and may not have a bidirectional communication channel.
404 * Even with this, there is no real guarantee against replay achieved here,
405 * unless the latest timestamp is persisted. While persistence should be
406 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
407 * communicators must protect against replay attacks when using backchannel
410 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
413 * Target's peer identity.
415 struct GNUNET_PeerIdentity target;
418 * Ephemeral key setup by the sender for @e target, used
419 * to encrypt the payload.
421 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
426 * Plaintext of the variable-size payload that is encrypted
427 * within a `struct TransportBackchannelEncapsulationMessage`
429 struct TransportDVBoxPayloadP
433 * Sender's peer identity.
435 struct GNUNET_PeerIdentity sender;
438 * Signature of the sender over an
439 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
441 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
444 * Current monotonic time of the sending transport service. Used to
445 * detect replayed messages. Note that the receiver should remember
446 * a list of the recently seen timestamps and only reject messages
447 * if the timestamp is in the list, or the list is "full" and the
448 * timestamp is smaller than the lowest in the list.
450 * Like the @e ephemeral_validity, the list of timestamps per peer should be
451 * persisted to guard against replays after restarts.
453 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
455 /* Followed by a `struct GNUNET_MessageHeader` with a message
456 for the target peer */
461 * Outer layer of an encapsulated unfragmented application message sent
462 * over an unreliable channel.
464 struct TransportReliabilityBoxMessage
467 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
469 struct GNUNET_MessageHeader header;
472 * Number of messages still to be sent before a commulative
473 * ACK is requested. Zero if an ACK is requested immediately.
474 * In NBO. Note that the receiver may send the ACK faster
475 * if it believes that is reasonable.
477 uint32_t ack_countdown GNUNET_PACKED;
480 * Unique ID of the message used for signalling receipt of
481 * messages sent over possibly unreliable channels. Should
484 struct AcknowledgementUUIDP ack_uuid;
489 * Acknowledgement payload.
491 struct TransportCummulativeAckPayloadP
494 * How long was the ACK delayed for generating cummulative ACKs?
495 * Used to calculate the correct network RTT by taking the receipt
496 * time of the ack minus the transmission time of the sender minus
499 struct GNUNET_TIME_RelativeNBO ack_delay;
502 * UUID of a message being acknowledged.
504 struct AcknowledgementUUIDP ack_uuid;
509 * Confirmation that the receiver got a
510 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
511 * confirmation may be transmitted over a completely different queue,
512 * so ACKs are identified by a combination of PID of sender and
513 * message UUID, without the queue playing any role!
515 struct TransportReliabilityAckMessage
518 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
520 struct GNUNET_MessageHeader header;
523 * Counter of ACKs transmitted by the sender to us. Incremented
524 * by one for each ACK, used to detect how many ACKs were lost.
526 uint32_t ack_counter GNUNET_PACKED;
528 /* followed by any number of `struct TransportCummulativeAckPayloadP`
529 messages providing ACKs */
534 * Outer layer of an encapsulated fragmented application message.
536 struct TransportFragmentBoxMessage
539 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
541 struct GNUNET_MessageHeader header;
544 * Offset of this fragment in the overall message.
546 uint16_t frag_off GNUNET_PACKED;
549 * Total size of the message that is being fragmented.
551 uint16_t msg_size GNUNET_PACKED;
554 * Unique ID of this fragment (and fragment transmission!). Will
555 * change even if a fragement is retransmitted to make each
556 * transmission attempt unique! If a client receives a duplicate
557 * fragment (same @e frag_off for same @a msg_uuid, it must send
558 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
560 struct AcknowledgementUUIDP ack_uuid;
563 * Original message ID for of the message that all the fragments
564 * belong to. Must be the same for all fragments.
566 struct MessageUUIDP msg_uuid;
571 * Content signed by the initator during DV learning.
573 * The signature is required to prevent DDoS attacks. A peer sending out this
574 * message is potentially generating a lot of traffic that will go back to the
575 * initator, as peers receiving this message will try to let the initiator
576 * know that they got the message.
578 * Without this signature, an attacker could abuse this mechanism for traffic
579 * amplification, sending a lot of traffic to a peer by putting out this type
580 * of message with the victim's peer identity.
582 * Even with just a signature, traffic amplification would be possible via
583 * replay attacks. The @e monotonic_time limits such replay attacks, as every
584 * potential amplificator will check the @e monotonic_time and only respond
585 * (at most) once per message.
590 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
592 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
595 * Time at the initiator when generating the signature.
597 * Note that the receiver MUST IGNORE the absolute time, and only interpret
598 * the value as a mononic time and reject "older" values than the last one
599 * observed. This is necessary as we do not want to require synchronized
600 * clocks and may not have a bidirectional communication channel.
602 * Even with this, there is no real guarantee against replay achieved here,
603 * unless the latest timestamp is persisted. Persistence should be
604 * provided via PEERSTORE if possible.
606 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
609 * Challenge value used by the initiator to re-identify the path.
611 struct ChallengeNonceP challenge;
616 * Content signed by each peer during DV learning.
618 * This assues the initiator of the DV learning operation that the hop from @e
619 * pred via the signing peer to @e succ actually exists. This makes it
620 * impossible for an adversary to supply the network with bogus routes.
622 * The @e challenge is included to provide replay protection for the
623 * initiator. This way, the initiator knows that the hop existed after the
624 * original @e challenge was first transmitted, providing a freshness metric.
626 * Peers other than the initiator that passively learn paths by observing
627 * these messages do NOT benefit from this. Here, an adversary may indeed
628 * replay old messages. Thus, passively learned paths should always be
629 * immediately marked as "potentially stale".
634 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
636 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
639 * Identity of the previous peer on the path.
641 struct GNUNET_PeerIdentity pred;
644 * Identity of the next peer on the path.
646 struct GNUNET_PeerIdentity succ;
649 * Challenge value used by the initiator to re-identify the path.
651 struct ChallengeNonceP challenge;
656 * An entry describing a peer on a path in a
657 * `struct TransportDVLearnMessage` message.
662 * Identity of a peer on the path.
664 struct GNUNET_PeerIdentity hop;
667 * Signature of this hop over the path, of purpose
668 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
670 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
675 * Internal message used by transport for distance vector learning.
676 * If @e num_hops does not exceed the threshold, peers should append
677 * themselves to the peer list and flood the message (possibly only
678 * to a subset of their neighbours to limit discoverability of the
679 * network topology). To the extend that the @e bidirectional bits
680 * are set, peers may learn the inverse paths even if they did not
683 * Unless received on a bidirectional queue and @e num_hops just
684 * zero, peers that can forward to the initator should always try to
685 * forward to the initiator.
687 struct TransportDVLearnMessage
690 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
692 struct GNUNET_MessageHeader header;
695 * Number of hops this messages has travelled, in NBO. Zero if
698 uint16_t num_hops GNUNET_PACKED;
701 * Bitmask of the last 16 hops indicating whether they are confirmed
702 * available (without DV) in both directions or not, in NBO. Used
703 * to possibly instantly learn a path in both directions. Each peer
704 * should shift this value by one to the left, and then set the
705 * lowest bit IF the current sender can be reached from it (without
708 uint16_t bidirectional GNUNET_PACKED;
711 * Peers receiving this message and delaying forwarding to other
712 * peers for any reason should increment this value by the non-network
713 * delay created by the peer.
715 struct GNUNET_TIME_RelativeNBO non_network_delay;
718 * Time at the initiator when generating the signature.
720 * Note that the receiver MUST IGNORE the absolute time, and only interpret
721 * the value as a mononic time and reject "older" values than the last one
722 * observed. This is necessary as we do not want to require synchronized
723 * clocks and may not have a bidirectional communication channel.
725 * Even with this, there is no real guarantee against replay achieved here,
726 * unless the latest timestamp is persisted. Persistence should be
727 * provided via PEERSTORE if possible.
729 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
732 * Signature of this hop over the path, of purpose
733 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
735 struct GNUNET_CRYPTO_EddsaSignature init_sig;
738 * Identity of the peer that started this learning activity.
740 struct GNUNET_PeerIdentity initiator;
743 * Challenge value used by the initiator to re-identify the path.
745 struct ChallengeNonceP challenge;
747 /* Followed by @e num_hops `struct DVPathEntryP` values,
748 excluding the initiator of the DV trace; the last entry is the
749 current sender; the current peer must not be included. */
754 * Outer layer of an encapsulated message send over multiple hops.
755 * The path given only includes the identities of the subsequent
756 * peers, i.e. it will be empty if we are the receiver. Each
757 * forwarding peer should scan the list from the end, and if it can,
758 * forward to the respective peer. The list should then be shortened
759 * by all the entries up to and including that peer. Each hop should
760 * also increment @e total_hops to allow the receiver to get a precise
761 * estimate on the number of hops the message travelled. Senders must
762 * provide a learned path that thus should work, but intermediaries
763 * know of a shortcut, they are allowed to send the message via that
766 * If a peer finds itself still on the list, it must drop the message.
768 * The payload of the box can only be decrypted and verified by the
769 * ultimate receiver. Intermediaries do not learn the sender's
770 * identity and the path the message has taken. However, the first
771 * hop does learn the sender as @e total_hops would be zero and thus
772 * the predecessor must be the origin (so this is not really useful
773 * for anonymization).
775 struct TransportDVBoxMessage
778 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
780 struct GNUNET_MessageHeader header;
783 * Number of total hops this messages travelled. In NBO.
784 * @e origin sets this to zero, to be incremented at
785 * each hop. Peers should limit the @e total_hops value
786 * they accept from other peers.
788 uint16_t total_hops GNUNET_PACKED;
791 * Number of hops this messages includes. In NBO. Reduced by one
792 * or more at each hop. Peers should limit the @e num_hops value
793 * they accept from other peers.
795 uint16_t num_hops GNUNET_PACKED;
798 * Ephemeral key setup by the sender for target, used to encrypt the
799 * payload. Intermediaries must not change this value.
801 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
804 * We use an IV here as the @e ephemeral_key is re-used for
805 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
806 * Intermediaries must not change this value.
808 struct GNUNET_ShortHashCode iv;
811 * HMAC over the ciphertext of the encrypted, variable-size body
812 * that follows. Verified via DH of target and @e ephemeral_key.
813 * Intermediaries must not change this value.
815 struct GNUNET_HashCode hmac;
817 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
818 excluding the @e origin and the current peer, the last must be
819 the ultimate target; if @e num_hops is zero, the receiver of this
820 message is the ultimate target. */
822 /* Followed by encrypted, variable-size payload, which
823 must begin with a `struct TransportDVBoxPayloadP` */
825 /* Followed by the actual message, which itself must not be a
826 a DV_LEARN or DV_BOX message! */
831 * Message send to another peer to validate that it can indeed
832 * receive messages at a particular address.
834 struct TransportValidationChallengeMessage
838 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
840 struct GNUNET_MessageHeader header;
845 uint32_t reserved GNUNET_PACKED;
848 * Challenge to be signed by the receiving peer.
850 struct ChallengeNonceP challenge;
853 * Timestamp of the sender, to be copied into the reply to allow
854 * sender to calculate RTT. Must be monotonically increasing!
856 struct GNUNET_TIME_AbsoluteNBO sender_time;
861 * Message signed by a peer to confirm that it can indeed
862 * receive messages at a particular address.
864 struct TransportValidationPS
868 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
870 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
873 * How long does the sender believe the address on
874 * which the challenge was received to remain valid?
876 struct GNUNET_TIME_RelativeNBO validity_duration;
879 * Challenge signed by the receiving peer.
881 struct ChallengeNonceP challenge;
886 * Message send to a peer to respond to a
887 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
889 struct TransportValidationResponseMessage
893 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
895 struct GNUNET_MessageHeader header;
900 uint32_t reserved GNUNET_PACKED;
903 * The peer's signature matching the
904 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
906 struct GNUNET_CRYPTO_EddsaSignature signature;
909 * The challenge that was signed by the receiving peer.
911 struct ChallengeNonceP challenge;
914 * Original timestamp of the sender (was @code{sender_time}),
915 * copied into the reply to allow sender to calculate RTT.
917 struct GNUNET_TIME_AbsoluteNBO origin_time;
920 * How long does the sender believe this address to remain
923 struct GNUNET_TIME_RelativeNBO validity_duration;
928 * Message for Transport-to-Transport Flow control. Specifies the size
929 * of the flow control window, including how much we believe to have
930 * consumed (at transmission time), how much we believe to be allowed
931 * (at transmission time), and how much the other peer is allowed to
932 * send to us, and how much data we already received from the other
935 struct TransportFlowControlMessage
938 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
940 struct GNUNET_MessageHeader header;
943 * Sequence number of the flow control message. Incremented by one
944 * for each message. Starts at zero when a virtual link goes up.
945 * Used to detect one-sided connection drops. On wrap-around, the
946 * flow control counters will be reset as if the connection had
949 uint32_t seq GNUNET_PACKED;
952 * Flow control window size in bytes, in NBO.
953 * The receiver can send this many bytes at most.
955 uint64_t inbound_window_size GNUNET_PACKED;
958 * How many bytes has the sender sent that count for flow control at
959 * this time. Used to allow the receiver to estimate the packet
962 uint64_t outbound_sent GNUNET_PACKED;
965 * Latest flow control window size we learned from the other peer,
966 * in bytes, in NBO. We are limited to sending at most this many
967 * bytes to the other peer. May help the other peer detect when
968 * flow control messages were lost and should thus be retransmitted.
969 * In particular, if the delta to @e outbound_sent is too small,
970 * this signals that we are stalled.
972 uint64_t outbound_window_size GNUNET_PACKED;
975 * Timestamp of the sender. Must be monotonically increasing!
976 * Used to enable receiver to ignore out-of-order packets in
977 * combination with the @e seq. Note that @e seq will go down
978 * (back to zero) whenever either side believes the connection
979 * was dropped, allowing the peers to detect that they need to
980 * reset the counters for the number of bytes sent!
982 struct GNUNET_TIME_AbsoluteNBO sender_time;
986 GNUNET_NETWORK_STRUCT_END
990 * What type of client is the `struct TransportClient` about?
995 * We do not know yet (client is fresh).
1000 * Is the CORE service, we need to forward traffic to it.
1005 * It is a monitor, forward monitor data.
1010 * It is a communicator, use for communication.
1012 CT_COMMUNICATOR = 3,
1015 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
1022 * Which transmission options are allowable for transmission?
1023 * Interpreted bit-wise!
1025 enum RouteMessageOptions
1028 * Only confirmed, non-DV direct neighbours.
1033 * We are allowed to use DV routing for this @a hdr
1038 * We are allowed to use unconfirmed queues or DV routes for this message
1040 RMO_UNCONFIRMED_ALLOWED = 2,
1043 * Reliable and unreliable, DV and non-DV are all acceptable.
1045 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1048 * If we have multiple choices, it is OK to send this message
1049 * over multiple channels at the same time to improve loss tolerance.
1050 * (We do at most 2 transmissions.)
1057 * When did we launch this DV learning activity?
1059 struct LearnLaunchEntry
1063 * Kept (also) in a DLL sorted by launch time.
1065 struct LearnLaunchEntry *prev;
1068 * Kept (also) in a DLL sorted by launch time.
1070 struct LearnLaunchEntry *next;
1073 * Challenge that uniquely identifies this activity.
1075 struct ChallengeNonceP challenge;
1078 * When did we transmit the DV learn message (used to calculate RTT) and
1079 * determine freshness of paths learned via this operation.
1081 struct GNUNET_TIME_Absolute launch_time;
1086 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1087 * (or current) transmission performance.
1089 struct TransmissionHistoryEntry
1092 * Number of bytes actually sent in the interval.
1094 uint64_t bytes_sent;
1097 * Number of bytes received and acknowledged by the other peer in
1100 uint64_t bytes_received;
1105 * Performance data for a transmission possibility.
1107 struct PerformanceData
1110 * Weighted average for the RTT.
1112 struct GNUNET_TIME_Relative aged_rtt;
1115 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1118 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1121 * What was the last age when we wrote to @e the? Used to clear
1122 * old entries when the age advances.
1124 unsigned int last_age;
1129 * Client connected to the transport service.
1131 struct TransportClient;
1134 * A neighbour that at least one communicator is connected to.
1139 * Entry in our #dv_routes table, representing a (set of) distance
1140 * vector routes to a particular peer.
1142 struct DistanceVector;
1145 * A queue is a message queue provided by a communicator
1146 * via which we can reach a particular neighbour.
1151 * Message awaiting transmission. See detailed comments below.
1153 struct PendingMessage;
1156 * One possible hop towards a DV target.
1158 struct DistanceVectorHop;
1161 * A virtual link is another reachable peer that is known to CORE. It
1162 * can be either a `struct Neighbour` with at least one confirmed
1163 * `struct Queue`, or a `struct DistanceVector` with at least one
1164 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1165 * data that is per neighbour that is not specific to how the
1166 * connectivity is established.
1172 * Context from #handle_incoming_msg(). Closure for many
1173 * message handlers below.
1175 struct CommunicatorMessageContext
1179 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1180 * flow control to unchoke.
1182 struct CommunicatorMessageContext *next;
1185 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1186 * flow control to unchoke.
1188 struct CommunicatorMessageContext *prev;
1191 * Which communicator provided us with the message.
1193 struct TransportClient *tc;
1196 * Additional information for flow control and about the sender.
1198 struct GNUNET_TRANSPORT_IncomingMessage im;
1201 * Number of hops the message has travelled (if DV-routed).
1202 * FIXME: make use of this in ACK handling!
1204 uint16_t total_hops;
1209 * Closure for #core_env_sent_cb.
1211 struct CoreSentContext
1215 * Kept in a DLL to clear @e vl in case @e vl is lost.
1217 struct CoreSentContext *next;
1220 * Kept in a DLL to clear @e vl in case @e vl is lost.
1222 struct CoreSentContext *prev;
1225 * Virtual link this is about.
1227 struct VirtualLink *vl;
1230 * How big was the message.
1235 * By how much should we increment @e vl's
1236 * incoming_fc_window_size_used once we are done sending to CORE?
1237 * Use to ensure we do not increment twice if there is more than one
1245 * A virtual link is another reachable peer that is known to CORE. It
1246 * can be either a `struct Neighbour` with at least one confirmed
1247 * `struct Queue`, or a `struct DistanceVector` with at least one
1248 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1249 * data that is per neighbour that is not specific to how the
1250 * connectivity is established.
1255 * Identity of the peer at the other end of the link.
1257 struct GNUNET_PeerIdentity target;
1260 * Communicators blocked for receiving on @e target as we are waiting
1261 * on the @e core_recv_window to increase.
1263 struct CommunicatorMessageContext *cmc_head;
1266 * Communicators blocked for receiving on @e target as we are waiting
1267 * on the @e core_recv_window to increase.
1269 struct CommunicatorMessageContext *cmc_tail;
1272 * Head of list of messages pending for this VL.
1274 struct PendingMessage *pending_msg_head;
1277 * Tail of list of messages pending for this VL.
1279 struct PendingMessage *pending_msg_tail;
1282 * Kept in a DLL to clear @e vl in case @e vl is lost.
1284 struct CoreSentContext *csc_tail;
1287 * Kept in a DLL to clear @e vl in case @e vl is lost.
1289 struct CoreSentContext *csc_head;
1292 * Task scheduled to possibly notfiy core that this peer is no
1293 * longer counting as confirmed. Runs the #core_visibility_check(),
1294 * which checks that some DV-path or a queue exists that is still
1295 * considered confirmed.
1297 struct GNUNET_SCHEDULER_Task *visibility_task;
1300 * Neighbour used by this virtual link, NULL if @e dv is used.
1302 struct Neighbour *n;
1305 * Distance vector used by this virtual link, NULL if @e n is used.
1307 struct DistanceVector *dv;
1310 * Last challenge we received from @a n.
1311 * FIXME: where do we need this?
1313 struct ChallengeNonceP n_challenge;
1316 * Last challenge we used with @a n for flow control.
1317 * FIXME: where do we need this?
1319 struct ChallengeNonceP my_challenge;
1322 * Sender timestamp of @e n_challenge, used to generate out-of-order
1323 * challenges (as sender's timestamps must be monotonically
1324 * increasing). FIXME: where do we need this?
1326 struct GNUNET_TIME_Absolute n_challenge_time;
1329 * Sender timestamp of the last
1330 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1331 * received. Note that we do not persist this monotonic time as we
1332 * do not really have to worry about ancient flow control window
1333 * sizes after restarts.
1335 struct GNUNET_TIME_Absolute last_fc_timestamp;
1338 * Used to generate unique UUIDs for messages that are being
1341 uint64_t message_uuid_ctr;
1344 * Memory allocated for this virtual link. Expresses how much RAM
1345 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1346 * Can be adapted to dedicate more RAM to links that need it, while
1347 * sticking to some overall RAM limit. For now, set to
1348 * #DEFAULT_WINDOW_SIZE.
1350 uint64_t available_fc_window_size;
1353 * Memory actually used to buffer packets on this virtual link.
1354 * Expresses how much RAM we are currently using for virtual link.
1355 * Note that once CORE is done with a packet, we decrement the value
1358 uint64_t incoming_fc_window_size_ram;
1361 * Last flow control window size we provided to the other peer, in
1362 * bytes. We are allowing the other peer to send this
1365 uint64_t incoming_fc_window_size;
1368 * How much of the window did the other peer successfully use (and
1369 * we already passed it on to CORE)? Must be below @e
1370 * incoming_fc_window_size. We should effectively signal the
1371 * other peer that the window is this much bigger at the next
1372 * opportunity / challenge.
1374 uint64_t incoming_fc_window_size_used;
1377 * What is our current estimate on the message loss rate for the sender?
1378 * Based on the difference between how much the sender sent according
1379 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1380 * (@e outbound_sent field) and how much we actually received at that
1381 * time (@e incoming_fc_window_size_used). This delta is then
1382 * added onto the @e incoming_fc_window_size when determining the
1383 * @e outbound_window_size we send to the other peer. Initially zero.
1384 * May be negative if we (due to out-of-order delivery) actually received
1385 * more than the sender claims to have sent in its last FC message.
1387 int64_t incoming_fc_window_size_loss;
1390 * Our current flow control window size in bytes. We
1391 * are allowed to transmit this many bytes to @a n as per
1392 * our @e my_challenge "account".
1394 uint64_t outbound_fc_window_size;
1397 * How much of our current flow control window size have we
1398 * used (in bytes). Must be below
1399 * @e outbound_fc_window_size.
1401 uint64_t outbound_fc_window_size_used;
1404 * Generator for the sequence numbers of
1405 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1407 uint32_t fc_seq_gen;
1410 * Last sequence number of a
1411 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1414 uint32_t last_fc_seq;
1417 * How many more messages can we send to CORE before we exhaust
1418 * the receive window of CORE for this peer? If this hits zero,
1419 * we must tell communicators to stop providing us more messages
1420 * for this peer. In fact, the window can go negative as we
1421 * have multiple communicators, so per communicator we can go
1422 * down by one into the negative range. Furthermore, we count
1423 * delivery per CORE client, so if we had multiple cores, that
1424 * might also cause a negative window size here (as one message
1425 * would decrement the window by one per CORE client).
1427 int core_recv_window;
1432 * Data structure kept when we are waiting for an acknowledgement.
1434 struct PendingAcknowledgement
1438 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1439 * is kept in relation to its pending message.
1441 struct PendingAcknowledgement *next_pm;
1444 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1445 * is kept in relation to its pending message.
1447 struct PendingAcknowledgement *prev_pm;
1450 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1451 * is kept in relation to the queue that was used to transmit the
1454 struct PendingAcknowledgement *next_queue;
1457 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1458 * is kept in relation to the queue that was used to transmit the
1461 struct PendingAcknowledgement *prev_queue;
1464 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1465 * is kept in relation to the DVH that was used to transmit the
1468 struct PendingAcknowledgement *next_dvh;
1471 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1472 * is kept in relation to the DVH that was used to transmit the
1475 struct PendingAcknowledgement *prev_dvh;
1478 * Pointers for the DLL of all pending acknowledgements.
1479 * This list is sorted by @e transmission time. If the list gets too
1480 * long, the oldest entries are discarded.
1482 struct PendingAcknowledgement *next_pa;
1485 * Pointers for the DLL of all pending acknowledgements.
1486 * This list is sorted by @e transmission time. If the list gets too
1487 * long, the oldest entries are discarded.
1489 struct PendingAcknowledgement *prev_pa;
1492 * Unique identifier for this transmission operation.
1494 struct AcknowledgementUUIDP ack_uuid;
1497 * Message that was transmitted, may be NULL if the message was ACKed
1498 * via another channel.
1500 struct PendingMessage *pm;
1503 * Distance vector path chosen for this transmission, NULL if transmission
1504 * was to a direct neighbour OR if the path was forgotten in the meantime.
1506 struct DistanceVectorHop *dvh;
1509 * Queue used for transmission, NULL if the queue has been destroyed
1510 * (which may happen before we get an acknowledgement).
1512 struct Queue *queue;
1515 * Time of the transmission, for RTT calculation.
1517 struct GNUNET_TIME_Absolute transmission_time;
1520 * Number of bytes of the original message (to calculate bandwidth).
1522 uint16_t message_size;
1527 * One possible hop towards a DV target.
1529 struct DistanceVectorHop
1533 * Kept in a MDLL, sorted by @e timeout.
1535 struct DistanceVectorHop *next_dv;
1538 * Kept in a MDLL, sorted by @e timeout.
1540 struct DistanceVectorHop *prev_dv;
1545 struct DistanceVectorHop *next_neighbour;
1550 struct DistanceVectorHop *prev_neighbour;
1553 * Head of DLL of PAs that used our @a path.
1555 struct PendingAcknowledgement *pa_head;
1558 * Tail of DLL of PAs that used our @a path.
1560 struct PendingAcknowledgement *pa_tail;
1563 * What would be the next hop to @e target?
1565 struct Neighbour *next_hop;
1568 * Distance vector entry this hop belongs with.
1570 struct DistanceVector *dv;
1573 * Array of @e distance hops to the target, excluding @e next_hop.
1574 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1575 * at the end of this struct. Excludes the target itself!
1577 const struct GNUNET_PeerIdentity *path;
1580 * At what time do we forget about this path unless we see it again
1583 struct GNUNET_TIME_Absolute timeout;
1586 * For how long is the validation of this path considered
1588 * Set to ZERO if the path is learned by snooping on DV learn messages
1589 * initiated by other peers, and to the time at which we generated the
1590 * challenge for DV learn operations this peer initiated.
1592 struct GNUNET_TIME_Absolute path_valid_until;
1595 * Performance data for this transmission possibility.
1597 struct PerformanceData pd;
1600 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1601 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1604 unsigned int distance;
1609 * Entry in our #dv_routes table, representing a (set of) distance
1610 * vector routes to a particular peer.
1612 struct DistanceVector
1616 * To which peer is this a route?
1618 struct GNUNET_PeerIdentity target;
1621 * Known paths to @e target.
1623 struct DistanceVectorHop *dv_head;
1626 * Known paths to @e target.
1628 struct DistanceVectorHop *dv_tail;
1631 * Task scheduled to purge expired paths from @e dv_head MDLL.
1633 struct GNUNET_SCHEDULER_Task *timeout_task;
1636 * Do we have a confirmed working queue and are thus visible to
1637 * CORE? If so, this is the virtual link, otherwise NULL.
1639 struct VirtualLink *vl;
1642 * Signature affirming @e ephemeral_key of type
1643 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1645 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1648 * How long is @e sender_sig valid
1650 struct GNUNET_TIME_Absolute ephemeral_validity;
1653 * What time was @e sender_sig created
1655 struct GNUNET_TIME_Absolute monotime;
1658 * Our ephemeral key.
1660 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1663 * Our private ephemeral key.
1665 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1670 * Entry identifying transmission in one of our `struct
1671 * Queue` which still awaits an ACK. This is used to
1672 * ensure we do not overwhelm a communicator and limit the number of
1673 * messages outstanding per communicator (say in case communicator is
1674 * CPU bound) and per queue (in case bandwidth allocation exceeds
1675 * what the communicator can actually provide towards a particular
1684 struct QueueEntry *next;
1689 struct QueueEntry *prev;
1692 * Queue this entry is queued with.
1694 struct Queue *queue;
1697 * Pending message this entry is for, or NULL for none.
1699 struct PendingMessage *pm;
1702 * Message ID used for this message with the queue used for transmission.
1709 * A queue is a message queue provided by a communicator
1710 * via which we can reach a particular neighbour.
1717 struct Queue *next_neighbour;
1722 struct Queue *prev_neighbour;
1727 struct Queue *prev_client;
1732 struct Queue *next_client;
1735 * Head of DLL of PAs that used this queue.
1737 struct PendingAcknowledgement *pa_head;
1740 * Tail of DLL of PAs that used this queue.
1742 struct PendingAcknowledgement *pa_tail;
1745 * Head of DLL of unacked transmission requests.
1747 struct QueueEntry *queue_head;
1750 * End of DLL of unacked transmission requests.
1752 struct QueueEntry *queue_tail;
1755 * Which neighbour is this queue for?
1757 struct Neighbour *neighbour;
1760 * Which communicator offers this queue?
1762 struct TransportClient *tc;
1765 * Address served by the queue.
1767 const char *address;
1770 * Task scheduled for the time when this queue can (likely) transmit the
1773 struct GNUNET_SCHEDULER_Task *transmit_task;
1776 * How long do *we* consider this @e address to be valid? In the past or
1777 * zero if we have not yet validated it. Can be updated based on
1778 * challenge-response validations (via address validation logic), or when we
1779 * receive ACKs that we can definitively map to transmissions via this
1782 struct GNUNET_TIME_Absolute validated_until;
1785 * Performance data for this queue.
1787 struct PerformanceData pd;
1790 * Message ID generator for transmissions on this queue to the
1796 * Unique identifier of this queue with the communicator.
1801 * Maximum transmission unit supported by this queue.
1808 uint32_t num_msg_pending;
1813 uint32_t num_bytes_pending;
1816 * Length of the DLL starting at @e queue_head.
1818 unsigned int queue_length;
1821 * Network type offered by this queue.
1823 enum GNUNET_NetworkType nt;
1826 * Connection status for this queue.
1828 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1831 * Set to #GNUNET_YES if this queue is idle waiting for some
1832 * virtual link to give it a pending message.
1839 * Information we keep for a message that we are reassembling.
1841 struct ReassemblyContext
1845 * Original message ID for of the message that all the fragments
1848 struct MessageUUIDP msg_uuid;
1851 * Which neighbour is this context for?
1853 struct Neighbour *neighbour;
1856 * Entry in the reassembly heap (sorted by expiration).
1858 struct GNUNET_CONTAINER_HeapNode *hn;
1861 * Bitfield with @e msg_size bits representing the positions
1862 * where we have received fragments. When we receive a fragment,
1863 * we check the bits in @e bitfield before incrementing @e msg_missing.
1865 * Allocated after the reassembled message.
1870 * At what time will we give up reassembly of this message?
1872 struct GNUNET_TIME_Absolute reassembly_timeout;
1875 * Time we received the last fragment. @e avg_ack_delay must be
1876 * incremented by now - @e last_frag multiplied by @e num_acks.
1878 struct GNUNET_TIME_Absolute last_frag;
1881 * How big is the message we are reassembling in total?
1886 * How many bytes of the message are still missing? Defragmentation
1887 * is complete when @e msg_missing == 0.
1889 uint16_t msg_missing;
1891 /* Followed by @e msg_size bytes of the (partially) defragmented original
1894 /* Followed by @e bitfield data */
1899 * A neighbour that at least one communicator is connected to.
1905 * Which peer is this about?
1907 struct GNUNET_PeerIdentity pid;
1910 * Map with `struct ReassemblyContext` structs for fragments under
1911 * reassembly. May be NULL if we currently have no fragments from
1912 * this @e pid (lazy initialization).
1914 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1917 * Heap with `struct ReassemblyContext` structs for fragments under
1918 * reassembly. May be NULL if we currently have no fragments from
1919 * this @e pid (lazy initialization).
1921 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1924 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1926 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1929 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1930 * purged if this neighbour goes down.
1932 struct DistanceVectorHop *dv_head;
1935 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1936 * purged if this neighbour goes down.
1938 struct DistanceVectorHop *dv_tail;
1941 * Head of DLL of queues to this peer.
1943 struct Queue *queue_head;
1946 * Tail of DLL of queues to this peer.
1948 struct Queue *queue_tail;
1951 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1952 * the PEERSTORE, or NULL.
1954 struct GNUNET_PEERSTORE_IterateContext *get;
1957 * Handle to a PEERSTORE store operation to store this @e pid's @e
1958 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1960 struct GNUNET_PEERSTORE_StoreContext *sc;
1963 * Do we have a confirmed working queue and are thus visible to
1964 * CORE? If so, this is the virtual link, otherwise NULL.
1966 struct VirtualLink *vl;
1969 * Latest DVLearn monotonic time seen from this peer. Initialized only
1970 * if @e dl_monotime_available is #GNUNET_YES.
1972 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1975 * Do we have the lastest value for @e last_dv_learn_monotime from
1976 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1978 int dv_monotime_available;
1983 * Another peer attempted to talk to us, we should try to establish
1984 * a connection in the other direction.
1986 struct IncomingRequest
1992 struct IncomingRequest *next;
1997 struct IncomingRequest *prev;
2000 * Handle for watching the peerstore for HELLOs for this peer.
2002 struct GNUNET_PEERSTORE_WatchContext *wc;
2005 * Which peer is this about?
2007 struct GNUNET_PeerIdentity pid;
2012 * A peer that an application (client) would like us to talk to directly.
2018 * Which peer is this about?
2020 struct GNUNET_PeerIdentity pid;
2023 * Client responsible for the request.
2025 struct TransportClient *tc;
2028 * Handle for watching the peerstore for HELLOs for this peer.
2030 struct GNUNET_PEERSTORE_WatchContext *wc;
2033 * What kind of performance preference does this @e tc have?
2037 enum GNUNET_MQ_PriorityPreferences pk;
2040 * How much bandwidth would this @e tc like to see?
2042 struct GNUNET_BANDWIDTH_Value32NBO bw;
2047 * Types of different pending messages.
2049 enum PendingMessageType
2053 * Ordinary message received from the CORE service.
2060 PMT_FRAGMENT_BOX = 1,
2065 PMT_RELIABILITY_BOX = 2,
2068 * Pending message created during #forward_dv_box().
2076 * Transmission request that is awaiting delivery. The original
2077 * transmission requests from CORE may be too big for some queues.
2078 * In this case, a *tree* of fragments is created. At each
2079 * level of the tree, fragments are kept in a DLL ordered by which
2080 * fragment should be sent next (at the head). The tree is searched
2081 * top-down, with the original message at the root.
2083 * To select a node for transmission, first it is checked if the
2084 * current node's message fits with the MTU. If it does not, we
2085 * either calculate the next fragment (based on @e frag_off) from the
2086 * current node, or, if all fragments have already been created,
2087 * descend to the @e head_frag. Even though the node was already
2088 * fragmented, the fragment may be too big if the fragment was
2089 * generated for a queue with a larger MTU. In this case, the node
2090 * may be fragmented again, thus creating a tree.
2092 * When acknowledgements for fragments are received, the tree
2093 * must be pruned, removing those parts that were already
2094 * acknowledged. When fragments are sent over a reliable
2095 * channel, they can be immediately removed.
2097 * If a message is ever fragmented, then the original "full" message
2098 * is never again transmitted (even if it fits below the MTU), and
2099 * only (remaining) fragments are sent.
2101 struct PendingMessage
2104 * Kept in a MDLL of messages for this @a vl.
2106 struct PendingMessage *next_vl;
2109 * Kept in a MDLL of messages for this @a vl.
2111 struct PendingMessage *prev_vl;
2114 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2116 struct PendingMessage *next_client;
2119 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2121 struct PendingMessage *prev_client;
2124 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2125 * #PMT_FRAGMENT_BOx)
2127 struct PendingMessage *next_frag;
2130 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2131 * #PMT_FRAGMENT_BOX)
2133 struct PendingMessage *prev_frag;
2136 * Head of DLL of PAs for this pending message.
2138 struct PendingAcknowledgement *pa_head;
2141 * Tail of DLL of PAs for this pending message.
2143 struct PendingAcknowledgement *pa_tail;
2146 * This message, reliability *or* DV-boxed. Only possibly available
2147 * if @e pmt is #PMT_CORE.
2149 struct PendingMessage *bpm;
2152 * Target of the request (always the ultimate destination!).
2154 struct VirtualLink *vl;
2157 * Set to non-NULL value if this message is currently being given to a
2158 * communicator and we are awaiting that communicator's acknowledgement.
2159 * Note that we must not retransmit a pending message while we're still
2160 * in the process of giving it to a communicator. If a pending message
2161 * is free'd while this entry is non-NULL, the @e qe reference to us
2162 * should simply be set to NULL.
2164 struct QueueEntry *qe;
2167 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2169 struct TransportClient *client;
2172 * Head of a MDLL of fragments created for this core message.
2174 struct PendingMessage *head_frag;
2177 * Tail of a MDLL of fragments created for this core message.
2179 struct PendingMessage *tail_frag;
2182 * Our parent in the fragmentation tree.
2184 struct PendingMessage *frag_parent;
2187 * At what time should we give up on the transmission (and no longer retry)?
2189 struct GNUNET_TIME_Absolute timeout;
2192 * What is the earliest time for us to retry transmission of this message?
2194 struct GNUNET_TIME_Absolute next_attempt;
2197 * UUID to use for this message (used for reassembly of fragments, only
2198 * initialized if @e msg_uuid_set is #GNUNET_YES).
2200 struct MessageUUIDP msg_uuid;
2203 * UUID we use to identify this message in our logs.
2204 * Generated by incrementing the "logging_uuid_gen".
2206 unsigned long long logging_uuid;
2209 * Type of the pending message.
2211 enum PendingMessageType pmt;
2214 * Preferences for this message.
2215 * TODO: actually use this!
2217 enum GNUNET_MQ_PriorityPreferences prefs;
2220 * Size of the original message.
2225 * Offset at which we should generate the next fragment.
2230 * #GNUNET_YES once @e msg_uuid was initialized
2232 int16_t msg_uuid_set;
2234 /* Followed by @e bytes_msg to transmit */
2239 * Acknowledgement payload.
2241 struct TransportCummulativeAckPayload
2244 * When did we receive the message we are ACKing? Used to calculate
2245 * the delay we introduced by cummulating ACKs.
2247 struct GNUNET_TIME_Absolute receive_time;
2250 * UUID of a message being acknowledged.
2252 struct AcknowledgementUUIDP ack_uuid;
2257 * Data structure in which we track acknowledgements still to
2260 struct AcknowledgementCummulator
2263 * Target peer for which we are accumulating ACKs here.
2265 struct GNUNET_PeerIdentity target;
2268 * ACK data being accumulated. Only @e num_acks slots are valid.
2270 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2273 * Task scheduled either to transmit the cummulative ACK message,
2274 * or to clean up this data structure after extended periods of
2275 * inactivity (if @e num_acks is zero).
2277 struct GNUNET_SCHEDULER_Task *task;
2280 * When is @e task run (only used if @e num_acks is non-zero)?
2282 struct GNUNET_TIME_Absolute min_transmission_time;
2285 * Counter to produce the `ack_counter` in the `struct
2286 * TransportReliabilityAckMessage`. Allows the receiver to detect
2287 * lost ACK messages. Incremented by @e num_acks upon transmission.
2289 uint32_t ack_counter;
2292 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2294 unsigned int num_acks;
2299 * One of the addresses of this peer.
2301 struct AddressListEntry
2307 struct AddressListEntry *next;
2312 struct AddressListEntry *prev;
2315 * Which communicator provides this address?
2317 struct TransportClient *tc;
2320 * The actual address.
2322 const char *address;
2325 * Current context for storing this address in the peerstore.
2327 struct GNUNET_PEERSTORE_StoreContext *sc;
2330 * Task to periodically do @e st operation.
2332 struct GNUNET_SCHEDULER_Task *st;
2335 * What is a typical lifetime the communicator expects this
2336 * address to have? (Always from now.)
2338 struct GNUNET_TIME_Relative expiration;
2341 * Address identifier used by the communicator.
2346 * Network type offered by this address.
2348 enum GNUNET_NetworkType nt;
2353 * Client connected to the transport service.
2355 struct TransportClient
2361 struct TransportClient *next;
2366 struct TransportClient *prev;
2369 * Handle to the client.
2371 struct GNUNET_SERVICE_Client *client;
2374 * Message queue to the client.
2376 struct GNUNET_MQ_Handle *mq;
2379 * What type of client is this?
2381 enum ClientType type;
2387 * Information for @e type #CT_CORE.
2393 * Head of list of messages pending for this client, sorted by
2394 * transmission time ("next_attempt" + possibly internal prioritization).
2396 struct PendingMessage *pending_msg_head;
2399 * Tail of list of messages pending for this client.
2401 struct PendingMessage *pending_msg_tail;
2406 * Information for @e type #CT_MONITOR.
2412 * Peer identity to monitor the addresses of.
2413 * Zero to monitor all neighbours. Valid if
2414 * @e type is #CT_MONITOR.
2416 struct GNUNET_PeerIdentity peer;
2419 * Is this a one-shot monitor?
2427 * Information for @e type #CT_COMMUNICATOR.
2432 * If @e type is #CT_COMMUNICATOR, this communicator
2433 * supports communicating using these addresses.
2435 char *address_prefix;
2438 * Head of DLL of queues offered by this communicator.
2440 struct Queue *queue_head;
2443 * Tail of DLL of queues offered by this communicator.
2445 struct Queue *queue_tail;
2448 * Head of list of the addresses of this peer offered by this
2451 struct AddressListEntry *addr_head;
2454 * Tail of list of the addresses of this peer offered by this
2457 struct AddressListEntry *addr_tail;
2460 * Number of queue entries in all queues to this communicator. Used
2461 * throttle sending to a communicator if we see that the communicator
2462 * is globally unable to keep up.
2464 unsigned int total_queue_length;
2467 * Characteristics of this communicator.
2469 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2474 * Information for @e type #CT_APPLICATION
2480 * Map of requests for peers the given client application would like to
2481 * see connections for. Maps from PIDs to `struct PeerRequest`.
2483 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2492 * State we keep for validation activities. Each of these
2493 * is both in the #validation_heap and the #validation_map.
2495 struct ValidationState
2499 * For which peer is @a address to be validated (or possibly valid)?
2500 * Serves as key in the #validation_map.
2502 struct GNUNET_PeerIdentity pid;
2505 * How long did the peer claim this @e address to be valid? Capped at
2506 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2507 * were told about the address and the value claimed by the other peer at
2508 * that time. May be updated similarly when validation succeeds.
2510 struct GNUNET_TIME_Absolute valid_until;
2513 * How long do *we* consider this @e address to be valid?
2514 * In the past or zero if we have not yet validated it.
2516 struct GNUNET_TIME_Absolute validated_until;
2519 * When did we FIRST use the current @e challenge in a message?
2520 * Used to sanity-check @code{origin_time} in the response when
2521 * calculating the RTT. If the @code{origin_time} is not in
2522 * the expected range, the response is discarded as malicious.
2524 struct GNUNET_TIME_Absolute first_challenge_use;
2527 * When did we LAST use the current @e challenge in a message?
2528 * Used to sanity-check @code{origin_time} in the response when
2529 * calculating the RTT. If the @code{origin_time} is not in
2530 * the expected range, the response is discarded as malicious.
2532 struct GNUNET_TIME_Absolute last_challenge_use;
2535 * Next time we will send the @e challenge to the peer, if this time is past
2536 * @e valid_until, this validation state is released at this time. If the
2537 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2538 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2539 * to re-validate before the validity actually expires.
2541 struct GNUNET_TIME_Absolute next_challenge;
2544 * Current backoff factor we're applying for sending the @a challenge.
2545 * Reset to 0 if the @a challenge is confirmed upon validation.
2546 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2547 * existing value if we receive an unvalidated address again over
2548 * another channel (and thus should consider the information "fresh").
2549 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2551 struct GNUNET_TIME_Relative challenge_backoff;
2554 * Initially set to "forever". Once @e validated_until is set, this value is
2555 * set to the RTT that tells us how long it took to receive the validation.
2557 struct GNUNET_TIME_Relative validation_rtt;
2560 * The challenge we sent to the peer to get it to validate the address. Note
2561 * that we rotate the challenge whenever we update @e validated_until to
2562 * avoid attacks where a peer simply replays an old challenge in the future.
2563 * (We must not rotate more often as otherwise we may discard valid answers
2564 * due to packet losses, latency and reorderings on the network).
2566 struct ChallengeNonceP challenge;
2569 * Claimed address of the peer.
2574 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2575 * heap is used to figure out when the next validation activity should be
2578 struct GNUNET_CONTAINER_HeapNode *hn;
2581 * Handle to a PEERSTORE store operation for this @e address. NULL if
2582 * no PEERSTORE operation is pending.
2584 struct GNUNET_PEERSTORE_StoreContext *sc;
2587 * Self-imposed limit on the previous flow control window. (May be zero,
2588 * if we never used data from the previous window or are establishing the
2589 * connection for the first time).
2591 uint32_t last_window_consum_limit;
2594 * We are technically ready to send the challenge, but we are waiting for
2595 * the respective queue to become available for transmission.
2602 * A Backtalker is a peer sending us backchannel messages. We use this
2603 * struct to detect monotonic time violations, cache ephemeral key
2604 * material (to avoid repeatedly checking signatures), and to synchronize
2605 * monotonic time with the PEERSTORE.
2610 * Peer this is about.
2612 struct GNUNET_PeerIdentity pid;
2615 * Last (valid) monotonic time received from this sender.
2617 struct GNUNET_TIME_Absolute monotonic_time;
2620 * When will this entry time out?
2622 struct GNUNET_TIME_Absolute timeout;
2625 * Last (valid) ephemeral key received from this sender.
2627 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2630 * Task associated with this backtalker. Can be for timeout,
2631 * or other asynchronous operations.
2633 struct GNUNET_SCHEDULER_Task *task;
2636 * Communicator context waiting on this backchannel's @e get, or NULL.
2638 struct CommunicatorMessageContext *cmc;
2641 * Handle for an operation to fetch @e monotonic_time information from the
2642 * PEERSTORE, or NULL.
2644 struct GNUNET_PEERSTORE_IterateContext *get;
2647 * Handle to a PEERSTORE store operation for this @e pid's @e
2648 * monotonic_time. NULL if no PEERSTORE operation is pending.
2650 struct GNUNET_PEERSTORE_StoreContext *sc;
2653 * Number of bytes of the original message body that follows after this
2661 * Head of linked list of all clients to this service.
2663 static struct TransportClient *clients_head;
2666 * Tail of linked list of all clients to this service.
2668 static struct TransportClient *clients_tail;
2671 * Statistics handle.
2673 static struct GNUNET_STATISTICS_Handle *GST_stats;
2676 * Configuration handle.
2678 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2683 static struct GNUNET_PeerIdentity GST_my_identity;
2688 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2691 * Map from PIDs to `struct Neighbour` entries. A peer is
2692 * a neighbour if we have an MQ to it from some communicator.
2694 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2697 * Map from PIDs to `struct Backtalker` entries. A peer is
2698 * a backtalker if it recently send us backchannel messages.
2700 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2703 * Map from PIDs to `struct AcknowledgementCummulator`s.
2704 * Here we track the cummulative ACKs for transmission.
2706 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2709 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2710 * a `struct PendingAcknowledgement`.
2712 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2715 * Map from PIDs to `struct DistanceVector` entries describing
2716 * known paths to the peer.
2718 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2721 * Map from PIDs to `struct ValidationState` entries describing
2722 * addresses we are aware of and their validity state.
2724 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2727 * Map from PIDs to `struct VirtualLink` entries describing
2728 * links CORE knows to exist.
2730 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2733 * Map from challenges to `struct LearnLaunchEntry` values.
2735 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2738 * Head of a DLL sorted by launch time.
2740 static struct LearnLaunchEntry *lle_head;
2743 * Tail of a DLL sorted by launch time.
2745 static struct LearnLaunchEntry *lle_tail;
2748 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2749 * sorting addresses we are aware of by when we should next try to (re)validate
2752 static struct GNUNET_CONTAINER_Heap *validation_heap;
2755 * Database for peer's HELLOs.
2757 static struct GNUNET_PEERSTORE_Handle *peerstore;
2760 * Task run to initiate DV learning.
2762 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2765 * Task to run address validation.
2767 static struct GNUNET_SCHEDULER_Task *validation_task;
2770 * The most recent PA we have created, head of DLL.
2771 * The length of the DLL is kept in #pa_count.
2773 static struct PendingAcknowledgement *pa_head;
2776 * The oldest PA we have created, tail of DLL.
2777 * The length of the DLL is kept in #pa_count.
2779 static struct PendingAcknowledgement *pa_tail;
2782 * List of incomming connections where we are trying
2783 * to get a connection back established. Length
2784 * kept in #ir_total.
2786 static struct IncomingRequest *ir_head;
2789 * Tail of DLL starting at #ir_head.
2791 static struct IncomingRequest *ir_tail;
2794 * Length of the DLL starting at #ir_head.
2796 static unsigned int ir_total;
2799 * Generator of `logging_uuid` in `struct PendingMessage`.
2801 static unsigned long long logging_uuid_gen;
2804 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2805 * limit the size of the data structure.
2807 static unsigned int pa_count;
2810 * Monotonic time we use for HELLOs generated at this time. TODO: we
2811 * should increase this value from time to time (i.e. whenever a
2812 * `struct AddressListEntry` actually expires), but IF we do this, we
2813 * must also update *all* (remaining) addresses in the PEERSTORE at
2814 * that time! (So for now only increased when the peer is restarted,
2815 * which hopefully roughly matches whenever our addresses change.)
2817 static struct GNUNET_TIME_Absolute hello_mono_time;
2821 * Get an offset into the transmission history buffer for `struct
2822 * PerformanceData`. Note that the caller must perform the required
2823 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2826 * An 'age' lasts 15 minute slots.
2828 * @return current age of the world
2833 struct GNUNET_TIME_Absolute now;
2835 now = GNUNET_TIME_absolute_get ();
2836 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2841 * Release @a ir data structure.
2843 * @param ir data structure to release
2846 free_incoming_request (struct IncomingRequest *ir)
2848 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2849 GNUNET_assert (ir_total > 0);
2851 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2857 * Release @a pa data structure.
2859 * @param pa data structure to release
2862 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2864 struct Queue *q = pa->queue;
2865 struct PendingMessage *pm = pa->pm;
2866 struct DistanceVectorHop *dvh = pa->dvh;
2868 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2872 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2877 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2882 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2885 GNUNET_assert (GNUNET_YES ==
2886 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2887 &pa->ack_uuid.value,
2894 * Free fragment tree below @e root, excluding @e root itself.
2895 * FIXME: this does NOT seem to have the intended semantics
2896 * based on how this is called. Seems we generally DO expect
2897 * @a root to be free'ed itself as well!
2899 * @param root root of the tree to free
2902 free_fragment_tree (struct PendingMessage *root)
2904 struct PendingMessage *frag;
2906 while (NULL != (frag = root->head_frag))
2908 struct PendingAcknowledgement *pa;
2910 free_fragment_tree (frag);
2911 while (NULL != (pa = frag->pa_head))
2913 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2916 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2923 * Release memory associated with @a pm and remove @a pm from associated
2924 * data structures. @a pm must be a top-level pending message and not
2925 * a fragment in the tree. The entire tree is freed (if applicable).
2927 * @param pm the pending message to free
2930 free_pending_message (struct PendingMessage *pm)
2932 struct TransportClient *tc = pm->client;
2933 struct VirtualLink *vl = pm->vl;
2934 struct PendingAcknowledgement *pa;
2938 GNUNET_CONTAINER_MDLL_remove (client,
2939 tc->details.core.pending_msg_head,
2940 tc->details.core.pending_msg_tail,
2945 GNUNET_CONTAINER_MDLL_remove (vl,
2946 vl->pending_msg_head,
2947 vl->pending_msg_tail,
2950 while (NULL != (pa = pm->pa_head))
2952 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2956 free_fragment_tree (pm);
2959 GNUNET_assert (pm == pm->qe->pm);
2962 if (NULL != pm->bpm)
2964 free_fragment_tree (pm->bpm);
2965 GNUNET_free (pm->bpm);
2972 * Free virtual link.
2974 * @param vl link data to free
2977 free_virtual_link (struct VirtualLink *vl)
2979 struct PendingMessage *pm;
2980 struct CoreSentContext *csc;
2982 while (NULL != (pm = vl->pending_msg_head))
2983 free_pending_message (pm);
2984 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2985 if (NULL != vl->visibility_task)
2987 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2988 vl->visibility_task = NULL;
2990 while (NULL != (csc = vl->csc_head))
2992 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
2993 GNUNET_assert (vl == csc->vl);
2996 GNUNET_break (NULL == vl->n);
2997 GNUNET_break (NULL == vl->dv);
3003 * Free validation state.
3005 * @param vs validation state to free
3008 free_validation_state (struct ValidationState *vs)
3010 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
3011 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3015 GNUNET_PEERSTORE_store_cancel (vs->sc);
3018 GNUNET_free (vs->address);
3024 * Lookup neighbour for peer @a pid.
3026 * @param pid neighbour to look for
3027 * @return NULL if we do not have this peer as a neighbour
3029 static struct Neighbour *
3030 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3032 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3037 * Lookup virtual link for peer @a pid.
3039 * @param pid virtual link to look for
3040 * @return NULL if we do not have this peer as a virtual link
3042 static struct VirtualLink *
3043 lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3045 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3050 * Details about what to notify monitors about.
3055 * @deprecated To be discussed if we keep these...
3057 struct GNUNET_TIME_Absolute last_validation;
3058 struct GNUNET_TIME_Absolute valid_until;
3059 struct GNUNET_TIME_Absolute next_validation;
3062 * Current round-trip time estimate.
3064 struct GNUNET_TIME_Relative rtt;
3067 * Connection status.
3069 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3074 uint32_t num_msg_pending;
3079 uint32_t num_bytes_pending;
3084 * Free a @dvh. Callers MAY want to check if this was the last path to the
3085 * `target`, and if so call #free_dv_route to also free the associated DV
3086 * entry in #dv_routes (if not, the associated scheduler job should eventually
3089 * @param dvh hop to free
3092 free_distance_vector_hop (struct DistanceVectorHop *dvh)
3094 struct Neighbour *n = dvh->next_hop;
3095 struct DistanceVector *dv = dvh->dv;
3096 struct PendingAcknowledgement *pa;
3098 while (NULL != (pa = dvh->pa_head))
3100 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3103 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3104 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3110 * Task run to check whether the hops of the @a cls still
3111 * are validated, or if we need to core about disconnection.
3113 * @param cls a `struct VirtualLink`
3116 check_link_down (void *cls);
3120 * Send message to CORE clients that we lost a connection.
3122 * @param pid peer the connection was for
3125 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3128 "Informing CORE clients about disconnect from %s\n",
3130 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3132 struct GNUNET_MQ_Envelope *env;
3133 struct DisconnectInfoMessage *dim;
3135 if (CT_CORE != tc->type)
3137 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3139 GNUNET_MQ_send (tc->mq, env);
3145 * Free entry in #dv_routes. First frees all hops to the target, and
3146 * if there are no entries left, frees @a dv as well.
3148 * @param dv route to free
3151 free_dv_route (struct DistanceVector *dv)
3153 struct DistanceVectorHop *dvh;
3155 while (NULL != (dvh = dv->dv_head))
3156 free_distance_vector_hop (dvh);
3157 if (NULL == dv->dv_head)
3159 struct VirtualLink *vl;
3163 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3164 if (NULL != (vl = dv->vl))
3166 GNUNET_assert (dv == vl->dv);
3170 cores_send_disconnect_info (&dv->target);
3171 free_virtual_link (vl);
3175 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3176 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3181 if (NULL != dv->timeout_task)
3183 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3184 dv->timeout_task = NULL;
3192 * Notify monitor @a tc about an event. That @a tc
3193 * cares about the event has already been checked.
3195 * Send @a tc information in @a me about a @a peer's status with
3196 * respect to some @a address to all monitors that care.
3198 * @param tc monitor to inform
3199 * @param peer peer the information is about
3200 * @param address address the information is about
3201 * @param nt network type associated with @a address
3202 * @param me detailed information to transmit
3205 notify_monitor (struct TransportClient *tc,
3206 const struct GNUNET_PeerIdentity *peer,
3207 const char *address,
3208 enum GNUNET_NetworkType nt,
3209 const struct MonitorEvent *me)
3211 struct GNUNET_MQ_Envelope *env;
3212 struct GNUNET_TRANSPORT_MonitorData *md;
3213 size_t addr_len = strlen (address) + 1;
3215 env = GNUNET_MQ_msg_extra (md,
3217 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3218 md->nt = htonl ((uint32_t) nt);
3220 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3221 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3222 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3223 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3224 md->cs = htonl ((uint32_t) me->cs);
3225 md->num_msg_pending = htonl (me->num_msg_pending);
3226 md->num_bytes_pending = htonl (me->num_bytes_pending);
3227 memcpy (&md[1], address, addr_len);
3228 GNUNET_MQ_send (tc->mq, env);
3233 * Send information in @a me about a @a peer's status with respect
3234 * to some @a address to all monitors that care.
3236 * @param peer peer the information is about
3237 * @param address address the information is about
3238 * @param nt network type associated with @a address
3239 * @param me detailed information to transmit
3242 notify_monitors (const struct GNUNET_PeerIdentity *peer,
3243 const char *address,
3244 enum GNUNET_NetworkType nt,
3245 const struct MonitorEvent *me)
3247 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3249 if (CT_MONITOR != tc->type)
3251 if (tc->details.monitor.one_shot)
3253 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
3254 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3256 notify_monitor (tc, peer, address, nt, me);
3262 * Called whenever a client connects. Allocates our
3263 * data structures associated with that client.
3265 * @param cls closure, NULL
3266 * @param client identification of the client
3267 * @param mq message queue for the client
3268 * @return our `struct TransportClient`
3271 client_connect_cb (void *cls,
3272 struct GNUNET_SERVICE_Client *client,
3273 struct GNUNET_MQ_Handle *mq)
3275 struct TransportClient *tc;
3278 tc = GNUNET_new (struct TransportClient);
3279 tc->client = client;
3281 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
3290 * @param rc data structure to free
3293 free_reassembly_context (struct ReassemblyContext *rc)
3295 struct Neighbour *n = rc->neighbour;
3297 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3298 GNUNET_assert (GNUNET_OK ==
3299 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
3307 * Task run to clean up reassembly context of a neighbour that have expired.
3309 * @param cls a `struct Neighbour`
3312 reassembly_cleanup_task (void *cls)
3314 struct Neighbour *n = cls;
3315 struct ReassemblyContext *rc;
3317 n->reassembly_timeout_task = NULL;
3318 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
3320 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3323 free_reassembly_context (rc);
3326 GNUNET_assert (NULL == n->reassembly_timeout_task);
3327 n->reassembly_timeout_task =
3328 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3329 &reassembly_cleanup_task,
3337 * function called to #free_reassembly_context().
3341 * @param value a `struct ReassemblyContext` to free
3342 * @return #GNUNET_OK (continue iteration)
3345 free_reassembly_cb (void *cls, uint32_t key, void *value)
3347 struct ReassemblyContext *rc = value;
3351 free_reassembly_context (rc);
3357 * Release memory used by @a neighbour.
3359 * @param neighbour neighbour entry to free
3362 free_neighbour (struct Neighbour *neighbour)
3364 struct DistanceVectorHop *dvh;
3365 struct VirtualLink *vl;
3367 GNUNET_assert (NULL == neighbour->queue_head);
3368 GNUNET_assert (GNUNET_YES ==
3369 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3372 if (NULL != neighbour->reassembly_map)
3374 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
3375 &free_reassembly_cb,
3377 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
3378 neighbour->reassembly_map = NULL;
3379 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
3380 neighbour->reassembly_heap = NULL;
3382 while (NULL != (dvh = neighbour->dv_head))
3384 struct DistanceVector *dv = dvh->dv;
3386 free_distance_vector_hop (dvh);
3387 if (NULL == dv->dv_head)
3390 if (NULL != neighbour->reassembly_timeout_task)
3392 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
3393 neighbour->reassembly_timeout_task = NULL;
3395 if (NULL != neighbour->get)
3397 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3398 neighbour->get = NULL;
3400 if (NULL != neighbour->sc)
3402 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3403 neighbour->sc = NULL;
3405 if (NULL != (vl = neighbour->vl))
3407 GNUNET_assert (neighbour == vl->n);
3411 cores_send_disconnect_info (&vl->target);
3412 free_virtual_link (vl);
3416 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3417 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3419 neighbour->vl = NULL;
3421 GNUNET_free (neighbour);
3426 * Send message to CORE clients that we lost a connection.
3428 * @param tc client to inform (must be CORE client)
3429 * @param pid peer the connection is for
3432 core_send_connect_info (struct TransportClient *tc,
3433 const struct GNUNET_PeerIdentity *pid)
3435 struct GNUNET_MQ_Envelope *env;
3436 struct ConnectInfoMessage *cim;
3438 GNUNET_assert (CT_CORE == tc->type);
3439 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3441 GNUNET_MQ_send (tc->mq, env);
3446 * Send message to CORE clients that we gained a connection
3448 * @param pid peer the queue was for
3451 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3454 "Informing CORE clients about connection to %s\n",
3456 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3458 if (CT_CORE != tc->type)
3460 core_send_connect_info (tc, pid);
3466 * We believe we are ready to transmit a message on a queue. Gives the
3467 * message to the communicator for transmission (updating the tracker,
3468 * and re-scheduling itself if applicable).
3470 * @param cls the `struct Queue` to process transmissions for
3473 transmit_on_queue (void *cls);
3477 * Called whenever something changed that might effect when we
3478 * try to do the next transmission on @a queue using #transmit_on_queue().
3480 * @param queue the queue to do scheduling for
3481 * @param p task priority to use, if @a queue is scheduled
3484 schedule_transmit_on_queue (struct Queue *queue,
3485 enum GNUNET_SCHEDULER_Priority p)
3487 if (queue->tc->details.communicator.total_queue_length >=
3488 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3490 GNUNET_STATISTICS_update (
3492 "# Transmission throttled due to communicator queue limit",
3495 queue->idle = GNUNET_NO;
3498 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3500 GNUNET_STATISTICS_update (GST_stats,
3501 "# Transmission throttled due to queue queue limit",
3504 queue->idle = GNUNET_NO;
3507 /* queue might indeed be ready, schedule it */
3508 if (NULL != queue->transmit_task)
3509 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3510 queue->transmit_task =
3511 GNUNET_SCHEDULER_add_with_priority (p, &transmit_on_queue, queue);
3512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3513 "Considering transmission on queue `%s' to %s\n",
3515 GNUNET_i2s (&queue->neighbour->pid));
3520 * Task run to check whether the hops of the @a cls still
3521 * are validated, or if we need to core about disconnection.
3523 * @param cls a `struct VirtualLink`
3526 check_link_down (void *cls)
3528 struct VirtualLink *vl = cls;
3529 struct DistanceVector *dv = vl->dv;
3530 struct Neighbour *n = vl->n;
3531 struct GNUNET_TIME_Absolute dvh_timeout;
3532 struct GNUNET_TIME_Absolute q_timeout;
3534 vl->visibility_task = NULL;
3535 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3536 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3538 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3539 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3544 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3545 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3546 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3547 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3552 if ((NULL == vl->n) && (NULL == vl->dv))
3554 cores_send_disconnect_info (&vl->target);
3555 free_virtual_link (vl);
3558 vl->visibility_task =
3559 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3568 * @param queue the queue to free
3571 free_queue (struct Queue *queue)
3573 struct Neighbour *neighbour = queue->neighbour;
3574 struct TransportClient *tc = queue->tc;
3575 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3576 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3577 struct QueueEntry *qe;
3579 struct PendingAcknowledgement *pa;
3580 struct VirtualLink *vl;
3582 if (NULL != queue->transmit_task)
3584 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3585 queue->transmit_task = NULL;
3587 while (NULL != (pa = queue->pa_head))
3589 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3593 GNUNET_CONTAINER_MDLL_remove (neighbour,
3594 neighbour->queue_head,
3595 neighbour->queue_tail,
3597 GNUNET_CONTAINER_MDLL_remove (client,
3598 tc->details.communicator.queue_head,
3599 tc->details.communicator.queue_tail,
3601 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3602 tc->details.communicator.total_queue_length);
3603 while (NULL != (qe = queue->queue_head))
3605 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3606 queue->queue_length--;
3607 tc->details.communicator.total_queue_length--;
3610 GNUNET_assert (qe == qe->pm->qe);
3615 GNUNET_assert (0 == queue->queue_length);
3616 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3617 tc->details.communicator.total_queue_length))
3619 /* Communicator dropped below threshold, resume all _other_ queues */
3620 GNUNET_STATISTICS_update (
3622 "# Transmission throttled due to communicator queue limit",
3625 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3627 schedule_transmit_on_queue (s, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3629 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3630 GNUNET_free (queue);
3632 vl = lookup_virtual_link (&neighbour->pid);
3633 if ((NULL != vl) && (neighbour == vl->n))
3635 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3636 check_link_down (vl);
3638 if (NULL == neighbour->queue_head)
3640 free_neighbour (neighbour);
3648 * @param ale address list entry to free
3651 free_address_list_entry (struct AddressListEntry *ale)
3653 struct TransportClient *tc = ale->tc;
3655 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3656 tc->details.communicator.addr_tail,
3658 if (NULL != ale->sc)
3660 GNUNET_PEERSTORE_store_cancel (ale->sc);
3663 if (NULL != ale->st)
3665 GNUNET_SCHEDULER_cancel (ale->st);
3673 * Stop the peer request in @a value.
3675 * @param cls a `struct TransportClient` that no longer makes the request
3676 * @param pid the peer's identity
3677 * @param value a `struct PeerRequest`
3678 * @return #GNUNET_YES (always)
3681 stop_peer_request (void *cls,
3682 const struct GNUNET_PeerIdentity *pid,
3685 struct TransportClient *tc = cls;
3686 struct PeerRequest *pr = value;
3688 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3691 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3701 * Called whenever a client is disconnected. Frees our
3702 * resources associated with that client.
3704 * @param cls closure, NULL
3705 * @param client identification of the client
3706 * @param app_ctx our `struct TransportClient`
3709 client_disconnect_cb (void *cls,
3710 struct GNUNET_SERVICE_Client *client,
3713 struct TransportClient *tc = app_ctx;
3717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3718 "Client %p disconnected, cleaning up.\n",
3720 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3726 struct PendingMessage *pm;
3728 while (NULL != (pm = tc->details.core.pending_msg_head))
3730 GNUNET_CONTAINER_MDLL_remove (client,
3731 tc->details.core.pending_msg_head,
3732 tc->details.core.pending_msg_tail,
3740 case CT_COMMUNICATOR: {
3742 struct AddressListEntry *ale;
3744 while (NULL != (q = tc->details.communicator.queue_head))
3746 while (NULL != (ale = tc->details.communicator.addr_head))
3747 free_address_list_entry (ale);
3748 GNUNET_free (tc->details.communicator.address_prefix);
3751 case CT_APPLICATION:
3752 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3755 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3763 * Iterator telling new CORE client about all existing
3764 * connections to peers.
3766 * @param cls the new `struct TransportClient`
3767 * @param pid a connected peer
3768 * @param value the `struct Neighbour` with more information
3769 * @return #GNUNET_OK (continue to iterate)
3772 notify_client_connect_info (void *cls,
3773 const struct GNUNET_PeerIdentity *pid,
3776 struct TransportClient *tc = cls;
3779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3780 "Telling new CORE client about existing connection to %s\n",
3782 core_send_connect_info (tc, pid);
3788 * Initialize a "CORE" client. We got a start message from this
3789 * client, so add it to the list of clients for broadcasting of
3792 * @param cls the client
3793 * @param start the start message that was sent
3796 handle_client_start (void *cls, const struct StartMessage *start)
3798 struct TransportClient *tc = cls;
3801 options = ntohl (start->options);
3802 if ((0 != (1 & options)) &&
3803 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3805 /* client thinks this is a different peer, reject */
3807 GNUNET_SERVICE_client_drop (tc->client);
3810 if (CT_NONE != tc->type)
3813 GNUNET_SERVICE_client_drop (tc->client);
3817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3818 "New CORE client with PID %s registered\n",
3819 GNUNET_i2s (&start->self));
3820 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3821 ¬ify_client_connect_info,
3823 GNUNET_SERVICE_client_continue (tc->client);
3828 * Client asked for transmission to a peer. Process the request.
3830 * @param cls the client
3831 * @param obm the send message that was sent
3834 check_client_send (void *cls, const struct OutboundMessage *obm)
3836 struct TransportClient *tc = cls;
3838 const struct GNUNET_MessageHeader *obmm;
3840 if (CT_CORE != tc->type)
3843 return GNUNET_SYSERR;
3845 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3846 if (size < sizeof (struct GNUNET_MessageHeader))
3849 return GNUNET_SYSERR;
3851 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3852 if (size != ntohs (obmm->size))
3855 return GNUNET_SYSERR;
3862 * Send a response to the @a pm that we have processed a "send"
3863 * request. Sends a confirmation to the "core" client responsible for
3864 * the original request and free's @a pm.
3866 * @param pm handle to the original pending message
3869 client_send_response (struct PendingMessage *pm)
3871 struct TransportClient *tc = pm->client;
3872 struct VirtualLink *vl = pm->vl;
3873 struct GNUNET_MQ_Envelope *env;
3874 struct SendOkMessage *som;
3878 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3879 som->peer = vl->target;
3880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3881 "Confirming transmission of <%llu> to %s\n",
3883 GNUNET_i2s (&vl->target));
3884 GNUNET_MQ_send (tc->mq, env);
3886 free_pending_message (pm);
3891 * Pick @a hops_array_length random DV paths satisfying @a options
3893 * @param dv data structure to pick paths from
3894 * @param options constraints to satisfy
3895 * @param hops_array[out] set to the result
3896 * @param hops_array_length length of the @a hops_array
3897 * @return number of entries set in @a hops_array
3900 pick_random_dv_hops (const struct DistanceVector *dv,
3901 enum RouteMessageOptions options,
3902 struct DistanceVectorHop **hops_array,
3903 unsigned int hops_array_length)
3905 uint64_t choices[hops_array_length];
3907 unsigned int dv_count;
3909 /* Pick random vectors, but weighted by distance, giving more weight
3910 to shorter vectors */
3913 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3916 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3917 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3918 .rel_value_us == 0))
3919 continue; /* pos unconfirmed and confirmed required */
3920 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3925 if (dv_count <= hops_array_length)
3928 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3930 hops_array[dv_count++] = pos;
3933 for (unsigned int i = 0; i < hops_array_length; i++)
3936 while (GNUNET_NO == ok)
3939 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3941 for (unsigned int j = 0; j < i; j++)
3942 if (choices[i] == choices[j])
3951 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3954 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3956 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3957 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3958 .rel_value_us == 0))
3959 continue; /* pos unconfirmed and confirmed required */
3960 for (unsigned int i = 0; i < hops_array_length; i++)
3961 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3962 hops_array[dv_count++] = pos;
3970 * There is a message at the head of the pending messages for @a vl
3971 * which may be ready for transmission. Check if a queue is ready to
3974 * This function must (1) check for flow control to ensure that we can
3975 * right now send to @a vl, (2) check that the pending message in the
3976 * queue is actually eligible, (3) determine if any applicable queue
3977 * (direct neighbour or DVH path) is ready to accept messages, and
3978 * (4) prioritize based on the preferences associated with the
3983 * @param vl virtual link where we should check for transmission
3986 check_vl_transmission (struct VirtualLink *vl)
3988 struct Neighbour *n = vl->n;
3989 struct DistanceVector *dv = vl->dv;
3990 struct GNUNET_TIME_Absolute now;
3993 /* FIXME-FC: need to implement virtual link flow control! */
3995 /* Check that we have an eligible pending message!
3996 (cheaper than having #transmit_on_queue() find out!) */
3998 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
4002 continue; /* not eligible, is in a queue! */
4006 if (GNUNET_NO == elig)
4009 /* Notify queues at direct neighbours that we are interested */
4010 now = GNUNET_TIME_absolute_get ();
4013 for (struct Queue *queue = n->queue_head; NULL != queue;
4014 queue = queue->next_neighbour)
4015 if ((GNUNET_YES == queue->idle) &&
4016 (queue->validated_until.abs_value_us > now.abs_value_us))
4017 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4019 /* Notify queues via DV that we are interested */
4022 /* Do DV with lower scheduler priority, which effectively means that
4023 IF a neighbour exists and is available, we prefer it. */
4024 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4027 struct Neighbour *nh = pos->next_hop;
4029 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
4030 continue; /* skip this one: path not validated */
4031 for (struct Queue *queue = nh->queue_head; NULL != queue;
4032 queue = queue->next_neighbour)
4033 if ((GNUNET_YES == queue->idle) &&
4034 (queue->validated_until.abs_value_us > now.abs_value_us))
4035 schedule_transmit_on_queue (queue,
4036 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
4043 * Client asked for transmission to a peer. Process the request.
4045 * @param cls the client
4046 * @param obm the send message that was sent
4049 handle_client_send (void *cls, const struct OutboundMessage *obm)
4051 struct TransportClient *tc = cls;
4052 struct PendingMessage *pm;
4053 const struct GNUNET_MessageHeader *obmm;
4055 struct VirtualLink *vl;
4056 enum GNUNET_MQ_PriorityPreferences pp;
4058 GNUNET_assert (CT_CORE == tc->type);
4059 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4060 bytes_msg = ntohs (obmm->size);
4061 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
4062 vl = lookup_virtual_link (&obm->peer);
4065 /* Failure: don't have this peer as a neighbour (anymore).
4066 Might have gone down asynchronously, so this is NOT
4067 a protocol violation by CORE. Still count the event,
4068 as this should be rare. */
4069 GNUNET_SERVICE_client_continue (tc->client);
4070 GNUNET_STATISTICS_update (GST_stats,
4071 "# messages dropped (neighbour unknown)",
4077 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
4078 pm->logging_uuid = logging_uuid_gen++;
4082 pm->bytes_msg = bytes_msg;
4083 memcpy (&pm[1], obmm, bytes_msg);
4084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4085 "Sending %u bytes as <%llu> to %s\n",
4088 GNUNET_i2s (&obm->peer));
4089 GNUNET_CONTAINER_MDLL_insert (client,
4090 tc->details.core.pending_msg_head,
4091 tc->details.core.pending_msg_tail,
4093 GNUNET_CONTAINER_MDLL_insert (vl,
4094 vl->pending_msg_head,
4095 vl->pending_msg_tail,
4097 check_vl_transmission (vl);
4102 * Communicator started. Test message is well-formed.
4104 * @param cls the client
4105 * @param cam the send message that was sent
4108 check_communicator_available (
4110 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4112 struct TransportClient *tc = cls;
4115 if (CT_NONE != tc->type)
4118 return GNUNET_SYSERR;
4120 tc->type = CT_COMMUNICATOR;
4121 size = ntohs (cam->header.size) - sizeof (*cam);
4123 return GNUNET_OK; /* receive-only communicator */
4124 GNUNET_MQ_check_zero_termination (cam);
4130 * Send ACK to communicator (if requested) and free @a cmc.
4132 * @param cmc context for which we are done handling the message
4135 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4137 if (0 != ntohl (cmc->im.fc_on))
4139 /* send ACK when done to communicator for flow control! */
4140 struct GNUNET_MQ_Envelope *env;
4141 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4143 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4144 ack->reserved = htonl (0);
4145 ack->fc_id = cmc->im.fc_id;
4146 ack->sender = cmc->im.sender;
4147 GNUNET_MQ_send (cmc->tc->mq, env);
4149 GNUNET_SERVICE_client_continue (cmc->tc->client);
4155 * Client confirms that it is done handling message(s) to a particular
4156 * peer. We may now provide more messages to CORE for this peer.
4158 * Notifies the respective queues that more messages can now be received.
4160 * @param cls the client
4161 * @param rom the message that was sent
4164 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4166 struct TransportClient *tc = cls;
4167 struct VirtualLink *vl;
4169 struct CommunicatorMessageContext *cmc;
4171 if (CT_CORE != tc->type)
4174 GNUNET_SERVICE_client_drop (tc->client);
4177 vl = lookup_virtual_link (&rom->peer);
4180 GNUNET_STATISTICS_update (GST_stats,
4181 "# RECV_OK dropped: virtual link unknown",
4184 GNUNET_SERVICE_client_continue (tc->client);
4187 delta = ntohl (rom->increase_window_delta);
4188 vl->core_recv_window += delta;
4189 if (vl->core_recv_window <= 0)
4191 /* resume communicators */
4192 while (NULL != (cmc = vl->cmc_tail))
4194 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4195 finish_cmc_handling (cmc);
4201 * Communicator started. Process the request.
4203 * @param cls the client
4204 * @param cam the send message that was sent
4207 handle_communicator_available (
4209 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4211 struct TransportClient *tc = cls;
4214 size = ntohs (cam->header.size) - sizeof (*cam);
4217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4218 "Receive-only communicator connected\n");
4219 return; /* receive-only communicator */
4221 tc->details.communicator.address_prefix =
4222 GNUNET_strdup ((const char *) &cam[1]);
4223 tc->details.communicator.cc =
4224 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4226 "Communicator with prefix `%s' connected\n",
4227 tc->details.communicator.address_prefix);
4228 GNUNET_SERVICE_client_continue (tc->client);
4233 * Communicator requests backchannel transmission. Check the request.
4235 * @param cls the client
4236 * @param cb the send message that was sent
4237 * @return #GNUNET_OK if message is well-formed
4240 check_communicator_backchannel (
4242 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4244 const struct GNUNET_MessageHeader *inbox;
4250 msize = ntohs (cb->header.size) - sizeof (*cb);
4251 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4252 isize = ntohs (inbox->size);
4256 return GNUNET_SYSERR;
4258 is = (const char *) inbox;
4261 GNUNET_assert (0 < msize);
4262 if ('\0' != is[msize - 1])
4265 return GNUNET_SYSERR;
4272 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4275 * @param dv[in,out] virtual link to update ephemeral for
4278 update_ephemeral (struct DistanceVector *dv)
4280 struct EphemeralConfirmationPS ec;
4283 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4285 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4286 dv->ephemeral_validity =
4287 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4288 GNUNET_assert (GNUNET_OK ==
4289 GNUNET_CRYPTO_ecdhe_key_create2 (&dv->private_key));
4290 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4291 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4292 ec.purpose.size = htonl (sizeof (ec));
4293 ec.target = dv->target;
4294 ec.ephemeral_key = dv->ephemeral_key;
4295 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4302 * Send the message @a payload on @a queue.
4304 * @param queue the queue to use for transmission
4305 * @param pm pending message to update once transmission is done, may be NULL!
4306 * @param payload the payload to send (encapsulated in a
4307 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4308 * @param payload_size number of bytes in @a payload
4311 queue_send_msg (struct Queue *queue,
4312 struct PendingMessage *pm,
4313 const void *payload,
4314 size_t payload_size)
4316 struct Neighbour *n = queue->neighbour;
4317 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4318 struct GNUNET_MQ_Envelope *env;
4320 queue->idle = GNUNET_NO;
4322 GNUNET_ERROR_TYPE_DEBUG,
4323 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4324 (unsigned int) payload_size,
4326 (unsigned long long) queue->qid,
4327 GNUNET_i2s (&queue->neighbour->pid));
4328 env = GNUNET_MQ_msg_extra (smt,
4330 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4331 smt->qid = queue->qid;
4332 smt->mid = queue->mid_gen;
4333 smt->receiver = n->pid;
4334 memcpy (&smt[1], payload, payload_size);
4336 /* Pass the env to the communicator of queue for transmission. */
4337 struct QueueEntry *qe;
4339 qe = GNUNET_new (struct QueueEntry);
4340 qe->mid = queue->mid_gen++;
4345 GNUNET_assert (NULL == pm->qe);
4348 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4349 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4350 queue->queue_length++;
4351 queue->tc->details.communicator.total_queue_length++;
4352 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4353 queue->tc->details.communicator.total_queue_length)
4354 queue->idle = GNUNET_NO;
4355 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4356 queue->idle = GNUNET_NO;
4357 GNUNET_MQ_send (queue->tc->mq, env);
4363 * Pick a queue of @a n under constraints @a options and schedule
4364 * transmission of @a hdr.
4366 * @param n neighbour to send to
4367 * @param hdr message to send as payload
4368 * @param options whether queues must be confirmed or not,
4369 * and whether we may pick multiple (2) queues
4372 route_via_neighbour (const struct Neighbour *n,
4373 const struct GNUNET_MessageHeader *hdr,
4374 enum RouteMessageOptions options)
4376 struct GNUNET_TIME_Absolute now;
4377 unsigned int candidates;
4381 /* Pick one or two 'random' queues from n (under constraints of options) */
4382 now = GNUNET_TIME_absolute_get ();
4383 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4384 weight in the future; weight could be assigned by observed
4385 bandwidth (note: not sure if we should do this for this type
4386 of control traffic though). */
4388 for (struct Queue *pos = n->queue_head; NULL != pos;
4389 pos = pos->next_neighbour)
4391 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4392 (pos->validated_until.abs_value_us > now.abs_value_us))
4395 if (0 == candidates)
4397 /* This can happen rarely if the last confirmed queue timed
4398 out just as we were beginning to process this message. */
4399 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4400 "Could not route message of type %u to %s: no valid queue\n",
4402 GNUNET_i2s (&n->pid));
4403 GNUNET_STATISTICS_update (GST_stats,
4404 "# route selection failed (all no valid queue)",
4410 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4411 if (0 == (options & RMO_REDUNDANT))
4412 sel2 = candidates; /* picks none! */
4414 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4416 for (struct Queue *pos = n->queue_head; NULL != pos;
4417 pos = pos->next_neighbour)
4419 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4420 (pos->validated_until.abs_value_us > now.abs_value_us))
4422 if ((sel1 == candidates) || (sel2 == candidates))
4424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4425 "Routing message of type %u to %s using %s (#%u)\n",
4427 GNUNET_i2s (&n->pid),
4429 (sel1 == candidates) ? 1 : 2);
4430 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4439 * Structure of the key material used to encrypt backchannel messages.
4444 * State of our block cipher.
4446 gcry_cipher_hd_t cipher;
4449 * Actual key material.
4455 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4457 struct GNUNET_CRYPTO_AuthKey hmac_key;
4460 * Symmetric key to use for encryption.
4462 char aes_key[256 / 8];
4465 * Counter value to use during setup.
4467 char aes_ctr[128 / 8];
4474 * Given the key material in @a km and the initialization vector
4475 * @a iv, setup the key material for the backchannel in @a key.
4477 * @param km raw master secret
4478 * @param iv initialization vector
4479 * @param key[out] symmetric cipher and HMAC state to generate
4482 dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4483 const struct GNUNET_ShortHashCode *iv,
4484 struct DVKeyState *key)
4486 /* must match #dh_key_derive_eph_pub */
4487 GNUNET_assert (GNUNET_YES ==
4488 GNUNET_CRYPTO_kdf (&key->material,
4489 sizeof (key->material),
4490 "transport-backchannel-key",
4491 strlen ("transport-backchannel-key"),
4496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4497 "Deriving backchannel key based on KM %s and IV %s\n",
4500 gcry_cipher_open (&key->cipher,
4501 GCRY_CIPHER_AES256 /* low level: go for speed */,
4502 GCRY_CIPHER_MODE_CTR,
4504 gcry_cipher_setkey (key->cipher,
4505 &key->material.aes_key,
4506 sizeof (key->material.aes_key));
4507 gcry_cipher_setctr (key->cipher,
4508 &key->material.aes_ctr,
4509 sizeof (key->material.aes_ctr));
4514 * Derive backchannel encryption key material from @a priv_ephemeral
4515 * and @a target and @a iv.
4517 * @param priv_ephemeral ephemeral private key to use
4518 * @param target the target peer to encrypt to
4519 * @param iv unique IV to use
4520 * @param key[out] set to the key material
4523 dh_key_derive_eph_pid (
4524 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4525 const struct GNUNET_PeerIdentity *target,
4526 const struct GNUNET_ShortHashCode *iv,
4527 struct DVKeyState *key)
4529 struct GNUNET_HashCode km;
4531 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4532 &target->public_key,
4534 dv_setup_key_state_from_km (&km, iv, key);
4539 * Derive backchannel encryption key material from #GST_my_private_key
4540 * and @a pub_ephemeral and @a iv.
4542 * @param priv_ephemeral ephemeral private key to use
4543 * @param target the target peer to encrypt to
4544 * @param iv unique IV to use
4545 * @param key[out] set to the key material
4548 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4549 const struct GNUNET_ShortHashCode *iv,
4550 struct DVKeyState *key)
4552 struct GNUNET_HashCode km;
4554 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4557 dv_setup_key_state_from_km (&km, iv, key);
4562 * Do HMAC calculation for backchannel messages over @a data using key
4563 * material from @a key.
4565 * @param key key material (from DH)
4566 * @param hmac[out] set to the HMAC
4567 * @param data data to perform HMAC calculation over
4568 * @param data_size number of bytes in @a data
4571 dv_hmac (const struct DVKeyState *key,
4572 struct GNUNET_HashCode *hmac,
4576 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4581 * Perform backchannel encryption using symmetric secret in @a key
4582 * to encrypt data from @a in to @a dst.
4584 * @param key[in,out] key material to use
4585 * @param dst where to write the result
4586 * @param in input data to encrypt (plaintext)
4587 * @param in_size number of bytes of input in @a in and available at @a dst
4590 dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4593 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4598 * Perform backchannel encryption using symmetric secret in @a key
4599 * to encrypt data from @a in to @a dst.
4601 * @param key[in,out] key material to use
4602 * @param ciph cipher text to decrypt
4603 * @param out[out] output data to generate (plaintext)
4604 * @param out_size number of bytes of input in @a ciph and available in @a out
4607 dv_decrypt (struct DVKeyState *key,
4613 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4618 * Clean up key material in @a key.
4620 * @param key key material to clean up (memory must not be free'd!)
4623 dv_key_clean (struct DVKeyState *key)
4625 gcry_cipher_close (key->cipher);
4626 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4631 * Function to call to further operate on the now DV encapsulated
4632 * message @a hdr, forwarding it via @a next_hop under respect of
4635 * @param cls closure
4636 * @param next_hop next hop of the DV path
4637 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4638 * @param options options of the original message
4640 typedef void (*DVMessageHandler) (void *cls,
4641 struct Neighbour *next_hop,
4642 const struct GNUNET_MessageHeader *hdr,
4643 enum RouteMessageOptions options);
4646 * Pick a path of @a dv under constraints @a options and schedule
4647 * transmission of @a hdr.
4649 * @param target neighbour to ultimately send to
4650 * @param num_dvhs length of the @a dvhs array
4651 * @param dvhs array of hops to send the message to
4652 * @param hdr message to send as payload
4653 * @param use function to call with the encapsulated message
4654 * @param use_cls closure for @a use
4655 * @param options whether path must be confirmed or not, to be passed to @a use
4658 encapsulate_for_dv (struct DistanceVector *dv,
4659 unsigned int num_dvhs,
4660 struct DistanceVectorHop **dvhs,
4661 const struct GNUNET_MessageHeader *hdr,
4662 DVMessageHandler use,
4664 enum RouteMessageOptions options)
4666 struct TransportDVBoxMessage box_hdr;
4667 struct TransportDVBoxPayloadP payload_hdr;
4668 uint16_t enc_body_size = ntohs (hdr->size);
4669 char enc[sizeof (struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4670 struct TransportDVBoxPayloadP *enc_payload_hdr =
4671 (struct TransportDVBoxPayloadP *) enc;
4672 struct DVKeyState key;
4674 /* Encrypt payload */
4675 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4676 box_hdr.total_hops = htons (0);
4677 update_ephemeral (dv);
4678 box_hdr.ephemeral_key = dv->ephemeral_key;
4679 payload_hdr.sender_sig = dv->sender_sig;
4680 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4682 sizeof (box_hdr.iv));
4683 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, &key);
4684 payload_hdr.sender = GST_my_identity;
4685 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4686 dv_encrypt (&key, &payload_hdr, enc_payload_hdr, sizeof (payload_hdr));
4689 &enc[sizeof (struct TransportDVBoxPayloadP)],
4691 dv_hmac (&key, &box_hdr.hmac, enc, sizeof (enc));
4692 dv_key_clean (&key);
4694 /* For each selected path, take the pre-computed header and body
4695 and add the path in the middle of the message; then send it. */
4696 for (unsigned int i = 0; i < num_dvhs; i++)
4698 struct DistanceVectorHop *dvh = dvhs[i];
4699 unsigned int num_hops = dvh->distance + 1;
4700 char buf[sizeof (struct TransportDVBoxMessage) +
4701 sizeof (struct GNUNET_PeerIdentity) * num_hops +
4702 sizeof (struct TransportDVBoxPayloadP) +
4703 enc_body_size] GNUNET_ALIGN;
4704 struct GNUNET_PeerIdentity *dhops;
4706 box_hdr.header.size = htons (sizeof (buf));
4707 box_hdr.num_hops = htons (num_hops);
4708 memcpy (buf, &box_hdr, sizeof (box_hdr));
4709 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof (box_hdr)];
4712 dvh->distance * sizeof (struct GNUNET_PeerIdentity));
4713 dhops[dvh->distance] = dv->target;
4714 if (GNUNET_EXTRA_LOGGING > 0)
4718 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4719 for (unsigned int i = 0; i <= num_hops; i++)
4723 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
4727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4728 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4730 GNUNET_i2s (&dv->target),
4737 memcpy (&dhops[num_hops], enc, sizeof (enc));
4740 (const struct GNUNET_MessageHeader *) buf,
4747 * Wrapper around #route_via_neighbour() that matches the
4748 * #DVMessageHandler structure.
4751 * @param next_hop where to send next
4752 * @param hdr header of the message to send
4753 * @param options message options for queue selection
4756 send_dv_to_neighbour (void *cls,
4757 struct Neighbour *next_hop,
4758 const struct GNUNET_MessageHeader *hdr,
4759 enum RouteMessageOptions options)
4762 route_via_neighbour (next_hop, hdr, options);
4767 * We need to transmit @a hdr to @a target. If necessary, this may
4768 * involve DV routing. This function routes without applying flow
4769 * control or congestion control and should only be used for control
4772 * @param target peer to receive @a hdr
4773 * @param hdr header of the message to route and #GNUNET_free()
4774 * @param options which transmission channels are allowed
4777 route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4778 const struct GNUNET_MessageHeader *hdr,
4779 enum RouteMessageOptions options)
4781 struct VirtualLink *vl;
4782 struct Neighbour *n;
4783 struct DistanceVector *dv;
4785 vl = lookup_virtual_link (target);
4787 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4788 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4790 /* if confirmed is required, and we do not have anything
4791 confirmed, drop respective options */
4793 n = lookup_neighbour (target);
4794 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4795 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4797 if ((NULL == n) && (NULL == dv))
4799 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4800 "Cannot route message of type %u to %s: no route\n",
4802 GNUNET_i2s (target));
4803 GNUNET_STATISTICS_update (GST_stats,
4804 "# Messages dropped in routing: no acceptable method",
4809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4810 "Routing message of type %u to %s with options %X\n",
4812 GNUNET_i2s (target),
4813 (unsigned int) options);
4814 /* If both dv and n are possible and we must choose:
4815 flip a coin for the choice between the two; for now 50/50 */
4816 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4818 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4823 if ((NULL != n) && (NULL != dv))
4824 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4825 enough for redunancy, so clear the flag. */
4828 route_via_neighbour (n, hdr, options);
4832 struct DistanceVectorHop *hops[2];
4835 res = pick_random_dv_hops (dv,
4838 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4841 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4842 "Failed to route message, could not determine DV path\n");
4845 encapsulate_for_dv (dv,
4849 &send_dv_to_neighbour,
4851 options & (~RMO_REDUNDANT));
4857 * Communicator requests backchannel transmission. Process the request.
4858 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
4859 * (which for now has exactly the same format, only a different message type)
4860 * and passes it on for routing.
4862 * @param cls the client
4863 * @param cb the send message that was sent
4866 handle_communicator_backchannel (
4868 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4870 struct TransportClient *tc = cls;
4871 const struct GNUNET_MessageHeader *inbox =
4872 (const struct GNUNET_MessageHeader *) &cb[1];
4873 uint16_t isize = ntohs (inbox->size);
4874 const char *is = ((const char *) &cb[1]) + isize;
4877 sizeof (struct TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
4878 struct TransportBackchannelEncapsulationMessage *be =
4879 (struct TransportBackchannelEncapsulationMessage *) mbuf;
4881 /* 0-termination of 'is' was checked already in
4882 #check_communicator_backchannel() */
4883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4884 "Preparing backchannel transmission to %s:%s of type %u\n",
4885 GNUNET_i2s (&cb->pid),
4887 ntohs (inbox->size));
4888 /* encapsulate and encrypt message */
4890 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4891 be->header.size = htons (sizeof (mbuf));
4892 memcpy (&be[1], inbox, isize);
4893 memcpy (&mbuf[sizeof (struct TransportBackchannelEncapsulationMessage) +
4897 route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
4898 GNUNET_SERVICE_client_continue (tc->client);
4903 * Address of our peer added. Test message is well-formed.
4905 * @param cls the client
4906 * @param aam the send message that was sent
4907 * @return #GNUNET_OK if message is well-formed
4910 check_add_address (void *cls,
4911 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4913 struct TransportClient *tc = cls;
4915 if (CT_COMMUNICATOR != tc->type)
4918 return GNUNET_SYSERR;
4920 GNUNET_MQ_check_zero_termination (aam);
4926 * Ask peerstore to store our address.
4928 * @param cls an `struct AddressListEntry *`
4931 store_pi (void *cls);
4935 * Function called when peerstore is done storing our address.
4937 * @param cls a `struct AddressListEntry`
4938 * @param success #GNUNET_YES if peerstore was successful
4941 peerstore_store_own_cb (void *cls, int success)
4943 struct AddressListEntry *ale = cls;
4946 if (GNUNET_YES != success)
4947 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4948 "Failed to store our own address `%s' in peerstore!\n",
4951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4952 "Successfully stored our own address `%s' in peerstore!\n",
4954 /* refresh period is 1/4 of expiration time, that should be plenty
4955 without being excessive. */
4957 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4965 * Ask peerstore to store our address.
4967 * @param cls an `struct AddressListEntry *`
4970 store_pi (void *cls)
4972 struct AddressListEntry *ale = cls;
4975 struct GNUNET_TIME_Absolute expiration;
4978 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4980 "Storing our address `%s' in peerstore until %s!\n",
4982 GNUNET_STRINGS_absolute_time_to_string (expiration));
4983 GNUNET_HELLO_sign_address (ale->address,
4989 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4992 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4996 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4997 &peerstore_store_own_cb,
5000 if (NULL == ale->sc)
5002 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5003 "Failed to store our address `%s' with peerstore\n",
5006 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5012 * Address of our peer added. Process the request.
5014 * @param cls the client
5015 * @param aam the send message that was sent
5018 handle_add_address (void *cls,
5019 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5021 struct TransportClient *tc = cls;
5022 struct AddressListEntry *ale;
5025 /* 0-termination of &aam[1] was checked in #check_add_address */
5026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5027 "Communicator added address `%s'!\n",
5028 (const char *) &aam[1]);
5029 slen = ntohs (aam->header.size) - sizeof (*aam);
5030 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
5032 ale->address = (const char *) &ale[1];
5033 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5034 ale->aid = aam->aid;
5035 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5036 memcpy (&ale[1], &aam[1], slen);
5037 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5038 tc->details.communicator.addr_tail,
5040 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5041 GNUNET_SERVICE_client_continue (tc->client);
5046 * Address of our peer deleted. Process the request.
5048 * @param cls the client
5049 * @param dam the send message that was sent
5052 handle_del_address (void *cls,
5053 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5055 struct TransportClient *tc = cls;
5057 if (CT_COMMUNICATOR != tc->type)
5060 GNUNET_SERVICE_client_drop (tc->client);
5063 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5067 if (dam->aid != ale->aid)
5069 GNUNET_assert (ale->tc == tc);
5070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5071 "Communicator deleted address `%s'!\n",
5073 free_address_list_entry (ale);
5074 GNUNET_SERVICE_client_continue (tc->client);
5077 GNUNET_SERVICE_client_drop (tc->client);
5082 * Given an inbound message @a msg from a communicator @a cmc,
5083 * demultiplex it based on the type calling the right handler.
5085 * @param cmc context for demultiplexing
5086 * @param msg message to demultiplex
5089 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5090 const struct GNUNET_MessageHeader *msg);
5094 * Function called when we are done giving a message of a certain
5095 * size to CORE and should thus decrement the number of bytes of
5096 * RAM reserved for that peer's MQ.
5098 * @param cls a `struct CoreSentContext`
5101 core_env_sent_cb (void *cls)
5103 struct CoreSentContext *ctx = cls;
5104 struct VirtualLink *vl = ctx->vl;
5108 /* lost the link in the meantime, ignore */
5112 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5113 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5114 vl->incoming_fc_window_size_ram -= ctx->size;
5115 vl->incoming_fc_window_size_used += ctx->isize;
5122 * Communicator gave us an unencapsulated message to pass as-is to
5123 * CORE. Process the request.
5125 * @param cls a `struct CommunicatorMessageContext` (must call
5126 * #finish_cmc_handling() when done)
5127 * @param mh the message that was received
5130 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5132 struct CommunicatorMessageContext *cmc = cls;
5133 struct VirtualLink *vl;
5134 uint16_t size = ntohs (mh->size);
5137 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
5138 (size < sizeof (struct GNUNET_MessageHeader)))
5140 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5143 finish_cmc_handling (cmc);
5144 GNUNET_SERVICE_client_drop (client);
5147 vl = lookup_virtual_link (&cmc->im.sender);
5150 /* FIXME: sender is giving us messages for CORE but we don't have
5151 the link up yet! I *suspect* this can happen right now (i.e.
5152 sender has verified us, but we didn't verify sender), but if
5153 we pass this on, CORE would be confused (link down, messages
5154 arrive). We should investigate more if this happens often,
5155 or in a persistent manner, and possibly do "something" about
5156 it. Thus logging as error for now. */
5157 GNUNET_break_op (0);
5158 GNUNET_STATISTICS_update (GST_stats,
5159 "# CORE messages droped (virtual link still down)",
5163 finish_cmc_handling (cmc);
5166 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5168 GNUNET_STATISTICS_update (GST_stats,
5169 "# CORE messages droped (FC arithmetic overflow)",
5173 finish_cmc_handling (cmc);
5176 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5178 GNUNET_STATISTICS_update (GST_stats,
5179 "# CORE messages droped (FC window overflow)",
5182 finish_cmc_handling (cmc);
5186 /* Forward to all CORE clients */
5187 have_core = GNUNET_NO;
5188 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5190 struct GNUNET_MQ_Envelope *env;
5191 struct InboundMessage *im;
5192 struct CoreSentContext *ctx;
5194 if (CT_CORE != tc->type)
5196 vl->incoming_fc_window_size_ram += size;
5197 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5198 ctx = GNUNET_new (struct CoreSentContext);
5201 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5202 have_core = GNUNET_YES;
5203 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5204 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5205 im->peer = cmc->im.sender;
5206 memcpy (&im[1], mh, size);
5207 GNUNET_MQ_send (tc->mq, env);
5208 vl->core_recv_window--;
5210 if (GNUNET_NO == have_core)
5212 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5213 "Dropped message to CORE: no CORE client connected!\n");
5214 /* Nevertheless, count window as used, as it is from the
5215 perspective of the other peer! */
5216 vl->incoming_fc_window_size_used += size;
5218 finish_cmc_handling (cmc);
5221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5222 "Delivered message from %s of type %u to CORE\n",
5223 GNUNET_i2s (&cmc->im.sender),
5225 if (vl->core_recv_window > 0)
5227 finish_cmc_handling (cmc);
5230 /* Wait with calling #finish_cmc_handling(cmc) until the message
5231 was processed by CORE MQs (for CORE flow control)! */
5232 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5237 * Communicator gave us a fragment box. Check the message.
5239 * @param cls a `struct CommunicatorMessageContext`
5240 * @param fb the send message that was sent
5241 * @return #GNUNET_YES if message is well-formed
5244 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5246 uint16_t size = ntohs (fb->header.size);
5247 uint16_t bsize = size - sizeof (*fb);
5252 GNUNET_break_op (0);
5253 return GNUNET_SYSERR;
5255 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5257 GNUNET_break_op (0);
5258 return GNUNET_SYSERR;
5260 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5262 GNUNET_break_op (0);
5263 return GNUNET_SYSERR;
5270 * Clean up an idle cummulative acknowledgement data structure.
5272 * @param cls a `struct AcknowledgementCummulator *`
5275 destroy_ack_cummulator (void *cls)
5277 struct AcknowledgementCummulator *ac = cls;
5280 GNUNET_assert (0 == ac->num_acks);
5283 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5289 * Do the transmission of a cummulative acknowledgement now.
5291 * @param cls a `struct AcknowledgementCummulator *`
5294 transmit_cummulative_ack_cb (void *cls)
5296 struct AcknowledgementCummulator *ac = cls;
5297 char buf[sizeof (struct TransportReliabilityAckMessage) +
5299 sizeof (struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5300 struct TransportReliabilityAckMessage *ack =
5301 (struct TransportReliabilityAckMessage *) buf;
5302 struct TransportCummulativeAckPayloadP *ap;
5305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5306 "Sending ACK with %u components to %s\n",
5308 GNUNET_i2s (&ac->target));
5309 GNUNET_assert (0 < ac->ack_counter);
5310 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5312 htons (sizeof (*ack) +
5313 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
5314 ack->ack_counter = htonl (ac->ack_counter++);
5315 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5316 for (unsigned int i = 0; i < ac->ack_counter; i++)
5318 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5319 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5320 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5322 route_control_message_without_fc (&ac->target, &ack->header, RMO_DV_ALLOWED);
5324 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5325 &destroy_ack_cummulator,
5331 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5332 * transmission by at most @a ack_delay.
5334 * @param pid target peer
5335 * @param ack_uuid UUID to ack
5336 * @param max_delay how long can the ACK wait
5339 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5340 const struct AcknowledgementUUIDP *ack_uuid,
5341 struct GNUNET_TIME_Absolute max_delay)
5343 struct AcknowledgementCummulator *ac;
5345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5346 "Scheduling ACK %s for transmission to %s\n",
5347 GNUNET_sh2s (&ack_uuid->value),
5349 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5352 ac = GNUNET_new (struct AcknowledgementCummulator);
5354 ac->min_transmission_time = max_delay;
5355 GNUNET_assert (GNUNET_YES ==
5356 GNUNET_CONTAINER_multipeermap_put (
5360 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5364 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5366 /* must run immediately, ack buffer full! */
5367 GNUNET_SCHEDULER_cancel (ac->task);
5368 transmit_cummulative_ack_cb (ac);
5370 GNUNET_SCHEDULER_cancel (ac->task);
5371 ac->min_transmission_time =
5372 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5374 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5375 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5376 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5378 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5379 &transmit_cummulative_ack_cb,
5385 * Closure for #find_by_message_uuid.
5387 struct FindByMessageUuidContext
5392 struct MessageUUIDP message_uuid;
5395 * Set to the reassembly context if found.
5397 struct ReassemblyContext *rc;
5402 * Iterator called to find a reassembly context by the message UUID in the
5405 * @param cls a `struct FindByMessageUuidContext`
5406 * @param key a key (unused)
5407 * @param value a `struct ReassemblyContext`
5408 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5411 find_by_message_uuid (void *cls, uint32_t key, void *value)
5413 struct FindByMessageUuidContext *fc = cls;
5414 struct ReassemblyContext *rc = value;
5417 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5427 * Communicator gave us a fragment. Process the request.
5429 * @param cls a `struct CommunicatorMessageContext` (must call
5430 * #finish_cmc_handling() when done)
5431 * @param fb the message that was received
5434 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5436 struct CommunicatorMessageContext *cmc = cls;
5437 struct Neighbour *n;
5438 struct ReassemblyContext *rc;
5439 const struct GNUNET_MessageHeader *msg;
5444 struct GNUNET_TIME_Relative cdelay;
5445 struct FindByMessageUuidContext fc;
5447 n = lookup_neighbour (&cmc->im.sender);
5450 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5453 finish_cmc_handling (cmc);
5454 GNUNET_SERVICE_client_drop (client);
5457 if (NULL == n->reassembly_map)
5459 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5460 n->reassembly_heap =
5461 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5462 n->reassembly_timeout_task =
5463 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5464 &reassembly_cleanup_task,
5467 msize = ntohs (fb->msg_size);
5468 fc.message_uuid = fb->msg_uuid;
5470 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5472 &find_by_message_uuid,
5474 if (NULL == (rc = fc.rc))
5476 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5477 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5478 rc->msg_uuid = fb->msg_uuid;
5480 rc->msg_size = msize;
5481 rc->reassembly_timeout =
5482 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5483 rc->last_frag = GNUNET_TIME_absolute_get ();
5484 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5486 rc->reassembly_timeout.abs_value_us);
5487 GNUNET_assert (GNUNET_OK ==
5488 GNUNET_CONTAINER_multihashmap32_put (
5492 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5493 target = (char *) &rc[1];
5494 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5495 rc->msg_missing = rc->msg_size;
5496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5497 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5498 ntohs (fb->frag_off),
5500 GNUNET_i2s (&cmc->im.sender),
5501 (unsigned int) fb->msg_uuid.uuid);
5505 target = (char *) &rc[1];
5506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5507 "Received fragment at offset %u/%u from %s for message %u\n",
5508 ntohs (fb->frag_off),
5510 GNUNET_i2s (&cmc->im.sender),
5511 (unsigned int) fb->msg_uuid.uuid);
5513 if (msize != rc->msg_size)
5516 finish_cmc_handling (cmc);
5521 fsize = ntohs (fb->header.size) - sizeof (*fb);
5525 finish_cmc_handling (cmc);
5528 frag_off = ntohs (fb->frag_off);
5529 memcpy (&target[frag_off], &fb[1], fsize);
5530 /* update bitfield and msg_missing */
5531 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5533 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5535 rc->bitfield[i / 8] |= (1 << (i % 8));
5540 /* Compute cummulative ACK */
5541 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5542 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5543 if (0 == rc->msg_missing)
5544 cdelay = GNUNET_TIME_UNIT_ZERO;
5545 cummulative_ack (&cmc->im.sender,
5547 GNUNET_TIME_relative_to_absolute (cdelay));
5548 rc->last_frag = GNUNET_TIME_absolute_get ();
5549 /* is reassembly complete? */
5550 if (0 != rc->msg_missing)
5552 finish_cmc_handling (cmc);
5555 /* reassembly is complete, verify result */
5556 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5557 if (ntohs (msg->size) != rc->msg_size)
5560 free_reassembly_context (rc);
5561 finish_cmc_handling (cmc);
5564 /* successful reassembly */
5565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5566 "Fragment reassembly complete for message %u\n",
5567 (unsigned int) fb->msg_uuid.uuid);
5568 /* FIXME: check that the resulting msg is NOT a
5569 DV Box or Reliability Box, as that is NOT allowed! */
5570 demultiplex_with_cmc (cmc, msg);
5571 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5572 en-route and we forget that we finished this reassembly immediately!
5573 -> keep around until timeout?
5574 -> shorten timeout based on ACK? */
5575 free_reassembly_context (rc);
5580 * Communicator gave us a reliability box. Check the message.
5582 * @param cls a `struct CommunicatorMessageContext`
5583 * @param rb the send message that was sent
5584 * @return #GNUNET_YES if message is well-formed
5587 check_reliability_box (void *cls,
5588 const struct TransportReliabilityBoxMessage *rb)
5591 GNUNET_MQ_check_boxed_message (rb);
5597 * Communicator gave us a reliability box. Process the request.
5599 * @param cls a `struct CommunicatorMessageContext` (must call
5600 * #finish_cmc_handling() when done)
5601 * @param rb the message that was received
5604 handle_reliability_box (void *cls,
5605 const struct TransportReliabilityBoxMessage *rb)
5607 struct CommunicatorMessageContext *cmc = cls;
5608 const struct GNUNET_MessageHeader *inbox =
5609 (const struct GNUNET_MessageHeader *) &rb[1];
5610 struct GNUNET_TIME_Relative rtt;
5612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5613 "Received reliability box from %s with UUID %s of type %u\n",
5614 GNUNET_i2s (&cmc->im.sender),
5615 GNUNET_sh2s (&rb->ack_uuid.value),
5616 (unsigned int) ntohs (inbox->type));
5617 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5618 do not really have an RTT for the
5619 *incoming* queue (should we have
5620 the sender add it to the rb message?) */
5624 (0 == ntohl (rb->ack_countdown))
5625 ? GNUNET_TIME_UNIT_ZERO_ABS
5626 : GNUNET_TIME_relative_to_absolute (
5627 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5628 /* continue with inner message */
5629 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5630 reliability box (not allowed!) */
5631 demultiplex_with_cmc (cmc, inbox);
5636 * Check if we have advanced to another age since the last time. If
5637 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5640 * @param pd[in,out] data to update
5641 * @param age current age
5644 update_pd_age (struct PerformanceData *pd, unsigned int age)
5648 if (age == pd->last_age)
5649 return; /* nothing to do */
5650 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5651 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5653 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5655 the->bytes_sent = 0;
5656 the->bytes_received = 0;
5663 * Update @a pd based on the latest @a rtt and the number of bytes
5664 * that were confirmed to be successfully transmitted.
5666 * @param pd[in,out] data to update
5667 * @param rtt latest round-trip time
5668 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5671 update_performance_data (struct PerformanceData *pd,
5672 struct GNUNET_TIME_Relative rtt,
5673 uint16_t bytes_transmitted_ok)
5675 uint64_t nval = rtt.rel_value_us;
5676 uint64_t oval = pd->aged_rtt.rel_value_us;
5677 unsigned int age = get_age ();
5678 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5680 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5683 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5684 update_pd_age (pd, age);
5685 the->bytes_received += bytes_transmitted_ok;
5690 * We have successfully transmitted data via @a q, update metrics.
5692 * @param q queue to update
5693 * @param rtt round trip time observed
5694 * @param bytes_transmitted_ok number of bytes successfully transmitted
5697 update_queue_performance (struct Queue *q,
5698 struct GNUNET_TIME_Relative rtt,
5699 uint16_t bytes_transmitted_ok)
5701 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5706 * We have successfully transmitted data via @a dvh, update metrics.
5708 * @param dvh distance vector path data to update
5709 * @param rtt round trip time observed
5710 * @param bytes_transmitted_ok number of bytes successfully transmitted
5713 update_dvh_performance (struct DistanceVectorHop *dvh,
5714 struct GNUNET_TIME_Relative rtt,
5715 uint16_t bytes_transmitted_ok)
5717 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5722 * We have completed transmission of @a pm, remove it from
5723 * the transmission queues (and if it is a fragment, continue
5724 * up the tree as necessary).
5726 * @param pm pending message that was transmitted
5729 completed_pending_message (struct PendingMessage *pm)
5731 struct PendingMessage *pos;
5736 case PMT_RELIABILITY_BOX:
5737 /* Full message sent, we are done */
5738 client_send_response (pm);
5740 case PMT_FRAGMENT_BOX:
5741 /* Fragment sent over reliabile channel */
5742 free_fragment_tree (pm);
5743 pos = pm->frag_parent;
5744 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5746 /* check if subtree is done */
5747 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5751 pos = pm->frag_parent;
5752 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5756 /* Was this the last applicable fragmment? */
5757 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
5758 (pos->frag_off == pos->bytes_msg))
5759 client_send_response (pos);
5762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5763 "Completed transmission of message %llu (DV Box)\n",
5765 free_pending_message (pm);
5772 * The @a pa was acknowledged, process the acknowledgement.
5774 * @param pa the pending acknowledgement that was satisfied
5775 * @param ack_delay artificial delay from cummulative acks created by the
5779 handle_acknowledged (struct PendingAcknowledgement *pa,
5780 struct GNUNET_TIME_Relative ack_delay)
5782 struct GNUNET_TIME_Relative delay;
5784 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5785 if (delay.rel_value_us > ack_delay.rel_value_us)
5786 delay = GNUNET_TIME_UNIT_ZERO;
5788 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5789 if (NULL != pa->queue)
5790 update_queue_performance (pa->queue, delay, pa->message_size);
5791 if (NULL != pa->dvh)
5792 update_dvh_performance (pa->dvh, delay, pa->message_size);
5794 completed_pending_message (pa->pm);
5795 free_pending_acknowledgement (pa);
5800 * Communicator gave us a reliability ack. Check it is well-formed.
5802 * @param cls a `struct CommunicatorMessageContext` (unused)
5803 * @param ra the message that was received
5804 * @return #GNUNET_Ok if @a ra is well-formed
5807 check_reliability_ack (void *cls,
5808 const struct TransportReliabilityAckMessage *ra)
5810 unsigned int n_acks;
5813 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5814 sizeof (struct TransportCummulativeAckPayloadP);
5817 GNUNET_break_op (0);
5818 return GNUNET_SYSERR;
5820 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5821 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5823 GNUNET_break_op (0);
5824 return GNUNET_SYSERR;
5831 * Communicator gave us a reliability ack. Process the request.
5833 * @param cls a `struct CommunicatorMessageContext` (must call
5834 * #finish_cmc_handling() when done)
5835 * @param ra the message that was received
5838 handle_reliability_ack (void *cls,
5839 const struct TransportReliabilityAckMessage *ra)
5841 struct CommunicatorMessageContext *cmc = cls;
5842 const struct TransportCummulativeAckPayloadP *ack;
5843 struct PendingAcknowledgement *pa;
5844 unsigned int n_acks;
5845 uint32_t ack_counter;
5847 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5848 sizeof (struct TransportCummulativeAckPayloadP);
5849 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5850 for (unsigned int i = 0; i < n_acks; i++)
5853 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5856 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5857 "Received ACK from %s with UUID %s which is unknown to us!\n",
5858 GNUNET_i2s (&cmc->im.sender),
5859 GNUNET_sh2s (&ack[i].ack_uuid.value));
5860 GNUNET_STATISTICS_update (
5862 "# FRAGMENT_ACKS dropped, no matching pending message",
5867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5868 "Received ACK from %s with UUID %s\n",
5869 GNUNET_i2s (&cmc->im.sender),
5870 GNUNET_sh2s (&ack[i].ack_uuid.value));
5871 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5874 ack_counter = htonl (ra->ack_counter);
5875 (void) ack_counter; /* silence compiler warning for now */
5876 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5877 // (DV and/or Neighbour?)
5878 finish_cmc_handling (cmc);
5883 * Communicator gave us a backchannel encapsulation. Check the message.
5885 * @param cls a `struct CommunicatorMessageContext`
5886 * @param be the send message that was sent
5887 * @return #GNUNET_YES if message is well-formed
5890 check_backchannel_encapsulation (
5892 const struct TransportBackchannelEncapsulationMessage *be)
5894 uint16_t size = ntohs (be->header.size) - sizeof (*be);
5895 const struct GNUNET_MessageHeader *inbox =
5896 (const struct GNUNET_MessageHeader *) &be[1];
5901 if (ntohs (inbox->size) >= size)
5903 GNUNET_break_op (0);
5904 return GNUNET_SYSERR;
5906 isize = ntohs (inbox->size);
5907 is = ((const char *) inbox) + isize;
5909 if ('\0' != is[size - 1])
5911 GNUNET_break_op (0);
5912 return GNUNET_SYSERR;
5919 * Communicator gave us a backchannel encapsulation. Process the request.
5920 * (We are the destination of the backchannel here.)
5922 * @param cls a `struct CommunicatorMessageContext` (must call
5923 * #finish_cmc_handling() when done)
5924 * @param be the message that was received
5927 handle_backchannel_encapsulation (
5929 const struct TransportBackchannelEncapsulationMessage *be)
5931 struct CommunicatorMessageContext *cmc = cls;
5932 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5933 struct GNUNET_MQ_Envelope *env;
5934 struct TransportClient *tc;
5935 const struct GNUNET_MessageHeader *inbox =
5936 (const struct GNUNET_MessageHeader *) &be[1];
5937 uint16_t isize = ntohs (inbox->size);
5938 const char *target_communicator = ((const char *) inbox) + isize;
5940 /* Find client providing this communicator */
5941 for (tc = clients_head; NULL != tc; tc = tc->next)
5942 if ((CT_COMMUNICATOR == tc->type) &&
5944 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5952 "# Backchannel message dropped: target communicator `%s' unknown",
5953 target_communicator);
5954 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5955 GNUNET_free (stastr);
5958 /* Finally, deliver backchannel message to communicator */
5959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5960 "Delivering backchannel message from %s of type %u to %s\n",
5961 GNUNET_i2s (&cmc->im.sender),
5962 ntohs (inbox->type),
5963 target_communicator);
5964 env = GNUNET_MQ_msg_extra (
5967 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5968 cbi->pid = cmc->im.sender;
5969 memcpy (&cbi[1], inbox, isize);
5970 GNUNET_MQ_send (tc->mq, env);
5975 * Task called when we should check if any of the DV paths
5976 * we have learned to a target are due for garbage collection.
5978 * Collects stale paths, and possibly frees the entire DV
5979 * entry if no paths are left. Otherwise re-schedules itself.
5981 * @param cls a `struct DistanceVector`
5984 path_cleanup_cb (void *cls)
5986 struct DistanceVector *dv = cls;
5987 struct DistanceVectorHop *pos;
5989 dv->timeout_task = NULL;
5990 while (NULL != (pos = dv->dv_head))
5992 GNUNET_assert (dv == pos->dv);
5993 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5995 free_distance_vector_hop (pos);
6003 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6008 * The @a hop is a validated path to the respective target
6009 * peer and we should tell core about it -- and schedule
6010 * a job to revoke the state.
6012 * @param hop a path to some peer that is the reason for activation
6015 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6017 struct DistanceVector *dv = hop->dv;
6018 struct VirtualLink *vl;
6020 vl = lookup_virtual_link (&dv->target);
6023 /* Link was already up, remember dv is also now available and we are done */
6025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6026 "Virtual link to %s could now also use DV!\n",
6027 GNUNET_i2s (&dv->target));
6030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6031 "Creating new virtual link to %s using DV!\n",
6032 GNUNET_i2s (&dv->target));
6033 vl = GNUNET_new (struct VirtualLink);
6034 vl->message_uuid_ctr =
6035 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6036 vl->target = dv->target;
6039 vl->core_recv_window = RECV_WINDOW_SIZE;
6040 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6041 vl->visibility_task =
6042 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6043 GNUNET_break (GNUNET_YES ==
6044 GNUNET_CONTAINER_multipeermap_put (
6048 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6049 /* We lacked a confirmed connection to the target
6050 before, so tell CORE about it (finally!) */
6051 cores_send_connect_info (&dv->target);
6056 * We have learned a @a path through the network to some other peer, add it to
6057 * our DV data structure (returning #GNUNET_YES on success).
6059 * We do not add paths if we have a sufficient number of shorter
6060 * paths to this target already (returning #GNUNET_NO).
6062 * We also do not add problematic paths, like those where we lack the first
6063 * hop in our neighbour list (i.e. due to a topology change) or where some
6064 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6066 * @param path the path we learned, path[0] should be us,
6067 * and then path contains a valid path from us to
6068 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6069 * @param path_len number of entries on the @a path, at least three!
6070 * @param network_latency how long does the message take from us to
6071 * `path[path_len-1]`? set to "forever" if unknown
6072 * @param path_valid_until how long is this path considered validated? Maybe
6074 * @return #GNUNET_YES on success,
6075 * #GNUNET_NO if we have better path(s) to the target
6076 * #GNUNET_SYSERR if the path is useless and/or invalid
6077 * (i.e. path[1] not a direct neighbour
6078 * or path[i+1] is a direct neighbour for i>0)
6081 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6082 unsigned int path_len,
6083 struct GNUNET_TIME_Relative network_latency,
6084 struct GNUNET_TIME_Absolute path_valid_until)
6086 struct DistanceVectorHop *hop;
6087 struct DistanceVector *dv;
6088 struct Neighbour *next_hop;
6089 unsigned int shorter_distance;
6093 /* what a boring path! not allowed! */
6095 return GNUNET_SYSERR;
6097 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6098 next_hop = lookup_neighbour (&path[1]);
6099 if (NULL == next_hop)
6101 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6103 return GNUNET_SYSERR;
6105 for (unsigned int i = 2; i < path_len; i++)
6106 if (NULL != lookup_neighbour (&path[i]))
6108 /* Useless path: we have a direct connection to some hop
6109 in the middle of the path, so this one is not even
6110 terribly useful for redundancy */
6111 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6112 "Path of %u hops useless: directly link to hop %u (%s)\n",
6115 GNUNET_i2s (&path[i]));
6116 GNUNET_STATISTICS_update (GST_stats,
6117 "# Useless DV path ignored: hop is neighbour",
6120 return GNUNET_SYSERR;
6122 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6125 dv = GNUNET_new (struct DistanceVector);
6126 dv->target = path[path_len - 1];
6127 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6130 GNUNET_assert (GNUNET_OK ==
6131 GNUNET_CONTAINER_multipeermap_put (
6135 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6137 /* Check if we have this path already! */
6138 shorter_distance = 0;
6139 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6142 if (pos->distance < path_len - 2)
6144 /* Note that the distances in 'pos' excludes us (path[0]) and
6145 the next_hop (path[1]), so we need to subtract two
6146 and check next_hop explicitly */
6147 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6149 int match = GNUNET_YES;
6151 for (unsigned int i = 0; i < pos->distance; i++)
6153 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6159 if (GNUNET_YES == match)
6161 struct GNUNET_TIME_Relative last_timeout;
6163 /* Re-discovered known path, update timeout */
6164 GNUNET_STATISTICS_update (GST_stats,
6165 "# Known DV path refreshed",
6168 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6170 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6171 pos->path_valid_until =
6172 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6173 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6174 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6176 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6177 activate_core_visible_dv_path (pos);
6178 if (last_timeout.rel_value_us <
6179 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6180 DV_PATH_DISCOVERY_FREQUENCY)
6183 /* Some peer send DV learn messages too often, we are learning
6184 the same path faster than it would be useful; do not forward! */
6185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6186 "Rediscovered path too quickly, not forwarding further\n");
6189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6190 "Refreshed known path to %s, forwarding further\n",
6191 GNUNET_i2s (&dv->target));
6196 /* Count how many shorter paths we have (incl. direct
6197 neighbours) before simply giving up on this one! */
6198 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6200 /* We have a shorter path already! */
6201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6202 "Have many shorter DV paths %s, not forwarding further\n",
6203 GNUNET_i2s (&dv->target));
6206 /* create new DV path entry */
6207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6208 "Discovered new DV path to %s\n",
6209 GNUNET_i2s (&dv->target));
6210 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6211 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6212 hop->next_hop = next_hop;
6214 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6217 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6218 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6219 hop->path_valid_until = path_valid_until;
6220 hop->distance = path_len - 2;
6221 hop->pd.aged_rtt = network_latency;
6222 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6223 GNUNET_CONTAINER_MDLL_insert (neighbour,
6227 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6228 activate_core_visible_dv_path (hop);
6234 * Communicator gave us a DV learn message. Check the message.
6236 * @param cls a `struct CommunicatorMessageContext`
6237 * @param dvl the send message that was sent
6238 * @return #GNUNET_YES if message is well-formed
6241 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6243 uint16_t size = ntohs (dvl->header.size);
6244 uint16_t num_hops = ntohs (dvl->num_hops);
6245 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6248 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6250 GNUNET_break_op (0);
6251 return GNUNET_SYSERR;
6253 if (num_hops > MAX_DV_HOPS_ALLOWED)
6255 GNUNET_break_op (0);
6256 return GNUNET_SYSERR;
6258 for (unsigned int i = 0; i < num_hops; i++)
6260 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6262 GNUNET_break_op (0);
6263 return GNUNET_SYSERR;
6265 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6267 GNUNET_break_op (0);
6268 return GNUNET_SYSERR;
6276 * Build and forward a DV learn message to @a next_hop.
6278 * @param next_hop peer to send the message to
6279 * @param msg message received
6280 * @param bi_history bitmask specifying hops on path that were bidirectional
6281 * @param nhops length of the @a hops array
6282 * @param hops path the message traversed so far
6283 * @param in_time when did we receive the message, used to calculate network
6287 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6288 const struct TransportDVLearnMessage *msg,
6289 uint16_t bi_history,
6291 const struct DVPathEntryP *hops,
6292 struct GNUNET_TIME_Absolute in_time)
6294 struct DVPathEntryP *dhops;
6295 char buf[sizeof (struct TransportDVLearnMessage) +
6296 (nhops + 1) * sizeof (struct DVPathEntryP)] GNUNET_ALIGN;
6297 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6298 struct GNUNET_TIME_Relative nnd;
6300 /* compute message for forwarding */
6301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6302 "Forwarding DV learn message originating from %s to %s\n",
6303 GNUNET_i2s (&msg->initiator),
6304 GNUNET_i2s2 (next_hop));
6305 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6306 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6307 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6308 (nhops + 1) * sizeof (struct DVPathEntryP));
6309 fwd->num_hops = htons (nhops + 1);
6310 fwd->bidirectional = htons (bi_history);
6311 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6312 GNUNET_TIME_relative_ntoh (
6313 msg->non_network_delay));
6314 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6315 fwd->init_sig = msg->init_sig;
6316 fwd->initiator = msg->initiator;
6317 fwd->challenge = msg->challenge;
6318 dhops = (struct DVPathEntryP *) &fwd[1];
6319 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6320 dhops[nhops].hop = GST_my_identity;
6322 struct DvHopPS dhp = {.purpose.purpose =
6323 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6324 .purpose.size = htonl (sizeof (dhp)),
6325 .pred = dhops[nhops - 1].hop,
6327 .challenge = msg->challenge};
6329 GNUNET_assert (GNUNET_OK ==
6330 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6332 &dhops[nhops].hop_sig));
6334 route_control_message_without_fc (next_hop,
6336 RMO_UNCONFIRMED_ALLOWED);
6341 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6343 * @param sender_monotonic_time monotonic time of the initiator
6344 * @param init the signer
6345 * @param challenge the challenge that was signed
6346 * @param init_sig signature presumably by @a init
6347 * @return #GNUNET_OK if the signature is valid
6350 validate_dv_initiator_signature (
6351 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6352 const struct GNUNET_PeerIdentity *init,
6353 const struct ChallengeNonceP *challenge,
6354 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6356 struct DvInitPS ip = {.purpose.purpose = htonl (
6357 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6358 .purpose.size = htonl (sizeof (ip)),
6359 .monotonic_time = sender_monotonic_time,
6360 .challenge = *challenge};
6364 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6369 GNUNET_break_op (0);
6370 return GNUNET_SYSERR;
6377 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6379 struct NeighbourSelectionContext
6382 * Original message we received.
6384 const struct TransportDVLearnMessage *dvl;
6389 const struct DVPathEntryP *hops;
6392 * Time we received the message.
6394 struct GNUNET_TIME_Absolute in_time;
6397 * Offsets of the selected peers.
6399 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6402 * Number of peers eligible for selection.
6404 unsigned int num_eligible;
6407 * Number of peers that were selected for forwarding.
6409 unsigned int num_selections;
6412 * Number of hops in @e hops
6417 * Bitmap of bidirectional connections encountered.
6419 uint16_t bi_history;
6424 * Function called for each neighbour during #handle_dv_learn.
6426 * @param cls a `struct NeighbourSelectionContext *`
6427 * @param pid identity of the peer
6428 * @param value a `struct Neighbour`
6429 * @return #GNUNET_YES (always)
6432 dv_neighbour_selection (void *cls,
6433 const struct GNUNET_PeerIdentity *pid,
6436 struct NeighbourSelectionContext *nsc = cls;
6439 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6440 return GNUNET_YES; /* skip initiator */
6441 for (unsigned int i = 0; i < nsc->nhops; i++)
6442 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6443 return GNUNET_YES; /* skip peers on path */
6444 nsc->num_eligible++;
6450 * Function called for each neighbour during #handle_dv_learn.
6451 * We call #forward_dv_learn() on the neighbour(s) selected
6452 * during #dv_neighbour_selection().
6454 * @param cls a `struct NeighbourSelectionContext *`
6455 * @param pid identity of the peer
6456 * @param value a `struct Neighbour`
6457 * @return #GNUNET_YES (always)
6460 dv_neighbour_transmission (void *cls,
6461 const struct GNUNET_PeerIdentity *pid,
6464 struct NeighbourSelectionContext *nsc = cls;
6467 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6468 return GNUNET_YES; /* skip initiator */
6469 for (unsigned int i = 0; i < nsc->nhops; i++)
6470 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6471 return GNUNET_YES; /* skip peers on path */
6472 for (unsigned int i = 0; i < nsc->num_selections; i++)
6474 if (nsc->selections[i] == nsc->num_eligible)
6476 forward_dv_learn (pid,
6485 nsc->num_eligible++;
6491 * Computes the number of neighbours we should forward a DVInit
6492 * message to given that it has so far taken @a hops_taken hops
6493 * though the network and that the number of neighbours we have
6494 * in total is @a neighbour_count, out of which @a eligible_count
6495 * are not yet on the path.
6497 * NOTE: technically we might want to include NSE in the formula to
6498 * get a better grip on the overall network size. However, for now
6499 * using NSE here would create a dependency issue in the build system.
6500 * => Left for later, hardcoded to 50 for now.
6502 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6503 * peers via DV (`target_total`). We want the reach to be spread out
6504 * over various distances to the origin, with a bias towards shorter
6507 * We make the strong assumption that the network topology looks
6508 * "similar" at other hops, in particular the @a neighbour_count
6509 * should be comparable at other hops.
6511 * If the local neighbourhood is densely connected, we expect that @a
6512 * eligible_count is close to @a neighbour_count minus @a hops_taken
6513 * as a lot of the path is already known. In that case, we should
6514 * forward to few(er) peers to try to find a path out of the
6515 * neighbourhood. OTOH, if @a eligible_count is close to @a
6516 * neighbour_count, we should forward to many peers as we are either
6517 * still close to the origin (i.e. @a hops_taken is small) or because
6518 * we managed to get beyond a local cluster. We express this as
6519 * the `boost_factor` using the square of the fraction of eligible
6520 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6521 * 99% are eligible, the 'boost' will be almost 1).
6523 * Second, the more hops we have taken, the larger the problem of an
6524 * exponential traffic explosion gets. So we take the `target_total`,
6525 * and compute our degree such that at each distance d 2^{-d} peers
6526 * are selected (corrected by the `boost_factor`).
6528 * @param hops_taken number of hops DVInit has travelled so far
6529 * @param neighbour_count number of neighbours we have in total
6530 * @param eligible_count number of neighbours we could in
6534 calculate_fork_degree (unsigned int hops_taken,
6535 unsigned int neighbour_count,
6536 unsigned int eligible_count)
6538 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6539 double eligible_ratio =
6540 ((double) eligible_count) / ((double) neighbour_count);
6541 double boost_factor = eligible_ratio * eligible_ratio;
6545 if (hops_taken >= 64)
6548 return 0; /* precaution given bitshift below */
6550 for (unsigned int i = 1; i < hops_taken; i++)
6552 /* For each hop, subtract the expected number of targets
6553 reached at distance d (so what remains divided by 2^d) */
6554 target_total -= (target_total * boost_factor / (1LLU << i));
6557 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6558 /* round up or down probabilistically depending on how close we were
6559 when floor()ing to rnd */
6560 left = target_total - (double) rnd;
6561 if (UINT32_MAX * left >
6562 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6563 rnd++; /* round up */
6564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6565 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6575 * Function called when peerstore is done storing a DV monotonic time.
6577 * @param cls a `struct Neighbour`
6578 * @param success #GNUNET_YES if peerstore was successful
6581 neighbour_store_dvmono_cb (void *cls, int success)
6583 struct Neighbour *n = cls;
6586 if (GNUNET_YES != success)
6587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6588 "Failed to store other peer's monotonic time in peerstore!\n");
6593 * Communicator gave us a DV learn message. Process the request.
6595 * @param cls a `struct CommunicatorMessageContext` (must call
6596 * #finish_cmc_handling() when done)
6597 * @param dvl the message that was received
6600 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6602 struct CommunicatorMessageContext *cmc = cls;
6603 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6606 uint16_t bi_history;
6607 const struct DVPathEntryP *hops;
6610 struct GNUNET_TIME_Absolute in_time;
6611 struct Neighbour *n;
6613 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6614 bi_history = ntohs (dvl->bidirectional);
6615 hops = (const struct DVPathEntryP *) &dvl[1];
6619 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6622 finish_cmc_handling (cmc);
6629 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6632 finish_cmc_handling (cmc);
6637 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6638 cc = cmc->tc->details.communicator.cc;
6639 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6640 cc); // FIXME: add bi-directional flag to cc?
6641 in_time = GNUNET_TIME_absolute_get ();
6643 /* continue communicator here, everything else can happen asynchronous! */
6644 finish_cmc_handling (cmc);
6646 n = lookup_neighbour (&dvl->initiator);
6649 if ((n->dv_monotime_available == GNUNET_YES) &&
6650 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6651 n->last_dv_learn_monotime.abs_value_us))
6653 GNUNET_STATISTICS_update (GST_stats,
6654 "# DV learn discarded due to time travel",
6659 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6664 GNUNET_break_op (0);
6667 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6668 if (GNUNET_YES == n->dv_monotime_available)
6671 GNUNET_PEERSTORE_store_cancel (n->sc);
6673 GNUNET_PEERSTORE_store (peerstore,
6676 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6677 &dvl->monotonic_time,
6678 sizeof (dvl->monotonic_time),
6679 GNUNET_TIME_UNIT_FOREVER_ABS,
6680 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6681 &neighbour_store_dvmono_cb,
6685 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6686 If signature verification load too high, implement random drop strategy */
6687 for (unsigned int i = 0; i < nhops; i++)
6689 struct DvHopPS dhp = {.purpose.purpose =
6690 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6691 .purpose.size = htonl (sizeof (dhp)),
6692 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6693 .succ = (nhops == i + 1) ? GST_my_identity
6695 .challenge = dvl->challenge};
6698 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6701 &hops[i].hop.public_key))
6703 GNUNET_break_op (0);
6708 if (GNUNET_EXTRA_LOGGING > 0)
6712 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6713 for (unsigned int i = 0; i < nhops; i++)
6717 GNUNET_asprintf (&tmp,
6720 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6721 GNUNET_i2s (&hops[i].hop));
6725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6726 "Received DVInit via %s%s%s\n",
6728 bi_hop ? "<->" : "-->",
6729 GNUNET_i2s (&GST_my_identity));
6733 do_fwd = GNUNET_YES;
6734 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6736 struct GNUNET_PeerIdentity path[nhops + 1];
6737 struct GNUNET_TIME_Relative host_latency_sum;
6738 struct GNUNET_TIME_Relative latency;
6739 struct GNUNET_TIME_Relative network_latency;
6741 /* We initiated this, learn the forward path! */
6742 path[0] = GST_my_identity;
6743 path[1] = hops[0].hop;
6744 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6746 // Need also something to lookup initiation time
6747 // to compute RTT! -> add RTT argument here?
6748 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6749 // (based on dvl->challenge, we can identify time of origin!)
6751 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6752 /* assumption: latency on all links is the same */
6753 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6755 for (unsigned int i = 2; i <= nhops; i++)
6757 struct GNUNET_TIME_Relative ilat;
6759 /* assumption: linear latency increase per hop */
6760 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6761 path[i] = hops[i - 1].hop;
6762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6763 "Learned path with %u hops to %s with latency %s\n",
6765 GNUNET_i2s (&path[i]),
6766 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6767 learn_dv_path (path,
6770 GNUNET_TIME_relative_to_absolute (
6771 ADDRESS_VALIDATION_LIFETIME));
6773 /* as we initiated, do not forward again (would be circular!) */
6779 /* last hop was bi-directional, we could learn something here! */
6780 struct GNUNET_PeerIdentity path[nhops + 2];
6782 path[0] = GST_my_identity;
6783 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6784 for (unsigned int i = 0; i < nhops; i++)
6788 if (0 == (bi_history & (1 << i)))
6789 break; /* i-th hop not bi-directional, stop learning! */
6792 path[i + 2] = dvl->initiator;
6796 path[i + 2] = hops[nhops - i - 2].hop;
6799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6800 "Learned inverse path with %u hops to %s\n",
6802 GNUNET_i2s (&path[i + 2]));
6803 iret = learn_dv_path (path,
6805 GNUNET_TIME_UNIT_FOREVER_REL,
6806 GNUNET_TIME_UNIT_ZERO_ABS);
6807 if (GNUNET_SYSERR == iret)
6809 /* path invalid or too long to be interesting for US, thus should also
6810 not be interesting to our neighbours, cut path when forwarding to
6811 'i' hops, except of course for the one that goes back to the
6813 GNUNET_STATISTICS_update (GST_stats,
6814 "# DV learn not forwarded due invalidity of path",
6820 if ((GNUNET_NO == iret) && (nhops == i + 1))
6822 /* we have better paths, and this is the longest target,
6823 so there cannot be anything interesting later */
6824 GNUNET_STATISTICS_update (GST_stats,
6825 "# DV learn not forwarded, got better paths",
6834 if (MAX_DV_HOPS_ALLOWED == nhops)
6836 /* At limit, we're out of here! */
6837 finish_cmc_handling (cmc);
6841 /* Forward to initiator, if path non-trivial and possible */
6842 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6843 did_initiator = GNUNET_NO;
6846 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6848 /* send back to origin! */
6849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6850 "Sending DVL back to initiator %s\n",
6851 GNUNET_i2s (&dvl->initiator));
6852 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6853 did_initiator = GNUNET_YES;
6855 /* We forward under two conditions: either we still learned something
6856 ourselves (do_fwd), or the path was darn short and thus the initiator is
6857 likely to still be very interested in this (and we did NOT already
6858 send it back to the initiator) */
6859 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6860 (GNUNET_NO == did_initiator)))
6862 /* Pick random neighbours that are not yet on the path */
6863 struct NeighbourSelectionContext nsc;
6866 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6869 nsc.bi_history = bi_history;
6871 nsc.in_time = in_time;
6872 nsc.num_eligible = 0;
6873 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6874 &dv_neighbour_selection,
6876 if (0 == nsc.num_eligible)
6877 return; /* done here, cannot forward to anyone else */
6878 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6879 nsc.num_selections =
6880 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6882 "Forwarding DVL to %u other peers\n",
6883 nsc.num_selections);
6884 for (unsigned int i = 0; i < nsc.num_selections; i++)
6886 (nsc.num_selections == n_cnt)
6887 ? i /* all were selected, avoid collisions by chance */
6888 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6889 nsc.num_eligible = 0;
6890 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6891 &dv_neighbour_transmission,
6898 * Communicator gave us a DV box. Check the message.
6900 * @param cls a `struct CommunicatorMessageContext`
6901 * @param dvb the send message that was sent
6902 * @return #GNUNET_YES if message is well-formed
6905 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6907 uint16_t size = ntohs (dvb->header.size);
6908 uint16_t num_hops = ntohs (dvb->num_hops);
6909 const struct GNUNET_PeerIdentity *hops =
6910 (const struct GNUNET_PeerIdentity *) &dvb[1];
6913 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6914 sizeof (struct GNUNET_MessageHeader))
6916 GNUNET_break_op (0);
6917 return GNUNET_SYSERR;
6919 /* This peer must not be on the path */
6920 for (unsigned int i = 0; i < num_hops; i++)
6921 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6923 GNUNET_break_op (0);
6924 return GNUNET_SYSERR;
6931 * Create a DV Box message and queue it for transmission to
6934 * @param next_hop peer to receive the message next
6935 * @param total_hops how many hops did the message take so far
6936 * @param num_hops length of the @a hops array
6937 * @param origin origin of the message
6938 * @param hops next peer(s) to the destination, including destination
6939 * @param payload payload of the box
6940 * @param payload_size number of bytes in @a payload
6943 forward_dv_box (struct Neighbour *next_hop,
6944 const struct TransportDVBoxMessage *hdr,
6945 uint16_t total_hops,
6947 const struct GNUNET_PeerIdentity *hops,
6948 const void *enc_payload,
6949 uint16_t enc_payload_size)
6951 struct VirtualLink *vl = next_hop->vl;
6952 struct PendingMessage *pm;
6955 struct GNUNET_PeerIdentity *dhops;
6957 GNUNET_assert (NULL != vl);
6958 msg_size = sizeof (struct TransportDVBoxMessage) +
6959 num_hops * sizeof (struct GNUNET_PeerIdentity) + enc_payload_size;
6960 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
6961 pm->pmt = PMT_DV_BOX;
6963 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
6964 pm->logging_uuid = logging_uuid_gen++;
6965 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
6966 pm->bytes_msg = msg_size;
6967 buf = (char *) &pm[1];
6968 memcpy (buf, hdr, sizeof (*hdr));
6970 (struct GNUNET_PeerIdentity *) &buf[sizeof (struct TransportDVBoxMessage)];
6971 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
6972 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
6973 GNUNET_CONTAINER_MDLL_insert (vl,
6974 vl->pending_msg_head,
6975 vl->pending_msg_tail,
6977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6978 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
6980 GNUNET_i2s (&next_hop->pid),
6981 (unsigned int) num_hops,
6982 (unsigned int) total_hops);
6983 check_vl_transmission (vl);
6988 * Free data structures associated with @a b.
6990 * @param b data structure to release
6993 free_backtalker (struct Backtalker *b)
6997 GNUNET_PEERSTORE_iterate_cancel (b->get);
6999 GNUNET_assert (NULL != b->cmc);
7000 finish_cmc_handling (b->cmc);
7003 if (NULL != b->task)
7005 GNUNET_SCHEDULER_cancel (b->task);
7010 GNUNET_PEERSTORE_store_cancel (b->sc);
7015 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7021 * Callback to free backtalker records.
7025 * @param value a `struct Backtalker`
7026 * @return #GNUNET_OK (always)
7029 free_backtalker_cb (void *cls,
7030 const struct GNUNET_PeerIdentity *pid,
7033 struct Backtalker *b = value;
7037 free_backtalker (b);
7043 * Function called when it is time to clean up a backtalker.
7045 * @param cls a `struct Backtalker`
7048 backtalker_timeout_cb (void *cls)
7050 struct Backtalker *b = cls;
7053 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7055 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7058 GNUNET_assert (NULL == b->sc);
7059 free_backtalker (b);
7064 * Function called with the monotonic time of a backtalker
7065 * by PEERSTORE. Updates the time and continues processing.
7067 * @param cls a `struct Backtalker`
7068 * @param record the information found, NULL for the last call
7069 * @param emsg error message
7072 backtalker_monotime_cb (void *cls,
7073 const struct GNUNET_PEERSTORE_Record *record,
7076 struct Backtalker *b = cls;
7077 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7078 struct GNUNET_TIME_Absolute mt;
7083 /* we're done with #backtalker_monotime_cb() invocations,
7084 continue normal processing */
7086 GNUNET_assert (NULL != b->cmc);
7087 if (0 != b->body_size)
7088 demultiplex_with_cmc (b->cmc,
7089 (const struct GNUNET_MessageHeader *) &b[1]);
7091 finish_cmc_handling (b->cmc);
7095 if (sizeof (*mtbe) != record->value_size)
7100 mtbe = record->value;
7101 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7102 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7105 "Backtalker message from %s dropped, monotime in the past\n",
7106 GNUNET_i2s (&b->pid));
7107 GNUNET_STATISTICS_update (
7109 "# Backchannel messages dropped: monotonic time not increasing",
7112 b->monotonic_time = mt;
7113 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7122 * Function called by PEERSTORE when the store operation of
7123 * a backtalker's monotonic time is complete.
7125 * @param cls the `struct Backtalker`
7126 * @param success #GNUNET_OK on success
7129 backtalker_monotime_store_cb (void *cls, int success)
7131 struct Backtalker *b = cls;
7133 if (GNUNET_OK != success)
7135 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7136 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7139 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7144 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7146 * @param b a backtalker with updated monotonic time
7149 update_backtalker_monotime (struct Backtalker *b)
7151 struct GNUNET_TIME_AbsoluteNBO mtbe;
7155 GNUNET_PEERSTORE_store_cancel (b->sc);
7160 GNUNET_SCHEDULER_cancel (b->task);
7163 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7165 GNUNET_PEERSTORE_store (peerstore,
7168 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7171 GNUNET_TIME_UNIT_FOREVER_ABS,
7172 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7173 &backtalker_monotime_store_cb,
7179 * Communicator gave us a DV box. Process the request.
7181 * @param cls a `struct CommunicatorMessageContext` (must call
7182 * #finish_cmc_handling() when done)
7183 * @param dvb the message that was received
7186 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7188 struct CommunicatorMessageContext *cmc = cls;
7189 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
7190 uint16_t num_hops = ntohs (dvb->num_hops);
7191 const struct GNUNET_PeerIdentity *hops =
7192 (const struct GNUNET_PeerIdentity *) &dvb[1];
7193 const char *enc_payload = (const char *) &hops[num_hops];
7194 uint16_t enc_payload_size =
7195 size - (num_hops * sizeof (struct GNUNET_PeerIdentity));
7196 struct DVKeyState key;
7197 struct GNUNET_HashCode hmac;
7201 if (GNUNET_EXTRA_LOGGING > 0)
7205 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7206 for (unsigned int i = 0; i < num_hops; i++)
7210 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7215 "Received DVBox with remainig path %s\n",
7222 /* We're trying from the end of the hops array, as we may be
7223 able to find a shortcut unknown to the origin that way */
7224 for (int i = num_hops - 1; i >= 0; i--)
7226 struct Neighbour *n;
7228 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7230 GNUNET_break_op (0);
7231 finish_cmc_handling (cmc);
7234 n = lookup_neighbour (&hops[i]);
7237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7238 "Skipping %u/%u hops ahead while routing DV Box\n",
7243 ntohs (dvb->total_hops) + 1,
7244 num_hops - i - 1, /* number of hops left */
7245 &hops[i + 1], /* remaining hops */
7248 GNUNET_STATISTICS_update (GST_stats,
7249 "# DV hops skipped routing boxes",
7252 GNUNET_STATISTICS_update (GST_stats,
7253 "# DV boxes routed (total)",
7256 finish_cmc_handling (cmc);
7259 /* Woopsie, next hop not in neighbours, drop! */
7260 GNUNET_STATISTICS_update (GST_stats,
7261 "# DV Boxes dropped: next hop unknown",
7264 finish_cmc_handling (cmc);
7267 /* We are the target. Unbox and handle message. */
7268 GNUNET_STATISTICS_update (GST_stats,
7269 "# DV boxes opened (ultimate target)",
7272 cmc->total_hops = ntohs (dvb->total_hops);
7274 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key);
7275 hdr = (const char *) &dvb[1];
7276 hdr_len = ntohs (dvb->header.size) - sizeof (*dvb);
7277 dv_hmac (&key, &hmac, hdr, hdr_len);
7278 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7280 /* HMAC missmatch, disard! */
7281 GNUNET_break_op (0);
7282 finish_cmc_handling (cmc);
7285 /* begin actual decryption */
7287 struct Backtalker *b;
7288 struct GNUNET_TIME_Absolute monotime;
7289 struct TransportDVBoxPayloadP ppay;
7290 char body[hdr_len - sizeof (ppay)] GNUNET_ALIGN;
7291 const struct GNUNET_MessageHeader *mh =
7292 (const struct GNUNET_MessageHeader *) body;
7294 GNUNET_assert (hdr_len >=
7295 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
7296 dv_decrypt (&key, &ppay, hdr, sizeof (ppay));
7297 dv_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
7298 dv_key_clean (&key);
7299 if (ntohs (mh->size) != sizeof (body))
7301 GNUNET_break_op (0);
7302 finish_cmc_handling (cmc);
7305 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7306 switch (ntohs (mh->type))
7308 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7309 GNUNET_break_op (0);
7310 finish_cmc_handling (cmc);
7312 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7313 GNUNET_break_op (0);
7314 finish_cmc_handling (cmc);
7317 /* permitted, continue */
7320 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7322 "Decrypted backtalk from %s\n",
7323 GNUNET_i2s (&ppay.sender));
7324 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
7325 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
7327 GNUNET_STATISTICS_update (
7329 "# Backchannel messages dropped: monotonic time not increasing",
7332 finish_cmc_handling (cmc);
7336 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
7338 /* Check signature */
7339 struct EphemeralConfirmationPS ec;
7341 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
7342 ec.purpose.size = htonl (sizeof (ec));
7343 ec.target = GST_my_identity;
7344 ec.ephemeral_key = dvb->ephemeral_key;
7347 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
7350 &ppay.sender.public_key))
7352 /* Signature invalid, disard! */
7353 GNUNET_break_op (0);
7354 finish_cmc_handling (cmc);
7358 /* Update sender, we now know the real origin! */
7359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7360 "DVBox received for me from %s via %s\n",
7361 GNUNET_i2s2 (&ppay.sender),
7362 GNUNET_i2s (&cmc->im.sender));
7363 cmc->im.sender = ppay.sender;
7367 /* update key cache and mono time */
7368 b->last_ephemeral = dvb->ephemeral_key;
7369 b->monotonic_time = monotime;
7370 update_backtalker_monotime (b);
7372 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7374 demultiplex_with_cmc (cmc, mh);
7377 /* setup data structure to cache signature AND check
7378 monotonic time with PEERSTORE before forwarding backchannel payload */
7379 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
7380 b->pid = ppay.sender;
7381 b->body_size = sizeof (body);
7382 memcpy (&b[1], body, sizeof (body));
7383 GNUNET_assert (GNUNET_YES ==
7384 GNUNET_CONTAINER_multipeermap_put (
7388 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7389 b->monotonic_time = monotime; /* NOTE: to be checked still! */
7392 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7393 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7395 GNUNET_PEERSTORE_iterate (peerstore,
7398 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7399 &backtalker_monotime_cb,
7401 } /* end actual decryption */
7406 * Client notified us about transmission from a peer. Process the request.
7408 * @param cls a `struct TransportClient` which sent us the message
7409 * @param obm the send message that was sent
7410 * @return #GNUNET_YES if message is well-formed
7413 check_incoming_msg (void *cls,
7414 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7416 struct TransportClient *tc = cls;
7418 if (CT_COMMUNICATOR != tc->type)
7421 return GNUNET_SYSERR;
7423 GNUNET_MQ_check_boxed_message (im);
7430 * We received a @a challenge from another peer, check if we can
7431 * increase the flow control window to that peer.
7433 * @param vl virtual link
7434 * @param challenge the challenge we received
7435 * @param sender_time when did the peer send the message?
7436 * @param last_window_consum_limit maximum number of kb the sender
7437 * promises to use of the previous window (if any)
7440 update_fc_window (struct VirtualLink *vl,
7441 struct GNUNET_TIME_Absolute sender_time,
7442 uint32_t last_window_consum_limit)
7444 // FIXME: update to new FC logic
7445 if (0 == GNUNET_memcmp (challenge, &vl->n_challenge))
7449 /* Challenge identical to last one, update
7450 @a last_window_consum_limit (to minimum) */
7451 vl->last_fc_window_size_remaining =
7452 GNUNET_MIN (last_window_consum_limit, vl->last_fc_window_size_remaining);
7453 /* window could have shrunk! */
7454 if (vl->available_fc_window_size > vl->last_fc_window_size_remaining)
7455 avail = vl->available_fc_window_size - vl->last_fc_window_size_remaining;
7458 /* guard against integer overflow */
7459 if (vl->incoming_fc_window_size_used + avail >=
7460 vl->incoming_fc_window_size_used)
7461 vl->incoming_fc_window_size = vl->incoming_fc_window_size_used + avail;
7463 vl->incoming_fc_window_size = UINT32_MAX;
7464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7465 "Updated window to %u/%u kb (%u used) for virtual link to %s!\n",
7466 vl->incoming_fc_window_size,
7467 vl->available_fc_window_size,
7468 vl->incoming_fc_window_size_used,
7469 GNUNET_i2s (&vl->target));
7472 if (vl->n_challenge_time.abs_value_us >= sender_time.abs_value_us)
7474 GNUNET_STATISTICS_update (GST_stats,
7475 "# Challenges ignored: sender time not increasing",
7480 /* new challenge! */
7481 if (vl->incoming_fc_window_size_used > last_window_consum_limit)
7483 /* lying peer: it already used more than it promised it would ever use! */
7484 GNUNET_break_op (0);
7485 last_window_consum_limit = vl->incoming_fc_window_size_used;
7487 /* What remains is at most the difference between what we already processed
7488 and what the sender promises to limit itself to. */
7489 vl->last_fc_window_size_remaining =
7490 last_window_consum_limit - vl->incoming_fc_window_size_used;
7491 vl->n_challenge = *challenge;
7492 vl->n_challenge_time = sender_time;
7493 vl->incoming_fc_window_size_used = 0;
7494 /* window could have shrunk! */
7495 if (vl->available_fc_window_size > vl->last_fc_window_size_remaining)
7496 vl->incoming_fc_window_size =
7497 vl->available_fc_window_size - vl->last_fc_window_size_remaining;
7499 vl->incoming_fc_window_size = 0;
7501 GNUNET_ERROR_TYPE_DEBUG,
7502 "New window at %u/%u kb (%u left on previous) for virtual link to %s!\n",
7503 vl->incoming_fc_window_size,
7504 vl->available_fc_window_size,
7505 vl->last_fc_window_size_remaining,
7506 GNUNET_i2s (&vl->target));
7512 * Closure for #check_known_address.
7514 struct CheckKnownAddressContext
7517 * Set to the address we are looking for.
7519 const char *address;
7522 * Set to a matching validation state, if one was found.
7524 struct ValidationState *vs;
7529 * Test if the validation state in @a value matches the
7530 * address from @a cls.
7532 * @param cls a `struct CheckKnownAddressContext`
7533 * @param pid unused (must match though)
7534 * @param value a `struct ValidationState`
7535 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7538 check_known_address (void *cls,
7539 const struct GNUNET_PeerIdentity *pid,
7542 struct CheckKnownAddressContext *ckac = cls;
7543 struct ValidationState *vs = value;
7546 if (0 != strcmp (vs->address, ckac->address))
7554 * Task run periodically to validate some address based on #validation_heap.
7559 validation_start_cb (void *cls);
7563 * Set the time for next_challenge of @a vs to @a new_time.
7564 * Updates the heap and if necessary reschedules the job.
7566 * @param vs validation state to update
7567 * @param new_time new time for revalidation
7570 update_next_challenge_time (struct ValidationState *vs,
7571 struct GNUNET_TIME_Absolute new_time)
7573 struct GNUNET_TIME_Relative delta;
7575 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7576 return; /* be lazy */
7577 vs->next_challenge = new_time;
7580 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7582 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7583 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7584 (NULL != validation_task))
7586 if (NULL != validation_task)
7587 GNUNET_SCHEDULER_cancel (validation_task);
7588 /* randomize a bit */
7589 delta.rel_value_us =
7590 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7591 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7592 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7594 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7599 * Start address validation.
7601 * @param pid peer the @a address is for
7602 * @param address an address to reach @a pid (presumably)
7605 start_address_validation (const struct GNUNET_PeerIdentity *pid,
7606 const char *address)
7608 struct GNUNET_TIME_Absolute now;
7609 struct ValidationState *vs;
7610 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7612 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7614 &check_known_address,
7616 if (NULL != (vs = ckac.vs))
7618 /* if 'vs' is not currently valid, we need to speed up retrying the
7620 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7622 /* reduce backoff as we got a fresh advertisement */
7623 vs->challenge_backoff =
7624 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7625 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7627 update_next_challenge_time (vs,
7628 GNUNET_TIME_relative_to_absolute (
7629 vs->challenge_backoff));
7633 now = GNUNET_TIME_absolute_get ();
7634 vs = GNUNET_new (struct ValidationState);
7637 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7638 vs->first_challenge_use = now;
7639 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7640 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7642 sizeof (vs->challenge));
7643 vs->address = GNUNET_strdup (address);
7644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7645 "Starting address validation `%s' of peer %s using challenge %s\n",
7648 GNUNET_sh2s (&vs->challenge.value));
7649 GNUNET_assert (GNUNET_YES ==
7650 GNUNET_CONTAINER_multipeermap_put (
7654 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7655 update_next_challenge_time (vs, now);
7660 * Function called by PEERSTORE for each matching record.
7662 * @param cls closure, a `struct IncomingRequest`
7663 * @param record peerstore record information
7664 * @param emsg error message, or NULL if no errors
7667 handle_hello_for_incoming (void *cls,
7668 const struct GNUNET_PEERSTORE_Record *record,
7671 struct IncomingRequest *ir = cls;
7676 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7677 "Got failure from PEERSTORE: %s\n",
7681 val = record->value;
7682 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7687 start_address_validation (&ir->pid, (const char *) record->value);
7692 * Communicator gave us a transport address validation challenge. Process the
7695 * @param cls a `struct CommunicatorMessageContext` (must call
7696 * #finish_cmc_handling() when done)
7697 * @param tvc the message that was received
7700 handle_validation_challenge (
7702 const struct TransportValidationChallengeMessage *tvc)
7704 struct CommunicatorMessageContext *cmc = cls;
7705 struct TransportValidationResponseMessage tvr;
7706 struct VirtualLink *vl;
7707 struct GNUNET_TIME_RelativeNBO validity_duration;
7708 struct IncomingRequest *ir;
7709 struct Neighbour *n;
7711 /* DV-routed messages are not allowed for validation challenges */
7712 if (cmc->total_hops > 0)
7714 GNUNET_break_op (0);
7715 finish_cmc_handling (cmc);
7718 validity_duration = cmc->im.expected_address_validity;
7719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7720 "Received address validation challenge %s\n",
7721 GNUNET_sh2s (&tvc->challenge.value));
7722 /* If we have a virtual link, we use this mechanism to signal the
7723 size of the flow control window, and to allow the sender
7724 to ask for increases. If for us the virtual link is still down,
7725 we will always give a window size of zero. */
7727 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7728 tvr.header.size = htons (sizeof (tvr));
7729 tvr.reserved = htonl (0);
7730 tvr.challenge = tvc->challenge;
7731 tvr.origin_time = tvc->sender_time;
7732 tvr.validity_duration = validity_duration;
7734 /* create signature */
7735 struct TransportValidationPS tvp =
7736 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7737 .purpose.size = htonl (sizeof (tvp)),
7738 .validity_duration = validity_duration,
7739 .challenge = tvc->challenge};
7741 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7745 route_control_message_without_fc (&cmc->im.sender,
7747 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7748 finish_cmc_handling (cmc);
7750 vl = lookup_virtual_link (&cmc->im.sender);
7754 /* For us, the link is still down, but we need bi-directional
7755 connections (for flow-control and for this to be useful for
7756 CORE), so we must try to bring the link up! */
7758 /* (1) Check existing queues, if any, we may be lucky! */
7759 n = lookup_neighbour (&cmc->im.sender);
7761 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7762 start_address_validation (&cmc->im.sender, q->address);
7763 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7765 for (ir = ir_head; NULL != ir; ir = ir->next)
7766 if (0 == GNUNET_memcmp (&ir->pid, &cmc->im.sender))
7767 return; /* we are already trying */
7768 ir = GNUNET_new (struct IncomingRequest);
7769 ir->pid = cmc->im.sender;
7770 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7771 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7774 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7775 &handle_hello_for_incoming,
7778 /* Bound attempts we do in parallel here, might otherwise get excessive */
7779 while (ir_total > MAX_INCOMING_REQUEST)
7780 free_incoming_request (ir_head);
7785 * Closure for #check_known_challenge.
7787 struct CheckKnownChallengeContext
7790 * Set to the challenge we are looking for.
7792 const struct ChallengeNonceP *challenge;
7795 * Set to a matching validation state, if one was found.
7797 struct ValidationState *vs;
7802 * Test if the validation state in @a value matches the
7803 * challenge from @a cls.
7805 * @param cls a `struct CheckKnownChallengeContext`
7806 * @param pid unused (must match though)
7807 * @param value a `struct ValidationState`
7808 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7811 check_known_challenge (void *cls,
7812 const struct GNUNET_PeerIdentity *pid,
7815 struct CheckKnownChallengeContext *ckac = cls;
7816 struct ValidationState *vs = value;
7819 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7827 * Function called when peerstore is done storing a
7828 * validated address.
7830 * @param cls a `struct ValidationState`
7831 * @param success #GNUNET_YES on success
7834 peerstore_store_validation_cb (void *cls, int success)
7836 struct ValidationState *vs = cls;
7839 if (GNUNET_YES == success)
7841 GNUNET_STATISTICS_update (GST_stats,
7842 "# Peerstore failed to store foreign address",
7849 * Find the queue matching @a pid and @a address.
7851 * @param pid peer the queue must go to
7852 * @param address address the queue must use
7853 * @return NULL if no such queue exists
7855 static struct Queue *
7856 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7858 struct Neighbour *n;
7860 n = lookup_neighbour (pid);
7863 for (struct Queue *pos = n->queue_head; NULL != pos;
7864 pos = pos->next_neighbour)
7866 if (0 == strcmp (pos->address, address))
7874 * Communicator gave us a transport address validation response. Process the
7877 * @param cls a `struct CommunicatorMessageContext` (must call
7878 * #finish_cmc_handling() when done)
7879 * @param tvr the message that was received
7882 handle_validation_response (
7884 const struct TransportValidationResponseMessage *tvr)
7886 struct CommunicatorMessageContext *cmc = cls;
7887 struct ValidationState *vs;
7888 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7890 struct GNUNET_TIME_Absolute origin_time;
7892 struct Neighbour *n;
7893 struct VirtualLink *vl;
7895 /* check this is one of our challenges */
7896 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7898 &check_known_challenge,
7900 if (NULL == (vs = ckac.vs))
7902 /* This can happen simply if we 'forgot' the challenge by now,
7903 i.e. because we received the validation response twice */
7904 GNUNET_STATISTICS_update (GST_stats,
7905 "# Validations dropped, challenge unknown",
7908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7909 "Validation response %s dropped, challenge unknown\n",
7910 GNUNET_sh2s (&tvr->challenge.value));
7911 finish_cmc_handling (cmc);
7915 /* sanity check on origin time */
7916 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7917 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7918 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7920 GNUNET_break_op (0);
7921 finish_cmc_handling (cmc);
7926 /* check signature */
7927 struct TransportValidationPS tvp =
7928 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7929 .purpose.size = htonl (sizeof (tvp)),
7930 .validity_duration = tvr->validity_duration,
7931 .challenge = tvr->challenge};
7935 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7938 &cmc->im.sender.public_key))
7940 GNUNET_break_op (0);
7941 finish_cmc_handling (cmc);
7946 /* validity is capped by our willingness to keep track of the
7947 validation entry and the maximum the other peer allows */
7948 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7949 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7950 tvr->validity_duration),
7951 MAX_ADDRESS_VALID_UNTIL));
7952 vs->validated_until =
7953 GNUNET_TIME_absolute_min (vs->valid_until,
7954 GNUNET_TIME_relative_to_absolute (
7955 ADDRESS_VALIDATION_LIFETIME));
7956 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7957 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7958 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7960 sizeof (vs->challenge));
7961 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7962 vs->validated_until,
7963 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7964 VALIDATION_RTT_BUFFER_FACTOR));
7965 vs->last_challenge_use =
7966 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7967 update_next_challenge_time (vs, vs->first_challenge_use);
7968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7969 "Validation response %s accepted, address valid until %s\n",
7970 GNUNET_sh2s (&tvr->challenge.value),
7971 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
7972 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7975 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7977 strlen (vs->address) + 1,
7979 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7980 &peerstore_store_validation_cb,
7982 finish_cmc_handling (cmc);
7984 /* Finally, we now possibly have a confirmed (!) working queue,
7985 update queue status (if queue still is around) */
7986 q = find_queue (&vs->pid, vs->address);
7989 GNUNET_STATISTICS_update (GST_stats,
7990 "# Queues lost at time of successful validation",
7995 q->validated_until = vs->validated_until;
7996 q->pd.aged_rtt = vs->validation_rtt;
7998 vl = lookup_virtual_link (&vs->pid);
8001 /* Link was already up, remember n is also now available and we are done */
8006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8007 "Virtual link to %s could now also direct neighbour!\n",
8008 GNUNET_i2s (&vs->pid));
8012 GNUNET_assert (n == vl->n);
8016 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8017 "Creating new virtual link to %s using direct neighbour!\n",
8018 GNUNET_i2s (&vs->pid));
8019 vl = GNUNET_new (struct VirtualLink);
8020 vl->target = n->pid;
8023 vl->core_recv_window = RECV_WINDOW_SIZE;
8024 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8025 vl->my_challenge = tvr->challenge;
8026 vl->visibility_task =
8027 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8028 GNUNET_break (GNUNET_YES ==
8029 GNUNET_CONTAINER_multipeermap_put (
8033 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8034 /* We lacked a confirmed connection to the target
8035 before, so tell CORE about it (finally!) */
8036 cores_send_connect_info (&n->pid);
8041 * Incoming meessage. Process the request.
8043 * @param im the send message that was received
8046 handle_incoming_msg (void *cls,
8047 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8049 struct TransportClient *tc = cls;
8050 struct CommunicatorMessageContext *cmc =
8051 GNUNET_new (struct CommunicatorMessageContext);
8055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8056 "Received message via communicator from peer %s\n",
8057 GNUNET_i2s (&im->sender));
8058 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8063 * Given an inbound message @a msg from a communicator @a cmc,
8064 * demultiplex it based on the type calling the right handler.
8066 * @param cmc context for demultiplexing
8067 * @param msg message to demultiplex
8070 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8071 const struct GNUNET_MessageHeader *msg)
8073 struct GNUNET_MQ_MessageHandler handlers[] =
8074 {GNUNET_MQ_hd_var_size (fragment_box,
8075 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8076 struct TransportFragmentBoxMessage,
8078 GNUNET_MQ_hd_var_size (reliability_box,
8079 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8080 struct TransportReliabilityBoxMessage,
8082 GNUNET_MQ_hd_var_size (reliability_ack,
8083 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8084 struct TransportReliabilityAckMessage,
8086 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8087 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8088 struct TransportBackchannelEncapsulationMessage,
8090 GNUNET_MQ_hd_var_size (dv_learn,
8091 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8092 struct TransportDVLearnMessage,
8094 GNUNET_MQ_hd_var_size (dv_box,
8095 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8096 struct TransportDVBoxMessage,
8098 GNUNET_MQ_hd_fixed_size (
8099 validation_challenge,
8100 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8101 struct TransportValidationChallengeMessage,
8103 GNUNET_MQ_hd_fixed_size (
8104 validation_response,
8105 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8106 struct TransportValidationResponseMessage,
8108 GNUNET_MQ_handler_end ()};
8111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8112 "Handling message of type %u with %u bytes\n",
8113 (unsigned int) ntohs (msg->type),
8114 (unsigned int) ntohs (msg->size));
8115 ret = GNUNET_MQ_handle_message (handlers, msg);
8116 if (GNUNET_SYSERR == ret)
8119 GNUNET_SERVICE_client_drop (cmc->tc->client);
8123 if (GNUNET_NO == ret)
8125 /* unencapsulated 'raw' message */
8126 handle_raw_message (&cmc, msg);
8132 * New queue became available. Check message.
8134 * @param cls the client
8135 * @param aqm the send message that was sent
8138 check_add_queue_message (void *cls,
8139 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8141 struct TransportClient *tc = cls;
8143 if (CT_COMMUNICATOR != tc->type)
8146 return GNUNET_SYSERR;
8148 GNUNET_MQ_check_zero_termination (aqm);
8154 * If necessary, generates the UUID for a @a pm
8156 * @param pm pending message to generate UUID for.
8159 set_pending_message_uuid (struct PendingMessage *pm)
8161 if (pm->msg_uuid_set)
8163 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8164 pm->msg_uuid_set = GNUNET_YES;
8169 * Setup data structure waiting for acknowledgements.
8171 * @param queue queue the @a pm will be sent over
8172 * @param dvh path the message will take, may be NULL
8173 * @param pm the pending message for transmission
8174 * @return corresponding fresh pending acknowledgement
8176 static struct PendingAcknowledgement *
8177 prepare_pending_acknowledgement (struct Queue *queue,
8178 struct DistanceVectorHop *dvh,
8179 struct PendingMessage *pm)
8181 struct PendingAcknowledgement *pa;
8183 pa = GNUNET_new (struct PendingAcknowledgement);
8189 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8191 sizeof (pa->ack_uuid));
8192 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
8194 &pa->ack_uuid.value,
8196 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8197 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8198 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8200 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8201 pa->transmission_time = GNUNET_TIME_absolute_get ();
8202 pa->message_size = pm->bytes_msg;
8203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8204 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8205 GNUNET_sh2s (&pa->ack_uuid.value),
8212 * Fragment the given @a pm to the given @a mtu. Adds
8213 * additional fragments to the neighbour as well. If the
8214 * @a mtu is too small, generates and error for the @a pm
8217 * @param queue which queue to fragment for
8218 * @param dvh path the message will take, or NULL
8219 * @param pm pending message to fragment for transmission
8220 * @return new message to transmit
8222 static struct PendingMessage *
8223 fragment_message (struct Queue *queue,
8224 struct DistanceVectorHop *dvh,
8225 struct PendingMessage *pm)
8227 struct PendingAcknowledgement *pa;
8228 struct PendingMessage *ff;
8231 mtu = (0 == queue->mtu)
8232 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
8234 set_pending_message_uuid (pm);
8235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8236 "Fragmenting message %llu <%llu> to %s for MTU %u\n",
8237 (unsigned long long) pm->msg_uuid.uuid,
8239 GNUNET_i2s (&pm->vl->target),
8240 (unsigned int) mtu);
8241 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8243 /* This invariant is established in #handle_add_queue_message() */
8244 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
8246 /* select fragment for transmission, descending the tree if it has
8247 been expanded until we are at a leaf or at a fragment that is small
8251 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
8252 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
8254 ff = ff->head_frag; /* descent into fragmented fragments */
8257 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
8259 /* Did not yet calculate all fragments, calculate next fragment */
8260 struct PendingMessage *frag;
8261 struct TransportFragmentBoxMessage tfb;
8269 orig = (const char *) &ff[1];
8270 msize = ff->bytes_msg;
8273 const struct TransportFragmentBoxMessage *tfbo;
8275 tfbo = (const struct TransportFragmentBoxMessage *) orig;
8276 orig += sizeof (struct TransportFragmentBoxMessage);
8277 msize -= sizeof (struct TransportFragmentBoxMessage);
8278 xoff = ntohs (tfbo->frag_off);
8280 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
8281 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
8283 GNUNET_malloc (sizeof (struct PendingMessage) +
8284 sizeof (struct TransportFragmentBoxMessage) + fragsize);
8285 frag->logging_uuid = logging_uuid_gen++;
8287 frag->frag_parent = ff;
8288 frag->timeout = pm->timeout;
8289 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
8290 frag->pmt = PMT_FRAGMENT_BOX;
8291 msg = (char *) &frag[1];
8292 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
8294 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
8295 tfb.ack_uuid = pa->ack_uuid;
8296 tfb.msg_uuid = pm->msg_uuid;
8297 tfb.frag_off = htons (ff->frag_off + xoff);
8298 tfb.msg_size = htons (pm->bytes_msg);
8299 memcpy (msg, &tfb, sizeof (tfb));
8300 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
8301 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
8302 ff->frag_off += fragsize;
8306 /* Move head to the tail and return it */
8307 GNUNET_CONTAINER_MDLL_remove (frag,
8308 ff->frag_parent->head_frag,
8309 ff->frag_parent->tail_frag,
8311 GNUNET_CONTAINER_MDLL_insert_tail (frag,
8312 ff->frag_parent->head_frag,
8313 ff->frag_parent->tail_frag,
8320 * Reliability-box the given @a pm. On error (can there be any), NULL
8321 * may be returned, otherwise the "replacement" for @a pm (which
8322 * should then be added to the respective neighbour's queue instead of
8323 * @a pm). If the @a pm is already fragmented or reliability boxed,
8324 * or itself an ACK, this function simply returns @a pm.
8326 * @param queue which queue to prepare transmission for
8327 * @param dvh path the message will take, or NULL
8328 * @param pm pending message to box for transmission over unreliabile queue
8329 * @return new message to transmit
8331 static struct PendingMessage *
8332 reliability_box_message (struct Queue *queue,
8333 struct DistanceVectorHop *dvh,
8334 struct PendingMessage *pm)
8336 struct TransportReliabilityBoxMessage rbox;
8337 struct PendingAcknowledgement *pa;
8338 struct PendingMessage *bpm;
8341 if (PMT_CORE != pm->pmt)
8342 return pm; /* already fragmented or reliability boxed, or control message:
8344 if (NULL != pm->bpm)
8345 return pm->bpm; /* already computed earlier: do nothing */
8346 GNUNET_assert (NULL == pm->head_frag);
8347 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
8351 client_send_response (pm);
8354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8355 "Preparing reliability box for message <%llu> to %s on queue %s\n",
8357 GNUNET_i2s (&pm->vl->target),
8359 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8361 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
8363 bpm->logging_uuid = logging_uuid_gen++;
8365 bpm->frag_parent = pm;
8366 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
8367 bpm->timeout = pm->timeout;
8368 bpm->pmt = PMT_RELIABILITY_BOX;
8369 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
8370 set_pending_message_uuid (bpm);
8371 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
8372 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
8373 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
8375 rbox.ack_uuid = pa->ack_uuid;
8376 msg = (char *) &bpm[1];
8377 memcpy (msg, &rbox, sizeof (rbox));
8378 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
8385 * Change the value of the `next_attempt` field of @a pm
8386 * to @a next_attempt and re-order @a pm in the transmission
8387 * list as required by the new timestmap.
8389 * @param pm a pending message to update
8390 * @param next_attempt timestamp to use
8393 update_pm_next_attempt (struct PendingMessage *pm,
8394 struct GNUNET_TIME_Absolute next_attempt)
8396 struct VirtualLink *vl = pm->vl;
8398 pm->next_attempt = next_attempt;
8399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8400 "Next attempt for message <%llu> set to %s\n",
8402 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
8404 if (NULL == pm->frag_parent)
8406 struct PendingMessage *pos;
8408 /* re-insert sort in neighbour list */
8409 GNUNET_CONTAINER_MDLL_remove (vl,
8410 vl->pending_msg_head,
8411 vl->pending_msg_tail,
8413 pos = vl->pending_msg_tail;
8414 while ((NULL != pos) &&
8415 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8417 GNUNET_CONTAINER_MDLL_insert_after (vl,
8418 vl->pending_msg_head,
8419 vl->pending_msg_tail,
8425 /* re-insert sort in fragment list */
8426 struct PendingMessage *fp = pm->frag_parent;
8427 struct PendingMessage *pos;
8429 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
8430 pos = fp->tail_frag;
8431 while ((NULL != pos) &&
8432 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8433 pos = pos->prev_frag;
8434 GNUNET_CONTAINER_MDLL_insert_after (frag,
8444 * Context for #select_best_pending_from_link().
8446 struct PendingMessageScoreContext
8449 * Set to the best message that was found, NULL for none.
8451 struct PendingMessage *best;
8454 * DVH that @e best should take, or NULL for direct transmission.
8456 struct DistanceVectorHop *dvh;
8459 * What is the estimated total overhead for this message?
8461 size_t real_overhead;
8464 * Number of pending messages we seriously considered this time.
8466 unsigned int consideration_counter;
8469 * Did we have to fragment?
8474 * Did we have to reliability box?
8481 * Select the best pending message from @a vl for transmission
8484 * @param sc[in,out] best message so far (NULL for none), plus scoring data
8485 * @param queue the queue that will be used for transmission
8486 * @param vl the virtual link providing the messages
8487 * @param dvh path we are currently considering, or NULL for none
8488 * @param overhead number of bytes of overhead to be expected
8489 * from DV encapsulation (0 for without DV)
8492 select_best_pending_from_link (struct PendingMessageScoreContext *sc,
8493 struct Queue *queue,
8494 struct VirtualLink *vl,
8495 struct DistanceVectorHop *dvh,
8498 struct GNUNET_TIME_Absolute now;
8500 now = GNUNET_TIME_absolute_get ();
8501 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
8504 size_t real_overhead = overhead;
8508 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
8509 continue; /* DV messages must not be DV-routed to next hop! */
8510 if (pos->next_attempt.abs_value_us > now.abs_value_us)
8511 break; /* too early for all messages, they are sorted by next_attempt */
8512 if (NULL != pos->qe)
8513 continue; /* not eligible */
8514 sc->consideration_counter++;
8515 /* determine if we have to reliability-box, if so add reliability box
8518 if ((GNUNET_NO == frag) &&
8519 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
8520 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
8523 real_overhead += sizeof (struct TransportReliabilityBoxMessage);
8525 /* determine if we have to fragment, if so add fragmentation
8528 if ( ( (0 != queue->mtu) &&
8529 (pos->bytes_msg + real_overhead > queue->mtu) ) ||
8530 (pos->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
8531 (NULL != pos->head_frag /* fragments already exist, should
8532 respect that even if MTU is 0 for
8536 relb = GNUNET_NO; /* if we fragment, we never also reliability box */
8537 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
8539 /* FIXME-OPTIMIZE: we could use an optimized, shorter fragmentation
8540 header without the ACK UUID when using a *reliable* channel! */
8542 real_overhead = overhead + sizeof (struct TransportFragmentBoxMessage);
8545 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
8546 message would beat it! */
8547 if (NULL != sc->best)
8549 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
8550 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
8551 experimentally validated. There may be some huge potential for
8552 improvement here. Also, we right now only compare how well the
8553 given message fits _this_ queue, and do not consider how well other
8554 queues might suit the message. Taking other queues into consideration
8555 may further improve the result, but could also be expensive
8556 in terms of CPU time. */
8557 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
8558 long long pm_score = frag * 40 + relb * 20 + real_overhead;
8559 long long time_delta =
8560 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us) /
8563 /* "time_delta" considers which message has been 'ready' for transmission
8564 for longer, if a message has a preference for low latency, increase
8565 the weight of the time_delta by 10x if it is favorable for that message */
8566 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8567 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
8568 time_delta *= 10; /* increase weight (always, both are low latency) */
8569 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8572 10; /* increase weight, favors 'pos', which is low latency */
8573 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8576 10; /* increase weight, favors 'sc->best', which is low latency */
8577 if (0 != queue->mtu)
8579 /* Grant bonus if we are bellow MTU, larger bonus the closer we will
8581 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
8582 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
8583 if (queue->mtu > real_overhead + pos->bytes_msg)
8584 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
8586 if (sc_score + time_delta > pm_score)
8587 continue; /* sc_score larger, keep sc->best */
8598 * Function to call to further operate on the now DV encapsulated
8599 * message @a hdr, forwarding it via @a next_hop under respect of
8602 * @param cls a `struct PendingMessageScoreContext`
8603 * @param next_hop next hop of the DV path
8604 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
8605 * @param options options of the original message
8608 extract_box_cb (void *cls,
8609 struct Neighbour *next_hop,
8610 const struct GNUNET_MessageHeader *hdr,
8611 enum RouteMessageOptions options)
8613 struct PendingMessageScoreContext *sc = cls;
8614 struct PendingMessage *pm = sc->best;
8615 struct PendingMessage *bpm;
8616 uint16_t bsize = ntohs (hdr->size);
8618 GNUNET_assert (NULL == pm->bpm);
8619 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + bsize);
8620 bpm->logging_uuid = logging_uuid_gen++;
8621 bpm->pmt = PMT_DV_BOX;
8622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8623 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
8626 GNUNET_i2s (&next_hop->pid));
8627 memcpy (&bpm[1], hdr, bsize);
8633 * We believe we are ready to transmit a `struct PendingMessage` on a
8634 * queue, the big question is which one! We need to see if there is
8635 * one pending that is allowed by flow control and congestion control
8636 * and (ideally) matches our queue's performance profile.
8638 * If such a message is found, we give the message to the communicator
8639 * for transmission (updating the tracker, and re-scheduling ourselves
8642 * If no such message is found, the queue's `idle` field must be set
8645 * @param cls the `struct Queue` to process transmissions for
8648 transmit_on_queue (void *cls)
8650 struct Queue *queue = cls;
8651 struct Neighbour *n = queue->neighbour;
8652 struct PendingMessageScoreContext sc;
8653 struct PendingMessage *pm;
8655 queue->transmit_task = NULL;
8658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8659 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
8660 GNUNET_i2s (&n->pid),
8662 queue->idle = GNUNET_YES;
8665 memset (&sc, 0, sizeof (sc));
8666 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
8667 if (NULL == sc.best)
8669 /* Also look at DVH that have the n as first hop! */
8670 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
8671 dvh = dvh->next_neighbour)
8673 select_best_pending_from_link (&sc,
8677 sizeof (struct GNUNET_PeerIdentity) *
8678 (1 + dvh->distance) +
8679 sizeof (struct TransportDVBoxMessage) +
8680 sizeof (struct TransportDVBoxPayloadP));
8683 if (NULL == sc.best)
8685 /* no message pending, nothing to do here! */
8686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8687 "No pending messages, queue `%s' to %s now idle\n",
8689 GNUNET_i2s (&n->pid));
8690 queue->idle = GNUNET_YES;
8694 /* Given selection in `sc`, do transmission */
8698 GNUNET_assert (PMT_DV_BOX != pm->pmt);
8699 if (NULL != sc.best->bpm)
8701 /* We did this boxing before, but possibly for a different path!
8702 Discard old DV box! OPTIMIZE-ME: we might want to check if
8703 it is the same and then not re-build the message... */
8704 free_pending_message (sc.best->bpm);
8705 sc.best->bpm = NULL;
8707 encapsulate_for_dv (sc.dvh->dv,
8710 (const struct GNUNET_MessageHeader *) &sc.best[1],
8714 GNUNET_assert (NULL != sc.best->bpm);
8717 if (GNUNET_YES == sc.frag)
8719 pm = fragment_message (queue, sc.dvh, pm);
8722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8723 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
8725 GNUNET_i2s (&n->pid),
8727 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8730 else if (GNUNET_YES == sc.relb)
8732 pm = reliability_box_message (queue, sc.dvh, pm);
8735 /* Reliability boxing failed, try next message... */
8737 GNUNET_ERROR_TYPE_DEBUG,
8738 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
8740 GNUNET_i2s (&n->pid),
8742 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8747 /* Pass 'pm' for transission to the communicator */
8749 GNUNET_ERROR_TYPE_DEBUG,
8750 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
8753 GNUNET_i2s (&n->pid),
8754 sc.consideration_counter);
8756 /* Flow control: increment amount of traffic sent; if we are routing
8757 via DV (and thus the ultimate target of the pending message is for
8758 a different virtual link than the one of the queue), then we need
8759 to use up not only the window of the direct link but also the
8760 flow control window for the DV link! */
8761 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
8763 if (pm->vl != queue->neighbour->vl)
8765 /* If the virtual link of the queue differs, this better be distance
8767 GNUNET_assert (NULL != sc.dvh);
8768 /* If we do distance vector routing, we better not do this for a
8769 message that was itself DV-routed */
8770 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
8771 /* We use the size of the unboxed message here, to avoid counting
8772 the DV-Box header which is eaten up on the way by intermediaries */
8773 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
8777 GNUNET_assert (NULL == sc.dvh);
8780 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
8782 /* Check if this transmission somehow conclusively finished handing 'pm'
8783 even without any explicit ACKs */
8784 if ((PMT_CORE == pm->pmt) ||
8785 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
8787 completed_pending_message (pm);
8791 /* Message not finished, waiting for acknowledgement.
8792 Update time by which we might retransmit 's' based on queue
8793 characteristics (i.e. RTT); it takes one RTT for the message to
8794 arrive and the ACK to come back in the best case; but the other
8795 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
8798 OPTIMIZE: Note that in the future this heuristic should likely
8799 be improved further (measure RTT stability, consider message
8800 urgency and size when delaying ACKs, etc.) */
8801 update_pm_next_attempt (pm,
8802 GNUNET_TIME_relative_to_absolute (
8803 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
8806 /* finally, re-schedule queue transmission task itself */
8807 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8812 * Queue to a peer went down. Process the request.
8814 * @param cls the client
8815 * @param dqm the send message that was sent
8818 handle_del_queue_message (void *cls,
8819 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
8821 struct TransportClient *tc = cls;
8823 if (CT_COMMUNICATOR != tc->type)
8826 GNUNET_SERVICE_client_drop (tc->client);
8829 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8830 queue = queue->next_client)
8832 struct Neighbour *neighbour = queue->neighbour;
8834 if ((dqm->qid != queue->qid) ||
8835 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
8837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8838 "Dropped queue %s to peer %s\n",
8840 GNUNET_i2s (&neighbour->pid));
8842 GNUNET_SERVICE_client_continue (tc->client);
8846 GNUNET_SERVICE_client_drop (tc->client);
8851 * Message was transmitted. Process the request.
8853 * @param cls the client
8854 * @param sma the send message that was sent
8857 handle_send_message_ack (void *cls,
8858 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
8860 struct TransportClient *tc = cls;
8861 struct QueueEntry *qe;
8862 struct PendingMessage *pm;
8864 if (CT_COMMUNICATOR != tc->type)
8867 GNUNET_SERVICE_client_drop (tc->client);
8871 /* find our queue entry matching the ACK */
8873 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
8874 queue = queue->next_client)
8876 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
8878 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
8881 if (qep->mid != sma->mid)
8890 /* this should never happen */
8892 GNUNET_SERVICE_client_drop (tc->client);
8895 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
8896 qe->queue->queue_tail,
8898 qe->queue->queue_length--;
8899 tc->details.communicator.total_queue_length--;
8900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8901 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
8903 GNUNET_i2s (&qe->queue->neighbour->pid),
8904 qe->queue->queue_length,
8905 tc->details.communicator.total_queue_length);
8906 GNUNET_SERVICE_client_continue (tc->client);
8908 /* if applicable, resume transmissions that waited on ACK */
8909 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
8910 tc->details.communicator.total_queue_length)
8912 /* Communicator dropped below threshold, resume all queues
8913 incident with this client! */
8914 GNUNET_STATISTICS_update (
8916 "# Transmission throttled due to communicator queue limit",
8919 for (struct Queue *queue = tc->details.communicator.queue_head;
8921 queue = queue->next_client)
8922 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8924 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
8926 /* queue dropped below threshold; only resume this one queue */
8927 GNUNET_STATISTICS_update (GST_stats,
8928 "# Transmission throttled due to queue queue limit",
8931 schedule_transmit_on_queue (qe->queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8934 if (NULL != (pm = qe->pm))
8936 struct VirtualLink *vl;
8938 GNUNET_assert (qe == pm->qe);
8940 /* If waiting for this communicator may have blocked transmission
8941 of pm on other queues for this neighbour, force schedule
8942 transmit on queue for queues of the neighbour */
8944 if (vl->pending_msg_head == pm)
8945 check_vl_transmission (vl);
8952 * Iterator telling new MONITOR client about all existing
8955 * @param cls the new `struct TransportClient`
8956 * @param pid a connected peer
8957 * @param value the `struct Neighbour` with more information
8958 * @return #GNUNET_OK (continue to iterate)
8961 notify_client_queues (void *cls,
8962 const struct GNUNET_PeerIdentity *pid,
8965 struct TransportClient *tc = cls;
8966 struct Neighbour *neighbour = value;
8968 GNUNET_assert (CT_MONITOR == tc->type);
8969 for (struct Queue *q = neighbour->queue_head; NULL != q;
8970 q = q->next_neighbour)
8972 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
8974 .num_msg_pending = q->num_msg_pending,
8975 .num_bytes_pending = q->num_bytes_pending};
8977 notify_monitor (tc, pid, q->address, q->nt, &me);
8984 * Initialize a monitor client.
8986 * @param cls the client
8987 * @param start the start message that was sent
8990 handle_monitor_start (void *cls,
8991 const struct GNUNET_TRANSPORT_MonitorStart *start)
8993 struct TransportClient *tc = cls;
8995 if (CT_NONE != tc->type)
8998 GNUNET_SERVICE_client_drop (tc->client);
9001 tc->type = CT_MONITOR;
9002 tc->details.monitor.peer = start->peer;
9003 tc->details.monitor.one_shot = ntohl (start->one_shot);
9004 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
9005 GNUNET_SERVICE_client_mark_monitor (tc->client);
9006 GNUNET_SERVICE_client_continue (tc->client);
9011 * Find transport client providing communication service
9012 * for the protocol @a prefix.
9014 * @param prefix communicator name
9015 * @return NULL if no such transport client is available
9017 static struct TransportClient *
9018 lookup_communicator (const char *prefix)
9020 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
9022 if (CT_COMMUNICATOR != tc->type)
9024 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
9028 GNUNET_ERROR_TYPE_WARNING,
9029 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
9036 * Signature of a function called with a communicator @a address of a peer
9037 * @a pid that an application wants us to connect to.
9039 * @param pid target peer
9040 * @param address the address to try
9043 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
9045 static uint32_t idgen;
9046 struct TransportClient *tc;
9048 struct GNUNET_TRANSPORT_CreateQueue *cqm;
9049 struct GNUNET_MQ_Envelope *env;
9052 prefix = GNUNET_HELLO_address_to_prefix (address);
9055 GNUNET_break (0); /* We got an invalid address!? */
9058 tc = lookup_communicator (prefix);
9061 GNUNET_STATISTICS_update (GST_stats,
9062 "# Suggestions ignored due to missing communicator",
9065 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9066 "Cannot connect to %s at `%s', no matching communicator present\n",
9071 /* forward suggestion for queue creation to communicator */
9072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9073 "Request #%u for `%s' communicator to create queue to `%s'\n",
9074 (unsigned int) idgen,
9077 alen = strlen (address) + 1;
9079 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
9080 cqm->request_id = htonl (idgen++);
9081 cqm->receiver = *pid;
9082 memcpy (&cqm[1], address, alen);
9083 GNUNET_MQ_send (tc->mq, env);
9088 * The queue @a q (which matches the peer and address in @a vs) is
9089 * ready for queueing. We should now queue the validation request.
9091 * @param q queue to send on
9092 * @param vs state to derive validation challenge from
9095 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
9097 struct TransportValidationChallengeMessage tvc;
9099 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
9101 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
9102 tvc.header.size = htons (sizeof (tvc));
9103 tvc.reserved = htonl (0);
9104 tvc.challenge = vs->challenge;
9105 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
9106 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9107 "Sending address validation challenge %s to %s\n",
9108 GNUNET_sh2s (&tvc.challenge.value),
9109 GNUNET_i2s (&q->neighbour->pid));
9110 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
9115 * Task run periodically to validate some address based on #validation_heap.
9120 validation_start_cb (void *cls)
9122 struct ValidationState *vs;
9126 validation_task = NULL;
9127 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9128 /* drop validations past their expiration */
9131 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
9133 free_validation_state (vs);
9134 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9138 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9139 "Address validation task not scheduled anymore, nothing to do\n");
9140 return; /* woopsie, no more addresses known, should only
9141 happen if we're really a lonely peer */
9143 q = find_queue (&vs->pid, vs->address);
9146 vs->awaiting_queue = GNUNET_YES;
9147 suggest_to_connect (&vs->pid, vs->address);
9150 validation_transmit_on_queue (q, vs);
9151 /* Finally, reschedule next attempt */
9152 vs->challenge_backoff =
9153 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
9154 MAX_VALIDATION_CHALLENGE_FREQ);
9155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9156 "Address validation task will run again in %s\n",
9157 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
9159 update_next_challenge_time (vs,
9160 GNUNET_TIME_relative_to_absolute (
9161 vs->challenge_backoff));
9166 * Closure for #check_connection_quality.
9168 struct QueueQualityContext
9171 * Set to the @e k'th queue encountered.
9176 * Set to the number of quality queues encountered.
9178 unsigned int quality_count;
9181 * Set to the total number of queues encountered.
9183 unsigned int num_queues;
9186 * Decremented for each queue, for selection of the
9187 * k-th queue in @e q.
9194 * Check whether any queue to the given neighbour is
9195 * of a good "quality" and if so, increment the counter.
9196 * Also counts the total number of queues, and returns
9197 * the k-th queue found.
9199 * @param cls a `struct QueueQualityContext *` with counters
9200 * @param pid peer this is about
9201 * @param value a `struct Neighbour`
9202 * @return #GNUNET_OK (continue to iterate)
9205 check_connection_quality (void *cls,
9206 const struct GNUNET_PeerIdentity *pid,
9209 struct QueueQualityContext *ctx = cls;
9210 struct Neighbour *n = value;
9215 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9220 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
9221 statistics and consider those as well here? */
9222 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
9223 do_inc = GNUNET_YES;
9225 if (GNUNET_YES == do_inc)
9226 ctx->quality_count++;
9232 * Task run when we CONSIDER initiating a DV learn
9233 * process. We first check that sending out a message is
9234 * even possible (queues exist), then that it is desirable
9235 * (if not, reschedule the task for later), and finally
9236 * we may then begin the job. If there are too many
9237 * entries in the #dvlearn_map, we purge the oldest entry
9243 start_dv_learn (void *cls)
9245 struct LearnLaunchEntry *lle;
9246 struct QueueQualityContext qqc;
9247 struct TransportDVLearnMessage dvl;
9250 dvlearn_task = NULL;
9251 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
9252 return; /* lost all connectivity, cannot do learning */
9253 qqc.quality_count = 0;
9255 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9256 &check_connection_quality,
9258 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
9260 struct GNUNET_TIME_Relative delay;
9261 unsigned int factor;
9263 /* scale our retries by how far we are above the threshold */
9264 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
9265 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
9266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9267 "At connection quality %u, will launch DV learn in %s\n",
9269 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
9270 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
9273 /* remove old entries in #dvlearn_map if it has grown too big */
9274 while (MAX_DV_LEARN_PENDING >=
9275 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
9278 GNUNET_assert (GNUNET_YES ==
9279 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
9280 &lle->challenge.value,
9282 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9285 /* setup data structure for learning */
9286 lle = GNUNET_new (struct LearnLaunchEntry);
9287 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9289 sizeof (lle->challenge));
9290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9291 "Starting launch DV learn with challenge %s\n",
9292 GNUNET_sh2s (&lle->challenge.value));
9293 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
9294 GNUNET_break (GNUNET_YES ==
9295 GNUNET_CONTAINER_multishortmap_put (
9297 &lle->challenge.value,
9299 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9300 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
9301 dvl.header.size = htons (sizeof (dvl));
9302 dvl.num_hops = htons (0);
9303 dvl.bidirectional = htons (0);
9304 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
9305 dvl.monotonic_time =
9306 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
9308 struct DvInitPS dvip = {.purpose.purpose = htonl (
9309 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
9310 .purpose.size = htonl (sizeof (dvip)),
9311 .monotonic_time = dvl.monotonic_time,
9312 .challenge = lle->challenge};
9314 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9318 dvl.initiator = GST_my_identity;
9319 dvl.challenge = lle->challenge;
9321 qqc.quality_count = 0;
9322 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
9325 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9326 &check_connection_quality,
9328 GNUNET_assert (NULL != qqc.q);
9330 /* Do this as close to transmission time as possible! */
9331 lle->launch_time = GNUNET_TIME_absolute_get ();
9333 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
9334 /* reschedule this job, randomizing the time it runs (but no
9336 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
9337 DV_LEARN_BASE_FREQUENCY),
9344 * A new queue has been created, check if any address validation
9345 * requests have been waiting for it.
9347 * @param cls a `struct Queue`
9348 * @param pid peer concerned (unused)
9349 * @param value a `struct ValidationState`
9350 * @return #GNUNET_NO if a match was found and we can stop looking
9353 check_validation_request_pending (void *cls,
9354 const struct GNUNET_PeerIdentity *pid,
9357 struct Queue *q = cls;
9358 struct ValidationState *vs = value;
9361 if ((GNUNET_YES == vs->awaiting_queue) &&
9362 (0 == strcmp (vs->address, q->address)))
9364 vs->awaiting_queue = GNUNET_NO;
9365 validation_transmit_on_queue (q, vs);
9373 * Function called with the monotonic time of a DV initiator
9374 * by PEERSTORE. Updates the time.
9376 * @param cls a `struct Neighbour`
9377 * @param record the information found, NULL for the last call
9378 * @param emsg error message
9381 neighbour_dv_monotime_cb (void *cls,
9382 const struct GNUNET_PEERSTORE_Record *record,
9385 struct Neighbour *n = cls;
9386 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9391 /* we're done with #neighbour_dv_monotime_cb() invocations,
9392 continue normal processing */
9394 n->dv_monotime_available = GNUNET_YES;
9397 if (sizeof (*mtbe) != record->value_size)
9402 mtbe = record->value;
9403 n->last_dv_learn_monotime =
9404 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
9405 GNUNET_TIME_absolute_ntoh (*mtbe));
9410 * New queue became available. Process the request.
9412 * @param cls the client
9413 * @param aqm the send message that was sent
9416 handle_add_queue_message (void *cls,
9417 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9419 struct TransportClient *tc = cls;
9420 struct Queue *queue;
9421 struct Neighbour *neighbour;
9425 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
9427 /* MTU so small as to be useless for transmissions,
9428 required for #fragment_message()! */
9429 GNUNET_break_op (0);
9430 GNUNET_SERVICE_client_drop (tc->client);
9433 neighbour = lookup_neighbour (&aqm->receiver);
9434 if (NULL == neighbour)
9436 neighbour = GNUNET_new (struct Neighbour);
9437 neighbour->pid = aqm->receiver;
9438 GNUNET_assert (GNUNET_OK ==
9439 GNUNET_CONTAINER_multipeermap_put (
9443 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9445 GNUNET_PEERSTORE_iterate (peerstore,
9448 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
9449 &neighbour_dv_monotime_cb,
9452 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
9453 addr = (const char *) &aqm[1];
9454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9455 "New queue %s to %s available with QID %llu\n",
9457 GNUNET_i2s (&aqm->receiver),
9458 (unsigned long long) aqm->qid);
9459 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
9461 queue->address = (const char *) &queue[1];
9462 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
9463 queue->qid = aqm->qid;
9464 queue->mtu = ntohl (aqm->mtu);
9465 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
9466 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
9467 queue->neighbour = neighbour;
9468 queue->idle = GNUNET_YES;
9469 memcpy (&queue[1], addr, addr_len);
9470 /* notify monitors about new queue */
9472 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
9474 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
9476 GNUNET_CONTAINER_MDLL_insert (neighbour,
9477 neighbour->queue_head,
9478 neighbour->queue_tail,
9480 GNUNET_CONTAINER_MDLL_insert (client,
9481 tc->details.communicator.queue_head,
9482 tc->details.communicator.queue_tail,
9484 /* check if valdiations are waiting for the queue */
9486 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9488 &check_validation_request_pending,
9490 /* look for traffic for this queue */
9491 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9492 /* might be our first queue, try launching DV learning */
9493 if (NULL == dvlearn_task)
9494 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
9495 GNUNET_SERVICE_client_continue (tc->client);
9500 * Communicator tells us that our request to create a queue "worked", that
9501 * is setting up the queue is now in process.
9503 * @param cls the `struct TransportClient`
9504 * @param cqr confirmation message
9507 handle_queue_create_ok (void *cls,
9508 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9510 struct TransportClient *tc = cls;
9512 if (CT_COMMUNICATOR != tc->type)
9515 GNUNET_SERVICE_client_drop (tc->client);
9518 GNUNET_STATISTICS_update (GST_stats,
9519 "# Suggestions succeeded at communicator",
9522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9523 "Request #%u for communicator to create queue succeeded\n",
9524 (unsigned int) ntohs (cqr->request_id));
9525 GNUNET_SERVICE_client_continue (tc->client);
9530 * Communicator tells us that our request to create a queue failed. This
9531 * usually indicates that the provided address is simply invalid or that the
9532 * communicator's resources are exhausted.
9534 * @param cls the `struct TransportClient`
9535 * @param cqr failure message
9538 handle_queue_create_fail (
9540 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9542 struct TransportClient *tc = cls;
9544 if (CT_COMMUNICATOR != tc->type)
9547 GNUNET_SERVICE_client_drop (tc->client);
9550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9551 "Request #%u for communicator to create queue failed\n",
9552 (unsigned int) ntohs (cqr->request_id));
9553 GNUNET_STATISTICS_update (GST_stats,
9554 "# Suggestions failed in queue creation at communicator",
9557 GNUNET_SERVICE_client_continue (tc->client);
9562 * We have received a `struct ExpressPreferenceMessage` from an application
9565 * @param cls handle to the client
9566 * @param msg the start message
9569 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
9571 struct TransportClient *tc = cls;
9572 struct PeerRequest *pr;
9574 if (CT_APPLICATION != tc->type)
9577 GNUNET_SERVICE_client_drop (tc->client);
9580 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
9585 GNUNET_SERVICE_client_drop (tc->client);
9588 (void) stop_peer_request (tc, &pr->pid, pr);
9589 GNUNET_SERVICE_client_continue (tc->client);
9594 * Function called by PEERSTORE for each matching record.
9596 * @param cls closure, a `struct PeerRequest`
9597 * @param record peerstore record information
9598 * @param emsg error message, or NULL if no errors
9601 handle_hello_for_client (void *cls,
9602 const struct GNUNET_PEERSTORE_Record *record,
9605 struct PeerRequest *pr = cls;
9610 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9611 "Got failure from PEERSTORE: %s\n",
9615 val = record->value;
9616 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
9621 start_address_validation (&pr->pid, (const char *) record->value);
9626 * We have received a `struct ExpressPreferenceMessage` from an application
9629 * @param cls handle to the client
9630 * @param msg the start message
9633 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9635 struct TransportClient *tc = cls;
9636 struct PeerRequest *pr;
9638 if (CT_NONE == tc->type)
9640 tc->type = CT_APPLICATION;
9641 tc->details.application.requests =
9642 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9644 if (CT_APPLICATION != tc->type)
9647 GNUNET_SERVICE_client_drop (tc->client);
9650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9651 "Client suggested we talk to %s with preference %d at rate %u\n",
9652 GNUNET_i2s (&msg->peer),
9653 (int) ntohl (msg->pk),
9654 (int) ntohl (msg->bw.value__));
9655 pr = GNUNET_new (struct PeerRequest);
9657 pr->pid = msg->peer;
9659 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
9660 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
9661 tc->details.application.requests,
9664 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
9668 GNUNET_SERVICE_client_drop (tc->client);
9671 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
9674 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9675 &handle_hello_for_client,
9677 GNUNET_SERVICE_client_continue (tc->client);
9682 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
9685 * @param cls a `struct TransportClient *`
9686 * @param m message to verify
9687 * @return #GNUNET_OK on success
9690 check_request_hello_validation (void *cls,
9691 const struct RequestHelloValidationMessage *m)
9694 GNUNET_MQ_check_zero_termination (m);
9700 * A client encountered an address of another peer. Consider validating it,
9701 * and if validation succeeds, persist it to PEERSTORE.
9703 * @param cls a `struct TransportClient *`
9704 * @param m message to verify
9707 handle_request_hello_validation (void *cls,
9708 const struct RequestHelloValidationMessage *m)
9710 struct TransportClient *tc = cls;
9712 start_address_validation (&m->peer, (const char *) &m[1]);
9713 GNUNET_SERVICE_client_continue (tc->client);
9718 * Free neighbour entry.
9722 * @param value a `struct Neighbour`
9723 * @return #GNUNET_OK (always)
9726 free_neighbour_cb (void *cls,
9727 const struct GNUNET_PeerIdentity *pid,
9730 struct Neighbour *neighbour = value;
9734 GNUNET_break (0); // should this ever happen?
9735 free_neighbour (neighbour);
9742 * Free DV route entry.
9746 * @param value a `struct DistanceVector`
9747 * @return #GNUNET_OK (always)
9750 free_dv_routes_cb (void *cls,
9751 const struct GNUNET_PeerIdentity *pid,
9754 struct DistanceVector *dv = value;
9765 * Free validation state.
9769 * @param value a `struct ValidationState`
9770 * @return #GNUNET_OK (always)
9773 free_validation_state_cb (void *cls,
9774 const struct GNUNET_PeerIdentity *pid,
9777 struct ValidationState *vs = value;
9781 free_validation_state (vs);
9787 * Free pending acknowledgement.
9791 * @param value a `struct PendingAcknowledgement`
9792 * @return #GNUNET_OK (always)
9795 free_pending_ack_cb (void *cls,
9796 const struct GNUNET_ShortHashCode *key,
9799 struct PendingAcknowledgement *pa = value;
9803 free_pending_acknowledgement (pa);
9809 * Free acknowledgement cummulator.
9813 * @param value a `struct AcknowledgementCummulator`
9814 * @return #GNUNET_OK (always)
9817 free_ack_cummulator_cb (void *cls,
9818 const struct GNUNET_PeerIdentity *pid,
9821 struct AcknowledgementCummulator *ac = value;
9831 * Function called when the service shuts down. Unloads our plugins
9832 * and cancels pending validations.
9834 * @param cls closure, unused
9837 do_shutdown (void *cls)
9839 struct LearnLaunchEntry *lle;
9842 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9843 if (NULL != peerstore)
9845 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9848 if (NULL != GST_stats)
9850 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9853 if (NULL != GST_my_private_key)
9855 GNUNET_free (GST_my_private_key);
9856 GST_my_private_key = NULL;
9858 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9859 &free_ack_cummulator_cb,
9861 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9862 ack_cummulators = NULL;
9863 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
9864 &free_pending_ack_cb,
9866 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
9867 pending_acks = NULL;
9868 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9869 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9871 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9872 GNUNET_CONTAINER_multipeermap_destroy (links);
9874 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9875 &free_backtalker_cb,
9877 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9879 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9880 &free_validation_state_cb,
9882 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9883 validation_map = NULL;
9884 while (NULL != ir_head)
9885 free_incoming_request (ir_head);
9886 GNUNET_assert (0 == ir_total);
9887 while (NULL != (lle = lle_head))
9889 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9892 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
9894 GNUNET_CONTAINER_heap_destroy (validation_heap);
9895 validation_heap = NULL;
9896 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
9897 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
9903 * Initiate transport service.
9905 * @param cls closure
9906 * @param c configuration to use
9907 * @param service the initialized service
9911 const struct GNUNET_CONFIGURATION_Handle *c,
9912 struct GNUNET_SERVICE_Handle *service)
9917 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
9919 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9920 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
9921 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
9922 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9923 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
9924 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9925 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
9927 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9929 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
9930 GST_my_private_key =
9931 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
9932 if (NULL == GST_my_private_key)
9935 GNUNET_ERROR_TYPE_ERROR,
9937 "Transport service is lacking key configuration settings. Exiting.\n"));
9938 GNUNET_SCHEDULER_shutdown ();
9941 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
9942 &GST_my_identity.public_key);
9943 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9944 "My identity is `%s'\n",
9945 GNUNET_i2s_full (&GST_my_identity));
9946 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
9947 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
9948 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
9949 if (NULL == peerstore)
9952 GNUNET_SCHEDULER_shutdown ();
9959 * Define "main" method using service macro.
9961 GNUNET_SERVICE_MAIN (
9963 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
9966 &client_disconnect_cb,
9968 /* communication with applications */
9969 GNUNET_MQ_hd_fixed_size (suggest,
9970 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
9971 struct ExpressPreferenceMessage,
9973 GNUNET_MQ_hd_fixed_size (suggest_cancel,
9974 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
9975 struct ExpressPreferenceMessage,
9977 GNUNET_MQ_hd_var_size (request_hello_validation,
9978 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
9979 struct RequestHelloValidationMessage,
9981 /* communication with core */
9982 GNUNET_MQ_hd_fixed_size (client_start,
9983 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
9984 struct StartMessage,
9986 GNUNET_MQ_hd_var_size (client_send,
9987 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
9988 struct OutboundMessage,
9990 GNUNET_MQ_hd_fixed_size (client_recv_ok,
9991 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
9992 struct RecvOkMessage,
9994 /* communication with communicators */
9995 GNUNET_MQ_hd_var_size (communicator_available,
9996 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
9997 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
9999 GNUNET_MQ_hd_var_size (communicator_backchannel,
10000 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
10001 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
10003 GNUNET_MQ_hd_var_size (add_address,
10004 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
10005 struct GNUNET_TRANSPORT_AddAddressMessage,
10007 GNUNET_MQ_hd_fixed_size (del_address,
10008 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
10009 struct GNUNET_TRANSPORT_DelAddressMessage,
10011 GNUNET_MQ_hd_var_size (incoming_msg,
10012 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
10013 struct GNUNET_TRANSPORT_IncomingMessage,
10015 GNUNET_MQ_hd_fixed_size (queue_create_ok,
10016 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
10017 struct GNUNET_TRANSPORT_CreateQueueResponse,
10019 GNUNET_MQ_hd_fixed_size (queue_create_fail,
10020 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
10021 struct GNUNET_TRANSPORT_CreateQueueResponse,
10023 GNUNET_MQ_hd_var_size (add_queue_message,
10024 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
10025 struct GNUNET_TRANSPORT_AddQueueMessage,
10027 GNUNET_MQ_hd_fixed_size (del_queue_message,
10028 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
10029 struct GNUNET_TRANSPORT_DelQueueMessage,
10031 GNUNET_MQ_hd_fixed_size (send_message_ack,
10032 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
10033 struct GNUNET_TRANSPORT_SendMessageToAck,
10035 /* communication with monitors */
10036 GNUNET_MQ_hd_fixed_size (monitor_start,
10037 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
10038 struct GNUNET_TRANSPORT_MonitorStart,
10040 GNUNET_MQ_handler_end ());
10043 /* end of file gnunet-service-transport.c */