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 * - add (more) logging
28 * - realize transport-to-transport flow control (needed in case
29 * communicators do not offer flow control). Note that we may not
30 * want to simply delay the ACKs as that may cause unnecessary
31 * re-transmissions. => Introduce proper flow and congestion window(s)!
32 * - review retransmission logic, right now there is no smartness there!
33 * => congestion control, flow control, etc [PERFORMANCE-BASICS]
36 * - When forwarding DV learn messages, if a peer is reached that
37 * has a *bidirectional* link to the origin beyond 1st hop,
38 * do NOT forward it to peers _other_ than the origin, as
39 * there is clearly a better path directly from the origin to
40 * whatever else we could reach.
41 * - AcknowledgementUUIDPs are overkill with 256 bits (128 would do)
42 * => Need 128 bit hash map though! [BANDWIDTH, MEMORY]
43 * - queue_send_msg and route_message both by API design have to make copies
44 * of the payload, and route_message on top of that requires a malloc/free.
45 * Change design to approximate "zero" copy better... [CPU]
46 * - could avoid copying body of message into each fragment and keep
47 * fragments as just pointers into the original message and only
48 * fully build fragments just before transmission (optimization, should
49 * reduce CPU and memory use) [CPU, MEMORY]
50 * - if messages are below MTU, consider adding ACKs and other stuff
51 * to the same transmission to avoid tiny messages (requires planning at
52 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
53 * - When we passively learned DV (with unconfirmed freshness), we
54 * right now add the path to our list but with a zero path_valid_until
55 * time and only use it for unconfirmed routes. However, we could consider
56 * triggering an explicit validation mechansim ourselves, specifically routing
57 * a challenge-response message over the path [ROUTING]
58 * - Track ACK losses based on ACK-counter [ROUTING]
60 * Design realizations / discussion:
61 * - communicators do flow control by calling MQ "notify sent"
62 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
63 * or explicitly via backchannel FC ACKs. As long as the
64 * channel is not full, they may 'notify sent' even if the other
65 * peer has not yet confirmed receipt. The other peer confirming
66 * is _only_ for FC, not for more reliable transmission; reliable
67 * transmission (i.e. of fragments) is left to _transport_.
68 * - ACKs sent back in uni-directional communicators are done via
69 * the background channel API; here transport _may_ initially
70 * broadcast (with bounded # hops) if no path is known;
71 * - transport should _integrate_ DV-routing and build a view of
72 * the network; then background channel traffic can be
73 * routed via DV as well as explicit "DV" traffic.
74 * - background channel is also used for ACKs and NAT traversal support
75 * - transport service is responsible for AEAD'ing the background
76 * channel, timestamps and monotonic time are used against replay
77 * of old messages -> peerstore needs to be supplied with
78 * "latest timestamps seen" data
79 * - if transport implements DV, we likely need a 3rd peermap
80 * in addition to ephemerals and (direct) neighbours
81 * ==> check if stuff needs to be moved out of "Neighbour"
82 * - transport should encapsualte core-level messages and do its
83 * own ACKing for RTT/goodput/loss measurements _and_ fragment
87 #include "gnunet_util_lib.h"
88 #include "gnunet_statistics_service.h"
89 #include "gnunet_transport_monitor_service.h"
90 #include "gnunet_peerstore_service.h"
91 #include "gnunet_hello_lib.h"
92 #include "gnunet_signatures.h"
93 #include "transport.h"
96 * Maximum number of messages we acknowledge together in one
97 * cummulative ACK. Larger values may save a bit of bandwidth.
99 #define MAX_CUMMULATIVE_ACKS 64
102 * What is the size we assume for a read operation in the
103 * absence of an MTU for the purpose of flow control?
105 #define IN_PACKET_SIZE_WITHOUT_MTU 128
108 * Number of slots we keep of historic data for computation of
109 * goodput / message loss ratio.
111 #define GOODPUT_AGING_SLOTS 4
114 * Maximum number of peers we select for forwarding DVInit
115 * messages at the same time (excluding initiator).
117 #define MAX_DV_DISCOVERY_SELECTION 16
120 * Window size. How many messages to the same target do we pass
121 * to CORE without a RECV_OK in between? Small values limit
122 * thoughput, large values will increase latency.
124 * FIXME-OPTIMIZE: find out what good values are experimentally,
125 * maybe set adaptively (i.e. to observed available bandwidth).
127 #define RECV_WINDOW_SIZE 4
130 * Minimum number of hops we should forward DV learn messages
131 * even if they are NOT useful for us in hope of looping
132 * back to the initiator?
134 * FIXME: allow initiator some control here instead?
136 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
139 * Maximum DV distance allowed ever.
141 #define MAX_DV_HOPS_ALLOWED 16
144 * Maximum number of DV learning activities we may
145 * have pending at the same time.
147 #define MAX_DV_LEARN_PENDING 64
150 * Maximum number of DV paths we keep simultaneously to the same target.
152 #define MAX_DV_PATHS_TO_TARGET 3
155 * If a queue delays the next message by more than this number
156 * of seconds we log a warning. Note: this is for testing,
157 * the value chosen here might be too aggressively low!
159 #define DELAY_WARN_THRESHOLD \
160 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
163 * We only consider queues as "quality" connections when
164 * suppressing the generation of DV initiation messages if
165 * the latency of the queue is below this threshold.
167 #define DV_QUALITY_RTT_THRESHOLD \
168 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
171 * How long do we consider a DV path valid if we see no
172 * further updates on it? Note: the value chosen here might be too low!
174 #define DV_PATH_VALIDITY_TIMEOUT \
175 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
178 * How long do we cache backchannel (struct Backtalker) information
179 * after a backchannel goes inactive?
181 #define BACKCHANNEL_INACTIVITY_TIMEOUT \
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
185 * How long before paths expire would we like to (re)discover DV paths? Should
186 * be below #DV_PATH_VALIDITY_TIMEOUT.
188 #define DV_PATH_DISCOVERY_FREQUENCY \
189 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
192 * How long are ephemeral keys valid?
194 #define EPHEMERAL_VALIDITY \
195 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
198 * How long do we keep partially reassembled messages around before giving up?
200 #define REASSEMBLY_EXPIRATION \
201 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
204 * What is the fastest rate at which we send challenges *if* we keep learning
205 * an address (gossip, DHT, etc.)?
207 #define FAST_VALIDATION_CHALLENGE_FREQ \
208 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
211 * What is the slowest rate at which we send challenges?
213 #define MAX_VALIDATION_CHALLENGE_FREQ \
214 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
217 * How long until we forget about historic accumulators and thus
218 * reset the ACK counter? Should exceed the maximum time an
219 * active connection experiences without an ACK.
221 #define ACK_CUMMULATOR_TIMEOUT \
222 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
225 * What is the non-randomized base frequency at which we
226 * would initiate DV learn messages?
228 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
231 * How many good connections (confirmed, bi-directional, not DV)
232 * do we need to have to suppress initiating DV learn messages?
234 #define DV_LEARN_QUALITY_THRESHOLD 100
237 * When do we forget an invalid address for sure?
239 #define MAX_ADDRESS_VALID_UNTIL \
240 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
243 * How long do we consider an address valid if we just checked?
245 #define ADDRESS_VALIDATION_LIFETIME \
246 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
249 * What is the maximum frequency at which we do address validation?
250 * A random value between 0 and this value is added when scheduling
251 * the #validation_task (both to ensure we do not validate too often,
252 * and to randomize a bit).
254 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
257 * How many network RTTs before an address validation expires should we begin
258 * trying to revalidate? (Note that the RTT used here is the one that we
259 * experienced during the last validation, not necessarily the latest RTT
262 #define VALIDATION_RTT_BUFFER_FACTOR 3
265 * How many messages can we have pending for a given communicator
266 * process before we start to throttle that communicator?
268 * Used if a communicator might be CPU-bound and cannot handle the traffic.
270 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
273 * How many messages can we have pending for a given queue (queue to
274 * a particular peer via a communicator) process before we start to
275 * throttle that queue?
277 #define QUEUE_LENGTH_LIMIT 32
280 GNUNET_NETWORK_STRUCT_BEGIN
283 * Unique identifier we attach to a message.
288 * Unique value, generated by incrementing the
289 * `message_uuid_ctr` of `struct Neighbour`.
291 uint64_t uuid GNUNET_PACKED;
296 * Unique identifier to map an acknowledgement to a transmission.
298 struct AcknowledgementUUIDP
301 * The UUID value. Not actually a hash, but a random value.
303 struct GNUNET_ShortHashCode value;
308 * Type of a nonce used for challenges.
310 struct ChallengeNonceP
313 * The value of the nonce. Note that this is NOT a hash.
315 struct GNUNET_ShortHashCode value;
320 * Outer layer of an encapsulated backchannel message.
322 struct TransportBackchannelEncapsulationMessage
325 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
327 struct GNUNET_MessageHeader header;
330 * Reserved, always zero.
332 uint32_t reserved GNUNET_PACKED;
335 * Target's peer identity (as backchannels may be transmitted
336 * indirectly, or even be broadcast).
338 struct GNUNET_PeerIdentity target;
341 * Ephemeral key setup by the sender for @e target, used
342 * to encrypt the payload.
344 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
347 * We use an IV here as the @e ephemeral_key is re-used for
348 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
350 struct GNUNET_ShortHashCode iv;
353 * HMAC over the ciphertext of the encrypted, variable-size
354 * body that follows. Verified via DH of @e target and
357 struct GNUNET_HashCode hmac;
359 /* Followed by encrypted, variable-size payload */
364 * Body by which a peer confirms that it is using an ephemeral key.
366 struct EphemeralConfirmationPS
370 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
372 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
375 * How long is this signature over the ephemeral key valid?
377 * Note that the receiver MUST IGNORE the absolute time, and only interpret
378 * the value as a mononic time and reject "older" values than the last one
379 * observed. This is necessary as we do not want to require synchronized
380 * clocks and may not have a bidirectional communication channel.
382 * Even with this, there is no real guarantee against replay achieved here,
383 * unless the latest timestamp is persisted. While persistence should be
384 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
385 * communicators must protect against replay attacks when using backchannel
388 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
391 * Target's peer identity.
393 struct GNUNET_PeerIdentity target;
396 * Ephemeral key setup by the sender for @e target, used
397 * to encrypt the payload.
399 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
404 * Plaintext of the variable-size payload that is encrypted
405 * within a `struct TransportBackchannelEncapsulationMessage`
407 struct TransportBackchannelRequestPayloadP
411 * Sender's peer identity.
413 struct GNUNET_PeerIdentity sender;
416 * Signature of the sender over an
417 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
419 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
422 * Current monotonic time of the sending transport service. Used to
423 * detect replayed messages. Note that the receiver should remember
424 * a list of the recently seen timestamps and only reject messages
425 * if the timestamp is in the list, or the list is "full" and the
426 * timestamp is smaller than the lowest in the list.
428 * Like the @e ephemeral_validity, the list of timestamps per peer should be
429 * persisted to guard against replays after restarts.
431 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
433 /* Followed by a `struct GNUNET_MessageHeader` with a message
434 for a communicator */
436 /* Followed by a 0-termianted string specifying the name of
437 the communicator which is to receive the message */
442 * Outer layer of an encapsulated unfragmented application message sent
443 * over an unreliable channel.
445 struct TransportReliabilityBoxMessage
448 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
450 struct GNUNET_MessageHeader header;
453 * Number of messages still to be sent before a commulative
454 * ACK is requested. Zero if an ACK is requested immediately.
455 * In NBO. Note that the receiver may send the ACK faster
456 * if it believes that is reasonable.
458 uint32_t ack_countdown GNUNET_PACKED;
461 * Unique ID of the message used for signalling receipt of
462 * messages sent over possibly unreliable channels. Should
465 struct AcknowledgementUUIDP ack_uuid;
470 * Acknowledgement payload.
472 struct TransportCummulativeAckPayloadP
475 * How long was the ACK delayed for generating cummulative ACKs?
476 * Used to calculate the correct network RTT by taking the receipt
477 * time of the ack minus the transmission time of the sender minus
480 struct GNUNET_TIME_RelativeNBO ack_delay;
483 * UUID of a message being acknowledged.
485 struct AcknowledgementUUIDP ack_uuid;
490 * Confirmation that the receiver got a
491 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
492 * confirmation may be transmitted over a completely different queue,
493 * so ACKs are identified by a combination of PID of sender and
494 * message UUID, without the queue playing any role!
496 struct TransportReliabilityAckMessage
499 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
501 struct GNUNET_MessageHeader header;
504 * Counter of ACKs transmitted by the sender to us. Incremented
505 * by one for each ACK, used to detect how many ACKs were lost.
507 uint32_t ack_counter GNUNET_PACKED;
509 /* followed by any number of `struct TransportCummulativeAckPayloadP`
510 messages providing ACKs */
515 * Outer layer of an encapsulated fragmented application message.
517 struct TransportFragmentBoxMessage
520 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
522 struct GNUNET_MessageHeader header;
525 * Offset of this fragment in the overall message.
527 uint16_t frag_off GNUNET_PACKED;
530 * Total size of the message that is being fragmented.
532 uint16_t msg_size GNUNET_PACKED;
535 * Unique ID of this fragment (and fragment transmission!). Will
536 * change even if a fragement is retransmitted to make each
537 * transmission attempt unique! If a client receives a duplicate
538 * fragment (same @e frag_off for same @a msg_uuid, it must send
539 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
541 struct AcknowledgementUUIDP ack_uuid;
544 * Original message ID for of the message that all the fragments
545 * belong to. Must be the same for all fragments.
547 struct MessageUUIDP msg_uuid;
552 * Content signed by the initator during DV learning.
554 * The signature is required to prevent DDoS attacks. A peer sending out this
555 * message is potentially generating a lot of traffic that will go back to the
556 * initator, as peers receiving this message will try to let the initiator
557 * know that they got the message.
559 * Without this signature, an attacker could abuse this mechanism for traffic
560 * amplification, sending a lot of traffic to a peer by putting out this type
561 * of message with the victim's peer identity.
563 * Even with just a signature, traffic amplification would be possible via
564 * replay attacks. The @e monotonic_time limits such replay attacks, as every
565 * potential amplificator will check the @e monotonic_time and only respond
566 * (at most) once per message.
571 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
573 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
576 * Time at the initiator when generating the signature.
578 * Note that the receiver MUST IGNORE the absolute time, and only interpret
579 * the value as a mononic time and reject "older" values than the last one
580 * observed. This is necessary as we do not want to require synchronized
581 * clocks and may not have a bidirectional communication channel.
583 * Even with this, there is no real guarantee against replay achieved here,
584 * unless the latest timestamp is persisted. Persistence should be
585 * provided via PEERSTORE if possible.
587 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
590 * Challenge value used by the initiator to re-identify the path.
592 struct ChallengeNonceP challenge;
597 * Content signed by each peer during DV learning.
599 * This assues the initiator of the DV learning operation that the hop from @e
600 * pred via the signing peer to @e succ actually exists. This makes it
601 * impossible for an adversary to supply the network with bogus routes.
603 * The @e challenge is included to provide replay protection for the
604 * initiator. This way, the initiator knows that the hop existed after the
605 * original @e challenge was first transmitted, providing a freshness metric.
607 * Peers other than the initiator that passively learn paths by observing
608 * these messages do NOT benefit from this. Here, an adversary may indeed
609 * replay old messages. Thus, passively learned paths should always be
610 * immediately marked as "potentially stale".
615 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
617 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
620 * Identity of the previous peer on the path.
622 struct GNUNET_PeerIdentity pred;
625 * Identity of the next peer on the path.
627 struct GNUNET_PeerIdentity succ;
630 * Challenge value used by the initiator to re-identify the path.
632 struct ChallengeNonceP challenge;
637 * An entry describing a peer on a path in a
638 * `struct TransportDVLearnMessage` message.
643 * Identity of a peer on the path.
645 struct GNUNET_PeerIdentity hop;
648 * Signature of this hop over the path, of purpose
649 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
651 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
656 * Internal message used by transport for distance vector learning.
657 * If @e num_hops does not exceed the threshold, peers should append
658 * themselves to the peer list and flood the message (possibly only
659 * to a subset of their neighbours to limit discoverability of the
660 * network topology). To the extend that the @e bidirectional bits
661 * are set, peers may learn the inverse paths even if they did not
664 * Unless received on a bidirectional queue and @e num_hops just
665 * zero, peers that can forward to the initator should always try to
666 * forward to the initiator.
668 struct TransportDVLearnMessage
671 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
673 struct GNUNET_MessageHeader header;
676 * Number of hops this messages has travelled, in NBO. Zero if
679 uint16_t num_hops GNUNET_PACKED;
682 * Bitmask of the last 16 hops indicating whether they are confirmed
683 * available (without DV) in both directions or not, in NBO. Used
684 * to possibly instantly learn a path in both directions. Each peer
685 * should shift this value by one to the left, and then set the
686 * lowest bit IF the current sender can be reached from it (without
689 uint16_t bidirectional GNUNET_PACKED;
692 * Peers receiving this message and delaying forwarding to other
693 * peers for any reason should increment this value by the non-network
694 * delay created by the peer.
696 struct GNUNET_TIME_RelativeNBO non_network_delay;
699 * Time at the initiator when generating the signature.
701 * Note that the receiver MUST IGNORE the absolute time, and only interpret
702 * the value as a mononic time and reject "older" values than the last one
703 * observed. This is necessary as we do not want to require synchronized
704 * clocks and may not have a bidirectional communication channel.
706 * Even with this, there is no real guarantee against replay achieved here,
707 * unless the latest timestamp is persisted. Persistence should be
708 * provided via PEERSTORE if possible.
710 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
713 * Signature of this hop over the path, of purpose
714 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
716 struct GNUNET_CRYPTO_EddsaSignature init_sig;
719 * Identity of the peer that started this learning activity.
721 struct GNUNET_PeerIdentity initiator;
724 * Challenge value used by the initiator to re-identify the path.
726 struct ChallengeNonceP challenge;
728 /* Followed by @e num_hops `struct DVPathEntryP` values,
729 excluding the initiator of the DV trace; the last entry is the
730 current sender; the current peer must not be included. */
735 * Outer layer of an encapsulated message send over multiple hops.
736 * The path given only includes the identities of the subsequent
737 * peers, i.e. it will be empty if we are the receiver. Each
738 * forwarding peer should scan the list from the end, and if it can,
739 * forward to the respective peer. The list should then be shortened
740 * by all the entries up to and including that peer. Each hop should
741 * also increment @e total_hops to allow the receiver to get a precise
742 * estimate on the number of hops the message travelled. Senders must
743 * provide a learned path that thus should work, but intermediaries
744 * know of a shortcut, they are allowed to send the message via that
747 * If a peer finds itself still on the list, it must drop the message.
749 struct TransportDVBoxMessage
752 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
754 struct GNUNET_MessageHeader header;
757 * Number of total hops this messages travelled. In NBO.
758 * @e origin sets this to zero, to be incremented at
761 uint16_t total_hops GNUNET_PACKED;
764 * Number of hops this messages includes. In NBO.
766 uint16_t num_hops GNUNET_PACKED;
769 * Identity of the peer that originated the message.
771 struct GNUNET_PeerIdentity origin;
773 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
774 excluding the @e origin and the current peer, the last must be
775 the ultimate target; if @e num_hops is zero, the receiver of this
776 message is the ultimate target. */
778 /* Followed by the actual message, which itself may be
779 another box, but not a DV_LEARN or DV_BOX message! */
784 * Message send to another peer to validate that it can indeed
785 * receive messages at a particular address.
787 struct TransportValidationChallengeMessage
791 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
793 struct GNUNET_MessageHeader header;
798 uint32_t reserved GNUNET_PACKED;
801 * Challenge to be signed by the receiving peer.
803 struct ChallengeNonceP challenge;
806 * Timestamp of the sender, to be copied into the reply
807 * to allow sender to calculate RTT.
809 struct GNUNET_TIME_AbsoluteNBO sender_time;
814 * Message signed by a peer to confirm that it can indeed
815 * receive messages at a particular address.
817 struct TransportValidationPS
821 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
823 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
826 * How long does the sender believe the address on
827 * which the challenge was received to remain valid?
829 struct GNUNET_TIME_RelativeNBO validity_duration;
832 * Challenge signed by the receiving peer.
834 struct ChallengeNonceP challenge;
839 * Message send to a peer to respond to a
840 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
842 struct TransportValidationResponseMessage
846 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
848 struct GNUNET_MessageHeader header;
853 uint32_t reserved GNUNET_PACKED;
856 * The peer's signature matching the
857 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
859 struct GNUNET_CRYPTO_EddsaSignature signature;
862 * The challenge that was signed by the receiving peer.
864 struct ChallengeNonceP challenge;
867 * Original timestamp of the sender (was @code{sender_time}),
868 * copied into the reply to allow sender to calculate RTT.
870 struct GNUNET_TIME_AbsoluteNBO origin_time;
873 * How long does the sender believe this address to remain
876 struct GNUNET_TIME_RelativeNBO validity_duration;
880 GNUNET_NETWORK_STRUCT_END
884 * What type of client is the `struct TransportClient` about?
889 * We do not know yet (client is fresh).
894 * Is the CORE service, we need to forward traffic to it.
899 * It is a monitor, forward monitor data.
904 * It is a communicator, use for communication.
909 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
916 * Which transmission options are allowable for transmission?
917 * Interpreted bit-wise!
919 enum RouteMessageOptions
922 * Only confirmed, non-DV direct neighbours.
927 * We are allowed to use DV routing for this @a hdr
932 * We are allowed to use unconfirmed queues or DV routes for this message
934 RMO_UNCONFIRMED_ALLOWED = 2,
937 * Reliable and unreliable, DV and non-DV are all acceptable.
939 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
942 * If we have multiple choices, it is OK to send this message
943 * over multiple channels at the same time to improve loss tolerance.
944 * (We do at most 2 transmissions.)
951 * When did we launch this DV learning activity?
953 struct LearnLaunchEntry
957 * Kept (also) in a DLL sorted by launch time.
959 struct LearnLaunchEntry *prev;
962 * Kept (also) in a DLL sorted by launch time.
964 struct LearnLaunchEntry *next;
967 * Challenge that uniquely identifies this activity.
969 struct ChallengeNonceP challenge;
972 * When did we transmit the DV learn message (used to calculate RTT) and
973 * determine freshness of paths learned via this operation.
975 struct GNUNET_TIME_Absolute launch_time;
980 * Entry in our cache of ephemeral keys we currently use. This way, we only
981 * sign an ephemeral once per @e target, and then can re-use it over multiple
982 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION messages (as
983 * signing is expensive and in some cases we may use backchannel messages a
986 struct EphemeralCacheEntry
990 * Target's peer identity (we don't re-use ephemerals
991 * to limit linkability of messages).
993 struct GNUNET_PeerIdentity target;
996 * Signature affirming @e ephemeral_key of type
997 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
999 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1002 * How long is @e sender_sig valid
1004 struct GNUNET_TIME_Absolute ephemeral_validity;
1007 * What time was @e sender_sig created
1009 struct GNUNET_TIME_Absolute monotime;
1012 * Our ephemeral key.
1014 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1017 * Our private ephemeral key.
1019 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1022 * Node in the ephemeral cache for this entry.
1023 * Used for expiration.
1025 struct GNUNET_CONTAINER_HeapNode *hn;
1030 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1031 * (or current) transmission performance.
1033 struct TransmissionHistoryEntry
1036 * Number of bytes actually sent in the interval.
1038 uint64_t bytes_sent;
1041 * Number of bytes received and acknowledged by the other peer in
1044 uint64_t bytes_received;
1049 * Performance data for a transmission possibility.
1051 struct PerformanceData
1054 * Weighted average for the RTT.
1056 struct GNUNET_TIME_Relative aged_rtt;
1059 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1062 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1065 * What was the last age when we wrote to @e the? Used to clear
1066 * old entries when the age advances.
1068 unsigned int last_age;
1073 * Client connected to the transport service.
1075 struct TransportClient;
1078 * A neighbour that at least one communicator is connected to.
1083 * Entry in our #dv_routes table, representing a (set of) distance
1084 * vector routes to a particular peer.
1086 struct DistanceVector;
1089 * A queue is a message queue provided by a communicator
1090 * via which we can reach a particular neighbour.
1095 * Message awaiting transmission. See detailed comments below.
1097 struct PendingMessage;
1100 * One possible hop towards a DV target.
1102 struct DistanceVectorHop;
1106 * Context from #handle_incoming_msg(). Closure for many
1107 * message handlers below.
1109 struct CommunicatorMessageContext
1113 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1114 * flow control to unchoke.
1116 struct CommunicatorMessageContext *next;
1119 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1120 * flow control to unchoke.
1122 struct CommunicatorMessageContext *prev;
1125 * Which communicator provided us with the message.
1127 struct TransportClient *tc;
1130 * Additional information for flow control and about the sender.
1132 struct GNUNET_TRANSPORT_IncomingMessage im;
1135 * Number of hops the message has travelled (if DV-routed).
1136 * FIXME: make use of this in ACK handling!
1138 uint16_t total_hops;
1143 * A virtual link is another reachable peer that is known to CORE. It
1144 * can be either a `struct Neighbour` with at least one confirmed
1145 * `struct Queue`, or a `struct DistanceVector` with at least one
1146 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1147 * data that is per neighbour that is not specific to how the
1148 * connectivity is established.
1153 * Identity of the peer at the other end of the link.
1155 struct GNUNET_PeerIdentity target;
1158 * Communicators blocked for receiving on @e target as we are waiting
1159 * on the @e core_recv_window to increase.
1161 struct CommunicatorMessageContext *cmc_head;
1164 * Communicators blocked for receiving on @e target as we are waiting
1165 * on the @e core_recv_window to increase.
1167 struct CommunicatorMessageContext *cmc_tail;
1170 * Task scheduled to possibly notfiy core that this peer is no
1171 * longer counting as confirmed. Runs the #core_visibility_check(),
1172 * which checks that some DV-path or a queue exists that is still
1173 * considered confirmed.
1175 struct GNUNET_SCHEDULER_Task *visibility_task;
1178 * Neighbour used by this virtual link, NULL if @e dv is used.
1180 struct Neighbour *n;
1183 * Distance vector used by this virtual link, NULL if @e n is used.
1185 struct DistanceVector *dv;
1188 * How many more messages can we send to core before we exhaust
1189 * the receive window of CORE for this peer? If this hits zero,
1190 * we must tell communicators to stop providing us more messages
1191 * for this peer. In fact, the window can go negative as we
1192 * have multiple communicators, so per communicator we can go
1193 * down by one into the negative range.
1195 int core_recv_window;
1200 * Data structure kept when we are waiting for an acknowledgement.
1202 struct PendingAcknowledgement
1206 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1207 * is kept in relation to its pending message.
1209 struct PendingAcknowledgement *next_pm;
1212 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1213 * is kept in relation to its pending message.
1215 struct PendingAcknowledgement *prev_pm;
1218 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1219 * is kept in relation to the queue that was used to transmit the
1222 struct PendingAcknowledgement *next_queue;
1225 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1226 * is kept in relation to the queue that was used to transmit the
1229 struct PendingAcknowledgement *prev_queue;
1232 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1233 * is kept in relation to the DVH that was used to transmit the
1236 struct PendingAcknowledgement *next_dvh;
1239 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1240 * is kept in relation to the DVH that was used to transmit the
1243 struct PendingAcknowledgement *prev_dvh;
1246 * Pointers for the DLL of all pending acknowledgements.
1247 * This list is sorted by @e transmission time. If the list gets too
1248 * long, the oldest entries are discarded.
1250 struct PendingAcknowledgement *next_pa;
1253 * Pointers for the DLL of all pending acknowledgements.
1254 * This list is sorted by @e transmission time. If the list gets too
1255 * long, the oldest entries are discarded.
1257 struct PendingAcknowledgement *prev_pa;
1260 * Unique identifier for this transmission operation.
1262 struct AcknowledgementUUIDP ack_uuid;
1265 * Message that was transmitted, may be NULL if the message was ACKed
1266 * via another channel.
1268 struct PendingMessage *pm;
1271 * Distance vector path chosen for this transmission, NULL if transmission
1272 * was to a direct neighbour OR if the path was forgotten in the meantime.
1274 struct DistanceVectorHop *dvh;
1277 * Queue used for transmission, NULL if the queue has been destroyed
1278 * (which may happen before we get an acknowledgement).
1280 struct Queue *queue;
1283 * Time of the transmission, for RTT calculation.
1285 struct GNUNET_TIME_Absolute transmission_time;
1288 * Number of bytes of the original message (to calculate bandwidth).
1290 uint16_t message_size;
1295 * One possible hop towards a DV target.
1297 struct DistanceVectorHop
1301 * Kept in a MDLL, sorted by @e timeout.
1303 struct DistanceVectorHop *next_dv;
1306 * Kept in a MDLL, sorted by @e timeout.
1308 struct DistanceVectorHop *prev_dv;
1313 struct DistanceVectorHop *next_neighbour;
1318 struct DistanceVectorHop *prev_neighbour;
1321 * Head of MDLL of messages routed via this path.
1323 struct PendingMessage *pending_msg_head;
1326 * Tail of MDLL of messages routed via this path.
1328 struct PendingMessage *pending_msg_tail;
1331 * Head of DLL of PAs that used our @a path.
1333 struct PendingAcknowledgement *pa_head;
1336 * Tail of DLL of PAs that used our @a path.
1338 struct PendingAcknowledgement *pa_tail;
1341 * What would be the next hop to @e target?
1343 struct Neighbour *next_hop;
1346 * Distance vector entry this hop belongs with.
1348 struct DistanceVector *dv;
1351 * Array of @e distance hops to the target, excluding @e next_hop.
1352 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1353 * at the end of this struct. Excludes the target itself!
1355 const struct GNUNET_PeerIdentity *path;
1358 * At what time do we forget about this path unless we see it again
1361 struct GNUNET_TIME_Absolute timeout;
1364 * For how long is the validation of this path considered
1366 * Set to ZERO if the path is learned by snooping on DV learn messages
1367 * initiated by other peers, and to the time at which we generated the
1368 * challenge for DV learn operations this peer initiated.
1370 struct GNUNET_TIME_Absolute path_valid_until;
1373 * Performance data for this transmission possibility.
1375 struct PerformanceData pd;
1378 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1379 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1382 unsigned int distance;
1387 * Entry in our #dv_routes table, representing a (set of) distance
1388 * vector routes to a particular peer.
1390 struct DistanceVector
1394 * To which peer is this a route?
1396 struct GNUNET_PeerIdentity target;
1399 * Known paths to @e target.
1401 struct DistanceVectorHop *dv_head;
1404 * Known paths to @e target.
1406 struct DistanceVectorHop *dv_tail;
1409 * Task scheduled to purge expired paths from @e dv_head MDLL.
1411 struct GNUNET_SCHEDULER_Task *timeout_task;
1414 * Do we have a confirmed working queue and are thus visible to
1415 * CORE? If so, this is the virtual link, otherwise NULL.
1417 struct VirtualLink *link;
1422 * Entry identifying transmission in one of our `struct
1423 * Queue` which still awaits an ACK. This is used to
1424 * ensure we do not overwhelm a communicator and limit the number of
1425 * messages outstanding per communicator (say in case communicator is
1426 * CPU bound) and per queue (in case bandwidth allocation exceeds
1427 * what the communicator can actually provide towards a particular
1436 struct QueueEntry *next;
1441 struct QueueEntry *prev;
1444 * Queue this entry is queued with.
1446 struct Queue *queue;
1449 * Pending message this entry is for, or NULL for none.
1451 struct PendingMessage *pm;
1454 * Message ID used for this message with the queue used for transmission.
1461 * A queue is a message queue provided by a communicator
1462 * via which we can reach a particular neighbour.
1469 struct Queue *next_neighbour;
1474 struct Queue *prev_neighbour;
1479 struct Queue *prev_client;
1484 struct Queue *next_client;
1487 * Head of DLL of PAs that used this queue.
1489 struct PendingAcknowledgement *pa_head;
1492 * Tail of DLL of PAs that used this queue.
1494 struct PendingAcknowledgement *pa_tail;
1497 * Head of DLL of unacked transmission requests.
1499 struct QueueEntry *queue_head;
1502 * End of DLL of unacked transmission requests.
1504 struct QueueEntry *queue_tail;
1507 * Which neighbour is this queue for?
1509 struct Neighbour *neighbour;
1512 * Which communicator offers this queue?
1514 struct TransportClient *tc;
1517 * Address served by the queue.
1519 const char *address;
1522 * Task scheduled for the time when this queue can (likely) transmit the
1525 struct GNUNET_SCHEDULER_Task *transmit_task;
1528 * How long do *we* consider this @e address to be valid? In the past or
1529 * zero if we have not yet validated it. Can be updated based on
1530 * challenge-response validations (via address validation logic), or when we
1531 * receive ACKs that we can definitively map to transmissions via this
1534 struct GNUNET_TIME_Absolute validated_until;
1537 * Performance data for this queue.
1539 struct PerformanceData pd;
1542 * Message ID generator for transmissions on this queue to the
1548 * Unique identifier of this queue with the communicator.
1553 * Maximum transmission unit supported by this queue.
1560 uint32_t num_msg_pending;
1565 uint32_t num_bytes_pending;
1568 * Length of the DLL starting at @e queue_head.
1570 unsigned int queue_length;
1573 * Network type offered by this queue.
1575 enum GNUNET_NetworkType nt;
1578 * Connection status for this queue.
1580 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1585 * Information we keep for a message that we are reassembling.
1587 struct ReassemblyContext
1591 * Original message ID for of the message that all the fragments
1594 struct MessageUUIDP msg_uuid;
1597 * Which neighbour is this context for?
1599 struct Neighbour *neighbour;
1602 * Entry in the reassembly heap (sorted by expiration).
1604 struct GNUNET_CONTAINER_HeapNode *hn;
1607 * Bitfield with @e msg_size bits representing the positions
1608 * where we have received fragments. When we receive a fragment,
1609 * we check the bits in @e bitfield before incrementing @e msg_missing.
1611 * Allocated after the reassembled message.
1616 * At what time will we give up reassembly of this message?
1618 struct GNUNET_TIME_Absolute reassembly_timeout;
1621 * Time we received the last fragment. @e avg_ack_delay must be
1622 * incremented by now - @e last_frag multiplied by @e num_acks.
1624 struct GNUNET_TIME_Absolute last_frag;
1627 * How big is the message we are reassembling in total?
1632 * How many bytes of the message are still missing? Defragmentation
1633 * is complete when @e msg_missing == 0.
1635 uint16_t msg_missing;
1637 /* Followed by @e msg_size bytes of the (partially) defragmented original
1640 /* Followed by @e bitfield data */
1645 * A neighbour that at least one communicator is connected to.
1651 * Which peer is this about?
1653 struct GNUNET_PeerIdentity pid;
1656 * Map with `struct ReassemblyContext` structs for fragments under
1657 * reassembly. May be NULL if we currently have no fragments from
1658 * this @e pid (lazy initialization).
1660 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1663 * Heap with `struct ReassemblyContext` structs for fragments under
1664 * reassembly. May be NULL if we currently have no fragments from
1665 * this @e pid (lazy initialization).
1667 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1670 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1672 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1675 * Head of list of messages pending for this neighbour.
1677 struct PendingMessage *pending_msg_head;
1680 * Tail of list of messages pending for this neighbour.
1682 struct PendingMessage *pending_msg_tail;
1685 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1686 * purged if this neighbour goes down.
1688 struct DistanceVectorHop *dv_head;
1691 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1692 * purged if this neighbour goes down.
1694 struct DistanceVectorHop *dv_tail;
1697 * Head of DLL of queues to this peer.
1699 struct Queue *queue_head;
1702 * Tail of DLL of queues to this peer.
1704 struct Queue *queue_tail;
1707 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1708 * the PEERSTORE, or NULL.
1710 struct GNUNET_PEERSTORE_IterateContext *get;
1713 * Handle to a PEERSTORE store operation to store this @e pid's @e
1714 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1716 struct GNUNET_PEERSTORE_StoreContext *sc;
1719 * Do we have a confirmed working queue and are thus visible to
1720 * CORE? If so, this is the virtual link, otherwise NULL.
1722 struct VirtualLink *link;
1725 * Latest DVLearn monotonic time seen from this peer. Initialized only
1726 * if @e dl_monotime_available is #GNUNET_YES.
1728 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1731 * Used to generate unique UUIDs for messages that are being
1734 uint64_t message_uuid_ctr;
1737 * Do we have the lastest value for @e last_dv_learn_monotime from
1738 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1740 int dv_monotime_available;
1745 * A peer that an application (client) would like us to talk to directly.
1751 * Which peer is this about?
1753 struct GNUNET_PeerIdentity pid;
1756 * Client responsible for the request.
1758 struct TransportClient *tc;
1761 * Handle for watching the peerstore for HELLOs for this peer.
1763 struct GNUNET_PEERSTORE_WatchContext *wc;
1766 * What kind of performance preference does this @e tc have?
1770 enum GNUNET_MQ_PriorityPreferences pk;
1773 * How much bandwidth would this @e tc like to see?
1775 struct GNUNET_BANDWIDTH_Value32NBO bw;
1780 * Types of different pending messages.
1782 enum PendingMessageType
1786 * Ordinary message received from the CORE service.
1793 PMT_FRAGMENT_BOX = 1,
1798 PMT_RELIABILITY_BOX = 2,
1801 * Any type of acknowledgement.
1803 PMT_ACKNOWLEDGEMENT = 3,
1806 * Control traffic generated by the TRANSPORT service itself.
1814 * Transmission request that is awaiting delivery. The original
1815 * transmission requests from CORE may be too big for some queues.
1816 * In this case, a *tree* of fragments is created. At each
1817 * level of the tree, fragments are kept in a DLL ordered by which
1818 * fragment should be sent next (at the head). The tree is searched
1819 * top-down, with the original message at the root.
1821 * To select a node for transmission, first it is checked if the
1822 * current node's message fits with the MTU. If it does not, we
1823 * either calculate the next fragment (based on @e frag_off) from the
1824 * current node, or, if all fragments have already been created,
1825 * descend to the @e head_frag. Even though the node was already
1826 * fragmented, the fragment may be too big if the fragment was
1827 * generated for a queue with a larger MTU. In this case, the node
1828 * may be fragmented again, thus creating a tree.
1830 * When acknowledgements for fragments are received, the tree
1831 * must be pruned, removing those parts that were already
1832 * acknowledged. When fragments are sent over a reliable
1833 * channel, they can be immediately removed.
1835 * If a message is ever fragmented, then the original "full" message
1836 * is never again transmitted (even if it fits below the MTU), and
1837 * only (remaining) fragments are sent.
1839 struct PendingMessage
1842 * Kept in a MDLL of messages for this @a target.
1844 struct PendingMessage *next_neighbour;
1847 * Kept in a MDLL of messages for this @a target.
1849 struct PendingMessage *prev_neighbour;
1852 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1854 struct PendingMessage *next_client;
1857 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1859 struct PendingMessage *prev_client;
1862 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1863 * #PMT_FRAGMENT_BOx)
1865 struct PendingMessage *next_frag;
1868 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
1869 * #PMT_FRAGMENT_BOX)
1871 struct PendingMessage *prev_frag;
1874 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1877 struct PendingMessage *next_dvh;
1880 * Kept in a MDLL of messages using this @a dvh (if @e dvh is
1883 struct PendingMessage *prev_dvh;
1886 * Head of DLL of PAs for this pending message.
1888 struct PendingAcknowledgement *pa_head;
1891 * Tail of DLL of PAs for this pending message.
1893 struct PendingAcknowledgement *pa_tail;
1896 * This message, reliability boxed. Only possibly available if @e pmt is
1899 struct PendingMessage *bpm;
1902 * Target of the request (for transmission, may not be ultimate
1905 struct Neighbour *target;
1908 * Distance vector path selected for this message, or
1909 * NULL if transmitted directly.
1911 struct DistanceVectorHop *dvh;
1914 * Set to non-NULL value if this message is currently being given to a
1915 * communicator and we are awaiting that communicator's acknowledgement.
1916 * Note that we must not retransmit a pending message while we're still
1917 * in the process of giving it to a communicator. If a pending message
1918 * is free'd while this entry is non-NULL, the @e qe reference to us
1919 * should simply be set to NULL.
1921 struct QueueEntry *qe;
1924 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1926 struct TransportClient *client;
1929 * Head of a MDLL of fragments created for this core message.
1931 struct PendingMessage *head_frag;
1934 * Tail of a MDLL of fragments created for this core message.
1936 struct PendingMessage *tail_frag;
1939 * Our parent in the fragmentation tree.
1941 struct PendingMessage *frag_parent;
1944 * At what time should we give up on the transmission (and no longer retry)?
1946 struct GNUNET_TIME_Absolute timeout;
1949 * What is the earliest time for us to retry transmission of this message?
1951 struct GNUNET_TIME_Absolute next_attempt;
1954 * UUID to use for this message (used for reassembly of fragments, only
1955 * initialized if @e msg_uuid_set is #GNUNET_YES).
1957 struct MessageUUIDP msg_uuid;
1960 * Type of the pending message.
1962 enum PendingMessageType pmt;
1965 * Preferences for this message.
1966 * TODO: actually use this!
1968 enum GNUNET_MQ_PriorityPreferences prefs;
1971 * Size of the original message.
1976 * Offset at which we should generate the next fragment.
1981 * #GNUNET_YES once @e msg_uuid was initialized
1983 int16_t msg_uuid_set;
1985 /* Followed by @e bytes_msg to transmit */
1990 * Acknowledgement payload.
1992 struct TransportCummulativeAckPayload
1995 * When did we receive the message we are ACKing? Used to calculate
1996 * the delay we introduced by cummulating ACKs.
1998 struct GNUNET_TIME_Absolute receive_time;
2001 * UUID of a message being acknowledged.
2003 struct AcknowledgementUUIDP ack_uuid;
2008 * Data structure in which we track acknowledgements still to
2011 struct AcknowledgementCummulator
2014 * Target peer for which we are accumulating ACKs here.
2016 struct GNUNET_PeerIdentity target;
2019 * ACK data being accumulated. Only @e num_acks slots are valid.
2021 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2024 * Task scheduled either to transmit the cummulative ACK message,
2025 * or to clean up this data structure after extended periods of
2026 * inactivity (if @e num_acks is zero).
2028 struct GNUNET_SCHEDULER_Task *task;
2031 * When is @e task run (only used if @e num_acks is non-zero)?
2033 struct GNUNET_TIME_Absolute min_transmission_time;
2036 * Counter to produce the `ack_counter` in the `struct
2037 * TransportReliabilityAckMessage`. Allows the receiver to detect
2038 * lost ACK messages. Incremented by @e num_acks upon transmission.
2040 uint32_t ack_counter;
2043 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2045 unsigned int num_acks;
2050 * One of the addresses of this peer.
2052 struct AddressListEntry
2058 struct AddressListEntry *next;
2063 struct AddressListEntry *prev;
2066 * Which communicator provides this address?
2068 struct TransportClient *tc;
2071 * The actual address.
2073 const char *address;
2076 * Current context for storing this address in the peerstore.
2078 struct GNUNET_PEERSTORE_StoreContext *sc;
2081 * Task to periodically do @e st operation.
2083 struct GNUNET_SCHEDULER_Task *st;
2086 * What is a typical lifetime the communicator expects this
2087 * address to have? (Always from now.)
2089 struct GNUNET_TIME_Relative expiration;
2092 * Address identifier used by the communicator.
2097 * Network type offered by this address.
2099 enum GNUNET_NetworkType nt;
2104 * Client connected to the transport service.
2106 struct TransportClient
2112 struct TransportClient *next;
2117 struct TransportClient *prev;
2120 * Handle to the client.
2122 struct GNUNET_SERVICE_Client *client;
2125 * Message queue to the client.
2127 struct GNUNET_MQ_Handle *mq;
2130 * What type of client is this?
2132 enum ClientType type;
2138 * Information for @e type #CT_CORE.
2144 * Head of list of messages pending for this client, sorted by
2145 * transmission time ("next_attempt" + possibly internal prioritization).
2147 struct PendingMessage *pending_msg_head;
2150 * Tail of list of messages pending for this client.
2152 struct PendingMessage *pending_msg_tail;
2157 * Information for @e type #CT_MONITOR.
2163 * Peer identity to monitor the addresses of.
2164 * Zero to monitor all neighbours. Valid if
2165 * @e type is #CT_MONITOR.
2167 struct GNUNET_PeerIdentity peer;
2170 * Is this a one-shot monitor?
2178 * Information for @e type #CT_COMMUNICATOR.
2183 * If @e type is #CT_COMMUNICATOR, this communicator
2184 * supports communicating using these addresses.
2186 char *address_prefix;
2189 * Head of DLL of queues offered by this communicator.
2191 struct Queue *queue_head;
2194 * Tail of DLL of queues offered by this communicator.
2196 struct Queue *queue_tail;
2199 * Head of list of the addresses of this peer offered by this
2202 struct AddressListEntry *addr_head;
2205 * Tail of list of the addresses of this peer offered by this
2208 struct AddressListEntry *addr_tail;
2211 * Number of queue entries in all queues to this communicator. Used
2212 * throttle sending to a communicator if we see that the communicator
2213 * is globally unable to keep up.
2215 unsigned int total_queue_length;
2218 * Characteristics of this communicator.
2220 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2225 * Information for @e type #CT_APPLICATION
2231 * Map of requests for peers the given client application would like to
2232 * see connections for. Maps from PIDs to `struct PeerRequest`.
2234 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2243 * State we keep for validation activities. Each of these
2244 * is both in the #validation_heap and the #validation_map.
2246 struct ValidationState
2250 * For which peer is @a address to be validated (or possibly valid)?
2251 * Serves as key in the #validation_map.
2253 struct GNUNET_PeerIdentity pid;
2256 * How long did the peer claim this @e address to be valid? Capped at
2257 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2258 * were told about the address and the value claimed by the other peer at
2259 * that time. May be updated similarly when validation succeeds.
2261 struct GNUNET_TIME_Absolute valid_until;
2264 * How long do *we* consider this @e address to be valid?
2265 * In the past or zero if we have not yet validated it.
2267 struct GNUNET_TIME_Absolute validated_until;
2270 * When did we FIRST use the current @e challenge in a message?
2271 * Used to sanity-check @code{origin_time} in the response when
2272 * calculating the RTT. If the @code{origin_time} is not in
2273 * the expected range, the response is discarded as malicious.
2275 struct GNUNET_TIME_Absolute first_challenge_use;
2278 * When did we LAST use the current @e challenge in a message?
2279 * Used to sanity-check @code{origin_time} in the response when
2280 * calculating the RTT. If the @code{origin_time} is not in
2281 * the expected range, the response is discarded as malicious.
2283 struct GNUNET_TIME_Absolute last_challenge_use;
2286 * Next time we will send the @e challenge to the peer, if this time is past
2287 * @e valid_until, this validation state is released at this time. If the
2288 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2289 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2290 * to re-validate before the validity actually expires.
2292 struct GNUNET_TIME_Absolute next_challenge;
2295 * Current backoff factor we're applying for sending the @a challenge.
2296 * Reset to 0 if the @a challenge is confirmed upon validation.
2297 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2298 * existing value if we receive an unvalidated address again over
2299 * another channel (and thus should consider the information "fresh").
2300 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2302 struct GNUNET_TIME_Relative challenge_backoff;
2305 * Initially set to "forever". Once @e validated_until is set, this value is
2306 * set to the RTT that tells us how long it took to receive the validation.
2308 struct GNUNET_TIME_Relative validation_rtt;
2311 * The challenge we sent to the peer to get it to validate the address. Note
2312 * that we rotate the challenge whenever we update @e validated_until to
2313 * avoid attacks where a peer simply replays an old challenge in the future.
2314 * (We must not rotate more often as otherwise we may discard valid answers
2315 * due to packet losses, latency and reorderings on the network).
2317 struct ChallengeNonceP challenge;
2320 * Claimed address of the peer.
2325 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2326 * heap is used to figure out when the next validation activity should be
2329 struct GNUNET_CONTAINER_HeapNode *hn;
2332 * Handle to a PEERSTORE store operation for this @e address. NULL if
2333 * no PEERSTORE operation is pending.
2335 struct GNUNET_PEERSTORE_StoreContext *sc;
2338 * We are technically ready to send the challenge, but we are waiting for
2339 * the respective queue to become available for transmission.
2346 * A Backtalker is a peer sending us backchannel messages. We use this
2347 * struct to detect monotonic time violations, cache ephemeral key
2348 * material (to avoid repeatedly checking signatures), and to synchronize
2349 * monotonic time with the PEERSTORE.
2354 * Peer this is about.
2356 struct GNUNET_PeerIdentity pid;
2359 * Last (valid) monotonic time received from this sender.
2361 struct GNUNET_TIME_Absolute monotonic_time;
2364 * When will this entry time out?
2366 struct GNUNET_TIME_Absolute timeout;
2369 * Last (valid) ephemeral key received from this sender.
2371 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2374 * Task associated with this backtalker. Can be for timeout,
2375 * or other asynchronous operations.
2377 struct GNUNET_SCHEDULER_Task *task;
2380 * Communicator context waiting on this backchannel's @e get, or NULL.
2382 struct CommunicatorMessageContext *cmc;
2385 * Handle for an operation to fetch @e monotonic_time information from the
2386 * PEERSTORE, or NULL.
2388 struct GNUNET_PEERSTORE_IterateContext *get;
2391 * Handle to a PEERSTORE store operation for this @e pid's @e
2392 * monotonic_time. NULL if no PEERSTORE operation is pending.
2394 struct GNUNET_PEERSTORE_StoreContext *sc;
2397 * Number of bytes of the original message body that follows after this
2405 * Head of linked list of all clients to this service.
2407 static struct TransportClient *clients_head;
2410 * Tail of linked list of all clients to this service.
2412 static struct TransportClient *clients_tail;
2415 * Statistics handle.
2417 static struct GNUNET_STATISTICS_Handle *GST_stats;
2420 * Configuration handle.
2422 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2427 static struct GNUNET_PeerIdentity GST_my_identity;
2432 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2435 * Map from PIDs to `struct Neighbour` entries. A peer is
2436 * a neighbour if we have an MQ to it from some communicator.
2438 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2441 * Map from PIDs to `struct Backtalker` entries. A peer is
2442 * a backtalker if it recently send us backchannel messages.
2444 static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2447 * Map from PIDs to `struct AcknowledgementCummulator`s.
2448 * Here we track the cummulative ACKs for transmission.
2450 static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2453 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2454 * a `struct PendingAcknowledgement`.
2456 static struct GNUNET_CONTAINER_MultiShortmap *pending_acks;
2459 * Map from PIDs to `struct DistanceVector` entries describing
2460 * known paths to the peer.
2462 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2465 * Map from PIDs to `struct ValidationState` entries describing
2466 * addresses we are aware of and their validity state.
2468 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2471 * Map from PIDs to `struct VirtualLink` entries describing
2472 * links CORE knows to exist.
2474 static struct GNUNET_CONTAINER_MultiPeerMap *links;
2477 * Map from challenges to `struct LearnLaunchEntry` values.
2479 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2482 * Head of a DLL sorted by launch time.
2484 static struct LearnLaunchEntry *lle_head;
2487 * Tail of a DLL sorted by launch time.
2489 static struct LearnLaunchEntry *lle_tail;
2492 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2493 * sorting addresses we are aware of by when we should next try to (re)validate
2496 static struct GNUNET_CONTAINER_Heap *validation_heap;
2499 * Database for peer's HELLOs.
2501 static struct GNUNET_PEERSTORE_Handle *peerstore;
2504 * Heap sorting `struct EphemeralCacheEntry` by their
2505 * key/signature validity.
2507 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
2510 * Hash map for looking up `struct EphemeralCacheEntry`s
2511 * by peer identity. (We may have ephemerals in our
2512 * cache for which we do not have a neighbour entry,
2513 * and similar many neighbours may not need ephemerals,
2514 * so we use a second map.)
2516 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
2519 * Task to free expired ephemerals.
2521 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
2524 * Task run to initiate DV learning.
2526 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2529 * Task to run address validation.
2531 static struct GNUNET_SCHEDULER_Task *validation_task;
2534 * The most recent PA we have created, head of DLL.
2535 * The length of the DLL is kept in #pa_count.
2537 static struct PendingAcknowledgement *pa_head;
2540 * The oldest PA we have created, tail of DLL.
2541 * The length of the DLL is kept in #pa_count.
2543 static struct PendingAcknowledgement *pa_tail;
2546 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2547 * limit the size of the data structure.
2549 static unsigned int pa_count;
2552 * Monotonic time we use for HELLOs generated at this time. TODO: we
2553 * should increase this value from time to time (i.e. whenever a
2554 * `struct AddressListEntry` actually expires), but IF we do this, we
2555 * must also update *all* (remaining) addresses in the PEERSTORE at
2556 * that time! (So for now only increased when the peer is restarted,
2557 * which hopefully roughly matches whenever our addresses change.)
2559 static struct GNUNET_TIME_Absolute hello_mono_time;
2563 * Get an offset into the transmission history buffer for `struct
2564 * PerformanceData`. Note that the caller must perform the required
2565 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2568 * An 'age' lasts 15 minute slots.
2570 * @return current age of the world
2575 struct GNUNET_TIME_Absolute now;
2577 now = GNUNET_TIME_absolute_get ();
2578 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2583 * Release @a pa data structure.
2585 * @param pa data structure to release
2588 free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2590 struct Queue *q = pa->queue;
2591 struct PendingMessage *pm = pa->pm;
2592 struct DistanceVectorHop *dvh = pa->dvh;
2594 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2598 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2603 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2608 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2611 GNUNET_assert (GNUNET_YES ==
2612 GNUNET_CONTAINER_multishortmap_remove (pending_acks,
2613 &pa->ack_uuid.value,
2620 * Free cached ephemeral key.
2622 * @param ece cached signature to free
2625 free_ephemeral (struct EphemeralCacheEntry *ece)
2627 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map, &ece->target, ece);
2628 GNUNET_CONTAINER_heap_remove_node (ece->hn);
2634 * Free virtual link.
2636 * @param vl link data to free
2639 free_virtual_link (struct VirtualLink *vl)
2641 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl);
2642 if (NULL != vl->visibility_task)
2644 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2645 vl->visibility_task = NULL;
2647 GNUNET_break (NULL == vl->n);
2648 GNUNET_break (NULL == vl->dv);
2654 * Free validation state.
2656 * @param vs validation state to free
2659 free_validation_state (struct ValidationState *vs)
2661 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs);
2662 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2666 GNUNET_PEERSTORE_store_cancel (vs->sc);
2669 GNUNET_free (vs->address);
2675 * Lookup neighbour record for peer @a pid.
2677 * @param pid neighbour to look for
2678 * @return NULL if we do not have this peer as a neighbour
2680 static struct Neighbour *
2681 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
2683 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
2688 * Details about what to notify monitors about.
2693 * @deprecated To be discussed if we keep these...
2695 struct GNUNET_TIME_Absolute last_validation;
2696 struct GNUNET_TIME_Absolute valid_until;
2697 struct GNUNET_TIME_Absolute next_validation;
2700 * Current round-trip time estimate.
2702 struct GNUNET_TIME_Relative rtt;
2705 * Connection status.
2707 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2712 uint32_t num_msg_pending;
2717 uint32_t num_bytes_pending;
2722 * Free a @dvh. Callers MAY want to check if this was the last path to the
2723 * `target`, and if so call #free_dv_route to also free the associated DV
2724 * entry in #dv_routes (if not, the associated scheduler job should eventually
2727 * @param dvh hop to free
2730 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2732 struct Neighbour *n = dvh->next_hop;
2733 struct DistanceVector *dv = dvh->dv;
2734 struct PendingAcknowledgement *pa;
2735 struct PendingMessage *pm;
2737 while (NULL != (pm = dvh->pending_msg_head))
2739 GNUNET_CONTAINER_MDLL_remove (dvh,
2740 dvh->pending_msg_head,
2741 dvh->pending_msg_tail,
2745 while (NULL != (pa = dvh->pa_head))
2747 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2750 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
2751 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
2757 * Free entry in #dv_routes. First frees all hops to the target, and
2758 * if there are no entries left, frees @a dv as well.
2760 * @param dv route to free
2763 free_dv_route (struct DistanceVector *dv)
2765 struct DistanceVectorHop *dvh;
2767 while (NULL != (dvh = dv->dv_head))
2768 free_distance_vector_hop (dvh);
2769 if (NULL == dv->dv_head)
2773 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
2774 if (NULL != dv->timeout_task)
2775 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2782 * Notify monitor @a tc about an event. That @a tc
2783 * cares about the event has already been checked.
2785 * Send @a tc information in @a me about a @a peer's status with
2786 * respect to some @a address to all monitors that care.
2788 * @param tc monitor to inform
2789 * @param peer peer the information is about
2790 * @param address address the information is about
2791 * @param nt network type associated with @a address
2792 * @param me detailed information to transmit
2795 notify_monitor (struct TransportClient *tc,
2796 const struct GNUNET_PeerIdentity *peer,
2797 const char *address,
2798 enum GNUNET_NetworkType nt,
2799 const struct MonitorEvent *me)
2801 struct GNUNET_MQ_Envelope *env;
2802 struct GNUNET_TRANSPORT_MonitorData *md;
2803 size_t addr_len = strlen (address) + 1;
2805 env = GNUNET_MQ_msg_extra (md,
2807 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2808 md->nt = htonl ((uint32_t) nt);
2810 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2811 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2812 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2813 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2814 md->cs = htonl ((uint32_t) me->cs);
2815 md->num_msg_pending = htonl (me->num_msg_pending);
2816 md->num_bytes_pending = htonl (me->num_bytes_pending);
2817 memcpy (&md[1], address, addr_len);
2818 GNUNET_MQ_send (tc->mq, env);
2823 * Send information in @a me about a @a peer's status with respect
2824 * to some @a address to all monitors that care.
2826 * @param peer peer the information is about
2827 * @param address address the information is about
2828 * @param nt network type associated with @a address
2829 * @param me detailed information to transmit
2832 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2833 const char *address,
2834 enum GNUNET_NetworkType nt,
2835 const struct MonitorEvent *me)
2837 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
2839 if (CT_MONITOR != tc->type)
2841 if (tc->details.monitor.one_shot)
2843 if ((0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2844 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
2846 notify_monitor (tc, peer, address, nt, me);
2852 * Called whenever a client connects. Allocates our
2853 * data structures associated with that client.
2855 * @param cls closure, NULL
2856 * @param client identification of the client
2857 * @param mq message queue for the client
2858 * @return our `struct TransportClient`
2861 client_connect_cb (void *cls,
2862 struct GNUNET_SERVICE_Client *client,
2863 struct GNUNET_MQ_Handle *mq)
2865 struct TransportClient *tc;
2868 tc = GNUNET_new (struct TransportClient);
2869 tc->client = client;
2871 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
2872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
2880 * @param rc data structure to free
2883 free_reassembly_context (struct ReassemblyContext *rc)
2885 struct Neighbour *n = rc->neighbour;
2887 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
2888 GNUNET_assert (GNUNET_OK ==
2889 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
2897 * Task run to clean up reassembly context of a neighbour that have expired.
2899 * @param cls a `struct Neighbour`
2902 reassembly_cleanup_task (void *cls)
2904 struct Neighbour *n = cls;
2905 struct ReassemblyContext *rc;
2907 n->reassembly_timeout_task = NULL;
2908 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2910 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
2913 free_reassembly_context (rc);
2916 GNUNET_assert (NULL == n->reassembly_timeout_task);
2917 n->reassembly_timeout_task =
2918 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2919 &reassembly_cleanup_task,
2927 * function called to #free_reassembly_context().
2931 * @param value a `struct ReassemblyContext` to free
2932 * @return #GNUNET_OK (continue iteration)
2935 free_reassembly_cb (void *cls, uint32_t key, void *value)
2937 struct ReassemblyContext *rc = value;
2941 free_reassembly_context (rc);
2947 * Release memory used by @a neighbour.
2949 * @param neighbour neighbour entry to free
2952 free_neighbour (struct Neighbour *neighbour)
2954 struct DistanceVectorHop *dvh;
2956 GNUNET_assert (NULL == neighbour->queue_head);
2957 GNUNET_assert (GNUNET_YES ==
2958 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2961 if (NULL != neighbour->reassembly_map)
2963 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
2964 &free_reassembly_cb,
2966 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
2967 neighbour->reassembly_map = NULL;
2968 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2969 neighbour->reassembly_heap = NULL;
2971 while (NULL != (dvh = neighbour->dv_head))
2973 struct DistanceVector *dv = dvh->dv;
2975 free_distance_vector_hop (dvh);
2976 if (NULL == dv->dv_head)
2979 if (NULL != neighbour->reassembly_timeout_task)
2981 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2982 neighbour->reassembly_timeout_task = NULL;
2984 if (NULL != neighbour->get)
2986 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
2987 neighbour->get = NULL;
2989 if (NULL != neighbour->sc)
2991 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
2992 neighbour->sc = NULL;
2994 GNUNET_free (neighbour);
2999 * Send message to CORE clients that we lost a connection.
3001 * @param tc client to inform (must be CORE client)
3002 * @param pid peer the connection is for
3005 core_send_connect_info (struct TransportClient *tc,
3006 const struct GNUNET_PeerIdentity *pid)
3008 struct GNUNET_MQ_Envelope *env;
3009 struct ConnectInfoMessage *cim;
3011 GNUNET_assert (CT_CORE == tc->type);
3012 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3014 GNUNET_MQ_send (tc->mq, env);
3019 * Send message to CORE clients that we gained a connection
3021 * @param pid peer the queue was for
3024 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3027 "Informing CORE clients about connection to %s\n",
3029 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3031 if (CT_CORE != tc->type)
3033 core_send_connect_info (tc, pid);
3039 * Send message to CORE clients that we lost a connection.
3041 * @param pid peer the connection was for
3044 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3046 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3047 "Informing CORE clients about disconnect from %s\n",
3049 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3051 struct GNUNET_MQ_Envelope *env;
3052 struct DisconnectInfoMessage *dim;
3054 if (CT_CORE != tc->type)
3056 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3058 GNUNET_MQ_send (tc->mq, env);
3064 * We believe we are ready to transmit a message on a queue. Gives the
3065 * message to the communicator for transmission (updating the tracker,
3066 * and re-scheduling itself if applicable).
3068 * @param cls the `struct Queue` to process transmissions for
3071 transmit_on_queue (void *cls);
3075 * Schedule next run of #transmit_on_queue(). Does NOTHING if
3076 * we should run immediately or if the message queue is empty.
3077 * Test for no task being added AND queue not being empty to
3078 * transmit immediately afterwards! This function must only
3079 * be called if the message queue is non-empty!
3081 * @param queue the queue to do scheduling for
3082 * @param inside_job set to #GNUNET_YES if called from
3083 * #transmit_on_queue() itself and NOT setting
3084 * the task means running immediately
3087 schedule_transmit_on_queue (struct Queue *queue, int inside_job)
3089 struct Neighbour *n = queue->neighbour;
3090 struct PendingMessage *pm = n->pending_msg_head;
3091 struct GNUNET_TIME_Relative out_delay;
3093 GNUNET_assert (NULL != pm);
3094 if (queue->tc->details.communicator.total_queue_length >=
3095 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3097 GNUNET_STATISTICS_update (
3099 "# Transmission throttled due to communicator queue limit",
3104 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3106 GNUNET_STATISTICS_update (GST_stats,
3107 "# Transmission throttled due to queue queue limit",
3113 out_delay = GNUNET_TIME_absolute_get_remaining (pm->next_attempt);
3114 if ((GNUNET_YES == inside_job) && (0 == out_delay.rel_value_us))
3117 GNUNET_ERROR_TYPE_DEBUG,
3118 "Schedule transmission on queue %llu of %s decides to run immediately\n",
3119 (unsigned long long) queue->qid,
3120 GNUNET_i2s (&n->pid));
3121 return; /* we should run immediately! */
3123 /* queue has changed since we were scheduled, reschedule again */
3124 queue->transmit_task =
3125 GNUNET_SCHEDULER_add_delayed (out_delay, &transmit_on_queue, queue);
3126 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
3127 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3128 "Next transmission on queue `%s' in %s (high delay)\n",
3130 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3133 "Next transmission on queue `%s' in %s\n",
3135 GNUNET_STRINGS_relative_time_to_string (out_delay, GNUNET_YES));
3140 * Task run to check whether the hops of the @a cls still
3141 * are validated, or if we need to core about disconnection.
3143 * @param cls a `struct VirtualLink`
3146 check_link_down (void *cls)
3148 struct VirtualLink *vl = cls;
3149 struct DistanceVector *dv = vl->dv;
3150 struct Neighbour *n = vl->n;
3151 struct GNUNET_TIME_Absolute dvh_timeout;
3152 struct GNUNET_TIME_Absolute q_timeout;
3154 vl->visibility_task = NULL;
3155 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3156 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3158 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout, pos->path_valid_until);
3159 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3161 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3162 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3163 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3164 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3166 if ((NULL == vl->n) && (NULL == vl->dv))
3168 cores_send_disconnect_info (&dv->target);
3169 free_virtual_link (vl);
3172 vl->visibility_task =
3173 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3182 * @param queue the queue to free
3185 free_queue (struct Queue *queue)
3187 struct Neighbour *neighbour = queue->neighbour;
3188 struct TransportClient *tc = queue->tc;
3189 struct MonitorEvent me = {.cs = GNUNET_TRANSPORT_CS_DOWN,
3190 .rtt = GNUNET_TIME_UNIT_FOREVER_REL};
3191 struct QueueEntry *qe;
3193 struct PendingAcknowledgement *pa;
3194 struct VirtualLink *vl;
3196 if (NULL != queue->transmit_task)
3198 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3199 queue->transmit_task = NULL;
3201 while (NULL != (pa = queue->pa_head))
3203 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3207 GNUNET_CONTAINER_MDLL_remove (neighbour,
3208 neighbour->queue_head,
3209 neighbour->queue_tail,
3211 GNUNET_CONTAINER_MDLL_remove (client,
3212 tc->details.communicator.queue_head,
3213 tc->details.communicator.queue_tail,
3215 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3216 tc->details.communicator.total_queue_length);
3217 while (NULL != (qe = queue->queue_head))
3219 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3220 queue->queue_length--;
3221 tc->details.communicator.total_queue_length--;
3224 GNUNET_assert (qe == qe->pm->qe);
3229 GNUNET_assert (0 == queue->queue_length);
3230 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3231 tc->details.communicator.total_queue_length))
3233 /* Communicator dropped below threshold, resume all queues */
3234 GNUNET_STATISTICS_update (
3236 "# Transmission throttled due to communicator queue limit",
3239 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3241 schedule_transmit_on_queue (s, GNUNET_NO);
3243 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3244 GNUNET_free (queue);
3246 vl = GNUNET_CONTAINER_multipeermap_get (links, &neighbour->pid);
3247 if ((NULL != vl) && (neighbour == vl->n))
3249 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3250 check_link_down (vl);
3252 if (NULL == neighbour->queue_head)
3254 free_neighbour (neighbour);
3262 * @param ale address list entry to free
3265 free_address_list_entry (struct AddressListEntry *ale)
3267 struct TransportClient *tc = ale->tc;
3269 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3270 tc->details.communicator.addr_tail,
3272 if (NULL != ale->sc)
3274 GNUNET_PEERSTORE_store_cancel (ale->sc);
3277 if (NULL != ale->st)
3279 GNUNET_SCHEDULER_cancel (ale->st);
3287 * Stop the peer request in @a value.
3289 * @param cls a `struct TransportClient` that no longer makes the request
3290 * @param pid the peer's identity
3291 * @param value a `struct PeerRequest`
3292 * @return #GNUNET_YES (always)
3295 stop_peer_request (void *cls,
3296 const struct GNUNET_PeerIdentity *pid,
3299 struct TransportClient *tc = cls;
3300 struct PeerRequest *pr = value;
3302 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3305 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3315 * Called whenever a client is disconnected. Frees our
3316 * resources associated with that client.
3318 * @param cls closure, NULL
3319 * @param client identification of the client
3320 * @param app_ctx our `struct TransportClient`
3323 client_disconnect_cb (void *cls,
3324 struct GNUNET_SERVICE_Client *client,
3327 struct TransportClient *tc = app_ctx;
3331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3332 "Client %p disconnected, cleaning up.\n",
3334 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3340 struct PendingMessage *pm;
3342 while (NULL != (pm = tc->details.core.pending_msg_head))
3344 GNUNET_CONTAINER_MDLL_remove (client,
3345 tc->details.core.pending_msg_head,
3346 tc->details.core.pending_msg_tail,
3354 case CT_COMMUNICATOR: {
3356 struct AddressListEntry *ale;
3358 while (NULL != (q = tc->details.communicator.queue_head))
3360 while (NULL != (ale = tc->details.communicator.addr_head))
3361 free_address_list_entry (ale);
3362 GNUNET_free (tc->details.communicator.address_prefix);
3365 case CT_APPLICATION:
3366 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3369 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3377 * Iterator telling new CORE client about all existing
3378 * connections to peers.
3380 * @param cls the new `struct TransportClient`
3381 * @param pid a connected peer
3382 * @param value the `struct Neighbour` with more information
3383 * @return #GNUNET_OK (continue to iterate)
3386 notify_client_connect_info (void *cls,
3387 const struct GNUNET_PeerIdentity *pid,
3390 struct TransportClient *tc = cls;
3393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3394 "Telling new CORE client about existing connection to %s\n",
3396 core_send_connect_info (tc, pid);
3402 * Initialize a "CORE" client. We got a start message from this
3403 * client, so add it to the list of clients for broadcasting of
3406 * @param cls the client
3407 * @param start the start message that was sent
3410 handle_client_start (void *cls, const struct StartMessage *start)
3412 struct TransportClient *tc = cls;
3415 options = ntohl (start->options);
3416 if ((0 != (1 & options)) &&
3417 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3419 /* client thinks this is a different peer, reject */
3421 GNUNET_SERVICE_client_drop (tc->client);
3424 if (CT_NONE != tc->type)
3427 GNUNET_SERVICE_client_drop (tc->client);
3431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3432 "New CORE client with PID %s registered\n",
3433 GNUNET_i2s (&start->self));
3434 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3435 ¬ify_client_connect_info,
3437 GNUNET_SERVICE_client_continue (tc->client);
3442 * Client asked for transmission to a peer. Process the request.
3444 * @param cls the client
3445 * @param obm the send message that was sent
3448 check_client_send (void *cls, const struct OutboundMessage *obm)
3450 struct TransportClient *tc = cls;
3452 const struct GNUNET_MessageHeader *obmm;
3454 if (CT_CORE != tc->type)
3457 return GNUNET_SYSERR;
3459 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
3460 if (size < sizeof (struct GNUNET_MessageHeader))
3463 return GNUNET_SYSERR;
3465 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3466 if (size != ntohs (obmm->size))
3469 return GNUNET_SYSERR;
3476 * Free fragment tree below @e root, excluding @e root itself.
3477 * FIXME: this does NOT seem to have the intended semantics
3478 * based on how this is called. Seems we generally DO expect
3479 * @a root to be free'ed itself as well!
3481 * @param root root of the tree to free
3484 free_fragment_tree (struct PendingMessage *root)
3486 struct PendingMessage *frag;
3488 while (NULL != (frag = root->head_frag))
3490 struct PendingAcknowledgement *pa;
3492 free_fragment_tree (frag);
3493 while (NULL != (pa = frag->pa_head))
3495 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3498 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3505 * Release memory associated with @a pm and remove @a pm from associated
3506 * data structures. @a pm must be a top-level pending message and not
3507 * a fragment in the tree. The entire tree is freed (if applicable).
3509 * @param pm the pending message to free
3512 free_pending_message (struct PendingMessage *pm)
3514 struct TransportClient *tc = pm->client;
3515 struct Neighbour *target = pm->target;
3516 struct DistanceVectorHop *dvh = pm->dvh;
3517 struct PendingAcknowledgement *pa;
3521 GNUNET_CONTAINER_MDLL_remove (client,
3522 tc->details.core.pending_msg_head,
3523 tc->details.core.pending_msg_tail,
3528 GNUNET_CONTAINER_MDLL_remove (dvh,
3529 dvh->pending_msg_head,
3530 dvh->pending_msg_tail,
3533 GNUNET_CONTAINER_MDLL_remove (neighbour,
3534 target->pending_msg_head,
3535 target->pending_msg_tail,
3537 while (NULL != (pa = pm->pa_head))
3539 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3543 free_fragment_tree (pm);
3546 GNUNET_assert (pm == pm->qe->pm);
3549 GNUNET_free_non_null (pm->bpm);
3555 * Send a response to the @a pm that we have processed a "send"
3556 * request. Sends a confirmation to the "core" client responsible for
3557 * the original request and free's @a pm.
3559 * @param pm handle to the original pending message
3562 client_send_response (struct PendingMessage *pm)
3564 struct TransportClient *tc = pm->client;
3565 struct Neighbour *target = pm->target;
3566 struct GNUNET_MQ_Envelope *env;
3567 struct SendOkMessage *som;
3571 env = GNUNET_MQ_msg (som, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3572 som->peer = target->pid;
3573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3574 "Confirming transmission to %s\n",
3575 GNUNET_i2s (&pm->target->pid));
3576 GNUNET_MQ_send (tc->mq, env);
3578 free_pending_message (pm);
3583 * Create a DV Box message.
3585 * @param total_hops how many hops did the message take so far
3586 * @param num_hops length of the @a hops array
3587 * @param origin origin of the message
3588 * @param hops next peer(s) to the destination, including destination
3589 * @param payload payload of the box
3590 * @param payload_size number of bytes in @a payload
3591 * @return boxed message (caller must #GNUNET_free() it).
3593 static struct TransportDVBoxMessage *
3594 create_dv_box (uint16_t total_hops,
3595 const struct GNUNET_PeerIdentity *origin,
3596 const struct GNUNET_PeerIdentity *target,
3598 const struct GNUNET_PeerIdentity *hops,
3599 const void *payload,
3600 uint16_t payload_size)
3602 struct TransportDVBoxMessage *dvb;
3603 struct GNUNET_PeerIdentity *dhops;
3605 GNUNET_assert (UINT16_MAX <
3606 sizeof (struct TransportDVBoxMessage) +
3607 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3609 dvb = GNUNET_malloc (sizeof (struct TransportDVBoxMessage) +
3610 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) +
3613 htons (sizeof (struct TransportDVBoxMessage) +
3614 sizeof (struct GNUNET_PeerIdentity) * (num_hops + 1) + payload_size);
3615 dvb->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
3616 dvb->total_hops = htons (total_hops);
3617 dvb->num_hops = htons (num_hops + 1);
3618 dvb->origin = *origin;
3619 dhops = (struct GNUNET_PeerIdentity *) &dvb[1];
3620 memcpy (dhops, hops, num_hops * sizeof (struct GNUNET_PeerIdentity));
3621 dhops[num_hops] = *target;
3622 memcpy (&dhops[num_hops + 1], payload, payload_size);
3624 if (GNUNET_EXTRA_LOGGING > 0)
3628 path = GNUNET_strdup (GNUNET_i2s (&dvb->origin));
3629 for (unsigned int i = 0; i <= num_hops; i++)
3633 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[i]));
3637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3638 "Creating DVBox for %u bytes of payload via %s\n",
3639 (unsigned int) payload_size,
3649 * Pick @a hops_array_length random DV paths satisfying @a options
3651 * @param dv data structure to pick paths from
3652 * @param options constraints to satisfy
3653 * @param hops_array[out] set to the result
3654 * @param hops_array_length length of the @a hops_array
3655 * @return number of entries set in @a hops_array
3658 pick_random_dv_hops (const struct DistanceVector *dv,
3659 enum RouteMessageOptions options,
3660 struct DistanceVectorHop **hops_array,
3661 unsigned int hops_array_length)
3663 uint64_t choices[hops_array_length];
3665 unsigned int dv_count;
3667 /* Pick random vectors, but weighted by distance, giving more weight
3668 to shorter vectors */
3671 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3674 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3675 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3676 .rel_value_us == 0))
3677 continue; /* pos unconfirmed and confirmed required */
3678 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3683 if (dv_count <= hops_array_length)
3686 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3688 hops_array[dv_count++] = pos;
3691 for (unsigned int i = 0; i < hops_array_length; i++)
3694 while (GNUNET_NO == ok)
3697 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3699 for (unsigned int j = 0; j < i; j++)
3700 if (choices[i] == choices[j])
3709 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3712 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3714 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3715 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3716 .rel_value_us == 0))
3717 continue; /* pos unconfirmed and confirmed required */
3718 for (unsigned int i = 0; i < hops_array_length; i++)
3719 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3720 hops_array[dv_count++] = pos;
3728 * Client asked for transmission to a peer. Process the request.
3730 * @param cls the client
3731 * @param obm the send message that was sent
3734 handle_client_send (void *cls, const struct OutboundMessage *obm)
3736 struct TransportClient *tc = cls;
3737 struct PendingMessage *pm;
3738 const struct GNUNET_MessageHeader *obmm;
3739 struct Neighbour *target;
3740 struct DistanceVector *dv;
3741 struct DistanceVectorHop *dvh;
3744 const void *payload;
3745 size_t payload_size;
3746 struct TransportDVBoxMessage *dvb;
3747 struct VirtualLink *vl;
3748 enum GNUNET_MQ_PriorityPreferences pp;
3750 GNUNET_assert (CT_CORE == tc->type);
3751 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3752 bytes_msg = ntohs (obmm->size);
3753 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
3754 vl = GNUNET_CONTAINER_multipeermap_get (links, &obm->peer);
3757 /* Failure: don't have this peer as a neighbour (anymore).
3758 Might have gone down asynchronously, so this is NOT
3759 a protocol violation by CORE. Still count the event,
3760 as this should be rare. */
3761 GNUNET_SERVICE_client_continue (tc->client);
3762 GNUNET_STATISTICS_update (GST_stats,
3763 "# messages dropped (neighbour unknown)",
3768 target = lookup_neighbour (&obm->peer);
3770 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &obm->peer);
3773 GNUNET_assert ((NULL != target) || (NULL != dv));
3774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3775 "Sending %u bytes to %s using %s\n",
3777 GNUNET_i2s (&obm->peer),
3778 (NULL == target) ? "distance vector path" : "direct queue");
3782 struct DistanceVectorHop *dvh;
3784 res = pick_random_dv_hops (dv, RMO_NONE, &dvh, 1);
3785 GNUNET_assert (1 == res);
3786 target = dvh->next_hop;
3787 dvb = create_dv_box (0,
3795 payload_size = ntohs (dvb->header.size);
3802 payload_size = bytes_msg;
3805 was_empty = (NULL == target->pending_msg_head);
3806 pm = GNUNET_malloc (sizeof (struct PendingMessage) + payload_size);
3809 pm->target = target;
3810 pm->bytes_msg = payload_size;
3811 memcpy (&pm[1], payload, payload_size);
3812 GNUNET_free_non_null (dvb);
3817 GNUNET_CONTAINER_MDLL_insert (dvh,
3818 dvh->pending_msg_head,
3819 dvh->pending_msg_tail,
3822 GNUNET_CONTAINER_MDLL_insert (neighbour,
3823 target->pending_msg_head,
3824 target->pending_msg_tail,
3826 GNUNET_CONTAINER_MDLL_insert (client,
3827 tc->details.core.pending_msg_head,
3828 tc->details.core.pending_msg_tail,
3831 return; /* all queues must already be busy */
3832 for (struct Queue *queue = target->queue_head; NULL != queue;
3833 queue = queue->next_neighbour)
3835 /* try transmission on any queue that is idle */
3836 if (NULL == queue->transmit_task)
3838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3839 "Queue %llu to %s is idle, triggering transmission\n",
3840 (unsigned long long) queue->qid,
3841 GNUNET_i2s (&queue->neighbour->pid));
3842 queue->transmit_task =
3843 GNUNET_SCHEDULER_add_now (&transmit_on_queue, queue);
3850 * Communicator started. Test message is well-formed.
3852 * @param cls the client
3853 * @param cam the send message that was sent
3856 check_communicator_available (
3858 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3860 struct TransportClient *tc = cls;
3863 if (CT_NONE != tc->type)
3866 return GNUNET_SYSERR;
3868 tc->type = CT_COMMUNICATOR;
3869 size = ntohs (cam->header.size) - sizeof (*cam);
3871 return GNUNET_OK; /* receive-only communicator */
3872 GNUNET_MQ_check_zero_termination (cam);
3878 * Send ACK to communicator (if requested) and free @a cmc.
3880 * @param cmc context for which we are done handling the message
3883 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3885 if (0 != ntohl (cmc->im.fc_on))
3887 /* send ACK when done to communicator for flow control! */
3888 struct GNUNET_MQ_Envelope *env;
3889 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3891 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3892 ack->reserved = htonl (0);
3893 ack->fc_id = cmc->im.fc_id;
3894 ack->sender = cmc->im.sender;
3895 GNUNET_MQ_send (cmc->tc->mq, env);
3897 GNUNET_SERVICE_client_continue (cmc->tc->client);
3903 * Client confirms that it is done handling message(s) to a particular
3904 * peer. We may now provide more messages to CORE for this peer.
3906 * Notifies the respective queues that more messages can now be received.
3908 * @param cls the client
3909 * @param rom the message that was sent
3912 handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
3914 struct TransportClient *tc = cls;
3915 struct VirtualLink *vl;
3917 struct CommunicatorMessageContext *cmc;
3919 if (CT_CORE != tc->type)
3922 GNUNET_SERVICE_client_drop (tc->client);
3925 vl = GNUNET_CONTAINER_multipeermap_get (links, &rom->peer);
3928 GNUNET_STATISTICS_update (GST_stats,
3929 "# RECV_OK dropped: virtual link unknown",
3932 GNUNET_SERVICE_client_continue (tc->client);
3935 delta = ntohl (rom->increase_window_delta);
3936 vl->core_recv_window += delta;
3937 if (vl->core_recv_window <= 0)
3939 /* resume communicators */
3940 while (NULL != (cmc = vl->cmc_tail))
3942 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
3943 finish_cmc_handling (cmc);
3949 * Communicator started. Process the request.
3951 * @param cls the client
3952 * @param cam the send message that was sent
3955 handle_communicator_available (
3957 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3959 struct TransportClient *tc = cls;
3962 size = ntohs (cam->header.size) - sizeof (*cam);
3965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3966 "Receive-only communicator connected\n");
3967 return; /* receive-only communicator */
3969 tc->details.communicator.address_prefix =
3970 GNUNET_strdup ((const char *) &cam[1]);
3971 tc->details.communicator.cc =
3972 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
3973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3974 "Communicator with prefix `%s' connected\n",
3975 tc->details.communicator.address_prefix);
3976 GNUNET_SERVICE_client_continue (tc->client);
3981 * Communicator requests backchannel transmission. Check the request.
3983 * @param cls the client
3984 * @param cb the send message that was sent
3985 * @return #GNUNET_OK if message is well-formed
3988 check_communicator_backchannel (
3990 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3992 const struct GNUNET_MessageHeader *inbox;
3998 msize = ntohs (cb->header.size) - sizeof (*cb);
3999 if (((size_t) (UINT16_MAX - msize)) >
4000 sizeof (struct TransportBackchannelEncapsulationMessage) +
4001 sizeof (struct TransportBackchannelRequestPayloadP))
4004 return GNUNET_SYSERR;
4006 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4007 isize = ntohs (inbox->size);
4011 return GNUNET_SYSERR;
4013 is = (const char *) inbox;
4016 GNUNET_assert (msize > 0);
4017 if ('\0' != is[msize - 1])
4020 return GNUNET_SYSERR;
4027 * Remove memory used by expired ephemeral keys.
4032 expire_ephemerals (void *cls)
4034 struct EphemeralCacheEntry *ece;
4037 ephemeral_task = NULL;
4038 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
4040 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4043 free_ephemeral (ece);
4046 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4055 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists,
4056 * generate one, cache it and return it.
4058 * @param pid peer to look up ephemeral for
4059 * @param private_key[out] set to the private key
4060 * @param ephemeral_key[out] set to the key
4061 * @param ephemeral_sender_sig[out] set to the signature
4062 * @param monotime[out] set to the monotime used for the signature
4065 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
4066 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
4067 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
4068 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
4069 struct GNUNET_TIME_Absolute *monotime)
4071 struct EphemeralCacheEntry *ece;
4072 struct EphemeralConfirmationPS ec;
4074 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, pid);
4075 if ((NULL != ece) &&
4076 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity)
4079 free_ephemeral (ece);
4084 ece = GNUNET_new (struct EphemeralCacheEntry);
4086 ece->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4087 ece->ephemeral_validity =
4088 GNUNET_TIME_absolute_add (ece->monotime, EPHEMERAL_VALIDITY);
4089 GNUNET_assert (GNUNET_OK ==
4090 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
4091 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, &ece->ephemeral_key);
4092 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4093 ec.purpose.size = htonl (sizeof (ec));
4095 ec.ephemeral_key = ece->ephemeral_key;
4096 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4100 GNUNET_CONTAINER_heap_insert (ephemeral_heap,
4102 ece->ephemeral_validity.abs_value_us);
4103 GNUNET_assert (GNUNET_OK ==
4104 GNUNET_CONTAINER_multipeermap_put (
4108 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4109 if (NULL == ephemeral_task)
4110 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
4114 *private_key = ece->private_key;
4115 *ephemeral_key = ece->ephemeral_key;
4116 *ephemeral_sender_sig = ece->sender_sig;
4117 *monotime = ece->monotime;
4122 * Send the control message @a payload on @a queue.
4124 * @param queue the queue to use for transmission
4125 * @param pm pending message to update once transmission is done, may be NULL!
4126 * @param payload the payload to send (encapsulated in a
4127 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4128 * @param payload_size number of bytes in @a payload
4131 queue_send_msg (struct Queue *queue,
4132 struct PendingMessage *pm,
4133 const void *payload,
4134 size_t payload_size)
4136 struct Neighbour *n = queue->neighbour;
4137 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4138 struct GNUNET_MQ_Envelope *env;
4140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4141 "Queueing %u bytes of payload for transmission on queue %llu to %s\n",
4142 (unsigned int) payload_size,
4143 (unsigned long long) queue->qid,
4144 GNUNET_i2s (&queue->neighbour->pid));
4145 env = GNUNET_MQ_msg_extra (smt,
4147 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4148 smt->qid = queue->qid;
4149 smt->mid = queue->mid_gen;
4150 smt->receiver = n->pid;
4151 memcpy (&smt[1], payload, payload_size);
4153 /* Pass the env to the communicator of queue for transmission. */
4154 struct QueueEntry *qe;
4156 qe = GNUNET_new (struct QueueEntry);
4157 qe->mid = queue->mid_gen++;
4162 GNUNET_assert (NULL == pm->qe);
4165 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4166 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4167 queue->queue_length++;
4168 queue->tc->details.communicator.total_queue_length++;
4169 GNUNET_MQ_send (queue->tc->mq, env);
4175 * Pick a queue of @a n under constraints @a options and schedule
4176 * transmission of @a hdr.
4178 * @param n neighbour to send to
4179 * @param hdr message to send as payload
4180 * @param options whether queues must be confirmed or not,
4181 * and whether we may pick multiple (2) queues
4184 route_via_neighbour (const struct Neighbour *n,
4185 const struct GNUNET_MessageHeader *hdr,
4186 enum RouteMessageOptions options)
4188 struct GNUNET_TIME_Absolute now;
4189 unsigned int candidates;
4193 /* Pick one or two 'random' queues from n (under constraints of options) */
4194 now = GNUNET_TIME_absolute_get ();
4195 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4196 weight in the future; weight could be assigned by observed
4197 bandwidth (note: not sure if we should do this for this type
4198 of control traffic though). */
4200 for (struct Queue *pos = n->queue_head; NULL != pos;
4201 pos = pos->next_neighbour)
4203 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4204 (pos->validated_until.abs_value_us > now.abs_value_us))
4207 if (0 == candidates)
4209 /* This can happen rarely if the last confirmed queue timed
4210 out just as we were beginning to process this message. */
4211 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4212 "Could not route message of type %u to %s: no valid queue\n",
4214 GNUNET_i2s (&n->pid));
4215 GNUNET_STATISTICS_update (GST_stats,
4216 "# route selection failed (all no valid queue)",
4221 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4222 if (0 == (options & RMO_REDUNDANT))
4223 sel2 = candidates; /* picks none! */
4225 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4227 for (struct Queue *pos = n->queue_head; NULL != pos;
4228 pos = pos->next_neighbour)
4230 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) ||
4231 (pos->validated_until.abs_value_us > now.abs_value_us))
4233 if ((sel1 == candidates) || (sel2 == candidates))
4235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4236 "Routing message of type %u to %s using %s (#%u)\n",
4238 GNUNET_i2s (&n->pid),
4240 (sel1 == candidates) ? 1 : 2);
4241 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4250 * Given a distance vector path @a dvh route @a payload to
4251 * the ultimate destination respecting @a options.
4252 * Sets up the boxed message and queues it at the next hop.
4254 * @param dvh choice of the path for the message
4255 * @param payload body to transmit
4256 * @param options options to use for control
4259 forward_via_dvh (const struct DistanceVectorHop *dvh,
4260 const struct GNUNET_MessageHeader *payload,
4261 enum RouteMessageOptions options)
4263 struct TransportDVBoxMessage *dvb;
4265 dvb = create_dv_box (0,
4271 ntohs (payload->size));
4272 route_via_neighbour (dvh->next_hop, &dvb->header, options);
4278 * Pick a path of @a dv under constraints @a options and schedule
4279 * transmission of @a hdr.
4281 * @param n neighbour to send to
4282 * @param hdr message to send as payload
4283 * @param options whether path must be confirmed or not
4284 * and whether we may pick multiple (2) paths
4287 route_via_dv (const struct DistanceVector *dv,
4288 const struct GNUNET_MessageHeader *hdr,
4289 enum RouteMessageOptions options)
4291 struct DistanceVectorHop *hops[2];
4294 res = pick_random_dv_hops (dv,
4297 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4298 for (unsigned int i = 0; i < res; i++)
4300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4301 "Routing message of type %u to %s using DV (#%u/%u)\n",
4303 GNUNET_i2s (&dv->target),
4306 forward_via_dvh (hops[i], hdr, options & (~RMO_REDUNDANT));
4312 * We need to transmit @a hdr to @a target. If necessary, this may
4313 * involve DV routing.
4315 * @param target peer to receive @a hdr
4316 * @param hdr header of the message to route and #GNUNET_free()
4317 * @param options which transmission channels are allowed
4320 route_message (const struct GNUNET_PeerIdentity *target,
4321 struct GNUNET_MessageHeader *hdr,
4322 enum RouteMessageOptions options)
4324 struct VirtualLink *vl;
4325 struct Neighbour *n;
4326 struct DistanceVector *dv;
4328 vl = GNUNET_CONTAINER_multipeermap_get (links, target);
4330 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4331 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4333 /* if confirmed is required, and we do not have anything
4334 confirmed, drop respective options */
4336 n = lookup_neighbour (target);
4337 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4338 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4340 if ((NULL == n) && (NULL == dv))
4342 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4343 "Cannot route message of type %u to %s: no route\n",
4345 GNUNET_i2s (target));
4346 GNUNET_STATISTICS_update (GST_stats,
4347 "# Messages dropped in routing: no acceptable method",
4353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4354 "Routing message of type %u to %s with options %X\n",
4356 GNUNET_i2s (target),
4357 (unsigned int) options);
4358 /* If both dv and n are possible and we must choose:
4359 flip a coin for the choice between the two; for now 50/50 */
4360 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4362 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4367 if ((NULL != n) && (NULL != dv))
4368 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4369 enough for redunancy, so clear the flag. */
4372 route_via_neighbour (n, hdr, options);
4376 route_via_dv (dv, hdr, options);
4383 * Structure of the key material used to encrypt backchannel messages.
4385 struct BackchannelKeyState
4388 * State of our block cipher.
4390 gcry_cipher_hd_t cipher;
4393 * Actual key material.
4399 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4401 struct GNUNET_CRYPTO_AuthKey hmac_key;
4404 * Symmetric key to use for encryption.
4406 char aes_key[256 / 8];
4409 * Counter value to use during setup.
4411 char aes_ctr[128 / 8];
4418 * Given the key material in @a km and the initialization vector
4419 * @a iv, setup the key material for the backchannel in @a key.
4421 * @param km raw master secret
4422 * @param iv initialization vector
4423 * @param key[out] symmetric cipher and HMAC state to generate
4426 bc_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4427 const struct GNUNET_ShortHashCode *iv,
4428 struct BackchannelKeyState *key)
4430 /* must match #dh_key_derive_eph_pub */
4431 GNUNET_assert (GNUNET_YES ==
4432 GNUNET_CRYPTO_kdf (&key->material,
4433 sizeof (key->material),
4434 "transport-backchannel-key",
4435 strlen ("transport-backchannel-key"),
4440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4441 "Deriving backchannel key based on KM %s and IV %s\n",
4444 gcry_cipher_open (&key->cipher,
4445 GCRY_CIPHER_AES256 /* low level: go for speed */,
4446 GCRY_CIPHER_MODE_CTR,
4448 gcry_cipher_setkey (key->cipher,
4449 &key->material.aes_key,
4450 sizeof (key->material.aes_key));
4451 gcry_cipher_setctr (key->cipher,
4452 &key->material.aes_ctr,
4453 sizeof (key->material.aes_ctr));
4458 * Derive backchannel encryption key material from @a priv_ephemeral
4459 * and @a target and @a iv.
4461 * @param priv_ephemeral ephemeral private key to use
4462 * @param target the target peer to encrypt to
4463 * @param iv unique IV to use
4464 * @param key[out] set to the key material
4467 dh_key_derive_eph_pid (
4468 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4469 const struct GNUNET_PeerIdentity *target,
4470 const struct GNUNET_ShortHashCode *iv,
4471 struct BackchannelKeyState *key)
4473 struct GNUNET_HashCode km;
4475 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4476 &target->public_key,
4478 bc_setup_key_state_from_km (&km, iv, key);
4483 * Derive backchannel encryption key material from #GST_my_private_key
4484 * and @a pub_ephemeral and @a iv.
4486 * @param priv_ephemeral ephemeral private key to use
4487 * @param target the target peer to encrypt to
4488 * @param iv unique IV to use
4489 * @param key[out] set to the key material
4492 dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4493 const struct GNUNET_ShortHashCode *iv,
4494 struct BackchannelKeyState *key)
4496 struct GNUNET_HashCode km;
4498 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4501 bc_setup_key_state_from_km (&km, iv, key);
4506 * Do HMAC calculation for backchannel messages over @a data using key
4507 * material from @a key.
4509 * @param key key material (from DH)
4510 * @param hmac[out] set to the HMAC
4511 * @param data data to perform HMAC calculation over
4512 * @param data_size number of bytes in @a data
4515 bc_hmac (const struct BackchannelKeyState *key,
4516 struct GNUNET_HashCode *hmac,
4520 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4525 * Perform backchannel encryption using symmetric secret in @a key
4526 * to encrypt data from @a in to @a dst.
4528 * @param key[in,out] key material to use
4529 * @param dst where to write the result
4530 * @param in input data to encrypt (plaintext)
4531 * @param in_size number of bytes of input in @a in and available at @a dst
4534 bc_encrypt (struct BackchannelKeyState *key,
4540 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4545 * Perform backchannel encryption using symmetric secret in @a key
4546 * to encrypt data from @a in to @a dst.
4548 * @param key[in,out] key material to use
4549 * @param ciph cipher text to decrypt
4550 * @param out[out] output data to generate (plaintext)
4551 * @param out_size number of bytes of input in @a ciph and available in @a out
4554 bc_decrypt (struct BackchannelKeyState *key,
4560 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4565 * Clean up key material in @a key.
4567 * @param key key material to clean up (memory must not be free'd!)
4570 bc_key_clean (struct BackchannelKeyState *key)
4572 gcry_cipher_close (key->cipher);
4573 GNUNET_CRYPTO_zero_keys (&key->material, sizeof (key->material));
4578 * Communicator requests backchannel transmission. Process the request.
4580 * @param cls the client
4581 * @param cb the send message that was sent
4584 handle_communicator_backchannel (
4586 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4588 struct TransportClient *tc = cls;
4589 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
4590 struct GNUNET_TIME_Absolute monotime;
4591 struct TransportBackchannelEncapsulationMessage *enc;
4592 struct TransportBackchannelRequestPayloadP ppay;
4593 struct BackchannelKeyState key;
4598 const struct GNUNET_MessageHeader *inbox;
4601 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4602 /* 0-termination of 'is' was checked already in
4603 #check_communicator_backchannel() */
4604 is = (const char *) &cb[1];
4605 is += ntohs (inbox->size);
4606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4607 "Preparing backchannel transmission to %s:%s of type %u\n",
4608 GNUNET_i2s (&cb->pid),
4610 ntohs (inbox->size));
4612 /* encapsulate and encrypt message */
4613 msize = ntohs (cb->header.size) - sizeof (*cb) +
4614 sizeof (struct TransportBackchannelRequestPayloadP);
4615 enc = GNUNET_malloc (sizeof (*enc) + msize);
4617 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
4618 enc->header.size = htons (sizeof (*enc) + msize);
4619 enc->target = cb->pid;
4620 lookup_ephemeral (&cb->pid,
4622 &enc->ephemeral_key,
4625 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4628 dh_key_derive_eph_pid (&private_key, &cb->pid, &enc->iv, &key);
4629 ppay.monotonic_time = GNUNET_TIME_absolute_hton (monotime);
4630 mpos = (char *) &enc[1];
4631 bc_encrypt (&key, &ppay, mpos, sizeof (ppay));
4634 &mpos[sizeof (ppay)],
4635 ntohs (cb->header.size) - sizeof (*cb));
4639 sizeof (ppay) + ntohs (cb->header.size) - sizeof (*cb));
4640 bc_key_clean (&key);
4641 route_message (&cb->pid, &enc->header, RMO_DV_ALLOWED);
4642 GNUNET_SERVICE_client_continue (tc->client);
4647 * Address of our peer added. Test message is well-formed.
4649 * @param cls the client
4650 * @param aam the send message that was sent
4651 * @return #GNUNET_OK if message is well-formed
4654 check_add_address (void *cls,
4655 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4657 struct TransportClient *tc = cls;
4659 if (CT_COMMUNICATOR != tc->type)
4662 return GNUNET_SYSERR;
4664 GNUNET_MQ_check_zero_termination (aam);
4670 * Ask peerstore to store our address.
4672 * @param cls an `struct AddressListEntry *`
4675 store_pi (void *cls);
4679 * Function called when peerstore is done storing our address.
4681 * @param cls a `struct AddressListEntry`
4682 * @param success #GNUNET_YES if peerstore was successful
4685 peerstore_store_own_cb (void *cls, int success)
4687 struct AddressListEntry *ale = cls;
4690 if (GNUNET_YES != success)
4691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4692 "Failed to store our own address `%s' in peerstore!\n",
4695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4696 "Successfully stored our own address `%s' in peerstore!\n",
4698 /* refresh period is 1/4 of expiration time, that should be plenty
4699 without being excessive. */
4701 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
4709 * Ask peerstore to store our address.
4711 * @param cls an `struct AddressListEntry *`
4714 store_pi (void *cls)
4716 struct AddressListEntry *ale = cls;
4719 struct GNUNET_TIME_Absolute expiration;
4722 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
4723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4724 "Storing our address `%s' in peerstore until %s!\n",
4726 GNUNET_STRINGS_absolute_time_to_string (expiration));
4727 GNUNET_HELLO_sign_address (ale->address,
4733 ale->sc = GNUNET_PEERSTORE_store (peerstore,
4736 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
4740 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4741 &peerstore_store_own_cb,
4744 if (NULL == ale->sc)
4746 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4747 "Failed to store our address `%s' with peerstore\n",
4750 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
4756 * Address of our peer added. Process the request.
4758 * @param cls the client
4759 * @param aam the send message that was sent
4762 handle_add_address (void *cls,
4763 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
4765 struct TransportClient *tc = cls;
4766 struct AddressListEntry *ale;
4769 /* 0-termination of &aam[1] was checked in #check_add_address */
4770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4771 "Communicator added address `%s'!\n",
4772 (const char *) &aam[1]);
4773 slen = ntohs (aam->header.size) - sizeof (*aam);
4774 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
4776 ale->address = (const char *) &ale[1];
4777 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
4778 ale->aid = aam->aid;
4779 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
4780 memcpy (&ale[1], &aam[1], slen);
4781 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
4782 tc->details.communicator.addr_tail,
4784 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
4785 GNUNET_SERVICE_client_continue (tc->client);
4790 * Address of our peer deleted. Process the request.
4792 * @param cls the client
4793 * @param dam the send message that was sent
4796 handle_del_address (void *cls,
4797 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
4799 struct TransportClient *tc = cls;
4801 if (CT_COMMUNICATOR != tc->type)
4804 GNUNET_SERVICE_client_drop (tc->client);
4807 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
4811 if (dam->aid != ale->aid)
4813 GNUNET_assert (ale->tc == tc);
4814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4815 "Communicator deleted address `%s'!\n",
4817 free_address_list_entry (ale);
4818 GNUNET_SERVICE_client_continue (tc->client);
4821 GNUNET_SERVICE_client_drop (tc->client);
4826 * Given an inbound message @a msg from a communicator @a cmc,
4827 * demultiplex it based on the type calling the right handler.
4829 * @param cmc context for demultiplexing
4830 * @param msg message to demultiplex
4833 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4834 const struct GNUNET_MessageHeader *msg);
4838 * Communicator gave us an unencapsulated message to pass as-is to
4839 * CORE. Process the request.
4841 * @param cls a `struct CommunicatorMessageContext` (must call
4842 * #finish_cmc_handling() when done)
4843 * @param mh the message that was received
4846 handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
4848 struct CommunicatorMessageContext *cmc = cls;
4849 struct VirtualLink *vl;
4850 uint16_t size = ntohs (mh->size);
4853 if ((size > UINT16_MAX - sizeof (struct InboundMessage)) ||
4854 (size < sizeof (struct GNUNET_MessageHeader)))
4856 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
4859 finish_cmc_handling (cmc);
4860 GNUNET_SERVICE_client_drop (client);
4863 vl = GNUNET_CONTAINER_multipeermap_get (links, &cmc->im.sender);
4866 /* FIXME: sender is giving us messages for CORE but we don't have
4867 the link up yet! I *suspect* this can happen right now (i.e.
4868 sender has verified us, but we didn't verify sender), but if
4869 we pass this on, CORE would be confused (link down, messages
4870 arrive). We should investigate more if this happens often,
4871 or in a persistent manner, and possibly do "something" about
4872 it. Thus logging as error for now. */
4873 GNUNET_break_op (0);
4874 GNUNET_STATISTICS_update (GST_stats,
4875 "# CORE messages droped (virtual link still down)",
4879 finish_cmc_handling (cmc);
4882 /* Forward to all CORE clients */
4883 have_core = GNUNET_NO;
4884 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4886 struct GNUNET_MQ_Envelope *env;
4887 struct InboundMessage *im;
4889 if (CT_CORE != tc->type)
4891 have_core = GNUNET_YES;
4892 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4893 im->peer = cmc->im.sender;
4894 memcpy (&im[1], mh, size);
4895 GNUNET_MQ_send (tc->mq, env);
4897 vl->core_recv_window--;
4898 if (GNUNET_NO == have_core)
4899 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4900 "Dropped message to CORE: no CORE client connected!\n");
4902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4903 "Delivered message from %s of type %u to CORE\n",
4904 GNUNET_i2s (&cmc->im.sender),
4906 if (vl->core_recv_window > 0)
4908 finish_cmc_handling (cmc);
4911 /* Wait with calling #finish_cmc_handling(cmc) until the message
4912 was processed by CORE MQs (for CORE flow control)! */
4913 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
4918 * Communicator gave us a fragment box. Check the message.
4920 * @param cls a `struct CommunicatorMessageContext`
4921 * @param fb the send message that was sent
4922 * @return #GNUNET_YES if message is well-formed
4925 check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
4927 uint16_t size = ntohs (fb->header.size);
4928 uint16_t bsize = size - sizeof (*fb);
4933 GNUNET_break_op (0);
4934 return GNUNET_SYSERR;
4936 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
4938 GNUNET_break_op (0);
4939 return GNUNET_SYSERR;
4941 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
4943 GNUNET_break_op (0);
4944 return GNUNET_SYSERR;
4951 * Clean up an idle cummulative acknowledgement data structure.
4953 * @param cls a `struct AcknowledgementCummulator *`
4956 destroy_ack_cummulator (void *cls)
4958 struct AcknowledgementCummulator *ac = cls;
4961 GNUNET_assert (0 == ac->num_acks);
4964 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
4970 * Do the transmission of a cummulative acknowledgement now.
4972 * @param cls a `struct AcknowledgementCummulator *`
4975 transmit_cummulative_ack_cb (void *cls)
4977 struct AcknowledgementCummulator *ac = cls;
4978 struct TransportReliabilityAckMessage *ack;
4979 struct TransportCummulativeAckPayloadP *ap;
4982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4983 "Sending ACK with %u components to %s\n",
4985 GNUNET_i2s (&ac->target));
4986 GNUNET_assert (0 < ac->ack_counter);
4987 ack = GNUNET_malloc (sizeof (*ack) +
4989 sizeof (struct TransportCummulativeAckPayloadP));
4990 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
4992 htons (sizeof (*ack) +
4993 ac->ack_counter * sizeof (struct TransportCummulativeAckPayloadP));
4994 ack->ack_counter = htonl (ac->ack_counter++);
4995 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
4996 for (unsigned int i = 0; i < ac->ack_counter; i++)
4998 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
4999 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5000 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5002 route_message (&ac->target, &ack->header, RMO_DV_ALLOWED);
5004 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5005 &destroy_ack_cummulator,
5011 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5012 * transmission by at most @a ack_delay.
5014 * @param pid target peer
5015 * @param ack_uuid UUID to ack
5016 * @param max_delay how long can the ACK wait
5019 cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5020 const struct AcknowledgementUUIDP *ack_uuid,
5021 struct GNUNET_TIME_Absolute max_delay)
5023 struct AcknowledgementCummulator *ac;
5025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5026 "Scheduling ACK %s for transmission to %s\n",
5027 GNUNET_sh2s (&ack_uuid->value),
5029 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5032 ac = GNUNET_new (struct AcknowledgementCummulator);
5034 ac->min_transmission_time = max_delay;
5035 GNUNET_assert (GNUNET_YES ==
5036 GNUNET_CONTAINER_multipeermap_put (
5040 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5044 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5046 /* must run immediately, ack buffer full! */
5047 GNUNET_SCHEDULER_cancel (ac->task);
5048 transmit_cummulative_ack_cb (ac);
5050 GNUNET_SCHEDULER_cancel (ac->task);
5051 ac->min_transmission_time =
5052 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5054 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5055 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5056 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5058 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5059 &transmit_cummulative_ack_cb,
5065 * Closure for #find_by_message_uuid.
5067 struct FindByMessageUuidContext
5072 struct MessageUUIDP message_uuid;
5075 * Set to the reassembly context if found.
5077 struct ReassemblyContext *rc;
5082 * Iterator called to find a reassembly context by the message UUID in the
5085 * @param cls a `struct FindByMessageUuidContext`
5086 * @param key a key (unused)
5087 * @param value a `struct ReassemblyContext`
5088 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5091 find_by_message_uuid (void *cls, uint32_t key, void *value)
5093 struct FindByMessageUuidContext *fc = cls;
5094 struct ReassemblyContext *rc = value;
5097 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5107 * Communicator gave us a fragment. Process the request.
5109 * @param cls a `struct CommunicatorMessageContext` (must call
5110 * #finish_cmc_handling() when done)
5111 * @param fb the message that was received
5114 handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5116 struct CommunicatorMessageContext *cmc = cls;
5117 struct Neighbour *n;
5118 struct ReassemblyContext *rc;
5119 const struct GNUNET_MessageHeader *msg;
5124 struct GNUNET_TIME_Relative cdelay;
5125 struct FindByMessageUuidContext fc;
5127 n = lookup_neighbour (&cmc->im.sender);
5130 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5133 finish_cmc_handling (cmc);
5134 GNUNET_SERVICE_client_drop (client);
5137 if (NULL == n->reassembly_map)
5139 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5140 n->reassembly_heap =
5141 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5142 n->reassembly_timeout_task =
5143 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5144 &reassembly_cleanup_task,
5147 msize = ntohs (fb->msg_size);
5148 fc.message_uuid = fb->msg_uuid;
5150 GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5152 &find_by_message_uuid,
5154 if (NULL == (rc = fc.rc))
5156 rc = GNUNET_malloc (sizeof (*rc) + msize + /* reassembly payload buffer */
5157 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
5158 rc->msg_uuid = fb->msg_uuid;
5160 rc->msg_size = msize;
5161 rc->reassembly_timeout =
5162 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5163 rc->last_frag = GNUNET_TIME_absolute_get ();
5164 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5166 rc->reassembly_timeout.abs_value_us);
5167 GNUNET_assert (GNUNET_OK ==
5168 GNUNET_CONTAINER_multihashmap32_put (
5172 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5173 target = (char *) &rc[1];
5174 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5175 rc->msg_missing = rc->msg_size;
5176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5177 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5178 ntohs (fb->frag_off),
5180 GNUNET_i2s (&cmc->im.sender),
5181 (unsigned int) fb->msg_uuid.uuid);
5185 target = (char *) &rc[1];
5186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5187 "Received fragment at offset %u/%u from %s for message %u\n",
5188 ntohs (fb->frag_off),
5190 GNUNET_i2s (&cmc->im.sender),
5191 (unsigned int) fb->msg_uuid.uuid);
5193 if (msize != rc->msg_size)
5196 finish_cmc_handling (cmc);
5201 fsize = ntohs (fb->header.size) - sizeof (*fb);
5205 finish_cmc_handling (cmc);
5208 frag_off = ntohs (fb->frag_off);
5209 memcpy (&target[frag_off], &fb[1], fsize);
5210 /* update bitfield and msg_missing */
5211 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5213 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5215 rc->bitfield[i / 8] |= (1 << (i % 8));
5220 /* Compute cummulative ACK */
5221 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5222 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5223 if (0 == rc->msg_missing)
5224 cdelay = GNUNET_TIME_UNIT_ZERO;
5225 cummulative_ack (&cmc->im.sender,
5227 GNUNET_TIME_relative_to_absolute (cdelay));
5228 rc->last_frag = GNUNET_TIME_absolute_get ();
5229 /* is reassembly complete? */
5230 if (0 != rc->msg_missing)
5232 finish_cmc_handling (cmc);
5235 /* reassembly is complete, verify result */
5236 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5237 if (ntohs (msg->size) != rc->msg_size)
5240 free_reassembly_context (rc);
5241 finish_cmc_handling (cmc);
5244 /* successful reassembly */
5245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5246 "Fragment reassembly complete for message %u\n",
5247 (unsigned int) fb->msg_uuid.uuid);
5249 demultiplex_with_cmc (cmc, msg);
5250 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5251 en-route and we forget that we finished this reassembly immediately!
5252 -> keep around until timeout?
5253 -> shorten timeout based on ACK? */
5254 free_reassembly_context (rc);
5259 * Communicator gave us a reliability box. Check the message.
5261 * @param cls a `struct CommunicatorMessageContext`
5262 * @param rb the send message that was sent
5263 * @return #GNUNET_YES if message is well-formed
5266 check_reliability_box (void *cls,
5267 const struct TransportReliabilityBoxMessage *rb)
5270 GNUNET_MQ_check_boxed_message (rb);
5276 * Communicator gave us a reliability box. Process the request.
5278 * @param cls a `struct CommunicatorMessageContext` (must call
5279 * #finish_cmc_handling() when done)
5280 * @param rb the message that was received
5283 handle_reliability_box (void *cls,
5284 const struct TransportReliabilityBoxMessage *rb)
5286 struct CommunicatorMessageContext *cmc = cls;
5287 const struct GNUNET_MessageHeader *inbox =
5288 (const struct GNUNET_MessageHeader *) &rb[1];
5289 struct GNUNET_TIME_Relative rtt;
5291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5292 "Received reliability box from %s with UUID %s of type %u\n",
5293 GNUNET_i2s (&cmc->im.sender),
5294 GNUNET_sh2s (&rb->ack_uuid.value),
5295 (unsigned int) ntohs (inbox->type));
5296 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5297 do not really have an RTT for the
5298 *incoming* queue (should we have
5299 the sender add it to the rb message?) */
5303 (0 == ntohl (rb->ack_countdown))
5304 ? GNUNET_TIME_UNIT_ZERO_ABS
5305 : GNUNET_TIME_relative_to_absolute (
5306 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5307 /* continue with inner message */
5308 demultiplex_with_cmc (cmc, inbox);
5313 * Check if we have advanced to another age since the last time. If
5314 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5317 * @param pd[in,out] data to update
5318 * @param age current age
5321 update_pd_age (struct PerformanceData *pd, unsigned int age)
5325 if (age == pd->last_age)
5326 return; /* nothing to do */
5327 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5328 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5330 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5332 the->bytes_sent = 0;
5333 the->bytes_received = 0;
5340 * Update @a pd based on the latest @a rtt and the number of bytes
5341 * that were confirmed to be successfully transmitted.
5343 * @param pd[in,out] data to update
5344 * @param rtt latest round-trip time
5345 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5348 update_performance_data (struct PerformanceData *pd,
5349 struct GNUNET_TIME_Relative rtt,
5350 uint16_t bytes_transmitted_ok)
5352 uint64_t nval = rtt.rel_value_us;
5353 uint64_t oval = pd->aged_rtt.rel_value_us;
5354 unsigned int age = get_age ();
5355 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5357 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5360 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5361 update_pd_age (pd, age);
5362 the->bytes_received += bytes_transmitted_ok;
5367 * We have successfully transmitted data via @a q, update metrics.
5369 * @param q queue to update
5370 * @param rtt round trip time observed
5371 * @param bytes_transmitted_ok number of bytes successfully transmitted
5374 update_queue_performance (struct Queue *q,
5375 struct GNUNET_TIME_Relative rtt,
5376 uint16_t bytes_transmitted_ok)
5378 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5383 * We have successfully transmitted data via @a dvh, update metrics.
5385 * @param dvh distance vector path data to update
5386 * @param rtt round trip time observed
5387 * @param bytes_transmitted_ok number of bytes successfully transmitted
5390 update_dvh_performance (struct DistanceVectorHop *dvh,
5391 struct GNUNET_TIME_Relative rtt,
5392 uint16_t bytes_transmitted_ok)
5394 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5399 * The @a pa was acknowledged, process the acknowledgement.
5401 * @param pa the pending acknowledgement that was satisfied
5402 * @param ack_delay artificial delay from cummulative acks created by the
5406 handle_acknowledged (struct PendingAcknowledgement *pa,
5407 struct GNUNET_TIME_Relative ack_delay)
5409 struct PendingMessage *pm = pa->pm;
5410 struct GNUNET_TIME_Relative delay;
5412 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5413 if (delay.rel_value_us > ack_delay.rel_value_us)
5414 delay = GNUNET_TIME_UNIT_ZERO;
5416 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5417 if (NULL != pa->queue)
5418 update_queue_performance (pa->queue, delay, pa->message_size);
5419 if (NULL != pa->dvh)
5420 update_dvh_performance (pa->dvh, delay, pa->message_size);
5423 if (NULL != pm->frag_parent)
5425 pm = pm->frag_parent;
5426 free_fragment_tree (pa->pm);
5428 while ((NULL != pm->frag_parent) && (NULL == pm->head_frag))
5430 struct PendingMessage *parent = pm->frag_parent;
5432 free_fragment_tree (pm);
5435 if (NULL != pm->head_frag)
5436 pm = NULL; /* we are done, otherwise free 'pm' below */
5439 free_pending_message (pm);
5440 free_pending_acknowledgement (pa);
5445 * Communicator gave us a reliability ack. Check it is well-formed.
5447 * @param cls a `struct CommunicatorMessageContext` (unused)
5448 * @param ra the message that was received
5449 * @return #GNUNET_Ok if @a ra is well-formed
5452 check_reliability_ack (void *cls,
5453 const struct TransportReliabilityAckMessage *ra)
5455 unsigned int n_acks;
5458 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5459 sizeof (struct TransportCummulativeAckPayloadP);
5462 GNUNET_break_op (0);
5463 return GNUNET_SYSERR;
5465 if ((ntohs (ra->header.size) - sizeof (*ra)) !=
5466 n_acks * sizeof (struct TransportCummulativeAckPayloadP))
5468 GNUNET_break_op (0);
5469 return GNUNET_SYSERR;
5476 * Communicator gave us a reliability ack. Process the request.
5478 * @param cls a `struct CommunicatorMessageContext` (must call
5479 * #finish_cmc_handling() when done)
5480 * @param ra the message that was received
5483 handle_reliability_ack (void *cls,
5484 const struct TransportReliabilityAckMessage *ra)
5486 struct CommunicatorMessageContext *cmc = cls;
5487 const struct TransportCummulativeAckPayloadP *ack;
5488 struct PendingAcknowledgement *pa;
5489 unsigned int n_acks;
5490 uint32_t ack_counter;
5492 n_acks = (ntohs (ra->header.size) - sizeof (*ra)) /
5493 sizeof (struct TransportCummulativeAckPayloadP);
5494 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5495 for (unsigned int i = 0; i < n_acks; i++)
5498 GNUNET_CONTAINER_multishortmap_get (pending_acks, &ack[i].ack_uuid.value);
5501 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5502 "Received ACK from %s with UUID %s which is unknown to us!\n",
5503 GNUNET_i2s (&cmc->im.sender),
5504 GNUNET_sh2s (&ack[i].ack_uuid.value));
5505 GNUNET_STATISTICS_update (
5507 "# FRAGMENT_ACKS dropped, no matching pending message",
5512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5513 "Received ACK from %s with UUID %s\n",
5514 GNUNET_i2s (&cmc->im.sender),
5515 GNUNET_sh2s (&ack[i].ack_uuid.value));
5516 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
5519 ack_counter = htonl (ra->ack_counter);
5520 (void) ack_counter; /* silence compiler warning for now */
5521 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
5522 // (DV and/or Neighbour?)
5523 finish_cmc_handling (cmc);
5528 * Communicator gave us a backchannel encapsulation. Check the message.
5530 * @param cls a `struct CommunicatorMessageContext`
5531 * @param be the send message that was sent
5532 * @return #GNUNET_YES if message is well-formed
5535 check_backchannel_encapsulation (
5537 const struct TransportBackchannelEncapsulationMessage *be)
5539 uint16_t size = ntohs (be->header.size);
5542 if ((size - sizeof (*be)) <
5543 (sizeof (struct TransportBackchannelRequestPayloadP) +
5544 sizeof (struct GNUNET_MessageHeader)))
5546 GNUNET_break_op (0);
5547 return GNUNET_SYSERR;
5554 * We received the plaintext @a msg from backtalker @a b. Forward
5555 * it to the respective communicator.
5557 * @param b a backtalker
5558 * @param msg a message, consisting of a `struct GNUNET_MessageHeader`
5559 * followed by the target name of the communicator
5560 * @param msg_size number of bytes in @a msg
5563 forward_backchannel_payload (struct Backtalker *b,
5567 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
5568 struct GNUNET_MQ_Envelope *env;
5569 struct TransportClient *tc;
5570 const struct GNUNET_MessageHeader *mh;
5571 const char *target_communicator;
5574 /* Determine target_communicator and check @a msg is well-formed */
5576 mhs = ntohs (mh->size);
5577 if (mhs <= msg_size)
5579 GNUNET_break_op (0);
5582 target_communicator = &((const char *) msg)[ntohs (mh->size)];
5583 if ('\0' != target_communicator[msg_size - mhs - 1])
5585 GNUNET_break_op (0);
5588 /* Find client providing this communicator */
5589 for (tc = clients_head; NULL != tc; tc = tc->next)
5590 if ((CT_COMMUNICATOR == tc->type) &&
5592 strcmp (tc->details.communicator.address_prefix, target_communicator)))
5600 "# Backchannel message dropped: target communicator `%s' unknown",
5601 target_communicator);
5602 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
5603 GNUNET_free (stastr);
5606 /* Finally, deliver backchannel message to communicator */
5607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5608 "Delivering backchannel message from %s of type %u to %s\n",
5609 GNUNET_i2s (&b->pid),
5611 target_communicator);
5612 env = GNUNET_MQ_msg_extra (
5615 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
5617 memcpy (&cbi[1], msg, msg_size);
5618 GNUNET_MQ_send (tc->mq, env);
5623 * Free data structures associated with @a b.
5625 * @param b data structure to release
5628 free_backtalker (struct Backtalker *b)
5632 GNUNET_PEERSTORE_iterate_cancel (b->get);
5634 GNUNET_assert (NULL != b->cmc);
5635 finish_cmc_handling (b->cmc);
5638 if (NULL != b->task)
5640 GNUNET_SCHEDULER_cancel (b->task);
5645 GNUNET_PEERSTORE_store_cancel (b->sc);
5650 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
5656 * Callback to free backtalker records.
5660 * @param value a `struct Backtalker`
5661 * @return #GNUNET_OK (always)
5664 free_backtalker_cb (void *cls,
5665 const struct GNUNET_PeerIdentity *pid,
5668 struct Backtalker *b = value;
5672 free_backtalker (b);
5678 * Function called when it is time to clean up a backtalker.
5680 * @param cls a `struct Backtalker`
5683 backtalker_timeout_cb (void *cls)
5685 struct Backtalker *b = cls;
5688 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
5690 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5693 GNUNET_assert (NULL == b->sc);
5694 free_backtalker (b);
5699 * Function called with the monotonic time of a backtalker
5700 * by PEERSTORE. Updates the time and continues processing.
5702 * @param cls a `struct Backtalker`
5703 * @param record the information found, NULL for the last call
5704 * @param emsg error message
5707 backtalker_monotime_cb (void *cls,
5708 const struct GNUNET_PEERSTORE_Record *record,
5711 struct Backtalker *b = cls;
5712 struct GNUNET_TIME_AbsoluteNBO *mtbe;
5713 struct GNUNET_TIME_Absolute mt;
5718 /* we're done with #backtalker_monotime_cb() invocations,
5719 continue normal processing */
5721 GNUNET_assert (NULL != b->cmc);
5722 finish_cmc_handling (b->cmc);
5724 if (0 != b->body_size)
5725 forward_backchannel_payload (b, &b[1], b->body_size);
5728 if (sizeof (*mtbe) != record->value_size)
5733 mtbe = record->value;
5734 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
5735 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
5737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5738 "Backtalker message from %s dropped, monotime in the past\n",
5739 GNUNET_i2s (&b->pid));
5740 GNUNET_STATISTICS_update (
5742 "# Backchannel messages dropped: monotonic time not increasing",
5745 b->monotonic_time = mt;
5746 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
5755 * Function called by PEERSTORE when the store operation of
5756 * a backtalker's monotonic time is complete.
5758 * @param cls the `struct Backtalker`
5759 * @param success #GNUNET_OK on success
5762 backtalker_monotime_store_cb (void *cls, int success)
5764 struct Backtalker *b = cls;
5766 if (GNUNET_OK != success)
5768 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5769 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
5772 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5777 * The backtalker @a b monotonic time changed. Update PEERSTORE.
5779 * @param b a backtalker with updated monotonic time
5782 update_backtalker_monotime (struct Backtalker *b)
5784 struct GNUNET_TIME_AbsoluteNBO mtbe;
5788 GNUNET_PEERSTORE_store_cancel (b->sc);
5793 GNUNET_SCHEDULER_cancel (b->task);
5796 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
5798 GNUNET_PEERSTORE_store (peerstore,
5801 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5804 GNUNET_TIME_UNIT_FOREVER_ABS,
5805 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
5806 &backtalker_monotime_store_cb,
5812 * Communicator gave us a backchannel encapsulation. Process the request.
5813 * (We are not the origin of the backchannel here, the communicator simply
5814 * received a backchannel message and we are expected to forward it.)
5816 * @param cls a `struct CommunicatorMessageContext` (must call
5817 * #finish_cmc_handling() when done)
5818 * @param be the message that was received
5821 handle_backchannel_encapsulation (
5823 const struct TransportBackchannelEncapsulationMessage *be)
5825 struct CommunicatorMessageContext *cmc = cls;
5826 struct BackchannelKeyState key;
5827 struct GNUNET_HashCode hmac;
5831 if (0 != GNUNET_memcmp (&be->target, &GST_my_identity))
5833 /* not for me, try to route to target */
5834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5835 "Forwarding backtalk to %s\n",
5836 GNUNET_i2s (&be->target));
5837 route_message (&be->target,
5838 GNUNET_copy_message (&be->header),
5840 finish_cmc_handling (cmc);
5843 dh_key_derive_eph_pub (&be->ephemeral_key, &be->iv, &key);
5844 hdr = (const char *) &be[1];
5845 hdr_len = ntohs (be->header.size) - sizeof (*be);
5846 bc_hmac (&key, &hmac, hdr, hdr_len);
5847 if (0 != GNUNET_memcmp (&hmac, &be->hmac))
5849 /* HMAC missmatch, disard! */
5850 GNUNET_break_op (0);
5851 finish_cmc_handling (cmc);
5854 /* begin actual decryption */
5856 struct Backtalker *b;
5857 struct GNUNET_TIME_Absolute monotime;
5858 struct TransportBackchannelRequestPayloadP ppay;
5859 char body[hdr_len - sizeof (ppay)];
5861 GNUNET_assert (hdr_len >=
5862 sizeof (ppay) + sizeof (struct GNUNET_MessageHeader));
5863 bc_decrypt (&key, &ppay, hdr, sizeof (ppay));
5864 bc_decrypt (&key, &body, &hdr[sizeof (ppay)], hdr_len - sizeof (ppay));
5865 bc_key_clean (&key);
5866 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
5867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5868 "Decrypted backtalk from %s\n",
5869 GNUNET_i2s (&ppay.sender));
5870 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
5871 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
5873 GNUNET_STATISTICS_update (
5875 "# Backchannel messages dropped: monotonic time not increasing",
5878 finish_cmc_handling (cmc);
5882 (0 != GNUNET_memcmp (&b->last_ephemeral, &be->ephemeral_key)))
5884 /* Check signature */
5885 struct EphemeralConfirmationPS ec;
5887 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5888 ec.purpose.size = htonl (sizeof (ec));
5889 ec.target = GST_my_identity;
5890 ec.ephemeral_key = be->ephemeral_key;
5893 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
5896 &ppay.sender.public_key))
5898 /* Signature invalid, disard! */
5899 GNUNET_break_op (0);
5900 finish_cmc_handling (cmc);
5906 /* update key cache and mono time */
5907 b->last_ephemeral = be->ephemeral_key;
5908 b->monotonic_time = monotime;
5909 update_backtalker_monotime (b);
5910 forward_backchannel_payload (b, body, sizeof (body));
5912 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5913 finish_cmc_handling (cmc);
5916 /* setup data structure to cache signature AND check
5917 monotonic time with PEERSTORE before forwarding backchannel payload */
5918 b = GNUNET_malloc (sizeof (struct Backtalker) + sizeof (body));
5919 b->pid = ppay.sender;
5920 b->body_size = sizeof (body);
5921 memcpy (&b[1], body, sizeof (body));
5922 GNUNET_assert (GNUNET_YES ==
5923 GNUNET_CONTAINER_multipeermap_put (
5927 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5928 b->monotonic_time = monotime; /* NOTE: to be checked still! */
5931 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
5932 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
5934 GNUNET_PEERSTORE_iterate (peerstore,
5937 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
5938 &backtalker_monotime_cb,
5945 * Task called when we should check if any of the DV paths
5946 * we have learned to a target are due for garbage collection.
5948 * Collects stale paths, and possibly frees the entire DV
5949 * entry if no paths are left. Otherwise re-schedules itself.
5951 * @param cls a `struct DistanceVector`
5954 path_cleanup_cb (void *cls)
5956 struct DistanceVector *dv = cls;
5957 struct DistanceVectorHop *pos;
5959 dv->timeout_task = NULL;
5960 while (NULL != (pos = dv->dv_head))
5962 GNUNET_assert (dv == pos->dv);
5963 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
5965 free_distance_vector_hop (pos);
5973 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
5978 * The @a hop is a validated path to the respective target
5979 * peer and we should tell core about it -- and schedule
5980 * a job to revoke the state.
5982 * @param hop a path to some peer that is the reason for activation
5985 activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5987 struct DistanceVector *dv = hop->dv;
5988 struct VirtualLink *vl;
5990 vl = GNUNET_CONTAINER_multipeermap_get (links, &dv->target);
5993 /* Link was already up, remember dv is also now available and we are done */
5995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5996 "Virtual link to %s could now also use DV!\n",
5997 GNUNET_i2s (&dv->target));
6000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6001 "Creating new virtual link to %s using DV!\n",
6002 GNUNET_i2s (&dv->target));
6003 vl = GNUNET_new (struct VirtualLink);
6004 vl->target = dv->target;
6006 vl->core_recv_window = RECV_WINDOW_SIZE;
6007 vl->visibility_task =
6008 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6009 GNUNET_break (GNUNET_YES ==
6010 GNUNET_CONTAINER_multipeermap_put (
6014 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6015 /* We lacked a confirmed connection to the target
6016 before, so tell CORE about it (finally!) */
6017 cores_send_connect_info (&dv->target);
6022 * We have learned a @a path through the network to some other peer, add it to
6023 * our DV data structure (returning #GNUNET_YES on success).
6025 * We do not add paths if we have a sufficient number of shorter
6026 * paths to this target already (returning #GNUNET_NO).
6028 * We also do not add problematic paths, like those where we lack the first
6029 * hop in our neighbour list (i.e. due to a topology change) or where some
6030 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6032 * @param path the path we learned, path[0] should be us,
6033 * and then path contains a valid path from us to
6034 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6035 * @param path_len number of entries on the @a path, at least three!
6036 * @param network_latency how long does the message take from us to
6037 * `path[path_len-1]`? set to "forever" if unknown
6038 * @param path_valid_until how long is this path considered validated? Maybe
6040 * @return #GNUNET_YES on success,
6041 * #GNUNET_NO if we have better path(s) to the target
6042 * #GNUNET_SYSERR if the path is useless and/or invalid
6043 * (i.e. path[1] not a direct neighbour
6044 * or path[i+1] is a direct neighbour for i>0)
6047 learn_dv_path (const struct GNUNET_PeerIdentity *path,
6048 unsigned int path_len,
6049 struct GNUNET_TIME_Relative network_latency,
6050 struct GNUNET_TIME_Absolute path_valid_until)
6052 struct DistanceVectorHop *hop;
6053 struct DistanceVector *dv;
6054 struct Neighbour *next_hop;
6055 unsigned int shorter_distance;
6059 /* what a boring path! not allowed! */
6061 return GNUNET_SYSERR;
6063 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6064 next_hop = lookup_neighbour (&path[1]);
6065 if (NULL == next_hop)
6067 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6069 return GNUNET_SYSERR;
6071 for (unsigned int i = 2; i < path_len; i++)
6072 if (NULL != lookup_neighbour (&path[i]))
6074 /* Useless path: we have a direct connection to some hop
6075 in the middle of the path, so this one is not even
6076 terribly useful for redundancy */
6077 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6078 "Path of %u hops useless: directly link to hop %u (%s)\n",
6081 GNUNET_i2s (&path[i]));
6082 GNUNET_STATISTICS_update (GST_stats,
6083 "# Useless DV path ignored: hop is neighbour",
6086 return GNUNET_SYSERR;
6088 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6091 dv = GNUNET_new (struct DistanceVector);
6092 dv->target = path[path_len - 1];
6093 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6096 GNUNET_assert (GNUNET_OK ==
6097 GNUNET_CONTAINER_multipeermap_put (
6101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6103 /* Check if we have this path already! */
6104 shorter_distance = 0;
6105 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6108 if (pos->distance < path_len - 2)
6110 /* Note that the distances in 'pos' excludes us (path[0]) and
6111 the next_hop (path[1]), so we need to subtract two
6112 and check next_hop explicitly */
6113 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6115 int match = GNUNET_YES;
6117 for (unsigned int i = 0; i < pos->distance; i++)
6119 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6125 if (GNUNET_YES == match)
6127 struct GNUNET_TIME_Relative last_timeout;
6129 /* Re-discovered known path, update timeout */
6130 GNUNET_STATISTICS_update (GST_stats,
6131 "# Known DV path refreshed",
6134 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6136 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6137 pos->path_valid_until =
6138 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6139 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6140 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6142 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6143 activate_core_visible_dv_path (pos);
6144 if (last_timeout.rel_value_us <
6145 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6146 DV_PATH_DISCOVERY_FREQUENCY)
6149 /* Some peer send DV learn messages too often, we are learning
6150 the same path faster than it would be useful; do not forward! */
6151 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6152 "Rediscovered path too quickly, not forwarding further\n");
6155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6156 "Refreshed known path to %s, forwarding further\n",
6157 GNUNET_i2s (&dv->target));
6162 /* Count how many shorter paths we have (incl. direct
6163 neighbours) before simply giving up on this one! */
6164 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6166 /* We have a shorter path already! */
6167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6168 "Have many shorter DV paths %s, not forwarding further\n",
6169 GNUNET_i2s (&dv->target));
6172 /* create new DV path entry */
6173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6174 "Discovered new DV path to %s\n",
6175 GNUNET_i2s (&dv->target));
6176 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
6177 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6178 hop->next_hop = next_hop;
6180 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6183 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
6184 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6185 hop->path_valid_until = path_valid_until;
6186 hop->distance = path_len - 2;
6187 hop->pd.aged_rtt = network_latency;
6188 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6189 GNUNET_CONTAINER_MDLL_insert (neighbour,
6193 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6194 activate_core_visible_dv_path (hop);
6200 * Communicator gave us a DV learn message. Check the message.
6202 * @param cls a `struct CommunicatorMessageContext`
6203 * @param dvl the send message that was sent
6204 * @return #GNUNET_YES if message is well-formed
6207 check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6209 uint16_t size = ntohs (dvl->header.size);
6210 uint16_t num_hops = ntohs (dvl->num_hops);
6211 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6214 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
6216 GNUNET_break_op (0);
6217 return GNUNET_SYSERR;
6219 if (num_hops > MAX_DV_HOPS_ALLOWED)
6221 GNUNET_break_op (0);
6222 return GNUNET_SYSERR;
6224 for (unsigned int i = 0; i < num_hops; i++)
6226 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6228 GNUNET_break_op (0);
6229 return GNUNET_SYSERR;
6231 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6233 GNUNET_break_op (0);
6234 return GNUNET_SYSERR;
6242 * Build and forward a DV learn message to @a next_hop.
6244 * @param next_hop peer to send the message to
6245 * @param msg message received
6246 * @param bi_history bitmask specifying hops on path that were bidirectional
6247 * @param nhops length of the @a hops array
6248 * @param hops path the message traversed so far
6249 * @param in_time when did we receive the message, used to calculate network
6253 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6254 const struct TransportDVLearnMessage *msg,
6255 uint16_t bi_history,
6257 const struct DVPathEntryP *hops,
6258 struct GNUNET_TIME_Absolute in_time)
6260 struct DVPathEntryP *dhops;
6261 struct TransportDVLearnMessage *fwd;
6262 struct GNUNET_TIME_Relative nnd;
6264 /* compute message for forwarding */
6265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6266 "Forwarding DV learn message originating from %s to %s\n",
6267 GNUNET_i2s (&msg->initiator),
6268 GNUNET_i2s2 (next_hop));
6269 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6270 fwd = GNUNET_malloc (sizeof (struct TransportDVLearnMessage) +
6271 (nhops + 1) * sizeof (struct DVPathEntryP));
6272 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6273 fwd->header.size = htons (sizeof (struct TransportDVLearnMessage) +
6274 (nhops + 1) * sizeof (struct DVPathEntryP));
6275 fwd->num_hops = htons (nhops + 1);
6276 fwd->bidirectional = htons (bi_history);
6277 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6278 GNUNET_TIME_relative_ntoh (
6279 msg->non_network_delay));
6280 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6281 fwd->init_sig = msg->init_sig;
6282 fwd->initiator = msg->initiator;
6283 fwd->challenge = msg->challenge;
6284 dhops = (struct DVPathEntryP *) &fwd[1];
6285 GNUNET_memcpy (dhops, hops, sizeof (struct DVPathEntryP) * nhops);
6286 dhops[nhops].hop = GST_my_identity;
6288 struct DvHopPS dhp = {.purpose.purpose =
6289 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6290 .purpose.size = htonl (sizeof (dhp)),
6291 .pred = dhops[nhops - 1].hop,
6293 .challenge = msg->challenge};
6295 GNUNET_assert (GNUNET_OK ==
6296 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6298 &dhops[nhops].hop_sig));
6300 route_message (next_hop, &fwd->header, RMO_UNCONFIRMED_ALLOWED);
6305 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6307 * @param sender_monotonic_time monotonic time of the initiator
6308 * @param init the signer
6309 * @param challenge the challenge that was signed
6310 * @param init_sig signature presumably by @a init
6311 * @return #GNUNET_OK if the signature is valid
6314 validate_dv_initiator_signature (
6315 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6316 const struct GNUNET_PeerIdentity *init,
6317 const struct ChallengeNonceP *challenge,
6318 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6320 struct DvInitPS ip = {.purpose.purpose = htonl (
6321 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6322 .purpose.size = htonl (sizeof (ip)),
6323 .monotonic_time = sender_monotonic_time,
6324 .challenge = *challenge};
6328 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6333 GNUNET_break_op (0);
6334 return GNUNET_SYSERR;
6341 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6343 struct NeighbourSelectionContext
6346 * Original message we received.
6348 const struct TransportDVLearnMessage *dvl;
6353 const struct DVPathEntryP *hops;
6356 * Time we received the message.
6358 struct GNUNET_TIME_Absolute in_time;
6361 * Offsets of the selected peers.
6363 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6366 * Number of peers eligible for selection.
6368 unsigned int num_eligible;
6371 * Number of peers that were selected for forwarding.
6373 unsigned int num_selections;
6376 * Number of hops in @e hops
6381 * Bitmap of bidirectional connections encountered.
6383 uint16_t bi_history;
6388 * Function called for each neighbour during #handle_dv_learn.
6390 * @param cls a `struct NeighbourSelectionContext *`
6391 * @param pid identity of the peer
6392 * @param value a `struct Neighbour`
6393 * @return #GNUNET_YES (always)
6396 dv_neighbour_selection (void *cls,
6397 const struct GNUNET_PeerIdentity *pid,
6400 struct NeighbourSelectionContext *nsc = cls;
6403 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6404 return GNUNET_YES; /* skip initiator */
6405 for (unsigned int i = 0; i < nsc->nhops; i++)
6406 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6407 return GNUNET_YES; /* skip peers on path */
6408 nsc->num_eligible++;
6414 * Function called for each neighbour during #handle_dv_learn.
6415 * We call #forward_dv_learn() on the neighbour(s) selected
6416 * during #dv_neighbour_selection().
6418 * @param cls a `struct NeighbourSelectionContext *`
6419 * @param pid identity of the peer
6420 * @param value a `struct Neighbour`
6421 * @return #GNUNET_YES (always)
6424 dv_neighbour_transmission (void *cls,
6425 const struct GNUNET_PeerIdentity *pid,
6428 struct NeighbourSelectionContext *nsc = cls;
6431 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6432 return GNUNET_YES; /* skip initiator */
6433 for (unsigned int i = 0; i < nsc->nhops; i++)
6434 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6435 return GNUNET_YES; /* skip peers on path */
6436 for (unsigned int i = 0; i < nsc->num_selections; i++)
6438 if (nsc->selections[i] == nsc->num_eligible)
6440 forward_dv_learn (pid,
6449 nsc->num_eligible++;
6455 * Computes the number of neighbours we should forward a DVInit
6456 * message to given that it has so far taken @a hops_taken hops
6457 * though the network and that the number of neighbours we have
6458 * in total is @a neighbour_count, out of which @a eligible_count
6459 * are not yet on the path.
6461 * NOTE: technically we might want to include NSE in the formula to
6462 * get a better grip on the overall network size. However, for now
6463 * using NSE here would create a dependency issue in the build system.
6464 * => Left for later, hardcoded to 50 for now.
6466 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6467 * peers via DV (`target_total`). We want the reach to be spread out
6468 * over various distances to the origin, with a bias towards shorter
6471 * We make the strong assumption that the network topology looks
6472 * "similar" at other hops, in particular the @a neighbour_count
6473 * should be comparable at other hops.
6475 * If the local neighbourhood is densely connected, we expect that @a
6476 * eligible_count is close to @a neighbour_count minus @a hops_taken
6477 * as a lot of the path is already known. In that case, we should
6478 * forward to few(er) peers to try to find a path out of the
6479 * neighbourhood. OTOH, if @a eligible_count is close to @a
6480 * neighbour_count, we should forward to many peers as we are either
6481 * still close to the origin (i.e. @a hops_taken is small) or because
6482 * we managed to get beyond a local cluster. We express this as
6483 * the `boost_factor` using the square of the fraction of eligible
6484 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6485 * 99% are eligible, the 'boost' will be almost 1).
6487 * Second, the more hops we have taken, the larger the problem of an
6488 * exponential traffic explosion gets. So we take the `target_total`,
6489 * and compute our degree such that at each distance d 2^{-d} peers
6490 * are selected (corrected by the `boost_factor`).
6492 * @param hops_taken number of hops DVInit has travelled so far
6493 * @param neighbour_count number of neighbours we have in total
6494 * @param eligible_count number of neighbours we could in
6498 calculate_fork_degree (unsigned int hops_taken,
6499 unsigned int neighbour_count,
6500 unsigned int eligible_count)
6502 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6503 double eligible_ratio =
6504 ((double) eligible_count) / ((double) neighbour_count);
6505 double boost_factor = eligible_ratio * eligible_ratio;
6509 if (hops_taken >= 64)
6512 return 0; /* precaution given bitshift below */
6514 for (unsigned int i = 1; i < hops_taken; i++)
6516 /* For each hop, subtract the expected number of targets
6517 reached at distance d (so what remains divided by 2^d) */
6518 target_total -= (target_total * boost_factor / (1LLU << i));
6521 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6522 /* round up or down probabilistically depending on how close we were
6523 when floor()ing to rnd */
6524 left = target_total - (double) rnd;
6525 if (UINT32_MAX * left >
6526 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6527 rnd++; /* round up */
6528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6529 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6539 * Function called when peerstore is done storing a DV monotonic time.
6541 * @param cls a `struct Neighbour`
6542 * @param success #GNUNET_YES if peerstore was successful
6545 neighbour_store_dvmono_cb (void *cls, int success)
6547 struct Neighbour *n = cls;
6550 if (GNUNET_YES != success)
6551 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6552 "Failed to store other peer's monotonic time in peerstore!\n");
6556 // FIXME: add logging logic from here!
6560 * Communicator gave us a DV learn message. Process the request.
6562 * @param cls a `struct CommunicatorMessageContext` (must call
6563 * #finish_cmc_handling() when done)
6564 * @param dvl the message that was received
6567 handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6569 struct CommunicatorMessageContext *cmc = cls;
6570 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6573 uint16_t bi_history;
6574 const struct DVPathEntryP *hops;
6577 struct GNUNET_TIME_Absolute in_time;
6578 struct Neighbour *n;
6580 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6581 bi_history = ntohs (dvl->bidirectional);
6582 hops = (const struct DVPathEntryP *) &dvl[1];
6586 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6589 finish_cmc_handling (cmc);
6596 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6599 finish_cmc_handling (cmc);
6604 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6605 cc = cmc->tc->details.communicator.cc;
6606 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6607 cc); // FIXME: add bi-directional flag to cc?
6608 in_time = GNUNET_TIME_absolute_get ();
6610 /* continue communicator here, everything else can happen asynchronous! */
6611 finish_cmc_handling (cmc);
6613 n = lookup_neighbour (&dvl->initiator);
6616 if ((n->dv_monotime_available == GNUNET_YES) &&
6617 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6618 n->last_dv_learn_monotime.abs_value_us))
6620 GNUNET_STATISTICS_update (GST_stats,
6621 "# DV learn discarded due to time travel",
6626 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6631 GNUNET_break_op (0);
6634 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6635 if (GNUNET_YES == n->dv_monotime_available)
6638 GNUNET_PEERSTORE_store_cancel (n->sc);
6640 GNUNET_PEERSTORE_store (peerstore,
6643 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6644 &dvl->monotonic_time,
6645 sizeof (dvl->monotonic_time),
6646 GNUNET_TIME_UNIT_FOREVER_ABS,
6647 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6648 &neighbour_store_dvmono_cb,
6652 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6653 If signature verification load too high, implement random drop strategy */
6654 for (unsigned int i = 0; i < nhops; i++)
6656 struct DvHopPS dhp = {.purpose.purpose =
6657 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6658 .purpose.size = htonl (sizeof (dhp)),
6659 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6660 .succ = (nhops - 1 == i) ? GST_my_identity
6662 .challenge = dvl->challenge};
6665 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6668 &hops[i].hop.public_key))
6670 GNUNET_break_op (0);
6675 do_fwd = GNUNET_YES;
6676 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6678 struct GNUNET_PeerIdentity path[nhops + 1];
6679 struct GNUNET_TIME_Relative host_latency_sum;
6680 struct GNUNET_TIME_Relative latency;
6681 struct GNUNET_TIME_Relative network_latency;
6683 /* We initiated this, learn the forward path! */
6684 path[0] = GST_my_identity;
6685 path[1] = hops[0].hop;
6686 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6688 // Need also something to lookup initiation time
6689 // to compute RTT! -> add RTT argument here?
6690 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6691 // (based on dvl->challenge, we can identify time of origin!)
6693 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6694 /* assumption: latency on all links is the same */
6695 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6697 for (unsigned int i = 2; i <= nhops; i++)
6699 struct GNUNET_TIME_Relative ilat;
6701 /* assumption: linear latency increase per hop */
6702 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6703 path[i] = hops[i - 1].hop;
6704 learn_dv_path (path,
6707 GNUNET_TIME_relative_to_absolute (
6708 ADDRESS_VALIDATION_LIFETIME));
6710 /* as we initiated, do not forward again (would be circular!) */
6716 /* last hop was bi-directional, we could learn something here! */
6717 struct GNUNET_PeerIdentity path[nhops + 2];
6719 path[0] = GST_my_identity;
6720 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6721 for (unsigned int i = 0; i < nhops; i++)
6725 if (0 == (bi_history & (1 << i)))
6726 break; /* i-th hop not bi-directional, stop learning! */
6729 path[i + 2] = dvl->initiator;
6733 path[i + 2] = hops[nhops - i - 2].hop;
6736 iret = learn_dv_path (path,
6738 GNUNET_TIME_UNIT_FOREVER_REL,
6739 GNUNET_TIME_UNIT_ZERO_ABS);
6740 if (GNUNET_SYSERR == iret)
6742 /* path invalid or too long to be interesting for US, thus should also
6743 not be interesting to our neighbours, cut path when forwarding to
6744 'i' hops, except of course for the one that goes back to the
6746 GNUNET_STATISTICS_update (GST_stats,
6747 "# DV learn not forwarded due invalidity of path",
6753 if ((GNUNET_NO == iret) && (nhops == i + 1))
6755 /* we have better paths, and this is the longest target,
6756 so there cannot be anything interesting later */
6757 GNUNET_STATISTICS_update (GST_stats,
6758 "# DV learn not forwarded, got better paths",
6767 if (MAX_DV_HOPS_ALLOWED == nhops)
6769 /* At limit, we're out of here! */
6770 finish_cmc_handling (cmc);
6774 /* Forward to initiator, if path non-trivial and possible */
6775 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6776 did_initiator = GNUNET_NO;
6779 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6781 /* send back to origin! */
6782 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6783 did_initiator = GNUNET_YES;
6785 /* We forward under two conditions: either we still learned something
6786 ourselves (do_fwd), or the path was darn short and thus the initiator is
6787 likely to still be very interested in this (and we did NOT already
6788 send it back to the initiator) */
6789 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
6790 (GNUNET_NO == did_initiator)))
6792 /* Pick random neighbours that are not yet on the path */
6793 struct NeighbourSelectionContext nsc;
6796 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
6799 nsc.bi_history = bi_history;
6801 nsc.in_time = in_time;
6802 nsc.num_eligible = 0;
6803 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6804 &dv_neighbour_selection,
6806 if (0 == nsc.num_eligible)
6807 return; /* done here, cannot forward to anyone else */
6808 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
6809 nsc.num_selections =
6810 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
6811 for (unsigned int i = 0; i < nsc.num_selections; i++)
6813 (nsc.num_selections == n_cnt)
6814 ? i /* all were selected, avoid collisions by chance */
6815 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
6816 nsc.num_eligible = 0;
6817 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6818 &dv_neighbour_transmission,
6825 * Communicator gave us a DV box. Check the message.
6827 * @param cls a `struct CommunicatorMessageContext`
6828 * @param dvb the send message that was sent
6829 * @return #GNUNET_YES if message is well-formed
6832 check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6834 uint16_t size = ntohs (dvb->header.size);
6835 uint16_t num_hops = ntohs (dvb->num_hops);
6836 const struct GNUNET_PeerIdentity *hops =
6837 (const struct GNUNET_PeerIdentity *) &dvb[1];
6838 const struct GNUNET_MessageHeader *inbox =
6839 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6844 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) +
6845 sizeof (struct GNUNET_MessageHeader))
6847 GNUNET_break_op (0);
6848 return GNUNET_SYSERR;
6850 isize = ntohs (inbox->size);
6852 sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
6854 GNUNET_break_op (0);
6855 return GNUNET_SYSERR;
6857 itype = ntohs (inbox->type);
6858 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
6859 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype))
6861 GNUNET_break_op (0);
6862 return GNUNET_SYSERR;
6864 if (0 == GNUNET_memcmp (&dvb->origin, &GST_my_identity))
6866 GNUNET_break_op (0);
6867 return GNUNET_SYSERR;
6874 * Create a DV Box message and queue it for transmission to
6877 * @param next_hop peer to receive the message next
6878 * @param total_hops how many hops did the message take so far
6879 * @param num_hops length of the @a hops array
6880 * @param origin origin of the message
6881 * @param hops next peer(s) to the destination, including destination
6882 * @param payload payload of the box
6883 * @param payload_size number of bytes in @a payload
6886 forward_dv_box (struct Neighbour *next_hop,
6887 uint16_t total_hops,
6889 const struct GNUNET_PeerIdentity *origin,
6890 const struct GNUNET_PeerIdentity *hops,
6891 const void *payload,
6892 uint16_t payload_size)
6894 struct TransportDVBoxMessage *dvb;
6896 dvb = create_dv_box (total_hops,
6898 &hops[num_hops - 1] /* == target */,
6899 num_hops - 1 /* do not count target twice */,
6903 route_message (&next_hop->pid, &dvb->header, RMO_NONE);
6909 * Communicator gave us a DV box. Process the request.
6911 * @param cls a `struct CommunicatorMessageContext` (must call
6912 * #finish_cmc_handling() when done)
6913 * @param dvb the message that was received
6916 handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
6918 struct CommunicatorMessageContext *cmc = cls;
6919 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
6920 uint16_t num_hops = ntohs (dvb->num_hops);
6921 const struct GNUNET_PeerIdentity *hops =
6922 (const struct GNUNET_PeerIdentity *) &dvb[1];
6923 const struct GNUNET_MessageHeader *inbox =
6924 (const struct GNUNET_MessageHeader *) &hops[num_hops];
6928 /* We're trying from the end of the hops array, as we may be
6929 able to find a shortcut unknown to the origin that way */
6930 for (int i = num_hops - 1; i >= 0; i--)
6932 struct Neighbour *n;
6934 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
6936 GNUNET_break_op (0);
6937 finish_cmc_handling (cmc);
6940 n = lookup_neighbour (&hops[i]);
6944 ntohs (dvb->total_hops) + 1,
6945 num_hops - i - 1, /* number of hops left */
6947 &hops[i + 1], /* remaining hops */
6948 (const void *) &dvb[1],
6950 finish_cmc_handling (cmc);
6953 /* Woopsie, next hop not in neighbours, drop! */
6954 GNUNET_STATISTICS_update (GST_stats,
6955 "# DV Boxes dropped: next hop unknown",
6958 finish_cmc_handling (cmc);
6961 /* We are the target. Unbox and handle message. */
6962 cmc->im.sender = dvb->origin;
6963 cmc->total_hops = ntohs (dvb->total_hops);
6964 demultiplex_with_cmc (cmc, inbox);
6969 * Client notified us about transmission from a peer. Process the request.
6971 * @param cls a `struct TransportClient` which sent us the message
6972 * @param obm the send message that was sent
6973 * @return #GNUNET_YES if message is well-formed
6976 check_incoming_msg (void *cls,
6977 const struct GNUNET_TRANSPORT_IncomingMessage *im)
6979 struct TransportClient *tc = cls;
6981 if (CT_COMMUNICATOR != tc->type)
6984 return GNUNET_SYSERR;
6986 GNUNET_MQ_check_boxed_message (im);
6992 * Communicator gave us a transport address validation challenge. Process the
6995 * @param cls a `struct CommunicatorMessageContext` (must call
6996 * #finish_cmc_handling() when done)
6997 * @param tvc the message that was received
7000 handle_validation_challenge (
7002 const struct TransportValidationChallengeMessage *tvc)
7004 struct CommunicatorMessageContext *cmc = cls;
7005 struct TransportValidationResponseMessage *tvr;
7007 if (cmc->total_hops > 0)
7009 /* DV routing is not allowed for validation challenges! */
7010 GNUNET_break_op (0);
7011 finish_cmc_handling (cmc);
7014 tvr = GNUNET_new (struct TransportValidationResponseMessage);
7016 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7017 tvr->header.size = htons (sizeof (*tvr));
7018 tvr->challenge = tvc->challenge;
7019 tvr->origin_time = tvc->sender_time;
7020 tvr->validity_duration = cmc->im.expected_address_validity;
7022 /* create signature */
7023 struct TransportValidationPS tvp =
7024 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7025 .purpose.size = htonl (sizeof (tvp)),
7026 .validity_duration = tvr->validity_duration,
7027 .challenge = tvc->challenge};
7029 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7033 route_message (&cmc->im.sender,
7035 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7036 finish_cmc_handling (cmc);
7041 * Closure for #check_known_challenge.
7043 struct CheckKnownChallengeContext
7046 * Set to the challenge we are looking for.
7048 const struct ChallengeNonceP *challenge;
7051 * Set to a matching validation state, if one was found.
7053 struct ValidationState *vs;
7058 * Test if the validation state in @a value matches the
7059 * challenge from @a cls.
7061 * @param cls a `struct CheckKnownChallengeContext`
7062 * @param pid unused (must match though)
7063 * @param value a `struct ValidationState`
7064 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7067 check_known_challenge (void *cls,
7068 const struct GNUNET_PeerIdentity *pid,
7071 struct CheckKnownChallengeContext *ckac = cls;
7072 struct ValidationState *vs = value;
7075 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7083 * Function called when peerstore is done storing a
7084 * validated address.
7086 * @param cls a `struct ValidationState`
7087 * @param success #GNUNET_YES on success
7090 peerstore_store_validation_cb (void *cls, int success)
7092 struct ValidationState *vs = cls;
7095 if (GNUNET_YES == success)
7097 GNUNET_STATISTICS_update (GST_stats,
7098 "# Peerstore failed to store foreign address",
7105 * Task run periodically to validate some address based on #validation_heap.
7110 validation_start_cb (void *cls);
7114 * Set the time for next_challenge of @a vs to @a new_time.
7115 * Updates the heap and if necessary reschedules the job.
7117 * @param vs validation state to update
7118 * @param new_time new time for revalidation
7121 update_next_challenge_time (struct ValidationState *vs,
7122 struct GNUNET_TIME_Absolute new_time)
7124 struct GNUNET_TIME_Relative delta;
7126 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7127 return; /* be lazy */
7128 vs->next_challenge = new_time;
7131 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7133 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7134 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7135 (NULL != validation_task))
7137 if (NULL != validation_task)
7138 GNUNET_SCHEDULER_cancel (validation_task);
7139 /* randomize a bit */
7140 delta.rel_value_us =
7141 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7142 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7143 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7145 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7150 * Find the queue matching @a pid and @a address.
7152 * @param pid peer the queue must go to
7153 * @param address address the queue must use
7154 * @return NULL if no such queue exists
7156 static struct Queue *
7157 find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7159 struct Neighbour *n;
7161 n = lookup_neighbour (pid);
7164 for (struct Queue *pos = n->queue_head; NULL != pos;
7165 pos = pos->next_neighbour)
7167 if (0 == strcmp (pos->address, address))
7175 * Communicator gave us a transport address validation response. Process the
7178 * @param cls a `struct CommunicatorMessageContext` (must call
7179 * #finish_cmc_handling() when done)
7180 * @param tvr the message that was received
7183 handle_validation_response (
7185 const struct TransportValidationResponseMessage *tvr)
7187 struct CommunicatorMessageContext *cmc = cls;
7188 struct ValidationState *vs;
7189 struct CheckKnownChallengeContext ckac = {.challenge = &tvr->challenge,
7191 struct GNUNET_TIME_Absolute origin_time;
7193 struct Neighbour *n;
7194 struct VirtualLink *vl;
7196 /* check this is one of our challenges */
7197 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7199 &check_known_challenge,
7201 if (NULL == (vs = ckac.vs))
7203 /* This can happen simply if we 'forgot' the challenge by now,
7204 i.e. because we received the validation response twice */
7205 GNUNET_STATISTICS_update (GST_stats,
7206 "# Validations dropped, challenge unknown",
7209 finish_cmc_handling (cmc);
7213 /* sanity check on origin time */
7214 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7215 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7216 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7218 GNUNET_break_op (0);
7219 finish_cmc_handling (cmc);
7224 /* check signature */
7225 struct TransportValidationPS tvp =
7226 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7227 .purpose.size = htonl (sizeof (tvp)),
7228 .validity_duration = tvr->validity_duration,
7229 .challenge = tvr->challenge};
7233 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
7236 &cmc->im.sender.public_key))
7238 GNUNET_break_op (0);
7239 finish_cmc_handling (cmc);
7244 /* validity is capped by our willingness to keep track of the
7245 validation entry and the maximum the other peer allows */
7246 vs->valid_until = GNUNET_TIME_relative_to_absolute (
7247 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
7248 tvr->validity_duration),
7249 MAX_ADDRESS_VALID_UNTIL));
7250 vs->validated_until =
7251 GNUNET_TIME_absolute_min (vs->valid_until,
7252 GNUNET_TIME_relative_to_absolute (
7253 ADDRESS_VALIDATION_LIFETIME));
7254 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
7255 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
7256 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7258 sizeof (vs->challenge));
7259 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
7260 vs->validated_until,
7261 GNUNET_TIME_relative_multiply (vs->validation_rtt,
7262 VALIDATION_RTT_BUFFER_FACTOR));
7263 vs->last_challenge_use =
7264 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
7265 update_next_challenge_time (vs, vs->first_challenge_use);
7266 vs->sc = GNUNET_PEERSTORE_store (peerstore,
7269 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7271 strlen (vs->address) + 1,
7273 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
7274 &peerstore_store_validation_cb,
7276 finish_cmc_handling (cmc);
7278 /* Finally, we now possibly have a confirmed (!) working queue,
7279 update queue status (if queue still is around) */
7280 q = find_queue (&vs->pid, vs->address);
7283 GNUNET_STATISTICS_update (GST_stats,
7284 "# Queues lost at time of successful validation",
7289 q->validated_until = vs->validated_until;
7290 q->pd.aged_rtt = vs->validation_rtt;
7292 vl = GNUNET_CONTAINER_multipeermap_get (links, &vs->pid);
7295 /* Link was already up, remember n is also now available and we are done */
7297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7298 "Virtual link to %s could now also direct neighbour!\n",
7299 GNUNET_i2s (&vs->pid));
7302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7303 "Creating new virtual link to %s using direct neighbour!\n",
7304 GNUNET_i2s (&vs->pid));
7305 vl = GNUNET_new (struct VirtualLink);
7306 vl->target = n->pid;
7308 vl->core_recv_window = RECV_WINDOW_SIZE;
7309 vl->visibility_task =
7310 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7311 GNUNET_break (GNUNET_YES ==
7312 GNUNET_CONTAINER_multipeermap_put (
7316 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7317 /* We lacked a confirmed connection to the target
7318 before, so tell CORE about it (finally!) */
7319 cores_send_connect_info (&n->pid);
7324 * Incoming meessage. Process the request.
7326 * @param im the send message that was received
7329 handle_incoming_msg (void *cls,
7330 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7332 struct TransportClient *tc = cls;
7333 struct CommunicatorMessageContext *cmc =
7334 GNUNET_new (struct CommunicatorMessageContext);
7338 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
7343 * Given an inbound message @a msg from a communicator @a cmc,
7344 * demultiplex it based on the type calling the right handler.
7346 * @param cmc context for demultiplexing
7347 * @param msg message to demultiplex
7350 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7351 const struct GNUNET_MessageHeader *msg)
7353 struct GNUNET_MQ_MessageHandler handlers[] =
7354 {GNUNET_MQ_hd_var_size (fragment_box,
7355 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
7356 struct TransportFragmentBoxMessage,
7358 GNUNET_MQ_hd_var_size (reliability_box,
7359 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
7360 struct TransportReliabilityBoxMessage,
7362 GNUNET_MQ_hd_var_size (reliability_ack,
7363 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
7364 struct TransportReliabilityAckMessage,
7366 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
7367 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
7368 struct TransportBackchannelEncapsulationMessage,
7370 GNUNET_MQ_hd_var_size (dv_learn,
7371 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
7372 struct TransportDVLearnMessage,
7374 GNUNET_MQ_hd_var_size (dv_box,
7375 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
7376 struct TransportDVBoxMessage,
7378 GNUNET_MQ_hd_fixed_size (
7379 validation_challenge,
7380 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
7381 struct TransportValidationChallengeMessage,
7383 GNUNET_MQ_hd_fixed_size (
7384 validation_response,
7385 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7386 struct TransportValidationResponseMessage,
7388 GNUNET_MQ_handler_end ()};
7391 ret = GNUNET_MQ_handle_message (handlers, msg);
7392 if (GNUNET_SYSERR == ret)
7395 GNUNET_SERVICE_client_drop (cmc->tc->client);
7399 if (GNUNET_NO == ret)
7401 /* unencapsulated 'raw' message */
7402 handle_raw_message (&cmc, msg);
7408 * New queue became available. Check message.
7410 * @param cls the client
7411 * @param aqm the send message that was sent
7414 check_add_queue_message (void *cls,
7415 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
7417 struct TransportClient *tc = cls;
7419 if (CT_COMMUNICATOR != tc->type)
7422 return GNUNET_SYSERR;
7424 GNUNET_MQ_check_zero_termination (aqm);
7430 * If necessary, generates the UUID for a @a pm
7432 * @param pm pending message to generate UUID for.
7435 set_pending_message_uuid (struct PendingMessage *pm)
7437 if (pm->msg_uuid_set)
7439 pm->msg_uuid.uuid = pm->target->message_uuid_ctr++;
7440 pm->msg_uuid_set = GNUNET_YES;
7445 * Setup data structure waiting for acknowledgements.
7447 * @param queue queue the @a pm will be sent over
7448 * @param dvh path the message will take, may be NULL
7449 * @param pm the pending message for transmission
7450 * @return corresponding fresh pending acknowledgement
7452 static struct PendingAcknowledgement *
7453 prepare_pending_acknowledgement (struct Queue *queue,
7454 struct DistanceVectorHop *dvh,
7455 struct PendingMessage *pm)
7457 struct PendingAcknowledgement *pa;
7459 pa = GNUNET_new (struct PendingAcknowledgement);
7465 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7467 sizeof (pa->ack_uuid));
7468 } while (GNUNET_YES != GNUNET_CONTAINER_multishortmap_put (
7470 &pa->ack_uuid.value,
7472 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7473 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
7474 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
7476 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
7477 pa->transmission_time = GNUNET_TIME_absolute_get ();
7478 pa->message_size = pm->bytes_msg;
7484 * Fragment the given @a pm to the given @a mtu. Adds
7485 * additional fragments to the neighbour as well. If the
7486 * @a mtu is too small, generates and error for the @a pm
7489 * @param queue which queue to fragment for
7490 * @param dvh path the message will take, or NULL
7491 * @param pm pending message to fragment for transmission
7492 * @return new message to transmit
7494 static struct PendingMessage *
7495 fragment_message (struct Queue *queue,
7496 struct DistanceVectorHop *dvh,
7497 struct PendingMessage *pm)
7499 struct PendingAcknowledgement *pa;
7500 struct PendingMessage *ff;
7503 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7504 mtu = (0 == queue->mtu)
7505 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
7507 set_pending_message_uuid (pm);
7509 /* This invariant is established in #handle_add_queue_message() */
7510 GNUNET_assert (mtu > sizeof (struct TransportFragmentBoxMessage));
7512 /* select fragment for transmission, descending the tree if it has
7513 been expanded until we are at a leaf or at a fragment that is small
7517 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
7518 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
7520 ff = ff->head_frag; /* descent into fragmented fragments */
7523 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
7525 /* Did not yet calculate all fragments, calculate next fragment */
7526 struct PendingMessage *frag;
7527 struct TransportFragmentBoxMessage tfb;
7535 orig = (const char *) &ff[1];
7536 msize = ff->bytes_msg;
7539 const struct TransportFragmentBoxMessage *tfbo;
7541 tfbo = (const struct TransportFragmentBoxMessage *) orig;
7542 orig += sizeof (struct TransportFragmentBoxMessage);
7543 msize -= sizeof (struct TransportFragmentBoxMessage);
7544 xoff = ntohs (tfbo->frag_off);
7546 fragmax = mtu - sizeof (struct TransportFragmentBoxMessage);
7547 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
7549 GNUNET_malloc (sizeof (struct PendingMessage) +
7550 sizeof (struct TransportFragmentBoxMessage) + fragsize);
7551 frag->target = pm->target;
7552 frag->frag_parent = ff;
7553 frag->timeout = pm->timeout;
7554 frag->bytes_msg = sizeof (struct TransportFragmentBoxMessage) + fragsize;
7555 frag->pmt = PMT_FRAGMENT_BOX;
7556 msg = (char *) &frag[1];
7557 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
7559 htons (sizeof (struct TransportFragmentBoxMessage) + fragsize);
7560 tfb.ack_uuid = pa->ack_uuid;
7561 tfb.msg_uuid = pm->msg_uuid;
7562 tfb.frag_off = htons (ff->frag_off + xoff);
7563 tfb.msg_size = htons (pm->bytes_msg);
7564 memcpy (msg, &tfb, sizeof (tfb));
7565 memcpy (&msg[sizeof (tfb)], &orig[ff->frag_off], fragsize);
7566 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
7567 ff->frag_off += fragsize;
7571 /* Move head to the tail and return it */
7572 GNUNET_CONTAINER_MDLL_remove (frag,
7573 ff->frag_parent->head_frag,
7574 ff->frag_parent->tail_frag,
7576 GNUNET_CONTAINER_MDLL_insert_tail (frag,
7577 ff->frag_parent->head_frag,
7578 ff->frag_parent->tail_frag,
7585 * Reliability-box the given @a pm. On error (can there be any), NULL
7586 * may be returned, otherwise the "replacement" for @a pm (which
7587 * should then be added to the respective neighbour's queue instead of
7588 * @a pm). If the @a pm is already fragmented or reliability boxed,
7589 * or itself an ACK, this function simply returns @a pm.
7591 * @param queue which queue to prepare transmission for
7592 * @param dvh path the message will take, or NULL
7593 * @param pm pending message to box for transmission over unreliabile queue
7594 * @return new message to transmit
7596 static struct PendingMessage *
7597 reliability_box_message (struct Queue *queue,
7598 struct DistanceVectorHop *dvh,
7599 struct PendingMessage *pm)
7601 struct TransportReliabilityBoxMessage rbox;
7602 struct PendingAcknowledgement *pa;
7603 struct PendingMessage *bpm;
7606 if (PMT_CORE != pm->pmt)
7607 return pm; /* already fragmented or reliability boxed, or control message:
7609 if (NULL != pm->bpm)
7610 return pm->bpm; /* already computed earlier: do nothing */
7611 GNUNET_assert (NULL == pm->head_frag);
7612 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
7616 client_send_response (pm);
7619 pa = prepare_pending_acknowledgement (queue, dvh, pm);
7621 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (rbox) +
7623 bpm->target = pm->target;
7624 bpm->frag_parent = pm;
7625 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
7626 bpm->timeout = pm->timeout;
7627 bpm->pmt = PMT_RELIABILITY_BOX;
7628 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
7629 set_pending_message_uuid (bpm);
7630 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
7631 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
7632 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
7634 rbox.ack_uuid = pa->ack_uuid;
7635 msg = (char *) &bpm[1];
7636 memcpy (msg, &rbox, sizeof (rbox));
7637 memcpy (&msg[sizeof (rbox)], &pm[1], pm->bytes_msg);
7644 * Change the value of the `next_attempt` field of @a pm
7645 * to @a next_attempt and re-order @a pm in the transmission
7646 * list as required by the new timestmap.
7648 * @param pm a pending message to update
7649 * @param next_attempt timestamp to use
7652 update_pm_next_attempt (struct PendingMessage *pm,
7653 struct GNUNET_TIME_Absolute next_attempt)
7655 struct Neighbour *neighbour = pm->target;
7657 pm->next_attempt = next_attempt;
7658 if (NULL == pm->frag_parent)
7660 struct PendingMessage *pos;
7662 /* re-insert sort in neighbour list */
7663 GNUNET_CONTAINER_MDLL_remove (neighbour,
7664 neighbour->pending_msg_head,
7665 neighbour->pending_msg_tail,
7667 pos = neighbour->pending_msg_tail;
7668 while ((NULL != pos) &&
7669 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7670 pos = pos->prev_neighbour;
7671 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
7672 neighbour->pending_msg_head,
7673 neighbour->pending_msg_tail,
7679 /* re-insert sort in fragment list */
7680 struct PendingMessage *fp = pm->frag_parent;
7681 struct PendingMessage *pos;
7683 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
7684 pos = fp->tail_frag;
7685 while ((NULL != pos) &&
7686 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
7687 pos = pos->prev_frag;
7688 GNUNET_CONTAINER_MDLL_insert_after (frag,
7698 * We believe we are ready to transmit a message on a queue.
7699 * Gives the message to the
7700 * communicator for transmission (updating the tracker, and re-scheduling
7701 * itself if applicable).
7703 * @param cls the `struct Queue` to process transmissions for
7706 transmit_on_queue (void *cls)
7708 struct Queue *queue = cls;
7709 struct Neighbour *n = queue->neighbour;
7710 struct PendingMessage *pm;
7711 struct PendingMessage *s;
7714 queue->transmit_task = NULL;
7715 if (NULL == (pm = n->pending_msg_head))
7717 /* no message pending, nothing to do here! */
7722 /* message still pending with communciator!
7723 LOGGING-FIXME: Use stats? logging? Should this not be rare? */
7726 schedule_transmit_on_queue (queue, GNUNET_YES);
7727 if (NULL != queue->transmit_task)
7728 return; /* do it later */
7730 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7731 overhead += sizeof (struct TransportReliabilityBoxMessage);
7733 if ( ( (0 != queue->mtu) &&
7734 (pm->bytes_msg + overhead > queue->mtu) ) ||
7735 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
7736 (NULL != pm->head_frag /* fragments already exist, should
7737 respect that even if MTU is 0 for
7739 s = fragment_message (queue, pm->dvh, s);
7742 /* Fragmentation failed, try next message... */
7743 schedule_transmit_on_queue (queue, GNUNET_NO);
7746 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
7747 // FIXME-OPTIMIZE: and if reliability was requested for 's' by core!
7748 s = reliability_box_message (queue, pm->dvh, s);
7751 /* Reliability boxing failed, try next message... */
7752 schedule_transmit_on_queue (queue, GNUNET_NO);
7756 /* Pass 's' for transission to the communicator */
7757 queue_send_msg (queue, s, &s[1], s->bytes_msg);
7758 // FIXME: do something similar to the logic below
7759 // in defragmentation / reliability ACK handling!
7761 /* Check if this transmission somehow conclusively finished handing 'pm'
7762 even without any explicit ACKs */
7763 if ((PMT_CORE == s->pmt) &&
7764 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
7766 /* Full message sent, and over reliabile channel */
7767 client_send_response (pm);
7769 else if ((GNUNET_TRANSPORT_CC_RELIABLE ==
7770 queue->tc->details.communicator.cc) &&
7771 (PMT_FRAGMENT_BOX == s->pmt))
7773 struct PendingMessage *pos;
7775 /* Fragment sent over reliabile channel */
7776 free_fragment_tree (s);
7777 pos = s->frag_parent;
7778 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7780 /* check if subtree is done */
7781 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
7785 pos = s->frag_parent;
7786 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, s);
7790 /* Was this the last applicable fragmment? */
7791 if ((NULL == pm->head_frag) && (pm->frag_off == pm->bytes_msg))
7792 client_send_response (pm);
7794 else if (PMT_CORE != pm->pmt)
7796 /* This was an acknowledgement of some type, always free */
7797 free_pending_message (pm);
7801 /* Message not finished, waiting for acknowledgement.
7802 Update time by which we might retransmit 's' based on queue
7803 characteristics (i.e. RTT); it takes one RTT for the message to
7804 arrive and the ACK to come back in the best case; but the other
7805 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
7806 retransmitting. Note that in the future this heuristic should
7807 likely be improved further (measure RTT stability, consider
7808 message urgency and size when delaying ACKs, etc.) */
7809 update_pm_next_attempt (s,
7810 GNUNET_TIME_relative_to_absolute (
7811 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
7815 /* finally, re-schedule queue transmission task itself */
7816 schedule_transmit_on_queue (queue, GNUNET_NO);
7821 * Queue to a peer went down. Process the request.
7823 * @param cls the client
7824 * @param dqm the send message that was sent
7827 handle_del_queue_message (void *cls,
7828 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
7830 struct TransportClient *tc = cls;
7832 if (CT_COMMUNICATOR != tc->type)
7835 GNUNET_SERVICE_client_drop (tc->client);
7838 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7839 queue = queue->next_client)
7841 struct Neighbour *neighbour = queue->neighbour;
7843 if ((dqm->qid != queue->qid) ||
7844 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
7847 GNUNET_SERVICE_client_continue (tc->client);
7851 GNUNET_SERVICE_client_drop (tc->client);
7856 * Message was transmitted. Process the request.
7858 * @param cls the client
7859 * @param sma the send message that was sent
7862 handle_send_message_ack (void *cls,
7863 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
7865 struct TransportClient *tc = cls;
7866 struct QueueEntry *qe;
7867 struct PendingMessage *pm;
7869 if (CT_COMMUNICATOR != tc->type)
7872 GNUNET_SERVICE_client_drop (tc->client);
7876 /* find our queue entry matching the ACK */
7878 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
7879 queue = queue->next_client)
7881 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
7883 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
7886 if (qep->mid != sma->mid)
7895 /* this should never happen */
7897 GNUNET_SERVICE_client_drop (tc->client);
7900 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
7901 qe->queue->queue_tail,
7903 qe->queue->queue_length--;
7904 tc->details.communicator.total_queue_length--;
7905 GNUNET_SERVICE_client_continue (tc->client);
7907 /* if applicable, resume transmissions that waited on ACK */
7908 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
7909 tc->details.communicator.total_queue_length)
7911 /* Communicator dropped below threshold, resume all queues
7912 incident with this client! */
7913 GNUNET_STATISTICS_update (
7915 "# Transmission throttled due to communicator queue limit",
7918 for (struct Queue *queue = tc->details.communicator.queue_head;
7920 queue = queue->next_client)
7921 schedule_transmit_on_queue (queue, GNUNET_NO);
7923 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
7925 /* queue dropped below threshold; only resume this one queue */
7926 GNUNET_STATISTICS_update (GST_stats,
7927 "# Transmission throttled due to queue queue limit",
7930 schedule_transmit_on_queue (qe->queue, GNUNET_NO);
7933 if (NULL != (pm = qe->pm))
7935 struct Neighbour *n;
7937 GNUNET_assert (qe == pm->qe);
7939 /* If waiting for this communicator may have blocked transmission
7940 of pm on other queues for this neighbour, force schedule
7941 transmit on queue for queues of the neighbour */
7943 if (n->pending_msg_head == pm)
7945 for (struct Queue *queue = n->queue_head; NULL != queue;
7946 queue = queue->next_neighbour)
7947 schedule_transmit_on_queue (queue, GNUNET_NO);
7949 if (GNUNET_OK != ntohl (sma->status))
7952 GNUNET_ERROR_TYPE_INFO,
7953 "Queue failed in transmission, will try retransmission immediately\n");
7954 update_pm_next_attempt (pm, GNUNET_TIME_UNIT_ZERO_ABS);
7962 * Iterator telling new MONITOR client about all existing
7965 * @param cls the new `struct TransportClient`
7966 * @param pid a connected peer
7967 * @param value the `struct Neighbour` with more information
7968 * @return #GNUNET_OK (continue to iterate)
7971 notify_client_queues (void *cls,
7972 const struct GNUNET_PeerIdentity *pid,
7975 struct TransportClient *tc = cls;
7976 struct Neighbour *neighbour = value;
7978 GNUNET_assert (CT_MONITOR == tc->type);
7979 for (struct Queue *q = neighbour->queue_head; NULL != q;
7980 q = q->next_neighbour)
7982 struct MonitorEvent me = {.rtt = q->pd.aged_rtt,
7984 .num_msg_pending = q->num_msg_pending,
7985 .num_bytes_pending = q->num_bytes_pending};
7987 notify_monitor (tc, pid, q->address, q->nt, &me);
7994 * Initialize a monitor client.
7996 * @param cls the client
7997 * @param start the start message that was sent
8000 handle_monitor_start (void *cls,
8001 const struct GNUNET_TRANSPORT_MonitorStart *start)
8003 struct TransportClient *tc = cls;
8005 if (CT_NONE != tc->type)
8008 GNUNET_SERVICE_client_drop (tc->client);
8011 tc->type = CT_MONITOR;
8012 tc->details.monitor.peer = start->peer;
8013 tc->details.monitor.one_shot = ntohl (start->one_shot);
8014 GNUNET_CONTAINER_multipeermap_iterate (neighbours, ¬ify_client_queues, tc);
8015 GNUNET_SERVICE_client_mark_monitor (tc->client);
8016 GNUNET_SERVICE_client_continue (tc->client);
8021 * Find transport client providing communication service
8022 * for the protocol @a prefix.
8024 * @param prefix communicator name
8025 * @return NULL if no such transport client is available
8027 static struct TransportClient *
8028 lookup_communicator (const char *prefix)
8030 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
8032 if (CT_COMMUNICATOR != tc->type)
8034 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
8038 GNUNET_ERROR_TYPE_WARNING,
8039 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
8046 * Signature of a function called with a communicator @a address of a peer
8047 * @a pid that an application wants us to connect to.
8049 * @param pid target peer
8050 * @param address the address to try
8053 suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
8055 static uint32_t idgen;
8056 struct TransportClient *tc;
8058 struct GNUNET_TRANSPORT_CreateQueue *cqm;
8059 struct GNUNET_MQ_Envelope *env;
8062 prefix = GNUNET_HELLO_address_to_prefix (address);
8065 GNUNET_break (0); /* We got an invalid address!? */
8068 tc = lookup_communicator (prefix);
8071 GNUNET_STATISTICS_update (GST_stats,
8072 "# Suggestions ignored due to missing communicator",
8077 /* forward suggestion for queue creation to communicator */
8078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8079 "Request #%u for `%s' communicator to create queue to `%s'\n",
8080 (unsigned int) idgen,
8083 alen = strlen (address) + 1;
8085 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
8086 cqm->request_id = htonl (idgen++);
8087 cqm->receiver = *pid;
8088 memcpy (&cqm[1], address, alen);
8089 GNUNET_MQ_send (tc->mq, env);
8094 * The queue @a q (which matches the peer and address in @a vs) is
8095 * ready for queueing. We should now queue the validation request.
8097 * @param q queue to send on
8098 * @param vs state to derive validation challenge from
8101 validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
8103 struct TransportValidationChallengeMessage tvc;
8105 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
8107 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
8108 tvc.header.size = htons (sizeof (tvc));
8109 tvc.reserved = htonl (0);
8110 tvc.challenge = vs->challenge;
8111 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
8112 queue_send_msg (q, NULL, &tvc, sizeof (tvc));
8117 * Task run periodically to validate some address based on #validation_heap.
8122 validation_start_cb (void *cls)
8124 struct ValidationState *vs;
8128 validation_task = NULL;
8129 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
8130 /* drop validations past their expiration */
8133 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
8135 free_validation_state (vs);
8136 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
8139 return; /* woopsie, no more addresses known, should only
8140 happen if we're really a lonely peer */
8141 q = find_queue (&vs->pid, vs->address);
8144 vs->awaiting_queue = GNUNET_YES;
8145 suggest_to_connect (&vs->pid, vs->address);
8148 validation_transmit_on_queue (q, vs);
8149 /* Finally, reschedule next attempt */
8150 vs->challenge_backoff =
8151 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
8152 MAX_VALIDATION_CHALLENGE_FREQ);
8153 update_next_challenge_time (vs,
8154 GNUNET_TIME_relative_to_absolute (
8155 vs->challenge_backoff));
8160 * Closure for #check_connection_quality.
8162 struct QueueQualityContext
8165 * Set to the @e k'th queue encountered.
8170 * Set to the number of quality queues encountered.
8172 unsigned int quality_count;
8175 * Set to the total number of queues encountered.
8177 unsigned int num_queues;
8180 * Decremented for each queue, for selection of the
8181 * k-th queue in @e q.
8188 * Check whether any queue to the given neighbour is
8189 * of a good "quality" and if so, increment the counter.
8190 * Also counts the total number of queues, and returns
8191 * the k-th queue found.
8193 * @param cls a `struct QueueQualityContext *` with counters
8194 * @param pid peer this is about
8195 * @param value a `struct Neighbour`
8196 * @return #GNUNET_OK (continue to iterate)
8199 check_connection_quality (void *cls,
8200 const struct GNUNET_PeerIdentity *pid,
8203 struct QueueQualityContext *ctx = cls;
8204 struct Neighbour *n = value;
8209 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8214 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
8215 statistics and consider those as well here? */
8216 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
8217 do_inc = GNUNET_YES;
8219 if (GNUNET_YES == do_inc)
8220 ctx->quality_count++;
8226 * Task run when we CONSIDER initiating a DV learn
8227 * process. We first check that sending out a message is
8228 * even possible (queues exist), then that it is desirable
8229 * (if not, reschedule the task for later), and finally
8230 * we may then begin the job. If there are too many
8231 * entries in the #dvlearn_map, we purge the oldest entry
8237 start_dv_learn (void *cls)
8239 struct LearnLaunchEntry *lle;
8240 struct QueueQualityContext qqc;
8241 struct TransportDVLearnMessage dvl;
8244 dvlearn_task = NULL;
8245 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
8246 return; /* lost all connectivity, cannot do learning */
8247 qqc.quality_count = 0;
8249 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8250 &check_connection_quality,
8252 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
8254 struct GNUNET_TIME_Relative delay;
8255 unsigned int factor;
8257 /* scale our retries by how far we are above the threshold */
8258 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
8259 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
8260 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
8263 /* remove old entries in #dvlearn_map if it has grown too big */
8264 while (MAX_DV_LEARN_PENDING >=
8265 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
8268 GNUNET_assert (GNUNET_YES ==
8269 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
8270 &lle->challenge.value,
8272 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
8275 /* setup data structure for learning */
8276 lle = GNUNET_new (struct LearnLaunchEntry);
8277 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8279 sizeof (lle->challenge));
8280 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
8281 GNUNET_break (GNUNET_YES ==
8282 GNUNET_CONTAINER_multishortmap_put (
8284 &lle->challenge.value,
8286 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8287 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
8288 dvl.header.size = htons (sizeof (dvl));
8289 dvl.num_hops = htons (0);
8290 dvl.bidirectional = htons (0);
8291 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
8292 dvl.monotonic_time =
8293 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
8295 struct DvInitPS dvip = {.purpose.purpose = htonl (
8296 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
8297 .purpose.size = htonl (sizeof (dvip)),
8298 .monotonic_time = dvl.monotonic_time,
8299 .challenge = lle->challenge};
8301 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8305 dvl.initiator = GST_my_identity;
8306 dvl.challenge = lle->challenge;
8308 qqc.quality_count = 0;
8309 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
8312 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8313 &check_connection_quality,
8315 GNUNET_assert (NULL != qqc.q);
8317 /* Do this as close to transmission time as possible! */
8318 lle->launch_time = GNUNET_TIME_absolute_get ();
8320 queue_send_msg (qqc.q, NULL, &dvl, sizeof (dvl));
8321 /* reschedule this job, randomizing the time it runs (but no
8323 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
8324 DV_LEARN_BASE_FREQUENCY),
8331 * A new queue has been created, check if any address validation
8332 * requests have been waiting for it.
8334 * @param cls a `struct Queue`
8335 * @param pid peer concerned (unused)
8336 * @param value a `struct ValidationState`
8337 * @return #GNUNET_NO if a match was found and we can stop looking
8340 check_validation_request_pending (void *cls,
8341 const struct GNUNET_PeerIdentity *pid,
8344 struct Queue *q = cls;
8345 struct ValidationState *vs = value;
8348 if ((GNUNET_YES == vs->awaiting_queue) &&
8349 (0 == strcmp (vs->address, q->address)))
8351 vs->awaiting_queue = GNUNET_NO;
8352 validation_transmit_on_queue (q, vs);
8360 * Function called with the monotonic time of a DV initiator
8361 * by PEERSTORE. Updates the time.
8363 * @param cls a `struct Neighbour`
8364 * @param record the information found, NULL for the last call
8365 * @param emsg error message
8368 neighbour_dv_monotime_cb (void *cls,
8369 const struct GNUNET_PEERSTORE_Record *record,
8372 struct Neighbour *n = cls;
8373 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8378 /* we're done with #neighbour_dv_monotime_cb() invocations,
8379 continue normal processing */
8381 n->dv_monotime_available = GNUNET_YES;
8384 if (sizeof (*mtbe) != record->value_size)
8389 mtbe = record->value;
8390 n->last_dv_learn_monotime =
8391 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
8392 GNUNET_TIME_absolute_ntoh (*mtbe));
8397 * New queue became available. Process the request.
8399 * @param cls the client
8400 * @param aqm the send message that was sent
8403 handle_add_queue_message (void *cls,
8404 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8406 struct TransportClient *tc = cls;
8407 struct Queue *queue;
8408 struct Neighbour *neighbour;
8412 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBoxMessage))
8414 /* MTU so small as to be useless for transmissions,
8415 required for #fragment_message()! */
8416 GNUNET_break_op (0);
8417 GNUNET_SERVICE_client_drop (tc->client);
8420 neighbour = lookup_neighbour (&aqm->receiver);
8421 if (NULL == neighbour)
8423 neighbour = GNUNET_new (struct Neighbour);
8424 neighbour->message_uuid_ctr =
8425 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8426 neighbour->pid = aqm->receiver;
8427 GNUNET_assert (GNUNET_OK ==
8428 GNUNET_CONTAINER_multipeermap_put (
8432 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8434 GNUNET_PEERSTORE_iterate (peerstore,
8437 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
8438 &neighbour_dv_monotime_cb,
8441 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
8442 addr = (const char *) &aqm[1];
8444 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
8446 queue->address = (const char *) &queue[1];
8447 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8448 queue->qid = aqm->qid;
8449 queue->mtu = ntohl (aqm->mtu);
8450 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
8451 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
8452 queue->neighbour = neighbour;
8453 memcpy (&queue[1], addr, addr_len);
8454 /* notify monitors about new queue */
8456 struct MonitorEvent me = {.rtt = queue->pd.aged_rtt, .cs = queue->cs};
8458 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
8460 GNUNET_CONTAINER_MDLL_insert (neighbour,
8461 neighbour->queue_head,
8462 neighbour->queue_tail,
8464 GNUNET_CONTAINER_MDLL_insert (client,
8465 tc->details.communicator.queue_head,
8466 tc->details.communicator.queue_tail,
8468 /* check if valdiations are waiting for the queue */
8470 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8472 &check_validation_request_pending,
8474 /* might be our first queue, try launching DV learning */
8475 if (NULL == dvlearn_task)
8476 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
8477 GNUNET_SERVICE_client_continue (tc->client);
8482 * Communicator tells us that our request to create a queue "worked", that
8483 * is setting up the queue is now in process.
8485 * @param cls the `struct TransportClient`
8486 * @param cqr confirmation message
8489 handle_queue_create_ok (void *cls,
8490 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8492 struct TransportClient *tc = cls;
8494 if (CT_COMMUNICATOR != tc->type)
8497 GNUNET_SERVICE_client_drop (tc->client);
8500 GNUNET_STATISTICS_update (GST_stats,
8501 "# Suggestions succeeded at communicator",
8504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8505 "Request #%u for communicator to create queue succeeded\n",
8506 (unsigned int) ntohs (cqr->request_id));
8507 GNUNET_SERVICE_client_continue (tc->client);
8512 * Communicator tells us that our request to create a queue failed. This
8513 * usually indicates that the provided address is simply invalid or that the
8514 * communicator's resources are exhausted.
8516 * @param cls the `struct TransportClient`
8517 * @param cqr failure message
8520 handle_queue_create_fail (
8522 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
8524 struct TransportClient *tc = cls;
8526 if (CT_COMMUNICATOR != tc->type)
8529 GNUNET_SERVICE_client_drop (tc->client);
8532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8533 "Request #%u for communicator to create queue failed\n",
8534 (unsigned int) ntohs (cqr->request_id));
8535 GNUNET_STATISTICS_update (GST_stats,
8536 "# Suggestions failed in queue creation at communicator",
8539 GNUNET_SERVICE_client_continue (tc->client);
8544 * We have received a `struct ExpressPreferenceMessage` from an application
8547 * @param cls handle to the client
8548 * @param msg the start message
8551 handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8553 struct TransportClient *tc = cls;
8554 struct PeerRequest *pr;
8556 if (CT_APPLICATION != tc->type)
8559 GNUNET_SERVICE_client_drop (tc->client);
8562 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
8567 GNUNET_SERVICE_client_drop (tc->client);
8570 (void) stop_peer_request (tc, &pr->pid, pr);
8571 GNUNET_SERVICE_client_continue (tc->client);
8576 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
8577 * messages. We do nothing here, real verification is done later.
8579 * @param cls a `struct TransportClient *`
8580 * @param msg message to verify
8581 * @return #GNUNET_OK
8584 check_address_consider_verify (
8586 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8595 * Closure for #check_known_address.
8597 struct CheckKnownAddressContext
8600 * Set to the address we are looking for.
8602 const char *address;
8605 * Set to a matching validation state, if one was found.
8607 struct ValidationState *vs;
8612 * Test if the validation state in @a value matches the
8613 * address from @a cls.
8615 * @param cls a `struct CheckKnownAddressContext`
8616 * @param pid unused (must match though)
8617 * @param value a `struct ValidationState`
8618 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8621 check_known_address (void *cls,
8622 const struct GNUNET_PeerIdentity *pid,
8625 struct CheckKnownAddressContext *ckac = cls;
8626 struct ValidationState *vs = value;
8629 if (0 != strcmp (vs->address, ckac->address))
8637 * Start address validation.
8639 * @param pid peer the @a address is for
8640 * @param address an address to reach @a pid (presumably)
8643 start_address_validation (const struct GNUNET_PeerIdentity *pid,
8644 const char *address)
8646 struct GNUNET_TIME_Absolute now;
8647 struct ValidationState *vs;
8648 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8650 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8652 &check_known_address,
8654 if (NULL != (vs = ckac.vs))
8656 /* if 'vs' is not currently valid, we need to speed up retrying the
8658 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8660 /* reduce backoff as we got a fresh advertisement */
8661 vs->challenge_backoff =
8662 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8663 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8665 update_next_challenge_time (vs,
8666 GNUNET_TIME_relative_to_absolute (
8667 vs->challenge_backoff));
8671 now = GNUNET_TIME_absolute_get ();
8672 vs = GNUNET_new (struct ValidationState);
8675 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8676 vs->first_challenge_use = now;
8677 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8678 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8680 sizeof (vs->challenge));
8681 vs->address = GNUNET_strdup (address);
8682 GNUNET_assert (GNUNET_YES ==
8683 GNUNET_CONTAINER_multipeermap_put (
8687 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8688 update_next_challenge_time (vs, now);
8693 * Function called by PEERSTORE for each matching record.
8695 * @param cls closure
8696 * @param record peerstore record information
8697 * @param emsg error message, or NULL if no errors
8700 handle_hello (void *cls,
8701 const struct GNUNET_PEERSTORE_Record *record,
8704 struct PeerRequest *pr = cls;
8709 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8710 "Got failure from PEERSTORE: %s\n",
8714 val = record->value;
8715 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8720 start_address_validation (&pr->pid, (const char *) record->value);
8725 * We have received a `struct ExpressPreferenceMessage` from an application
8728 * @param cls handle to the client
8729 * @param msg the start message
8732 handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
8734 struct TransportClient *tc = cls;
8735 struct PeerRequest *pr;
8737 if (CT_NONE == tc->type)
8739 tc->type = CT_APPLICATION;
8740 tc->details.application.requests =
8741 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
8743 if (CT_APPLICATION != tc->type)
8746 GNUNET_SERVICE_client_drop (tc->client);
8749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8750 "Client suggested we talk to %s with preference %d at rate %u\n",
8751 GNUNET_i2s (&msg->peer),
8752 (int) ntohl (msg->pk),
8753 (int) ntohl (msg->bw.value__));
8754 pr = GNUNET_new (struct PeerRequest);
8756 pr->pid = msg->peer;
8758 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
8759 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
8760 tc->details.application.requests,
8763 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
8767 GNUNET_SERVICE_client_drop (tc->client);
8770 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
8773 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8776 GNUNET_SERVICE_client_continue (tc->client);
8781 * Given another peers address, consider checking it for validity
8782 * and then adding it to the Peerstore.
8784 * @param cls a `struct TransportClient`
8785 * @param hdr message containing the raw address data and
8786 * signature in the body, see #GNUNET_HELLO_extract_address()
8789 handle_address_consider_verify (
8791 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
8793 struct TransportClient *tc = cls;
8795 enum GNUNET_NetworkType nt;
8796 struct GNUNET_TIME_Absolute mono_time;
8799 // OPTIMIZE-FIXME: checking that we know this address already should
8800 // be done BEFORE checking the signature => HELLO API change!
8801 // OPTIMIZE-FIXME: pre-check: rate-limit signature verification /
8804 GNUNET_HELLO_extract_address (&hdr[1],
8805 ntohs (hdr->header.size) - sizeof (*hdr),
8809 if (NULL == address)
8811 GNUNET_break_op (0);
8814 start_address_validation (&hdr->peer, address);
8815 GNUNET_free (address);
8816 GNUNET_SERVICE_client_continue (tc->client);
8821 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
8824 * @param cls a `struct TransportClient *`
8825 * @param m message to verify
8826 * @return #GNUNET_OK on success
8829 check_request_hello_validation (void *cls,
8830 const struct RequestHelloValidationMessage *m)
8833 GNUNET_MQ_check_zero_termination (m);
8839 * A client encountered an address of another peer. Consider validating it,
8840 * and if validation succeeds, persist it to PEERSTORE.
8842 * @param cls a `struct TransportClient *`
8843 * @param m message to verify
8846 handle_request_hello_validation (void *cls,
8847 const struct RequestHelloValidationMessage *m)
8849 struct TransportClient *tc = cls;
8851 start_address_validation (&m->peer, (const char *) &m[1]);
8852 GNUNET_SERVICE_client_continue (tc->client);
8857 * Free neighbour entry.
8861 * @param value a `struct Neighbour`
8862 * @return #GNUNET_OK (always)
8865 free_neighbour_cb (void *cls,
8866 const struct GNUNET_PeerIdentity *pid,
8869 struct Neighbour *neighbour = value;
8873 GNUNET_break (0); // should this ever happen?
8874 free_neighbour (neighbour);
8881 * Free DV route entry.
8885 * @param value a `struct DistanceVector`
8886 * @return #GNUNET_OK (always)
8889 free_dv_routes_cb (void *cls,
8890 const struct GNUNET_PeerIdentity *pid,
8893 struct DistanceVector *dv = value;
8904 * Free ephemeral entry.
8908 * @param value a `struct EphemeralCacheEntry`
8909 * @return #GNUNET_OK (always)
8912 free_ephemeral_cb (void *cls,
8913 const struct GNUNET_PeerIdentity *pid,
8916 struct EphemeralCacheEntry *ece = value;
8920 free_ephemeral (ece);
8926 * Free validation state.
8930 * @param value a `struct ValidationState`
8931 * @return #GNUNET_OK (always)
8934 free_validation_state_cb (void *cls,
8935 const struct GNUNET_PeerIdentity *pid,
8938 struct ValidationState *vs = value;
8942 free_validation_state (vs);
8948 * Free pending acknowledgement.
8952 * @param value a `struct PendingAcknowledgement`
8953 * @return #GNUNET_OK (always)
8956 free_pending_ack_cb (void *cls,
8957 const struct GNUNET_ShortHashCode *key,
8960 struct PendingAcknowledgement *pa = value;
8964 free_pending_acknowledgement (pa);
8970 * Free acknowledgement cummulator.
8974 * @param value a `struct AcknowledgementCummulator`
8975 * @return #GNUNET_OK (always)
8978 free_ack_cummulator_cb (void *cls,
8979 const struct GNUNET_PeerIdentity *pid,
8982 struct AcknowledgementCummulator *ac = value;
8992 * Function called when the service shuts down. Unloads our plugins
8993 * and cancels pending validations.
8995 * @param cls closure, unused
8998 do_shutdown (void *cls)
9000 struct LearnLaunchEntry *lle;
9003 if (NULL != ephemeral_task)
9005 GNUNET_SCHEDULER_cancel (ephemeral_task);
9006 ephemeral_task = NULL;
9008 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &free_neighbour_cb, NULL);
9009 if (NULL != peerstore)
9011 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
9014 if (NULL != GST_stats)
9016 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
9019 if (NULL != GST_my_private_key)
9021 GNUNET_free (GST_my_private_key);
9022 GST_my_private_key = NULL;
9024 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
9025 &free_ack_cummulator_cb,
9027 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
9028 ack_cummulators = NULL;
9029 GNUNET_CONTAINER_multishortmap_iterate (pending_acks,
9030 &free_pending_ack_cb,
9032 GNUNET_CONTAINER_multishortmap_destroy (pending_acks);
9033 pending_acks = NULL;
9034 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
9035 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
9037 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
9038 GNUNET_CONTAINER_multipeermap_destroy (links);
9040 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
9041 &free_backtalker_cb,
9043 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
9045 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
9046 &free_validation_state_cb,
9048 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9049 validation_map = NULL;
9050 while (NULL != (lle = lle_head))
9052 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9055 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
9057 GNUNET_CONTAINER_heap_destroy (validation_heap);
9058 validation_heap = NULL;
9059 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
9060 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
9062 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
9065 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
9066 ephemeral_map = NULL;
9067 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
9068 ephemeral_heap = NULL;
9073 * Initiate transport service.
9075 * @param cls closure
9076 * @param c configuration to use
9077 * @param service the initialized service
9081 const struct GNUNET_CONFIGURATION_Handle *c,
9082 struct GNUNET_SERVICE_Handle *service)
9087 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
9089 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9090 pending_acks = GNUNET_CONTAINER_multishortmap_create (32768, GNUNET_YES);
9091 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
9092 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9093 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
9094 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9095 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
9097 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
9098 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
9100 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
9102 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
9103 GST_my_private_key =
9104 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
9105 if (NULL == GST_my_private_key)
9108 GNUNET_ERROR_TYPE_ERROR,
9110 "Transport service is lacking key configuration settings. Exiting.\n"));
9111 GNUNET_SCHEDULER_shutdown ();
9114 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
9115 &GST_my_identity.public_key);
9116 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9117 "My identity is `%s'\n",
9118 GNUNET_i2s_full (&GST_my_identity));
9119 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
9120 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
9121 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
9122 if (NULL == peerstore)
9125 GNUNET_SCHEDULER_shutdown ();
9132 * Define "main" method using service macro.
9134 GNUNET_SERVICE_MAIN (
9136 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
9139 &client_disconnect_cb,
9141 /* communication with applications */
9142 GNUNET_MQ_hd_fixed_size (suggest,
9143 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
9144 struct ExpressPreferenceMessage,
9146 GNUNET_MQ_hd_fixed_size (suggest_cancel,
9147 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
9148 struct ExpressPreferenceMessage,
9150 GNUNET_MQ_hd_var_size (request_hello_validation,
9151 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
9152 struct RequestHelloValidationMessage,
9154 /* communication with core */
9155 GNUNET_MQ_hd_fixed_size (client_start,
9156 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
9157 struct StartMessage,
9159 GNUNET_MQ_hd_var_size (client_send,
9160 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
9161 struct OutboundMessage,
9163 GNUNET_MQ_hd_fixed_size (client_recv_ok,
9164 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
9165 struct RecvOkMessage,
9167 /* communication with communicators */
9168 GNUNET_MQ_hd_var_size (communicator_available,
9169 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
9170 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
9172 GNUNET_MQ_hd_var_size (communicator_backchannel,
9173 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
9174 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
9176 GNUNET_MQ_hd_var_size (add_address,
9177 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
9178 struct GNUNET_TRANSPORT_AddAddressMessage,
9180 GNUNET_MQ_hd_fixed_size (del_address,
9181 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
9182 struct GNUNET_TRANSPORT_DelAddressMessage,
9184 GNUNET_MQ_hd_var_size (incoming_msg,
9185 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
9186 struct GNUNET_TRANSPORT_IncomingMessage,
9188 GNUNET_MQ_hd_fixed_size (queue_create_ok,
9189 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
9190 struct GNUNET_TRANSPORT_CreateQueueResponse,
9192 GNUNET_MQ_hd_fixed_size (queue_create_fail,
9193 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
9194 struct GNUNET_TRANSPORT_CreateQueueResponse,
9196 GNUNET_MQ_hd_var_size (add_queue_message,
9197 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
9198 struct GNUNET_TRANSPORT_AddQueueMessage,
9200 GNUNET_MQ_hd_var_size (address_consider_verify,
9201 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
9202 struct GNUNET_TRANSPORT_AddressToVerify,
9204 GNUNET_MQ_hd_fixed_size (del_queue_message,
9205 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
9206 struct GNUNET_TRANSPORT_DelQueueMessage,
9208 GNUNET_MQ_hd_fixed_size (send_message_ack,
9209 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
9210 struct GNUNET_TRANSPORT_SendMessageToAck,
9212 /* communication with monitors */
9213 GNUNET_MQ_hd_fixed_size (monitor_start,
9214 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
9215 struct GNUNET_TRANSPORT_MonitorStart,
9217 GNUNET_MQ_handler_end ());
9220 /* end of file gnunet-service-transport.c */