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 * - DV data structures:
37 * + initiation of DV learn (incl. RTT measurement logic!)
38 * - security considerations? add signatures to routes? initiator signature?
40 * - handling of DV-boxed messages that need to be forwarded
41 * - route_message implementation, including using DV data structures
42 * (but not when routing certain message types, like DV learn,
43 * MUST pay attention to content here -- or pass extra flags?)
44 * - ACK handling / retransmission
45 * - track RTT, distance, loss, etc.
46 * - backchannel message encryption & decryption
49 * - change transport-core API to provide proper flow control in both
50 * directions, allow multiple messages per peer simultaneously (tag
51 * confirmations with unique message ID), and replace quota-out with
52 * proper flow control;
53 * - if messages are below MTU, consider adding ACKs and other stuff
54 * (requires planning at receiver, and additional MST-style demultiplex
56 * - could avoid copying body of message into each fragment and keep
57 * fragments as just pointers into the original message and only
58 * fully build fragments just before transmission (optimization, should
59 * reduce CPU and memory use)
61 * Design realizations / discussion:
62 * - communicators do flow control by calling MQ "notify sent"
63 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
64 * or explicitly via backchannel FC ACKs. As long as the
65 * channel is not full, they may 'notify sent' even if the other
66 * peer has not yet confirmed receipt. The other peer confirming
67 * is _only_ for FC, not for more reliable transmission; reliable
68 * transmission (i.e. of fragments) is left to _transport_.
69 * - ACKs sent back in uni-directional communicators are done via
70 * the background channel API; here transport _may_ initially
71 * broadcast (with bounded # hops) if no path is known;
72 * - transport should _integrate_ DV-routing and build a view of
73 * the network; then background channel traffic can be
74 * routed via DV as well as explicit "DV" traffic.
75 * - background channel is also used for ACKs and NAT traversal support
76 * - transport service is responsible for AEAD'ing the background
77 * channel, timestamps and monotonic time are used against replay
78 * of old messages -> peerstore needs to be supplied with
79 * "latest timestamps seen" data
80 * - if transport implements DV, we likely need a 3rd peermap
81 * in addition to ephemerals and (direct) neighbours
82 * ==> check if stuff needs to be moved out of "Neighbour"
83 * - transport should encapsualte core-level messages and do its
84 * own ACKing for RTT/goodput/loss measurements _and_ fragment
88 #include "gnunet_util_lib.h"
89 #include "gnunet_statistics_service.h"
90 #include "gnunet_transport_monitor_service.h"
91 #include "gnunet_peerstore_service.h"
92 #include "gnunet_hello_lib.h"
93 #include "gnunet_signatures.h"
94 #include "transport.h"
98 * What is the size we assume for a read operation in the
99 * absence of an MTU for the purpose of flow control?
101 #define IN_PACKET_SIZE_WITHOUT_MTU 128
104 * Minimum number of hops we should forward DV learn messages
105 * even if they are NOT useful for us in hope of looping
106 * back to the initiator?
108 * FIXME: allow initiator some control here instead?
110 #define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
113 * Maximum DV distance allowed ever.
115 #define MAX_DV_HOPS_ALLOWED 16
118 * Maximum number of DV paths we keep simultaneously to the same target.
120 #define MAX_DV_PATHS_TO_TARGET 3
123 * If a queue delays the next message by more than this number
124 * of seconds we log a warning. Note: this is for testing,
125 * the value chosen here might be too aggressively low!
127 #define DELAY_WARN_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
130 * How long do we consider a DV path valid if we see no
131 * further updates on it? Note: the value chosen here might be too low!
133 #define DV_PATH_VALIDITY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
136 * How long before paths expire would we like to (re)discover DV paths? Should
137 * be below #DV_PATH_VALIDITY_TIMEOUT.
139 #define DV_PATH_DISCOVERY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
142 * How long are ephemeral keys valid?
144 #define EPHEMERAL_VALIDITY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
147 * How long do we keep partially reassembled messages around before giving up?
149 #define REASSEMBLY_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
152 * What is the fastest rate at which we send challenges *if* we keep learning
153 * an address (gossip, DHT, etc.)?
155 #define FAST_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
158 * What is the slowest rate at which we send challenges?
160 #define MAX_VALIDATION_CHALLENGE_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
163 * When do we forget an invalid address for sure?
165 #define MAX_ADDRESS_VALID_UNTIL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
167 * How long do we consider an address valid if we just checked?
169 #define ADDRESS_VALIDATION_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
172 * What is the maximum frequency at which we do address validation?
173 * A random value between 0 and this value is added when scheduling
174 * the #validation_task (both to ensure we do not validate too often,
175 * and to randomize a bit).
177 #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
180 * How many network RTTs before an address validation expires should we begin
181 * trying to revalidate? (Note that the RTT used here is the one that we
182 * experienced during the last validation, not necessarily the latest RTT
185 #define VALIDATION_RTT_BUFFER_FACTOR 3
188 * How many messages can we have pending for a given communicator
189 * process before we start to throttle that communicator?
191 * Used if a communicator might be CPU-bound and cannot handle the traffic.
193 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
196 * How many messages can we have pending for a given queue (queue to
197 * a particular peer via a communicator) process before we start to
198 * throttle that queue?
200 #define QUEUE_LENGTH_LIMIT 32
203 GNUNET_NETWORK_STRUCT_BEGIN
206 * Outer layer of an encapsulated backchannel message.
208 struct TransportBackchannelEncapsulationMessage
211 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
213 struct GNUNET_MessageHeader header;
216 * Distance the backchannel message has traveled, to be updated at
217 * each hop. Used to bound the number of hops in case a backchannel
218 * message is broadcast and thus travels without routing
219 * information (during initial backchannel discovery).
224 * Target's peer identity (as backchannels may be transmitted
225 * indirectly, or even be broadcast).
227 struct GNUNET_PeerIdentity target;
230 * Ephemeral key setup by the sender for @e target, used
231 * to encrypt the payload.
233 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
235 // FIXME: probably should add random IV here as well,
236 // especially if we re-use ephemeral keys!
239 * HMAC over the ciphertext of the encrypted, variable-size
240 * body that follows. Verified via DH of @e target and
243 struct GNUNET_HashCode hmac;
245 /* Followed by encrypted, variable-size payload */
250 * Body by which a peer confirms that it is using an ephemeral key.
252 struct EphemeralConfirmation
256 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
258 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
261 * How long is this signature over the ephemeral key valid?
262 * Note that the receiver MUST IGNORE the absolute time, and
263 * only interpret the value as a mononic time and reject
264 * "older" values than the last one observed. Even with this,
265 * there is no real guarantee against replay achieved here,
266 * as the latest timestamp is not persisted. This is
267 * necessary as we do not want to require synchronized
268 * clocks and may not have a bidirectional communication
269 * channel. Communicators must protect against replay
270 * attacks when using backchannel communication!
272 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
275 * Target's peer identity.
277 struct GNUNET_PeerIdentity target;
280 * Ephemeral key setup by the sender for @e target, used
281 * to encrypt the payload.
283 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
289 * Plaintext of the variable-size payload that is encrypted
290 * within a `struct TransportBackchannelEncapsulationMessage`
292 struct TransportBackchannelRequestPayload
296 * Sender's peer identity.
298 struct GNUNET_PeerIdentity sender;
301 * Signature of the sender over an
302 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
304 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
307 * How long is this signature over the ephemeral key
310 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
313 * Current monotonic time of the sending transport service. Used to
314 * detect replayed messages. Note that the receiver should remember
315 * a list of the recently seen timestamps and only reject messages
316 * if the timestamp is in the list, or the list is "full" and the
317 * timestamp is smaller than the lowest in the list. This list of
318 * timestamps per peer should be persisted to guard against replays
321 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
323 /* Followed by a `struct GNUNET_MessageHeader` with a message
324 for a communicator */
326 /* Followed by a 0-termianted string specifying the name of
327 the communicator which is to receive the message */
333 * Outer layer of an encapsulated unfragmented application message sent
334 * over an unreliable channel.
336 struct TransportReliabilityBox
339 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
341 struct GNUNET_MessageHeader header;
344 * Number of messages still to be sent before a commulative
345 * ACK is requested. Zero if an ACK is requested immediately.
346 * In NBO. Note that the receiver may send the ACK faster
347 * if it believes that is reasonable.
349 uint32_t ack_countdown GNUNET_PACKED;
352 * Unique ID of the message used for signalling receipt of
353 * messages sent over possibly unreliable channels. Should
356 struct GNUNET_ShortHashCode msg_uuid;
361 * Confirmation that the receiver got a
362 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
363 * confirmation may be transmitted over a completely different queue,
364 * so ACKs are identified by a combination of PID of sender and
365 * message UUID, without the queue playing any role!
367 struct TransportReliabilityAckMessage
370 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
372 struct GNUNET_MessageHeader header;
377 uint32_t reserved GNUNET_PACKED;
380 * How long was the ACK delayed relative to the average time of
381 * receipt of the messages being acknowledged? Used to calculate
382 * the average RTT by taking the receipt time of the ack minus the
383 * average transmission time of the sender minus this value.
385 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
387 /* followed by any number of `struct GNUNET_ShortHashCode`
388 messages providing ACKs */
393 * Outer layer of an encapsulated fragmented application message.
395 struct TransportFragmentBox
398 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
400 struct GNUNET_MessageHeader header;
403 * Unique ID of this fragment (and fragment transmission!). Will
404 * change even if a fragement is retransmitted to make each
405 * transmission attempt unique! Should be incremented by one for
406 * each fragment transmission. If a client receives a duplicate
407 * fragment (same @e frag_off), it must send
408 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
410 uint32_t frag_uuid GNUNET_PACKED;
413 * Original message ID for of the message that all the1
414 * fragments belong to. Must be the same for all fragments.
416 struct GNUNET_ShortHashCode msg_uuid;
419 * Offset of this fragment in the overall message.
421 uint16_t frag_off GNUNET_PACKED;
424 * Total size of the message that is being fragmented.
426 uint16_t msg_size GNUNET_PACKED;
432 * Outer layer of an fragmented application message sent over a queue
433 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
434 * received, the receiver has two RTTs or 64 further fragments with
435 * the same basic message time to send an acknowledgement, possibly
436 * acknowledging up to 65 fragments in one ACK. ACKs must also be
437 * sent immediately once all fragments were sent.
439 struct TransportFragmentAckMessage
442 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
444 struct GNUNET_MessageHeader header;
447 * Unique ID of the lowest fragment UUID being acknowledged.
449 uint32_t frag_uuid GNUNET_PACKED;
452 * Bitfield of up to 64 additional fragments following the
453 * @e msg_uuid being acknowledged by this message.
455 uint64_t extra_acks GNUNET_PACKED;
458 * Original message ID for of the message that all the
459 * fragments belong to.
461 struct GNUNET_ShortHashCode msg_uuid;
464 * How long was the ACK delayed relative to the average time of
465 * receipt of the fragments being acknowledged? Used to calculate
466 * the average RTT by taking the receipt time of the ack minus the
467 * average transmission time of the sender minus this value.
469 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
472 * How long until the receiver will stop trying reassembly
475 struct GNUNET_TIME_RelativeNBO reassembly_timeout;
480 * Content signed by each peer during DV learning.
485 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
487 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
490 * Challenge value used by the initiator to re-identify the path.
492 struct GNUNET_ShortHashCode challenge;
498 * Content signed by each peer during DV learning.
503 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
505 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
508 * Identity of the previous peer on the path.
510 struct GNUNET_PeerIdentity pred;
513 * Identity of the next peer on the path.
515 struct GNUNET_PeerIdentity succ;
518 * Challenge value used by the initiator to re-identify the path.
520 struct GNUNET_ShortHashCode challenge;
526 * An entry describing a peer on a path in a
527 * `struct TransportDVLearn` message.
532 * Identity of a peer on the path.
534 struct GNUNET_PeerIdentity hop;
537 * Signature of this hop over the path, of purpose
538 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
540 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
546 * Internal message used by transport for distance vector learning.
547 * If @e num_hops does not exceed the threshold, peers should append
548 * themselves to the peer list and flood the message (possibly only
549 * to a subset of their neighbours to limit discoverability of the
550 * network topology). To the extend that the @e bidirectional bits
551 * are set, peers may learn the inverse paths even if they did not
554 * Unless received on a bidirectional queue and @e num_hops just
555 * zero, peers that can forward to the initator should always try to
556 * forward to the initiator.
558 struct TransportDVLearn
561 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
563 struct GNUNET_MessageHeader header;
566 * Number of hops this messages has travelled, in NBO. Zero if
569 uint16_t num_hops GNUNET_PACKED;
572 * Bitmask of the last 16 hops indicating whether they are confirmed
573 * available (without DV) in both directions or not, in NBO. Used
574 * to possibly instantly learn a path in both directions. Each peer
575 * should shift this value by one to the left, and then set the
576 * lowest bit IF the current sender can be reached from it (without
579 uint16_t bidirectional GNUNET_PACKED;
582 * Peers receiving this message and delaying forwarding to other
583 * peers for any reason should increment this value by the non-network
584 * delay created by the peer.
586 struct GNUNET_TIME_RelativeNBO non_network_delay;
589 * Signature of this hop over the path, of purpose
590 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
592 struct GNUNET_CRYPTO_EddsaSignature init_sig;
595 * Identity of the peer that started this learning activity.
597 struct GNUNET_PeerIdentity initiator;
600 * Challenge value used by the initiator to re-identify the path.
602 struct GNUNET_ShortHashCode challenge;
604 /* Followed by @e num_hops `struct DVPathEntryP` values,
605 excluding the initiator of the DV trace; the last entry is the
606 current sender; the current peer must not be included. */
612 * Outer layer of an encapsulated message send over multiple hops.
613 * The path given only includes the identities of the subsequent
614 * peers, i.e. it will be empty if we are the receiver. Each
615 * forwarding peer should scan the list from the end, and if it can,
616 * forward to the respective peer. The list should then be shortened
617 * by all the entries up to and including that peer. Each hop should
618 * also increment @e total_hops to allow the receiver to get a precise
619 * estimate on the number of hops the message travelled. Senders must
620 * provide a learned path that thus should work, but intermediaries
621 * know of a shortcut, they are allowed to send the message via that
624 * If a peer finds itself still on the list, it must drop the message.
626 struct TransportDVBox
629 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
631 struct GNUNET_MessageHeader header;
634 * Number of total hops this messages travelled. In NBO.
635 * @e origin sets this to zero, to be incremented at
638 uint16_t total_hops GNUNET_PACKED;
641 * Number of hops this messages includes. In NBO.
643 uint16_t num_hops GNUNET_PACKED;
646 * Identity of the peer that originated the message.
648 struct GNUNET_PeerIdentity origin;
650 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
651 excluding the @e origin and the current peer, the last must be
652 the ultimate target; if @e num_hops is zero, the receiver of this
653 message is the ultimate target. */
655 /* Followed by the actual message, which itself may be
656 another box, but not a DV_LEARN or DV_BOX message! */
661 * Message send to another peer to validate that it can indeed
662 * receive messages at a particular address.
664 struct TransportValidationChallenge
668 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
670 struct GNUNET_MessageHeader header;
675 uint32_t reserved GNUNET_PACKED;
678 * Challenge to be signed by the receiving peer.
680 struct GNUNET_ShortHashCode challenge;
683 * Timestamp of the sender, to be copied into the reply
684 * to allow sender to calculate RTT.
686 struct GNUNET_TIME_AbsoluteNBO sender_time;
691 * Message signed by a peer to confirm that it can indeed
692 * receive messages at a particular address.
694 struct TransportValidationPS
698 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
700 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
703 * How long does the sender believe the address on
704 * which the challenge was received to remain valid?
706 struct GNUNET_TIME_RelativeNBO validity_duration;
709 * Challenge signed by the receiving peer.
711 struct GNUNET_ShortHashCode challenge;
717 * Message send to a peer to respond to a
718 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
720 struct TransportValidationResponse
724 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
726 struct GNUNET_MessageHeader header;
731 uint32_t reserved GNUNET_PACKED;
734 * The peer's signature matching the
735 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
737 struct GNUNET_CRYPTO_EddsaSignature signature;
740 * The challenge that was signed by the receiving peer.
742 struct GNUNET_ShortHashCode challenge;
745 * Original timestamp of the sender (was @code{sender_time}),
746 * copied into the reply to allow sender to calculate RTT.
748 struct GNUNET_TIME_AbsoluteNBO origin_time;
751 * How long does the sender believe this address to remain
754 struct GNUNET_TIME_RelativeNBO validity_duration;
759 GNUNET_NETWORK_STRUCT_END
763 * What type of client is the `struct TransportClient` about?
768 * We do not know yet (client is fresh).
773 * Is the CORE service, we need to forward traffic to it.
778 * It is a monitor, forward monitor data.
783 * It is a communicator, use for communication.
788 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
795 * Entry in our cache of ephemeral keys we currently use.
796 * This way, we only sign an ephemeral once per @e target,
797 * and then can re-use it over multiple
798 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION
799 * messages (as signing is expensive).
801 struct EphemeralCacheEntry
805 * Target's peer identity (we don't re-use ephemerals
806 * to limit linkability of messages).
808 struct GNUNET_PeerIdentity target;
811 * Signature affirming @e ephemeral_key of type
812 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
814 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
817 * How long is @e sender_sig valid
819 struct GNUNET_TIME_Absolute ephemeral_validity;
824 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
827 * Our private ephemeral key.
829 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
832 * Node in the ephemeral cache for this entry.
833 * Used for expiration.
835 struct GNUNET_CONTAINER_HeapNode *hn;
840 * Client connected to the transport service.
842 struct TransportClient;
846 * A neighbour that at least one communicator is connected to.
852 * Entry in our #dv_routes table, representing a (set of) distance
853 * vector routes to a particular peer.
855 struct DistanceVector;
858 * One possible hop towards a DV target.
860 struct DistanceVectorHop
864 * Kept in a MDLL, sorted by @e timeout.
866 struct DistanceVectorHop *next_dv;
869 * Kept in a MDLL, sorted by @e timeout.
871 struct DistanceVectorHop *prev_dv;
876 struct DistanceVectorHop *next_neighbour;
881 struct DistanceVectorHop *prev_neighbour;
884 * What would be the next hop to @e target?
886 struct Neighbour *next_hop;
889 * Distance vector entry this hop belongs with.
891 struct DistanceVector *dv;
894 * Array of @e distance hops to the target, excluding @e next_hop.
895 * NULL if the entire path is us to @e next_hop to `target`. Allocated
896 * at the end of this struct.
898 const struct GNUNET_PeerIdentity *path;
901 * At what time do we forget about this path unless we see it again
904 struct GNUNET_TIME_Absolute timeout;
907 * How many hops in total to the `target` (excluding @e next_hop and `target` itself),
908 * thus 0 still means a distance of 2 hops (to @e next_hop and then to `target`)?
910 unsigned int distance;
915 * Entry in our #dv_routes table, representing a (set of) distance
916 * vector routes to a particular peer.
918 struct DistanceVector
922 * To which peer is this a route?
924 struct GNUNET_PeerIdentity target;
927 * Known paths to @e target.
929 struct DistanceVectorHop *dv_head;
932 * Known paths to @e target.
934 struct DistanceVectorHop *dv_tail;
937 * Task scheduled to purge expired paths from @e dv_head MDLL.
939 struct GNUNET_SCHEDULER_Task *timeout_task;
944 * A queue is a message queue provided by a communicator
945 * via which we can reach a particular neighbour.
951 * Entry identifying transmission in one of our `struct
952 * Queue` which still awaits an ACK. This is used to
953 * ensure we do not overwhelm a communicator and limit the number of
954 * messages outstanding per communicator (say in case communicator is
955 * CPU bound) and per queue (in case bandwidth allocation exceeds
956 * what the communicator can actually provide towards a particular
965 struct QueueEntry *next;
970 struct QueueEntry *prev;
973 * Queue this entry is queued with.
978 * Message ID used for this message with the queue used for transmission.
985 * A queue is a message queue provided by a communicator
986 * via which we can reach a particular neighbour.
993 struct Queue *next_neighbour;
998 struct Queue *prev_neighbour;
1003 struct Queue *prev_client;
1008 struct Queue *next_client;
1011 * Head of DLL of unacked transmission requests.
1013 struct QueueEntry *queue_head;
1016 * End of DLL of unacked transmission requests.
1018 struct QueueEntry *queue_tail;
1021 * Which neighbour is this queue for?
1023 struct Neighbour *neighbour;
1026 * Which communicator offers this queue?
1028 struct TransportClient *tc;
1031 * Address served by the queue.
1033 const char *address;
1036 * Task scheduled for the time when this queue can (likely) transmit the
1037 * next message. Still needs to check with the @e tracker_out to be sure.
1039 struct GNUNET_SCHEDULER_Task *transmit_task;
1042 * Our current RTT estimate for this queue.
1044 struct GNUNET_TIME_Relative rtt;
1047 * Message ID generator for transmissions on this queue.
1052 * Unique identifier of this queue with the communicator.
1057 * Maximum transmission unit supported by this queue.
1062 * Distance to the target of this queue.
1069 uint32_t num_msg_pending;
1074 uint32_t num_bytes_pending;
1077 * Length of the DLL starting at @e queue_head.
1079 unsigned int queue_length;
1082 * Network type offered by this queue.
1084 enum GNUNET_NetworkType nt;
1087 * Connection status for this queue.
1089 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1092 * How much outbound bandwidth do we have available for this queue?
1094 struct GNUNET_BANDWIDTH_Tracker tracker_out;
1097 * How much inbound bandwidth do we have available for this queue?
1099 struct GNUNET_BANDWIDTH_Tracker tracker_in;
1104 * Information we keep for a message that we are reassembling.
1106 struct ReassemblyContext
1110 * Original message ID for of the message that all the
1111 * fragments belong to.
1113 struct GNUNET_ShortHashCode msg_uuid;
1116 * Which neighbour is this context for?
1118 struct Neighbour *neighbour;
1121 * Entry in the reassembly heap (sorted by expiration).
1123 struct GNUNET_CONTAINER_HeapNode *hn;
1126 * Bitfield with @e msg_size bits representing the positions
1127 * where we have received fragments. When we receive a fragment,
1128 * we check the bits in @e bitfield before incrementing @e msg_missing.
1130 * Allocated after the reassembled message.
1135 * Task for sending ACK. We may send ACKs either because of hitting
1136 * the @e extra_acks limit, or based on time and @e num_acks. This
1137 * task is for the latter case.
1139 struct GNUNET_SCHEDULER_Task *ack_task;
1142 * At what time will we give up reassembly of this message?
1144 struct GNUNET_TIME_Absolute reassembly_timeout;
1147 * Average delay of all acks in @e extra_acks and @e frag_uuid.
1148 * Should be reset to zero when @e num_acks is set to 0.
1150 struct GNUNET_TIME_Relative avg_ack_delay;
1153 * Time we received the last fragment. @e avg_ack_delay must be
1154 * incremented by now - @e last_frag multiplied by @e num_acks.
1156 struct GNUNET_TIME_Absolute last_frag;
1159 * Bitfield of up to 64 additional fragments following @e frag_uuid
1160 * to be acknowledged in the next cummulative ACK.
1162 uint64_t extra_acks;
1165 * Unique ID of the lowest fragment UUID to be acknowledged in the
1166 * next cummulative ACK. Only valid if @e num_acks > 0.
1171 * Number of ACKs we have accumulated so far. Reset to 0
1172 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
1174 unsigned int num_acks;
1177 * How big is the message we are reassembling in total?
1182 * How many bytes of the message are still missing? Defragmentation
1183 * is complete when @e msg_missing == 0.
1185 uint16_t msg_missing;
1187 /* Followed by @e msg_size bytes of the (partially) defragmented original message */
1189 /* Followed by @e bitfield data */
1194 * A neighbour that at least one communicator is connected to.
1200 * Which peer is this about?
1202 struct GNUNET_PeerIdentity pid;
1205 * Map with `struct ReassemblyContext` structs for fragments under
1206 * reassembly. May be NULL if we currently have no fragments from
1207 * this @e pid (lazy initialization).
1209 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
1212 * Heap with `struct ReassemblyContext` structs for fragments under
1213 * reassembly. May be NULL if we currently have no fragments from
1214 * this @e pid (lazy initialization).
1216 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1219 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1221 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1224 * Head of list of messages pending for this neighbour.
1226 struct PendingMessage *pending_msg_head;
1229 * Tail of list of messages pending for this neighbour.
1231 struct PendingMessage *pending_msg_tail;
1234 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1235 * purged if this neighbour goes down.
1237 struct DistanceVectorHop *dv_head;
1240 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1241 * purged if this neighbour goes down.
1243 struct DistanceVectorHop *dv_tail;
1246 * Head of DLL of queues to this peer.
1248 struct Queue *queue_head;
1251 * Tail of DLL of queues to this peer.
1253 struct Queue *queue_tail;
1256 * Task run to cleanup pending messages that have exceeded their timeout.
1258 struct GNUNET_SCHEDULER_Task *timeout_task;
1261 * Quota at which CORE is allowed to transmit to this peer.
1263 * FIXME: not yet used, tricky to get right given multiple queues!
1264 * (=> Idea: measure???)
1265 * FIXME: how do we set this value initially when we tell CORE?
1266 * Options: start at a minimum value or at literally zero?
1267 * (=> Current thought: clean would be zero!)
1269 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
1272 * What is the earliest timeout of any message in @e pending_msg_tail?
1274 struct GNUNET_TIME_Absolute earliest_timeout;
1280 * A peer that an application (client) would like us to talk to directly.
1286 * Which peer is this about?
1288 struct GNUNET_PeerIdentity pid;
1291 * Client responsible for the request.
1293 struct TransportClient *tc;
1296 * Handle for watching the peerstore for HELLOs for this peer.
1298 struct GNUNET_PEERSTORE_WatchContext *wc;
1301 * What kind of performance preference does this @e tc have?
1303 enum GNUNET_MQ_PreferenceKind pk;
1306 * How much bandwidth would this @e tc like to see?
1308 struct GNUNET_BANDWIDTH_Value32NBO bw;
1314 * Types of different pending messages.
1316 enum PendingMessageType
1320 * Ordinary message received from the CORE service.
1327 PMT_FRAGMENT_BOX = 1,
1332 PMT_RELIABILITY_BOX = 2,
1335 * Any type of acknowledgement.
1337 PMT_ACKNOWLEDGEMENT = 3
1343 * Transmission request that is awaiting delivery. The original
1344 * transmission requests from CORE may be too big for some queues.
1345 * In this case, a *tree* of fragments is created. At each
1346 * level of the tree, fragments are kept in a DLL ordered by which
1347 * fragment should be sent next (at the head). The tree is searched
1348 * top-down, with the original message at the root.
1350 * To select a node for transmission, first it is checked if the
1351 * current node's message fits with the MTU. If it does not, we
1352 * either calculate the next fragment (based on @e frag_off) from the
1353 * current node, or, if all fragments have already been created,
1354 * descend to the @e head_frag. Even though the node was already
1355 * fragmented, the fragment may be too big if the fragment was
1356 * generated for a queue with a larger MTU. In this case, the node
1357 * may be fragmented again, thus creating a tree.
1359 * When acknowledgements for fragments are received, the tree
1360 * must be pruned, removing those parts that were already
1361 * acknowledged. When fragments are sent over a reliable
1362 * channel, they can be immediately removed.
1364 * If a message is ever fragmented, then the original "full" message
1365 * is never again transmitted (even if it fits below the MTU), and
1366 * only (remaining) fragments are sent.
1368 struct PendingMessage
1371 * Kept in a MDLL of messages for this @a target.
1373 struct PendingMessage *next_neighbour;
1376 * Kept in a MDLL of messages for this @a target.
1378 struct PendingMessage *prev_neighbour;
1381 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1383 struct PendingMessage *next_client;
1386 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1388 struct PendingMessage *prev_client;
1391 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOx)
1393 struct PendingMessage *next_frag;
1396 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOX)
1398 struct PendingMessage *prev_frag;
1401 * This message, reliability boxed. Only possibly available if @e pmt is #PMT_CORE.
1403 struct PendingMessage *bpm;
1406 * Target of the request.
1408 struct Neighbour *target;
1411 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1413 struct TransportClient *client;
1416 * Head of a MDLL of fragments created for this core message.
1418 struct PendingMessage *head_frag;
1421 * Tail of a MDLL of fragments created for this core message.
1423 struct PendingMessage *tail_frag;
1426 * Our parent in the fragmentation tree.
1428 struct PendingMessage *frag_parent;
1431 * At what time should we give up on the transmission (and no longer retry)?
1433 struct GNUNET_TIME_Absolute timeout;
1436 * What is the earliest time for us to retry transmission of this message?
1438 struct GNUNET_TIME_Absolute next_attempt;
1441 * UUID to use for this message (used for reassembly of fragments, only
1442 * initialized if @e msg_uuid_set is #GNUNET_YES).
1444 struct GNUNET_ShortHashCode msg_uuid;
1447 * Counter incremented per generated fragment.
1449 uint32_t frag_uuidgen;
1452 * Type of the pending message.
1454 enum PendingMessageType pmt;
1457 * Size of the original message.
1462 * Offset at which we should generate the next fragment.
1467 * #GNUNET_YES once @e msg_uuid was initialized
1469 int16_t msg_uuid_set;
1471 /* Followed by @e bytes_msg to transmit */
1476 * One of the addresses of this peer.
1478 struct AddressListEntry
1484 struct AddressListEntry *next;
1489 struct AddressListEntry *prev;
1492 * Which communicator provides this address?
1494 struct TransportClient *tc;
1497 * The actual address.
1499 const char *address;
1502 * Current context for storing this address in the peerstore.
1504 struct GNUNET_PEERSTORE_StoreContext *sc;
1507 * Task to periodically do @e st operation.
1509 struct GNUNET_SCHEDULER_Task *st;
1512 * What is a typical lifetime the communicator expects this
1513 * address to have? (Always from now.)
1515 struct GNUNET_TIME_Relative expiration;
1518 * Address identifier used by the communicator.
1523 * Network type offered by this address.
1525 enum GNUNET_NetworkType nt;
1531 * Client connected to the transport service.
1533 struct TransportClient
1539 struct TransportClient *next;
1544 struct TransportClient *prev;
1547 * Handle to the client.
1549 struct GNUNET_SERVICE_Client *client;
1552 * Message queue to the client.
1554 struct GNUNET_MQ_Handle *mq;
1557 * What type of client is this?
1559 enum ClientType type;
1565 * Information for @e type #CT_CORE.
1570 * Head of list of messages pending for this client, sorted by
1571 * transmission time ("next_attempt" + possibly internal prioritization).
1573 struct PendingMessage *pending_msg_head;
1576 * Tail of list of messages pending for this client.
1578 struct PendingMessage *pending_msg_tail;
1583 * Information for @e type #CT_MONITOR.
1588 * Peer identity to monitor the addresses of.
1589 * Zero to monitor all neighbours. Valid if
1590 * @e type is #CT_MONITOR.
1592 struct GNUNET_PeerIdentity peer;
1595 * Is this a one-shot monitor?
1603 * Information for @e type #CT_COMMUNICATOR.
1607 * If @e type is #CT_COMMUNICATOR, this communicator
1608 * supports communicating using these addresses.
1610 char *address_prefix;
1613 * Head of DLL of queues offered by this communicator.
1615 struct Queue *queue_head;
1618 * Tail of DLL of queues offered by this communicator.
1620 struct Queue *queue_tail;
1623 * Head of list of the addresses of this peer offered by this communicator.
1625 struct AddressListEntry *addr_head;
1628 * Tail of list of the addresses of this peer offered by this communicator.
1630 struct AddressListEntry *addr_tail;
1633 * Number of queue entries in all queues to this communicator. Used
1634 * throttle sending to a communicator if we see that the communicator
1635 * is globally unable to keep up.
1637 unsigned int total_queue_length;
1640 * Characteristics of this communicator.
1642 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1647 * Information for @e type #CT_APPLICATION
1652 * Map of requests for peers the given client application would like to
1653 * see connections for. Maps from PIDs to `struct PeerRequest`.
1655 struct GNUNET_CONTAINER_MultiPeerMap *requests;
1665 * State we keep for validation activities. Each of these
1666 * is both in the #validation_heap and the #validation_map.
1668 struct ValidationState
1672 * For which peer is @a address to be validated (or possibly valid)?
1673 * Serves as key in the #validation_map.
1675 struct GNUNET_PeerIdentity pid;
1678 * How long did the peer claim this @e address to be valid? Capped at
1679 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
1680 * were told about the address and the value claimed by the other peer at
1681 * that time. May be updated similarly when validation succeeds.
1683 struct GNUNET_TIME_Absolute valid_until;
1686 * How long do *we* consider this @e address to be valid?
1687 * In the past or zero if we have not yet validated it.
1689 struct GNUNET_TIME_Absolute validated_until;
1692 * When did we FIRST use the current @e challenge in a message?
1693 * Used to sanity-check @code{origin_time} in the response when
1694 * calculating the RTT. If the @code{origin_time} is not in
1695 * the expected range, the response is discarded as malicious.
1697 struct GNUNET_TIME_Absolute first_challenge_use;
1700 * When did we LAST use the current @e challenge in a message?
1701 * Used to sanity-check @code{origin_time} in the response when
1702 * calculating the RTT. If the @code{origin_time} is not in
1703 * the expected range, the response is discarded as malicious.
1705 struct GNUNET_TIME_Absolute last_challenge_use;
1708 * Next time we will send the @e challenge to the peer, if this time is past
1709 * @e valid_until, this validation state is released at this time. If the
1710 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
1711 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
1712 * to re-validate before the validity actually expires.
1714 struct GNUNET_TIME_Absolute next_challenge;
1717 * Current backoff factor we're applying for sending the @a challenge.
1718 * Reset to 0 if the @a challenge is confirmed upon validation.
1719 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
1720 * existing value if we receive an unvalidated address again over
1721 * another channel (and thus should consider the information "fresh").
1722 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
1724 struct GNUNET_TIME_Relative challenge_backoff;
1727 * Initially set to "forever". Once @e validated_until is set, this value is
1728 * set to the RTT that tells us how long it took to receive the validation.
1730 struct GNUNET_TIME_Relative validation_rtt;
1733 * The challenge we sent to the peer to get it to validate the address. Note
1734 * that we rotate the challenge whenever we update @e validated_until to
1735 * avoid attacks where a peer simply replays an old challenge in the future.
1736 * (We must not rotate more often as otherwise we may discard valid answers
1737 * due to packet losses, latency and reorderings on the network).
1739 struct GNUNET_ShortHashCode challenge;
1742 * Claimed address of the peer.
1747 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
1748 * heap is used to figure out when the next validation activity should be
1751 struct GNUNET_CONTAINER_HeapNode *hn;
1754 * Handle to a PEERSTORE store operation for this @e address. NULL if
1755 * no PEERSTORE operation is pending.
1757 struct GNUNET_PEERSTORE_StoreContext *sc;
1760 * We are technically ready to send the challenge, but we are waiting for
1761 * the respective queue to become available for transmission.
1769 * Head of linked list of all clients to this service.
1771 static struct TransportClient *clients_head;
1774 * Tail of linked list of all clients to this service.
1776 static struct TransportClient *clients_tail;
1779 * Statistics handle.
1781 static struct GNUNET_STATISTICS_Handle *GST_stats;
1784 * Configuration handle.
1786 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1791 static struct GNUNET_PeerIdentity GST_my_identity;
1796 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1799 * Map from PIDs to `struct Neighbour` entries. A peer is
1800 * a neighbour if we have an MQ to it from some communicator.
1802 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1805 * Map from PIDs to `struct DistanceVector` entries describing
1806 * known paths to the peer.
1808 static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
1811 * Map from PIDs to `struct ValidationState` entries describing
1812 * addresses we are aware of and their validity state.
1814 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
1817 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
1818 * sorting addresses we are aware of by when we should next try to (re)validate
1821 static struct GNUNET_CONTAINER_Heap *validation_heap;
1824 * Database for peer's HELLOs.
1826 static struct GNUNET_PEERSTORE_Handle *peerstore;
1829 * Heap sorting `struct EphemeralCacheEntry` by their
1830 * key/signature validity.
1832 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
1835 * Hash map for looking up `struct EphemeralCacheEntry`s
1836 * by peer identity. (We may have ephemerals in our
1837 * cache for which we do not have a neighbour entry,
1838 * and similar many neighbours may not need ephemerals,
1839 * so we use a second map.)
1841 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
1844 * Task to free expired ephemerals.
1846 static struct GNUNET_SCHEDULER_Task *ephemeral_task;
1849 * Task to run address validation.
1851 static struct GNUNET_SCHEDULER_Task *validation_task;
1855 * Free cached ephemeral key.
1857 * @param ece cached signature to free
1860 free_ephemeral (struct EphemeralCacheEntry *ece)
1862 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map,
1865 GNUNET_CONTAINER_heap_remove_node (ece->hn);
1871 * Free validation state.
1873 * @param vs validation state to free
1876 free_validation_state (struct ValidationState *vs)
1878 GNUNET_CONTAINER_multipeermap_remove (validation_map,
1881 GNUNET_CONTAINER_heap_remove_node (vs->hn);
1885 GNUNET_PEERSTORE_store_cancel (vs->sc);
1888 GNUNET_free (vs->address);
1894 * Lookup neighbour record for peer @a pid.
1896 * @param pid neighbour to look for
1897 * @return NULL if we do not have this peer as a neighbour
1899 static struct Neighbour *
1900 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
1902 return GNUNET_CONTAINER_multipeermap_get (neighbours,
1908 * Details about what to notify monitors about.
1913 * @deprecated To be discussed if we keep these...
1915 struct GNUNET_TIME_Absolute last_validation;
1916 struct GNUNET_TIME_Absolute valid_until;
1917 struct GNUNET_TIME_Absolute next_validation;
1920 * Current round-trip time estimate.
1922 struct GNUNET_TIME_Relative rtt;
1925 * Connection status.
1927 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1932 uint32_t num_msg_pending;
1937 uint32_t num_bytes_pending;
1944 * Free a @dvh. Callers MAY want to check if this was the last path to the
1945 * `target`, and if so call #free_dv_route to also free the associated DV
1946 * entry in #dv_routes (if not, the associated scheduler job should eventually
1949 * @param dvh hop to free
1952 free_distance_vector_hop (struct DistanceVectorHop *dvh)
1954 struct Neighbour *n = dvh->next_hop;
1955 struct DistanceVector *dv = dvh->dv;
1957 GNUNET_CONTAINER_MDLL_remove (neighbour,
1961 GNUNET_CONTAINER_MDLL_remove (dv,
1970 * Free entry in #dv_routes. First frees all hops to the target, and
1971 * if there are no entries left, frees @a dv as well.
1973 * @param dv route to free
1976 free_dv_route (struct DistanceVector *dv)
1978 struct DistanceVectorHop *dvh;
1980 while (NULL != (dvh = dv->dv_head))
1981 free_distance_vector_hop (dvh);
1982 if (NULL == dv->dv_head)
1984 GNUNET_assert (GNUNET_YES ==
1985 GNUNET_CONTAINER_multipeermap_remove (dv_routes,
1988 if (NULL != dv->timeout_task)
1989 GNUNET_SCHEDULER_cancel (dv->timeout_task);
1996 * Notify monitor @a tc about an event. That @a tc
1997 * cares about the event has already been checked.
1999 * Send @a tc information in @a me about a @a peer's status with
2000 * respect to some @a address to all monitors that care.
2002 * @param tc monitor to inform
2003 * @param peer peer the information is about
2004 * @param address address the information is about
2005 * @param nt network type associated with @a address
2006 * @param me detailed information to transmit
2009 notify_monitor (struct TransportClient *tc,
2010 const struct GNUNET_PeerIdentity *peer,
2011 const char *address,
2012 enum GNUNET_NetworkType nt,
2013 const struct MonitorEvent *me)
2015 struct GNUNET_MQ_Envelope *env;
2016 struct GNUNET_TRANSPORT_MonitorData *md;
2017 size_t addr_len = strlen (address) + 1;
2019 env = GNUNET_MQ_msg_extra (md,
2021 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
2022 md->nt = htonl ((uint32_t) nt);
2024 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
2025 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
2026 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
2027 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
2028 md->cs = htonl ((uint32_t) me->cs);
2029 md->num_msg_pending = htonl (me->num_msg_pending);
2030 md->num_bytes_pending = htonl (me->num_bytes_pending);
2034 GNUNET_MQ_send (tc->mq,
2040 * Send information in @a me about a @a peer's status with respect
2041 * to some @a address to all monitors that care.
2043 * @param peer peer the information is about
2044 * @param address address the information is about
2045 * @param nt network type associated with @a address
2046 * @param me detailed information to transmit
2049 notify_monitors (const struct GNUNET_PeerIdentity *peer,
2050 const char *address,
2051 enum GNUNET_NetworkType nt,
2052 const struct MonitorEvent *me)
2054 for (struct TransportClient *tc = clients_head;
2058 if (CT_MONITOR != tc->type)
2060 if (tc->details.monitor.one_shot)
2062 if ( (0 != GNUNET_is_zero (&tc->details.monitor.peer)) &&
2063 (0 != GNUNET_memcmp (&tc->details.monitor.peer,
2076 * Called whenever a client connects. Allocates our
2077 * data structures associated with that client.
2079 * @param cls closure, NULL
2080 * @param client identification of the client
2081 * @param mq message queue for the client
2082 * @return our `struct TransportClient`
2085 client_connect_cb (void *cls,
2086 struct GNUNET_SERVICE_Client *client,
2087 struct GNUNET_MQ_Handle *mq)
2089 struct TransportClient *tc;
2091 tc = GNUNET_new (struct TransportClient);
2092 tc->client = client;
2094 GNUNET_CONTAINER_DLL_insert (clients_head,
2097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2098 "Client %p connected\n",
2107 * @param rc data structure to free
2110 free_reassembly_context (struct ReassemblyContext *rc)
2112 struct Neighbour *n = rc->neighbour;
2114 GNUNET_assert (rc ==
2115 GNUNET_CONTAINER_heap_remove_node (rc->hn));
2116 GNUNET_assert (GNUNET_OK ==
2117 GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map,
2125 * Task run to clean up reassembly context of a neighbour that have expired.
2127 * @param cls a `struct Neighbour`
2130 reassembly_cleanup_task (void *cls)
2132 struct Neighbour *n = cls;
2133 struct ReassemblyContext *rc;
2135 n->reassembly_timeout_task = NULL;
2136 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
2138 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout).rel_value_us)
2140 free_reassembly_context (rc);
2143 GNUNET_assert (NULL == n->reassembly_timeout_task);
2144 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
2145 &reassembly_cleanup_task,
2153 * function called to #free_reassembly_context().
2157 * @param value a `struct ReassemblyContext` to free
2158 * @return #GNUNET_OK (continue iteration)
2161 free_reassembly_cb (void *cls,
2162 const struct GNUNET_ShortHashCode *key,
2165 struct ReassemblyContext *rc = value;
2169 free_reassembly_context (rc);
2175 * Release memory used by @a neighbour.
2177 * @param neighbour neighbour entry to free
2180 free_neighbour (struct Neighbour *neighbour)
2182 struct DistanceVectorHop *dvh;
2184 GNUNET_assert (NULL == neighbour->queue_head);
2185 GNUNET_assert (GNUNET_YES ==
2186 GNUNET_CONTAINER_multipeermap_remove (neighbours,
2189 if (NULL != neighbour->timeout_task)
2190 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
2191 if (NULL != neighbour->reassembly_map)
2193 GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map,
2194 &free_reassembly_cb,
2196 GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map);
2197 neighbour->reassembly_map = NULL;
2198 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
2199 neighbour->reassembly_heap = NULL;
2201 while (NULL != (dvh = neighbour->dv_head))
2203 struct DistanceVector *dv = dvh->dv;
2205 free_distance_vector_hop (dvh);
2206 if (NULL == dv->dv_head)
2209 if (NULL != neighbour->reassembly_timeout_task)
2210 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
2211 GNUNET_free (neighbour);
2216 * Send message to CORE clients that we lost a connection.
2218 * @param tc client to inform (must be CORE client)
2219 * @param pid peer the connection is for
2220 * @param quota_out current quota for the peer
2223 core_send_connect_info (struct TransportClient *tc,
2224 const struct GNUNET_PeerIdentity *pid,
2225 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2227 struct GNUNET_MQ_Envelope *env;
2228 struct ConnectInfoMessage *cim;
2230 GNUNET_assert (CT_CORE == tc->type);
2231 env = GNUNET_MQ_msg (cim,
2232 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2233 cim->quota_out = quota_out;
2235 GNUNET_MQ_send (tc->mq,
2241 * Send message to CORE clients that we gained a connection
2243 * @param pid peer the queue was for
2244 * @param quota_out current quota for the peer
2247 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
2248 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
2250 for (struct TransportClient *tc = clients_head;
2254 if (CT_CORE != tc->type)
2256 core_send_connect_info (tc,
2264 * Send message to CORE clients that we lost a connection.
2266 * @param pid peer the connection was for
2269 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
2271 for (struct TransportClient *tc = clients_head;
2275 struct GNUNET_MQ_Envelope *env;
2276 struct DisconnectInfoMessage *dim;
2278 if (CT_CORE != tc->type)
2280 env = GNUNET_MQ_msg (dim,
2281 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2283 GNUNET_MQ_send (tc->mq,
2290 * We believe we are ready to transmit a message on a queue. Double-checks
2291 * with the queue's "tracker_out" and then gives the message to the
2292 * communicator for transmission (updating the tracker, and re-scheduling
2293 * itself if applicable).
2295 * @param cls the `struct Queue` to process transmissions for
2298 transmit_on_queue (void *cls);
2302 * Schedule next run of #transmit_on_queue(). Does NOTHING if
2303 * we should run immediately or if the message queue is empty.
2304 * Test for no task being added AND queue not being empty to
2305 * transmit immediately afterwards! This function must only
2306 * be called if the message queue is non-empty!
2308 * @param queue the queue to do scheduling for
2311 schedule_transmit_on_queue (struct Queue *queue)
2313 struct Neighbour *n = queue->neighbour;
2314 struct PendingMessage *pm = n->pending_msg_head;
2315 struct GNUNET_TIME_Relative out_delay;
2318 GNUNET_assert (NULL != pm);
2319 if (queue->tc->details.communicator.total_queue_length >=
2320 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
2322 GNUNET_STATISTICS_update (GST_stats,
2323 "# Transmission throttled due to communicator queue limit",
2328 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
2330 GNUNET_STATISTICS_update (GST_stats,
2331 "# Transmission throttled due to queue queue limit",
2337 wsize = (0 == queue->mtu)
2338 ? pm->bytes_msg /* FIXME: add overheads? */
2340 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out,
2342 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (pm->next_attempt),
2344 if (0 == out_delay.rel_value_us)
2345 return; /* we should run immediately! */
2346 /* queue has changed since we were scheduled, reschedule again */
2347 queue->transmit_task
2348 = GNUNET_SCHEDULER_add_delayed (out_delay,
2351 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
2352 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2353 "Next transmission on queue `%s' in %s (high delay)\n",
2355 GNUNET_STRINGS_relative_time_to_string (out_delay,
2358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2359 "Next transmission on queue `%s' in %s\n",
2361 GNUNET_STRINGS_relative_time_to_string (out_delay,
2369 * @param queue the queue to free
2372 free_queue (struct Queue *queue)
2374 struct Neighbour *neighbour = queue->neighbour;
2375 struct TransportClient *tc = queue->tc;
2376 struct MonitorEvent me = {
2377 .cs = GNUNET_TRANSPORT_CS_DOWN,
2378 .rtt = GNUNET_TIME_UNIT_FOREVER_REL
2380 struct QueueEntry *qe;
2383 if (NULL != queue->transmit_task)
2385 GNUNET_SCHEDULER_cancel (queue->transmit_task);
2386 queue->transmit_task = NULL;
2388 GNUNET_CONTAINER_MDLL_remove (neighbour,
2389 neighbour->queue_head,
2390 neighbour->queue_tail,
2392 GNUNET_CONTAINER_MDLL_remove (client,
2393 tc->details.communicator.queue_head,
2394 tc->details.communicator.queue_tail,
2396 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >= tc->details.communicator.total_queue_length);
2397 while (NULL != (qe = queue->queue_head))
2399 GNUNET_CONTAINER_DLL_remove (queue->queue_head,
2402 queue->queue_length--;
2403 tc->details.communicator.total_queue_length--;
2406 GNUNET_assert (0 == queue->queue_length);
2408 (COMMUNICATOR_TOTAL_QUEUE_LIMIT < tc->details.communicator.total_queue_length) )
2410 /* Communicator dropped below threshold, resume all queues */
2411 GNUNET_STATISTICS_update (GST_stats,
2412 "# Transmission throttled due to communicator queue limit",
2415 for (struct Queue *s = tc->details.communicator.queue_head;
2418 schedule_transmit_on_queue (s);
2420 notify_monitors (&neighbour->pid,
2424 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
2425 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
2426 GNUNET_free (queue);
2427 if (NULL == neighbour->queue_head)
2429 cores_send_disconnect_info (&neighbour->pid);
2430 free_neighbour (neighbour);
2438 * @param ale address list entry to free
2441 free_address_list_entry (struct AddressListEntry *ale)
2443 struct TransportClient *tc = ale->tc;
2445 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
2446 tc->details.communicator.addr_tail,
2448 if (NULL != ale->sc)
2450 GNUNET_PEERSTORE_store_cancel (ale->sc);
2453 if (NULL != ale->st)
2455 GNUNET_SCHEDULER_cancel (ale->st);
2463 * Stop the peer request in @a value.
2465 * @param cls a `struct TransportClient` that no longer makes the request
2466 * @param pid the peer's identity
2467 * @param value a `struct PeerRequest`
2468 * @return #GNUNET_YES (always)
2471 stop_peer_request (void *cls,
2472 const struct GNUNET_PeerIdentity *pid,
2475 struct TransportClient *tc = cls;
2476 struct PeerRequest *pr = value;
2478 GNUNET_PEERSTORE_watch_cancel (pr->wc);
2479 GNUNET_assert (GNUNET_YES ==
2480 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
2490 * Called whenever a client is disconnected. Frees our
2491 * resources associated with that client.
2493 * @param cls closure, NULL
2494 * @param client identification of the client
2495 * @param app_ctx our `struct TransportClient`
2498 client_disconnect_cb (void *cls,
2499 struct GNUNET_SERVICE_Client *client,
2502 struct TransportClient *tc = app_ctx;
2504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2505 "Client %p disconnected, cleaning up.\n",
2507 GNUNET_CONTAINER_DLL_remove (clients_head,
2516 struct PendingMessage *pm;
2518 while (NULL != (pm = tc->details.core.pending_msg_head))
2520 GNUNET_CONTAINER_MDLL_remove (client,
2521 tc->details.core.pending_msg_head,
2522 tc->details.core.pending_msg_tail,
2530 case CT_COMMUNICATOR:
2533 struct AddressListEntry *ale;
2535 while (NULL != (q = tc->details.communicator.queue_head))
2537 while (NULL != (ale = tc->details.communicator.addr_head))
2538 free_address_list_entry (ale);
2539 GNUNET_free (tc->details.communicator.address_prefix);
2542 case CT_APPLICATION:
2543 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
2546 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
2554 * Iterator telling new CORE client about all existing
2555 * connections to peers.
2557 * @param cls the new `struct TransportClient`
2558 * @param pid a connected peer
2559 * @param value the `struct Neighbour` with more information
2560 * @return #GNUNET_OK (continue to iterate)
2563 notify_client_connect_info (void *cls,
2564 const struct GNUNET_PeerIdentity *pid,
2567 struct TransportClient *tc = cls;
2568 struct Neighbour *neighbour = value;
2570 core_send_connect_info (tc,
2572 neighbour->quota_out);
2578 * Initialize a "CORE" client. We got a start message from this
2579 * client, so add it to the list of clients for broadcasting of
2582 * @param cls the client
2583 * @param start the start message that was sent
2586 handle_client_start (void *cls,
2587 const struct StartMessage *start)
2589 struct TransportClient *tc = cls;
2592 options = ntohl (start->options);
2593 if ( (0 != (1 & options)) &&
2595 GNUNET_memcmp (&start->self,
2596 &GST_my_identity)) )
2598 /* client thinks this is a different peer, reject */
2600 GNUNET_SERVICE_client_drop (tc->client);
2603 if (CT_NONE != tc->type)
2606 GNUNET_SERVICE_client_drop (tc->client);
2610 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2611 ¬ify_client_connect_info,
2613 GNUNET_SERVICE_client_continue (tc->client);
2618 * Client asked for transmission to a peer. Process the request.
2620 * @param cls the client
2621 * @param obm the send message that was sent
2624 check_client_send (void *cls,
2625 const struct OutboundMessage *obm)
2627 struct TransportClient *tc = cls;
2629 const struct GNUNET_MessageHeader *obmm;
2631 if (CT_CORE != tc->type)
2634 return GNUNET_SYSERR;
2636 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
2637 if (size < sizeof (struct GNUNET_MessageHeader))
2640 return GNUNET_SYSERR;
2642 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2643 if (size != ntohs (obmm->size))
2646 return GNUNET_SYSERR;
2653 * Free fragment tree below @e root, excluding @e root itself.
2655 * @param root root of the tree to free
2658 free_fragment_tree (struct PendingMessage *root)
2660 struct PendingMessage *frag;
2662 while (NULL != (frag = root->head_frag))
2664 free_fragment_tree (frag);
2665 GNUNET_CONTAINER_MDLL_remove (frag,
2675 * Release memory associated with @a pm and remove @a pm from associated
2676 * data structures. @a pm must be a top-level pending message and not
2677 * a fragment in the tree. The entire tree is freed (if applicable).
2679 * @param pm the pending message to free
2682 free_pending_message (struct PendingMessage *pm)
2684 struct TransportClient *tc = pm->client;
2685 struct Neighbour *target = pm->target;
2689 GNUNET_CONTAINER_MDLL_remove (client,
2690 tc->details.core.pending_msg_head,
2691 tc->details.core.pending_msg_tail,
2694 GNUNET_CONTAINER_MDLL_remove (neighbour,
2695 target->pending_msg_head,
2696 target->pending_msg_tail,
2698 free_fragment_tree (pm);
2699 GNUNET_free_non_null (pm->bpm);
2705 * Send a response to the @a pm that we have processed a
2706 * "send" request with status @a success. We
2707 * transmitted @a bytes_physical on the actual wire.
2708 * Sends a confirmation to the "core" client responsible
2709 * for the original request and free's @a pm.
2711 * @param pm handle to the original pending message
2712 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
2713 * for transmission failure
2714 * @param bytes_physical amount of bandwidth consumed
2717 client_send_response (struct PendingMessage *pm,
2719 uint32_t bytes_physical)
2721 struct TransportClient *tc = pm->client;
2722 struct Neighbour *target = pm->target;
2723 struct GNUNET_MQ_Envelope *env;
2724 struct SendOkMessage *som;
2728 env = GNUNET_MQ_msg (som,
2729 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2730 som->success = htonl ((uint32_t) success);
2731 som->bytes_msg = htons (pm->bytes_msg);
2732 som->bytes_physical = htonl (bytes_physical);
2733 som->peer = target->pid;
2734 GNUNET_MQ_send (tc->mq,
2737 free_pending_message (pm);
2742 * Checks the message queue for a neighbour for messages that have timed
2743 * out and purges them.
2745 * @param cls a `struct Neighbour`
2748 check_queue_timeouts (void *cls)
2750 struct Neighbour *n = cls;
2751 struct PendingMessage *pm;
2752 struct GNUNET_TIME_Absolute now;
2753 struct GNUNET_TIME_Absolute earliest_timeout;
2755 n->timeout_task = NULL;
2756 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2757 now = GNUNET_TIME_absolute_get ();
2758 for (struct PendingMessage *pos = n->pending_msg_head;
2762 pm = pos->next_neighbour;
2763 if (pos->timeout.abs_value_us <= now.abs_value_us)
2765 GNUNET_STATISTICS_update (GST_stats,
2766 "# messages dropped (timeout before confirmation)",
2769 client_send_response (pm,
2774 earliest_timeout = GNUNET_TIME_absolute_min (earliest_timeout,
2777 n->earliest_timeout = earliest_timeout;
2778 if (NULL != n->pending_msg_head)
2779 n->timeout_task = GNUNET_SCHEDULER_add_at (earliest_timeout,
2780 &check_queue_timeouts,
2786 * Client asked for transmission to a peer. Process the request.
2788 * @param cls the client
2789 * @param obm the send message that was sent
2792 handle_client_send (void *cls,
2793 const struct OutboundMessage *obm)
2795 struct TransportClient *tc = cls;
2796 struct PendingMessage *pm;
2797 const struct GNUNET_MessageHeader *obmm;
2798 struct Neighbour *target;
2802 GNUNET_assert (CT_CORE == tc->type);
2803 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2804 bytes_msg = ntohs (obmm->size);
2805 target = lookup_neighbour (&obm->peer);
2808 /* Failure: don't have this peer as a neighbour (anymore).
2809 Might have gone down asynchronously, so this is NOT
2810 a protocol violation by CORE. Still count the event,
2811 as this should be rare. */
2812 struct GNUNET_MQ_Envelope *env;
2813 struct SendOkMessage *som;
2815 env = GNUNET_MQ_msg (som,
2816 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
2817 som->success = htonl (GNUNET_SYSERR);
2818 som->bytes_msg = htonl (bytes_msg);
2819 som->bytes_physical = htonl (0);
2820 som->peer = obm->peer;
2821 GNUNET_MQ_send (tc->mq,
2823 GNUNET_SERVICE_client_continue (tc->client);
2824 GNUNET_STATISTICS_update (GST_stats,
2825 "# messages dropped (neighbour unknown)",
2830 was_empty = (NULL == target->pending_msg_head);
2831 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
2833 pm->target = target;
2834 pm->bytes_msg = bytes_msg;
2835 pm->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
2839 GNUNET_CONTAINER_MDLL_insert (neighbour,
2840 target->pending_msg_head,
2841 target->pending_msg_tail,
2843 GNUNET_CONTAINER_MDLL_insert (client,
2844 tc->details.core.pending_msg_head,
2845 tc->details.core.pending_msg_tail,
2847 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
2849 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
2850 if (NULL != target->timeout_task)
2851 GNUNET_SCHEDULER_cancel (target->timeout_task);
2852 target->timeout_task
2853 = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
2854 &check_queue_timeouts,
2858 return; /* all queues must already be busy */
2859 for (struct Queue *queue = target->queue_head;
2861 queue = queue->next_neighbour)
2863 /* try transmission on any queue that is idle */
2864 if (NULL == queue->transmit_task)
2865 queue->transmit_task = GNUNET_SCHEDULER_add_now (&transmit_on_queue,
2872 * Communicator started. Test message is well-formed.
2874 * @param cls the client
2875 * @param cam the send message that was sent
2878 check_communicator_available (void *cls,
2879 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
2881 struct TransportClient *tc = cls;
2884 if (CT_NONE != tc->type)
2887 return GNUNET_SYSERR;
2889 tc->type = CT_COMMUNICATOR;
2890 size = ntohs (cam->header.size) - sizeof (*cam);
2892 return GNUNET_OK; /* receive-only communicator */
2893 GNUNET_MQ_check_zero_termination (cam);
2899 * Communicator started. Process the request.
2901 * @param cls the client
2902 * @param cam the send message that was sent
2905 handle_communicator_available (void *cls,
2906 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
2908 struct TransportClient *tc = cls;
2911 size = ntohs (cam->header.size) - sizeof (*cam);
2913 return; /* receive-only communicator */
2914 tc->details.communicator.address_prefix
2915 = GNUNET_strdup ((const char *) &cam[1]);
2916 tc->details.communicator.cc
2917 = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
2918 GNUNET_SERVICE_client_continue (tc->client);
2923 * Communicator requests backchannel transmission. Check the request.
2925 * @param cls the client
2926 * @param cb the send message that was sent
2927 * @return #GNUNET_OK if message is well-formed
2930 check_communicator_backchannel (void *cls,
2931 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
2933 const struct GNUNET_MessageHeader *inbox;
2938 msize = ntohs (cb->header.size) - sizeof (*cb);
2939 if (UINT16_MAX - msize >
2940 sizeof (struct TransportBackchannelEncapsulationMessage) +
2941 sizeof (struct TransportBackchannelRequestPayload) )
2944 return GNUNET_SYSERR;
2946 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
2947 isize = ntohs (inbox->size);
2951 return GNUNET_SYSERR;
2953 is = (const char *) inbox;
2956 GNUNET_assert (msize > 0);
2957 if ('\0' != is[msize-1])
2960 return GNUNET_SYSERR;
2967 * Remove memory used by expired ephemeral keys.
2972 expire_ephemerals (void *cls)
2974 struct EphemeralCacheEntry *ece;
2977 ephemeral_task = NULL;
2978 while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap)))
2980 if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us)
2982 free_ephemeral (ece);
2985 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
2994 * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate
2995 * one, cache it and return it.
2997 * @param pid peer to look up ephemeral for
2998 * @param private_key[out] set to the private key
2999 * @param ephemeral_key[out] set to the key
3000 * @param ephemeral_sender_sig[out] set to the signature
3001 * @param ephemeral_validity[out] set to the validity expiration time
3004 lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
3005 struct GNUNET_CRYPTO_EcdhePrivateKey *private_key,
3006 struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
3007 struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig,
3008 struct GNUNET_TIME_Absolute *ephemeral_validity)
3010 struct EphemeralCacheEntry *ece;
3011 struct EphemeralConfirmation ec;
3013 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map,
3015 if ( (NULL != ece) &&
3016 (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us) )
3018 free_ephemeral (ece);
3023 ece = GNUNET_new (struct EphemeralCacheEntry);
3025 ece->ephemeral_validity = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg),
3026 EPHEMERAL_VALIDITY);
3027 GNUNET_assert (GNUNET_OK ==
3028 GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key));
3029 GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key,
3030 &ece->ephemeral_key);
3031 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
3032 ec.purpose.size = htonl (sizeof (ec));
3034 ec.ephemeral_key = ece->ephemeral_key;
3035 GNUNET_assert (GNUNET_OK ==
3036 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
3039 ece->hn = GNUNET_CONTAINER_heap_insert (ephemeral_heap,
3041 ece->ephemeral_validity.abs_value_us);
3042 GNUNET_assert (GNUNET_OK ==
3043 GNUNET_CONTAINER_multipeermap_put (ephemeral_map,
3046 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3047 if (NULL == ephemeral_task)
3048 ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity,
3052 *private_key = ece->private_key;
3053 *ephemeral_key = ece->ephemeral_key;
3054 *ephemeral_sender_sig = ece->sender_sig;
3055 *ephemeral_validity = ece->ephemeral_validity;
3060 * We need to transmit @a hdr to @a target. If necessary, this may
3061 * involve DV routing or even broadcasting and fragmentation.
3063 * @param target peer to receive @a hdr
3064 * @param hdr header of the message to route
3067 route_message (const struct GNUNET_PeerIdentity *target,
3068 struct GNUNET_MessageHeader *hdr)
3070 // FIXME: this one is tricky:
3071 // - we could try a direct, reliable channel
3072 // - if that is unavailable / for load balancing, we may try:
3073 // * multiple (?) direct unreliable channels - depending on loss rate?
3074 // * some (?) DV channels - if above unavailable / too lossy?
3075 // * _random_ other peers ("broadcasting") in hope of *discovering*
3076 // a path back! - if all else fails
3077 // => need more on DV first!
3079 // FIXME: send hdr to target, free hdr (possibly using DV, possibly broadcasting)
3085 * Communicator requests backchannel transmission. Process the request.
3087 * @param cls the client
3088 * @param cb the send message that was sent
3091 handle_communicator_backchannel (void *cls,
3092 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
3094 struct TransportClient *tc = cls;
3095 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
3096 struct GNUNET_TIME_Absolute ephemeral_validity;
3097 struct TransportBackchannelEncapsulationMessage *enc;
3098 struct TransportBackchannelRequestPayload ppay;
3102 /* encapsulate and encrypt message */
3103 msize = ntohs (cb->header.size) - sizeof (*cb) + sizeof (struct TransportBackchannelRequestPayload);
3104 enc = GNUNET_malloc (sizeof (*enc) + msize);
3105 enc->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
3106 enc->header.size = htons (sizeof (*enc) + msize);
3107 enc->target = cb->pid;
3108 lookup_ephemeral (&cb->pid,
3110 &enc->ephemeral_key,
3112 &ephemeral_validity);
3113 // FIXME: setup 'iv'
3115 dh_key_derive (&private_key,
3120 ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity);
3121 ppay.monotonic_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
3122 mpos = (char *) &enc[1];
3131 ntohs (cb->header.size) - sizeof (*cb));
3135 route_message (&cb->pid,
3137 GNUNET_SERVICE_client_continue (tc->client);
3142 * Address of our peer added. Test message is well-formed.
3144 * @param cls the client
3145 * @param aam the send message that was sent
3146 * @return #GNUNET_OK if message is well-formed
3149 check_add_address (void *cls,
3150 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3152 struct TransportClient *tc = cls;
3154 if (CT_COMMUNICATOR != tc->type)
3157 return GNUNET_SYSERR;
3159 GNUNET_MQ_check_zero_termination (aam);
3165 * Ask peerstore to store our address.
3167 * @param cls an `struct AddressListEntry *`
3170 store_pi (void *cls);
3174 * Function called when peerstore is done storing our address.
3176 * @param cls a `struct AddressListEntry`
3177 * @param success #GNUNET_YES if peerstore was successful
3180 peerstore_store_own_cb (void *cls,
3183 struct AddressListEntry *ale = cls;
3186 if (GNUNET_YES != success)
3187 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3188 "Failed to store our own address `%s' in peerstore!\n",
3190 /* refresh period is 1/4 of expiration time, that should be plenty
3191 without being excessive. */
3192 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
3200 * Ask peerstore to store our address.
3202 * @param cls an `struct AddressListEntry *`
3205 store_pi (void *cls)
3207 struct AddressListEntry *ale = cls;
3210 struct GNUNET_TIME_Absolute expiration;
3213 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
3214 GNUNET_HELLO_sign_address (ale->address,
3220 ale->sc = GNUNET_PEERSTORE_store (peerstore,
3223 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
3227 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
3228 &peerstore_store_own_cb,
3231 if (NULL == ale->sc)
3233 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3234 "Failed to store our address `%s' with peerstore\n",
3236 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
3244 * Address of our peer added. Process the request.
3246 * @param cls the client
3247 * @param aam the send message that was sent
3250 handle_add_address (void *cls,
3251 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
3253 struct TransportClient *tc = cls;
3254 struct AddressListEntry *ale;
3257 slen = ntohs (aam->header.size) - sizeof (*aam);
3258 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
3260 ale->address = (const char *) &ale[1];
3261 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
3262 ale->aid = aam->aid;
3263 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
3267 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
3268 tc->details.communicator.addr_tail,
3270 ale->st = GNUNET_SCHEDULER_add_now (&store_pi,
3272 GNUNET_SERVICE_client_continue (tc->client);
3277 * Address of our peer deleted. Process the request.
3279 * @param cls the client
3280 * @param dam the send message that was sent
3283 handle_del_address (void *cls,
3284 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
3286 struct TransportClient *tc = cls;
3288 if (CT_COMMUNICATOR != tc->type)
3291 GNUNET_SERVICE_client_drop (tc->client);
3294 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
3298 if (dam->aid != ale->aid)
3300 GNUNET_assert (ale->tc == tc);
3301 free_address_list_entry (ale);
3302 GNUNET_SERVICE_client_continue (tc->client);
3305 GNUNET_SERVICE_client_drop (tc->client);
3310 * Context from #handle_incoming_msg(). Closure for many
3311 * message handlers below.
3313 struct CommunicatorMessageContext
3316 * Which communicator provided us with the message.
3318 struct TransportClient *tc;
3321 * Additional information for flow control and about the sender.
3323 struct GNUNET_TRANSPORT_IncomingMessage im;
3326 * Number of hops the message has travelled (if DV-routed).
3327 * FIXME: make use of this in ACK handling!
3329 uint16_t total_hops;
3334 * Given an inbound message @a msg from a communicator @a cmc,
3335 * demultiplex it based on the type calling the right handler.
3337 * @param cmc context for demultiplexing
3338 * @param msg message to demultiplex
3341 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3342 const struct GNUNET_MessageHeader *msg);
3346 * Send ACK to communicator (if requested) and free @a cmc.
3348 * @param cmc context for which we are done handling the message
3351 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
3353 if (0 != ntohl (cmc->im.fc_on))
3355 /* send ACK when done to communicator for flow control! */
3356 struct GNUNET_MQ_Envelope *env;
3357 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
3359 env = GNUNET_MQ_msg (ack,
3360 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
3361 ack->reserved = htonl (0);
3362 ack->fc_id = cmc->im.fc_id;
3363 ack->sender = cmc->im.sender;
3364 GNUNET_MQ_send (cmc->tc->mq,
3367 GNUNET_SERVICE_client_continue (cmc->tc->client);
3373 * Communicator gave us an unencapsulated message to pass as-is to
3374 * CORE. Process the request.
3376 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3377 * @param mh the message that was received
3380 handle_raw_message (void *cls,
3381 const struct GNUNET_MessageHeader *mh)
3383 struct CommunicatorMessageContext *cmc = cls;
3384 uint16_t size = ntohs (mh->size);
3386 if ( (size > UINT16_MAX - sizeof (struct InboundMessage)) ||
3387 (size < sizeof (struct GNUNET_MessageHeader)) )
3389 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3392 finish_cmc_handling (cmc);
3393 GNUNET_SERVICE_client_drop (client);
3396 /* Forward to all CORE clients */
3397 for (struct TransportClient *tc = clients_head;
3401 struct GNUNET_MQ_Envelope *env;
3402 struct InboundMessage *im;
3404 if (CT_CORE != tc->type)
3406 env = GNUNET_MQ_msg_extra (im,
3408 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3409 im->peer = cmc->im.sender;
3413 GNUNET_MQ_send (tc->mq,
3416 /* FIXME: consider doing this _only_ once the message
3417 was drained from the CORE MQs to extend flow control to CORE!
3418 (basically, increment counter in cmc, decrement on MQ send continuation! */
3419 finish_cmc_handling (cmc);
3424 * Communicator gave us a fragment box. Check the message.
3426 * @param cls a `struct CommunicatorMessageContext`
3427 * @param fb the send message that was sent
3428 * @return #GNUNET_YES if message is well-formed
3431 check_fragment_box (void *cls,
3432 const struct TransportFragmentBox *fb)
3434 uint16_t size = ntohs (fb->header.size);
3435 uint16_t bsize = size - sizeof (*fb);
3439 GNUNET_break_op (0);
3440 return GNUNET_SYSERR;
3442 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
3444 GNUNET_break_op (0);
3445 return GNUNET_SYSERR;
3447 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
3449 GNUNET_break_op (0);
3450 return GNUNET_SYSERR;
3457 * Generate a fragment acknowledgement for an @a rc.
3459 * @param rc context to generate ACK for, @a rc ACK state is reset
3462 send_fragment_ack (struct ReassemblyContext *rc)
3464 struct TransportFragmentAckMessage *ack;
3466 ack = GNUNET_new (struct TransportFragmentAckMessage);
3467 ack->header.size = htons (sizeof (struct TransportFragmentAckMessage));
3468 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK);
3469 ack->frag_uuid = htonl (rc->frag_uuid);
3470 ack->extra_acks = GNUNET_htonll (rc->extra_acks);
3471 ack->msg_uuid = rc->msg_uuid;
3472 ack->avg_ack_delay = GNUNET_TIME_relative_hton (rc->avg_ack_delay);
3473 if (0 == rc->msg_missing)
3474 ack->reassembly_timeout
3475 = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL); /* signal completion */
3477 ack->reassembly_timeout
3478 = GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout));
3479 route_message (&rc->neighbour->pid,
3481 rc->avg_ack_delay = GNUNET_TIME_UNIT_ZERO;
3483 rc->extra_acks = 0LLU;
3488 * Communicator gave us a fragment. Process the request.
3490 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3491 * @param fb the message that was received
3494 handle_fragment_box (void *cls,
3495 const struct TransportFragmentBox *fb)
3497 struct CommunicatorMessageContext *cmc = cls;
3498 struct Neighbour *n;
3499 struct ReassemblyContext *rc;
3500 const struct GNUNET_MessageHeader *msg;
3506 struct GNUNET_TIME_Relative cdelay;
3509 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
3513 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3516 finish_cmc_handling (cmc);
3517 GNUNET_SERVICE_client_drop (client);
3520 if (NULL == n->reassembly_map)
3522 n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8,
3524 n->reassembly_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3525 n->reassembly_timeout_task = GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
3526 &reassembly_cleanup_task,
3529 msize = ntohs (fb->msg_size);
3530 rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map,
3534 rc = GNUNET_malloc (sizeof (*rc) +
3535 msize + /* reassembly payload buffer */
3536 (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */);
3537 rc->msg_uuid = fb->msg_uuid;
3539 rc->msg_size = msize;
3540 rc->reassembly_timeout = GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
3541 rc->last_frag = GNUNET_TIME_absolute_get ();
3542 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
3544 rc->reassembly_timeout.abs_value_us);
3545 GNUNET_assert (GNUNET_OK ==
3546 GNUNET_CONTAINER_multishortmap_put (n->reassembly_map,
3549 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3550 target = (char *) &rc[1];
3551 rc->bitfield = (uint8_t *) (target + rc->msg_size);
3552 rc->msg_missing = rc->msg_size;
3556 target = (char *) &rc[1];
3558 if (msize != rc->msg_size)
3561 finish_cmc_handling (cmc);
3566 fsize = ntohs (fb->header.size) - sizeof (*fb);
3567 frag_off = ntohs (fb->frag_off);
3568 memcpy (&target[frag_off],
3571 /* update bitfield and msg_missing */
3572 for (unsigned int i=frag_off;i<frag_off+fsize;i++)
3574 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
3576 rc->bitfield[i / 8] |= (1 << (i % 8));
3581 /* Compute cummulative ACK */
3582 frag_uuid = ntohl (fb->frag_uuid);
3583 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
3584 cdelay = GNUNET_TIME_relative_multiply (cdelay,
3586 rc->last_frag = GNUNET_TIME_absolute_get ();
3587 rc->avg_ack_delay = GNUNET_TIME_relative_add (rc->avg_ack_delay,
3589 ack_now = GNUNET_NO;
3590 if (0 == rc->num_acks)
3592 /* case one: first ack */
3593 rc->frag_uuid = frag_uuid;
3594 rc->extra_acks = 0LLU;
3597 else if ( (frag_uuid >= rc->frag_uuid) &&
3598 (frag_uuid <= rc->frag_uuid + 64) )
3600 /* case two: ack fits after existing min UUID */
3601 if ( (frag_uuid == rc->frag_uuid) ||
3602 (0 != (rc->extra_acks & (1LLU << (frag_uuid - rc->frag_uuid - 1)))) )
3604 /* duplicate fragment, ack now! */
3605 ack_now = GNUNET_YES;
3609 rc->extra_acks |= (1LLU << (frag_uuid - rc->frag_uuid - 1));
3613 else if ( (rc->frag_uuid > frag_uuid) &&
3614 ( ( (rc->frag_uuid == frag_uuid + 64) &&
3615 (0 == rc->extra_acks) ) ||
3616 ( (rc->frag_uuid < frag_uuid + 64) &&
3617 (rc->extra_acks == (rc->extra_acks & ~ ((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))) ) ) )
3619 /* can fit ack by shifting extra acks and starting at
3620 frag_uid, test above esured that the bits we will
3621 shift 'extra_acks' by are all zero. */
3622 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
3623 rc->extra_acks |= (1LLU << (rc->frag_uuid - frag_uuid - 1));
3624 rc->frag_uuid = frag_uuid;
3627 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very aggressive. */
3628 ack_now = GNUNET_YES; /* maximum acks received */
3629 // FIXME: possibly also ACK based on RTT (but for that we'd need to
3630 // determine the queue used for the ACK first!)
3632 /* is reassembly complete? */
3633 if (0 != rc->msg_missing)
3636 send_fragment_ack (rc);
3637 finish_cmc_handling (cmc);
3640 /* reassembly is complete, verify result */
3641 msg = (const struct GNUNET_MessageHeader *) &rc[1];
3642 if (ntohs (msg->size) != rc->msg_size)
3645 free_reassembly_context (rc);
3646 finish_cmc_handling (cmc);
3649 /* successful reassembly */
3650 send_fragment_ack (rc);
3651 demultiplex_with_cmc (cmc,
3653 /* FIXME: really free here? Might be bad if fragments are still
3654 en-route and we forget that we finished this reassembly immediately!
3655 -> keep around until timeout?
3656 -> shorten timeout based on ACK? */
3657 free_reassembly_context (rc);
3662 * Communicator gave us a fragment acknowledgement. Process the request.
3664 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3665 * @param fa the message that was received
3668 handle_fragment_ack (void *cls,
3669 const struct TransportFragmentAckMessage *fa)
3671 struct CommunicatorMessageContext *cmc = cls;
3673 // FIXME: do work: identify original message; then identify fragments being acked;
3674 // remove those from the tree to prevent retransmission;
3676 // if entire message is ACKed, handle that as well.
3677 finish_cmc_handling (cmc);
3682 * Communicator gave us a reliability box. Check the message.
3684 * @param cls a `struct CommunicatorMessageContext`
3685 * @param rb the send message that was sent
3686 * @return #GNUNET_YES if message is well-formed
3689 check_reliability_box (void *cls,
3690 const struct TransportReliabilityBox *rb)
3692 GNUNET_MQ_check_boxed_message (rb);
3698 * Communicator gave us a reliability box. Process the request.
3700 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3701 * @param rb the message that was received
3704 handle_reliability_box (void *cls,
3705 const struct TransportReliabilityBox *rb)
3707 struct CommunicatorMessageContext *cmc = cls;
3708 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &rb[1];
3710 if (0 == ntohl (rb->ack_countdown))
3712 struct TransportReliabilityAckMessage *ack;
3714 /* FIXME: implement cummulative ACKs and ack_countdown,
3715 then setting the avg_ack_delay field below: */
3716 ack = GNUNET_malloc (sizeof (*ack) +
3717 sizeof (struct GNUNET_ShortHashCode));
3718 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
3719 ack->header.size = htons (sizeof (*ack) +
3720 sizeof (struct GNUNET_ShortHashCode));
3723 sizeof (struct GNUNET_ShortHashCode));
3724 route_message (&cmc->im.sender,
3727 /* continue with inner message */
3728 demultiplex_with_cmc (cmc,
3734 * Communicator gave us a reliability ack. Process the request.
3736 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3737 * @param ra the message that was received
3740 handle_reliability_ack (void *cls,
3741 const struct TransportReliabilityAckMessage *ra)
3743 struct CommunicatorMessageContext *cmc = cls;
3745 // FIXME: do work: find message that was acknowledged, and
3746 // remove from transmission queue; update RTT.
3747 finish_cmc_handling (cmc);
3752 * Communicator gave us a backchannel encapsulation. Check the message.
3754 * @param cls a `struct CommunicatorMessageContext`
3755 * @param be the send message that was sent
3756 * @return #GNUNET_YES if message is well-formed
3759 check_backchannel_encapsulation (void *cls,
3760 const struct TransportBackchannelEncapsulationMessage *be)
3762 uint16_t size = ntohs (be->header.size);
3764 if (size - sizeof (*be) < sizeof (struct GNUNET_MessageHeader))
3766 GNUNET_break_op (0);
3767 return GNUNET_SYSERR;
3774 * Communicator gave us a backchannel encapsulation. Process the request.
3776 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
3777 * @param be the message that was received
3780 handle_backchannel_encapsulation (void *cls,
3781 const struct TransportBackchannelEncapsulationMessage *be)
3783 struct CommunicatorMessageContext *cmc = cls;
3785 if (0 != GNUNET_memcmp (&be->target,
3788 /* not for me, try to route to target */
3789 route_message (&be->target,
3790 GNUNET_copy_message (&be->header));
3791 finish_cmc_handling (cmc);
3794 // FIXME: compute shared secret
3795 // FIXME: check HMAC
3796 // FIXME: decrypt payload
3797 // FIXME: forward to specified communicator!
3798 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
3799 finish_cmc_handling (cmc);
3804 * Task called when we should check if any of the DV paths
3805 * we have learned to a target are due for garbage collection.
3807 * Collects stale paths, and possibly frees the entire DV
3808 * entry if no paths are left. Otherwise re-schedules itself.
3810 * @param cls a `struct DistanceVector`
3813 path_cleanup_cb (void *cls)
3815 struct DistanceVector *dv = cls;
3816 struct DistanceVectorHop *pos;
3818 dv->timeout_task = NULL;
3819 while (NULL != (pos = dv->dv_head))
3821 GNUNET_assert (dv == pos->dv);
3822 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
3824 free_distance_vector_hop (pos);
3831 dv->timeout_task = GNUNET_SCHEDULER_add_at (pos->timeout,
3838 * We have learned a @a path through the network to some other peer, add it to
3839 * our DV data structure (returning #GNUNET_YES on success).
3841 * We do not add paths if we have a sufficient number of shorter
3842 * paths to this target already (returning #GNUNET_NO).
3844 * We also do not add problematic paths, like those where we lack the first
3845 * hop in our neighbour list (i.e. due to a topology change) or where some
3846 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
3848 * @param path the path we learned, path[0] should be us,
3849 * and then path contains a valid path from us to `path[path_len-1]`
3850 * path[1] should be a direct neighbour (we should check!)
3851 * @param path_len number of entries on the @a path, at least three!
3852 * @param network_latency how long does the message take from us to `path[path_len-1]`?
3853 * set to "forever" if unknown
3854 * @return #GNUNET_YES on success,
3855 * #GNUNET_NO if we have better path(s) to the target
3856 * #GNUNET_SYSERR if the path is useless and/or invalid
3857 * (i.e. path[1] not a direct neighbour
3858 * or path[i+1] is a direct neighbour for i>0)
3861 learn_dv_path (const struct GNUNET_PeerIdentity *path,
3862 unsigned int path_len,
3863 struct GNUNET_TIME_Relative network_latency)
3865 struct DistanceVectorHop *hop;
3866 struct DistanceVector *dv;
3867 struct Neighbour *next_hop;
3868 unsigned int shorter_distance;
3872 /* what a boring path! not allowed! */
3874 return GNUNET_SYSERR;
3877 GNUNET_memcmp (&GST_my_identity,
3879 next_hop = GNUNET_CONTAINER_multipeermap_get (neighbours,
3881 if (NULL == next_hop)
3883 /* next hop must be a neighbour, otherwise this whole thing is useless! */
3885 return GNUNET_SYSERR;
3887 for (unsigned int i=2;i<path_len;i++)
3889 GNUNET_CONTAINER_multipeermap_get (neighbours,
3892 /* Useless path, we have a direct connection to some hop
3893 in the middle of the path, so this one doesn't even
3894 seem terribly useful for redundancy */
3895 return GNUNET_SYSERR;
3897 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes,
3898 &path[path_len - 1]);
3901 dv = GNUNET_new (struct DistanceVector);
3902 dv->target = path[path_len - 1];
3903 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
3906 GNUNET_assert (GNUNET_OK ==
3907 GNUNET_CONTAINER_multipeermap_put (dv_routes,
3910 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3912 /* Check if we have this path already! */
3913 shorter_distance = 0;
3914 for (struct DistanceVectorHop *pos = dv->dv_head;
3918 if (pos->distance < path_len - 2)
3920 /* Note that the distances in 'pos' excludes us (path[0]) and
3921 the next_hop (path[1]), so we need to subtract two
3922 and check next_hop explicitly */
3923 if ( (pos->distance == path_len - 2) &&
3924 (pos->next_hop == next_hop) )
3926 int match = GNUNET_YES;
3928 for (unsigned int i=0;i<pos->distance;i++)
3931 GNUNET_memcmp (&pos->path[i],
3938 if (GNUNET_YES == match)
3940 struct GNUNET_TIME_Relative last_timeout;
3942 /* Re-discovered known path, update timeout */
3943 GNUNET_STATISTICS_update (GST_stats,
3944 "# Known DV path refreshed",
3947 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
3949 = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
3950 GNUNET_CONTAINER_MDLL_remove (dv,
3954 GNUNET_CONTAINER_MDLL_insert (dv,
3958 if (last_timeout.rel_value_us <
3959 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
3960 DV_PATH_DISCOVERY_FREQUENCY).rel_value_us)
3962 /* Some peer send DV learn messages too often, we are learning
3963 the same path faster than it would be useful; do not forward! */
3970 /* Count how many shorter paths we have (incl. direct
3971 neighbours) before simply giving up on this one! */
3972 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
3974 /* We have a shorter path already! */
3977 /* create new DV path entry */
3978 hop = GNUNET_malloc (sizeof (struct DistanceVectorHop) +
3979 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
3980 hop->next_hop = next_hop;
3982 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
3985 sizeof (struct GNUNET_PeerIdentity) * (path_len - 2));
3986 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
3987 hop->distance = path_len - 2;
3988 GNUNET_CONTAINER_MDLL_insert (dv,
3992 GNUNET_CONTAINER_MDLL_insert (neighbour,
4001 * Communicator gave us a DV learn message. Check the message.
4003 * @param cls a `struct CommunicatorMessageContext`
4004 * @param dvl the send message that was sent
4005 * @return #GNUNET_YES if message is well-formed
4008 check_dv_learn (void *cls,
4009 const struct TransportDVLearn *dvl)
4011 uint16_t size = ntohs (dvl->header.size);
4012 uint16_t num_hops = ntohs (dvl->num_hops);
4013 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
4015 if (size != sizeof (*dvl) + num_hops * sizeof (struct DVPathEntryP))
4017 GNUNET_break_op (0);
4018 return GNUNET_SYSERR;
4020 if (num_hops > MAX_DV_HOPS_ALLOWED)
4022 GNUNET_break_op (0);
4023 return GNUNET_SYSERR;
4025 for (unsigned int i=0;i<num_hops;i++)
4027 if (0 == GNUNET_memcmp (&dvl->initiator,
4030 GNUNET_break_op (0);
4031 return GNUNET_SYSERR;
4033 if (0 == GNUNET_memcmp (&GST_my_identity,
4036 GNUNET_break_op (0);
4037 return GNUNET_SYSERR;
4045 * Build and forward a DV learn message to @a next_hop.
4047 * @param next_hop peer to send the message to
4048 * @param msg message received
4049 * @param bi_history bitmask specifying hops on path that were bidirectional
4050 * @param nhops length of the @a hops array
4051 * @param hops path the message traversed so far
4052 * @param in_time when did we receive the message, used to calculate network delay
4055 forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
4056 const struct TransportDVLearn *msg,
4057 uint16_t bi_history,
4059 const struct DVPathEntryP *hops,
4060 struct GNUNET_TIME_Absolute in_time)
4062 struct DVPathEntryP *dhops;
4063 struct TransportDVLearn *fwd;
4064 struct GNUNET_TIME_Relative nnd;
4066 /* compute message for forwarding */
4067 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
4068 fwd = GNUNET_malloc (sizeof (struct TransportDVLearn) +
4069 (nhops + 1) * sizeof (struct DVPathEntryP));
4070 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
4071 fwd->header.size = htons (sizeof (struct TransportDVLearn) +
4072 (nhops + 1) * sizeof (struct DVPathEntryP));
4073 fwd->num_hops = htons (nhops + 1);
4074 fwd->bidirectional = htons (bi_history);
4075 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
4076 GNUNET_TIME_relative_ntoh (msg->non_network_delay));
4077 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
4078 fwd->init_sig = msg->init_sig;
4079 fwd->initiator = msg->initiator;
4080 fwd->challenge = msg->challenge;
4081 dhops = (struct DVPathEntryP *) &fwd[1];
4082 GNUNET_memcpy (dhops,
4084 sizeof (struct DVPathEntryP) * nhops);
4085 dhops[nhops].hop = GST_my_identity;
4087 struct DvHopPS dhp = {
4088 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
4089 .purpose.size = htonl (sizeof (dhp)),
4090 .pred = dhops[nhops-1].hop,
4092 .challenge = msg->challenge
4095 GNUNET_assert (GNUNET_OK ==
4096 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4098 &dhops[nhops].hop_sig));
4100 route_message (next_hop,
4106 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
4108 * @param init the signer
4109 * @param challenge the challenge that was signed
4110 * @param init_sig signature presumably by @a init
4111 * @return #GNUNET_OK if the signature is valid
4114 validate_dv_initiator_signature (const struct GNUNET_PeerIdentity *init,
4115 const struct GNUNET_ShortHashCode *challenge,
4116 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
4118 struct DvInitPS ip = {
4119 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
4120 .purpose.size = htonl (sizeof (ip)),
4121 .challenge = *challenge
4125 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
4130 GNUNET_break_op (0);
4131 return GNUNET_SYSERR;
4138 * Communicator gave us a DV learn message. Process the request.
4140 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4141 * @param dvl the message that was received
4144 handle_dv_learn (void *cls,
4145 const struct TransportDVLearn *dvl)
4147 struct CommunicatorMessageContext *cmc = cls;
4148 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
4151 uint16_t bi_history;
4152 const struct DVPathEntryP *hops;
4155 struct GNUNET_TIME_Absolute in_time;
4157 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
4158 bi_history = ntohs (dvl->bidirectional);
4159 hops = (const struct DVPathEntryP *) &dvl[1];
4163 if (0 != GNUNET_memcmp (&dvl->initiator,
4167 finish_cmc_handling (cmc);
4174 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop,
4178 finish_cmc_handling (cmc);
4183 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
4184 cc = cmc->tc->details.communicator.cc;
4185 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE == cc); // FIXME: add bi-directional flag to cc?
4186 in_time = GNUNET_TIME_absolute_get ();
4188 /* continue communicator here, everything else can happen asynchronous! */
4189 finish_cmc_handling (cmc);
4191 // FIXME: should we bother to verify _every_ DV initiator signature?
4193 validate_dv_initiator_signature (&dvl->initiator,
4197 GNUNET_break_op (0);
4200 // FIXME: asynchronously (!) verify hop-by-hop signatures!
4201 // => if signature verification load too high, implement random drop strategy!
4203 do_fwd = GNUNET_YES;
4204 if (0 == GNUNET_memcmp (&GST_my_identity,
4207 struct GNUNET_PeerIdentity path[nhops + 1];
4208 struct GNUNET_TIME_Relative host_latency_sum;
4209 struct GNUNET_TIME_Relative latency;
4210 struct GNUNET_TIME_Relative network_latency;
4212 /* We initiated this, learn the forward path! */
4213 path[0] = GST_my_identity;
4214 path[1] = hops[0].hop;
4215 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
4217 // Need also something to lookup initiation time
4218 // to compute RTT! -> add RTT argument here?
4219 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
4220 // (based on dvl->challenge, we can identify time of origin!)
4222 network_latency = GNUNET_TIME_relative_subtract (latency,
4224 /* assumption: latency on all links is the same */
4225 network_latency = GNUNET_TIME_relative_divide (network_latency,
4228 for (unsigned int i=2;i<=nhops;i++)
4230 struct GNUNET_TIME_Relative ilat;
4232 /* assumption: linear latency increase per hop */
4233 ilat = GNUNET_TIME_relative_multiply (network_latency,
4235 path[i] = hops[i-1].hop;
4236 learn_dv_path (path,
4240 /* as we initiated, do not forward again (would be circular!) */
4246 /* last hop was bi-directional, we could learn something here! */
4247 struct GNUNET_PeerIdentity path[nhops + 2];
4249 path[0] = GST_my_identity;
4250 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
4251 for (unsigned int i=0;i<nhops;i++)
4255 if (0 == (bi_history & (1 << i)))
4256 break; /* i-th hop not bi-directional, stop learning! */
4259 path[i + 2] = dvl->initiator;
4263 path[i + 2] = hops[nhops - i - 2].hop;
4266 iret = learn_dv_path (path,
4268 GNUNET_TIME_UNIT_FOREVER_REL);
4269 if (GNUNET_SYSERR == iret)
4271 /* path invalid or too long to be interesting for US, thus should also
4272 not be interesting to our neighbours, cut path when forwarding to
4273 'i' hops, except of course for the one that goes back to the
4275 GNUNET_STATISTICS_update (GST_stats,
4276 "# DV learn not forwarded due invalidity of path",
4282 if ( (GNUNET_NO == iret) &&
4285 /* we have better paths, and this is the longest target,
4286 so there cannot be anything interesting later */
4287 GNUNET_STATISTICS_update (GST_stats,
4288 "# DV learn not forwarded, got better paths",
4297 if (MAX_DV_HOPS_ALLOWED == nhops)
4299 /* At limit, we're out of here! */
4300 finish_cmc_handling (cmc);
4304 /* Forward to initiator, if path non-trivial and possible */
4305 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
4306 did_initiator = GNUNET_NO;
4309 GNUNET_CONTAINER_multipeermap_contains (neighbours,
4312 /* send back to origin! */
4313 forward_dv_learn (&dvl->initiator,
4319 did_initiator = GNUNET_YES;
4321 /* We forward under two conditions: either we still learned something
4322 ourselves (do_fwd), or the path was darn short and thus the initiator is
4323 likely to still be very interested in this (and we did NOT already
4324 send it back to the initiator) */
4326 ( (nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
4327 (GNUNET_NO == did_initiator) ) )
4329 /* FIXME: loop over all neighbours, pick those with low
4330 queues AND that are not yet on the path; possibly
4331 adapt threshold to nhops! */
4333 forward_dv_learn (NULL, // fill in peer from iterator here!
4345 * Communicator gave us a DV box. Check the message.
4347 * @param cls a `struct CommunicatorMessageContext`
4348 * @param dvb the send message that was sent
4349 * @return #GNUNET_YES if message is well-formed
4352 check_dv_box (void *cls,
4353 const struct TransportDVBox *dvb)
4355 uint16_t size = ntohs (dvb->header.size);
4356 uint16_t num_hops = ntohs (dvb->num_hops);
4357 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
4358 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
4362 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct GNUNET_MessageHeader))
4364 GNUNET_break_op (0);
4365 return GNUNET_SYSERR;
4367 isize = ntohs (inbox->size);
4368 if (size != sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
4370 GNUNET_break_op (0);
4371 return GNUNET_SYSERR;
4373 itype = ntohs (inbox->type);
4374 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
4375 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype) )
4377 GNUNET_break_op (0);
4378 return GNUNET_SYSERR;
4385 * Communicator gave us a DV box. Process the request.
4387 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4388 * @param dvb the message that was received
4391 handle_dv_box (void *cls,
4392 const struct TransportDVBox *dvb)
4394 struct CommunicatorMessageContext *cmc = cls;
4395 uint16_t size = ntohs (dvb->header.size) - sizeof (*dvb);
4396 uint16_t num_hops = ntohs (dvb->num_hops);
4397 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
4398 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
4402 // FIXME: if we are not the target, shorten path and forward along.
4403 // Try from the _end_ of hops array if we know the given
4404 // neighbour (shortening the path!).
4405 // NOTE: increment total_hops!
4406 finish_cmc_handling (cmc);
4409 /* We are the target. Unbox and handle message. */
4410 cmc->im.sender = dvb->origin;
4411 cmc->total_hops = ntohs (dvb->total_hops);
4412 demultiplex_with_cmc (cmc,
4418 * Client notified us about transmission from a peer. Process the request.
4420 * @param cls a `struct TransportClient` which sent us the message
4421 * @param obm the send message that was sent
4422 * @return #GNUNET_YES if message is well-formed
4425 check_incoming_msg (void *cls,
4426 const struct GNUNET_TRANSPORT_IncomingMessage *im)
4428 struct TransportClient *tc = cls;
4430 if (CT_COMMUNICATOR != tc->type)
4433 return GNUNET_SYSERR;
4435 GNUNET_MQ_check_boxed_message (im);
4441 * Communicator gave us a transport address validation challenge. Process the request.
4443 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4444 * @param tvc the message that was received
4447 handle_validation_challenge (void *cls,
4448 const struct TransportValidationChallenge *tvc)
4450 struct CommunicatorMessageContext *cmc = cls;
4451 struct TransportValidationResponse *tvr;
4453 if (cmc->total_hops > 0)
4455 /* DV routing is not allowed for validation challenges! */
4456 GNUNET_break_op (0);
4457 finish_cmc_handling (cmc);
4460 tvr = GNUNET_new (struct TransportValidationResponse);
4461 tvr->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
4462 tvr->header.size = htons (sizeof (*tvr));
4463 tvr->challenge = tvc->challenge;
4464 tvr->origin_time = tvc->sender_time;
4465 tvr->validity_duration = cmc->im.expected_address_validity;
4467 /* create signature */
4468 struct TransportValidationPS tvp = {
4469 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
4470 .purpose.size = htonl (sizeof (tvp)),
4471 .validity_duration = tvr->validity_duration,
4472 .challenge = tvc->challenge
4475 GNUNET_assert (GNUNET_OK ==
4476 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4480 route_message (&cmc->im.sender,
4482 finish_cmc_handling (cmc);
4487 * Closure for #check_known_challenge.
4489 struct CheckKnownChallengeContext
4492 * Set to the challenge we are looking for.
4494 const struct GNUNET_ShortHashCode *challenge;
4497 * Set to a matching validation state, if one was found.
4499 struct ValidationState *vs;
4504 * Test if the validation state in @a value matches the
4505 * challenge from @a cls.
4507 * @param cls a `struct CheckKnownChallengeContext`
4508 * @param pid unused (must match though)
4509 * @param value a `struct ValidationState`
4510 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
4513 check_known_challenge (void *cls,
4514 const struct GNUNET_PeerIdentity *pid,
4517 struct CheckKnownChallengeContext *ckac = cls;
4518 struct ValidationState *vs = value;
4521 if (0 != GNUNET_memcmp (&vs->challenge,
4530 * Function called when peerstore is done storing a
4531 * validated address.
4533 * @param cls a `struct ValidationState`
4534 * @param success #GNUNET_YES on success
4537 peerstore_store_validation_cb (void *cls,
4540 struct ValidationState *vs = cls;
4543 if (GNUNET_YES == success)
4545 GNUNET_STATISTICS_update (GST_stats,
4546 "# Peerstore failed to store foreign address",
4553 * Task run periodically to validate some address based on #validation_heap.
4558 validation_start_cb (void *cls);
4562 * Set the time for next_challenge of @a vs to @a new_time.
4563 * Updates the heap and if necessary reschedules the job.
4565 * @param vs validation state to update
4566 * @param new_time new time for revalidation
4569 update_next_challenge_time (struct ValidationState *vs,
4570 struct GNUNET_TIME_Absolute new_time)
4572 struct GNUNET_TIME_Relative delta;
4574 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
4575 return; /* be lazy */
4576 vs->next_challenge = new_time;
4578 vs->hn = GNUNET_CONTAINER_heap_insert (validation_heap,
4580 new_time.abs_value_us);
4582 GNUNET_CONTAINER_heap_update_cost (vs->hn,
4583 new_time.abs_value_us);
4584 if ( (vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
4585 (NULL != validation_task) )
4587 if (NULL != validation_task)
4588 GNUNET_SCHEDULER_cancel (validation_task);
4589 /* randomize a bit */
4590 delta.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
4591 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
4592 new_time = GNUNET_TIME_absolute_add (new_time,
4594 validation_task = GNUNET_SCHEDULER_add_at (new_time,
4595 &validation_start_cb,
4601 * Communicator gave us a transport address validation response. Process the request.
4603 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
4604 * @param tvr the message that was received
4607 handle_validation_response (void *cls,
4608 const struct TransportValidationResponse *tvr)
4610 struct CommunicatorMessageContext *cmc = cls;
4611 struct ValidationState *vs;
4612 struct CheckKnownChallengeContext ckac = {
4613 .challenge = &tvr->challenge,
4616 struct GNUNET_TIME_Absolute origin_time;
4618 /* check this is one of our challenges */
4619 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
4621 &check_known_challenge,
4623 if (NULL == (vs = ckac.vs))
4625 /* This can happen simply if we 'forgot' the challenge by now,
4626 i.e. because we received the validation response twice */
4627 GNUNET_STATISTICS_update (GST_stats,
4628 "# Validations dropped, challenge unknown",
4631 finish_cmc_handling (cmc);
4635 /* sanity check on origin time */
4636 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
4637 if ( (origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
4638 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us) )
4640 GNUNET_break_op (0);
4641 finish_cmc_handling (cmc);
4646 /* check signature */
4647 struct TransportValidationPS tvp = {
4648 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
4649 .purpose.size = htonl (sizeof (tvp)),
4650 .validity_duration = tvr->validity_duration,
4651 .challenge = tvr->challenge
4655 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
4658 &cmc->im.sender.public_key))
4660 GNUNET_break_op (0);
4661 finish_cmc_handling (cmc);
4666 /* validity is capped by our willingness to keep track of the
4667 validation entry and the maximum the other peer allows */
4669 = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (tvr->validity_duration),
4670 MAX_ADDRESS_VALID_UNTIL));
4672 = GNUNET_TIME_absolute_min (vs->valid_until,
4673 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME));
4674 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
4675 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
4676 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4678 sizeof (vs->challenge));
4679 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (vs->validated_until,
4680 GNUNET_TIME_relative_multiply (vs->validation_rtt,
4681 VALIDATION_RTT_BUFFER_FACTOR));
4682 vs->last_challenge_use = GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
4683 update_next_challenge_time (vs,
4684 vs->first_challenge_use);
4685 vs->sc = GNUNET_PEERSTORE_store (peerstore,
4688 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
4690 strlen (vs->address) + 1,
4692 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
4693 &peerstore_store_validation_cb,
4695 // FIXME: should we find the matching queue and update the RTT?
4696 finish_cmc_handling (cmc);
4701 * Incoming meessage. Process the request.
4703 * @param im the send message that was received
4706 handle_incoming_msg (void *cls,
4707 const struct GNUNET_TRANSPORT_IncomingMessage *im)
4709 struct TransportClient *tc = cls;
4710 struct CommunicatorMessageContext *cmc = GNUNET_new (struct CommunicatorMessageContext);
4714 demultiplex_with_cmc (cmc,
4715 (const struct GNUNET_MessageHeader *) &im[1]);
4720 * Given an inbound message @a msg from a communicator @a cmc,
4721 * demultiplex it based on the type calling the right handler.
4723 * @param cmc context for demultiplexing
4724 * @param msg message to demultiplex
4727 demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
4728 const struct GNUNET_MessageHeader *msg)
4730 struct GNUNET_MQ_MessageHandler handlers[] = {
4731 GNUNET_MQ_hd_var_size (fragment_box,
4732 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
4733 struct TransportFragmentBox,
4735 GNUNET_MQ_hd_fixed_size (fragment_ack,
4736 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
4737 struct TransportFragmentAckMessage,
4739 GNUNET_MQ_hd_var_size (reliability_box,
4740 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
4741 struct TransportReliabilityBox,
4743 GNUNET_MQ_hd_fixed_size (reliability_ack,
4744 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
4745 struct TransportReliabilityAckMessage,
4747 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
4748 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
4749 struct TransportBackchannelEncapsulationMessage,
4751 GNUNET_MQ_hd_var_size (dv_learn,
4752 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
4753 struct TransportDVLearn,
4755 GNUNET_MQ_hd_var_size (dv_box,
4756 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
4757 struct TransportDVBox,
4759 GNUNET_MQ_hd_fixed_size (validation_challenge,
4760 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
4761 struct TransportValidationChallenge,
4763 GNUNET_MQ_hd_fixed_size (validation_response,
4764 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
4765 struct TransportValidationResponse,
4767 GNUNET_MQ_handler_end()
4771 ret = GNUNET_MQ_handle_message (handlers,
4773 if (GNUNET_SYSERR == ret)
4776 GNUNET_SERVICE_client_drop (cmc->tc->client);
4780 if (GNUNET_NO == ret)
4782 /* unencapsulated 'raw' message */
4783 handle_raw_message (&cmc,
4790 * New queue became available. Check message.
4792 * @param cls the client
4793 * @param aqm the send message that was sent
4796 check_add_queue_message (void *cls,
4797 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
4799 struct TransportClient *tc = cls;
4801 if (CT_COMMUNICATOR != tc->type)
4804 return GNUNET_SYSERR;
4806 GNUNET_MQ_check_zero_termination (aqm);
4812 * Bandwidth tracker informs us that the delay until we should receive
4815 * @param cls a `struct Queue` for which the delay changed
4818 tracker_update_in_cb (void *cls)
4820 struct Queue *queue = cls;
4821 struct GNUNET_TIME_Relative in_delay;
4824 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
4825 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in,
4827 // FIXME: how exactly do we do inbound flow control?
4832 * If necessary, generates the UUID for a @a pm
4834 * @param pm pending message to generate UUID for.
4837 set_pending_message_uuid (struct PendingMessage *pm)
4839 if (pm->msg_uuid_set)
4841 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4843 sizeof (pm->msg_uuid));
4844 pm->msg_uuid_set = GNUNET_YES;
4849 * Fragment the given @a pm to the given @a mtu. Adds
4850 * additional fragments to the neighbour as well. If the
4851 * @a mtu is too small, generates and error for the @a pm
4854 * @param pm pending message to fragment for transmission
4855 * @param mtu MTU to apply
4856 * @return new message to transmit
4858 static struct PendingMessage *
4859 fragment_message (struct PendingMessage *pm,
4862 struct PendingMessage *ff;
4864 set_pending_message_uuid (pm);
4866 /* This invariant is established in #handle_add_queue_message() */
4867 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
4869 /* select fragment for transmission, descending the tree if it has
4870 been expanded until we are at a leaf or at a fragment that is small enough */
4872 while ( ( (ff->bytes_msg > mtu) ||
4874 (ff->frag_off == ff->bytes_msg) &&
4875 (NULL != ff->head_frag) )
4877 ff = ff->head_frag; /* descent into fragmented fragments */
4880 if ( ( (ff->bytes_msg > mtu) ||
4882 (pm->frag_off < pm->bytes_msg) )
4884 /* Did not yet calculate all fragments, calculate next fragment */
4885 struct PendingMessage *frag;
4886 struct TransportFragmentBox tfb;
4894 orig = (const char *) &ff[1];
4895 msize = ff->bytes_msg;
4898 const struct TransportFragmentBox *tfbo;
4900 tfbo = (const struct TransportFragmentBox *) orig;
4901 orig += sizeof (struct TransportFragmentBox);
4902 msize -= sizeof (struct TransportFragmentBox);
4903 xoff = ntohs (tfbo->frag_off);
4905 fragmax = mtu - sizeof (struct TransportFragmentBox);
4906 fragsize = GNUNET_MIN (msize - ff->frag_off,
4908 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
4909 sizeof (struct TransportFragmentBox) +
4911 frag->target = pm->target;
4912 frag->frag_parent = ff;
4913 frag->timeout = pm->timeout;
4914 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
4915 frag->pmt = PMT_FRAGMENT_BOX;
4916 msg = (char *) &frag[1];
4917 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
4918 tfb.header.size = htons (sizeof (struct TransportFragmentBox) +
4920 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
4921 tfb.msg_uuid = pm->msg_uuid;
4922 tfb.frag_off = htons (ff->frag_off + xoff);
4923 tfb.msg_size = htons (pm->bytes_msg);
4927 memcpy (&msg[sizeof (tfb)],
4928 &orig[ff->frag_off],
4930 GNUNET_CONTAINER_MDLL_insert (frag,
4934 ff->frag_off += fragsize;
4938 /* Move head to the tail and return it */
4939 GNUNET_CONTAINER_MDLL_remove (frag,
4940 ff->frag_parent->head_frag,
4941 ff->frag_parent->tail_frag,
4943 GNUNET_CONTAINER_MDLL_insert_tail (frag,
4944 ff->frag_parent->head_frag,
4945 ff->frag_parent->tail_frag,
4952 * Reliability-box the given @a pm. On error (can there be any), NULL
4953 * may be returned, otherwise the "replacement" for @a pm (which
4954 * should then be added to the respective neighbour's queue instead of
4955 * @a pm). If the @a pm is already fragmented or reliability boxed,
4956 * or itself an ACK, this function simply returns @a pm.
4958 * @param pm pending message to box for transmission over unreliabile queue
4959 * @return new message to transmit
4961 static struct PendingMessage *
4962 reliability_box_message (struct PendingMessage *pm)
4964 struct TransportReliabilityBox rbox;
4965 struct PendingMessage *bpm;
4968 if (PMT_CORE != pm->pmt)
4969 return pm; /* already fragmented or reliability boxed, or control message: do nothing */
4970 if (NULL != pm->bpm)
4971 return pm->bpm; /* already computed earlier: do nothing */
4972 GNUNET_assert (NULL == pm->head_frag);
4973 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
4977 client_send_response (pm,
4982 bpm = GNUNET_malloc (sizeof (struct PendingMessage) +
4985 bpm->target = pm->target;
4986 bpm->frag_parent = pm;
4987 GNUNET_CONTAINER_MDLL_insert (frag,
4991 bpm->timeout = pm->timeout;
4992 bpm->pmt = PMT_RELIABILITY_BOX;
4993 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
4994 set_pending_message_uuid (bpm);
4995 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
4996 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
4997 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
4998 rbox.msg_uuid = pm->msg_uuid;
4999 msg = (char *) &bpm[1];
5003 memcpy (&msg[sizeof (rbox)],
5012 * We believe we are ready to transmit a message on a queue. Double-checks
5013 * with the queue's "tracker_out" and then gives the message to the
5014 * communicator for transmission (updating the tracker, and re-scheduling
5015 * itself if applicable).
5017 * @param cls the `struct Queue` to process transmissions for
5020 transmit_on_queue (void *cls)
5022 struct Queue *queue = cls;
5023 struct Neighbour *n = queue->neighbour;
5024 struct PendingMessage *pm;
5025 struct PendingMessage *s;
5027 struct GNUNET_TRANSPORT_SendMessageTo *smt;
5028 struct GNUNET_MQ_Envelope *env;
5030 queue->transmit_task = NULL;
5031 if (NULL == (pm = n->pending_msg_head))
5033 /* no message pending, nothing to do here! */
5036 schedule_transmit_on_queue (queue);
5037 if (NULL != queue->transmit_task)
5038 return; /* do it later */
5040 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5041 overhead += sizeof (struct TransportReliabilityBox);
5043 if ( ( (0 != queue->mtu) &&
5044 (pm->bytes_msg + overhead > queue->mtu) ) ||
5045 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
5046 (NULL != pm->head_frag /* fragments already exist, should
5047 respect that even if MTU is 0 for
5049 s = fragment_message (s,
5051 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
5055 /* Fragmentation failed, try next message... */
5056 schedule_transmit_on_queue (queue);
5059 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
5060 s = reliability_box_message (s);
5063 /* Reliability boxing failed, try next message... */
5064 schedule_transmit_on_queue (queue);
5068 /* Pass 's' for transission to the communicator */
5069 env = GNUNET_MQ_msg_extra (smt,
5071 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
5072 smt->qid = queue->qid;
5073 smt->mid = queue->mid_gen;
5074 smt->receiver = n->pid;
5079 /* Pass the env to the communicator of queue for transmission. */
5080 struct QueueEntry *qe;
5082 qe = GNUNET_new (struct QueueEntry);
5083 qe->mid = queue->mid_gen++;
5085 // qe->pm = s; // FIXME: not so easy, reference management on 'free(s)'!
5086 GNUNET_CONTAINER_DLL_insert (queue->queue_head,
5089 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5090 queue->queue_length++;
5091 queue->tc->details.communicator.total_queue_length++;
5092 GNUNET_MQ_send (queue->tc->mq,
5096 // FIXME: do something similar to the logic below
5097 // in defragmentation / reliability ACK handling!
5099 /* Check if this transmission somehow conclusively finished handing 'pm'
5100 even without any explicit ACKs */
5101 if ( (PMT_CORE == s->pmt) &&
5102 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) )
5104 /* Full message sent, and over reliabile channel */
5105 client_send_response (pm,
5109 else if ( (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) &&
5110 (PMT_FRAGMENT_BOX == s->pmt) )
5112 struct PendingMessage *pos;
5114 /* Fragment sent over reliabile channel */
5115 free_fragment_tree (s);
5116 pos = s->frag_parent;
5117 GNUNET_CONTAINER_MDLL_remove (frag,
5122 /* check if subtree is done */
5123 while ( (NULL == pos->head_frag) &&
5124 (pos->frag_off == pos->bytes_msg) &&
5128 pos = s->frag_parent;
5129 GNUNET_CONTAINER_MDLL_remove (frag,
5136 /* Was this the last applicable fragmment? */
5137 if ( (NULL == pm->head_frag) &&
5138 (pm->frag_off == pm->bytes_msg) )
5139 client_send_response (pm,
5141 pm->bytes_msg /* FIXME: calculate and add overheads! */);
5143 else if (PMT_CORE != pm->pmt)
5145 /* This was an acknowledgement of some type, always free */
5146 free_pending_message (pm);
5150 /* message not finished, waiting for acknowledgement */
5151 struct Neighbour *neighbour = pm->target;
5152 /* Update time by which we might retransmit 's' based on queue
5153 characteristics (i.e. RTT); it takes one RTT for the message to
5154 arrive and the ACK to come back in the best case; but the other
5155 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
5156 retransmitting. Note that in the future this heuristic should
5157 likely be improved further (measure RTT stability, consider
5158 message urgency and size when delaying ACKs, etc.) */
5159 s->next_attempt = GNUNET_TIME_relative_to_absolute
5160 (GNUNET_TIME_relative_multiply (queue->rtt,
5164 struct PendingMessage *pos;
5166 /* re-insert sort in neighbour list */
5167 GNUNET_CONTAINER_MDLL_remove (neighbour,
5168 neighbour->pending_msg_head,
5169 neighbour->pending_msg_tail,
5171 pos = neighbour->pending_msg_tail;
5172 while ( (NULL != pos) &&
5173 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5174 pos = pos->prev_neighbour;
5175 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
5176 neighbour->pending_msg_head,
5177 neighbour->pending_msg_tail,
5183 /* re-insert sort in fragment list */
5184 struct PendingMessage *fp = s->frag_parent;
5185 struct PendingMessage *pos;
5187 GNUNET_CONTAINER_MDLL_remove (frag,
5191 pos = fp->tail_frag;
5192 while ( (NULL != pos) &&
5193 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
5194 pos = pos->prev_frag;
5195 GNUNET_CONTAINER_MDLL_insert_after (frag,
5203 /* finally, re-schedule queue transmission task itself */
5204 schedule_transmit_on_queue (queue);
5209 * Bandwidth tracker informs us that the delay until we
5210 * can transmit again changed.
5212 * @param cls a `struct Queue` for which the delay changed
5215 tracker_update_out_cb (void *cls)
5217 struct Queue *queue = cls;
5218 struct Neighbour *n = queue->neighbour;
5220 if (NULL == n->pending_msg_head)
5222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5223 "Bandwidth allocation updated for empty transmission queue `%s'\n",
5225 return; /* no message pending, nothing to do here! */
5227 GNUNET_SCHEDULER_cancel (queue->transmit_task);
5228 queue->transmit_task = NULL;
5229 schedule_transmit_on_queue (queue);
5234 * Bandwidth tracker informs us that excessive outbound bandwidth was
5235 * allocated which is not being used.
5237 * @param cls a `struct Queue` for which the excess was noted
5240 tracker_excess_out_cb (void *cls)
5242 /* FIXME: trigger excess bandwidth report to core? Right now,
5243 this is done internally within transport_api2_core already,
5244 but we probably want to change the logic and trigger it
5245 from here via a message instead! */
5246 /* TODO: maybe inform someone at this point? */
5247 GNUNET_STATISTICS_update (GST_stats,
5248 "# Excess outbound bandwidth reported",
5256 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
5257 * which is not being used.
5259 * @param cls a `struct Queue` for which the excess was noted
5262 tracker_excess_in_cb (void *cls)
5264 /* TODO: maybe inform somone at this point? */
5265 GNUNET_STATISTICS_update (GST_stats,
5266 "# Excess inbound bandwidth reported",
5273 * Queue to a peer went down. Process the request.
5275 * @param cls the client
5276 * @param dqm the send message that was sent
5279 handle_del_queue_message (void *cls,
5280 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
5282 struct TransportClient *tc = cls;
5284 if (CT_COMMUNICATOR != tc->type)
5287 GNUNET_SERVICE_client_drop (tc->client);
5290 for (struct Queue *queue = tc->details.communicator.queue_head;
5292 queue = queue->next_client)
5294 struct Neighbour *neighbour = queue->neighbour;
5296 if ( (dqm->qid != queue->qid) ||
5297 (0 != GNUNET_memcmp (&dqm->receiver,
5301 GNUNET_SERVICE_client_continue (tc->client);
5305 GNUNET_SERVICE_client_drop (tc->client);
5310 * Message was transmitted. Process the request.
5312 * @param cls the client
5313 * @param sma the send message that was sent
5316 handle_send_message_ack (void *cls,
5317 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
5319 struct TransportClient *tc = cls;
5320 struct QueueEntry *qe;
5322 if (CT_COMMUNICATOR != tc->type)
5325 GNUNET_SERVICE_client_drop (tc->client);
5329 /* find our queue entry matching the ACK */
5331 for (struct Queue *queue = tc->details.communicator.queue_head;
5333 queue = queue->next_client)
5335 if (0 != GNUNET_memcmp (&queue->neighbour->pid,
5338 for (struct QueueEntry *qep = queue->queue_head;
5342 if (qep->mid != sma->mid)
5351 /* this should never happen */
5353 GNUNET_SERVICE_client_drop (tc->client);
5356 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
5357 qe->queue->queue_tail,
5359 qe->queue->queue_length--;
5360 tc->details.communicator.total_queue_length--;
5361 GNUNET_SERVICE_client_continue (tc->client);
5363 /* if applicable, resume transmissions that waited on ACK */
5364 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 == tc->details.communicator.total_queue_length)
5366 /* Communicator dropped below threshold, resume all queues */
5367 GNUNET_STATISTICS_update (GST_stats,
5368 "# Transmission throttled due to communicator queue limit",
5371 for (struct Queue *queue = tc->details.communicator.queue_head;
5373 queue = queue->next_client)
5374 schedule_transmit_on_queue (queue);
5376 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
5378 /* queue dropped below threshold; only resume this one queue */
5379 GNUNET_STATISTICS_update (GST_stats,
5380 "# Transmission throttled due to queue queue limit",
5383 schedule_transmit_on_queue (qe->queue);
5386 /* TODO: we also should react on the status! */
5387 // FIXME: this probably requires queue->pm = s assignment!
5388 // FIXME: react to communicator status about transmission request. We got:
5389 sma->status; // OK success, SYSERR failure
5396 * Iterator telling new MONITOR client about all existing
5399 * @param cls the new `struct TransportClient`
5400 * @param pid a connected peer
5401 * @param value the `struct Neighbour` with more information
5402 * @return #GNUNET_OK (continue to iterate)
5405 notify_client_queues (void *cls,
5406 const struct GNUNET_PeerIdentity *pid,
5409 struct TransportClient *tc = cls;
5410 struct Neighbour *neighbour = value;
5412 GNUNET_assert (CT_MONITOR == tc->type);
5413 for (struct Queue *q = neighbour->queue_head;
5415 q = q->next_neighbour)
5417 struct MonitorEvent me = {
5420 .num_msg_pending = q->num_msg_pending,
5421 .num_bytes_pending = q->num_bytes_pending
5435 * Initialize a monitor client.
5437 * @param cls the client
5438 * @param start the start message that was sent
5441 handle_monitor_start (void *cls,
5442 const struct GNUNET_TRANSPORT_MonitorStart *start)
5444 struct TransportClient *tc = cls;
5446 if (CT_NONE != tc->type)
5449 GNUNET_SERVICE_client_drop (tc->client);
5452 tc->type = CT_MONITOR;
5453 tc->details.monitor.peer = start->peer;
5454 tc->details.monitor.one_shot = ntohl (start->one_shot);
5455 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
5456 ¬ify_client_queues,
5458 GNUNET_SERVICE_client_mark_monitor (tc->client);
5459 GNUNET_SERVICE_client_continue (tc->client);
5464 * Find transport client providing communication service
5465 * for the protocol @a prefix.
5467 * @param prefix communicator name
5468 * @return NULL if no such transport client is available
5470 static struct TransportClient *
5471 lookup_communicator (const char *prefix)
5473 for (struct TransportClient *tc = clients_head;
5477 if (CT_COMMUNICATOR != tc->type)
5479 if (0 == strcmp (prefix,
5480 tc->details.communicator.address_prefix))
5483 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5484 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
5491 * Signature of a function called with a communicator @a address of a peer
5492 * @a pid that an application wants us to connect to.
5494 * @param pid target peer
5495 * @param address the address to try
5498 suggest_to_connect (const struct GNUNET_PeerIdentity *pid,
5499 const char *address)
5501 static uint32_t idgen;
5502 struct TransportClient *tc;
5504 struct GNUNET_TRANSPORT_CreateQueue *cqm;
5505 struct GNUNET_MQ_Envelope *env;
5508 prefix = GNUNET_HELLO_address_to_prefix (address);
5511 GNUNET_break (0); /* We got an invalid address!? */
5514 tc = lookup_communicator (prefix);
5517 GNUNET_STATISTICS_update (GST_stats,
5518 "# Suggestions ignored due to missing communicator",
5523 /* forward suggestion for queue creation to communicator */
5524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5525 "Request #%u for `%s' communicator to create queue to `%s'\n",
5526 (unsigned int) idgen,
5529 alen = strlen (address) + 1;
5530 env = GNUNET_MQ_msg_extra (cqm,
5532 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
5533 cqm->request_id = htonl (idgen++);
5534 cqm->receiver = *pid;
5538 GNUNET_MQ_send (tc->mq,
5544 * The queue @a q (which matches the peer and address in @a vs) is
5545 * ready for queueing. We should now queue the validation request.
5547 * @param q queue to send on
5548 * @param vs state to derive validation challenge from
5551 validation_transmit_on_queue (struct Queue *q,
5552 struct ValidationState *vs)
5554 struct GNUNET_MQ_Envelope *env;
5555 struct TransportValidationChallenge *tvc;
5557 vs->last_challenge_use = GNUNET_TIME_absolute_get ();
5558 env = GNUNET_MQ_msg (tvc,
5559 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
5560 tvc->reserved = htonl (0);
5561 tvc->challenge = vs->challenge;
5562 tvc->sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
5563 GNUNET_MQ_send (q->tc->mq,
5569 * Task run periodically to validate some address based on #validation_heap.
5574 validation_start_cb (void *cls)
5576 struct ValidationState *vs;
5577 struct Neighbour *n;
5581 validation_task = NULL;
5582 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
5583 /* drop validations past their expiration */
5584 while ( (NULL != vs) &&
5585 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us) )
5587 free_validation_state (vs);
5588 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
5591 return; /* woopsie, no more addresses known, should only
5592 happen if we're really a lonely peer */
5593 n = GNUNET_CONTAINER_multipeermap_get (neighbours,
5598 for (struct Queue *pos = n->queue_head;
5600 pos = pos->next_neighbour)
5602 if (0 == strcmp (pos->address,
5612 vs->awaiting_queue = GNUNET_YES;
5613 suggest_to_connect (&vs->pid,
5617 validation_transmit_on_queue (q,
5619 /* Finally, reschedule next attempt */
5620 vs->challenge_backoff = GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
5621 MAX_VALIDATION_CHALLENGE_FREQ);
5622 update_next_challenge_time (vs,
5623 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
5628 * A new queue has been created, check if any address validation
5629 * requests have been waiting for it.
5631 * @param cls a `struct Queue`
5632 * @param pid peer concerned (unused)
5633 * @param value a `struct ValidationState`
5634 * @return #GNUNET_NO if a match was found and we can stop looking
5637 check_validation_request_pending (void *cls,
5638 const struct GNUNET_PeerIdentity *pid,
5641 struct Queue *q = cls;
5642 struct ValidationState *vs = value;
5645 if ( (GNUNET_YES == vs->awaiting_queue) &&
5646 (0 == strcmp (vs->address,
5649 vs->awaiting_queue = GNUNET_NO;
5650 validation_transmit_on_queue (q,
5659 * New queue became available. Process the request.
5661 * @param cls the client
5662 * @param aqm the send message that was sent
5665 handle_add_queue_message (void *cls,
5666 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
5668 struct TransportClient *tc = cls;
5669 struct Queue *queue;
5670 struct Neighbour *neighbour;
5674 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
5676 /* MTU so small as to be useless for transmissions,
5677 required for #fragment_message()! */
5678 GNUNET_break_op (0);
5679 GNUNET_SERVICE_client_drop (tc->client);
5682 neighbour = lookup_neighbour (&aqm->receiver);
5683 if (NULL == neighbour)
5685 neighbour = GNUNET_new (struct Neighbour);
5686 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
5687 neighbour->pid = aqm->receiver;
5688 GNUNET_assert (GNUNET_OK ==
5689 GNUNET_CONTAINER_multipeermap_put (neighbours,
5692 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5693 cores_send_connect_info (&neighbour->pid,
5694 GNUNET_BANDWIDTH_ZERO);
5696 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
5697 addr = (const char *) &aqm[1];
5699 queue = GNUNET_malloc (sizeof (struct Queue) + addr_len);
5701 queue->address = (const char *) &queue[1];
5702 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
5703 queue->qid = aqm->qid;
5704 queue->mtu = ntohl (aqm->mtu);
5705 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
5706 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
5707 queue->neighbour = neighbour;
5708 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
5709 &tracker_update_in_cb,
5711 GNUNET_BANDWIDTH_ZERO,
5712 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
5713 &tracker_excess_in_cb,
5715 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
5716 &tracker_update_out_cb,
5718 GNUNET_BANDWIDTH_ZERO,
5719 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
5720 &tracker_excess_out_cb,
5725 /* notify monitors about new queue */
5727 struct MonitorEvent me = {
5732 notify_monitors (&neighbour->pid,
5737 GNUNET_CONTAINER_MDLL_insert (neighbour,
5738 neighbour->queue_head,
5739 neighbour->queue_tail,
5741 GNUNET_CONTAINER_MDLL_insert (client,
5742 tc->details.communicator.queue_head,
5743 tc->details.communicator.queue_tail,
5745 /* check if valdiations are waiting for the queue */
5746 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5748 &check_validation_request_pending,
5750 GNUNET_SERVICE_client_continue (tc->client);
5755 * Communicator tells us that our request to create a queue "worked", that
5756 * is setting up the queue is now in process.
5758 * @param cls the `struct TransportClient`
5759 * @param cqr confirmation message
5762 handle_queue_create_ok (void *cls,
5763 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
5765 struct TransportClient *tc = cls;
5767 if (CT_COMMUNICATOR != tc->type)
5770 GNUNET_SERVICE_client_drop (tc->client);
5773 GNUNET_STATISTICS_update (GST_stats,
5774 "# Suggestions succeeded at communicator",
5777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5778 "Request #%u for communicator to create queue succeeded\n",
5779 (unsigned int) ntohs (cqr->request_id));
5780 GNUNET_SERVICE_client_continue (tc->client);
5785 * Communicator tells us that our request to create a queue failed. This usually
5786 * indicates that the provided address is simply invalid or that the communicator's
5787 * resources are exhausted.
5789 * @param cls the `struct TransportClient`
5790 * @param cqr failure message
5793 handle_queue_create_fail (void *cls,
5794 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
5796 struct TransportClient *tc = cls;
5798 if (CT_COMMUNICATOR != tc->type)
5801 GNUNET_SERVICE_client_drop (tc->client);
5804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5805 "Request #%u for communicator to create queue failed\n",
5806 (unsigned int) ntohs (cqr->request_id));
5807 GNUNET_STATISTICS_update (GST_stats,
5808 "# Suggestions failed in queue creation at communicator",
5811 GNUNET_SERVICE_client_continue (tc->client);
5816 * We have received a `struct ExpressPreferenceMessage` from an application client.
5818 * @param cls handle to the client
5819 * @param msg the start message
5822 handle_suggest_cancel (void *cls,
5823 const struct ExpressPreferenceMessage *msg)
5825 struct TransportClient *tc = cls;
5826 struct PeerRequest *pr;
5828 if (CT_APPLICATION != tc->type)
5831 GNUNET_SERVICE_client_drop (tc->client);
5834 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
5839 GNUNET_SERVICE_client_drop (tc->client);
5842 (void) stop_peer_request (tc,
5845 GNUNET_SERVICE_client_continue (tc->client);
5850 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
5851 * messages. We do nothing here, real verification is done later.
5853 * @param cls a `struct TransportClient *`
5854 * @param msg message to verify
5855 * @return #GNUNET_OK
5858 check_address_consider_verify (void *cls,
5859 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
5868 * Closure for #check_known_address.
5870 struct CheckKnownAddressContext
5873 * Set to the address we are looking for.
5875 const char *address;
5878 * Set to a matching validation state, if one was found.
5880 struct ValidationState *vs;
5885 * Test if the validation state in @a value matches the
5886 * address from @a cls.
5888 * @param cls a `struct CheckKnownAddressContext`
5889 * @param pid unused (must match though)
5890 * @param value a `struct ValidationState`
5891 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
5894 check_known_address (void *cls,
5895 const struct GNUNET_PeerIdentity *pid,
5898 struct CheckKnownAddressContext *ckac = cls;
5899 struct ValidationState *vs = value;
5902 if (0 != strcmp (vs->address,
5911 * Start address validation.
5913 * @param pid peer the @a address is for
5914 * @param address an address to reach @a pid (presumably)
5915 * @param expiration when did @a pid claim @a address will become invalid
5918 start_address_validation (const struct GNUNET_PeerIdentity *pid,
5919 const char *address,
5920 struct GNUNET_TIME_Absolute expiration)
5922 struct GNUNET_TIME_Absolute now;
5923 struct ValidationState *vs;
5924 struct CheckKnownAddressContext ckac = {
5929 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
5930 return; /* expired */
5931 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
5933 &check_known_address,
5935 if (NULL != (vs = ckac.vs))
5937 /* if 'vs' is not currently valid, we need to speed up retrying the validation */
5938 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
5940 /* reduce backoff as we got a fresh advertisement */
5941 vs->challenge_backoff = GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
5942 GNUNET_TIME_relative_divide (vs->challenge_backoff,
5944 update_next_challenge_time (vs,
5945 GNUNET_TIME_relative_to_absolute (vs->challenge_backoff));
5949 now = GNUNET_TIME_absolute_get();
5950 vs = GNUNET_new (struct ValidationState);
5952 vs->valid_until = expiration;
5953 vs->first_challenge_use = now;
5954 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
5955 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5957 sizeof (vs->challenge));
5958 vs->address = GNUNET_strdup (address);
5959 GNUNET_assert (GNUNET_YES ==
5960 GNUNET_CONTAINER_multipeermap_put (validation_map,
5963 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5964 update_next_challenge_time (vs,
5970 * Function called by PEERSTORE for each matching record.
5972 * @param cls closure
5973 * @param record peerstore record information
5974 * @param emsg error message, or NULL if no errors
5977 handle_hello (void *cls,
5978 const struct GNUNET_PEERSTORE_Record *record,
5981 struct PeerRequest *pr = cls;
5986 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5987 "Got failure from PEERSTORE: %s\n",
5991 val = record->value;
5992 if ( (0 == record->value_size) ||
5993 ('\0' != val[record->value_size - 1]) )
5998 start_address_validation (&pr->pid,
5999 (const char *) record->value,
6005 * We have received a `struct ExpressPreferenceMessage` from an application client.
6007 * @param cls handle to the client
6008 * @param msg the start message
6011 handle_suggest (void *cls,
6012 const struct ExpressPreferenceMessage *msg)
6014 struct TransportClient *tc = cls;
6015 struct PeerRequest *pr;
6017 if (CT_NONE == tc->type)
6019 tc->type = CT_APPLICATION;
6020 tc->details.application.requests
6021 = GNUNET_CONTAINER_multipeermap_create (16,
6024 if (CT_APPLICATION != tc->type)
6027 GNUNET_SERVICE_client_drop (tc->client);
6030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6031 "Client suggested we talk to %s with preference %d at rate %u\n",
6032 GNUNET_i2s (&msg->peer),
6033 (int) ntohl (msg->pk),
6034 (int) ntohl (msg->bw.value__));
6035 pr = GNUNET_new (struct PeerRequest);
6037 pr->pid = msg->peer;
6039 pr->pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
6041 GNUNET_CONTAINER_multipeermap_put (tc->details.application.requests,
6044 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
6048 GNUNET_SERVICE_client_drop (tc->client);
6051 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
6054 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
6057 GNUNET_SERVICE_client_continue (tc->client);
6062 * Given another peers address, consider checking it for validity
6063 * and then adding it to the Peerstore.
6065 * @param cls a `struct TransportClient`
6066 * @param hdr message containing the raw address data and
6067 * signature in the body, see #GNUNET_HELLO_extract_address()
6070 handle_address_consider_verify (void *cls,
6071 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
6073 struct TransportClient *tc = cls;
6075 enum GNUNET_NetworkType nt;
6076 struct GNUNET_TIME_Absolute expiration;
6079 // FIXME: checking that we know this address already should
6080 // be done BEFORE checking the signature => HELLO API change!
6081 // FIXME: pre-check: rate-limit signature verification / validation?!
6082 address = GNUNET_HELLO_extract_address (&hdr[1],
6083 ntohs (hdr->header.size) - sizeof (*hdr),
6087 if (NULL == address)
6089 GNUNET_break_op (0);
6092 start_address_validation (&hdr->peer,
6095 GNUNET_free (address);
6096 GNUNET_SERVICE_client_continue (tc->client);
6101 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
6104 * @param cls a `struct TransportClient *`
6105 * @param m message to verify
6106 * @return #GNUNET_OK on success
6109 check_request_hello_validation (void *cls,
6110 const struct RequestHelloValidationMessage *m)
6112 GNUNET_MQ_check_zero_termination (m);
6118 * A client encountered an address of another peer. Consider validating it,
6119 * and if validation succeeds, persist it to PEERSTORE.
6121 * @param cls a `struct TransportClient *`
6122 * @param m message to verify
6125 handle_request_hello_validation (void *cls,
6126 const struct RequestHelloValidationMessage *m)
6128 struct TransportClient *tc = cls;
6130 start_address_validation (&m->peer,
6131 (const char *) &m[1],
6132 GNUNET_TIME_absolute_ntoh (m->expiration));
6133 GNUNET_SERVICE_client_continue (tc->client);
6138 * Free neighbour entry.
6142 * @param value a `struct Neighbour`
6143 * @return #GNUNET_OK (always)
6146 free_neighbour_cb (void *cls,
6147 const struct GNUNET_PeerIdentity *pid,
6150 struct Neighbour *neighbour = value;
6154 GNUNET_break (0); // should this ever happen?
6155 free_neighbour (neighbour);
6162 * Free DV route entry.
6166 * @param value a `struct DistanceVector`
6167 * @return #GNUNET_OK (always)
6170 free_dv_routes_cb (void *cls,
6171 const struct GNUNET_PeerIdentity *pid,
6174 struct DistanceVector *dv = value;
6185 * Free ephemeral entry.
6189 * @param value a `struct EphemeralCacheEntry`
6190 * @return #GNUNET_OK (always)
6193 free_ephemeral_cb (void *cls,
6194 const struct GNUNET_PeerIdentity *pid,
6197 struct EphemeralCacheEntry *ece = value;
6201 free_ephemeral (ece);
6207 * Free validation state.
6211 * @param value a `struct ValidationState`
6212 * @return #GNUNET_OK (always)
6215 free_validation_state_cb (void *cls,
6216 const struct GNUNET_PeerIdentity *pid,
6219 struct ValidationState *vs = value;
6223 free_validation_state (vs);
6229 * Function called when the service shuts down. Unloads our plugins
6230 * and cancels pending validations.
6232 * @param cls closure, unused
6235 do_shutdown (void *cls)
6239 if (NULL != ephemeral_task)
6241 GNUNET_SCHEDULER_cancel (ephemeral_task);
6242 ephemeral_task = NULL;
6244 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
6247 if (NULL != peerstore)
6249 GNUNET_PEERSTORE_disconnect (peerstore,
6253 if (NULL != GST_stats)
6255 GNUNET_STATISTICS_destroy (GST_stats,
6259 if (NULL != GST_my_private_key)
6261 GNUNET_free (GST_my_private_key);
6262 GST_my_private_key = NULL;
6264 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
6266 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
6267 &free_validation_state_cb,
6269 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
6270 validation_map = NULL;
6271 GNUNET_CONTAINER_heap_destroy (validation_heap);
6272 validation_heap = NULL;
6273 GNUNET_CONTAINER_multipeermap_iterate (dv_routes,
6276 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
6278 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
6281 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
6282 ephemeral_map = NULL;
6283 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
6284 ephemeral_heap = NULL;
6289 * Initiate transport service.
6291 * @param cls closure
6292 * @param c configuration to use
6293 * @param service the initialized service
6297 const struct GNUNET_CONFIGURATION_Handle *c,
6298 struct GNUNET_SERVICE_Handle *service)
6303 neighbours = GNUNET_CONTAINER_multipeermap_create (1024,
6305 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024,
6307 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32,
6309 ephemeral_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
6310 validation_map = GNUNET_CONTAINER_multipeermap_create (1024,
6312 validation_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
6313 GST_my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
6314 if (NULL == GST_my_private_key)
6316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6317 _("Transport service is lacking key configuration settings. Exiting.\n"));
6318 GNUNET_SCHEDULER_shutdown ();
6321 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
6322 &GST_my_identity.public_key);
6323 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
6324 "My identity is `%s'\n",
6325 GNUNET_i2s_full (&GST_my_identity));
6326 GST_stats = GNUNET_STATISTICS_create ("transport",
6328 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
6330 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
6331 if (NULL == peerstore)
6334 GNUNET_SCHEDULER_shutdown ();
6341 * Define "main" method using service macro.
6345 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
6348 &client_disconnect_cb,
6350 /* communication with applications */
6351 GNUNET_MQ_hd_fixed_size (suggest,
6352 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
6353 struct ExpressPreferenceMessage,
6355 GNUNET_MQ_hd_fixed_size (suggest_cancel,
6356 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
6357 struct ExpressPreferenceMessage,
6359 GNUNET_MQ_hd_var_size (request_hello_validation,
6360 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
6361 struct RequestHelloValidationMessage,
6363 /* communication with core */
6364 GNUNET_MQ_hd_fixed_size (client_start,
6365 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
6366 struct StartMessage,
6368 GNUNET_MQ_hd_var_size (client_send,
6369 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
6370 struct OutboundMessage,
6372 /* communication with communicators */
6373 GNUNET_MQ_hd_var_size (communicator_available,
6374 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
6375 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
6377 GNUNET_MQ_hd_var_size (communicator_backchannel,
6378 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
6379 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
6381 GNUNET_MQ_hd_var_size (add_address,
6382 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
6383 struct GNUNET_TRANSPORT_AddAddressMessage,
6385 GNUNET_MQ_hd_fixed_size (del_address,
6386 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
6387 struct GNUNET_TRANSPORT_DelAddressMessage,
6389 GNUNET_MQ_hd_var_size (incoming_msg,
6390 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
6391 struct GNUNET_TRANSPORT_IncomingMessage,
6393 GNUNET_MQ_hd_fixed_size (queue_create_ok,
6394 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
6395 struct GNUNET_TRANSPORT_CreateQueueResponse,
6397 GNUNET_MQ_hd_fixed_size (queue_create_fail,
6398 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
6399 struct GNUNET_TRANSPORT_CreateQueueResponse,
6401 GNUNET_MQ_hd_var_size (add_queue_message,
6402 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
6403 struct GNUNET_TRANSPORT_AddQueueMessage,
6405 GNUNET_MQ_hd_var_size (address_consider_verify,
6406 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
6407 struct GNUNET_TRANSPORT_AddressToVerify,
6409 GNUNET_MQ_hd_fixed_size (del_queue_message,
6410 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
6411 struct GNUNET_TRANSPORT_DelQueueMessage,
6413 GNUNET_MQ_hd_fixed_size (send_message_ack,
6414 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
6415 struct GNUNET_TRANSPORT_SendMessageToAck,
6417 /* communication with monitors */
6418 GNUNET_MQ_hd_fixed_size (monitor_start,
6419 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
6420 struct GNUNET_TRANSPORT_MonitorStart,
6422 GNUNET_MQ_handler_end ());
6425 /* end of file gnunet-service-transport.c */