2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
26 * - figure out how to transmit (selective) ACKs in case of uni-directional
27 * communicators (with/without core? DV-only?) When do we use ACKs?
28 * => communicators use selective ACKs for flow control
29 * => transport uses message-level ACKs for RTT, fragment confirmation
30 * => integrate DV into transport, use neither core nor communicators
31 * but rather give communicators transport-encapsulated messages
32 * (which could be core-data, background-channel traffic, or
33 * transport-to-transport traffic)
36 * - backchannel message encryption & decryption
37 * - DV data structures:
39 * - handling of DV-boxed messages that need to be forwarded
40 * - route_message implementation, including using DV data structures
41 * (but not when routing certain message types, like DV learn,
42 * MUST pay attention to content here -- or pass extra flags?)
44 * - track RTT, distance, loss, etc. => requires extra data structures!
47 * - change transport-core API to provide proper flow control in both
48 * directions, allow multiple messages per peer simultaneously (tag
49 * confirmations with unique message ID), and replace quota-out with
50 * proper flow control;
51 * - if messages are below MTU, consider adding ACKs and other stuff
52 * (requires planning at receiver, and additional MST-style demultiplex
54 * - could avoid copying body of message into each fragment and keep
55 * fragments as just pointers into the original message and only
56 * fully build fragments just before transmission (optimization, should
57 * reduce CPU and memory use)
60 * - use shorthashmap on msg_uuid's when matching reliability/fragment ACKs
61 * against our pending message queue (requires additional per neighbour
62 * hash map to be maintained, avoids possible linear scan on pending msgs)
64 * Design realizations / discussion:
65 * - communicators do flow control by calling MQ "notify sent"
66 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
67 * or explicitly via backchannel FC ACKs. As long as the
68 * channel is not full, they may 'notify sent' even if the other
69 * peer has not yet confirmed receipt. The other peer confirming
70 * is _only_ for FC, not for more reliable transmission; reliable
71 * transmission (i.e. of fragments) is left to _transport_.
72 * - ACKs sent back in uni-directional communicators are done via
73 * the background channel API; here transport _may_ initially
74 * broadcast (with bounded # hops) if no path is known;
75 * - transport should _integrate_ DV-routing and build a view of
76 * the network; then background channel traffic can be
77 * routed via DV as well as explicit "DV" traffic.
78 * - background channel is also used for ACKs and NAT traversal support
79 * - transport service is responsible for AEAD'ing the background
80 * channel, timestamps and monotonic time are used against replay
81 * of old messages -> peerstore needs to be supplied with
82 * "latest timestamps seen" data
83 * - if transport implements DV, we likely need a 3rd peermap
84 * in addition to ephemerals and (direct) neighbours
85 * ==> check if stuff needs to be moved out of "Neighbour"
86 * - transport should encapsualte core-level messages and do its
87 * own ACKing for RTT/goodput/loss measurements _and_ fragment
91 #include "gnunet_util_lib.h"
92 #include "gnunet_statistics_service.h"
93 #include "gnunet_transport_monitor_service.h"
94 #include "gnunet_peerstore_service.h"
95 #include "gnunet_hello_lib.h"
96 #include "gnunet_signatures.h"
97 #include "transport.h"
101 * What is the size we assume for a read operation in the
102 * absence of an MTU for the purpose of flow control?
104 #define IN_PACKET_SIZE_WITHOUT_MTU 128
107 * Minimum number of hops we should forward DV learn messages
108 * even if they are NOT useful for us in hope of looping
109 * back to the initiator?
111 * FIXME: allow initiator some control here instead?
113 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
116 * Maximum DV distance allowed ever.
118 #define MAX_DV_HOPS_ALLOWED 16
121 * Maximum number of DV learning activities we may
122 * have pending at the same time.
124 #define MAX_DV_LEARN_PENDING 64
127 * Maximum number of DV paths we keep simultaneously to the same target.
129 #define MAX_DV_PATHS_TO_TARGET 3
132 * If a queue delays the next message by more than this number
133 * of seconds we log a warning. Note: this is for testing,
134 * the value chosen here might be too aggressively low!
136 #define DELAY_WARN_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
139 * We only consider queues as "quality" connections when
140 * suppressing the generation of DV initiation messages if
141 * the latency of the queue is below this threshold.
143 #define DV_QUALITY_RTT_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
146 * How long do we consider a DV path valid if we see no
147 * further updates on it? Note: the value chosen here might be too low!
149 #define DV_PATH_VALIDITY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
152 * How long before paths expire would we like to (re)discover DV paths? Should
153 * be below #DV_PATH_VALIDITY_TIMEOUT.
155 #define DV_PATH_DISCOVERY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
158 * How long are ephemeral keys valid?
160 #define EPHEMERAL_VALIDITY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
163 * How long do we keep partially reassembled messages around before giving up?
165 #define REASSEMBLY_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
168 * What is the fastest rate at which we send challenges *if* we keep learning
169 * an address (gossip, DHT, etc.)?
171 #define FAST_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
174 * What is the slowest rate at which we send challenges?
176 #define MAX_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
179 * What is the non-randomized base frequency at which we
180 * would initiate DV learn messages?
182 #define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
185 * How many good connections (confirmed, bi-directional, not DV)
186 * do we need to have to suppress initiating DV learn messages?
188 #define DV_LEARN_QUALITY_THRESHOLD 100
191 * When do we forget an invalid address for sure?
193 #define MAX_ADDRESS_VALID_UNTIL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
195 * How long do we consider an address valid if we just checked?
197 #define ADDRESS_VALIDATION_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
200 * What is the maximum frequency at which we do address validation?
201 * A random value between 0 and this value is added when scheduling
202 * the #validation_task (both to ensure we do not validate too often,
203 * and to randomize a bit).
205 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
208 * How many network RTTs before an address validation expires should we begin
209 * trying to revalidate? (Note that the RTT used here is the one that we
210 * experienced during the last validation, not necessarily the latest RTT
213 #define VALIDATION_RTT_BUFFER_FACTOR 3
216 * How many messages can we have pending for a given communicator
217 * process before we start to throttle that communicator?
219 * Used if a communicator might be CPU-bound and cannot handle the traffic.
221 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
224 * How many messages can we have pending for a given queue (queue to
225 * a particular peer via a communicator) process before we start to
226 * throttle that queue?
228 #define QUEUE_LENGTH_LIMIT 32
231 GNUNET_NETWORK_STRUCT_BEGIN
234 * Outer layer of an encapsulated backchannel message.
236 struct TransportBackchannelEncapsulationMessage
239 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
241 struct GNUNET_MessageHeader header;
244 * Distance the backchannel message has traveled, to be updated at
245 * each hop. Used to bound the number of hops in case a backchannel
246 * message is broadcast and thus travels without routing
247 * information (during initial backchannel discovery).
252 * Target's peer identity (as backchannels may be transmitted
253 * indirectly, or even be broadcast).
255 struct GNUNET_PeerIdentity target;
258 * Ephemeral key setup by the sender for @e target, used
259 * to encrypt the payload.
261 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
263 // FIXME: probably should add random IV here as well,
264 // especially if we re-use ephemeral keys!
267 * HMAC over the ciphertext of the encrypted, variable-size
268 * body that follows. Verified via DH of @e target and
271 struct GNUNET_HashCode hmac;
273 /* Followed by encrypted, variable-size payload */
278 * Body by which a peer confirms that it is using an ephemeral key.
280 struct EphemeralConfirmation
284 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
286 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
289 * How long is this signature over the ephemeral key valid?
290 * Note that the receiver MUST IGNORE the absolute time, and
291 * only interpret the value as a mononic time and reject
292 * "older" values than the last one observed. Even with this,
293 * there is no real guarantee against replay achieved here,
294 * as the latest timestamp is not persisted. This is
295 * necessary as we do not want to require synchronized
296 * clocks and may not have a bidirectional communication
297 * channel. Communicators must protect against replay
298 * attacks when using backchannel communication!
300 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
303 * Target's peer identity.
305 struct GNUNET_PeerIdentity target;
308 * Ephemeral key setup by the sender for @e target, used
309 * to encrypt the payload.
311 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
317 * Plaintext of the variable-size payload that is encrypted
318 * within a `struct TransportBackchannelEncapsulationMessage`
320 struct TransportBackchannelRequestPayload
324 * Sender's peer identity.
326 struct GNUNET_PeerIdentity sender;
329 * Signature of the sender over an
330 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
332 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
335 * How long is this signature over the ephemeral key
338 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
341 * Current monotonic time of the sending transport service. Used to
342 * detect replayed messages. Note that the receiver should remember
343 * a list of the recently seen timestamps and only reject messages
344 * if the timestamp is in the list, or the list is "full" and the
345 * timestamp is smaller than the lowest in the list. This list of
346 * timestamps per peer should be persisted to guard against replays
349 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
351 /* Followed by a `struct GNUNET_MessageHeader` with a message
352 for a communicator */
354 /* Followed by a 0-termianted string specifying the name of
355 the communicator which is to receive the message */
361 * Outer layer of an encapsulated unfragmented application message sent
362 * over an unreliable channel.
364 struct TransportReliabilityBox
367 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
369 struct GNUNET_MessageHeader header;
372 * Number of messages still to be sent before a commulative
373 * ACK is requested. Zero if an ACK is requested immediately.
374 * In NBO. Note that the receiver may send the ACK faster
375 * if it believes that is reasonable.
377 uint32_t ack_countdown GNUNET_PACKED;
380 * Unique ID of the message used for signalling receipt of
381 * messages sent over possibly unreliable channels. Should
384 struct GNUNET_ShortHashCode msg_uuid;
389 * Confirmation that the receiver got a
390 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
391 * confirmation may be transmitted over a completely different queue,
392 * so ACKs are identified by a combination of PID of sender and
393 * message UUID, without the queue playing any role!
395 struct TransportReliabilityAckMessage
398 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
400 struct GNUNET_MessageHeader header;
405 uint32_t reserved GNUNET_PACKED;
408 * How long was the ACK delayed relative to the average time of
409 * receipt of the messages being acknowledged? Used to calculate
410 * the average RTT by taking the receipt time of the ack minus the
411 * average transmission time of the sender minus this value.
413 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
415 /* followed by any number of `struct GNUNET_ShortHashCode`
416 messages providing ACKs */
421 * Outer layer of an encapsulated fragmented application message.
423 struct TransportFragmentBox
426 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
428 struct GNUNET_MessageHeader header;
431 * Unique ID of this fragment (and fragment transmission!). Will
432 * change even if a fragement is retransmitted to make each
433 * transmission attempt unique! Should be incremented by one for
434 * each fragment transmission. If a client receives a duplicate
435 * fragment (same @e frag_off), it must send
436 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
438 uint32_t frag_uuid GNUNET_PACKED;
441 * Original message ID for of the message that all the1
442 * fragments belong to. Must be the same for all fragments.
444 struct GNUNET_ShortHashCode msg_uuid;
447 * Offset of this fragment in the overall message.
449 uint16_t frag_off GNUNET_PACKED;
452 * Total size of the message that is being fragmented.
454 uint16_t msg_size GNUNET_PACKED;
460 * Outer layer of an fragmented application message sent over a queue
461 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
462 * received, the receiver has two RTTs or 64 further fragments with
463 * the same basic message time to send an acknowledgement, possibly
464 * acknowledging up to 65 fragments in one ACK. ACKs must also be
465 * sent immediately once all fragments were sent.
467 struct TransportFragmentAckMessage
470 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
472 struct GNUNET_MessageHeader header;
475 * Unique ID of the lowest fragment UUID being acknowledged.
477 uint32_t frag_uuid GNUNET_PACKED;
480 * Bitfield of up to 64 additional fragments following the
481 * @e msg_uuid being acknowledged by this message.
483 uint64_t extra_acks GNUNET_PACKED;
486 * Original message ID for of the message that all the
487 * fragments belong to.
489 struct GNUNET_ShortHashCode msg_uuid;
492 * How long was the ACK delayed relative to the average time of
493 * receipt of the fragments being acknowledged? Used to calculate
494 * the average RTT by taking the receipt time of the ack minus the
495 * average transmission time of the sender minus this value.
497 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
500 * How long until the receiver will stop trying reassembly
503 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
508 * Content signed by each peer during DV learning.
513 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
515 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
518 * Challenge value used by the initiator to re-identify the path.
520 struct GNUNET_ShortHashCode challenge;
526 * Content signed by each peer during DV learning.
531 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
533 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
536 * Identity of the previous peer on the path.
538 struct GNUNET_PeerIdentity pred;
541 * Identity of the next peer on the path.
543 struct GNUNET_PeerIdentity succ;
546 * Challenge value used by the initiator to re-identify the path.
548 struct GNUNET_ShortHashCode challenge;
554 * An entry describing a peer on a path in a
555 * `struct TransportDVLearn` message.
560 * Identity of a peer on the path.
562 struct GNUNET_PeerIdentity hop;
565 * Signature of this hop over the path, of purpose
566 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
568 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
574 * Internal message used by transport for distance vector learning.
575 * If @e num_hops does not exceed the threshold, peers should append
576 * themselves to the peer list and flood the message (possibly only
577 * to a subset of their neighbours to limit discoverability of the
578 * network topology). To the extend that the @e bidirectional bits
579 * are set, peers may learn the inverse paths even if they did not
582 * Unless received on a bidirectional queue and @e num_hops just
583 * zero, peers that can forward to the initator should always try to
584 * forward to the initiator.
586 struct TransportDVLearn
589 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
591 struct GNUNET_MessageHeader header;
594 * Number of hops this messages has travelled, in NBO. Zero if
597 uint16_t num_hops GNUNET_PACKED;
600 * Bitmask of the last 16 hops indicating whether they are confirmed
601 * available (without DV) in both directions or not, in NBO. Used
602 * to possibly instantly learn a path in both directions. Each peer
603 * should shift this value by one to the left, and then set the
604 * lowest bit IF the current sender can be reached from it (without
607 uint16_t bidirectional GNUNET_PACKED;
610 * Peers receiving this message and delaying forwarding to other
611 * peers for any reason should increment this value by the non-network
612 * delay created by the peer.
614 struct GNUNET_TIME_RelativeNBO non_network_delay;
617 * Signature of this hop over the path, of purpose
618 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
620 struct GNUNET_CRYPTO_EddsaSignature init_sig;
623 * Identity of the peer that started this learning activity.
625 struct GNUNET_PeerIdentity initiator;
628 * Challenge value used by the initiator to re-identify the path.
630 struct GNUNET_ShortHashCode challenge;
632 /* Followed by @e num_hops `struct DVPathEntryP` values,
633 excluding the initiator of the DV trace; the last entry is the
634 current sender; the current peer must not be included. */
640 * Outer layer of an encapsulated message send over multiple hops.
641 * The path given only includes the identities of the subsequent
642 * peers, i.e. it will be empty if we are the receiver. Each
643 * forwarding peer should scan the list from the end, and if it can,
644 * forward to the respective peer. The list should then be shortened
645 * by all the entries up to and including that peer. Each hop should
646 * also increment @e total_hops to allow the receiver to get a precise
647 * estimate on the number of hops the message travelled. Senders must
648 * provide a learned path that thus should work, but intermediaries
649 * know of a shortcut, they are allowed to send the message via that
652 * If a peer finds itself still on the list, it must drop the message.
654 struct TransportDVBox
657 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
659 struct GNUNET_MessageHeader header;
662 * Number of total hops this messages travelled. In NBO.
663 * @e origin sets this to zero, to be incremented at
666 uint16_t total_hops GNUNET_PACKED;
669 * Number of hops this messages includes. In NBO.
671 uint16_t num_hops GNUNET_PACKED;
674 * Identity of the peer that originated the message.
676 struct GNUNET_PeerIdentity origin;
678 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
679 excluding the @e origin and the current peer, the last must be
680 the ultimate target; if @e num_hops is zero, the receiver of this
681 message is the ultimate target. */
683 /* Followed by the actual message, which itself may be
684 another box, but not a DV_LEARN or DV_BOX message! */
689 * Message send to another peer to validate that it can indeed
690 * receive messages at a particular address.
692 struct TransportValidationChallenge
696 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
698 struct GNUNET_MessageHeader header;
703 uint32_t reserved GNUNET_PACKED;
706 * Challenge to be signed by the receiving peer.
708 struct GNUNET_ShortHashCode challenge;
711 * Timestamp of the sender, to be copied into the reply
712 * to allow sender to calculate RTT.
714 struct GNUNET_TIME_AbsoluteNBO sender_time;
719 * Message signed by a peer to confirm that it can indeed
720 * receive messages at a particular address.
722 struct TransportValidationPS
726 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
728 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
731 * How long does the sender believe the address on
732 * which the challenge was received to remain valid?
734 struct GNUNET_TIME_RelativeNBO validity_duration;
737 * Challenge signed by the receiving peer.
739 struct GNUNET_ShortHashCode challenge;
745 * Message send to a peer to respond to a
746 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
748 struct TransportValidationResponse
752 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
754 struct GNUNET_MessageHeader header;
759 uint32_t reserved GNUNET_PACKED;
762 * The peer's signature matching the
763 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
765 struct GNUNET_CRYPTO_EddsaSignature signature;
768 * The challenge that was signed by the receiving peer.
770 struct GNUNET_ShortHashCode challenge;
773 * Original timestamp of the sender (was @code{sender_time}),
774 * copied into the reply to allow sender to calculate RTT.
776 struct GNUNET_TIME_AbsoluteNBO origin_time;
779 * How long does the sender believe this address to remain
782 struct GNUNET_TIME_RelativeNBO validity_duration;
787 GNUNET_NETWORK_STRUCT_END
791 * What type of client is the `struct TransportClient` about?
796 * We do not know yet (client is fresh).
801 * Is the CORE service, we need to forward traffic to it.
806 * It is a monitor, forward monitor data.
811 * It is a communicator, use for communication.
816 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
823 * When did we launch this DV learning activity?
825 struct LearnLaunchEntry
829 * Kept (also) in a DLL sorted by launch time.
831 struct LearnLaunchEntry *prev;
834 * Kept (also) in a DLL sorted by launch time.
836 struct LearnLaunchEntry *next;
839 * Challenge that uniquely identifies this activity.
841 struct GNUNET_ShortHashCode challenge;
844 * When did we transmit the DV learn message (used to
847 struct GNUNET_TIME_Absolute launch_time;
853 * Entry in our cache of ephemeral keys we currently use.
854 * This way, we only sign an ephemeral once per @e target,
855 * and then can re-use it over multiple
856 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION
857 * messages (as signing is expensive).
859 struct EphemeralCacheEntry
863 * Target's peer identity (we don't re-use ephemerals
864 * to limit linkability of messages).
866 struct GNUNET_PeerIdentity target;
869 * Signature affirming @e ephemeral_key of type
870 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
872 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
875 * How long is @e sender_sig valid
877 struct GNUNET_TIME_Absolute ephemeral_validity;
882 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
885 * Our private ephemeral key.
887 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
890 * Node in the ephemeral cache for this entry.
891 * Used for expiration.
893 struct GNUNET_CONTAINER_HeapNode *hn;
898 * Client connected to the transport service.
900 struct TransportClient;
904 * A neighbour that at least one communicator is connected to.
910 * Entry in our #dv_routes table, representing a (set of) distance
911 * vector routes to a particular peer.
913 struct DistanceVector;
916 * One possible hop towards a DV target.
918 struct DistanceVectorHop
922 * Kept in a MDLL, sorted by @e timeout.
924 struct DistanceVectorHop *next_dv;
927 * Kept in a MDLL, sorted by @e timeout.
929 struct DistanceVectorHop *prev_dv;
934 struct DistanceVectorHop *next_neighbour;
939 struct DistanceVectorHop *prev_neighbour;
942 * What would be the next hop to @e target?
944 struct Neighbour *next_hop;
947 * Distance vector entry this hop belongs with.
949 struct DistanceVector *dv;
952 * Array of @e distance hops to the target, excluding @e next_hop.
953 * NULL if the entire path is us to @e next_hop to `target`. Allocated
954 * at the end of this struct.
956 const struct GNUNET_PeerIdentity *path;
959 * At what time do we forget about this path unless we see it again
962 struct GNUNET_TIME_Absolute timeout;
965 * How many hops in total to the `target` (excluding @e next_hop and `target` itself),
966 * thus 0 still means a distance of 2 hops (to @e next_hop and then to `target`)?
968 unsigned int distance;
973 * Entry in our #dv_routes table, representing a (set of) distance
974 * vector routes to a particular peer.
976 struct DistanceVector
980 * To which peer is this a route?
982 struct GNUNET_PeerIdentity target;
985 * Known paths to @e target.
987 struct DistanceVectorHop *dv_head;
990 * Known paths to @e target.
992 struct DistanceVectorHop *dv_tail;
995 * Task scheduled to purge expired paths from @e dv_head MDLL.
997 struct GNUNET_SCHEDULER_Task *timeout_task;
1002 * A queue is a message queue provided by a communicator
1003 * via which we can reach a particular neighbour.
1009 * Entry identifying transmission in one of our `struct
1010 * Queue` which still awaits an ACK. This is used to
1011 * ensure we do not overwhelm a communicator and limit the number of
1012 * messages outstanding per communicator (say in case communicator is
1013 * CPU bound) and per queue (in case bandwidth allocation exceeds
1014 * what the communicator can actually provide towards a particular
1023 struct QueueEntry *next;
1028 struct QueueEntry *prev;
1031 * Queue this entry is queued with.
1033 struct Queue *queue;
1036 * Message ID used for this message with the queue used for transmission.
1043 * A queue is a message queue provided by a communicator
1044 * via which we can reach a particular neighbour.
1051 struct Queue *next_neighbour;
1056 struct Queue *prev_neighbour;
1061 struct Queue *prev_client;
1066 struct Queue *next_client;
1069 * Head of DLL of unacked transmission requests.
1071 struct QueueEntry *queue_head;
1074 * End of DLL of unacked transmission requests.
1076 struct QueueEntry *queue_tail;
1079 * Which neighbour is this queue for?
1081 struct Neighbour *neighbour;
1084 * Which communicator offers this queue?
1086 struct TransportClient *tc;
1089 * Address served by the queue.
1091 const char *address;
1094 * Task scheduled for the time when this queue can (likely) transmit the
1095 * next message. Still needs to check with the @e tracker_out to be sure.
1097 struct GNUNET_SCHEDULER_Task *transmit_task;
1100 * Our current RTT estimate for this queue.
1102 struct GNUNET_TIME_Relative rtt;
1105 * Message ID generator for transmissions on this queue.
1110 * Unique identifier of this queue with the communicator.
1115 * Maximum transmission unit supported by this queue.
1120 * Distance to the target of this queue.
1121 * FIXME: needed? DV is done differently these days...
1128 uint32_t num_msg_pending;
1133 uint32_t num_bytes_pending;
1136 * Length of the DLL starting at @e queue_head.
1138 unsigned int queue_length;
1141 * Network type offered by this queue.
1143 enum GNUNET_NetworkType nt;
1146 * Connection status for this queue.
1148 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1151 * How much outbound bandwidth do we have available for this queue?
1153 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1156 * How much inbound bandwidth do we have available for this queue?
1158 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1163 * Information we keep for a message that we are reassembling.
1165 struct ReassemblyContext
1169 * Original message ID for of the message that all the
1170 * fragments belong to.
1172 struct GNUNET_ShortHashCode msg_uuid;
1175 * Which neighbour is this context for?
1177 struct Neighbour *neighbour;
1180 * Entry in the reassembly heap (sorted by expiration).
1182 struct GNUNET_CONTAINER_HeapNode *hn;
1185 * Bitfield with @e msg_size bits representing the positions
1186 * where we have received fragments. When we receive a fragment,
1187 * we check the bits in @e bitfield before incrementing @e msg_missing.
1189 * Allocated after the reassembled message.
1194 * Task for sending ACK. We may send ACKs either because of hitting
1195 * the @e extra_acks limit, or based on time and @e num_acks. This
1196 * task is for the latter case.
1198 struct GNUNET_SCHEDULER_Task *ack_task;
1201 * At what time will we give up reassembly of this message?
1203 struct GNUNET_TIME_Absolute reassembly_timeout;
1206 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1207 * Should be reset to zero when @e num_acks is set to 0.
1209 struct GNUNET_TIME_Relative avg_ack_delay;
1212 * Time we received the last fragment. @e avg_ack_delay must be
1213 * incremented by now - @e last_frag multiplied by @e num_acks.
1215 struct GNUNET_TIME_Absolute last_frag;
1218 * Bitfield of up to 64 additional fragments following @e frag_uuid
1219 * to be acknowledged in the next cummulative ACK.
1221 uint64_t extra_acks;
1224 * Unique ID of the lowest fragment UUID to be acknowledged in the
1225 * next cummulative ACK. Only valid if @e num_acks > 0.
1230 * Number of ACKs we have accumulated so far. Reset to 0
1231 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1233 unsigned int num_acks;
1236 * How big is the message we are reassembling in total?
1241 * How many bytes of the message are still missing? Defragmentation
1242 * is complete when @e msg_missing == 0.
1244 uint16_t msg_missing;
1246 /* Followed by @e msg_size bytes of the (partially) defragmented original message */
1248 /* Followed by @e bitfield data */
1253 * A neighbour that at least one communicator is connected to.
1259 * Which peer is this about?
1261 struct GNUNET_PeerIdentity pid;
1264 * Map with `struct ReassemblyContext` structs for fragments under
1265 * reassembly. May be NULL if we currently have no fragments from
1266 * this @e pid (lazy initialization).
1268 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1271 * Heap with `struct ReassemblyContext` structs for fragments under
1272 * reassembly. May be NULL if we currently have no fragments from
1273 * this @e pid (lazy initialization).
1275 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1278 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1280 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1283 * Head of list of messages pending for this neighbour.
1285 struct PendingMessage *pending_msg_head;
1288 * Tail of list of messages pending for this neighbour.
1290 struct PendingMessage *pending_msg_tail;
1293 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1294 * purged if this neighbour goes down.
1296 struct DistanceVectorHop *dv_head;
1299 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1300 * purged if this neighbour goes down.
1302 struct DistanceVectorHop *dv_tail;
1305 * Head of DLL of queues to this peer.
1307 struct Queue *queue_head;
1310 * Tail of DLL of queues to this peer.
1312 struct Queue *queue_tail;
1315 * Task run to cleanup pending messages that have exceeded their timeout.
1317 struct GNUNET_SCHEDULER_Task *timeout_task;
1320 * Quota at which CORE is allowed to transmit to this peer.
1322 * FIXME: not yet used, tricky to get right given multiple queues!
1323 * (=> Idea: measure???)
1324 * FIXME: how do we set this value initially when we tell CORE?
1325 * Options: start at a minimum value or at literally zero?
1326 * (=> Current thought: clean would be zero!)
1328 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1331 * What is the earliest timeout of any message in @e pending_msg_tail?
1333 struct GNUNET_TIME_Absolute earliest_timeout;
1339 * A peer that an application (client) would like us to talk to directly.
1345 * Which peer is this about?
1347 struct GNUNET_PeerIdentity pid;
1350 * Client responsible for the request.
1352 struct TransportClient *tc;
1355 * Handle for watching the peerstore for HELLOs for this peer.
1357 struct GNUNET_PEERSTORE_WatchContext *wc;
1360 * What kind of performance preference does this @e tc have?
1362 enum GNUNET_MQ_PreferenceKind pk;
1365 * How much bandwidth would this @e tc like to see?
1367 struct GNUNET_BANDWIDTH_Value32NBO bw;
1373 * Types of different pending messages.
1375 enum PendingMessageType
1379 * Ordinary message received from the CORE service.
1386 PMT_FRAGMENT_BOX = 1,
1391 PMT_RELIABILITY_BOX = 2,
1394 * Any type of acknowledgement.
1396 PMT_ACKNOWLEDGEMENT = 3
1402 * Transmission request that is awaiting delivery. The original
1403 * transmission requests from CORE may be too big for some queues.
1404 * In this case, a *tree* of fragments is created. At each
1405 * level of the tree, fragments are kept in a DLL ordered by which
1406 * fragment should be sent next (at the head). The tree is searched
1407 * top-down, with the original message at the root.
1409 * To select a node for transmission, first it is checked if the
1410 * current node's message fits with the MTU. If it does not, we
1411 * either calculate the next fragment (based on @e frag_off) from the
1412 * current node, or, if all fragments have already been created,
1413 * descend to the @e head_frag. Even though the node was already
1414 * fragmented, the fragment may be too big if the fragment was
1415 * generated for a queue with a larger MTU. In this case, the node
1416 * may be fragmented again, thus creating a tree.
1418 * When acknowledgements for fragments are received, the tree
1419 * must be pruned, removing those parts that were already
1420 * acknowledged. When fragments are sent over a reliable
1421 * channel, they can be immediately removed.
1423 * If a message is ever fragmented, then the original "full" message
1424 * is never again transmitted (even if it fits below the MTU), and
1425 * only (remaining) fragments are sent.
1427 struct PendingMessage
1430 * Kept in a MDLL of messages for this @a target.
1432 struct PendingMessage *next_neighbour;
1435 * Kept in a MDLL of messages for this @a target.
1437 struct PendingMessage *prev_neighbour;
1440 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1442 struct PendingMessage *next_client;
1445 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1447 struct PendingMessage *prev_client;
1450 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOx)
1452 struct PendingMessage *next_frag;
1455 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOX)
1457 struct PendingMessage *prev_frag;
1460 * This message, reliability boxed. Only possibly available if @e pmt is #PMT_CORE.
1462 struct PendingMessage *bpm;
1465 * Target of the request.
1467 struct Neighbour *target;
1470 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1472 struct TransportClient *client;
1475 * Head of a MDLL of fragments created for this core message.
1477 struct PendingMessage *head_frag;
1480 * Tail of a MDLL of fragments created for this core message.
1482 struct PendingMessage *tail_frag;
1485 * Our parent in the fragmentation tree.
1487 struct PendingMessage *frag_parent;
1490 * At what time should we give up on the transmission (and no longer retry)?
1492 struct GNUNET_TIME_Absolute timeout;
1495 * What is the earliest time for us to retry transmission of this message?
1497 struct GNUNET_TIME_Absolute next_attempt;
1500 * UUID to use for this message (used for reassembly of fragments, only
1501 * initialized if @e msg_uuid_set is #GNUNET_YES).
1503 struct GNUNET_ShortHashCode msg_uuid;
1506 * Counter incremented per generated fragment.
1508 uint32_t frag_uuidgen;
1511 * Type of the pending message.
1513 enum PendingMessageType pmt;
1516 * Size of the original message.
1521 * Offset at which we should generate the next fragment.
1526 * #GNUNET_YES once @e msg_uuid was initialized
1528 int16_t msg_uuid_set;
1530 /* Followed by @e bytes_msg to transmit */
1535 * One of the addresses of this peer.
1537 struct AddressListEntry
1543 struct AddressListEntry *next;
1548 struct AddressListEntry *prev;
1551 * Which communicator provides this address?
1553 struct TransportClient *tc;
1556 * The actual address.
1558 const char *address;
1561 * Current context for storing this address in the peerstore.
1563 struct GNUNET_PEERSTORE_StoreContext *sc;
1566 * Task to periodically do @e st operation.
1568 struct GNUNET_SCHEDULER_Task *st;
1571 * What is a typical lifetime the communicator expects this
1572 * address to have? (Always from now.)
1574 struct GNUNET_TIME_Relative expiration;
1577 * Address identifier used by the communicator.
1582 * Network type offered by this address.
1584 enum GNUNET_NetworkType nt;
1590 * Client connected to the transport service.
1592 struct TransportClient
1598 struct TransportClient *next;
1603 struct TransportClient *prev;
1606 * Handle to the client.
1608 struct GNUNET_SERVICE_Client *client;
1611 * Message queue to the client.
1613 struct GNUNET_MQ_Handle *mq;
1616 * What type of client is this?
1618 enum ClientType type;
1624 * Information for @e type #CT_CORE.
1629 * Head of list of messages pending for this client, sorted by
1630 * transmission time ("next_attempt" + possibly internal prioritization).
1632 struct PendingMessage *pending_msg_head;
1635 * Tail of list of messages pending for this client.
1637 struct PendingMessage *pending_msg_tail;
1642 * Information for @e type #CT_MONITOR.
1647 * Peer identity to monitor the addresses of.
1648 * Zero to monitor all neighbours. Valid if
1649 * @e type is #CT_MONITOR.
1651 struct GNUNET_PeerIdentity peer;
1654 * Is this a one-shot monitor?
1662 * Information for @e type #CT_COMMUNICATOR.
1666 * If @e type is #CT_COMMUNICATOR, this communicator
1667 * supports communicating using these addresses.
1669 char *address_prefix;
1672 * Head of DLL of queues offered by this communicator.
1674 struct Queue *queue_head;
1677 * Tail of DLL of queues offered by this communicator.
1679 struct Queue *queue_tail;
1682 * Head of list of the addresses of this peer offered by this communicator.
1684 struct AddressListEntry *addr_head;
1687 * Tail of list of the addresses of this peer offered by this communicator.
1689 struct AddressListEntry *addr_tail;
1692 * Number of queue entries in all queues to this communicator. Used
1693 * throttle sending to a communicator if we see that the communicator
1694 * is globally unable to keep up.
1696 unsigned int total_queue_length;
1699 * Characteristics of this communicator.
1701 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1706 * Information for @e type #CT_APPLICATION
1711 * Map of requests for peers the given client application would like to
1712 * see connections for. Maps from PIDs to `struct PeerRequest`.
1714 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1724 * State we keep for validation activities. Each of these
1725 * is both in the #validation_heap and the #validation_map.
1727 struct ValidationState
1731 * For which peer is @a address to be validated (or possibly valid)?
1732 * Serves as key in the #validation_map.
1734 struct GNUNET_PeerIdentity pid;
1737 * How long did the peer claim this @e address to be valid? Capped at
1738 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1739 * were told about the address and the value claimed by the other peer at
1740 * that time. May be updated similarly when validation succeeds.
1742 struct GNUNET_TIME_Absolute valid_until;
1745 * How long do *we* consider this @e address to be valid?
1746 * In the past or zero if we have not yet validated it.
1748 struct GNUNET_TIME_Absolute validated_until;
1751 * When did we FIRST use the current @e challenge in a message?
1752 * Used to sanity-check @code{origin_time} in the response when
1753 * calculating the RTT. If the @code{origin_time} is not in
1754 * the expected range, the response is discarded as malicious.
1756 struct GNUNET_TIME_Absolute first_challenge_use;
1759 * When did we LAST use the current @e challenge in a message?
1760 * Used to sanity-check @code{origin_time} in the response when
1761 * calculating the RTT. If the @code{origin_time} is not in
1762 * the expected range, the response is discarded as malicious.
1764 struct GNUNET_TIME_Absolute last_challenge_use;
1767 * Next time we will send the @e challenge to the peer, if this time is past
1768 * @e valid_until, this validation state is released at this time. If the
1769 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1770 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1771 * to re-validate before the validity actually expires.
1773 struct GNUNET_TIME_Absolute next_challenge;
1776 * Current backoff factor we're applying for sending the @a challenge.
1777 * Reset to 0 if the @a challenge is confirmed upon validation.
1778 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1779 * existing value if we receive an unvalidated address again over
1780 * another channel (and thus should consider the information "fresh").
1781 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1783 struct GNUNET_TIME_Relative challenge_backoff;
1786 * Initially set to "forever". Once @e validated_until is set, this value is
1787 * set to the RTT that tells us how long it took to receive the validation.
1789 struct GNUNET_TIME_Relative validation_rtt;
1792 * The challenge we sent to the peer to get it to validate the address. Note
1793 * that we rotate the challenge whenever we update @e validated_until to
1794 * avoid attacks where a peer simply replays an old challenge in the future.
1795 * (We must not rotate more often as otherwise we may discard valid answers
1796 * due to packet losses, latency and reorderings on the network).
1798 struct GNUNET_ShortHashCode challenge;
1801 * Claimed address of the peer.
1806 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1807 * heap is used to figure out when the next validation activity should be
1810 struct GNUNET_CONTAINER_HeapNode *hn;
1813 * Handle to a PEERSTORE store operation for this @e address. NULL if
1814 * no PEERSTORE operation is pending.
1816 struct GNUNET_PEERSTORE_StoreContext *sc;
1819 * We are technically ready to send the challenge, but we are waiting for
1820 * the respective queue to become available for transmission.
1828 * Head of linked list of all clients to this service.
1830 static struct TransportClient *clients_head;
1833 * Tail of linked list of all clients to this service.
1835 static struct TransportClient *clients_tail;
1838 * Statistics handle.
1840 static struct GNUNET_STATISTICS_Handle *GST_stats;
1843 * Configuration handle.
1845 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1850 static struct GNUNET_PeerIdentity GST_my_identity;
1855 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1858 * Map from PIDs to `struct Neighbour` entries. A peer is
1859 * a neighbour if we have an MQ to it from some communicator.
1861 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1864 * Map from PIDs to `struct DistanceVector` entries describing
1865 * known paths to the peer.
1867 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
1870 * Map from PIDs to `struct ValidationState` entries describing
1871 * addresses we are aware of and their validity state.
1873 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
1876 * Map from challenges to `struct LearnLaunchEntry` values.
1878 static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
1881 * Head of a DLL sorted by launch time.
1883 static struct LearnLaunchEntry *lle_head;
1886 * Tail of a DLL sorted by launch time.
1888 static struct LearnLaunchEntry *lle_tail;
1891 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
1892 * sorting addresses we are aware of by when we should next try to (re)validate
1895 static struct GNUNET_CONTAINER_Heap *validation_heap;
1898 * Database for peer's HELLOs.
1900 static struct GNUNET_PEERSTORE_Handle *peerstore;
1903 * Heap sorting `struct EphemeralCacheEntry` by their
1904 * key/signature validity.
1906 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
1909 * Hash map for looking up `struct EphemeralCacheEntry`s
1910 * by peer identity. (We may have ephemerals in our
1911 * cache for which we do not have a neighbour entry,
1912 * and similar many neighbours may not need ephemerals,
1913 * so we use a second map.)
1915 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
1918 * Task to free expired ephemerals.
1920 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
1923 * Task run to initiate DV learning.
1925 static struct GNUNET_SCHEDULER_Task *dvlearn_task;
1928 * Task to run address validation.
1930 static struct GNUNET_SCHEDULER_Task *validation_task;
1934 * Free cached ephemeral key.
1936 * @param ece cached signature to free
1939 free_ephemeral (struct EphemeralCacheEntry *ece)
1941 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map,
1944 GNUNET_CONTAINER_heap_remove_node (ece->hn);
1950 * Free validation state.
1952 * @param vs validation state to free
1955 free_validation_state (struct ValidationState *vs)
1957 GNUNET_CONTAINER_multipeermap_remove (validation_map,
1960 GNUNET_CONTAINER_heap_remove_node (vs->hn);
1964 GNUNET_PEERSTORE_store_cancel (vs->sc);
1967 GNUNET_free (vs->address);
1973 * Lookup neighbour record for peer @a pid.
1975 * @param pid neighbour to look for
1976 * @return NULL if we do not have this peer as a neighbour
1978 static struct Neighbour *
1979 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
1981 return GNUNET_CONTAINER_multipeermap_get (neighbours,
1987 * Details about what to notify monitors about.
1992 * @deprecated To be discussed if we keep these...
1994 struct GNUNET_TIME_Absolute last_validation;
1995 struct GNUNET_TIME_Absolute valid_until;
1996 struct GNUNET_TIME_Absolute next_validation;
1999 * Current round-trip time estimate.
2001 struct GNUNET_TIME_Relative rtt;
2004 * Connection status.
2006 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2011 uint32_t num_msg_pending;
2016 uint32_t num_bytes_pending;
2023 * Free a @dvh. Callers MAY want to check if this was the last path to the
2024 * `target`, and if so call #free_dv_route to also free the associated DV
2025 * entry in #dv_routes (if not, the associated scheduler job should eventually
2028 * @param dvh hop to free
2031 free_distance_vector_hop (struct DistanceVectorHop *dvh)
2033 struct Neighbour *n = dvh->next_hop;
2034 struct DistanceVector *dv = dvh->dv;
2036 GNUNET_CONTAINER_MDLL_remove (neighbour,
2040 GNUNET_CONTAINER_MDLL_remove (dv,
2049 * Free entry in #dv_routes. First frees all hops to the target, and
2050 * if there are no entries left, frees @a dv as well.
2052 * @param dv route to free
2055 free_dv_route (struct DistanceVector *dv)
2057 struct DistanceVectorHop *dvh;
2059 while (NULL != (dvh = dv->dv_head))
2060 free_distance_vector_hop (dvh);
2061 if (NULL == dv->dv_head)
2063 GNUNET_assert (GNUNET_YES ==
2064 GNUNET_CONTAINER_multipeermap_remove (dv_routes,
2067 if (NULL != dv->timeout_task)
2068 GNUNET_SCHEDULER_cancel (dv->timeout_task);
2075 * Notify monitor @a tc about an event. That @a tc
2076 * cares about the event has already been checked.
2078 * Send @a tc information in @a me about a @a peer's status with
2079 * respect to some @a address to all monitors that care.
2081 * @param tc monitor to inform
2082 * @param peer peer the information is about
2083 * @param address address the information is about
2084 * @param nt network type associated with @a address
2085 * @param me detailed information to transmit
2088 notify_monitor (struct TransportClient *tc,
2089 const struct GNUNET_PeerIdentity *peer,
2090 const char *address,
2091 enum GNUNET_NetworkType nt,
2092 const struct MonitorEvent *me)
2094 struct GNUNET_MQ_Envelope *env;
2095 struct GNUNET_TRANSPORT_MonitorData *md;
2096 size_t addr_len = strlen (address) + 1;
2098 env = GNUNET_MQ_msg_extra (md,
2100 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2101 md->nt = htonl ((uint32_t) nt);
2103 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2104 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2105 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2106 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2107 md->cs = htonl ((uint32_t) me->cs);
2108 md->num_msg_pending = htonl (me->num_msg_pending);
2109 md->num_bytes_pending = htonl (me->num_bytes_pending);
2113 GNUNET_MQ_send (tc->mq,
2119 * Send information in @a me about a @a peer's status with respect
2120 * to some @a address to all monitors that care.
2122 * @param peer peer the information is about
2123 * @param address address the information is about
2124 * @param nt network type associated with @a address
2125 * @param me detailed information to transmit
2128 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2129 const char *address,
2130 enum GNUNET_NetworkType nt,
2131 const struct MonitorEvent *me)
2133 for (struct TransportClient *tc = clients_head;
2137 if (CT_MONITOR != tc->type)
2139 if (tc->details.monitor.one_shot)
2141 if ( (0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2142 (0 != GNUNET_memcmp (&tc->details.monitor.peer,
2155 * Called whenever a client connects. Allocates our
2156 * data structures associated with that client.
2158 * @param cls closure, NULL
2159 * @param client identification of the client
2160 * @param mq message queue for the client
2161 * @return our `struct TransportClient`
2164 client_connect_cb (void *cls,
2165 struct GNUNET_SERVICE_Client *client,
2166 struct GNUNET_MQ_Handle *mq)
2168 struct TransportClient *tc;
2171 tc = GNUNET_new (struct TransportClient);
2172 tc->client = client;
2174 GNUNET_CONTAINER_DLL_insert (clients_head,
2177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2178 "Client %p connected\n",
2187 * @param rc data structure to free
2190 free_reassembly_context (struct ReassemblyContext *rc)
2192 struct Neighbour *n = rc->neighbour;
2194 GNUNET_assert (rc ==
2195 GNUNET_CONTAINER_heap_remove_node (rc->hn));
2196 GNUNET_assert (GNUNET_OK ==
2197 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2205 * Task run to clean up reassembly context of a neighbour that have expired.
2207 * @param cls a `struct Neighbour`
2210 reassembly_cleanup_task (void *cls)
2212 struct Neighbour *n = cls;
2213 struct ReassemblyContext *rc;
2215 n->reassembly_timeout_task = NULL;
2216 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2218 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout).rel_value_us)
2220 free_reassembly_context (rc);
2223 GNUNET_assert (NULL == n->reassembly_timeout_task);
2224 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2225 &reassembly_cleanup_task,
2233 * function called to #free_reassembly_context().
2237 * @param value a `struct ReassemblyContext` to free
2238 * @return #GNUNET_OK (continue iteration)
2241 free_reassembly_cb (void *cls,
2242 const struct GNUNET_ShortHashCode *key,
2245 struct ReassemblyContext *rc = value;
2249 free_reassembly_context (rc);
2255 * Release memory used by @a neighbour.
2257 * @param neighbour neighbour entry to free
2260 free_neighbour (struct Neighbour *neighbour)
2262 struct DistanceVectorHop *dvh;
2264 GNUNET_assert (NULL == neighbour->queue_head);
2265 GNUNET_assert (GNUNET_YES ==
2266 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2269 if (NULL != neighbour->timeout_task)
2270 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2271 if (NULL != neighbour->reassembly_map)
2273 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2274 &free_reassembly_cb,
2276 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2277 neighbour->reassembly_map = NULL;
2278 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2279 neighbour->reassembly_heap = NULL;
2281 while (NULL != (dvh = neighbour->dv_head))
2283 struct DistanceVector *dv = dvh->dv;
2285 free_distance_vector_hop (dvh);
2286 if (NULL == dv->dv_head)
2289 if (NULL != neighbour->reassembly_timeout_task)
2290 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2291 GNUNET_free (neighbour);
2296 * Send message to CORE clients that we lost a connection.
2298 * @param tc client to inform (must be CORE client)
2299 * @param pid peer the connection is for
2300 * @param quota_out current quota for the peer
2303 core_send_connect_info (struct TransportClient *tc,
2304 const struct GNUNET_PeerIdentity *pid,
2305 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2307 struct GNUNET_MQ_Envelope *env;
2308 struct ConnectInfoMessage *cim;
2310 GNUNET_assert (CT_CORE == tc->type);
2311 env = GNUNET_MQ_msg (cim,
2312 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2313 cim->quota_out = quota_out;
2315 GNUNET_MQ_send (tc->mq,
2321 * Send message to CORE clients that we gained a connection
2323 * @param pid peer the queue was for
2324 * @param quota_out current quota for the peer
2327 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2328 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2330 for (struct TransportClient *tc = clients_head;
2334 if (CT_CORE != tc->type)
2336 core_send_connect_info (tc,
2344 * Send message to CORE clients that we lost a connection.
2346 * @param pid peer the connection was for
2349 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2351 for (struct TransportClient *tc = clients_head;
2355 struct GNUNET_MQ_Envelope *env;
2356 struct DisconnectInfoMessage *dim;
2358 if (CT_CORE != tc->type)
2360 env = GNUNET_MQ_msg (dim,
2361 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2363 GNUNET_MQ_send (tc->mq,
2370 * We believe we are ready to transmit a message on a queue. Double-checks
2371 * with the queue's "tracker_out" and then gives the message to the
2372 * communicator for transmission (updating the tracker, and re-scheduling
2373 * itself if applicable).
2375 * @param cls the `struct Queue` to process transmissions for
2378 transmit_on_queue (void *cls);
2382 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2383 * we should run immediately or if the message queue is empty.
2384 * Test for no task being added AND queue not being empty to
2385 * transmit immediately afterwards! This function must only
2386 * be called if the message queue is non-empty!
2388 * @param queue the queue to do scheduling for
2391 schedule_transmit_on_queue (struct Queue *queue)
2393 struct Neighbour *n = queue->neighbour;
2394 struct PendingMessage *pm = n->pending_msg_head;
2395 struct GNUNET_TIME_Relative out_delay;
2398 GNUNET_assert (NULL != pm);
2399 if (queue->tc->details.communicator.total_queue_length >=
2400 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2402 GNUNET_STATISTICS_update (GST_stats,
2403 "# Transmission throttled due to communicator queue limit",
2408 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2410 GNUNET_STATISTICS_update (GST_stats,
2411 "# Transmission throttled due to queue queue limit",
2417 wsize = (0 == queue->mtu)
2418 ? pm->bytes_msg /* FIXME: add overheads? */
2420 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out,
2422 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (pm->next_attempt),
2424 if (0 == out_delay.rel_value_us)
2425 return; /* we should run immediately! */
2426 /* queue has changed since we were scheduled, reschedule again */
2427 queue->transmit_task
2428 = GNUNET_SCHEDULER_add_delayed (out_delay,
2431 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2432 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2433 "Next transmission on queue `%s' in %s (high delay)\n",
2435 GNUNET_STRINGS_relative_time_to_string (out_delay,
2438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2439 "Next transmission on queue `%s' in %s\n",
2441 GNUNET_STRINGS_relative_time_to_string (out_delay,
2449 * @param queue the queue to free
2452 free_queue (struct Queue *queue)
2454 struct Neighbour *neighbour = queue->neighbour;
2455 struct TransportClient *tc = queue->tc;
2456 struct MonitorEvent me = {
2457 .cs = GNUNET_TRANSPORT_CS_DOWN,
2458 .rtt = GNUNET_TIME_UNIT_FOREVER_REL
2460 struct QueueEntry *qe;
2463 if (NULL != queue->transmit_task)
2465 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2466 queue->transmit_task = NULL;
2468 GNUNET_CONTAINER_MDLL_remove (neighbour,
2469 neighbour->queue_head,
2470 neighbour->queue_tail,
2472 GNUNET_CONTAINER_MDLL_remove (client,
2473 tc->details.communicator.queue_head,
2474 tc->details.communicator.queue_tail,
2476 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >= tc->details.communicator.total_queue_length);
2477 while (NULL != (qe = queue->queue_head))
2479 GNUNET_CONTAINER_DLL_remove (queue->queue_head,
2482 queue->queue_length--;
2483 tc->details.communicator.total_queue_length--;
2486 GNUNET_assert (0 == queue->queue_length);
2488 (COMMUNICATOR_TOTAL_QUEUE_LIMIT < tc->details.communicator.total_queue_length) )
2490 /* Communicator dropped below threshold, resume all queues */
2491 GNUNET_STATISTICS_update (GST_stats,
2492 "# Transmission throttled due to communicator queue limit",
2495 for (struct Queue *s = tc->details.communicator.queue_head;
2498 schedule_transmit_on_queue (s);
2500 notify_monitors (&neighbour->pid,
2504 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2505 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2506 GNUNET_free (queue);
2507 if (NULL == neighbour->queue_head)
2509 cores_send_disconnect_info (&neighbour->pid);
2510 free_neighbour (neighbour);
2518 * @param ale address list entry to free
2521 free_address_list_entry (struct AddressListEntry *ale)
2523 struct TransportClient *tc = ale->tc;
2525 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2526 tc->details.communicator.addr_tail,
2528 if (NULL != ale->sc)
2530 GNUNET_PEERSTORE_store_cancel (ale->sc);
2533 if (NULL != ale->st)
2535 GNUNET_SCHEDULER_cancel (ale->st);
2543 * Stop the peer request in @a value.
2545 * @param cls a `struct TransportClient` that no longer makes the request
2546 * @param pid the peer's identity
2547 * @param value a `struct PeerRequest`
2548 * @return #GNUNET_YES (always)
2551 stop_peer_request (void *cls,
2552 const struct GNUNET_PeerIdentity *pid,
2555 struct TransportClient *tc = cls;
2556 struct PeerRequest *pr = value;
2558 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2559 GNUNET_assert (GNUNET_YES ==
2560 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2570 * Called whenever a client is disconnected. Frees our
2571 * resources associated with that client.
2573 * @param cls closure, NULL
2574 * @param client identification of the client
2575 * @param app_ctx our `struct TransportClient`
2578 client_disconnect_cb (void *cls,
2579 struct GNUNET_SERVICE_Client *client,
2582 struct TransportClient *tc = app_ctx;
2585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2586 "Client %p disconnected, cleaning up.\n",
2588 GNUNET_CONTAINER_DLL_remove (clients_head,
2597 struct PendingMessage *pm;
2599 while (NULL != (pm = tc->details.core.pending_msg_head))
2601 GNUNET_CONTAINER_MDLL_remove (client,
2602 tc->details.core.pending_msg_head,
2603 tc->details.core.pending_msg_tail,
2611 case CT_COMMUNICATOR:
2614 struct AddressListEntry *ale;
2616 while (NULL != (q = tc->details.communicator.queue_head))
2618 while (NULL != (ale = tc->details.communicator.addr_head))
2619 free_address_list_entry (ale);
2620 GNUNET_free (tc->details.communicator.address_prefix);
2623 case CT_APPLICATION:
2624 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2627 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2635 * Iterator telling new CORE client about all existing
2636 * connections to peers.
2638 * @param cls the new `struct TransportClient`
2639 * @param pid a connected peer
2640 * @param value the `struct Neighbour` with more information
2641 * @return #GNUNET_OK (continue to iterate)
2644 notify_client_connect_info (void *cls,
2645 const struct GNUNET_PeerIdentity *pid,
2648 struct TransportClient *tc = cls;
2649 struct Neighbour *neighbour = value;
2651 core_send_connect_info (tc,
2653 neighbour->quota_out);
2659 * Initialize a "CORE" client. We got a start message from this
2660 * client, so add it to the list of clients for broadcasting of
2663 * @param cls the client
2664 * @param start the start message that was sent
2667 handle_client_start (void *cls,
2668 const struct StartMessage *start)
2670 struct TransportClient *tc = cls;
2673 options = ntohl (start->options);
2674 if ( (0 != (1 & options)) &&
2676 GNUNET_memcmp (&start->self,
2677 &GST_my_identity)) )
2679 /* client thinks this is a different peer, reject */
2681 GNUNET_SERVICE_client_drop (tc->client);
2684 if (CT_NONE != tc->type)
2687 GNUNET_SERVICE_client_drop (tc->client);
2691 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2692 ¬ify_client_connect_info,
2694 GNUNET_SERVICE_client_continue (tc->client);
2699 * Client asked for transmission to a peer. Process the request.
2701 * @param cls the client
2702 * @param obm the send message that was sent
2705 check_client_send (void *cls,
2706 const struct OutboundMessage *obm)
2708 struct TransportClient *tc = cls;
2710 const struct GNUNET_MessageHeader *obmm;
2712 if (CT_CORE != tc->type)
2715 return GNUNET_SYSERR;
2717 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2718 if (size < sizeof (struct GNUNET_MessageHeader))
2721 return GNUNET_SYSERR;
2723 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2724 if (size != ntohs (obmm->size))
2727 return GNUNET_SYSERR;
2734 * Free fragment tree below @e root, excluding @e root itself.
2736 * @param root root of the tree to free
2739 free_fragment_tree (struct PendingMessage *root)
2741 struct PendingMessage *frag;
2743 while (NULL != (frag = root->head_frag))
2745 free_fragment_tree (frag);
2746 GNUNET_CONTAINER_MDLL_remove (frag,
2756 * Release memory associated with @a pm and remove @a pm from associated
2757 * data structures. @a pm must be a top-level pending message and not
2758 * a fragment in the tree. The entire tree is freed (if applicable).
2760 * @param pm the pending message to free
2763 free_pending_message (struct PendingMessage *pm)
2765 struct TransportClient *tc = pm->client;
2766 struct Neighbour *target = pm->target;
2770 GNUNET_CONTAINER_MDLL_remove (client,
2771 tc->details.core.pending_msg_head,
2772 tc->details.core.pending_msg_tail,
2775 GNUNET_CONTAINER_MDLL_remove (neighbour,
2776 target->pending_msg_head,
2777 target->pending_msg_tail,
2779 free_fragment_tree (pm);
2780 GNUNET_free_non_null (pm->bpm);
2786 * Send a response to the @a pm that we have processed a
2787 * "send" request with status @a success. We
2788 * transmitted @a bytes_physical on the actual wire.
2789 * Sends a confirmation to the "core" client responsible
2790 * for the original request and free's @a pm.
2792 * @param pm handle to the original pending message
2793 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2794 * for transmission failure
2795 * @param bytes_physical amount of bandwidth consumed
2798 client_send_response (struct PendingMessage *pm,
2800 uint32_t bytes_physical)
2802 struct TransportClient *tc = pm->client;
2803 struct Neighbour *target = pm->target;
2804 struct GNUNET_MQ_Envelope *env;
2805 struct SendOkMessage *som;
2809 env = GNUNET_MQ_msg (som,
2810 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2811 som->success = htonl ((uint32_t) success);
2812 som->bytes_msg = htons (pm->bytes_msg);
2813 som->bytes_physical = htonl (bytes_physical);
2814 som->peer = target->pid;
2815 GNUNET_MQ_send (tc->mq,
2818 free_pending_message (pm);
2823 * Checks the message queue for a neighbour for messages that have timed
2824 * out and purges them.
2826 * @param cls a `struct Neighbour`
2829 check_queue_timeouts (void *cls)
2831 struct Neighbour *n = cls;
2832 struct PendingMessage *pm;
2833 struct GNUNET_TIME_Absolute now;
2834 struct GNUNET_TIME_Absolute earliest_timeout;
2836 n->timeout_task = NULL;
2837 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2838 now = GNUNET_TIME_absolute_get ();
2839 for (struct PendingMessage *pos = n->pending_msg_head;
2843 pm = pos->next_neighbour;
2844 if (pos->timeout.abs_value_us <= now.abs_value_us)
2846 GNUNET_STATISTICS_update (GST_stats,
2847 "# messages dropped (timeout before confirmation)",
2850 client_send_response (pm,
2855 earliest_timeout = GNUNET_TIME_absolute_min (earliest_timeout,
2858 n->earliest_timeout = earliest_timeout;
2859 if (NULL != n->pending_msg_head)
2860 n->timeout_task = GNUNET_SCHEDULER_add_at (earliest_timeout,
2861 &check_queue_timeouts,
2867 * Client asked for transmission to a peer. Process the request.
2869 * @param cls the client
2870 * @param obm the send message that was sent
2873 handle_client_send (void *cls,
2874 const struct OutboundMessage *obm)
2876 struct TransportClient *tc = cls;
2877 struct PendingMessage *pm;
2878 const struct GNUNET_MessageHeader *obmm;
2879 struct Neighbour *target;
2883 GNUNET_assert (CT_CORE == tc->type);
2884 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2885 bytes_msg = ntohs (obmm->size);
2886 target = lookup_neighbour (&obm->peer);
2889 /* Failure: don't have this peer as a neighbour (anymore).
2890 Might have gone down asynchronously, so this is NOT
2891 a protocol violation by CORE. Still count the event,
2892 as this should be rare. */
2893 struct GNUNET_MQ_Envelope *env;
2894 struct SendOkMessage *som;
2896 env = GNUNET_MQ_msg (som,
2897 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2898 som->success = htonl (GNUNET_SYSERR);
2899 som->bytes_msg = htonl (bytes_msg);
2900 som->bytes_physical = htonl (0);
2901 som->peer = obm->peer;
2902 GNUNET_MQ_send (tc->mq,
2904 GNUNET_SERVICE_client_continue (tc->client);
2905 GNUNET_STATISTICS_update (GST_stats,
2906 "# messages dropped (neighbour unknown)",
2911 was_empty = (NULL == target->pending_msg_head);
2912 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2914 pm->target = target;
2915 pm->bytes_msg = bytes_msg;
2916 pm->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2920 GNUNET_CONTAINER_MDLL_insert (neighbour,
2921 target->pending_msg_head,
2922 target->pending_msg_tail,
2924 GNUNET_CONTAINER_MDLL_insert (client,
2925 tc->details.core.pending_msg_head,
2926 tc->details.core.pending_msg_tail,
2928 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
2930 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
2931 if (NULL != target->timeout_task)
2932 GNUNET_SCHEDULER_cancel (target->timeout_task);
2933 target->timeout_task
2934 = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
2935 &check_queue_timeouts,
2939 return; /* all queues must already be busy */
2940 for (struct Queue *queue = target->queue_head;
2942 queue = queue->next_neighbour)
2944 /* try transmission on any queue that is idle */
2945 if (NULL == queue->transmit_task)
2946 queue->transmit_task = GNUNET_SCHEDULER_add_now (&transmit_on_queue,
2953 * Communicator started. Test message is well-formed.
2955 * @param cls the client
2956 * @param cam the send message that was sent
2959 check_communicator_available (void *cls,
2960 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
2962 struct TransportClient *tc = cls;
2965 if (CT_NONE != tc->type)
2968 return GNUNET_SYSERR;
2970 tc->type = CT_COMMUNICATOR;
2971 size = ntohs (cam->header.size) - sizeof (*cam);
2973 return GNUNET_OK; /* receive-only communicator */
2974 GNUNET_MQ_check_zero_termination (cam);
2980 * Communicator started. Process the request.
2982 * @param cls the client
2983 * @param cam the send message that was sent
2986 handle_communicator_available (void *cls,
2987 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
2989 struct TransportClient *tc = cls;
2992 size = ntohs (cam->header.size) - sizeof (*cam);
2994 return; /* receive-only communicator */
2995 tc->details.communicator.address_prefix
2996 = GNUNET_strdup ((const char *) &cam[1]);
2997 tc->details.communicator.cc
2998 = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
2999 GNUNET_SERVICE_client_continue (tc->client);
3004 * Communicator requests backchannel transmission. Check the request.
3006 * @param cls the client
3007 * @param cb the send message that was sent
3008 * @return #GNUNET_OK if message is well-formed
3011 check_communicator_backchannel (void *cls,
3012 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3014 const struct GNUNET_MessageHeader *inbox;
3020 msize = ntohs (cb->header.size) - sizeof (*cb);
3021 if (UINT16_MAX - msize >
3022 sizeof (struct TransportBackchannelEncapsulationMessage) +
3023 sizeof (struct TransportBackchannelRequestPayload) )
3026 return GNUNET_SYSERR;
3028 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
3029 isize = ntohs (inbox->size);
3033 return GNUNET_SYSERR;
3035 is = (const char *) inbox;
3038 GNUNET_assert (msize > 0);
3039 if ('\0' != is[msize-1])
3042 return GNUNET_SYSERR;
3049 * Remove memory used by expired ephemeral keys.
3054 expire_ephemerals (void *cls)
3056 struct EphemeralCacheEntry *ece;
3059 ephemeral_task = NULL;
3060 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
3062 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us)
3064 free_ephemeral (ece);
3067 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3076 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
3077 * one, cache it and return it.
3079 * @param pid peer to look up ephemeral for
3080 * @param private_key[out] set to the private key
3081 * @param ephemeral_key[out] set to the key
3082 * @param ephemeral_sender_sig[out] set to the signature
3083 * @param ephemeral_validity[out] set to the validity expiration time
3086 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3087 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3088 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3089 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3090 struct GNUNET_TIME_Absolute *ephemeral_validity)
3092 struct EphemeralCacheEntry *ece;
3093 struct EphemeralConfirmation ec;
3095 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map,
3097 if ( (NULL != ece) &&
3098 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us) )
3100 free_ephemeral (ece);
3105 ece = GNUNET_new (struct EphemeralCacheEntry);
3107 ece->ephemeral_validity = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3108 EPHEMERAL_VALIDITY);
3109 GNUNET_assert (GNUNET_OK ==
3110 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3111 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key,
3112 &ece->ephemeral_key);
3113 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3114 ec.purpose.size = htonl (sizeof (ec));
3116 ec.ephemeral_key = ece->ephemeral_key;
3117 GNUNET_assert (GNUNET_OK ==
3118 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3121 ece->hn = GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3123 ece->ephemeral_validity.abs_value_us);
3124 GNUNET_assert (GNUNET_OK ==
3125 GNUNET_CONTAINER_multipeermap_put (ephemeral_map,
3128 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3129 if (NULL == ephemeral_task)
3130 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3134 *private_key = ece->private_key;
3135 *ephemeral_key = ece->ephemeral_key;
3136 *ephemeral_sender_sig = ece->sender_sig;
3137 *ephemeral_validity = ece->ephemeral_validity;
3142 * We need to transmit @a hdr to @a target. If necessary, this may
3143 * involve DV routing or even broadcasting and fragmentation.
3145 * @param target peer to receive @a hdr
3146 * @param hdr header of the message to route
3149 route_message (const struct GNUNET_PeerIdentity *target,
3150 struct GNUNET_MessageHeader *hdr)
3152 // FIXME: this one is tricky:
3153 // - we could try a direct, reliable channel
3154 // - if that is unavailable / for load balancing, we may try:
3155 // * multiple (?) direct unreliable channels - depending on loss rate?
3156 // * some (?) DV channels - if above unavailable / too lossy?
3157 // * _random_ other peers ("broadcasting") in hope of *discovering*
3158 // a path back! - if all else fails
3159 // => need more on DV first!
3161 // FIXME: send hdr to target, free hdr (possibly using DV, possibly broadcasting)
3167 * Communicator requests backchannel transmission. Process the request.
3169 * @param cls the client
3170 * @param cb the send message that was sent
3173 handle_communicator_backchannel (void *cls,
3174 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3176 struct TransportClient *tc = cls;
3177 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3178 struct GNUNET_TIME_Absolute ephemeral_validity;
3179 struct TransportBackchannelEncapsulationMessage *enc;
3180 struct TransportBackchannelRequestPayload ppay;
3184 /* encapsulate and encrypt message */
3185 msize = ntohs (cb->header.size) - sizeof (*cb) + sizeof (struct TransportBackchannelRequestPayload);
3186 enc = GNUNET_malloc (sizeof (*enc) + msize);
3187 enc->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3188 enc->header.size = htons (sizeof (*enc) + msize);
3189 enc->target = cb->pid;
3190 lookup_ephemeral (&cb->pid,
3192 &enc->ephemeral_key,
3194 &ephemeral_validity);
3195 // FIXME: setup 'iv'
3197 dh_key_derive (&private_key,
3202 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3203 ppay.monotonic_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3204 mpos = (char *) &enc[1];
3213 ntohs (cb->header.size) - sizeof (*cb));
3217 route_message (&cb->pid,
3219 GNUNET_SERVICE_client_continue (tc->client);
3224 * Address of our peer added. Test message is well-formed.
3226 * @param cls the client
3227 * @param aam the send message that was sent
3228 * @return #GNUNET_OK if message is well-formed
3231 check_add_address (void *cls,
3232 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3234 struct TransportClient *tc = cls;
3236 if (CT_COMMUNICATOR != tc->type)
3239 return GNUNET_SYSERR;
3241 GNUNET_MQ_check_zero_termination (aam);
3247 * Ask peerstore to store our address.
3249 * @param cls an `struct AddressListEntry *`
3252 store_pi (void *cls);
3256 * Function called when peerstore is done storing our address.
3258 * @param cls a `struct AddressListEntry`
3259 * @param success #GNUNET_YES if peerstore was successful
3262 peerstore_store_own_cb (void *cls,
3265 struct AddressListEntry *ale = cls;
3268 if (GNUNET_YES != success)
3269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3270 "Failed to store our own address `%s' in peerstore!\n",
3272 /* refresh period is 1/4 of expiration time, that should be plenty
3273 without being excessive. */
3274 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3282 * Ask peerstore to store our address.
3284 * @param cls an `struct AddressListEntry *`
3287 store_pi (void *cls)
3289 struct AddressListEntry *ale = cls;
3292 struct GNUNET_TIME_Absolute expiration;
3295 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3296 GNUNET_HELLO_sign_address (ale->address,
3302 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3305 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3309 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3310 &peerstore_store_own_cb,
3313 if (NULL == ale->sc)
3315 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3316 "Failed to store our address `%s' with peerstore\n",
3318 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
3326 * Address of our peer added. Process the request.
3328 * @param cls the client
3329 * @param aam the send message that was sent
3332 handle_add_address (void *cls,
3333 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3335 struct TransportClient *tc = cls;
3336 struct AddressListEntry *ale;
3339 slen = ntohs (aam->header.size) - sizeof (*aam);
3340 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3342 ale->address = (const char *) &ale[1];
3343 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3344 ale->aid = aam->aid;
3345 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3349 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3350 tc->details.communicator.addr_tail,
3352 ale->st = GNUNET_SCHEDULER_add_now (&store_pi,
3354 GNUNET_SERVICE_client_continue (tc->client);
3359 * Address of our peer deleted. Process the request.
3361 * @param cls the client
3362 * @param dam the send message that was sent
3365 handle_del_address (void *cls,
3366 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3368 struct TransportClient *tc = cls;
3370 if (CT_COMMUNICATOR != tc->type)
3373 GNUNET_SERVICE_client_drop (tc->client);
3376 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3380 if (dam->aid != ale->aid)
3382 GNUNET_assert (ale->tc == tc);
3383 free_address_list_entry (ale);
3384 GNUNET_SERVICE_client_continue (tc->client);
3387 GNUNET_SERVICE_client_drop (tc->client);
3392 * Context from #handle_incoming_msg(). Closure for many
3393 * message handlers below.
3395 struct CommunicatorMessageContext
3398 * Which communicator provided us with the message.
3400 struct TransportClient *tc;
3403 * Additional information for flow control and about the sender.
3405 struct GNUNET_TRANSPORT_IncomingMessage im;
3408 * Number of hops the message has travelled (if DV-routed).
3409 * FIXME: make use of this in ACK handling!
3411 uint16_t total_hops;
3416 * Given an inbound message @a msg from a communicator @a cmc,
3417 * demultiplex it based on the type calling the right handler.
3419 * @param cmc context for demultiplexing
3420 * @param msg message to demultiplex
3423 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3424 const struct GNUNET_MessageHeader *msg);
3428 * Send ACK to communicator (if requested) and free @a cmc.
3430 * @param cmc context for which we are done handling the message
3433 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3435 if (0 != ntohl (cmc->im.fc_on))
3437 /* send ACK when done to communicator for flow control! */
3438 struct GNUNET_MQ_Envelope *env;
3439 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3441 env = GNUNET_MQ_msg (ack,
3442 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3443 ack->reserved = htonl (0);
3444 ack->fc_id = cmc->im.fc_id;
3445 ack->sender = cmc->im.sender;
3446 GNUNET_MQ_send (cmc->tc->mq,
3449 GNUNET_SERVICE_client_continue (cmc->tc->client);
3455 * Communicator gave us an unencapsulated message to pass as-is to
3456 * CORE. Process the request.
3458 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3459 * @param mh the message that was received
3462 handle_raw_message (void *cls,
3463 const struct GNUNET_MessageHeader *mh)
3465 struct CommunicatorMessageContext *cmc = cls;
3466 uint16_t size = ntohs (mh->size);
3468 if ( (size > UINT16_MAX - sizeof (struct InboundMessage)) ||
3469 (size < sizeof (struct GNUNET_MessageHeader)) )
3471 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3474 finish_cmc_handling (cmc);
3475 GNUNET_SERVICE_client_drop (client);
3478 /* Forward to all CORE clients */
3479 for (struct TransportClient *tc = clients_head;
3483 struct GNUNET_MQ_Envelope *env;
3484 struct InboundMessage *im;
3486 if (CT_CORE != tc->type)
3488 env = GNUNET_MQ_msg_extra (im,
3490 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3491 im->peer = cmc->im.sender;
3495 GNUNET_MQ_send (tc->mq,
3498 /* FIXME: consider doing this _only_ once the message
3499 was drained from the CORE MQs to extend flow control to CORE!
3500 (basically, increment counter in cmc, decrement on MQ send continuation! */
3501 finish_cmc_handling (cmc);
3506 * Communicator gave us a fragment box. Check the message.
3508 * @param cls a `struct CommunicatorMessageContext`
3509 * @param fb the send message that was sent
3510 * @return #GNUNET_YES if message is well-formed
3513 check_fragment_box (void *cls,
3514 const struct TransportFragmentBox *fb)
3516 uint16_t size = ntohs (fb->header.size);
3517 uint16_t bsize = size - sizeof (*fb);
3521 GNUNET_break_op (0);
3522 return GNUNET_SYSERR;
3524 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
3526 GNUNET_break_op (0);
3527 return GNUNET_SYSERR;
3529 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
3531 GNUNET_break_op (0);
3532 return GNUNET_SYSERR;
3539 * Generate a fragment acknowledgement for an @a rc.
3541 * @param rc context to generate ACK for, @a rc ACK state is reset
3544 send_fragment_ack (struct ReassemblyContext *rc)
3546 struct TransportFragmentAckMessage *ack;
3548 ack = GNUNET_new (struct TransportFragmentAckMessage);
3549 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
3550 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
3551 ack->frag_uuid = htonl (rc->frag_uuid);
3552 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
3553 ack->msg_uuid = rc->msg_uuid;
3554 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
3555 if (0 == rc->msg_missing)
3556 ack->reassembly_timeout
3557 = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
3559 ack->reassembly_timeout
3560 = GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
3561 route_message (&rc->neighbour->pid,
3563 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
3565 rc->extra_acks = 0LLU;
3570 * Communicator gave us a fragment. Process the request.
3572 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3573 * @param fb the message that was received
3576 handle_fragment_box (void *cls,
3577 const struct TransportFragmentBox *fb)
3579 struct CommunicatorMessageContext *cmc = cls;
3580 struct Neighbour *n;
3581 struct ReassemblyContext *rc;
3582 const struct GNUNET_MessageHeader *msg;
3588 struct GNUNET_TIME_Relative cdelay;
3591 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
3595 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3598 finish_cmc_handling (cmc);
3599 GNUNET_SERVICE_client_drop (client);
3602 if (NULL == n->reassembly_map)
3604 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8,
3606 n->reassembly_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3607 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
3608 &reassembly_cleanup_task,
3611 msize = ntohs (fb->msg_size);
3612 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map,
3616 rc = GNUNET_malloc (sizeof (*rc) +
3617 msize + /* reassembly payload buffer */
3618 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
3619 rc->msg_uuid = fb->msg_uuid;
3621 rc->msg_size = msize;
3622 rc->reassembly_timeout = GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
3623 rc->last_frag = GNUNET_TIME_absolute_get ();
3624 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
3626 rc->reassembly_timeout.abs_value_us);
3627 GNUNET_assert (GNUNET_OK ==
3628 GNUNET_CONTAINER_multishortmap_put (n->reassembly_map,
3631 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3632 target = (char *) &rc[1];
3633 rc->bitfield = (uint8_t *) (target + rc->msg_size);
3634 rc->msg_missing = rc->msg_size;
3638 target = (char *) &rc[1];
3640 if (msize != rc->msg_size)
3643 finish_cmc_handling (cmc);
3648 fsize = ntohs (fb->header.size) - sizeof (*fb);
3649 frag_off = ntohs (fb->frag_off);
3650 memcpy (&target[frag_off],
3653 /* update bitfield and msg_missing */
3654 for (unsigned int i=frag_off;i<frag_off+fsize;i++)
3656 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
3658 rc->bitfield[i / 8] |= (1 << (i % 8));
3663 /* Compute cummulative ACK */
3664 frag_uuid = ntohl (fb->frag_uuid);
3665 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
3666 cdelay = GNUNET_TIME_relative_multiply (cdelay,
3668 rc->last_frag = GNUNET_TIME_absolute_get ();
3669 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay,
3671 ack_now = GNUNET_NO;
3672 if (0 == rc->num_acks)
3674 /* case one: first ack */
3675 rc->frag_uuid = frag_uuid;
3676 rc->extra_acks = 0LLU;
3679 else if ( (frag_uuid >= rc->frag_uuid) &&
3680 (frag_uuid <= rc->frag_uuid + 64) )
3682 /* case two: ack fits after existing min UUID */
3683 if ( (frag_uuid == rc->frag_uuid) ||
3684 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))) )
3686 /* duplicate fragment, ack now! */
3687 ack_now = GNUNET_YES;
3691 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
3695 else if ( (rc->frag_uuid > frag_uuid) &&
3696 ( ( (rc->frag_uuid == frag_uuid + 64) &&
3697 (0 == rc->extra_acks) ) ||
3698 ( (rc->frag_uuid < frag_uuid + 64) &&
3699 (rc->extra_acks == (rc->extra_acks & ~ ((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))) ) ) )
3701 /* can fit ack by shifting extra acks and starting at
3702 frag_uid, test above esured that the bits we will
3703 shift 'extra_acks' by are all zero. */
3704 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
3705 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
3706 rc->frag_uuid = frag_uuid;
3709 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very aggressive. */
3710 ack_now = GNUNET_YES; /* maximum acks received */
3711 // FIXME: possibly also ACK based on RTT (but for that we'd need to
3712 // determine the queue used for the ACK first!)
3714 /* is reassembly complete? */
3715 if (0 != rc->msg_missing)
3718 send_fragment_ack (rc);
3719 finish_cmc_handling (cmc);
3722 /* reassembly is complete, verify result */
3723 msg = (const struct GNUNET_MessageHeader *) &rc[1];
3724 if (ntohs (msg->size) != rc->msg_size)
3727 free_reassembly_context (rc);
3728 finish_cmc_handling (cmc);
3731 /* successful reassembly */
3732 send_fragment_ack (rc);
3733 demultiplex_with_cmc (cmc,
3735 /* FIXME: really free here? Might be bad if fragments are still
3736 en-route and we forget that we finished this reassembly immediately!
3737 -> keep around until timeout?
3738 -> shorten timeout based on ACK? */
3739 free_reassembly_context (rc);
3744 * Check the @a fa against the fragments associated with @a pm.
3745 * If it matches, remove the matching fragments from the transmission
3748 * @param pm pending message to check against the ack
3749 * @param fa the ack that was received
3750 * @return #GNUNET_YES if @a fa matched, #GNUNET_NO if not
3753 check_ack_against_pm (struct PendingMessage *pm,
3754 const struct TransportFragmentAckMessage *fa)
3757 struct PendingMessage *nxt;
3758 uint32_t fs = ntohl (fa->frag_uuid);
3759 uint64_t xtra = GNUNET_ntohll (fa->extra_acks);
3762 for (struct PendingMessage *frag = pm->head_frag;
3766 const struct TransportFragmentBox *tfb
3767 = (const struct TransportFragmentBox *) &pm[1];
3768 uint32_t fu = ntohl (tfb->frag_uuid);
3770 GNUNET_assert (PMT_FRAGMENT_BOX == frag->pmt);
3771 nxt = frag->next_frag;
3772 /* Check for exact match or match in the 'xtra' bitmask */
3776 (0 != (1LLU << (fu - fs - 1) & xtra)) ) )
3779 free_fragment_tree (frag);
3787 * Communicator gave us a fragment acknowledgement. Process the request.
3789 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3790 * @param fa the message that was received
3793 handle_fragment_ack (void *cls,
3794 const struct TransportFragmentAckMessage *fa)
3796 struct CommunicatorMessageContext *cmc = cls;
3797 struct Neighbour *n;
3800 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
3804 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3807 finish_cmc_handling (cmc);
3808 GNUNET_SERVICE_client_drop (client);
3811 /* FIXME-OPTIMIZE: maybe use another hash map here? */
3812 matched = GNUNET_NO;
3813 for (struct PendingMessage *pm = n->pending_msg_head;
3815 pm = pm->prev_neighbour)
3818 GNUNET_memcmp (&fa->msg_uuid,
3821 matched = GNUNET_YES;
3823 check_ack_against_pm (pm,
3826 struct GNUNET_TIME_Relative avg_ack_delay
3827 = GNUNET_TIME_relative_ntoh (fa->avg_ack_delay);
3828 // FIXME: update RTT and other reliability data!
3829 // ISSUE: we don't know which of n's queues the message(s)
3830 // took (and in fact the different messages might have gone
3831 // over different queues and possibly over multiple).
3832 // => track queues with PendingMessages, and update RTT only if
3833 // the queue used is unique?
3834 // -> how can we get loss rates?
3835 // -> or, add extra state to Box and ACK to identify queue?
3836 // IDEA: generate MULTIPLE frag-uuids per fragment and track
3837 // the queue with the fragment! (-> this logic must
3838 // be moved into check_ack_against_pm!)
3839 (void) avg_ack_delay;
3843 GNUNET_STATISTICS_update (GST_stats,
3844 "# FRAGMENT_ACKS dropped, no matching fragment",
3848 if (NULL == pm->head_frag)
3850 // if entire message is ACKed, handle that as well.
3851 // => clean up PM, any post actions?
3852 free_pending_message (pm);
3856 struct GNUNET_TIME_Relative reassembly_timeout
3857 = GNUNET_TIME_relative_ntoh (fa->reassembly_timeout);
3858 // OPTIMIZE-FIXME: adjust retransmission strategy based on reassembly_timeout!
3859 (void) reassembly_timeout;
3863 if (GNUNET_NO == matched)
3865 GNUNET_STATISTICS_update (GST_stats,
3866 "# FRAGMENT_ACKS dropped, no matching pending message",
3870 finish_cmc_handling (cmc);
3875 * Communicator gave us a reliability box. Check the message.
3877 * @param cls a `struct CommunicatorMessageContext`
3878 * @param rb the send message that was sent
3879 * @return #GNUNET_YES if message is well-formed
3882 check_reliability_box (void *cls,
3883 const struct TransportReliabilityBox *rb)
3885 GNUNET_MQ_check_boxed_message (rb);
3891 * Communicator gave us a reliability box. Process the request.
3893 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3894 * @param rb the message that was received
3897 handle_reliability_box (void *cls,
3898 const struct TransportReliabilityBox *rb)
3900 struct CommunicatorMessageContext *cmc = cls;
3901 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &rb[1];
3903 if (0 == ntohl (rb->ack_countdown))
3905 struct TransportReliabilityAckMessage *ack;
3907 /* FIXME: implement cummulative ACKs and ack_countdown,
3908 then setting the avg_ack_delay field below: */
3909 ack = GNUNET_malloc (sizeof (*ack) +
3910 sizeof (struct GNUNET_ShortHashCode));
3911 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
3912 ack->header.size = htons (sizeof (*ack) +
3913 sizeof (struct GNUNET_ShortHashCode));
3916 sizeof (struct GNUNET_ShortHashCode));
3917 route_message (&cmc->im.sender,
3920 /* continue with inner message */
3921 demultiplex_with_cmc (cmc,
3927 * Communicator gave us a reliability ack. Process the request.
3929 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3930 * @param ra the message that was received
3933 handle_reliability_ack (void *cls,
3934 const struct TransportReliabilityAckMessage *ra)
3936 struct CommunicatorMessageContext *cmc = cls;
3937 struct Neighbour *n;
3938 unsigned int n_acks;
3939 const struct GNUNET_ShortHashCode *msg_uuids;
3940 struct PendingMessage *nxt;
3943 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
3947 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3950 finish_cmc_handling (cmc);
3951 GNUNET_SERVICE_client_drop (client);
3954 n_acks = (ntohs (ra->header.size) - sizeof (*ra))
3955 / sizeof (struct GNUNET_ShortHashCode);
3956 msg_uuids = (const struct GNUNET_ShortHashCode *) &ra[1];
3958 /* FIXME-OPTIMIZE: maybe use another hash map here? */
3959 matched = GNUNET_NO;
3960 for (struct PendingMessage *pm = n->pending_msg_head;
3966 nxt = pm->next_neighbour;
3967 in_list = GNUNET_NO;
3968 for (unsigned int i=0;i<n_acks;i++)
3971 GNUNET_memcmp (&msg_uuids[i],
3974 in_list = GNUNET_YES;
3977 if (GNUNET_NO == in_list)
3980 /* this pm was acked! */
3981 matched = GNUNET_YES;
3982 free_pending_message (pm);
3985 struct GNUNET_TIME_Relative avg_ack_delay
3986 = GNUNET_TIME_relative_ntoh (ra->avg_ack_delay);
3987 // FIXME: update RTT and other reliability data!
3988 // ISSUE: we don't know which of n's queues the message(s)
3989 // took (and in fact the different messages might have gone
3990 // over different queues and possibly over multiple).
3991 // => track queues with PendingMessages, and update RTT only if
3992 // the queue used is unique?
3993 // -> how can we get loss rates?
3994 // -> or, add extra state to MSG and ACKs to identify queue?
3995 // -> if we do this, might just do the same for the avg_ack_delay!
3996 (void) avg_ack_delay;
3999 if (GNUNET_NO == matched)
4001 GNUNET_STATISTICS_update (GST_stats,
4002 "# FRAGMENT_ACKS dropped, no matching pending message",
4006 finish_cmc_handling (cmc);
4011 * Communicator gave us a backchannel encapsulation. Check the message.
4013 * @param cls a `struct CommunicatorMessageContext`
4014 * @param be the send message that was sent
4015 * @return #GNUNET_YES if message is well-formed
4018 check_backchannel_encapsulation (void *cls,
4019 const struct TransportBackchannelEncapsulationMessage *be)
4021 uint16_t size = ntohs (be->header.size);
4024 if (size - sizeof (*be) < sizeof (struct GNUNET_MessageHeader))
4026 GNUNET_break_op (0);
4027 return GNUNET_SYSERR;
4034 * Communicator gave us a backchannel encapsulation. Process the request.
4036 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4037 * @param be the message that was received
4040 handle_backchannel_encapsulation (void *cls,
4041 const struct TransportBackchannelEncapsulationMessage *be)
4043 struct CommunicatorMessageContext *cmc = cls;
4045 if (0 != GNUNET_memcmp (&be->target,
4048 /* not for me, try to route to target */
4049 route_message (&be->target,
4050 GNUNET_copy_message (&be->header));
4051 finish_cmc_handling (cmc);
4054 // FIXME: compute shared secret
4055 // FIXME: check HMAC
4056 // FIXME: decrypt payload
4057 // FIXME: forward to specified communicator!
4058 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
4059 finish_cmc_handling (cmc);
4064 * Task called when we should check if any of the DV paths
4065 * we have learned to a target are due for garbage collection.
4067 * Collects stale paths, and possibly frees the entire DV
4068 * entry if no paths are left. Otherwise re-schedules itself.
4070 * @param cls a `struct DistanceVector`
4073 path_cleanup_cb (void *cls)
4075 struct DistanceVector *dv = cls;
4076 struct DistanceVectorHop *pos;
4078 dv->timeout_task = NULL;
4079 while (NULL != (pos = dv->dv_head))
4081 GNUNET_assert (dv == pos->dv);
4082 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
4084 free_distance_vector_hop (pos);
4091 dv->timeout_task = GNUNET_SCHEDULER_add_at (pos->timeout,
4098 * We have learned a @a path through the network to some other peer, add it to
4099 * our DV data structure (returning #GNUNET_YES on success).
4101 * We do not add paths if we have a sufficient number of shorter
4102 * paths to this target already (returning #GNUNET_NO).
4104 * We also do not add problematic paths, like those where we lack the first
4105 * hop in our neighbour list (i.e. due to a topology change) or where some
4106 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
4108 * @param path the path we learned, path[0] should be us,
4109 * and then path contains a valid path from us to `path[path_len-1]`
4110 * path[1] should be a direct neighbour (we should check!)
4111 * @param path_len number of entries on the @a path, at least three!
4112 * @param network_latency how long does the message take from us to `path[path_len-1]`?
4113 * set to "forever" if unknown
4114 * @return #GNUNET_YES on success,
4115 * #GNUNET_NO if we have better path(s) to the target
4116 * #GNUNET_SYSERR if the path is useless and/or invalid
4117 * (i.e. path[1] not a direct neighbour
4118 * or path[i+1] is a direct neighbour for i>0)
4121 learn_dv_path (const struct GNUNET_PeerIdentity *path,
4122 unsigned int path_len,
4123 struct GNUNET_TIME_Relative network_latency)
4125 struct DistanceVectorHop *hop;
4126 struct DistanceVector *dv;
4127 struct Neighbour *next_hop;
4128 unsigned int shorter_distance;
4132 /* what a boring path! not allowed! */
4134 return GNUNET_SYSERR;
4137 GNUNET_memcmp (&GST_my_identity,
4139 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours,
4141 if (NULL == next_hop)
4143 /* next hop must be a neighbour, otherwise this whole thing is useless! */
4145 return GNUNET_SYSERR;
4147 for (unsigned int i=2;i<path_len;i++)
4149 GNUNET_CONTAINER_multipeermap_get (neighbours,
4152 /* Useless path, we have a direct connection to some hop
4153 in the middle of the path, so this one doesn't even
4154 seem terribly useful for redundancy */
4155 return GNUNET_SYSERR;
4157 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes,
4158 &path[path_len - 1]);
4161 dv = GNUNET_new (struct DistanceVector);
4162 dv->target = path[path_len - 1];
4163 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
4166 GNUNET_assert (GNUNET_OK ==
4167 GNUNET_CONTAINER_multipeermap_put (dv_routes,
4170 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
4172 /* Check if we have this path already! */
4173 shorter_distance = 0;
4174 for (struct DistanceVectorHop *pos = dv->dv_head;
4178 if (pos->distance < path_len - 2)
4180 /* Note that the distances in 'pos' excludes us (path[0]) and
4181 the next_hop (path[1]), so we need to subtract two
4182 and check next_hop explicitly */
4183 if ( (pos->distance == path_len - 2) &&
4184 (pos->next_hop == next_hop) )
4186 int match = GNUNET_YES;
4188 for (unsigned int i=0;i<pos->distance;i++)
4191 GNUNET_memcmp (&pos->path[i],
4198 if (GNUNET_YES == match)
4200 struct GNUNET_TIME_Relative last_timeout;
4202 /* Re-discovered known path, update timeout */
4203 GNUNET_STATISTICS_update (GST_stats,
4204 "# Known DV path refreshed",
4207 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
4209 = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4210 GNUNET_CONTAINER_MDLL_remove (dv,
4214 GNUNET_CONTAINER_MDLL_insert (dv,
4218 if (last_timeout.rel_value_us <
4219 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
4220 DV_PATH_DISCOVERY_FREQUENCY).rel_value_us)
4222 /* Some peer send DV learn messages too often, we are learning
4223 the same path faster than it would be useful; do not forward! */
4230 /* Count how many shorter paths we have (incl. direct
4231 neighbours) before simply giving up on this one! */
4232 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
4234 /* We have a shorter path already! */
4237 /* create new DV path entry */
4238 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
4239 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4240 hop->next_hop = next_hop;
4242 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
4245 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
4246 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
4247 hop->distance = path_len - 2;
4248 GNUNET_CONTAINER_MDLL_insert (dv,
4252 GNUNET_CONTAINER_MDLL_insert (neighbour,
4261 * Communicator gave us a DV learn message. Check the message.
4263 * @param cls a `struct CommunicatorMessageContext`
4264 * @param dvl the send message that was sent
4265 * @return #GNUNET_YES if message is well-formed
4268 check_dv_learn (void *cls,
4269 const struct TransportDVLearn *dvl)
4271 uint16_t size = ntohs (dvl->header.size);
4272 uint16_t num_hops = ntohs (dvl->num_hops);
4273 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4276 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4278 GNUNET_break_op (0);
4279 return GNUNET_SYSERR;
4281 if (num_hops > MAX_DV_HOPS_ALLOWED)
4283 GNUNET_break_op (0);
4284 return GNUNET_SYSERR;
4286 for (unsigned int i=0;i<num_hops;i++)
4288 if (0 == GNUNET_memcmp (&dvl->initiator,
4291 GNUNET_break_op (0);
4292 return GNUNET_SYSERR;
4294 if (0 == GNUNET_memcmp (&GST_my_identity,
4297 GNUNET_break_op (0);
4298 return GNUNET_SYSERR;
4306 * Build and forward a DV learn message to @a next_hop.
4308 * @param next_hop peer to send the message to
4309 * @param msg message received
4310 * @param bi_history bitmask specifying hops on path that were bidirectional
4311 * @param nhops length of the @a hops array
4312 * @param hops path the message traversed so far
4313 * @param in_time when did we receive the message, used to calculate network delay
4316 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4317 const struct TransportDVLearn *msg,
4318 uint16_t bi_history,
4320 const struct DVPathEntryP *hops,
4321 struct GNUNET_TIME_Absolute in_time)
4323 struct DVPathEntryP *dhops;
4324 struct TransportDVLearn *fwd;
4325 struct GNUNET_TIME_Relative nnd;
4327 /* compute message for forwarding */
4328 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4329 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4330 (nhops + 1) * sizeof (struct DVPathEntryP));
4331 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4332 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4333 (nhops + 1) * sizeof (struct DVPathEntryP));
4334 fwd->num_hops = htons (nhops + 1);
4335 fwd->bidirectional = htons (bi_history);
4336 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4337 GNUNET_TIME_relative_ntoh (msg->non_network_delay));
4338 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4339 fwd->init_sig = msg->init_sig;
4340 fwd->initiator = msg->initiator;
4341 fwd->challenge = msg->challenge;
4342 dhops = (struct DVPathEntryP *) &fwd[1];
4343 GNUNET_memcpy (dhops,
4345 sizeof (struct DVPathEntryP) * nhops);
4346 dhops[nhops].hop = GST_my_identity;
4348 struct DvHopPS dhp = {
4349 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4350 .purpose.size = htonl (sizeof (dhp)),
4351 .pred = dhops[nhops-1].hop,
4353 .challenge = msg->challenge
4356 GNUNET_assert (GNUNET_OK ==
4357 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4359 &dhops[nhops].hop_sig));
4361 route_message (next_hop,
4367 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4369 * @param init the signer
4370 * @param challenge the challenge that was signed
4371 * @param init_sig signature presumably by @a init
4372 * @return #GNUNET_OK if the signature is valid
4375 validate_dv_initiator_signature (const struct GNUNET_PeerIdentity *init,
4376 const struct GNUNET_ShortHashCode *challenge,
4377 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4379 struct DvInitPS ip = {
4380 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4381 .purpose.size = htonl (sizeof (ip)),
4382 .challenge = *challenge
4386 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4391 GNUNET_break_op (0);
4392 return GNUNET_SYSERR;
4399 * Communicator gave us a DV learn message. Process the request.
4401 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4402 * @param dvl the message that was received
4405 handle_dv_learn (void *cls,
4406 const struct TransportDVLearn *dvl)
4408 struct CommunicatorMessageContext *cmc = cls;
4409 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
4412 uint16_t bi_history;
4413 const struct DVPathEntryP *hops;
4416 struct GNUNET_TIME_Absolute in_time;
4418 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
4419 bi_history = ntohs (dvl->bidirectional);
4420 hops = (const struct DVPathEntryP *) &dvl[1];
4424 if (0 != GNUNET_memcmp (&dvl->initiator,
4428 finish_cmc_handling (cmc);
4435 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop,
4439 finish_cmc_handling (cmc);
4444 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
4445 cc = cmc->tc->details.communicator.cc;
4446 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE == cc); // FIXME: add bi-directional flag to cc?
4447 in_time = GNUNET_TIME_absolute_get ();
4449 /* continue communicator here, everything else can happen asynchronous! */
4450 finish_cmc_handling (cmc);
4452 // FIXME: should we bother to verify _every_ DV initiator signature?
4454 validate_dv_initiator_signature (&dvl->initiator,
4458 GNUNET_break_op (0);
4461 // FIXME: asynchronously (!) verify hop-by-hop signatures!
4462 // => if signature verification load too high, implement random drop strategy!
4464 do_fwd = GNUNET_YES;
4465 if (0 == GNUNET_memcmp (&GST_my_identity,
4468 struct GNUNET_PeerIdentity path[nhops + 1];
4469 struct GNUNET_TIME_Relative host_latency_sum;
4470 struct GNUNET_TIME_Relative latency;
4471 struct GNUNET_TIME_Relative network_latency;
4473 /* We initiated this, learn the forward path! */
4474 path[0] = GST_my_identity;
4475 path[1] = hops[0].hop;
4476 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
4478 // Need also something to lookup initiation time
4479 // to compute RTT! -> add RTT argument here?
4480 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
4481 // (based on dvl->challenge, we can identify time of origin!)
4483 network_latency = GNUNET_TIME_relative_subtract (latency,
4485 /* assumption: latency on all links is the same */
4486 network_latency = GNUNET_TIME_relative_divide (network_latency,
4489 for (unsigned int i=2;i<=nhops;i++)
4491 struct GNUNET_TIME_Relative ilat;
4493 /* assumption: linear latency increase per hop */
4494 ilat = GNUNET_TIME_relative_multiply (network_latency,
4496 path[i] = hops[i-1].hop;
4497 learn_dv_path (path,
4501 /* as we initiated, do not forward again (would be circular!) */
4507 /* last hop was bi-directional, we could learn something here! */
4508 struct GNUNET_PeerIdentity path[nhops + 2];
4510 path[0] = GST_my_identity;
4511 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
4512 for (unsigned int i=0;i<nhops;i++)
4516 if (0 == (bi_history & (1 << i)))
4517 break; /* i-th hop not bi-directional, stop learning! */
4520 path[i + 2] = dvl->initiator;
4524 path[i + 2] = hops[nhops - i - 2].hop;
4527 iret = learn_dv_path (path,
4529 GNUNET_TIME_UNIT_FOREVER_REL);
4530 if (GNUNET_SYSERR == iret)
4532 /* path invalid or too long to be interesting for US, thus should also
4533 not be interesting to our neighbours, cut path when forwarding to
4534 'i' hops, except of course for the one that goes back to the
4536 GNUNET_STATISTICS_update (GST_stats,
4537 "# DV learn not forwarded due invalidity of path",
4543 if ( (GNUNET_NO == iret) &&
4546 /* we have better paths, and this is the longest target,
4547 so there cannot be anything interesting later */
4548 GNUNET_STATISTICS_update (GST_stats,
4549 "# DV learn not forwarded, got better paths",
4558 if (MAX_DV_HOPS_ALLOWED == nhops)
4560 /* At limit, we're out of here! */
4561 finish_cmc_handling (cmc);
4565 /* Forward to initiator, if path non-trivial and possible */
4566 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
4567 did_initiator = GNUNET_NO;
4570 GNUNET_CONTAINER_multipeermap_contains (neighbours,
4573 /* send back to origin! */
4574 forward_dv_learn (&dvl->initiator,
4580 did_initiator = GNUNET_YES;
4582 /* We forward under two conditions: either we still learned something
4583 ourselves (do_fwd), or the path was darn short and thus the initiator is
4584 likely to still be very interested in this (and we did NOT already
4585 send it back to the initiator) */
4587 ( (nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
4588 (GNUNET_NO == did_initiator) ) )
4590 /* FIXME: loop over all neighbours, pick those with low
4591 queues AND that are not yet on the path; possibly
4592 adapt threshold to nhops! */
4594 forward_dv_learn (NULL, // fill in peer from iterator here!
4606 * Communicator gave us a DV box. Check the message.
4608 * @param cls a `struct CommunicatorMessageContext`
4609 * @param dvb the send message that was sent
4610 * @return #GNUNET_YES if message is well-formed
4613 check_dv_box (void *cls,
4614 const struct TransportDVBox *dvb)
4616 uint16_t size = ntohs (dvb->header.size);
4617 uint16_t num_hops = ntohs (dvb->num_hops);
4618 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
4619 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
4624 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct GNUNET_MessageHeader))
4626 GNUNET_break_op (0);
4627 return GNUNET_SYSERR;
4629 isize = ntohs (inbox->size);
4630 if (size != sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
4632 GNUNET_break_op (0);
4633 return GNUNET_SYSERR;
4635 itype = ntohs (inbox->type);
4636 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
4637 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype) )
4639 GNUNET_break_op (0);
4640 return GNUNET_SYSERR;
4647 * Communicator gave us a DV box. Process the request.
4649 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4650 * @param dvb the message that was received
4653 handle_dv_box (void *cls,
4654 const struct TransportDVBox *dvb)
4656 struct CommunicatorMessageContext *cmc = cls;
4657 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
4658 uint16_t num_hops = ntohs (dvb->num_hops);
4659 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
4660 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
4664 // FIXME: if we are not the target, shorten path and forward along.
4665 // Try from the _end_ of hops array if we know the given
4666 // neighbour (shortening the path!).
4667 // NOTE: increment total_hops!
4668 finish_cmc_handling (cmc);
4671 /* We are the target. Unbox and handle message. */
4672 cmc->im.sender = dvb->origin;
4673 cmc->total_hops = ntohs (dvb->total_hops);
4674 demultiplex_with_cmc (cmc,
4680 * Client notified us about transmission from a peer. Process the request.
4682 * @param cls a `struct TransportClient` which sent us the message
4683 * @param obm the send message that was sent
4684 * @return #GNUNET_YES if message is well-formed
4687 check_incoming_msg (void *cls,
4688 const struct GNUNET_TRANSPORT_IncomingMessage *im)
4690 struct TransportClient *tc = cls;
4692 if (CT_COMMUNICATOR != tc->type)
4695 return GNUNET_SYSERR;
4697 GNUNET_MQ_check_boxed_message (im);
4703 * Communicator gave us a transport address validation challenge. Process the request.
4705 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4706 * @param tvc the message that was received
4709 handle_validation_challenge (void *cls,
4710 const struct TransportValidationChallenge *tvc)
4712 struct CommunicatorMessageContext *cmc = cls;
4713 struct TransportValidationResponse *tvr;
4715 if (cmc->total_hops > 0)
4717 /* DV routing is not allowed for validation challenges! */
4718 GNUNET_break_op (0);
4719 finish_cmc_handling (cmc);
4722 tvr = GNUNET_new (struct TransportValidationResponse);
4723 tvr->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
4724 tvr->header.size = htons (sizeof (*tvr));
4725 tvr->challenge = tvc->challenge;
4726 tvr->origin_time = tvc->sender_time;
4727 tvr->validity_duration = cmc->im.expected_address_validity;
4729 /* create signature */
4730 struct TransportValidationPS tvp = {
4731 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
4732 .purpose.size = htonl (sizeof (tvp)),
4733 .validity_duration = tvr->validity_duration,
4734 .challenge = tvc->challenge
4737 GNUNET_assert (GNUNET_OK ==
4738 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4742 route_message (&cmc->im.sender,
4744 finish_cmc_handling (cmc);
4749 * Closure for #check_known_challenge.
4751 struct CheckKnownChallengeContext
4754 * Set to the challenge we are looking for.
4756 const struct GNUNET_ShortHashCode *challenge;
4759 * Set to a matching validation state, if one was found.
4761 struct ValidationState *vs;
4766 * Test if the validation state in @a value matches the
4767 * challenge from @a cls.
4769 * @param cls a `struct CheckKnownChallengeContext`
4770 * @param pid unused (must match though)
4771 * @param value a `struct ValidationState`
4772 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
4775 check_known_challenge (void *cls,
4776 const struct GNUNET_PeerIdentity *pid,
4779 struct CheckKnownChallengeContext *ckac = cls;
4780 struct ValidationState *vs = value;
4783 if (0 != GNUNET_memcmp (&vs->challenge,
4792 * Function called when peerstore is done storing a
4793 * validated address.
4795 * @param cls a `struct ValidationState`
4796 * @param success #GNUNET_YES on success
4799 peerstore_store_validation_cb (void *cls,
4802 struct ValidationState *vs = cls;
4805 if (GNUNET_YES == success)
4807 GNUNET_STATISTICS_update (GST_stats,
4808 "# Peerstore failed to store foreign address",
4815 * Task run periodically to validate some address based on #validation_heap.
4820 validation_start_cb (void *cls);
4824 * Set the time for next_challenge of @a vs to @a new_time.
4825 * Updates the heap and if necessary reschedules the job.
4827 * @param vs validation state to update
4828 * @param new_time new time for revalidation
4831 update_next_challenge_time (struct ValidationState *vs,
4832 struct GNUNET_TIME_Absolute new_time)
4834 struct GNUNET_TIME_Relative delta;
4836 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
4837 return; /* be lazy */
4838 vs->next_challenge = new_time;
4840 vs->hn = GNUNET_CONTAINER_heap_insert (validation_heap,
4842 new_time.abs_value_us);
4844 GNUNET_CONTAINER_heap_update_cost (vs->hn,
4845 new_time.abs_value_us);
4846 if ( (vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
4847 (NULL != validation_task) )
4849 if (NULL != validation_task)
4850 GNUNET_SCHEDULER_cancel (validation_task);
4851 /* randomize a bit */
4852 delta.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
4853 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
4854 new_time = GNUNET_TIME_absolute_add (new_time,
4856 validation_task = GNUNET_SCHEDULER_add_at (new_time,
4857 &validation_start_cb,
4863 * Communicator gave us a transport address validation response. Process the request.
4865 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4866 * @param tvr the message that was received
4869 handle_validation_response (void *cls,
4870 const struct TransportValidationResponse *tvr)
4872 struct CommunicatorMessageContext *cmc = cls;
4873 struct ValidationState *vs;
4874 struct CheckKnownChallengeContext ckac = {
4875 .challenge = &tvr->challenge,
4878 struct GNUNET_TIME_Absolute origin_time;
4880 /* check this is one of our challenges */
4881 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
4883 &check_known_challenge,
4885 if (NULL == (vs = ckac.vs))
4887 /* This can happen simply if we 'forgot' the challenge by now,
4888 i.e. because we received the validation response twice */
4889 GNUNET_STATISTICS_update (GST_stats,
4890 "# Validations dropped, challenge unknown",
4893 finish_cmc_handling (cmc);
4897 /* sanity check on origin time */
4898 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
4899 if ( (origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
4900 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us) )
4902 GNUNET_break_op (0);
4903 finish_cmc_handling (cmc);
4908 /* check signature */
4909 struct TransportValidationPS tvp = {
4910 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
4911 .purpose.size = htonl (sizeof (tvp)),
4912 .validity_duration = tvr->validity_duration,
4913 .challenge = tvr->challenge
4917 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
4920 &cmc->im.sender.public_key))
4922 GNUNET_break_op (0);
4923 finish_cmc_handling (cmc);
4928 /* validity is capped by our willingness to keep track of the
4929 validation entry and the maximum the other peer allows */
4931 = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (tvr->validity_duration),
4932 MAX_ADDRESS_VALID_UNTIL));
4934 = GNUNET_TIME_absolute_min (vs->valid_until,
4935 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME));
4936 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
4937 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
4938 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4940 sizeof (vs->challenge));
4941 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (vs->validated_until,
4942 GNUNET_TIME_relative_multiply (vs->validation_rtt,
4943 VALIDATION_RTT_BUFFER_FACTOR));
4944 vs->last_challenge_use = GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
4945 update_next_challenge_time (vs,
4946 vs->first_challenge_use);
4947 vs->sc = GNUNET_PEERSTORE_store (peerstore,
4950 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
4952 strlen (vs->address) + 1,
4954 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4955 &peerstore_store_validation_cb,
4957 // FIXME: should we find the matching queue and update the RTT?
4958 finish_cmc_handling (cmc);
4963 * Incoming meessage. Process the request.
4965 * @param im the send message that was received
4968 handle_incoming_msg (void *cls,
4969 const struct GNUNET_TRANSPORT_IncomingMessage *im)
4971 struct TransportClient *tc = cls;
4972 struct CommunicatorMessageContext *cmc = GNUNET_new (struct CommunicatorMessageContext);
4976 demultiplex_with_cmc (cmc,
4977 (const struct GNUNET_MessageHeader *) &im[1]);
4982 * Given an inbound message @a msg from a communicator @a cmc,
4983 * demultiplex it based on the type calling the right handler.
4985 * @param cmc context for demultiplexing
4986 * @param msg message to demultiplex
4989 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4990 const struct GNUNET_MessageHeader *msg)
4992 struct GNUNET_MQ_MessageHandler handlers[] = {
4993 GNUNET_MQ_hd_var_size (fragment_box,
4994 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
4995 struct TransportFragmentBox,
4997 GNUNET_MQ_hd_fixed_size (fragment_ack,
4998 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
4999 struct TransportFragmentAckMessage,
5001 GNUNET_MQ_hd_var_size (reliability_box,
5002 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
5003 struct TransportReliabilityBox,
5005 GNUNET_MQ_hd_fixed_size (reliability_ack,
5006 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
5007 struct TransportReliabilityAckMessage,
5009 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
5010 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
5011 struct TransportBackchannelEncapsulationMessage,
5013 GNUNET_MQ_hd_var_size (dv_learn,
5014 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
5015 struct TransportDVLearn,
5017 GNUNET_MQ_hd_var_size (dv_box,
5018 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
5019 struct TransportDVBox,
5021 GNUNET_MQ_hd_fixed_size (validation_challenge,
5022 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
5023 struct TransportValidationChallenge,
5025 GNUNET_MQ_hd_fixed_size (validation_response,
5026 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
5027 struct TransportValidationResponse,
5029 GNUNET_MQ_handler_end()
5033 ret = GNUNET_MQ_handle_message (handlers,
5035 if (GNUNET_SYSERR == ret)
5038 GNUNET_SERVICE_client_drop (cmc->tc->client);
5042 if (GNUNET_NO == ret)
5044 /* unencapsulated 'raw' message */
5045 handle_raw_message (&cmc,
5052 * New queue became available. Check message.
5054 * @param cls the client
5055 * @param aqm the send message that was sent
5058 check_add_queue_message (void *cls,
5059 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5061 struct TransportClient *tc = cls;
5063 if (CT_COMMUNICATOR != tc->type)
5066 return GNUNET_SYSERR;
5068 GNUNET_MQ_check_zero_termination (aqm);
5074 * Bandwidth tracker informs us that the delay until we should receive
5077 * @param cls a `struct Queue` for which the delay changed
5080 tracker_update_in_cb (void *cls)
5082 struct Queue *queue = cls;
5083 struct GNUNET_TIME_Relative in_delay;
5086 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
5087 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in,
5089 // FIXME: how exactly do we do inbound flow control?
5094 * If necessary, generates the UUID for a @a pm
5096 * @param pm pending message to generate UUID for.
5099 set_pending_message_uuid (struct PendingMessage *pm)
5101 if (pm->msg_uuid_set)
5103 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5105 sizeof (pm->msg_uuid));
5106 pm->msg_uuid_set = GNUNET_YES;
5111 * Fragment the given @a pm to the given @a mtu. Adds
5112 * additional fragments to the neighbour as well. If the
5113 * @a mtu is too small, generates and error for the @a pm
5116 * @param pm pending message to fragment for transmission
5117 * @param mtu MTU to apply
5118 * @return new message to transmit
5120 static struct PendingMessage *
5121 fragment_message (struct PendingMessage *pm,
5124 struct PendingMessage *ff;
5126 set_pending_message_uuid (pm);
5128 /* This invariant is established in #handle_add_queue_message() */
5129 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
5131 /* select fragment for transmission, descending the tree if it has
5132 been expanded until we are at a leaf or at a fragment that is small enough */
5134 while ( ( (ff->bytes_msg > mtu) ||
5136 (ff->frag_off == ff->bytes_msg) &&
5137 (NULL != ff->head_frag) )
5139 ff = ff->head_frag; /* descent into fragmented fragments */
5142 if ( ( (ff->bytes_msg > mtu) ||
5144 (pm->frag_off < pm->bytes_msg) )
5146 /* Did not yet calculate all fragments, calculate next fragment */
5147 struct PendingMessage *frag;
5148 struct TransportFragmentBox tfb;
5156 orig = (const char *) &ff[1];
5157 msize = ff->bytes_msg;
5160 const struct TransportFragmentBox *tfbo;
5162 tfbo = (const struct TransportFragmentBox *) orig;
5163 orig += sizeof (struct TransportFragmentBox);
5164 msize -= sizeof (struct TransportFragmentBox);
5165 xoff = ntohs (tfbo->frag_off);
5167 fragmax = mtu - sizeof (struct TransportFragmentBox);
5168 fragsize = GNUNET_MIN (msize - ff->frag_off,
5170 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
5171 sizeof (struct TransportFragmentBox) +
5173 frag->target = pm->target;
5174 frag->frag_parent = ff;
5175 frag->timeout = pm->timeout;
5176 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
5177 frag->pmt = PMT_FRAGMENT_BOX;
5178 msg = (char *) &frag[1];
5179 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
5180 tfb.header.size = htons (sizeof (struct TransportFragmentBox) +
5182 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
5183 tfb.msg_uuid = pm->msg_uuid;
5184 tfb.frag_off = htons (ff->frag_off + xoff);
5185 tfb.msg_size = htons (pm->bytes_msg);
5189 memcpy (&msg[sizeof (tfb)],
5190 &orig[ff->frag_off],
5192 GNUNET_CONTAINER_MDLL_insert (frag,
5196 ff->frag_off += fragsize;
5200 /* Move head to the tail and return it */
5201 GNUNET_CONTAINER_MDLL_remove (frag,
5202 ff->frag_parent->head_frag,
5203 ff->frag_parent->tail_frag,
5205 GNUNET_CONTAINER_MDLL_insert_tail (frag,
5206 ff->frag_parent->head_frag,
5207 ff->frag_parent->tail_frag,
5214 * Reliability-box the given @a pm. On error (can there be any), NULL
5215 * may be returned, otherwise the "replacement" for @a pm (which
5216 * should then be added to the respective neighbour's queue instead of
5217 * @a pm). If the @a pm is already fragmented or reliability boxed,
5218 * or itself an ACK, this function simply returns @a pm.
5220 * @param pm pending message to box for transmission over unreliabile queue
5221 * @return new message to transmit
5223 static struct PendingMessage *
5224 reliability_box_message (struct PendingMessage *pm)
5226 struct TransportReliabilityBox rbox;
5227 struct PendingMessage *bpm;
5230 if (PMT_CORE != pm->pmt)
5231 return pm; /* already fragmented or reliability boxed, or control message: do nothing */
5232 if (NULL != pm->bpm)
5233 return pm->bpm; /* already computed earlier: do nothing */
5234 GNUNET_assert (NULL == pm->head_frag);
5235 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
5239 client_send_response (pm,
5244 bpm = GNUNET_malloc (sizeof (struct PendingMessage) +
5247 bpm->target = pm->target;
5248 bpm->frag_parent = pm;
5249 GNUNET_CONTAINER_MDLL_insert (frag,
5253 bpm->timeout = pm->timeout;
5254 bpm->pmt = PMT_RELIABILITY_BOX;
5255 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
5256 set_pending_message_uuid (bpm);
5257 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
5258 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
5259 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
5260 rbox.msg_uuid = pm->msg_uuid;
5261 msg = (char *) &bpm[1];
5265 memcpy (&msg[sizeof (rbox)],
5274 * We believe we are ready to transmit a message on a queue. Double-checks
5275 * with the queue's "tracker_out" and then gives the message to the
5276 * communicator for transmission (updating the tracker, and re-scheduling
5277 * itself if applicable).
5279 * @param cls the `struct Queue` to process transmissions for
5282 transmit_on_queue (void *cls)
5284 struct Queue *queue = cls;
5285 struct Neighbour *n = queue->neighbour;
5286 struct PendingMessage *pm;
5287 struct PendingMessage *s;
5289 struct GNUNET_TRANSPORT_SendMessageTo *smt;
5290 struct GNUNET_MQ_Envelope *env;
5292 queue->transmit_task = NULL;
5293 if (NULL == (pm = n->pending_msg_head))
5295 /* no message pending, nothing to do here! */
5298 schedule_transmit_on_queue (queue);
5299 if (NULL != queue->transmit_task)
5300 return; /* do it later */
5302 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5303 overhead += sizeof (struct TransportReliabilityBox);
5305 if ( ( (0 != queue->mtu) &&
5306 (pm->bytes_msg + overhead > queue->mtu) ) ||
5307 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
5308 (NULL != pm->head_frag /* fragments already exist, should
5309 respect that even if MTU is 0 for
5311 s = fragment_message (s,
5313 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
5317 /* Fragmentation failed, try next message... */
5318 schedule_transmit_on_queue (queue);
5321 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5322 s = reliability_box_message (s);
5325 /* Reliability boxing failed, try next message... */
5326 schedule_transmit_on_queue (queue);
5330 /* Pass 's' for transission to the communicator */
5331 env = GNUNET_MQ_msg_extra (smt,
5333 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
5334 smt->qid = queue->qid;
5335 smt->mid = queue->mid_gen;
5336 smt->receiver = n->pid;
5341 /* Pass the env to the communicator of queue for transmission. */
5342 struct QueueEntry *qe;
5344 qe = GNUNET_new (struct QueueEntry);
5345 qe->mid = queue->mid_gen++;
5347 // qe->pm = s; // FIXME: not so easy, reference management on 'free(s)'!
5348 GNUNET_CONTAINER_DLL_insert (queue->queue_head,
5351 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5352 queue->queue_length++;
5353 queue->tc->details.communicator.total_queue_length++;
5354 GNUNET_MQ_send (queue->tc->mq,
5358 // FIXME: do something similar to the logic below
5359 // in defragmentation / reliability ACK handling!
5361 /* Check if this transmission somehow conclusively finished handing 'pm'
5362 even without any explicit ACKs */
5363 if ( (PMT_CORE == s->pmt) &&
5364 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) )
5366 /* Full message sent, and over reliabile channel */
5367 client_send_response (pm,
5371 else if ( (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) &&
5372 (PMT_FRAGMENT_BOX == s->pmt) )
5374 struct PendingMessage *pos;
5376 /* Fragment sent over reliabile channel */
5377 free_fragment_tree (s);
5378 pos = s->frag_parent;
5379 GNUNET_CONTAINER_MDLL_remove (frag,
5384 /* check if subtree is done */
5385 while ( (NULL == pos->head_frag) &&
5386 (pos->frag_off == pos->bytes_msg) &&
5390 pos = s->frag_parent;
5391 GNUNET_CONTAINER_MDLL_remove (frag,
5398 /* Was this the last applicable fragmment? */
5399 if ( (NULL == pm->head_frag) &&
5400 (pm->frag_off == pm->bytes_msg) )
5401 client_send_response (pm,
5403 pm->bytes_msg /* FIXME: calculate and add overheads! */);
5405 else if (PMT_CORE != pm->pmt)
5407 /* This was an acknowledgement of some type, always free */
5408 free_pending_message (pm);
5412 /* message not finished, waiting for acknowledgement */
5413 struct Neighbour *neighbour = pm->target;
5414 /* Update time by which we might retransmit 's' based on queue
5415 characteristics (i.e. RTT); it takes one RTT for the message to
5416 arrive and the ACK to come back in the best case; but the other
5417 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
5418 retransmitting. Note that in the future this heuristic should
5419 likely be improved further (measure RTT stability, consider
5420 message urgency and size when delaying ACKs, etc.) */
5421 s->next_attempt = GNUNET_TIME_relative_to_absolute
5422 (GNUNET_TIME_relative_multiply (queue->rtt,
5426 struct PendingMessage *pos;
5428 /* re-insert sort in neighbour list */
5429 GNUNET_CONTAINER_MDLL_remove (neighbour,
5430 neighbour->pending_msg_head,
5431 neighbour->pending_msg_tail,
5433 pos = neighbour->pending_msg_tail;
5434 while ( (NULL != pos) &&
5435 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5436 pos = pos->prev_neighbour;
5437 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
5438 neighbour->pending_msg_head,
5439 neighbour->pending_msg_tail,
5445 /* re-insert sort in fragment list */
5446 struct PendingMessage *fp = s->frag_parent;
5447 struct PendingMessage *pos;
5449 GNUNET_CONTAINER_MDLL_remove (frag,
5453 pos = fp->tail_frag;
5454 while ( (NULL != pos) &&
5455 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5456 pos = pos->prev_frag;
5457 GNUNET_CONTAINER_MDLL_insert_after (frag,
5465 /* finally, re-schedule queue transmission task itself */
5466 schedule_transmit_on_queue (queue);
5471 * Bandwidth tracker informs us that the delay until we
5472 * can transmit again changed.
5474 * @param cls a `struct Queue` for which the delay changed
5477 tracker_update_out_cb (void *cls)
5479 struct Queue *queue = cls;
5480 struct Neighbour *n = queue->neighbour;
5482 if (NULL == n->pending_msg_head)
5484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5485 "Bandwidth allocation updated for empty transmission queue `%s'\n",
5487 return; /* no message pending, nothing to do here! */
5489 GNUNET_SCHEDULER_cancel (queue->transmit_task);
5490 queue->transmit_task = NULL;
5491 schedule_transmit_on_queue (queue);
5496 * Bandwidth tracker informs us that excessive outbound bandwidth was
5497 * allocated which is not being used.
5499 * @param cls a `struct Queue` for which the excess was noted
5502 tracker_excess_out_cb (void *cls)
5506 /* FIXME: trigger excess bandwidth report to core? Right now,
5507 this is done internally within transport_api2_core already,
5508 but we probably want to change the logic and trigger it
5509 from here via a message instead! */
5510 /* TODO: maybe inform someone at this point? */
5511 GNUNET_STATISTICS_update (GST_stats,
5512 "# Excess outbound bandwidth reported",
5520 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
5521 * which is not being used.
5523 * @param cls a `struct Queue` for which the excess was noted
5526 tracker_excess_in_cb (void *cls)
5530 /* TODO: maybe inform somone at this point? */
5531 GNUNET_STATISTICS_update (GST_stats,
5532 "# Excess inbound bandwidth reported",
5539 * Queue to a peer went down. Process the request.
5541 * @param cls the client
5542 * @param dqm the send message that was sent
5545 handle_del_queue_message (void *cls,
5546 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
5548 struct TransportClient *tc = cls;
5550 if (CT_COMMUNICATOR != tc->type)
5553 GNUNET_SERVICE_client_drop (tc->client);
5556 for (struct Queue *queue = tc->details.communicator.queue_head;
5558 queue = queue->next_client)
5560 struct Neighbour *neighbour = queue->neighbour;
5562 if ( (dqm->qid != queue->qid) ||
5563 (0 != GNUNET_memcmp (&dqm->receiver,
5567 GNUNET_SERVICE_client_continue (tc->client);
5571 GNUNET_SERVICE_client_drop (tc->client);
5576 * Message was transmitted. Process the request.
5578 * @param cls the client
5579 * @param sma the send message that was sent
5582 handle_send_message_ack (void *cls,
5583 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
5585 struct TransportClient *tc = cls;
5586 struct QueueEntry *qe;
5588 if (CT_COMMUNICATOR != tc->type)
5591 GNUNET_SERVICE_client_drop (tc->client);
5595 /* find our queue entry matching the ACK */
5597 for (struct Queue *queue = tc->details.communicator.queue_head;
5599 queue = queue->next_client)
5601 if (0 != GNUNET_memcmp (&queue->neighbour->pid,
5604 for (struct QueueEntry *qep = queue->queue_head;
5608 if (qep->mid != sma->mid)
5617 /* this should never happen */
5619 GNUNET_SERVICE_client_drop (tc->client);
5622 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
5623 qe->queue->queue_tail,
5625 qe->queue->queue_length--;
5626 tc->details.communicator.total_queue_length--;
5627 GNUNET_SERVICE_client_continue (tc->client);
5629 /* if applicable, resume transmissions that waited on ACK */
5630 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 == tc->details.communicator.total_queue_length)
5632 /* Communicator dropped below threshold, resume all queues */
5633 GNUNET_STATISTICS_update (GST_stats,
5634 "# Transmission throttled due to communicator queue limit",
5637 for (struct Queue *queue = tc->details.communicator.queue_head;
5639 queue = queue->next_client)
5640 schedule_transmit_on_queue (queue);
5642 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
5644 /* queue dropped below threshold; only resume this one queue */
5645 GNUNET_STATISTICS_update (GST_stats,
5646 "# Transmission throttled due to queue queue limit",
5649 schedule_transmit_on_queue (qe->queue);
5652 /* TODO: we also should react on the status! */
5653 // FIXME: this probably requires queue->pm = s assignment!
5654 // FIXME: react to communicator status about transmission request. We got:
5655 sma->status; // OK success, SYSERR failure
5662 * Iterator telling new MONITOR client about all existing
5665 * @param cls the new `struct TransportClient`
5666 * @param pid a connected peer
5667 * @param value the `struct Neighbour` with more information
5668 * @return #GNUNET_OK (continue to iterate)
5671 notify_client_queues (void *cls,
5672 const struct GNUNET_PeerIdentity *pid,
5675 struct TransportClient *tc = cls;
5676 struct Neighbour *neighbour = value;
5678 GNUNET_assert (CT_MONITOR == tc->type);
5679 for (struct Queue *q = neighbour->queue_head;
5681 q = q->next_neighbour)
5683 struct MonitorEvent me = {
5686 .num_msg_pending = q->num_msg_pending,
5687 .num_bytes_pending = q->num_bytes_pending
5701 * Initialize a monitor client.
5703 * @param cls the client
5704 * @param start the start message that was sent
5707 handle_monitor_start (void *cls,
5708 const struct GNUNET_TRANSPORT_MonitorStart *start)
5710 struct TransportClient *tc = cls;
5712 if (CT_NONE != tc->type)
5715 GNUNET_SERVICE_client_drop (tc->client);
5718 tc->type = CT_MONITOR;
5719 tc->details.monitor.peer = start->peer;
5720 tc->details.monitor.one_shot = ntohl (start->one_shot);
5721 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
5722 ¬ify_client_queues,
5724 GNUNET_SERVICE_client_mark_monitor (tc->client);
5725 GNUNET_SERVICE_client_continue (tc->client);
5730 * Find transport client providing communication service
5731 * for the protocol @a prefix.
5733 * @param prefix communicator name
5734 * @return NULL if no such transport client is available
5736 static struct TransportClient *
5737 lookup_communicator (const char *prefix)
5739 for (struct TransportClient *tc = clients_head;
5743 if (CT_COMMUNICATOR != tc->type)
5745 if (0 == strcmp (prefix,
5746 tc->details.communicator.address_prefix))
5749 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5750 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
5757 * Signature of a function called with a communicator @a address of a peer
5758 * @a pid that an application wants us to connect to.
5760 * @param pid target peer
5761 * @param address the address to try
5764 suggest_to_connect (const struct GNUNET_PeerIdentity *pid,
5765 const char *address)
5767 static uint32_t idgen;
5768 struct TransportClient *tc;
5770 struct GNUNET_TRANSPORT_CreateQueue *cqm;
5771 struct GNUNET_MQ_Envelope *env;
5774 prefix = GNUNET_HELLO_address_to_prefix (address);
5777 GNUNET_break (0); /* We got an invalid address!? */
5780 tc = lookup_communicator (prefix);
5783 GNUNET_STATISTICS_update (GST_stats,
5784 "# Suggestions ignored due to missing communicator",
5789 /* forward suggestion for queue creation to communicator */
5790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5791 "Request #%u for `%s' communicator to create queue to `%s'\n",
5792 (unsigned int) idgen,
5795 alen = strlen (address) + 1;
5796 env = GNUNET_MQ_msg_extra (cqm,
5798 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
5799 cqm->request_id = htonl (idgen++);
5800 cqm->receiver = *pid;
5804 GNUNET_MQ_send (tc->mq,
5810 * The queue @a q (which matches the peer and address in @a vs) is
5811 * ready for queueing. We should now queue the validation request.
5813 * @param q queue to send on
5814 * @param vs state to derive validation challenge from
5817 validation_transmit_on_queue (struct Queue *q,
5818 struct ValidationState *vs)
5820 struct GNUNET_MQ_Envelope *env;
5821 struct TransportValidationChallenge *tvc;
5823 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
5824 env = GNUNET_MQ_msg (tvc,
5825 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
5826 tvc->reserved = htonl (0);
5827 tvc->challenge = vs->challenge;
5828 tvc->sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
5829 // FIXME: not so easy, need to BOX this message
5830 // in a transmission request! (mistake also done elsewhere!)
5831 GNUNET_MQ_send (q->tc->mq,
5837 * Task run periodically to validate some address based on #validation_heap.
5842 validation_start_cb (void *cls)
5844 struct ValidationState *vs;
5845 struct Neighbour *n;
5849 validation_task = NULL;
5850 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
5851 /* drop validations past their expiration */
5852 while ( (NULL != vs) &&
5853 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us) )
5855 free_validation_state (vs);
5856 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
5859 return; /* woopsie, no more addresses known, should only
5860 happen if we're really a lonely peer */
5861 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
5866 for (struct Queue *pos = n->queue_head;
5868 pos = pos->next_neighbour)
5870 if (0 == strcmp (pos->address,
5880 vs->awaiting_queue = GNUNET_YES;
5881 suggest_to_connect (&vs->pid,
5885 validation_transmit_on_queue (q,
5887 /* Finally, reschedule next attempt */
5888 vs->challenge_backoff = GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
5889 MAX_VALIDATION_CHALLENGE_FREQ);
5890 update_next_challenge_time (vs,
5891 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
5896 * Closure for #check_connection_quality.
5898 struct QueueQualityContext
5901 * Set to the @e k'th queue encountered.
5906 * Set to the number of quality queues encountered.
5908 unsigned int quality_count;
5911 * Set to the total number of queues encountered.
5913 unsigned int num_queues;
5916 * Decremented for each queue, for selection of the
5917 * k-th queue in @e q.
5925 * Check whether any queue to the given neighbour is
5926 * of a good "quality" and if so, increment the counter.
5927 * Also counts the total number of queues, and returns
5928 * the k-th queue found.
5930 * @param cls a `struct QueueQualityContext *` with counters
5931 * @param pid peer this is about
5932 * @param value a `struct Neighbour`
5933 * @return #GNUNET_OK (continue to iterate)
5936 check_connection_quality (void *cls,
5937 const struct GNUNET_PeerIdentity *pid,
5940 struct QueueQualityContext *ctx = cls;
5941 struct Neighbour *n = value;
5946 for (struct Queue *q = n->queue_head;
5948 q = q->next_neighbour)
5950 if (0 != q->distance)
5951 continue; /* DV does not count */
5955 /* OPTIMIZE-FIXME: in the future, add reliability / goodput
5956 statistics and consider those as well here? */
5957 if (q->rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
5958 do_inc = GNUNET_YES;
5960 if (GNUNET_YES == do_inc)
5961 ctx->quality_count++;
5967 * Task run when we CONSIDER initiating a DV learn
5968 * process. We first check that sending out a message is
5969 * even possible (queues exist), then that it is desirable
5970 * (if not, reschedule the task for later), and finally
5971 * we may then begin the job. If there are too many
5972 * entries in the #dvlearn_map, we purge the oldest entry
5978 start_dv_learn (void *cls)
5980 struct LearnLaunchEntry *lle;
5981 struct QueueQualityContext qqc;
5982 struct GNUNET_MQ_Envelope *env;
5983 struct TransportDVLearn *dvl;
5986 dvlearn_task = NULL;
5988 GNUNET_CONTAINER_multipeermap_size (neighbours))
5989 return; /* lost all connectivity, cannot do learning */
5990 qqc.quality_count = 0;
5992 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
5993 &check_connection_quality,
5995 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
5997 struct GNUNET_TIME_Relative delay;
5998 unsigned int factor;
6000 /* scale our retries by how far we are above the threshold */
6001 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
6002 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY,
6004 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay,
6009 /* remove old entries in #dvlearn_map if it has grown too big */
6010 while (MAX_DV_LEARN_PENDING >=
6011 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
6014 GNUNET_assert (GNUNET_YES ==
6015 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
6018 GNUNET_CONTAINER_DLL_remove (lle_head,
6023 /* setup data structure for learning */
6024 lle = GNUNET_new (struct LearnLaunchEntry);
6025 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6027 sizeof (lle->challenge));
6028 GNUNET_CONTAINER_DLL_insert (lle_head,
6031 GNUNET_break (GNUNET_YES ==
6032 GNUNET_CONTAINER_multishortmap_put (dvlearn_map,
6035 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6036 env = GNUNET_MQ_msg (dvl,
6037 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6038 dvl->num_hops = htons (0);
6039 dvl->bidirectional = htons (0);
6040 dvl->non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
6042 struct DvInitPS dvip = {
6043 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6044 .purpose.size = htonl (sizeof (dvip)),
6045 .challenge = lle->challenge
6048 GNUNET_assert (GNUNET_OK ==
6049 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6053 dvl->initiator = GST_my_identity;
6054 dvl->challenge = lle->challenge;
6056 qqc.quality_count = 0;
6057 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
6061 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6062 &check_connection_quality,
6064 GNUNET_assert (NULL != qqc.q);
6066 /* Do this as close to transmission time as possible! */
6067 lle->launch_time = GNUNET_TIME_absolute_get ();
6068 // FIXME: not so easy, need to BOX this message
6069 // in a transmission request! (mistake also done elsewhere!)
6070 GNUNET_MQ_send (qqc.q->tc->mq,
6073 /* reschedule this job, randomizing the time it runs (but no
6076 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (DV_LEARN_BASE_FREQUENCY),
6083 * A new queue has been created, check if any address validation
6084 * requests have been waiting for it.
6086 * @param cls a `struct Queue`
6087 * @param pid peer concerned (unused)
6088 * @param value a `struct ValidationState`
6089 * @return #GNUNET_NO if a match was found and we can stop looking
6092 check_validation_request_pending (void *cls,
6093 const struct GNUNET_PeerIdentity *pid,
6096 struct Queue *q = cls;
6097 struct ValidationState *vs = value;
6100 if ( (GNUNET_YES == vs->awaiting_queue) &&
6101 (0 == strcmp (vs->address,
6104 vs->awaiting_queue = GNUNET_NO;
6105 validation_transmit_on_queue (q,
6114 * New queue became available. Process the request.
6116 * @param cls the client
6117 * @param aqm the send message that was sent
6120 handle_add_queue_message (void *cls,
6121 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
6123 struct TransportClient *tc = cls;
6124 struct Queue *queue;
6125 struct Neighbour *neighbour;
6129 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
6131 /* MTU so small as to be useless for transmissions,
6132 required for #fragment_message()! */
6133 GNUNET_break_op (0);
6134 GNUNET_SERVICE_client_drop (tc->client);
6137 neighbour = lookup_neighbour (&aqm->receiver);
6138 if (NULL == neighbour)
6140 neighbour = GNUNET_new (struct Neighbour);
6141 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
6142 neighbour->pid = aqm->receiver;
6143 GNUNET_assert (GNUNET_OK ==
6144 GNUNET_CONTAINER_multipeermap_put (neighbours,
6147 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6148 cores_send_connect_info (&neighbour->pid,
6149 GNUNET_BANDWIDTH_ZERO);
6151 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
6152 addr = (const char *) &aqm[1];
6154 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
6156 queue->address = (const char *) &queue[1];
6157 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6158 queue->qid = aqm->qid;
6159 queue->mtu = ntohl (aqm->mtu);
6160 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
6161 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
6162 queue->neighbour = neighbour;
6163 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
6164 &tracker_update_in_cb,
6166 GNUNET_BANDWIDTH_ZERO,
6167 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6168 &tracker_excess_in_cb,
6170 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
6171 &tracker_update_out_cb,
6173 GNUNET_BANDWIDTH_ZERO,
6174 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
6175 &tracker_excess_out_cb,
6180 /* notify monitors about new queue */
6182 struct MonitorEvent me = {
6187 notify_monitors (&neighbour->pid,
6192 GNUNET_CONTAINER_MDLL_insert (neighbour,
6193 neighbour->queue_head,
6194 neighbour->queue_tail,
6196 GNUNET_CONTAINER_MDLL_insert (client,
6197 tc->details.communicator.queue_head,
6198 tc->details.communicator.queue_tail,
6200 /* check if valdiations are waiting for the queue */
6201 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6203 &check_validation_request_pending,
6205 /* might be our first queue, try launching DV learning */
6206 if (NULL == dvlearn_task)
6207 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn,
6209 GNUNET_SERVICE_client_continue (tc->client);
6214 * Communicator tells us that our request to create a queue "worked", that
6215 * is setting up the queue is now in process.
6217 * @param cls the `struct TransportClient`
6218 * @param cqr confirmation message
6221 handle_queue_create_ok (void *cls,
6222 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6224 struct TransportClient *tc = cls;
6226 if (CT_COMMUNICATOR != tc->type)
6229 GNUNET_SERVICE_client_drop (tc->client);
6232 GNUNET_STATISTICS_update (GST_stats,
6233 "# Suggestions succeeded at communicator",
6236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6237 "Request #%u for communicator to create queue succeeded\n",
6238 (unsigned int) ntohs (cqr->request_id));
6239 GNUNET_SERVICE_client_continue (tc->client);
6244 * Communicator tells us that our request to create a queue failed. This usually
6245 * indicates that the provided address is simply invalid or that the communicator's
6246 * resources are exhausted.
6248 * @param cls the `struct TransportClient`
6249 * @param cqr failure message
6252 handle_queue_create_fail (void *cls,
6253 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
6255 struct TransportClient *tc = cls;
6257 if (CT_COMMUNICATOR != tc->type)
6260 GNUNET_SERVICE_client_drop (tc->client);
6263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6264 "Request #%u for communicator to create queue failed\n",
6265 (unsigned int) ntohs (cqr->request_id));
6266 GNUNET_STATISTICS_update (GST_stats,
6267 "# Suggestions failed in queue creation at communicator",
6270 GNUNET_SERVICE_client_continue (tc->client);
6275 * We have received a `struct ExpressPreferenceMessage` from an application client.
6277 * @param cls handle to the client
6278 * @param msg the start message
6281 handle_suggest_cancel (void *cls,
6282 const struct ExpressPreferenceMessage *msg)
6284 struct TransportClient *tc = cls;
6285 struct PeerRequest *pr;
6287 if (CT_APPLICATION != tc->type)
6290 GNUNET_SERVICE_client_drop (tc->client);
6293 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
6298 GNUNET_SERVICE_client_drop (tc->client);
6301 (void) stop_peer_request (tc,
6304 GNUNET_SERVICE_client_continue (tc->client);
6309 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
6310 * messages. We do nothing here, real verification is done later.
6312 * @param cls a `struct TransportClient *`
6313 * @param msg message to verify
6314 * @return #GNUNET_OK
6317 check_address_consider_verify (void *cls,
6318 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6327 * Closure for #check_known_address.
6329 struct CheckKnownAddressContext
6332 * Set to the address we are looking for.
6334 const char *address;
6337 * Set to a matching validation state, if one was found.
6339 struct ValidationState *vs;
6344 * Test if the validation state in @a value matches the
6345 * address from @a cls.
6347 * @param cls a `struct CheckKnownAddressContext`
6348 * @param pid unused (must match though)
6349 * @param value a `struct ValidationState`
6350 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
6353 check_known_address (void *cls,
6354 const struct GNUNET_PeerIdentity *pid,
6357 struct CheckKnownAddressContext *ckac = cls;
6358 struct ValidationState *vs = value;
6361 if (0 != strcmp (vs->address,
6370 * Start address validation.
6372 * @param pid peer the @a address is for
6373 * @param address an address to reach @a pid (presumably)
6374 * @param expiration when did @a pid claim @a address will become invalid
6377 start_address_validation (const struct GNUNET_PeerIdentity *pid,
6378 const char *address,
6379 struct GNUNET_TIME_Absolute expiration)
6381 struct GNUNET_TIME_Absolute now;
6382 struct ValidationState *vs;
6383 struct CheckKnownAddressContext ckac = {
6388 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
6389 return; /* expired */
6390 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
6392 &check_known_address,
6394 if (NULL != (vs = ckac.vs))
6396 /* if 'vs' is not currently valid, we need to speed up retrying the validation */
6397 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
6399 /* reduce backoff as we got a fresh advertisement */
6400 vs->challenge_backoff = GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
6401 GNUNET_TIME_relative_divide (vs->challenge_backoff,
6403 update_next_challenge_time (vs,
6404 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
6408 now = GNUNET_TIME_absolute_get();
6409 vs = GNUNET_new (struct ValidationState);
6411 vs->valid_until = expiration;
6412 vs->first_challenge_use = now;
6413 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
6414 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
6416 sizeof (vs->challenge));
6417 vs->address = GNUNET_strdup (address);
6418 GNUNET_assert (GNUNET_YES ==
6419 GNUNET_CONTAINER_multipeermap_put (validation_map,
6422 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6423 update_next_challenge_time (vs,
6429 * Function called by PEERSTORE for each matching record.
6431 * @param cls closure
6432 * @param record peerstore record information
6433 * @param emsg error message, or NULL if no errors
6436 handle_hello (void *cls,
6437 const struct GNUNET_PEERSTORE_Record *record,
6440 struct PeerRequest *pr = cls;
6445 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6446 "Got failure from PEERSTORE: %s\n",
6450 val = record->value;
6451 if ( (0 == record->value_size) ||
6452 ('\0' != val[record->value_size - 1]) )
6457 start_address_validation (&pr->pid,
6458 (const char *) record->value,
6464 * We have received a `struct ExpressPreferenceMessage` from an application client.
6466 * @param cls handle to the client
6467 * @param msg the start message
6470 handle_suggest (void *cls,
6471 const struct ExpressPreferenceMessage *msg)
6473 struct TransportClient *tc = cls;
6474 struct PeerRequest *pr;
6476 if (CT_NONE == tc->type)
6478 tc->type = CT_APPLICATION;
6479 tc->details.application.requests
6480 = GNUNET_CONTAINER_multipeermap_create (16,
6483 if (CT_APPLICATION != tc->type)
6486 GNUNET_SERVICE_client_drop (tc->client);
6489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6490 "Client suggested we talk to %s with preference %d at rate %u\n",
6491 GNUNET_i2s (&msg->peer),
6492 (int) ntohl (msg->pk),
6493 (int) ntohl (msg->bw.value__));
6494 pr = GNUNET_new (struct PeerRequest);
6496 pr->pid = msg->peer;
6498 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
6500 GNUNET_CONTAINER_multipeermap_put (tc->details.application.requests,
6503 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
6507 GNUNET_SERVICE_client_drop (tc->client);
6510 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
6513 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
6516 GNUNET_SERVICE_client_continue (tc->client);
6521 * Given another peers address, consider checking it for validity
6522 * and then adding it to the Peerstore.
6524 * @param cls a `struct TransportClient`
6525 * @param hdr message containing the raw address data and
6526 * signature in the body, see #GNUNET_HELLO_extract_address()
6529 handle_address_consider_verify (void *cls,
6530 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6532 struct TransportClient *tc = cls;
6534 enum GNUNET_NetworkType nt;
6535 struct GNUNET_TIME_Absolute expiration;
6538 // FIXME: checking that we know this address already should
6539 // be done BEFORE checking the signature => HELLO API change!
6540 // FIXME: pre-check: rate-limit signature verification / validation?!
6541 address = GNUNET_HELLO_extract_address (&hdr[1],
6542 ntohs (hdr->header.size) - sizeof (*hdr),
6546 if (NULL == address)
6548 GNUNET_break_op (0);
6551 start_address_validation (&hdr->peer,
6554 GNUNET_free (address);
6555 GNUNET_SERVICE_client_continue (tc->client);
6560 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
6563 * @param cls a `struct TransportClient *`
6564 * @param m message to verify
6565 * @return #GNUNET_OK on success
6568 check_request_hello_validation (void *cls,
6569 const struct RequestHelloValidationMessage *m)
6572 GNUNET_MQ_check_zero_termination (m);
6578 * A client encountered an address of another peer. Consider validating it,
6579 * and if validation succeeds, persist it to PEERSTORE.
6581 * @param cls a `struct TransportClient *`
6582 * @param m message to verify
6585 handle_request_hello_validation (void *cls,
6586 const struct RequestHelloValidationMessage *m)
6588 struct TransportClient *tc = cls;
6590 start_address_validation (&m->peer,
6591 (const char *) &m[1],
6592 GNUNET_TIME_absolute_ntoh (m->expiration));
6593 GNUNET_SERVICE_client_continue (tc->client);
6598 * Free neighbour entry.
6602 * @param value a `struct Neighbour`
6603 * @return #GNUNET_OK (always)
6606 free_neighbour_cb (void *cls,
6607 const struct GNUNET_PeerIdentity *pid,
6610 struct Neighbour *neighbour = value;
6614 GNUNET_break (0); // should this ever happen?
6615 free_neighbour (neighbour);
6622 * Free DV route entry.
6626 * @param value a `struct DistanceVector`
6627 * @return #GNUNET_OK (always)
6630 free_dv_routes_cb (void *cls,
6631 const struct GNUNET_PeerIdentity *pid,
6634 struct DistanceVector *dv = value;
6645 * Free ephemeral entry.
6649 * @param value a `struct EphemeralCacheEntry`
6650 * @return #GNUNET_OK (always)
6653 free_ephemeral_cb (void *cls,
6654 const struct GNUNET_PeerIdentity *pid,
6657 struct EphemeralCacheEntry *ece = value;
6661 free_ephemeral (ece);
6667 * Free validation state.
6671 * @param value a `struct ValidationState`
6672 * @return #GNUNET_OK (always)
6675 free_validation_state_cb (void *cls,
6676 const struct GNUNET_PeerIdentity *pid,
6679 struct ValidationState *vs = value;
6683 free_validation_state (vs);
6689 * Function called when the service shuts down. Unloads our plugins
6690 * and cancels pending validations.
6692 * @param cls closure, unused
6695 do_shutdown (void *cls)
6697 struct LearnLaunchEntry *lle;
6700 if (NULL != ephemeral_task)
6702 GNUNET_SCHEDULER_cancel (ephemeral_task);
6703 ephemeral_task = NULL;
6705 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6708 if (NULL != peerstore)
6710 GNUNET_PEERSTORE_disconnect (peerstore,
6714 if (NULL != GST_stats)
6716 GNUNET_STATISTICS_destroy (GST_stats,
6720 if (NULL != GST_my_private_key)
6722 GNUNET_free (GST_my_private_key);
6723 GST_my_private_key = NULL;
6725 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
6727 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
6728 &free_validation_state_cb,
6730 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
6731 validation_map = NULL;
6732 while (NULL != (lle = lle_head))
6734 GNUNET_CONTAINER_DLL_remove (lle_head,
6739 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
6741 GNUNET_CONTAINER_heap_destroy (validation_heap);
6742 validation_heap = NULL;
6743 GNUNET_CONTAINER_multipeermap_iterate (dv_routes,
6746 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
6748 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
6751 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
6752 ephemeral_map = NULL;
6753 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
6754 ephemeral_heap = NULL;
6759 * Initiate transport service.
6761 * @param cls closure
6762 * @param c configuration to use
6763 * @param service the initialized service
6767 const struct GNUNET_CONFIGURATION_Handle *c,
6768 struct GNUNET_SERVICE_Handle *service)
6774 neighbours = GNUNET_CONTAINER_multipeermap_create (1024,
6776 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024,
6778 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32,
6780 ephemeral_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
6781 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
6783 validation_map = GNUNET_CONTAINER_multipeermap_create (1024,
6785 validation_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
6786 GST_my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
6787 if (NULL == GST_my_private_key)
6789 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6790 _("Transport service is lacking key configuration settings. Exiting.\n"));
6791 GNUNET_SCHEDULER_shutdown ();
6794 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
6795 &GST_my_identity.public_key);
6796 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
6797 "My identity is `%s'\n",
6798 GNUNET_i2s_full (&GST_my_identity));
6799 GST_stats = GNUNET_STATISTICS_create ("transport",
6801 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
6803 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
6804 if (NULL == peerstore)
6807 GNUNET_SCHEDULER_shutdown ();
6814 * Define "main" method using service macro.
6818 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
6821 &client_disconnect_cb,
6823 /* communication with applications */
6824 GNUNET_MQ_hd_fixed_size (suggest,
6825 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
6826 struct ExpressPreferenceMessage,
6828 GNUNET_MQ_hd_fixed_size (suggest_cancel,
6829 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
6830 struct ExpressPreferenceMessage,
6832 GNUNET_MQ_hd_var_size (request_hello_validation,
6833 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
6834 struct RequestHelloValidationMessage,
6836 /* communication with core */
6837 GNUNET_MQ_hd_fixed_size (client_start,
6838 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
6839 struct StartMessage,
6841 GNUNET_MQ_hd_var_size (client_send,
6842 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
6843 struct OutboundMessage,
6845 /* communication with communicators */
6846 GNUNET_MQ_hd_var_size (communicator_available,
6847 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
6848 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
6850 GNUNET_MQ_hd_var_size (communicator_backchannel,
6851 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
6852 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
6854 GNUNET_MQ_hd_var_size (add_address,
6855 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
6856 struct GNUNET_TRANSPORT_AddAddressMessage,
6858 GNUNET_MQ_hd_fixed_size (del_address,
6859 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
6860 struct GNUNET_TRANSPORT_DelAddressMessage,
6862 GNUNET_MQ_hd_var_size (incoming_msg,
6863 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
6864 struct GNUNET_TRANSPORT_IncomingMessage,
6866 GNUNET_MQ_hd_fixed_size (queue_create_ok,
6867 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
6868 struct GNUNET_TRANSPORT_CreateQueueResponse,
6870 GNUNET_MQ_hd_fixed_size (queue_create_fail,
6871 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
6872 struct GNUNET_TRANSPORT_CreateQueueResponse,
6874 GNUNET_MQ_hd_var_size (add_queue_message,
6875 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
6876 struct GNUNET_TRANSPORT_AddQueueMessage,
6878 GNUNET_MQ_hd_var_size (address_consider_verify,
6879 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
6880 struct GNUNET_TRANSPORT_AddressToVerify,
6882 GNUNET_MQ_hd_fixed_size (del_queue_message,
6883 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
6884 struct GNUNET_TRANSPORT_DelQueueMessage,
6886 GNUNET_MQ_hd_fixed_size (send_message_ack,
6887 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
6888 struct GNUNET_TRANSPORT_SendMessageToAck,
6890 /* communication with monitors */
6891 GNUNET_MQ_hd_fixed_size (monitor_start,
6892 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
6893 struct GNUNET_TRANSPORT_MonitorStart,
6895 GNUNET_MQ_handler_end ());
6898 /* end of file gnunet-service-transport.c */