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 * - manage defragmentation, retransmission, track RTT, loss, etc.
39 * - use ATS bandwidth allocation callback and schedule transmissions!
42 * - inform ATS about RTT, goodput/loss, overheads, etc. (GNUNET_ATS_session_update())
45 * - change transport-core API to provide proper flow control in both
46 * directions, allow multiple messages per peer simultaneously (tag
47 * confirmations with unique message ID), and replace quota-out with
48 * proper flow control;
50 * Design realizations / discussion:
51 * - communicators do flow control by calling MQ "notify sent"
52 * when 'ready'. They determine flow implicitly (i.e. TCP blocking)
53 * or explicitly via background channel FC ACKs. As long as the
54 * channel is not full, they may 'notify sent' even if the other
55 * peer has not yet confirmed receipt. The other peer confirming
56 * is _only_ for FC, not for more reliable transmission; reliable
57 * transmission (i.e. of fragments) is left to _transport_.
58 * - ACKs sent back in uni-directional communicators are done via
59 * the background channel API; here transport _may_ initially
60 * broadcast (with bounded # hops) if no path is known;
61 * - transport should _integrate_ DV-routing and build a view of
62 * the network; then background channel traffic can be
63 * routed via DV as well as explicit "DV" traffic.
64 * - background channel is also used for ACKs and NAT traversal support
65 * - transport service is responsible for AEAD'ing the background
66 * channel, timestamps and monotonic time are used against replay
67 * of old messages -> peerstore needs to be supplied with
68 * "latest timestamps seen" data
69 * - if transport implements DV, we likely need a 3rd peermap
70 * in addition to ephemerals and (direct) neighbours
71 * => in this data structure, we should track ATS metrics (distance, RTT, etc.)
72 * as well as latest timestamps seen, goodput, fragments for transmission, etc.
73 * ==> check if stuff needs to be moved out of "Neighbour"
74 * - transport should encapsualte core-level messages and do its
75 * own ACKing for RTT/goodput/loss measurements _and_ fragment
79 #include "gnunet_util_lib.h"
80 #include "gnunet_statistics_service.h"
81 #include "gnunet_transport_monitor_service.h"
82 #include "gnunet_peerstore_service.h"
83 #include "gnunet_hello_lib.h"
84 #include "gnunet_ats_transport_service.h"
85 #include "transport.h"
89 * What is the size we assume for a read operation in the
90 * absence of an MTU for the purpose of flow control?
92 #define IN_PACKET_SIZE_WITHOUT_MTU 128
95 * If a queue delays the next message by more than this number
96 * of seconds we log a warning. Note: this is for testing,
97 * the value chosen here might be too aggressively low!
99 #define DELAY_WARN_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
102 * How many messages can we have pending for a given communicator
103 * process before we start to throttle that communicator?
105 * Used if a communicator might be CPU-bound and cannot handle the traffic.
107 #define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
110 * How many messages can we have pending for a given session (queue to
111 * a particular peer via a communicator) process before we start to
112 * throttle that queue?
114 * Used if ATS assigns more bandwidth to a particular transmission
115 * method than that transmission method can right now handle. (Yes,
116 * ATS should eventually notice utilization below allocation and
117 * adjust, but we don't want to queue up tons of messages in the
118 * meantime). Must be significantly below
119 * #COMMUNICATOR_TOTAL_QUEUE_LIMIT.
121 #define SESSION_QUEUE_LIMIT 32
124 GNUNET_NETWORK_STRUCT_BEGIN
127 * Outer layer of an encapsulated backchannel message.
129 struct TransportBackchannelEncapsulationMessage
132 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
134 struct GNUNET_MessageHeader header;
137 * Distance the backchannel message has traveled, to be updated at
138 * each hop. Used to bound the number of hops in case a backchannel
139 * message is broadcast and thus travels without routing
140 * information (during initial backchannel discovery).
145 * Target's peer identity (as backchannels may be transmitted
146 * indirectly, or even be broadcast).
148 struct GNUNET_PeerIdentity target;
151 * Ephemeral key setup by the sender for @e target, used
152 * to encrypt the payload.
154 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
157 * HMAC over the ciphertext of the encrypted, variable-size
158 * body that follows. Verified via DH of @e target and
161 struct GNUNET_HashCode hmac;
163 /* Followed by encrypted, variable-size payload */
168 * Body by which a peqer confirms that it is using an ephemeral
171 struct EphemeralConfirmation
175 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
177 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
180 * How long is this signature over the ephemeral key
183 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
186 * Ephemeral key setup by the sender for @e target, used
187 * to encrypt the payload.
189 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
195 * Message by which a peqer confirms that it is using an ephemeral
198 struct EphemeralConfirmationMessage
202 * Message header, type is #GNUNET_MESSAGE_TYPE_TRANSPORT_EPHEMERAL_CONFIRMATION
204 struct GNUNET_MessageHeader header;
212 * How long is this signature over the ephemeral key
215 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
218 * Ephemeral key setup by the sender for @e target, used
219 * to encrypt the payload.
221 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
226 * Plaintext of the variable-size payload that is encrypted
227 * within a `struct TransportBackchannelEncapsulationMessage`
229 struct TransportBackchannelRequestPayload
233 * Sender's peer identity.
235 struct GNUNET_PeerIdentity sender;
238 * Signature of the sender over an
239 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
241 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
244 * How long is this signature over the ephemeral key
247 struct GNUNET_TIME_AbsoluteNBO ephemeral_validity;
250 * Current monotonic time of the sending transport service. Used to
251 * detect replayed messages. Note that the receiver should remember
252 * a list of the recently seen timestamps and only reject messages
253 * if the timestamp is in the list, or the list is "full" and the
254 * timestamp is smaller than the lowest in the list. This list of
255 * timestamps per peer should be persisted to guard against replays
258 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
260 /* Followed by a `struct GNUNET_MessageHeader` with a message
261 for a communicator */
263 /* Followed by a 0-termianted string specifying the name of
264 the communicator which is to receive the message */
270 * Outer layer of an encapsulated unfragmented application message sent
271 * over an unreliable channel.
273 struct TransportReliabilityBox
276 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
278 struct GNUNET_MessageHeader header;
281 * Number of messages still to be sent before a commulative
282 * ACK is requested. Zero if an ACK is requested immediately.
283 * In NBO. Note that the receiver may send the ACK faster
284 * if it believes that is reasonable.
286 uint32_t ack_countdown GNUNET_PACKED;
289 * Unique ID of the message used for signalling receipt of
290 * messages sent over possibly unreliable channels. Should
293 struct GNUNET_ShortHashCode msg_uuid;
298 * Confirmation that the receiver got a
299 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
300 * confirmation may be transmitted over a completely different queue,
301 * so ACKs are identified by a combination of PID of sender and
302 * message UUID, without the queue playing any role!
304 struct TransportReliabilityAckMessage
307 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
309 struct GNUNET_MessageHeader header;
314 uint32_t reserved GNUNET_PACKED;
317 * How long was the ACK delayed relative to the average time of
318 * receipt of the messages being acknowledged? Used to calculate
319 * the average RTT by taking the receipt time of the ack minus the
320 * average transmission time of the sender minus this value.
322 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
324 /* followed by any number of `struct GNUNET_ShortHashCode`
325 messages providing ACKs */
330 * Outer layer of an encapsulated fragmented application message.
332 struct TransportFragmentBox
335 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
337 struct GNUNET_MessageHeader header;
340 * Unique ID of this fragment (and fragment transmission!). Will
341 * change even if a fragement is retransmitted to make each
342 * transmission attempt unique! Should be incremented by one for
343 * each fragment transmission. If a client receives a duplicate
344 * fragment (same @e frag_off), it must send
345 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK immediately.
347 uint32_t frag_uuid GNUNET_PACKED;
350 * Original message ID for of the message that all the1
351 * fragments belong to. Must be the same for all fragments.
353 struct GNUNET_ShortHashCode msg_uuid;
356 * Offset of this fragment in the overall message.
358 uint16_t frag_off GNUNET_PACKED;
361 * Total size of the message that is being fragmented.
363 uint16_t msg_size GNUNET_PACKED;
369 * Outer layer of an fragmented application message sent over a queue
370 * with finite MTU. When a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT is
371 * received, the receiver has two RTTs or 64 further fragments with
372 * the same basic message time to send an acknowledgement, possibly
373 * acknowledging up to 65 fragments in one ACK. ACKs must also be
374 * sent immediately once all fragments were sent.
376 struct TransportFragmentAckMessage
379 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK
381 struct GNUNET_MessageHeader header;
384 * Unique ID of the lowest fragment UUID being acknowledged.
386 uint32_t frag_uuid GNUNET_PACKED;
389 * Bitfield of up to 64 additional fragments following the
390 * @e msg_uuid being acknowledged by this message.
392 uint64_t extra_acks GNUNET_PACKED;
395 * Original message ID for of the message that all the
396 * fragments belong to.
398 struct GNUNET_ShortHashCode msg_uuid;
401 * How long was the ACK delayed relative to the average time of
402 * receipt of the fragments being acknowledged? Used to calculate
403 * the average RTT by taking the receipt time of the ack minus the
404 * average transmission time of the sender minus this value.
406 struct GNUNET_TIME_RelativeNBO avg_ack_delay;
411 * Internal message used by transport for distance vector learning.
412 * If @e num_hops does not exceed the threshold, peers should append
413 * themselves to the peer list and flood the message (possibly only
414 * to a subset of their neighbours to limit discoverability of the
415 * network topology). To the extend that the @e bidirectional bits
416 * are set, peers may learn the inverse paths even if they did not
419 * Unless received on a bidirectional queue and @e num_hops just
420 * zero, peers that can forward to the initator should always try to
421 * forward to the initiator.
423 struct TransportDVLearn
426 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
428 struct GNUNET_MessageHeader header;
431 * Number of hops this messages has travelled, in NBO. Zero if
434 uint16_t num_hops GNUNET_PACKED;
437 * Bitmask of the last 16 hops indicating whether they are confirmed
438 * available (without DV) in both directions or not, in NBO. Used
439 * to possibly instantly learn a path in both directions. Each peer
440 * should shift this value by one to the left, and then set the
441 * lowest bit IF the current sender can be reached from it (without
444 uint16_t bidirectional GNUNET_PACKED;
447 * Peers receiving this message and delaying forwarding to other
448 * peers for any reason should increment this value such as to
449 * enable the origin to determine the actual network-only delay
450 * in addition to the real-time delay (assuming the message loops
451 * back to the origin).
453 struct GNUNET_TIME_Relative cummulative_non_network_delay;
456 * Identity of the peer that started this learning activity.
458 struct GNUNET_PeerIdentity initiator;
460 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values,
461 excluding the initiator of the DV trace; the last entry is the
462 current sender; the current peer must not be included. */
468 * Outer layer of an encapsulated message send over multiple hops.
469 * The path given only includes the identities of the subsequent
470 * peers, i.e. it will be empty if we are the receiver. Each
471 * forwarding peer should scan the list from the end, and if it can,
472 * forward to the respective peer. The list should then be shortened
473 * by all the entries up to and including that peer. Each hop should
474 * also increment @e total_hops to allow the receiver to get a precise
475 * estimate on the number of hops the message travelled. Senders must
476 * provide a learned path that thus should work, but intermediaries
477 * know of a shortcut, they are allowed to send the message via that
480 * If a peer finds itself still on the list, it must drop the message.
482 struct TransportDVBox
485 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
487 struct GNUNET_MessageHeader header;
490 * Number of total hops this messages travelled. In NBO.
491 * @e origin sets this to zero, to be incremented at
494 uint16_t total_hops GNUNET_PACKED;
497 * Number of hops this messages includes. In NBO.
499 uint16_t num_hops GNUNET_PACKED;
502 * Identity of the peer that originated the message.
504 struct GNUNET_PeerIdentity origin;
506 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
507 excluding the @e origin and the current peer, the last must be
508 the ultimate target; if @e num_hops is zero, the receiver of this
509 message is the ultimate target. */
511 /* Followed by the actual message, which itself may be
512 another box, but not a DV_LEARN or DV_BOX message! */
516 GNUNET_NETWORK_STRUCT_END
521 * What type of client is the `struct TransportClient` about?
526 * We do not know yet (client is fresh).
531 * Is the CORE service, we need to forward traffic to it.
536 * It is a monitor, forward monitor data.
541 * It is a communicator, use for communication.
548 * Entry in our cache of ephemeral keys we currently use.
550 struct EphemeralCacheEntry
554 * Target's peer identity (we don't re-use ephemerals
555 * to limit linkability of messages).
557 struct GNUNET_PeerIdentity target;
560 * Signature affirming @e ephemeral_key of type
561 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
563 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
566 * How long is @e sender_sig valid
568 struct GNUNET_TIME_Absolute ephemeral_validity;
573 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
576 * Node in the ephemeral cache for this entry.
577 * Used for expiration.
579 struct GNUNET_CONTAINER_HeapNode *hn;
584 * Client connected to the transport service.
586 struct TransportClient;
590 * A neighbour that at least one communicator is connected to.
596 * Entry identifying transmission in one of our `struct
597 * GNUNET_ATS_Sessions` which still awaits an ACK. This is used to
598 * ensure we do not overwhelm a communicator and limit the number of
599 * messages outstanding per communicator (say in case communicator is
600 * CPU bound) and per queue (in case ATS bandwidth allocation exceeds
601 * what the communicator can actually provide towards a particular
610 struct QueueEntry *next;
615 struct QueueEntry *prev;
618 * ATS session this entry is queued with.
620 struct GNUNET_ATS_Session *session;
623 * Message ID used for this message with the queue used for transmission.
630 * An ATS session is a message queue provided by a communicator
631 * via which we can reach a particular neighbour.
633 struct GNUNET_ATS_Session
638 struct GNUNET_ATS_Session *next_neighbour;
643 struct GNUNET_ATS_Session *prev_neighbour;
648 struct GNUNET_ATS_Session *prev_client;
653 struct GNUNET_ATS_Session *next_client;
656 * Head of DLL of unacked transmission requests.
658 struct QueueEntry *queue_head;
661 * End of DLL of unacked transmission requests.
663 struct QueueEntry *queue_tail;
666 * Which neighbour is this ATS session for?
668 struct Neighbour *neighbour;
671 * Which communicator offers this ATS session?
673 struct TransportClient *tc;
676 * Address served by the ATS session.
681 * Handle by which we inform ATS about this queue.
683 struct GNUNET_ATS_SessionRecord *sr;
686 * Task scheduled for the time when this queue can (likely) transmit the
687 * next message. Still needs to check with the @e tracker_out to be sure.
689 struct GNUNET_SCHEDULER_Task *transmit_task;
692 * Our current RTT estimate for this ATS session.
694 struct GNUNET_TIME_Relative rtt;
697 * Message ID generator for transmissions on this queue.
702 * Unique identifier of this ATS session with the communicator.
707 * Maximum transmission unit supported by this ATS session.
712 * Distance to the target of this ATS session.
719 uint32_t num_msg_pending;
724 uint32_t num_bytes_pending;
727 * Length of the DLL starting at @e queue_head.
729 unsigned int queue_length;
732 * Network type offered by this ATS session.
734 enum GNUNET_NetworkType nt;
737 * Connection status for this ATS session.
739 enum GNUNET_TRANSPORT_ConnectionStatus cs;
742 * How much outbound bandwidth do we have available for this session?
744 struct GNUNET_BANDWIDTH_Tracker tracker_out;
747 * How much inbound bandwidth do we have available for this session?
749 struct GNUNET_BANDWIDTH_Tracker tracker_in;
754 * A neighbour that at least one communicator is connected to.
760 * Which peer is this about?
762 struct GNUNET_PeerIdentity pid;
765 * Head of list of messages pending for this neighbour.
767 struct PendingMessage *pending_msg_head;
770 * Tail of list of messages pending for this neighbour.
772 struct PendingMessage *pending_msg_tail;
775 * Head of DLL of ATS sessions to this peer.
777 struct GNUNET_ATS_Session *session_head;
780 * Tail of DLL of ATS sessions to this peer.
782 struct GNUNET_ATS_Session *session_tail;
785 * Task run to cleanup pending messages that have exceeded their timeout.
787 struct GNUNET_SCHEDULER_Task *timeout_task;
790 * Quota at which CORE is allowed to transmit to this peer
793 * FIXME: not yet used, tricky to get right given multiple queues!
794 * (=> Idea: let ATS set a quota per queue and we add them up here?)
795 * FIXME: how do we set this value initially when we tell CORE?
796 * Options: start at a minimum value or at literally zero (before ATS?)
797 * (=> Current thought: clean would be zero!)
799 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
802 * What is the earliest timeout of any message in @e pending_msg_tail?
804 struct GNUNET_TIME_Absolute earliest_timeout;
810 * Types of different pending messages.
812 enum PendingMessageType
816 * Ordinary message received from the CORE service.
823 PMT_FRAGMENT_BOX = 1,
828 PMT_RELIABILITY_BOX = 2,
831 * Any type of acknowledgement.
833 PMT_ACKNOWLEDGEMENT = 3
840 * Transmission request that is awaiting delivery. The original
841 * transmission requests from CORE may be too big for some queues.
842 * In this case, a *tree* of fragments is created. At each
843 * level of the tree, fragments are kept in a DLL ordered by which
844 * fragment should be sent next (at the head). The tree is searched
845 * top-down, with the original message at the root.
847 * To select a node for transmission, first it is checked if the
848 * current node's message fits with the MTU. If it does not, we
849 * either calculate the next fragment (based on @e frag_off) from the
850 * current node, or, if all fragments have already been created,
851 * descend to the @e head_frag. Even though the node was already
852 * fragmented, the fragment may be too big if the fragment was
853 * generated for a queue with a larger MTU. In this case, the node
854 * may be fragmented again, thus creating a tree.
856 * When acknowledgements for fragments are received, the tree
857 * must be pruned, removing those parts that were already
858 * acknowledged. When fragments are sent over a reliable
859 * channel, they can be immediately removed.
861 * If a message is ever fragmented, then the original "full" message
862 * is never again transmitted (even if it fits below the MTU), and
863 * only (remaining) fragments are sent.
865 struct PendingMessage
868 * Kept in a MDLL of messages for this @a target.
870 struct PendingMessage *next_neighbour;
873 * Kept in a MDLL of messages for this @a target.
875 struct PendingMessage *prev_neighbour;
878 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
880 struct PendingMessage *next_client;
883 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
885 struct PendingMessage *prev_client;
888 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOx)
890 struct PendingMessage *next_frag;
893 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOX)
895 struct PendingMessage *prev_frag;
898 * This message, reliability boxed. Only possibly available if @e pmt is #PMT_CORE.
900 struct PendingMessage *bpm;
903 * Target of the request.
905 struct Neighbour *target;
908 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
910 struct TransportClient *client;
913 * Head of a MDLL of fragments created for this core message.
915 struct PendingMessage *head_frag;
918 * Tail of a MDLL of fragments created for this core message.
920 struct PendingMessage *tail_frag;
923 * Our parent in the fragmentation tree.
925 struct PendingMessage *frag_parent;
928 * At what time should we give up on the transmission (and no longer retry)?
930 struct GNUNET_TIME_Absolute timeout;
933 * What is the earliest time for us to retry transmission of this message?
935 struct GNUNET_TIME_Absolute next_attempt;
938 * UUID to use for this message (used for reassembly of fragments, only
939 * initialized if @e msg_uuid_set is #GNUNET_YES).
941 struct GNUNET_ShortHashCode msg_uuid;
944 * Counter incremented per generated fragment.
946 uint32_t frag_uuidgen;
949 * Type of the pending message.
951 enum PendingMessageType pmt;
954 * Size of the original message.
959 * Offset at which we should generate the next fragment.
964 * #GNUNET_YES once @e msg_uuid was initialized
966 int16_t msg_uuid_set;
968 /* Followed by @e bytes_msg to transmit */
973 * One of the addresses of this peer.
975 struct AddressListEntry
981 struct AddressListEntry *next;
986 struct AddressListEntry *prev;
989 * Which communicator provides this address?
991 struct TransportClient *tc;
994 * The actual address.
999 * Current context for storing this address in the peerstore.
1001 struct GNUNET_PEERSTORE_StoreContext *sc;
1004 * Task to periodically do @e st operation.
1006 struct GNUNET_SCHEDULER_Task *st;
1009 * What is a typical lifetime the communicator expects this
1010 * address to have? (Always from now.)
1012 struct GNUNET_TIME_Relative expiration;
1015 * Address identifier used by the communicator.
1020 * Network type offered by this address.
1022 enum GNUNET_NetworkType nt;
1028 * Client connected to the transport service.
1030 struct TransportClient
1036 struct TransportClient *next;
1041 struct TransportClient *prev;
1044 * Handle to the client.
1046 struct GNUNET_SERVICE_Client *client;
1049 * Message queue to the client.
1051 struct GNUNET_MQ_Handle *mq;
1054 * What type of client is this?
1056 enum ClientType type;
1062 * Information for @e type #CT_CORE.
1067 * Head of list of messages pending for this client, sorted by
1068 * transmission time ("next_attempt" + possibly internal prioritization).
1070 struct PendingMessage *pending_msg_head;
1073 * Tail of list of messages pending for this client.
1075 struct PendingMessage *pending_msg_tail;
1080 * Information for @e type #CT_MONITOR.
1085 * Peer identity to monitor the addresses of.
1086 * Zero to monitor all neighbours. Valid if
1087 * @e type is #CT_MONITOR.
1089 struct GNUNET_PeerIdentity peer;
1092 * Is this a one-shot monitor?
1100 * Information for @e type #CT_COMMUNICATOR.
1104 * If @e type is #CT_COMMUNICATOR, this communicator
1105 * supports communicating using these addresses.
1107 char *address_prefix;
1110 * Head of DLL of queues offered by this communicator.
1112 struct GNUNET_ATS_Session *session_head;
1115 * Tail of DLL of queues offered by this communicator.
1117 struct GNUNET_ATS_Session *session_tail;
1120 * Head of list of the addresses of this peer offered by this communicator.
1122 struct AddressListEntry *addr_head;
1125 * Tail of list of the addresses of this peer offered by this communicator.
1127 struct AddressListEntry *addr_tail;
1130 * Number of queue entries in all queues to this communicator. Used
1131 * throttle sending to a communicator if we see that the communicator
1132 * is globally unable to keep up.
1134 unsigned int total_queue_length;
1137 * Characteristics of this communicator.
1139 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
1149 * Head of linked list of all clients to this service.
1151 static struct TransportClient *clients_head;
1154 * Tail of linked list of all clients to this service.
1156 static struct TransportClient *clients_tail;
1159 * Statistics handle.
1161 static struct GNUNET_STATISTICS_Handle *GST_stats;
1164 * Configuration handle.
1166 static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
1171 static struct GNUNET_PeerIdentity GST_my_identity;
1176 static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
1179 * Map from PIDs to `struct Neighbour` entries. A peer is
1180 * a neighbour if we have an MQ to it from some communicator.
1182 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
1185 * Database for peer's HELLOs.
1187 static struct GNUNET_PEERSTORE_Handle *peerstore;
1190 * Heap sorting `struct EphemeralCacheEntry` by their
1191 * key/signature validity.
1193 static struct GNUNET_CONTAINER_Heap *ephemeral_heap;
1196 * Hash map for looking up `struct EphemeralCacheEntry`s
1197 * by peer identity. (We may have ephemerals in our
1198 * cache for which we do not have a neighbour entry,
1199 * and similar many neighbours may not need ephemerals,
1200 * so we use a second map.)
1202 static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map;
1205 * Our connection to ATS for allocation and bootstrapping.
1207 static struct GNUNET_ATS_TransportHandle *ats;
1211 * Free cached ephemeral key.
1213 * @param ece cached signature to free
1216 free_ephemeral (struct EphemeralCacheEntry *ece)
1218 GNUNET_CONTAINER_multipeermap_remove (ephemeral_map,
1221 GNUNET_CONTAINER_heap_remove_node (ece->hn);
1227 * Lookup neighbour record for peer @a pid.
1229 * @param pid neighbour to look for
1230 * @return NULL if we do not have this peer as a neighbour
1232 static struct Neighbour *
1233 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
1235 return GNUNET_CONTAINER_multipeermap_get (neighbours,
1241 * Details about what to notify monitors about.
1246 * @deprecated To be discussed if we keep these...
1248 struct GNUNET_TIME_Absolute last_validation;
1249 struct GNUNET_TIME_Absolute valid_until;
1250 struct GNUNET_TIME_Absolute next_validation;
1253 * Current round-trip time estimate.
1255 struct GNUNET_TIME_Relative rtt;
1258 * Connection status.
1260 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1265 uint32_t num_msg_pending;
1270 uint32_t num_bytes_pending;
1277 * Notify monitor @a tc about an event. That @a tc
1278 * cares about the event has already been checked.
1280 * Send @a tc information in @a me about a @a peer's status with
1281 * respect to some @a address to all monitors that care.
1283 * @param tc monitor to inform
1284 * @param peer peer the information is about
1285 * @param address address the information is about
1286 * @param nt network type associated with @a address
1287 * @param me detailed information to transmit
1290 notify_monitor (struct TransportClient *tc,
1291 const struct GNUNET_PeerIdentity *peer,
1292 const char *address,
1293 enum GNUNET_NetworkType nt,
1294 const struct MonitorEvent *me)
1296 struct GNUNET_MQ_Envelope *env;
1297 struct GNUNET_TRANSPORT_MonitorData *md;
1298 size_t addr_len = strlen (address) + 1;
1300 env = GNUNET_MQ_msg_extra (md,
1302 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
1303 md->nt = htonl ((uint32_t) nt);
1305 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
1306 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
1307 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
1308 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
1309 md->cs = htonl ((uint32_t) me->cs);
1310 md->num_msg_pending = htonl (me->num_msg_pending);
1311 md->num_bytes_pending = htonl (me->num_bytes_pending);
1315 GNUNET_MQ_send (tc->mq,
1321 * Send information in @a me about a @a peer's status with respect
1322 * to some @a address to all monitors that care.
1324 * @param peer peer the information is about
1325 * @param address address the information is about
1326 * @param nt network type associated with @a address
1327 * @param me detailed information to transmit
1330 notify_monitors (const struct GNUNET_PeerIdentity *peer,
1331 const char *address,
1332 enum GNUNET_NetworkType nt,
1333 const struct MonitorEvent *me)
1335 static struct GNUNET_PeerIdentity zero;
1337 for (struct TransportClient *tc = clients_head;
1341 if (CT_MONITOR != tc->type)
1343 if (tc->details.monitor.one_shot)
1345 if ( (0 != memcmp (&tc->details.monitor.peer,
1348 (0 != memcmp (&tc->details.monitor.peer,
1362 * Called whenever a client connects. Allocates our
1363 * data structures associated with that client.
1365 * @param cls closure, NULL
1366 * @param client identification of the client
1367 * @param mq message queue for the client
1368 * @return our `struct TransportClient`
1371 client_connect_cb (void *cls,
1372 struct GNUNET_SERVICE_Client *client,
1373 struct GNUNET_MQ_Handle *mq)
1375 struct TransportClient *tc;
1377 tc = GNUNET_new (struct TransportClient);
1378 tc->client = client;
1380 GNUNET_CONTAINER_DLL_insert (clients_head,
1383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1384 "Client %p connected\n",
1391 * Release memory used by @a neighbour.
1393 * @param neighbour neighbour entry to free
1396 free_neighbour (struct Neighbour *neighbour)
1398 GNUNET_assert (NULL == neighbour->session_head);
1399 GNUNET_assert (GNUNET_YES ==
1400 GNUNET_CONTAINER_multipeermap_remove (neighbours,
1403 if (NULL != neighbour->timeout_task)
1404 GNUNET_SCHEDULER_cancel (neighbour->timeout_task);
1405 GNUNET_free (neighbour);
1410 * Send message to CORE clients that we lost a connection.
1412 * @param tc client to inform (must be CORE client)
1413 * @param pid peer the connection is for
1414 * @param quota_out current quota for the peer
1417 core_send_connect_info (struct TransportClient *tc,
1418 const struct GNUNET_PeerIdentity *pid,
1419 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
1421 struct GNUNET_MQ_Envelope *env;
1422 struct ConnectInfoMessage *cim;
1424 GNUNET_assert (CT_CORE == tc->type);
1425 env = GNUNET_MQ_msg (cim,
1426 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1427 cim->quota_out = quota_out;
1429 GNUNET_MQ_send (tc->mq,
1435 * Send message to CORE clients that we gained a connection
1437 * @param pid peer the queue was for
1438 * @param quota_out current quota for the peer
1441 cores_send_connect_info (const struct GNUNET_PeerIdentity *pid,
1442 struct GNUNET_BANDWIDTH_Value32NBO quota_out)
1444 for (struct TransportClient *tc = clients_head;
1448 if (CT_CORE != tc->type)
1450 core_send_connect_info (tc,
1458 * Send message to CORE clients that we lost a connection.
1460 * @param pid peer the connection was for
1463 cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
1465 for (struct TransportClient *tc = clients_head;
1469 struct GNUNET_MQ_Envelope *env;
1470 struct DisconnectInfoMessage *dim;
1472 if (CT_CORE != tc->type)
1474 env = GNUNET_MQ_msg (dim,
1475 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1477 GNUNET_MQ_send (tc->mq,
1484 * We believe we are ready to transmit a message on a queue. Double-checks
1485 * with the queue's "tracker_out" and then gives the message to the
1486 * communicator for transmission (updating the tracker, and re-scheduling
1487 * itself if applicable).
1489 * @param cls the `struct GNUNET_ATS_Session` to process transmissions for
1492 transmit_on_queue (void *cls);
1496 * Schedule next run of #transmit_on_queue(). Does NOTHING if
1497 * we should run immediately or if the message queue is empty.
1498 * Test for no task being added AND queue not being empty to
1499 * transmit immediately afterwards! This function must only
1500 * be called if the message queue is non-empty!
1502 * @param queue the queue to do scheduling for
1505 schedule_transmit_on_queue (struct GNUNET_ATS_Session *queue)
1507 struct Neighbour *n = queue->neighbour;
1508 struct PendingMessage *pm = n->pending_msg_head;
1509 struct GNUNET_TIME_Relative out_delay;
1512 GNUNET_assert (NULL != pm);
1513 if (queue->tc->details.communicator.total_queue_length >= COMMUNICATOR_TOTAL_QUEUE_LIMIT)
1515 GNUNET_STATISTICS_update (GST_stats,
1516 "# Transmission throttled due to communicator queue limit",
1521 if (queue->queue_length >= SESSION_QUEUE_LIMIT)
1523 GNUNET_STATISTICS_update (GST_stats,
1524 "# Transmission throttled due to session queue limit",
1530 wsize = (0 == queue->mtu)
1531 ? pm->bytes_msg /* FIXME: add overheads? */
1533 out_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_out,
1535 out_delay = GNUNET_TIME_relative_max (GNUNET_TIME_absolute_get_remaining (pm->next_attempt),
1537 if (0 == out_delay.rel_value_us)
1538 return; /* we should run immediately! */
1539 /* queue has changed since we were scheduled, reschedule again */
1540 queue->transmit_task = GNUNET_SCHEDULER_add_delayed (out_delay,
1543 if (out_delay.rel_value_us > DELAY_WARN_THRESHOLD.rel_value_us)
1544 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1545 "Next transmission on queue `%s' in %s (high delay)\n",
1547 GNUNET_STRINGS_relative_time_to_string (out_delay,
1550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1551 "Next transmission on queue `%s' in %s\n",
1553 GNUNET_STRINGS_relative_time_to_string (out_delay,
1561 * @param session the session to free
1564 free_session (struct GNUNET_ATS_Session *session)
1566 struct Neighbour *neighbour = session->neighbour;
1567 struct TransportClient *tc = session->tc;
1568 struct MonitorEvent me = {
1569 .cs = GNUNET_TRANSPORT_CS_DOWN,
1570 .rtt = GNUNET_TIME_UNIT_FOREVER_REL
1572 struct QueueEntry *qe;
1575 if (NULL != session->transmit_task)
1577 GNUNET_SCHEDULER_cancel (session->transmit_task);
1578 session->transmit_task = NULL;
1580 GNUNET_CONTAINER_MDLL_remove (neighbour,
1581 neighbour->session_head,
1582 neighbour->session_tail,
1584 GNUNET_CONTAINER_MDLL_remove (client,
1585 tc->details.communicator.session_head,
1586 tc->details.communicator.session_tail,
1588 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >= tc->details.communicator.total_queue_length);
1589 while (NULL != (qe = session->queue_head))
1591 GNUNET_CONTAINER_DLL_remove (session->queue_head,
1592 session->queue_tail,
1594 session->queue_length--;
1595 tc->details.communicator.total_queue_length--;
1598 GNUNET_assert (0 == session->queue_length);
1600 (COMMUNICATOR_TOTAL_QUEUE_LIMIT < tc->details.communicator.total_queue_length) )
1602 /* Communicator dropped below threshold, resume all queues */
1603 GNUNET_STATISTICS_update (GST_stats,
1604 "# Transmission throttled due to communicator queue limit",
1607 for (struct GNUNET_ATS_Session *s = tc->details.communicator.session_head;
1610 schedule_transmit_on_queue (s);
1612 notify_monitors (&neighbour->pid,
1616 GNUNET_ATS_session_del (session->sr);
1617 GNUNET_BANDWIDTH_tracker_notification_stop (&session->tracker_in);
1618 GNUNET_BANDWIDTH_tracker_notification_stop (&session->tracker_out);
1619 GNUNET_free (session);
1620 if (NULL == neighbour->session_head)
1622 cores_send_disconnect_info (&neighbour->pid);
1623 free_neighbour (neighbour);
1631 * @param ale address list entry to free
1634 free_address_list_entry (struct AddressListEntry *ale)
1636 struct TransportClient *tc = ale->tc;
1638 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
1639 tc->details.communicator.addr_tail,
1641 if (NULL != ale->sc)
1643 GNUNET_PEERSTORE_store_cancel (ale->sc);
1646 if (NULL != ale->st)
1648 GNUNET_SCHEDULER_cancel (ale->st);
1656 * Called whenever a client is disconnected. Frees our
1657 * resources associated with that client.
1659 * @param cls closure, NULL
1660 * @param client identification of the client
1661 * @param app_ctx our `struct TransportClient`
1664 client_disconnect_cb (void *cls,
1665 struct GNUNET_SERVICE_Client *client,
1668 struct TransportClient *tc = app_ctx;
1670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671 "Client %p disconnected, cleaning up.\n",
1673 GNUNET_CONTAINER_DLL_remove (clients_head,
1682 struct PendingMessage *pm;
1684 while (NULL != (pm = tc->details.core.pending_msg_head))
1686 GNUNET_CONTAINER_MDLL_remove (client,
1687 tc->details.core.pending_msg_head,
1688 tc->details.core.pending_msg_tail,
1696 case CT_COMMUNICATOR:
1698 struct GNUNET_ATS_Session *q;
1699 struct AddressListEntry *ale;
1701 while (NULL != (q = tc->details.communicator.session_head))
1703 while (NULL != (ale = tc->details.communicator.addr_head))
1704 free_address_list_entry (ale);
1705 GNUNET_free (tc->details.communicator.address_prefix);
1714 * Iterator telling new CORE client about all existing
1715 * connections to peers.
1717 * @param cls the new `struct TransportClient`
1718 * @param pid a connected peer
1719 * @param value the `struct Neighbour` with more information
1720 * @return #GNUNET_OK (continue to iterate)
1723 notify_client_connect_info (void *cls,
1724 const struct GNUNET_PeerIdentity *pid,
1727 struct TransportClient *tc = cls;
1728 struct Neighbour *neighbour = value;
1730 core_send_connect_info (tc,
1732 neighbour->quota_out);
1738 * Initialize a "CORE" client. We got a start message from this
1739 * client, so add it to the list of clients for broadcasting of
1742 * @param cls the client
1743 * @param start the start message that was sent
1746 handle_client_start (void *cls,
1747 const struct StartMessage *start)
1749 struct TransportClient *tc = cls;
1752 options = ntohl (start->options);
1753 if ( (0 != (1 & options)) &&
1755 memcmp (&start->self,
1757 sizeof (struct GNUNET_PeerIdentity)) ) )
1759 /* client thinks this is a different peer, reject */
1761 GNUNET_SERVICE_client_drop (tc->client);
1764 if (CT_NONE != tc->type)
1767 GNUNET_SERVICE_client_drop (tc->client);
1771 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
1772 ¬ify_client_connect_info,
1774 GNUNET_SERVICE_client_continue (tc->client);
1779 * Client asked for transmission to a peer. Process the request.
1781 * @param cls the client
1782 * @param obm the send message that was sent
1785 check_client_send (void *cls,
1786 const struct OutboundMessage *obm)
1788 struct TransportClient *tc = cls;
1790 const struct GNUNET_MessageHeader *obmm;
1792 if (CT_CORE != tc->type)
1795 return GNUNET_SYSERR;
1797 size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
1798 if (size < sizeof (struct GNUNET_MessageHeader))
1801 return GNUNET_SYSERR;
1803 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
1804 if (size != ntohs (obmm->size))
1807 return GNUNET_SYSERR;
1814 * Free fragment tree below @e root, excluding @e root itself.
1816 * @param root root of the tree to free
1819 free_fragment_tree (struct PendingMessage *root)
1821 struct PendingMessage *frag;
1823 while (NULL != (frag = root->head_frag))
1825 free_fragment_tree (frag);
1826 GNUNET_CONTAINER_MDLL_remove (frag,
1836 * Release memory associated with @a pm and remove @a pm from associated
1837 * data structures. @a pm must be a top-level pending message and not
1838 * a fragment in the tree. The entire tree is freed (if applicable).
1840 * @param pm the pending message to free
1843 free_pending_message (struct PendingMessage *pm)
1845 struct TransportClient *tc = pm->client;
1846 struct Neighbour *target = pm->target;
1850 GNUNET_CONTAINER_MDLL_remove (client,
1851 tc->details.core.pending_msg_head,
1852 tc->details.core.pending_msg_tail,
1855 GNUNET_CONTAINER_MDLL_remove (neighbour,
1856 target->pending_msg_head,
1857 target->pending_msg_tail,
1859 free_fragment_tree (pm);
1860 GNUNET_free_non_null (pm->bpm);
1866 * Send a response to the @a pm that we have processed a
1867 * "send" request with status @a success. We
1868 * transmitted @a bytes_physical on the actual wire.
1869 * Sends a confirmation to the "core" client responsible
1870 * for the original request and free's @a pm.
1872 * @param pm handle to the original pending message
1873 * @param success status code, #GNUNET_OK on success, #GNUNET_SYSERR
1874 * for transmission failure
1875 * @param bytes_physical amount of bandwidth consumed
1878 client_send_response (struct PendingMessage *pm,
1880 uint32_t bytes_physical)
1882 struct TransportClient *tc = pm->client;
1883 struct Neighbour *target = pm->target;
1884 struct GNUNET_MQ_Envelope *env;
1885 struct SendOkMessage *som;
1889 env = GNUNET_MQ_msg (som,
1890 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1891 som->success = htonl ((uint32_t) success);
1892 som->bytes_msg = htons (pm->bytes_msg);
1893 som->bytes_physical = htonl (bytes_physical);
1894 som->peer = target->pid;
1895 GNUNET_MQ_send (tc->mq,
1898 free_pending_message (pm);
1903 * Checks the message queue for a neighbour for messages that have timed
1904 * out and purges them.
1906 * @param cls a `struct Neighbour`
1909 check_queue_timeouts (void *cls)
1911 struct Neighbour *n = cls;
1912 struct PendingMessage *pm;
1913 struct GNUNET_TIME_Absolute now;
1914 struct GNUNET_TIME_Absolute earliest_timeout;
1916 n->timeout_task = NULL;
1917 earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1918 now = GNUNET_TIME_absolute_get ();
1919 for (struct PendingMessage *pos = n->pending_msg_head;
1923 pm = pos->next_neighbour;
1924 if (pos->timeout.abs_value_us <= now.abs_value_us)
1926 GNUNET_STATISTICS_update (GST_stats,
1927 "# messages dropped (timeout before confirmation)",
1930 client_send_response (pm,
1935 earliest_timeout = GNUNET_TIME_absolute_min (earliest_timeout,
1938 n->earliest_timeout = earliest_timeout;
1939 if (NULL != n->pending_msg_head)
1940 n->timeout_task = GNUNET_SCHEDULER_add_at (earliest_timeout,
1941 &check_queue_timeouts,
1947 * Client asked for transmission to a peer. Process the request.
1949 * @param cls the client
1950 * @param obm the send message that was sent
1953 handle_client_send (void *cls,
1954 const struct OutboundMessage *obm)
1956 struct TransportClient *tc = cls;
1957 struct PendingMessage *pm;
1958 const struct GNUNET_MessageHeader *obmm;
1959 struct Neighbour *target;
1962 GNUNET_assert (CT_CORE == tc->type);
1963 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
1964 bytes_msg = ntohs (obmm->size);
1965 target = lookup_neighbour (&obm->peer);
1968 /* Failure: don't have this peer as a neighbour (anymore).
1969 Might have gone down asynchronously, so this is NOT
1970 a protocol violation by CORE. Still count the event,
1971 as this should be rare. */
1972 struct GNUNET_MQ_Envelope *env;
1973 struct SendOkMessage *som;
1975 env = GNUNET_MQ_msg (som,
1976 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1977 som->success = htonl (GNUNET_SYSERR);
1978 som->bytes_msg = htonl (bytes_msg);
1979 som->bytes_physical = htonl (0);
1980 som->peer = obm->peer;
1981 GNUNET_MQ_send (tc->mq,
1983 GNUNET_SERVICE_client_continue (tc->client);
1984 GNUNET_STATISTICS_update (GST_stats,
1985 "# messages dropped (neighbour unknown)",
1990 pm = GNUNET_malloc (sizeof (struct PendingMessage) + bytes_msg);
1992 pm->target = target;
1993 pm->bytes_msg = bytes_msg;
1994 pm->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
1998 GNUNET_CONTAINER_MDLL_insert (neighbour,
1999 target->pending_msg_head,
2000 target->pending_msg_tail,
2002 GNUNET_CONTAINER_MDLL_insert (client,
2003 tc->details.core.pending_msg_head,
2004 tc->details.core.pending_msg_tail,
2006 if (target->earliest_timeout.abs_value_us > pm->timeout.abs_value_us)
2008 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
2009 if (NULL != target->timeout_task)
2010 GNUNET_SCHEDULER_cancel (target->timeout_task);
2011 target->timeout_task
2012 = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
2013 &check_queue_timeouts,
2020 * Communicator started. Test message is well-formed.
2022 * @param cls the client
2023 * @param cam the send message that was sent
2026 check_communicator_available (void *cls,
2027 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
2029 struct TransportClient *tc = cls;
2032 if (CT_NONE != tc->type)
2035 return GNUNET_SYSERR;
2037 tc->type = CT_COMMUNICATOR;
2038 size = ntohs (cam->header.size) - sizeof (*cam);
2040 return GNUNET_OK; /* receive-only communicator */
2041 GNUNET_MQ_check_zero_termination (cam);
2047 * Communicator started. Process the request.
2049 * @param cls the client
2050 * @param cam the send message that was sent
2053 handle_communicator_available (void *cls,
2054 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
2056 struct TransportClient *tc = cls;
2059 size = ntohs (cam->header.size) - sizeof (*cam);
2061 return; /* receive-only communicator */
2062 tc->details.communicator.address_prefix
2063 = GNUNET_strdup ((const char *) &cam[1]);
2064 tc->details.communicator.cc
2065 = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
2066 GNUNET_SERVICE_client_continue (tc->client);
2071 * Communicator requests backchannel transmission. Check the request.
2073 * @param cls the client
2074 * @param cb the send message that was sent
2075 * @return #GNUNET_OK if message is well-formed
2078 check_communicator_backchannel (void *cls,
2079 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
2081 // FIXME: check encapsulated message
2082 // FIXME: check 0-termination of communcator at target
2088 * Communicator requests backchannel transmission. Process the request.
2090 * @param cls the client
2091 * @param cb the send message that was sent
2094 handle_communicator_backchannel (void *cls,
2095 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
2097 struct TransportClient *tc = cls;
2099 // FIXME: determine path (possibly DV)! to target peer
2100 // FIXME: encapsulate message, encrypt message!
2101 // FIXME: possibly fragment message
2102 // FIXME: possibly DV-route message!
2103 GNUNET_SERVICE_client_continue (tc->client);
2108 * Address of our peer added. Test message is well-formed.
2110 * @param cls the client
2111 * @param aam the send message that was sent
2112 * @return #GNUNET_OK if message is well-formed
2115 check_add_address (void *cls,
2116 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
2118 struct TransportClient *tc = cls;
2120 if (CT_COMMUNICATOR != tc->type)
2123 return GNUNET_SYSERR;
2125 GNUNET_MQ_check_zero_termination (aam);
2131 * Ask peerstore to store our address.
2133 * @param cls an `struct AddressListEntry *`
2136 store_pi (void *cls);
2140 * Function called when peerstore is done storing our address.
2143 peerstore_store_cb (void *cls,
2146 struct AddressListEntry *ale = cls;
2149 if (GNUNET_YES != success)
2150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2151 "Failed to store our own address `%s' in peerstore!\n",
2153 /* refresh period is 1/4 of expiration time, that should be plenty
2154 without being excessive. */
2155 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
2163 * Ask peerstore to store our address.
2165 * @param cls an `struct AddressListEntry *`
2168 store_pi (void *cls)
2170 struct AddressListEntry *ale = cls;
2173 struct GNUNET_TIME_Absolute expiration;
2176 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
2177 GNUNET_HELLO_sign_address (ale->address,
2183 ale->sc = GNUNET_PEERSTORE_store (peerstore,
2186 GNUNET_HELLO_PEERSTORE_KEY,
2190 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
2191 &peerstore_store_cb,
2194 if (NULL == ale->sc)
2196 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2197 "Failed to store our address `%s' with peerstore\n",
2199 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
2207 * Address of our peer added. Process the request.
2209 * @param cls the client
2210 * @param aam the send message that was sent
2213 handle_add_address (void *cls,
2214 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
2216 struct TransportClient *tc = cls;
2217 struct AddressListEntry *ale;
2220 slen = ntohs (aam->header.size) - sizeof (*aam);
2221 ale = GNUNET_malloc (sizeof (struct AddressListEntry) + slen);
2223 ale->address = (const char *) &ale[1];
2224 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
2225 ale->aid = aam->aid;
2226 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
2230 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
2231 tc->details.communicator.addr_tail,
2233 ale->st = GNUNET_SCHEDULER_add_now (&store_pi,
2235 GNUNET_SERVICE_client_continue (tc->client);
2240 * Address of our peer deleted. Process the request.
2242 * @param cls the client
2243 * @param dam the send message that was sent
2246 handle_del_address (void *cls,
2247 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
2249 struct TransportClient *tc = cls;
2251 if (CT_COMMUNICATOR != tc->type)
2254 GNUNET_SERVICE_client_drop (tc->client);
2257 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
2261 if (dam->aid != ale->aid)
2263 GNUNET_assert (ale->tc == tc);
2264 free_address_list_entry (ale);
2265 GNUNET_SERVICE_client_continue (tc->client);
2268 GNUNET_SERVICE_client_drop (tc->client);
2273 * Context from #handle_incoming_msg(). Closure for many
2274 * message handlers below.
2276 struct CommunicatorMessageContext
2279 * Which communicator provided us with the message.
2281 struct TransportClient *tc;
2284 * Additional information for flow control and about the sender.
2286 struct GNUNET_TRANSPORT_IncomingMessage im;
2291 * Send ACK to communicator (if requested) and free @a cmc.
2293 * @param cmc context for which we are done handling the message
2296 finish_cmc_handling (struct CommunicatorMessageContext *cmc)
2298 if (0 != ntohl (cmc->im.fc_on))
2300 /* send ACK when done to communicator for flow control! */
2301 struct GNUNET_MQ_Envelope *env;
2302 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
2304 env = GNUNET_MQ_msg (ack,
2305 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
2306 ack->reserved = htonl (0);
2307 ack->fc_id = cmc->im.fc_id;
2308 ack->sender = cmc->im.sender;
2309 GNUNET_MQ_send (cmc->tc->mq,
2312 GNUNET_SERVICE_client_continue (cmc->tc->client);
2318 * Communicator gave us an unencapsulated message to pass as-is to
2319 * CORE. Process the request.
2321 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2322 * @param mh the message that was received
2325 handle_raw_message (void *cls,
2326 const struct GNUNET_MessageHeader *mh)
2328 struct CommunicatorMessageContext *cmc = cls;
2329 uint16_t size = ntohs (mh->size);
2331 if ( (size > UINT16_MAX - sizeof (struct InboundMessage)) ||
2332 (size < sizeof (struct GNUNET_MessageHeader)) )
2334 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
2337 finish_cmc_handling (cmc);
2338 GNUNET_SERVICE_client_drop (client);
2341 /* Forward to all CORE clients */
2342 for (struct TransportClient *tc = clients_head;
2346 struct GNUNET_MQ_Envelope *env;
2347 struct InboundMessage *im;
2349 if (CT_CORE != tc->type)
2351 env = GNUNET_MQ_msg_extra (im,
2353 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2354 im->peer = cmc->im.sender;
2358 GNUNET_MQ_send (tc->mq,
2361 /* FIXME: consider doing this _only_ once the message
2362 was drained from the CORE MQs to extend flow control to CORE!
2363 (basically, increment counter in cmc, decrement on MQ send continuation! */
2364 finish_cmc_handling (cmc);
2369 * Communicator gave us a fragment box. Check the message.
2371 * @param cls a `struct CommunicatorMessageContext`
2372 * @param fb the send message that was sent
2373 * @return #GNUNET_YES if message is well-formed
2376 check_fragment_box (void *cls,
2377 const struct TransportFragmentBox *fb)
2379 uint16_t size = ntohs (fb->header.size);
2380 uint16_t bsize = size - sizeof (*fb);
2384 GNUNET_break_op (0);
2385 return GNUNET_SYSERR;
2387 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
2389 GNUNET_break_op (0);
2390 return GNUNET_SYSERR;
2392 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
2394 GNUNET_break_op (0);
2395 return GNUNET_SYSERR;
2402 * Communicator gave us a fragment. Process the request.
2404 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2405 * @param fb the message that was received
2408 handle_fragment_box (void *cls,
2409 const struct TransportFragmentBox *fb)
2411 struct CommunicatorMessageContext *cmc = cls;
2414 finish_cmc_handling (cmc);
2419 * Communicator gave us a fragment acknowledgement. Process the request.
2421 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2422 * @param fa the message that was received
2425 handle_fragment_ack (void *cls,
2426 const struct TransportFragmentAckMessage *fa)
2428 struct CommunicatorMessageContext *cmc = cls;
2431 finish_cmc_handling (cmc);
2436 * Communicator gave us a reliability box. Check the message.
2438 * @param cls a `struct CommunicatorMessageContext`
2439 * @param rb the send message that was sent
2440 * @return #GNUNET_YES if message is well-formed
2443 check_reliability_box (void *cls,
2444 const struct TransportReliabilityBox *rb)
2446 GNUNET_MQ_check_boxed_message (rb);
2452 * Communicator gave us a reliability box. Process the request.
2454 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2455 * @param rb the message that was received
2458 handle_reliability_box (void *cls,
2459 const struct TransportReliabilityBox *rb)
2461 struct CommunicatorMessageContext *cmc = cls;
2462 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &rb[1];
2464 // FIXME: send back reliability ACK (possibly conditional)
2465 /* forward encapsulated message to CORE */
2466 handle_raw_message (cmc,
2472 * Communicator gave us a reliability ack. Process the request.
2474 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2475 * @param ra the message that was received
2478 handle_reliability_ack (void *cls,
2479 const struct TransportReliabilityAckMessage *ra)
2481 struct CommunicatorMessageContext *cmc = cls;
2483 // FIXME: do work: find message that was acknowledged, and
2484 // remove from transmission queue; update RTT.
2485 finish_cmc_handling (cmc);
2490 * Communicator gave us a backchannel encapsulation. Check the message.
2492 * @param cls a `struct CommunicatorMessageContext`
2493 * @param be the send message that was sent
2494 * @return #GNUNET_YES if message is well-formed
2497 check_backchannel_encapsulation (void *cls,
2498 const struct TransportBackchannelEncapsulationMessage *be)
2500 uint16_t size = ntohs (be->header.size);
2502 if (size - sizeof (*be) < sizeof (struct GNUNET_MessageHeader))
2504 GNUNET_break_op (0);
2505 return GNUNET_SYSERR;
2512 * Communicator gave us a backchannel encapsulation. Process the request.
2514 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2515 * @param be the message that was received
2518 handle_backchannel_encapsulation (void *cls,
2519 const struct TransportBackchannelEncapsulationMessage *be)
2521 struct CommunicatorMessageContext *cmc = cls;
2523 // FIMXE: test if it is for me, if not, try to forward to target (DV routes!)
2524 // FIXME: compute shared secret
2525 // FIXME: check HMAC
2526 // FIXME: decrypt payload
2527 // FIXME: forward to specified communicator!
2529 finish_cmc_handling (cmc);
2534 * Communicator gave us an ephemeral confirmation. Process the request.
2536 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2537 * @param ec the message that was received
2540 handle_ephemeral_confirmation (void *cls,
2541 const struct EphemeralConfirmationMessage *ec)
2543 struct CommunicatorMessageContext *cmc = cls;
2545 // FIXME: notify communicator (?) about ephemeral confirmation!?
2546 // FIXME: or does this have something to do with the ephemeral_map?
2547 // where did I plan to use this message again!?
2548 // FIXME: communicator API has a very general notification API,
2549 // nothing specific for ephemeral keys;
2550 // why do we have a ephemeral key-specific message here?
2551 // => first revise where we get such messages from communicator
2552 // before processing further here!
2553 finish_cmc_handling (cmc);
2558 * Communicator gave us a DV learn message. Check the message.
2560 * @param cls a `struct CommunicatorMessageContext`
2561 * @param dvl the send message that was sent
2562 * @return #GNUNET_YES if message is well-formed
2565 check_dv_learn (void *cls,
2566 const struct TransportDVLearn *dvl)
2568 uint16_t size = ntohs (dvl->header.size);
2569 uint16_t num_hops = ntohs (dvl->num_hops);
2570 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvl[1];
2572 if (size != sizeof (*dvl) + num_hops * sizeof (struct GNUNET_PeerIdentity))
2574 GNUNET_break_op (0);
2575 return GNUNET_SYSERR;
2577 for (unsigned int i=0;i<num_hops;i++)
2579 if (0 == memcmp (&dvl->initiator,
2581 sizeof (struct GNUNET_PeerIdentity)))
2583 GNUNET_break_op (0);
2584 return GNUNET_SYSERR;
2586 if (0 == memcmp (&GST_my_identity,
2588 sizeof (struct GNUNET_PeerIdentity)))
2590 GNUNET_break_op (0);
2591 return GNUNET_SYSERR;
2599 * Communicator gave us a DV learn message. Process the request.
2601 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2602 * @param dvl the message that was received
2605 handle_dv_learn (void *cls,
2606 const struct TransportDVLearn *dvl)
2608 struct CommunicatorMessageContext *cmc = cls;
2610 // FIXME: learn path from DV message (if bi-directional flags are set)
2611 // FIXME: expand DV message, forward on (unless path is getting too long)
2612 finish_cmc_handling (cmc);
2617 * Communicator gave us a DV box. Check the message.
2619 * @param cls a `struct CommunicatorMessageContext`
2620 * @param dvb the send message that was sent
2621 * @return #GNUNET_YES if message is well-formed
2624 check_dv_box (void *cls,
2625 const struct TransportDVBox *dvb)
2627 uint16_t size = ntohs (dvb->header.size);
2628 uint16_t num_hops = ntohs (dvb->num_hops);
2629 const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1];
2630 const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops];
2634 if (size < sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct GNUNET_MessageHeader))
2636 GNUNET_break_op (0);
2637 return GNUNET_SYSERR;
2639 isize = ntohs (inbox->size);
2640 if (size != sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
2642 GNUNET_break_op (0);
2643 return GNUNET_SYSERR;
2645 itype = ntohs (inbox->type);
2646 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX == itype) ||
2647 (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN == itype) )
2649 GNUNET_break_op (0);
2650 return GNUNET_SYSERR;
2657 * Communicator gave us a DV box. Process the request.
2659 * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done)
2660 * @param dvb the message that was received
2663 handle_dv_box (void *cls,
2664 const struct TransportDVBox *dvb)
2666 struct CommunicatorMessageContext *cmc = cls;
2668 // FIXME: are we the target? Then unbox and handle message.
2669 // FIXME: if we are not the target, shorten path and forward along.
2670 finish_cmc_handling (cmc);
2675 * Client notified us about transmission from a peer. Process the request.
2677 * @param cls a `struct TransportClient` which sent us the message
2678 * @param obm the send message that was sent
2679 * @return #GNUNET_YES if message is well-formed
2682 check_incoming_msg (void *cls,
2683 const struct GNUNET_TRANSPORT_IncomingMessage *im)
2685 struct TransportClient *tc = cls;
2687 if (CT_COMMUNICATOR != tc->type)
2690 return GNUNET_SYSERR;
2692 GNUNET_MQ_check_boxed_message (im);
2698 * Incoming meessage. Process the request.
2700 * @param im the send message that was received
2703 handle_incoming_msg (void *cls,
2704 const struct GNUNET_TRANSPORT_IncomingMessage *im)
2706 struct TransportClient *tc = cls;
2707 struct CommunicatorMessageContext *cmc = GNUNET_new (struct CommunicatorMessageContext);
2708 struct GNUNET_MQ_MessageHandler handlers[] = {
2709 GNUNET_MQ_hd_var_size (fragment_box,
2710 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
2711 struct TransportFragmentBox,
2713 GNUNET_MQ_hd_fixed_size (fragment_ack,
2714 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK,
2715 struct TransportFragmentAckMessage,
2717 GNUNET_MQ_hd_var_size (reliability_box,
2718 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
2719 struct TransportReliabilityBox,
2721 GNUNET_MQ_hd_fixed_size (reliability_ack,
2722 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
2723 struct TransportReliabilityAckMessage,
2725 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
2726 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
2727 struct TransportBackchannelEncapsulationMessage,
2729 GNUNET_MQ_hd_fixed_size (ephemeral_confirmation,
2730 GNUNET_MESSAGE_TYPE_TRANSPORT_EPHEMERAL_CONFIRMATION,
2731 struct EphemeralConfirmationMessage,
2733 GNUNET_MQ_hd_var_size (dv_learn,
2734 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
2735 struct TransportDVLearn,
2737 GNUNET_MQ_hd_var_size (dv_box,
2738 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
2739 struct TransportDVBox,
2741 GNUNET_MQ_handler_end()
2747 ret = GNUNET_MQ_handle_message (handlers,
2748 (const struct GNUNET_MessageHeader *) &im[1]);
2749 if (GNUNET_SYSERR == ret)
2752 GNUNET_SERVICE_client_drop (tc->client);
2756 if (GNUNET_NO == ret)
2758 /* unencapsulated 'raw' message */
2759 handle_raw_message (&cmc,
2760 (const struct GNUNET_MessageHeader *) &im[1]);
2766 * New queue became available. Check message.
2768 * @param cls the client
2769 * @param aqm the send message that was sent
2772 check_add_queue_message (void *cls,
2773 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
2775 struct TransportClient *tc = cls;
2777 if (CT_COMMUNICATOR != tc->type)
2780 return GNUNET_SYSERR;
2782 GNUNET_MQ_check_zero_termination (aqm);
2788 * Bandwidth tracker informs us that the delay until we should receive
2791 * @param cls a `struct GNUNET_ATS_Session` for which the delay changed
2794 tracker_update_in_cb (void *cls)
2796 struct GNUNET_ATS_Session *queue = cls;
2797 struct GNUNET_TIME_Relative in_delay;
2800 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
2801 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in,
2803 // FIXME: how exactly do we do inbound flow control?
2808 * If necessary, generates the UUID for a @a pm
2810 * @param pm pending message to generate UUID for.
2813 set_pending_message_uuid (struct PendingMessage *pm)
2815 if (pm->msg_uuid_set)
2817 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
2819 sizeof (pm->msg_uuid));
2820 pm->msg_uuid_set = GNUNET_YES;
2825 * Fragment the given @a pm to the given @a mtu. Adds
2826 * additional fragments to the neighbour as well. If the
2827 * @a mtu is too small, generates and error for the @a pm
2830 * @param pm pending message to fragment for transmission
2831 * @param mtu MTU to apply
2832 * @return new message to transmit
2834 static struct PendingMessage *
2835 fragment_message (struct PendingMessage *pm,
2838 struct PendingMessage *ff;
2840 set_pending_message_uuid (pm);
2842 /* This invariant is established in #handle_add_queue_message() */
2843 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
2845 /* select fragment for transmission, descending the tree if it has
2846 been expanded until we are at a leaf or at a fragment that is small enough */
2848 while ( ( (ff->bytes_msg > mtu) ||
2850 (ff->frag_off == ff->bytes_msg) &&
2851 (NULL != ff->head_frag) )
2853 ff = ff->head_frag; /* descent into fragmented fragments */
2856 if ( ( (ff->bytes_msg > mtu) ||
2858 (pm->frag_off < pm->bytes_msg) )
2860 /* Did not yet calculate all fragments, calculate next fragment */
2861 struct PendingMessage *frag;
2862 struct TransportFragmentBox tfb;
2870 orig = (const char *) &ff[1];
2871 msize = ff->bytes_msg;
2874 const struct TransportFragmentBox *tfbo;
2876 tfbo = (const struct TransportFragmentBox *) orig;
2877 orig += sizeof (struct TransportFragmentBox);
2878 msize -= sizeof (struct TransportFragmentBox);
2879 xoff = ntohs (tfbo->frag_off);
2881 fragmax = mtu - sizeof (struct TransportFragmentBox);
2882 fragsize = GNUNET_MIN (msize - ff->frag_off,
2884 frag = GNUNET_malloc (sizeof (struct PendingMessage) +
2885 sizeof (struct TransportFragmentBox) +
2887 frag->target = pm->target;
2888 frag->frag_parent = ff;
2889 frag->timeout = pm->timeout;
2890 frag->bytes_msg = sizeof (struct TransportFragmentBox) + fragsize;
2891 frag->pmt = PMT_FRAGMENT_BOX;
2892 msg = (char *) &frag[1];
2893 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
2894 tfb.header.size = htons (sizeof (struct TransportFragmentBox) +
2896 tfb.frag_uuid = htonl (pm->frag_uuidgen++);
2897 tfb.msg_uuid = pm->msg_uuid;
2898 tfb.frag_off = htons (ff->frag_off + xoff);
2899 tfb.msg_size = htons (pm->bytes_msg);
2903 memcpy (&msg[sizeof (tfb)],
2904 &orig[ff->frag_off],
2906 GNUNET_CONTAINER_MDLL_insert (frag,
2910 ff->frag_off += fragsize;
2914 /* Move head to the tail and return it */
2915 GNUNET_CONTAINER_MDLL_remove (frag,
2916 ff->frag_parent->head_frag,
2917 ff->frag_parent->tail_frag,
2919 GNUNET_CONTAINER_MDLL_insert_tail (frag,
2920 ff->frag_parent->head_frag,
2921 ff->frag_parent->tail_frag,
2928 * Reliability-box the given @a pm. On error (can there be any), NULL
2929 * may be returned, otherwise the "replacement" for @a pm (which
2930 * should then be added to the respective neighbour's queue instead of
2931 * @a pm). If the @a pm is already fragmented or reliability boxed,
2932 * or itself an ACK, this function simply returns @a pm.
2934 * @param pm pending message to box for transmission over unreliabile queue
2935 * @return new message to transmit
2937 static struct PendingMessage *
2938 reliability_box_message (struct PendingMessage *pm)
2940 struct TransportReliabilityBox rbox;
2941 struct PendingMessage *bpm;
2944 if (PMT_CORE != pm->pmt)
2945 return pm; /* already fragmented or reliability boxed, or control message: do nothing */
2946 if (NULL != pm->bpm)
2947 return pm->bpm; /* already computed earlier: do nothing */
2948 GNUNET_assert (NULL == pm->head_frag);
2949 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
2953 client_send_response (pm,
2958 bpm = GNUNET_malloc (sizeof (struct PendingMessage) +
2961 bpm->target = pm->target;
2962 bpm->frag_parent = pm;
2963 GNUNET_CONTAINER_MDLL_insert (frag,
2967 bpm->timeout = pm->timeout;
2968 bpm->pmt = PMT_RELIABILITY_BOX;
2969 bpm->bytes_msg = pm->bytes_msg + sizeof (rbox);
2970 set_pending_message_uuid (bpm);
2971 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
2972 rbox.header.size = htons (sizeof (rbox) + pm->bytes_msg);
2973 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
2974 rbox.msg_uuid = pm->msg_uuid;
2975 msg = (char *) &bpm[1];
2979 memcpy (&msg[sizeof (rbox)],
2988 * We believe we are ready to transmit a message on a queue. Double-checks
2989 * with the queue's "tracker_out" and then gives the message to the
2990 * communicator for transmission (updating the tracker, and re-scheduling
2991 * itself if applicable).
2993 * @param cls the `struct GNUNET_ATS_Session` to process transmissions for
2996 transmit_on_queue (void *cls)
2998 struct GNUNET_ATS_Session *queue = cls;
2999 struct Neighbour *n = queue->neighbour;
3000 struct QueueEntry *qe;
3001 struct PendingMessage *pm;
3002 struct PendingMessage *s;
3004 struct GNUNET_TRANSPORT_SendMessageTo *smt;
3005 struct GNUNET_MQ_Envelope *env;
3007 queue->transmit_task = NULL;
3008 if (NULL == (pm = n->pending_msg_head))
3010 /* no message pending, nothing to do here! */
3013 schedule_transmit_on_queue (queue);
3014 if (NULL != queue->transmit_task)
3015 return; /* do it later */
3017 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
3018 overhead += sizeof (struct TransportReliabilityBox);
3020 if ( ( (0 != queue->mtu) &&
3021 (pm->bytes_msg + overhead > queue->mtu) ) ||
3022 (pm->bytes_msg > UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)) ||
3023 (NULL != pm->head_frag /* fragments already exist, should
3024 respect that even if MTU is 0 for
3026 s = fragment_message (s,
3028 ? UINT16_MAX - sizeof (struct GNUNET_TRANSPORT_SendMessageTo)
3032 /* Fragmentation failed, try next message... */
3033 schedule_transmit_on_queue (queue);
3036 if (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc)
3037 s = reliability_box_message (s);
3040 /* Reliability boxing failed, try next message... */
3041 schedule_transmit_on_queue (queue);
3045 /* Pass 's' for transission to the communicator */
3046 qe = GNUNET_new (struct QueueEntry);
3047 qe->mid = queue->mid_gen++;
3048 qe->session = queue;
3049 // qe->pm = s; // FIXME: not so easy, reference management on 'free(s)'!
3050 GNUNET_CONTAINER_DLL_insert (queue->queue_head,
3053 env = GNUNET_MQ_msg_extra (smt,
3055 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
3056 smt->qid = queue->qid;
3058 smt->receiver = n->pid;
3062 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
3063 queue->queue_length++;
3064 queue->tc->details.communicator.total_queue_length++;
3065 GNUNET_MQ_send (queue->tc->mq,
3068 // FIXME: do something similar to the logic below
3069 // in defragmentation / reliability ACK handling!
3071 /* Check if this transmission somehow conclusively finished handing 'pm'
3072 even without any explicit ACKs */
3073 if ( (PMT_CORE == s->pmt) &&
3074 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) )
3076 /* Full message sent, and over reliabile channel */
3077 client_send_response (pm,
3081 else if ( (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc) &&
3082 (PMT_FRAGMENT_BOX == s->pmt) )
3084 struct PendingMessage *pos;
3086 /* Fragment sent over reliabile channel */
3087 free_fragment_tree (s);
3088 pos = s->frag_parent;
3089 GNUNET_CONTAINER_MDLL_remove (frag,
3094 /* check if subtree is done */
3095 while ( (NULL == pos->head_frag) &&
3096 (pos->frag_off == pos->bytes_msg) &&
3100 pos = s->frag_parent;
3101 GNUNET_CONTAINER_MDLL_remove (frag,
3108 /* Was this the last applicable fragmment? */
3109 if ( (NULL == pm->head_frag) &&
3110 (pm->frag_off == pm->bytes_msg) )
3111 client_send_response (pm,
3113 pm->bytes_msg /* FIXME: calculate and add overheads! */);
3115 else if (PMT_CORE != pm->pmt)
3117 /* This was an acknowledgement of some type, always free */
3118 free_pending_message (pm);
3122 /* message not finished, waiting for acknowledgement */
3123 struct Neighbour *neighbour = pm->target;
3124 /* Update time by which we might retransmit 's' based on queue
3125 characteristics (i.e. RTT); it takes one RTT for the message to
3126 arrive and the ACK to come back in the best case; but the other
3127 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
3128 retransmitting. Note that in the future this heuristic should
3129 likely be improved further (measure RTT stability, consider
3130 message urgency and size when delaying ACKs, etc.) */
3131 s->next_attempt = GNUNET_TIME_relative_to_absolute
3132 (GNUNET_TIME_relative_multiply (queue->rtt,
3136 struct PendingMessage *pos;
3138 /* re-insert sort in neighbour list */
3139 GNUNET_CONTAINER_MDLL_remove (neighbour,
3140 neighbour->pending_msg_head,
3141 neighbour->pending_msg_tail,
3143 pos = neighbour->pending_msg_tail;
3144 while ( (NULL != pos) &&
3145 (pm->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
3146 pos = pos->prev_neighbour;
3147 GNUNET_CONTAINER_MDLL_insert_after (neighbour,
3148 neighbour->pending_msg_head,
3149 neighbour->pending_msg_tail,
3155 /* re-insert sort in fragment list */
3156 struct PendingMessage *fp = s->frag_parent;
3157 struct PendingMessage *pos;
3159 GNUNET_CONTAINER_MDLL_remove (frag,
3163 pos = fp->tail_frag;
3164 while ( (NULL != pos) &&
3165 (s->next_attempt.abs_value_us > pos->next_attempt.abs_value_us) )
3166 pos = pos->prev_frag;
3167 GNUNET_CONTAINER_MDLL_insert_after (frag,
3175 /* finally, re-schedule queue transmission task itself */
3176 schedule_transmit_on_queue (queue);
3181 * Bandwidth tracker informs us that the delay until we
3182 * can transmit again changed.
3184 * @param cls a `struct GNUNET_ATS_Session` for which the delay changed
3187 tracker_update_out_cb (void *cls)
3189 struct GNUNET_ATS_Session *queue = cls;
3190 struct Neighbour *n = queue->neighbour;
3192 if (NULL == n->pending_msg_head)
3194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3195 "Bandwidth allocation updated for empty transmission queue `%s'\n",
3197 return; /* no message pending, nothing to do here! */
3199 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3200 queue->transmit_task = NULL;
3201 schedule_transmit_on_queue (queue);
3206 * Bandwidth tracker informs us that excessive outbound bandwidth was
3207 * allocated which is not being used.
3209 * @param cls a `struct GNUNET_ATS_Session` for which the excess was noted
3212 tracker_excess_out_cb (void *cls)
3214 /* FIXME: trigger excess bandwidth report to core? Right now,
3215 this is done internally within transport_api2_core already,
3216 but we probably want to change the logic and trigger it
3217 from here via a message instead! */
3218 /* TODO: maybe inform ATS at this point? */
3219 GNUNET_STATISTICS_update (GST_stats,
3220 "# Excess outbound bandwidth reported",
3228 * Bandwidth tracker informs us that excessive inbound bandwidth was allocated
3229 * which is not being used.
3231 * @param cls a `struct GNUNET_ATS_Session` for which the excess was noted
3234 tracker_excess_in_cb (void *cls)
3236 /* TODO: maybe inform ATS at this point? */
3237 GNUNET_STATISTICS_update (GST_stats,
3238 "# Excess inbound bandwidth reported",
3245 * New queue became available. Process the request.
3247 * @param cls the client
3248 * @param aqm the send message that was sent
3251 handle_add_queue_message (void *cls,
3252 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
3254 struct TransportClient *tc = cls;
3255 struct GNUNET_ATS_Session *queue;
3256 struct Neighbour *neighbour;
3260 if (ntohl (aqm->mtu) <= sizeof (struct TransportFragmentBox))
3262 /* MTU so small as to be useless for transmissions,
3263 required for #fragment_message()! */
3264 GNUNET_break_op (0);
3265 GNUNET_SERVICE_client_drop (tc->client);
3268 neighbour = lookup_neighbour (&aqm->receiver);
3269 if (NULL == neighbour)
3271 neighbour = GNUNET_new (struct Neighbour);
3272 neighbour->earliest_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
3273 neighbour->pid = aqm->receiver;
3274 GNUNET_assert (GNUNET_OK ==
3275 GNUNET_CONTAINER_multipeermap_put (neighbours,
3278 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3279 cores_send_connect_info (&neighbour->pid,
3280 GNUNET_BANDWIDTH_ZERO);
3282 addr_len = ntohs (aqm->header.size) - sizeof (*aqm);
3283 addr = (const char *) &aqm[1];
3285 queue = GNUNET_malloc (sizeof (struct GNUNET_ATS_Session) + addr_len);
3287 queue->address = (const char *) &queue[1];
3288 queue->rtt = GNUNET_TIME_UNIT_FOREVER_REL;
3289 queue->qid = aqm->qid;
3290 queue->mtu = ntohl (aqm->mtu);
3291 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
3292 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
3293 queue->neighbour = neighbour;
3294 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_in,
3295 &tracker_update_in_cb,
3297 GNUNET_BANDWIDTH_ZERO,
3298 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
3299 &tracker_excess_in_cb,
3301 GNUNET_BANDWIDTH_tracker_init2 (&queue->tracker_out,
3302 &tracker_update_out_cb,
3304 GNUNET_BANDWIDTH_ZERO,
3305 GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S,
3306 &tracker_excess_out_cb,
3311 /* notify ATS about new queue */
3313 struct GNUNET_ATS_Properties prop = {
3314 .delay = GNUNET_TIME_UNIT_FOREVER_REL,
3317 .cc = tc->details.communicator.cc
3320 queue->sr = GNUNET_ATS_session_add (ats,
3325 if (NULL == queue->sr)
3327 /* This can only happen if the 'address' was way too long for ATS
3328 (approaching 64k in strlen()!). In this case, the communicator
3329 must be buggy and we drop it. */
3331 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_in);
3332 GNUNET_BANDWIDTH_tracker_notification_stop (&queue->tracker_out);
3333 GNUNET_free (queue);
3334 if (NULL == neighbour->session_head)
3336 cores_send_disconnect_info (&neighbour->pid);
3337 free_neighbour (neighbour);
3339 GNUNET_SERVICE_client_drop (tc->client);
3343 /* notify monitors about new queue */
3345 struct MonitorEvent me = {
3350 notify_monitors (&neighbour->pid,
3355 GNUNET_CONTAINER_MDLL_insert (neighbour,
3356 neighbour->session_head,
3357 neighbour->session_tail,
3359 GNUNET_CONTAINER_MDLL_insert (client,
3360 tc->details.communicator.session_head,
3361 tc->details.communicator.session_tail,
3363 GNUNET_SERVICE_client_continue (tc->client);
3368 * Queue to a peer went down. Process the request.
3370 * @param cls the client
3371 * @param dqm the send message that was sent
3374 handle_del_queue_message (void *cls,
3375 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
3377 struct TransportClient *tc = cls;
3379 if (CT_COMMUNICATOR != tc->type)
3382 GNUNET_SERVICE_client_drop (tc->client);
3385 for (struct GNUNET_ATS_Session *session = tc->details.communicator.session_head;
3387 session = session->next_client)
3389 struct Neighbour *neighbour = session->neighbour;
3391 if ( (dqm->qid != session->qid) ||
3392 (0 != memcmp (&dqm->receiver,
3394 sizeof (struct GNUNET_PeerIdentity))) )
3396 free_session (session);
3397 GNUNET_SERVICE_client_continue (tc->client);
3401 GNUNET_SERVICE_client_drop (tc->client);
3406 * Message was transmitted. Process the request.
3408 * @param cls the client
3409 * @param sma the send message that was sent
3412 handle_send_message_ack (void *cls,
3413 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
3415 struct TransportClient *tc = cls;
3416 struct QueueEntry *queue;
3418 if (CT_COMMUNICATOR != tc->type)
3421 GNUNET_SERVICE_client_drop (tc->client);
3425 /* find our queue entry matching the ACK */
3427 for (struct GNUNET_ATS_Session *session = tc->details.communicator.session_head;
3429 session = session->next_client)
3431 if (0 != memcmp (&session->neighbour->pid,
3433 sizeof (struct GNUNET_PeerIdentity)))
3435 for (struct QueueEntry *qe = session->queue_head;
3439 if (qe->mid != sma->mid)
3448 /* this should never happen */
3450 GNUNET_SERVICE_client_drop (tc->client);
3453 GNUNET_CONTAINER_DLL_remove (queue->session->queue_head,
3454 queue->session->queue_tail,
3456 queue->session->queue_length--;
3457 tc->details.communicator.total_queue_length--;
3458 GNUNET_SERVICE_client_continue (tc->client);
3460 /* if applicable, resume transmissions that waited on ACK */
3461 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 == tc->details.communicator.total_queue_length)
3463 /* Communicator dropped below threshold, resume all queues */
3464 GNUNET_STATISTICS_update (GST_stats,
3465 "# Transmission throttled due to communicator queue limit",
3468 for (struct GNUNET_ATS_Session *session = tc->details.communicator.session_head;
3470 session = session->next_client)
3471 schedule_transmit_on_queue (session);
3473 else if (SESSION_QUEUE_LIMIT - 1 == queue->session->queue_length)
3475 /* queue dropped below threshold; only resume this one queue */
3476 GNUNET_STATISTICS_update (GST_stats,
3477 "# Transmission throttled due to session queue limit",
3480 schedule_transmit_on_queue (queue->session);
3483 /* TODO: we also should react on the status! */
3484 // FIXME: this probably requires queue->pm = s assignment!
3485 // FIXME: react to communicator status about transmission request. We got:
3486 sma->status; // OK success, SYSERR failure
3488 GNUNET_free (queue);
3493 * Iterator telling new MONITOR client about all existing
3496 * @param cls the new `struct TransportClient`
3497 * @param pid a connected peer
3498 * @param value the `struct Neighbour` with more information
3499 * @return #GNUNET_OK (continue to iterate)
3502 notify_client_queues (void *cls,
3503 const struct GNUNET_PeerIdentity *pid,
3506 struct TransportClient *tc = cls;
3507 struct Neighbour *neighbour = value;
3509 GNUNET_assert (CT_MONITOR == tc->type);
3510 for (struct GNUNET_ATS_Session *q = neighbour->session_head;
3512 q = q->next_neighbour)
3514 struct MonitorEvent me = {
3517 .num_msg_pending = q->num_msg_pending,
3518 .num_bytes_pending = q->num_bytes_pending
3532 * Initialize a monitor client.
3534 * @param cls the client
3535 * @param start the start message that was sent
3538 handle_monitor_start (void *cls,
3539 const struct GNUNET_TRANSPORT_MonitorStart *start)
3541 struct TransportClient *tc = cls;
3543 if (CT_NONE != tc->type)
3546 GNUNET_SERVICE_client_drop (tc->client);
3549 tc->type = CT_MONITOR;
3550 tc->details.monitor.peer = start->peer;
3551 tc->details.monitor.one_shot = ntohl (start->one_shot);
3552 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3553 ¬ify_client_queues,
3555 GNUNET_SERVICE_client_mark_monitor (tc->client);
3556 GNUNET_SERVICE_client_continue (tc->client);
3561 * Signature of a function called by ATS with the current bandwidth
3562 * allocation to be used as determined by ATS.
3564 * @param cls closure, NULL
3565 * @param session session this is about
3566 * @param bandwidth_out assigned outbound bandwidth for the connection,
3567 * 0 to signal disconnect
3568 * @param bandwidth_in assigned inbound bandwidth for the connection,
3569 * 0 to signal disconnect
3572 ats_allocation_cb (void *cls,
3573 struct GNUNET_ATS_Session *session,
3574 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
3575 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
3578 GNUNET_BANDWIDTH_tracker_update_quota (&session->tracker_out,
3580 GNUNET_BANDWIDTH_tracker_update_quota (&session->tracker_in,
3586 * Find transport client providing communication service
3587 * for the protocol @a prefix.
3589 * @param prefix communicator name
3590 * @return NULL if no such transport client is available
3592 static struct TransportClient *
3593 lookup_communicator (const char *prefix)
3595 for (struct TransportClient *tc = clients_head;
3599 if (CT_COMMUNICATOR != tc->type)
3601 if (0 == strcmp (prefix,
3602 tc->details.communicator.address_prefix))
3605 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3606 "ATS suggested use of communicator for `%s', but we do not have such a communicator!\n",
3613 * Signature of a function called by ATS suggesting transport to
3614 * try connecting with a particular address.
3616 * @param cls closure, NULL
3617 * @param pid target peer
3618 * @param address the address to try
3621 ats_suggestion_cb (void *cls,
3622 const struct GNUNET_PeerIdentity *pid,
3623 const char *address)
3625 static uint32_t idgen;
3626 struct TransportClient *tc;
3628 struct GNUNET_TRANSPORT_CreateQueue *cqm;
3629 struct GNUNET_MQ_Envelope *env;
3633 prefix = GNUNET_HELLO_address_to_prefix (address);
3636 GNUNET_break (0); /* ATS gave invalid address!? */
3639 tc = lookup_communicator (prefix);
3642 GNUNET_STATISTICS_update (GST_stats,
3643 "# ATS suggestions ignored due to missing communicator",
3648 /* forward suggestion for queue creation to communicator */
3649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3650 "Request #%u for `%s' communicator to create queue to `%s'\n",
3651 (unsigned int) idgen,
3654 alen = strlen (address) + 1;
3655 env = GNUNET_MQ_msg_extra (cqm,
3657 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
3658 cqm->request_id = htonl (idgen++);
3659 cqm->receiver = *pid;
3663 GNUNET_MQ_send (tc->mq,
3669 * Communicator tells us that our request to create a queue "worked", that
3670 * is setting up the queue is now in process.
3672 * @param cls the `struct TransportClient`
3673 * @param cqr confirmation message
3676 handle_queue_create_ok (void *cls,
3677 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
3679 struct TransportClient *tc = cls;
3681 if (CT_COMMUNICATOR != tc->type)
3684 GNUNET_SERVICE_client_drop (tc->client);
3687 GNUNET_STATISTICS_update (GST_stats,
3688 "# ATS suggestions succeeded at communicator",
3691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3692 "Request #%u for communicator to create queue succeeded\n",
3693 (unsigned int) ntohs (cqr->request_id));
3694 GNUNET_SERVICE_client_continue (tc->client);
3699 * Communicator tells us that our request to create a queue failed. This usually
3700 * indicates that the provided address is simply invalid or that the communicator's
3701 * resources are exhausted.
3703 * @param cls the `struct TransportClient`
3704 * @param cqr failure message
3707 handle_queue_create_fail (void *cls,
3708 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
3710 struct TransportClient *tc = cls;
3712 if (CT_COMMUNICATOR != tc->type)
3715 GNUNET_SERVICE_client_drop (tc->client);
3718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3719 "Request #%u for communicator to create queue failed\n",
3720 (unsigned int) ntohs (cqr->request_id));
3721 GNUNET_STATISTICS_update (GST_stats,
3722 "# ATS suggestions failed in queue creation at communicator",
3725 GNUNET_SERVICE_client_continue (tc->client);
3730 * Free neighbour entry.
3734 * @param value a `struct Neighbour`
3735 * @return #GNUNET_OK (always)
3738 free_neighbour_cb (void *cls,
3739 const struct GNUNET_PeerIdentity *pid,
3742 struct Neighbour *neighbour = value;
3746 GNUNET_break (0); // should this ever happen?
3747 free_neighbour (neighbour);
3754 * Free ephemeral entry.
3758 * @param value a `struct Neighbour`
3759 * @return #GNUNET_OK (always)
3762 free_ephemeral_cb (void *cls,
3763 const struct GNUNET_PeerIdentity *pid,
3766 struct EphemeralCacheEntry *ece = value;
3770 free_ephemeral (ece);
3776 * Function called when the service shuts down. Unloads our plugins
3777 * and cancels pending validations.
3779 * @param cls closure, unused
3782 do_shutdown (void *cls)
3786 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3791 GNUNET_ATS_transport_done (ats);
3794 if (NULL != peerstore)
3796 GNUNET_PEERSTORE_disconnect (peerstore,
3800 if (NULL != GST_stats)
3802 GNUNET_STATISTICS_destroy (GST_stats,
3806 if (NULL != GST_my_private_key)
3808 GNUNET_free (GST_my_private_key);
3809 GST_my_private_key = NULL;
3811 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
3813 GNUNET_CONTAINER_multipeermap_iterate (ephemeral_map,
3816 GNUNET_CONTAINER_multipeermap_destroy (ephemeral_map);
3817 ephemeral_map = NULL;
3818 GNUNET_CONTAINER_heap_destroy (ephemeral_heap);
3819 ephemeral_heap = NULL;
3824 * Initiate transport service.
3826 * @param cls closure
3827 * @param c configuration to use
3828 * @param service the initialized service
3832 const struct GNUNET_CONFIGURATION_Handle *c,
3833 struct GNUNET_SERVICE_Handle *service)
3838 neighbours = GNUNET_CONTAINER_multipeermap_create (1024,
3840 ephemeral_map = GNUNET_CONTAINER_multipeermap_create (32,
3842 ephemeral_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3843 GST_my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
3844 if (NULL == GST_my_private_key)
3846 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3847 _("Transport service is lacking key configuration settings. Exiting.\n"));
3848 GNUNET_SCHEDULER_shutdown ();
3851 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
3852 &GST_my_identity.public_key);
3853 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
3854 "My identity is `%s'\n",
3855 GNUNET_i2s_full (&GST_my_identity));
3856 GST_stats = GNUNET_STATISTICS_create ("transport",
3858 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
3860 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
3861 if (NULL == peerstore)
3864 GNUNET_SCHEDULER_shutdown ();
3867 ats = GNUNET_ATS_transport_init (GST_cfg,
3875 GNUNET_SCHEDULER_shutdown ();
3882 * Define "main" method using service macro.
3886 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
3889 &client_disconnect_cb,
3891 /* communication with core */
3892 GNUNET_MQ_hd_fixed_size (client_start,
3893 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
3894 struct StartMessage,
3896 GNUNET_MQ_hd_var_size (client_send,
3897 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
3898 struct OutboundMessage,
3900 /* communication with communicators */
3901 GNUNET_MQ_hd_var_size (communicator_available,
3902 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
3903 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
3905 GNUNET_MQ_hd_var_size (communicator_backchannel,
3906 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
3907 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
3909 GNUNET_MQ_hd_var_size (add_address,
3910 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
3911 struct GNUNET_TRANSPORT_AddAddressMessage,
3913 GNUNET_MQ_hd_fixed_size (del_address,
3914 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
3915 struct GNUNET_TRANSPORT_DelAddressMessage,
3917 GNUNET_MQ_hd_var_size (incoming_msg,
3918 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
3919 struct GNUNET_TRANSPORT_IncomingMessage,
3921 GNUNET_MQ_hd_fixed_size (queue_create_ok,
3922 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
3923 struct GNUNET_TRANSPORT_CreateQueueResponse,
3925 GNUNET_MQ_hd_fixed_size (queue_create_fail,
3926 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
3927 struct GNUNET_TRANSPORT_CreateQueueResponse,
3929 GNUNET_MQ_hd_var_size (add_queue_message,
3930 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
3931 struct GNUNET_TRANSPORT_AddQueueMessage,
3933 GNUNET_MQ_hd_fixed_size (del_queue_message,
3934 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
3935 struct GNUNET_TRANSPORT_DelQueueMessage,
3937 GNUNET_MQ_hd_fixed_size (send_message_ack,
3938 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
3939 struct GNUNET_TRANSPORT_SendMessageToAck,
3941 /* communication with monitors */
3942 GNUNET_MQ_hd_fixed_size (monitor_start,
3943 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
3944 struct GNUNET_TRANSPORT_MonitorStart,
3946 GNUNET_MQ_handler_end ());
3949 /* end of file gnunet-service-transport.c */